target.c (16113B)
1 #include <stddef.h> 2 #include <stdint.h> 3 #include <stdio.h> 4 #include <string.h> 5 6 #include <kit/target.h> 7 8 #include "driver.h" 9 10 /* Target-triple parsing and the spec-derived target defaults now live in the 11 * public libkit API (<kit/target.h>, src/api/target.c). The functions below are 12 * thin driver-side wrappers that preserve the historical driver_* signatures 13 * (and the driver's int-status / diagnostic conventions) so every CLI caller is 14 * unaffected. The CLI feature-parsing policy (-march / -mattr / -mcpu / -m<feat> 15 * → DriverTargetFeatures) stays here, since it consumes argv and emits 16 * diagnostics. */ 17 18 int driver_arch_from_name(const char* name, KitArchKind* arch_out, 19 uint8_t* ptr_size_out) { 20 return kit_arch_from_name(name, arch_out, ptr_size_out) ? 0 : 1; 21 } 22 23 void driver_err_unknown_target(const char* tool, const char* value) { 24 const KitTargetProfile* profiles; 25 const char* candidates[64]; 26 DriverSuggestion suggestions[3]; 27 size_t count = 0, candidate_count = 0, i, nsuggestions; 28 profiles = kit_target_profiles(&count); 29 for (i = 0; i < count && candidate_count < 64; ++i) 30 candidates[candidate_count++] = profiles[i].triple; 31 for (i = 0; i < count && candidate_count < 64; ++i) 32 candidates[candidate_count++] = profiles[i].selector; 33 nsuggestions = driver_suggest_values(value, candidates, candidate_count, 34 suggestions, 3); 35 if (nsuggestions) 36 driver_errf(tool, "unrecognized target: %s; did you mean '%s'?", value, 37 suggestions[0].value); 38 else 39 driver_errf(tool, "unrecognized target: %s; run `kit targets` to list " 40 "supported profiles", 41 value); 42 } 43 44 KitPic driver_default_pic(KitObjFmt obj, KitOSKind os) { 45 return kit_target_default_pic(obj, os); 46 } 47 48 int driver_link_pie(KitTargetSpec target, int explicit_pie, int shared, 49 int relocatable) { 50 return kit_target_link_pie(target, explicit_pie, shared, relocatable); 51 } 52 53 const char* driver_default_exe_name(KitTargetSpec target) { 54 return kit_target_default_exe_name(target); 55 } 56 57 void driver_default_obj_ext(KitTargetSpec target, const char** ext_out, 58 size_t* ext_len_out) { 59 kit_target_default_obj_ext(target, ext_out, ext_len_out); 60 } 61 62 int driver_target_needs_sysroot_libdir(KitTargetSpec target) { 63 return kit_target_needs_sysroot_libdir(target); 64 } 65 66 int driver_target_default_hosted_profile(KitTargetSpec target) { 67 return kit_target_default_hosted_profile(target); 68 } 69 70 int driver_target_shared_uses_hosted(KitTargetSpec target) { 71 /* Whether a `-shared` link still needs the hosted CRT/libc is an OS policy 72 * (Android bionic does; ELF/Mach-O/COFF hosts otherwise do not). Read it from 73 * the OS hosted-ops vtable rather than hardcoding the identity here. The obj 74 * gate guards against a triple that names an OS but a mismatched object 75 * format. Note: no arch coupling -- Android shared libs need the hosted CRT on 76 * every arch (only aarch64 is built today, so behavior is preserved). */ 77 const KitOsImpl* o = kit_os_lookup(target.os); 78 return o && o->hosted && o->hosted->obj == target.obj && 79 o->hosted->shared_uses_hosted; 80 } 81 82 static int target_features_grow(DriverTargetFeatures* tf) { 83 DriverEnv* env = tf->env; 84 uint32_t old_cap = tf->cap_features; 85 uint32_t new_cap = old_cap ? old_cap * 2u : 8u; 86 size_t old_sz = (size_t)old_cap * sizeof(*tf->features); 87 size_t new_sz = (size_t)new_cap * sizeof(*tf->features); 88 void* p = env->heap->realloc(env->heap, tf->features, old_sz, new_sz, 89 _Alignof(KitTargetFeature)); 90 if (!p) return 1; 91 tf->features = (KitTargetFeature*)p; 92 memset(tf->features + old_cap, 0, new_sz - old_sz); 93 tf->cap_features = new_cap; 94 return 0; 95 } 96 97 int driver_target_features_init(DriverTargetFeatures* tf, DriverEnv* env, 98 int argc_bound) { 99 size_t bound = argc_bound > 0 ? (size_t)argc_bound + 8u : 8u; 100 if (!tf || !env || !env->heap) return 1; 101 memset(tf, 0, sizeof(*tf)); 102 tf->env = env; 103 tf->cap_features = (uint32_t)bound; 104 tf->features = driver_alloc_zeroed(env, bound * sizeof(*tf->features)); 105 if (!tf->features) return 1; 106 return 0; 107 } 108 109 void driver_target_features_fini(DriverTargetFeatures* tf, DriverEnv* env) { 110 if (!tf || !env) return; 111 driver_free(env, tf->features, 112 (size_t)tf->cap_features * sizeof(*tf->features)); 113 memset(tf, 0, sizeof(*tf)); 114 } 115 116 static int target_features_record_feature(DriverTargetFeatures* tf, 117 DriverEnv* env, KitSlice name, 118 int enabled) { 119 KitTargetFeature* f; 120 (void)env; 121 if (!name.s || name.len == 0) return 1; 122 if (tf->nfeatures >= tf->cap_features && target_features_grow(tf) != 0) 123 return 1; 124 f = &tf->features[tf->nfeatures++]; 125 f->name = name; 126 f->enabled = enabled ? true : false; 127 return 0; 128 } 129 130 static const char* target_features_pull_value(const char* tool, int argc, 131 char** argv, int* i, 132 size_t prefix_len, 133 const char* flag_label) { 134 const char* a = argv[*i]; 135 if (a[prefix_len]) return a + prefix_len; 136 if (++(*i) >= argc) { 137 driver_errf(tool, "%.*s requires an argument", 138 KIT_SLICE_ARG(kit_slice_cstr(flag_label))); 139 return NULL; 140 } 141 return argv[*i]; 142 } 143 144 static int target_features_parse_mattr(DriverTargetFeatures* tf, DriverEnv* env, 145 const char* tool, const char* list) { 146 const char* p = list; 147 if (!p || !*p) { 148 driver_errf(tool, "-mattr= requires a comma-separated feature list"); 149 return 1; 150 } 151 while (*p) { 152 int enabled; 153 const char* start; 154 if (*p == '+') { 155 enabled = 1; 156 } else if (*p == '-') { 157 enabled = 0; 158 } else { 159 driver_errf(tool, "-mattr entries must start with '+' or '-': %.*s", 160 KIT_SLICE_ARG(kit_slice_cstr(p))); 161 return 1; 162 } 163 ++p; 164 start = p; 165 while (*p && *p != ',') ++p; 166 if (p == start) { 167 driver_errf(tool, "empty -mattr feature"); 168 return 1; 169 } 170 if (target_features_record_feature( 171 tf, env, (KitSlice){.s = start, .len = (size_t)(p - start)}, 172 enabled) != 0) { 173 driver_errf(tool, "out of memory"); 174 return 1; 175 } 176 if (*p == ',') ++p; 177 } 178 return 0; 179 } 180 181 /* Map an ARM -mfpu= name onto the backend's VFP target features. `none` records 182 * nothing (soft-float). `fpv4-sp-d16` (Cortex-M4F) records `vfp`; `fpv5-d16` / 183 * `fpv5-sp-d16` (Cortex-M7) record `vfp`+`fpv5`. An unknown name is an error. 184 * The recorded features flow through opts->features[] into kit_target_new, where 185 * resolve_float_abi requires them for -mfloat-abi=hard/softfp and the 186 * feature_predefines hook keys __ARM_FP/__ARM_FPV5__ on them. */ 187 static int target_features_record_mfpu(DriverTargetFeatures* tf, DriverEnv* env, 188 const char* tool, const char* fpu) { 189 if (driver_streq(fpu, "none")) return 0; 190 if (driver_streq(fpu, "fpv4-sp-d16")) { 191 return target_features_record_feature(tf, env, KIT_SLICE_LIT("vfp"), 1) == 0 192 ? 0 193 : 1; 194 } 195 if (driver_streq(fpu, "fpv5-d16") || driver_streq(fpu, "fpv5-sp-d16")) { 196 if (target_features_record_feature(tf, env, KIT_SLICE_LIT("vfp"), 1) != 0) 197 return 1; 198 return target_features_record_feature(tf, env, KIT_SLICE_LIT("fpv5"), 1) == 0 199 ? 0 200 : 1; 201 } 202 driver_errf(tool, "-mfpu=%s is unsupported (none, fpv4-sp-d16, fpv5-d16, " 203 "fpv5-sp-d16)", 204 fpu); 205 return 1; 206 } 207 208 int driver_target_features_try_consume(DriverTargetFeatures* tf, DriverEnv* env, 209 const char* tool, int argc, char** argv, 210 int* i) { 211 const char* a = argv[*i]; 212 const char* v; 213 if (!tf || !a) return 0; 214 215 if (driver_strneq(a, "-mattr=", 7)) { 216 return target_features_parse_mattr(tf, env, tool, a + 7) == 0 ? 1 : -1; 217 } 218 if (driver_streq(a, "-mattr")) { 219 if (++(*i) >= argc) { 220 driver_errf(tool, "-mattr requires an argument"); 221 return -1; 222 } 223 return target_features_parse_mattr(tf, env, tool, argv[*i]) == 0 ? 1 : -1; 224 } 225 if (driver_strneq(a, "-mfeature=", 10) || 226 driver_strneq(a, "-mno-feature=", 13)) { 227 return 0; 228 } 229 if (driver_strneq(a, "-march=", 7)) { 230 tf->isa = kit_slice_cstr(a + 7); 231 return 1; 232 } 233 if (driver_streq(a, "-march")) { 234 if (++(*i) >= argc) { 235 driver_errf(tool, "-march requires an argument"); 236 return -1; 237 } 238 tf->isa = kit_slice_cstr(argv[*i]); 239 return 1; 240 } 241 if (driver_strneq(a, "-mabi=", 6)) { 242 tf->abi = kit_slice_cstr(a + 6); 243 return 1; 244 } 245 if (driver_streq(a, "-mabi")) { 246 if (++(*i) >= argc) { 247 driver_errf(tool, "-mabi requires an argument"); 248 return -1; 249 } 250 tf->abi = kit_slice_cstr(argv[*i]); 251 return 1; 252 } 253 if (driver_strneq(a, "-mcpu=", 6)) { 254 tf->cpu = kit_slice_cstr(a + 6); 255 return 1; 256 } 257 if (driver_streq(a, "-mcpu")) { 258 v = target_features_pull_value(tool, argc, argv, i, 5, "-mcpu"); 259 if (!v) return -1; 260 tf->cpu = kit_slice_cstr(v); 261 return 1; 262 } 263 if (driver_strneq(a, "-mtune=", 7)) { 264 tf->tune = kit_slice_cstr(a + 7); 265 return 1; 266 } 267 if (driver_streq(a, "-mtune")) { 268 v = target_features_pull_value(tool, argc, argv, i, 6, "-mtune"); 269 if (!v) return -1; 270 tf->tune = kit_slice_cstr(v); 271 return 1; 272 } 273 /* -mfloat-abi / -mfpu: ARM float-ABI selection. v1 supports soft-float only 274 * (FP via the AEABI helpers); the arch's resolve_float_abi pins float_abi to 275 * SOFT. Consume the flag here so it does not fall through to the generic 276 * -m<feature> recorder (which would reject "float-abi=soft" as an unknown 277 * feature). hard/softfp are a follow-on. -mfpu records the VFP target 278 * features so the FP-feature machinery (resolve_float_abi requiring vfp/fpv5, 279 * the __ARM_FP/__ARM_FPV5__ macros) is exercisable at the kit_target_new 280 * level, even though -mfloat-abi=hard/softfp is still rejected below. */ 281 if (driver_strneq(a, "-mfloat-abi=", 12)) { 282 if (!driver_streq(a + 12, "soft")) { 283 driver_errf(tool, 284 "-mfloat-abi=%s is unsupported (soft-float only; hard/softfp " 285 "are a follow-on)", 286 a + 12); 287 return -1; 288 } 289 return 1; 290 } 291 if (driver_streq(a, "-mfloat-abi")) { 292 v = target_features_pull_value(tool, argc, argv, i, 11, "-mfloat-abi"); 293 if (!v) return -1; 294 if (!driver_streq(v, "soft")) { 295 driver_errf(tool, 296 "-mfloat-abi %s is unsupported (soft-float only; hard/softfp " 297 "are a follow-on)", 298 v); 299 return -1; 300 } 301 return 1; 302 } 303 if (driver_strneq(a, "-mfpu=", 6)) 304 return target_features_record_mfpu(tf, env, tool, a + 6) == 0 ? 1 : -1; 305 if (driver_streq(a, "-mfpu")) { 306 v = target_features_pull_value(tool, argc, argv, i, 5, "-mfpu"); 307 if (!v) return -1; 308 return target_features_record_mfpu(tf, env, tool, v) == 0 ? 1 : -1; 309 } 310 if (driver_strneq(a, "-mno-", 5) && a[5] != '\0') { 311 if (target_features_record_feature(tf, env, kit_slice_cstr(a + 5), 0) != 312 0) { 313 driver_errf(tool, "out of memory"); 314 return -1; 315 } 316 return 1; 317 } 318 if (driver_strneq(a, "-m", 2) && a[2] != '\0') { 319 if (target_features_record_feature(tf, env, kit_slice_cstr(a + 2), 1) != 320 0) { 321 driver_errf(tool, "out of memory"); 322 return -1; 323 } 324 return 1; 325 } 326 return 0; 327 } 328 329 static int darwin_platform_set_arch(const char* tool, KitTargetSpec* target, 330 const char* arch) { 331 KitArchKind k; 332 uint8_t ptr_size; 333 if (!arch) { 334 driver_errf(tool, "-arch requires an argument"); 335 return 1; 336 } 337 if (driver_streq(arch, "arm64e")) arch = "arm64"; 338 if (driver_arch_from_name(arch, &k, &ptr_size) != 0) { 339 driver_errf(tool, "unsupported -arch value: %.*s", 340 KIT_SLICE_ARG(kit_slice_cstr(arch))); 341 return 1; 342 } 343 target->arch = k; 344 target->ptr_size = ptr_size; 345 target->ptr_align = ptr_size; 346 return 0; 347 } 348 349 static void darwin_platform_set_os(KitTargetSpec* target, const char* platform, 350 int pic_explicit) { 351 if (!platform) return; 352 if (driver_streq(platform, "macos")) { 353 target->os = KIT_OS_MACOS; 354 target->obj = KIT_OBJ_MACHO; 355 } else if (driver_streq(platform, "ios")) { 356 target->os = KIT_OS_IOS; 357 target->obj = KIT_OBJ_MACHO; 358 } else if (driver_streq(platform, "ios-simulator") || 359 driver_streq(platform, "iossimulator")) { 360 target->os = KIT_OS_IOS_SIMULATOR; 361 target->obj = KIT_OBJ_MACHO; 362 } else if (driver_streq(platform, "linux")) { 363 target->os = KIT_OS_LINUX; 364 target->obj = KIT_OBJ_ELF; 365 } else { 366 return; 367 } 368 if (!pic_explicit) target->pic = driver_default_pic(target->obj, target->os); 369 } 370 371 int driver_darwin_platform_try_consume(const char* tool, int argc, char** argv, 372 int* i, KitTargetSpec* target, 373 int pic_explicit) { 374 const char* a; 375 if (!argv || !i || !target || *i < 0 || *i >= argc) return 0; 376 a = argv[*i]; 377 if (driver_streq(a, "-arch")) { 378 if (++(*i) >= argc) { 379 driver_errf(tool, "-arch requires an argument"); 380 return -1; 381 } 382 return darwin_platform_set_arch(tool, target, argv[*i]) == 0 ? 1 : -1; 383 } 384 if (driver_streq(a, "-platform_version")) { 385 if (*i + 3 >= argc) { 386 driver_errf(tool, "-platform_version requires three arguments"); 387 return -1; 388 } 389 darwin_platform_set_os(target, argv[*i + 1], pic_explicit); 390 *i += 3; 391 return 1; 392 } 393 if (driver_streq(a, "-macosx_version_min")) { 394 if (++(*i) >= argc) { 395 driver_errf(tool, "-macosx_version_min requires an argument"); 396 return -1; 397 } 398 darwin_platform_set_os(target, "macos", pic_explicit); 399 return 1; 400 } 401 if (driver_streq(a, "-ios_version_min") || 402 driver_streq(a, "-iphoneos_version_min")) { 403 if (++(*i) >= argc) { 404 driver_errf(tool, "%s requires an argument", a); 405 return -1; 406 } 407 darwin_platform_set_os(target, "ios", pic_explicit); 408 return 1; 409 } 410 if (driver_streq(a, "-ios_simulator_version_min") || 411 driver_streq(a, "-iphonesimulator_version_min")) { 412 if (++(*i) >= argc) { 413 driver_errf(tool, "%s requires an argument", a); 414 return -1; 415 } 416 darwin_platform_set_os(target, "ios-simulator", pic_explicit); 417 return 1; 418 } 419 return 0; 420 } 421 422 int driver_target_options(const DriverTargetFeatures* tf, const char* tool, 423 KitTargetSpec target, KitTargetOptions* out) { 424 (void)tool; 425 if (!out) return 1; 426 memset(out, 0, sizeof(*out)); 427 out->spec = target; 428 if (!tf) return 0; 429 out->isa = tf->isa; 430 out->cpu = tf->cpu; 431 out->tune = tf->tune; 432 out->abi = tf->abi; 433 out->features = tf->features; 434 out->nfeatures = tf->nfeatures; 435 return 0; 436 } 437 438 KitStatus driver_target_new(const KitContext* ctx, KitTargetSpec target, 439 const DriverTargetFeatures* tf, const char* tool, 440 KitTarget** out) { 441 KitTargetOptions opts; 442 if (driver_target_options(tf, tool, target, &opts) != 0) { 443 if (out) *out = NULL; 444 return KIT_INVALID; 445 } 446 return kit_target_new(ctx, &opts, out); 447 } 448 449 int driver_target_from_triple(const char* triple, KitTargetSpec* out) { 450 return kit_target_from_triple(triple, out) ? 0 : 1; 451 } 452 453 int driver_target_to_triple(KitTargetSpec target, char* buf, size_t cap) { 454 return kit_target_to_triple(target, buf, cap) ? 0 : 1; 455 } 456 457 int driver_record_mcmodel(KitTargetSpec* target, const char* tool, 458 const char* val) { 459 KitCodeModel cm; 460 if (!kit_target_code_model_from_name(val, &cm)) { 461 driver_errf(tool, "unknown -mcmodel value: %.*s", 462 KIT_SLICE_ARG(kit_slice_cstr(val))); 463 return 1; 464 } 465 if (target) target->code_model = cm; 466 return 0; 467 }