link_flags.c (13553B)
1 #include "link_flags.h" 2 3 #include <string.h> 4 5 static int lf_tok_eq(const char* tok, size_t n, const char* lit) { 6 size_t ln = driver_strlen(lit); 7 return n == ln && driver_strneq(tok, lit, ln); 8 } 9 10 static int lf_tok_prefix(const char* tok, size_t n, const char* lit) { 11 size_t ln = driver_strlen(lit); 12 return n >= ln && driver_strneq(tok, lit, ln); 13 } 14 15 static int lf_grow_rpaths(DriverLinkFlags* lf) { 16 uint32_t old_cap = lf->cap_rpaths; 17 uint32_t new_cap = old_cap ? old_cap * 2u : 8u; 18 const char** nr; 19 if (new_cap <= old_cap) return 1; 20 nr = (const char**)driver_alloc_zeroed(lf->env, 21 (size_t)new_cap * sizeof(*nr)); 22 if (!nr) return 1; 23 if (lf->rpaths) { 24 driver_memcpy(nr, lf->rpaths, (size_t)lf->nrpaths * sizeof(*lf->rpaths)); 25 driver_free(lf->env, lf->rpaths, (size_t)old_cap * sizeof(*lf->rpaths)); 26 } 27 lf->rpaths = nr; 28 lf->cap_rpaths = new_cap; 29 return 0; 30 } 31 32 static int lf_grow_owned(DriverLinkFlags* lf) { 33 uint32_t old_cap = lf->cap_owned_strings; 34 uint32_t new_cap = old_cap ? old_cap * 2u : 8u; 35 char** ns; 36 size_t* nsz; 37 if (new_cap <= old_cap) return 1; 38 ns = (char**)driver_alloc_zeroed(lf->env, (size_t)new_cap * sizeof(*ns)); 39 nsz = (size_t*)driver_alloc_zeroed(lf->env, (size_t)new_cap * sizeof(*nsz)); 40 if (!ns || !nsz) { 41 if (ns) driver_free(lf->env, ns, (size_t)new_cap * sizeof(*ns)); 42 if (nsz) driver_free(lf->env, nsz, (size_t)new_cap * sizeof(*nsz)); 43 return 1; 44 } 45 if (lf->owned_strings) { 46 driver_memcpy(ns, lf->owned_strings, 47 (size_t)lf->nowned_strings * sizeof(*lf->owned_strings)); 48 driver_free(lf->env, lf->owned_strings, 49 (size_t)old_cap * sizeof(*lf->owned_strings)); 50 } 51 if (lf->owned_string_sizes) { 52 driver_memcpy(nsz, lf->owned_string_sizes, 53 (size_t)lf->nowned_strings * 54 sizeof(*lf->owned_string_sizes)); 55 driver_free(lf->env, lf->owned_string_sizes, 56 (size_t)old_cap * sizeof(*lf->owned_string_sizes)); 57 } 58 lf->owned_strings = ns; 59 lf->owned_string_sizes = nsz; 60 lf->cap_owned_strings = new_cap; 61 return 0; 62 } 63 64 static int lf_take_owned(DriverLinkFlags* lf, char* s, size_t n) { 65 if (lf->nowned_strings >= lf->cap_owned_strings && lf_grow_owned(lf) != 0) 66 return 1; 67 lf->owned_strings[lf->nowned_strings] = s; 68 lf->owned_string_sizes[lf->nowned_strings] = n; 69 lf->nowned_strings++; 70 return 0; 71 } 72 73 static char* lf_dup_owned(DriverLinkFlags* lf, const char* s, size_t n) { 74 size_t bytes = n + 1u; 75 char* buf; 76 if (bytes == 0) return NULL; 77 buf = (char*)driver_alloc(lf->env, bytes); 78 if (!buf) return NULL; 79 driver_memcpy(buf, s, n); 80 buf[n] = '\0'; 81 if (lf_take_owned(lf, buf, bytes) != 0) { 82 driver_free(lf->env, buf, bytes); 83 return NULL; 84 } 85 return buf; 86 } 87 88 static void lf_free_build_id(DriverLinkFlags* lf) { 89 if (lf->build_id_bytes) { 90 driver_free(lf->env, lf->build_id_bytes, lf->build_id_size); 91 lf->build_id_bytes = NULL; 92 lf->build_id_len = 0; 93 lf->build_id_size = 0; 94 } 95 } 96 97 static int lf_hex_val(char c, unsigned* out) { 98 if (c >= '0' && c <= '9') { 99 *out = (unsigned)(c - '0'); 100 return 0; 101 } 102 if (c >= 'a' && c <= 'f') { 103 *out = (unsigned)(c - 'a' + 10); 104 return 0; 105 } 106 if (c >= 'A' && c <= 'F') { 107 *out = (unsigned)(c - 'A' + 10); 108 return 0; 109 } 110 return 1; 111 } 112 113 static int lf_parse_hex_bytes(DriverLinkFlags* lf, const char* s, size_t n, 114 uint8_t** out_bytes, uint32_t* out_len, 115 size_t* out_size) { 116 uint8_t* bs; 117 size_t i; 118 if (n == 0 || (n & 1u) || n / 2u > UINT32_MAX) return 1; 119 bs = (uint8_t*)driver_alloc(lf->env, n / 2u); 120 if (!bs) return 1; 121 for (i = 0; i < n; i += 2u) { 122 unsigned hi, lo; 123 if (lf_hex_val(s[i], &hi) != 0 || lf_hex_val(s[i + 1u], &lo) != 0) { 124 driver_free(lf->env, bs, n / 2u); 125 return 1; 126 } 127 bs[i / 2u] = (uint8_t)((hi << 4) | lo); 128 } 129 *out_bytes = bs; 130 *out_len = (uint32_t)(n / 2u); 131 *out_size = n / 2u; 132 return 0; 133 } 134 135 static int lf_record_build_id_span(DriverLinkFlags* lf, const char* val, 136 size_t n) { 137 if (n == 4 && driver_strneq(val, "none", 4)) { 138 lf_free_build_id(lf); 139 lf->build_id_mode = KIT_BUILDID_NONE; 140 return 0; 141 } 142 if (n == 6 && driver_strneq(val, "sha256", 6)) { 143 lf_free_build_id(lf); 144 lf->build_id_mode = KIT_BUILDID_SHA256; 145 return 0; 146 } 147 if (n == 4 && driver_strneq(val, "uuid", 4)) { 148 lf_free_build_id(lf); 149 lf->build_id_mode = KIT_BUILDID_UUID; 150 return 0; 151 } 152 if (n >= 2 && driver_strneq(val, "0x", 2)) { 153 uint8_t* bytes = NULL; 154 uint32_t len = 0; 155 size_t size = 0; 156 if (lf_parse_hex_bytes(lf, val + 2, n - 2u, &bytes, &len, &size) != 0) { 157 driver_errf(lf->tool, 158 "--build-id=0x... requires an even-length hex string"); 159 return 1; 160 } 161 lf_free_build_id(lf); 162 lf->build_id_bytes = bytes; 163 lf->build_id_len = len; 164 lf->build_id_size = size; 165 lf->build_id_mode = KIT_BUILDID_USER; 166 return 0; 167 } 168 driver_errf(lf->tool, "unknown --build-id value: %.*s", (int)n, val); 169 return 1; 170 } 171 172 static int lf_record_rpath(DriverLinkFlags* lf, const char* s, size_t n) { 173 char* buf; 174 if (lf->nrpaths >= lf->cap_rpaths && lf_grow_rpaths(lf) != 0) { 175 driver_errf(lf->tool, "out of memory"); 176 return 1; 177 } 178 buf = lf_dup_owned(lf, s, n); 179 if (!buf) { 180 driver_errf(lf->tool, "out of memory"); 181 return 1; 182 } 183 lf->rpaths[lf->nrpaths++] = buf; 184 return 0; 185 } 186 187 static int lf_record_soname(DriverLinkFlags* lf, const char* s, size_t n) { 188 char* buf = lf_dup_owned(lf, s, n); 189 if (!buf) { 190 driver_errf(lf->tool, "out of memory"); 191 return 1; 192 } 193 lf->soname = buf; 194 return 0; 195 } 196 197 static int lf_record_interp(DriverLinkFlags* lf, const char* s, size_t n) { 198 char* buf = lf_dup_owned(lf, s, n); 199 if (!buf) { 200 driver_errf(lf->tool, "out of memory"); 201 return 1; 202 } 203 lf->interp_path = buf; 204 return 0; 205 } 206 207 static int lf_subsystem_eq(const char* val, size_t n, const char* want) { 208 size_t i; 209 for (i = 0; want[i]; ++i) { 210 char a; 211 char b; 212 if (i >= n) return 0; 213 a = val[i]; 214 b = want[i]; 215 if (a >= 'a' && a <= 'z') a = (char)(a - 'a' + 'A'); 216 if (b >= 'a' && b <= 'z') b = (char)(b - 'a' + 'A'); 217 if (a != b) return 0; 218 } 219 return i == n || val[i] == ','; 220 } 221 222 int driver_link_flags_init(DriverLinkFlags* lf, DriverEnv* env, 223 const char* tool, uint32_t initial_cap) { 224 uint32_t cap = initial_cap ? initial_cap : 8u; 225 memset(lf, 0, sizeof(*lf)); 226 lf->env = env; 227 lf->tool = tool; 228 lf->new_dtags = 1; 229 lf->cap_rpaths = cap; 230 lf->cap_owned_strings = cap; 231 lf->rpaths = 232 (const char**)driver_alloc_zeroed(env, (size_t)cap * sizeof(*lf->rpaths)); 233 lf->owned_strings = 234 (char**)driver_alloc_zeroed(env, (size_t)cap * sizeof(*lf->owned_strings)); 235 lf->owned_string_sizes = (size_t*)driver_alloc_zeroed( 236 env, (size_t)cap * sizeof(*lf->owned_string_sizes)); 237 if (!lf->rpaths || !lf->owned_strings || !lf->owned_string_sizes) { 238 driver_link_flags_fini(lf); 239 return 1; 240 } 241 return 0; 242 } 243 244 void driver_link_flags_fini(DriverLinkFlags* lf) { 245 uint32_t i; 246 if (!lf || !lf->env) return; 247 for (i = 0; i < lf->nowned_strings; ++i) { 248 if (lf->owned_strings[i]) 249 driver_free(lf->env, lf->owned_strings[i], lf->owned_string_sizes[i]); 250 } 251 lf_free_build_id(lf); 252 if (lf->rpaths) 253 driver_free(lf->env, lf->rpaths, 254 (size_t)lf->cap_rpaths * sizeof(*lf->rpaths)); 255 if (lf->owned_strings) 256 driver_free(lf->env, lf->owned_strings, 257 (size_t)lf->cap_owned_strings * sizeof(*lf->owned_strings)); 258 if (lf->owned_string_sizes) 259 driver_free(lf->env, lf->owned_string_sizes, 260 (size_t)lf->cap_owned_strings * 261 sizeof(*lf->owned_string_sizes)); 262 memset(lf, 0, sizeof(*lf)); 263 } 264 265 int driver_link_flags_record_build_id(DriverLinkFlags* lf, const char* val) { 266 return lf_record_build_id_span(lf, val, driver_strlen(val)); 267 } 268 269 int driver_link_flags_record_pe_subsystem(DriverLinkFlags* lf, 270 const char* val, size_t n) { 271 if (lf_subsystem_eq(val, n, "CONSOLE") || 272 lf_subsystem_eq(val, n, "CUI")) { 273 lf->pe_subsystem = KIT_PE_SUBSYSTEM_WINDOWS_CUI; 274 return 0; 275 } 276 if (lf_subsystem_eq(val, n, "WINDOWS") || 277 lf_subsystem_eq(val, n, "GUI")) { 278 lf->pe_subsystem = KIT_PE_SUBSYSTEM_WINDOWS_GUI; 279 return 0; 280 } 281 driver_errf(lf->tool, "unsupported subsystem: %.*s", (int)n, val); 282 return 1; 283 } 284 285 int driver_link_flags_record_wl(DriverLinkFlags* lf, const char* arg) { 286 const char* p = arg; 287 int expect_rpath = 0; 288 int expect_soname = 0; 289 int expect_interp = 0; 290 int expect_subsystem = 0; 291 while (*p) { 292 const char* tok = p; 293 size_t n = 0; 294 while (p[n] && p[n] != ',') ++n; 295 p = tok + n + (tok[n] == ',' ? 1u : 0u); 296 297 if (expect_rpath || expect_soname || expect_interp || expect_subsystem) { 298 int rc = 0; 299 if (expect_rpath) 300 rc = lf_record_rpath(lf, tok, n); 301 else if (expect_soname) 302 rc = lf_record_soname(lf, tok, n); 303 else if (expect_interp) 304 rc = lf_record_interp(lf, tok, n); 305 else if (expect_subsystem) 306 rc = driver_link_flags_record_pe_subsystem(lf, tok, n); 307 if (rc != 0) return 1; 308 expect_rpath = expect_soname = expect_interp = expect_subsystem = 0; 309 continue; 310 } 311 312 if (lf_tok_prefix(tok, n, "-soname=")) { 313 if (lf_record_soname(lf, tok + 8, n - 8u) != 0) return 1; 314 continue; 315 } 316 if (lf_tok_eq(tok, n, "-soname")) { 317 expect_soname = 1; 318 continue; 319 } 320 if (lf_tok_prefix(tok, n, "-rpath=")) { 321 if (lf_record_rpath(lf, tok + 7, n - 7u) != 0) return 1; 322 continue; 323 } 324 if (lf_tok_eq(tok, n, "-rpath")) { 325 expect_rpath = 1; 326 continue; 327 } 328 if (lf_tok_prefix(tok, n, "-dynamic-linker=")) { 329 if (lf_record_interp(lf, tok + 16, n - 16u) != 0) return 1; 330 continue; 331 } 332 if (lf_tok_eq(tok, n, "-dynamic-linker")) { 333 expect_interp = 1; 334 continue; 335 } 336 if (lf_tok_eq(tok, n, "--enable-new-dtags")) { 337 lf->new_dtags = 1; 338 continue; 339 } 340 if (lf_tok_eq(tok, n, "--disable-new-dtags")) { 341 lf->new_dtags = 0; 342 continue; 343 } 344 if (lf_tok_eq(tok, n, "--gc-sections")) { 345 lf->gc_sections = 1; 346 continue; 347 } 348 if (lf_tok_eq(tok, n, "--no-gc-sections")) { 349 lf->gc_sections = 0; 350 continue; 351 } 352 if (lf_tok_eq(tok, n, "-S") || lf_tok_eq(tok, n, "--strip-debug")) { 353 lf->strip_debug = 1; 354 continue; 355 } 356 if (lf_tok_prefix(tok, n, "--build-id=")) { 357 if (lf_record_build_id_span(lf, tok + 11, n - 11u) != 0) return 1; 358 continue; 359 } 360 if (lf_tok_eq(tok, n, "--build-id")) { 361 lf_free_build_id(lf); 362 lf->build_id_mode = KIT_BUILDID_SHA256; 363 continue; 364 } 365 if (lf_tok_prefix(tok, n, "--subsystem=")) { 366 if (driver_link_flags_record_pe_subsystem(lf, tok + 12, n - 12u) != 0) 367 return 1; 368 continue; 369 } 370 if (lf_tok_eq(tok, n, "--subsystem")) { 371 expect_subsystem = 1; 372 continue; 373 } 374 if (lf_tok_prefix(tok, n, "/SUBSYSTEM:")) { 375 if (driver_link_flags_record_pe_subsystem(lf, tok + 11, n - 11u) != 0) 376 return 1; 377 continue; 378 } 379 380 driver_errf(lf->tool, "unsupported -Wl, token: %.*s", (int)n, tok); 381 return 1; 382 } 383 if (expect_rpath || expect_soname || expect_interp || expect_subsystem) { 384 driver_errf(lf->tool, "-Wl option requires another comma argument"); 385 return 1; 386 } 387 return 0; 388 } 389 390 int driver_link_flags_fill_options(const DriverLinkFlags* lf, 391 KitTargetSpec target, int explicit_pie, 392 int shared, int relocatable, 393 uint8_t output_kind, 394 const KitLinkScript* script, 395 KitLinkSessionOptions* lopts, 396 KitSlice** rpath_slices_out) { 397 KitSlice* rpath_slices = NULL; 398 uint32_t i; 399 *rpath_slices_out = NULL; 400 if (lf->nrpaths) { 401 rpath_slices = (KitSlice*)driver_alloc_zeroed( 402 lf->env, (size_t)lf->nrpaths * sizeof(*rpath_slices)); 403 if (!rpath_slices) { 404 driver_errf(lf->tool, "out of memory"); 405 return 1; 406 } 407 for (i = 0; i < lf->nrpaths; ++i) 408 rpath_slices[i] = kit_slice_cstr(lf->rpaths[i]); 409 } 410 memset(lopts, 0, sizeof(*lopts)); 411 lopts->output_kind = output_kind; 412 lopts->entry = kit_slice_cstr(lf->entry); 413 lopts->linker_script = script; 414 lopts->build_id_mode = lf->build_id_mode; 415 lopts->build_id_bytes = lf->build_id_bytes; 416 lopts->build_id_len = lf->build_id_len; 417 lopts->gc_sections = lf->gc_sections != 0; 418 lopts->strip_debug = lf->strip_debug != 0; 419 lopts->pie = 420 driver_link_pie(target, explicit_pie, shared, relocatable) != 0; 421 lopts->pe_subsystem = lf->pe_subsystem; 422 lopts->interp_path = kit_slice_cstr(lf->interp_path); 423 lopts->soname = kit_slice_cstr(lf->soname); 424 if (lf->new_dtags) { 425 lopts->runpaths = rpath_slices; 426 lopts->nrunpaths = lf->nrpaths; 427 } else { 428 lopts->rpaths = rpath_slices; 429 lopts->nrpaths = lf->nrpaths; 430 } 431 lopts->allow_undefined = 1; 432 *rpath_slices_out = rpath_slices; 433 return 0; 434 } 435 436 void driver_link_flags_free_rpath_slices(const DriverLinkFlags* lf, 437 KitSlice* rpath_slices) { 438 if (rpath_slices) 439 driver_free(lf->env, rpath_slices, 440 (size_t)lf->nrpaths * sizeof(*rpath_slices)); 441 }