kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

link_flags.c (30220B)


      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 =
     21       (const char**)driver_alloc_zeroed(lf->env, (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 * sizeof(*lf->owned_string_sizes));
     54     driver_free(lf->env, lf->owned_string_sizes,
     55                 (size_t)old_cap * sizeof(*lf->owned_string_sizes));
     56   }
     57   lf->owned_strings = ns;
     58   lf->owned_string_sizes = nsz;
     59   lf->cap_owned_strings = new_cap;
     60   return 0;
     61 }
     62 
     63 static int lf_take_owned(DriverLinkFlags* lf, char* s, size_t n) {
     64   if (lf->nowned_strings >= lf->cap_owned_strings && lf_grow_owned(lf) != 0)
     65     return 1;
     66   lf->owned_strings[lf->nowned_strings] = s;
     67   lf->owned_string_sizes[lf->nowned_strings] = n;
     68   lf->nowned_strings++;
     69   return 0;
     70 }
     71 
     72 static char* lf_dup_owned(DriverLinkFlags* lf, const char* s, size_t n) {
     73   size_t bytes = n + 1u;
     74   char* buf;
     75   if (bytes == 0) return NULL;
     76   buf = (char*)driver_alloc(lf->env, bytes);
     77   if (!buf) return NULL;
     78   driver_memcpy(buf, s, n);
     79   buf[n] = '\0';
     80   if (lf_take_owned(lf, buf, bytes) != 0) {
     81     driver_free(lf->env, buf, bytes);
     82     return NULL;
     83   }
     84   return buf;
     85 }
     86 
     87 static void lf_free_build_id(DriverLinkFlags* lf) {
     88   if (lf->build_id_bytes) {
     89     driver_free(lf->env, lf->build_id_bytes, lf->build_id_size);
     90     lf->build_id_bytes = NULL;
     91     lf->build_id_len = 0;
     92     lf->build_id_size = 0;
     93   }
     94 }
     95 
     96 static int lf_parse_hex_bytes(DriverLinkFlags* lf, const char* s, size_t n,
     97                               uint8_t** out_bytes, uint32_t* out_len,
     98                               size_t* out_size) {
     99   uint8_t* bs;
    100   size_t i;
    101   if (n == 0 || (n & 1u) || n / 2u > UINT32_MAX) return 1;
    102   bs = (uint8_t*)driver_alloc(lf->env, n / 2u);
    103   if (!bs) return 1;
    104   for (i = 0; i < n; i += 2u) {
    105     int hi = driver_hex_nibble(s[i]);
    106     int lo = driver_hex_nibble(s[i + 1u]);
    107     if (hi < 0 || lo < 0) {
    108       driver_free(lf->env, bs, n / 2u);
    109       return 1;
    110     }
    111     bs[i / 2u] = (uint8_t)((hi << 4) | lo);
    112   }
    113   *out_bytes = bs;
    114   *out_len = (uint32_t)(n / 2u);
    115   *out_size = n / 2u;
    116   return 0;
    117 }
    118 
    119 static int lf_record_build_id_span(DriverLinkFlags* lf, const char* val,
    120                                    size_t n) {
    121   if (n == 4 && driver_strneq(val, "none", 4)) {
    122     lf_free_build_id(lf);
    123     lf->build_id_mode = KIT_BUILDID_NONE;
    124     return 0;
    125   }
    126   if (n == 6 && driver_strneq(val, "sha256", 6)) {
    127     lf_free_build_id(lf);
    128     lf->build_id_mode = KIT_BUILDID_SHA256;
    129     return 0;
    130   }
    131   if (n == 4 && driver_strneq(val, "uuid", 4)) {
    132     lf_free_build_id(lf);
    133     lf->build_id_mode = KIT_BUILDID_UUID;
    134     return 0;
    135   }
    136   if (n >= 2 && driver_strneq(val, "0x", 2)) {
    137     uint8_t* bytes = NULL;
    138     uint32_t len = 0;
    139     size_t size = 0;
    140     if (lf_parse_hex_bytes(lf, val + 2, n - 2u, &bytes, &len, &size) != 0) {
    141       driver_errf(lf->tool,
    142                   "--build-id=0x... requires an even-length hex string");
    143       return 1;
    144     }
    145     lf_free_build_id(lf);
    146     lf->build_id_bytes = bytes;
    147     lf->build_id_len = len;
    148     lf->build_id_size = size;
    149     lf->build_id_mode = KIT_BUILDID_USER;
    150     return 0;
    151   }
    152   driver_errf(lf->tool, "unknown --build-id value: %.*s", (int)n, val);
    153   return 1;
    154 }
    155 
    156 static int lf_record_rpath(DriverLinkFlags* lf, const char* s, size_t n) {
    157   char* buf;
    158   if (lf->nrpaths >= lf->cap_rpaths && lf_grow_rpaths(lf) != 0) {
    159     driver_errf(lf->tool, "out of memory");
    160     return 1;
    161   }
    162   buf = lf_dup_owned(lf, s, n);
    163   if (!buf) {
    164     driver_errf(lf->tool, "out of memory");
    165     return 1;
    166   }
    167   lf->rpaths[lf->nrpaths++] = buf;
    168   return 0;
    169 }
    170 
    171 static int lf_record_soname(DriverLinkFlags* lf, const char* s, size_t n) {
    172   char* buf = lf_dup_owned(lf, s, n);
    173   if (!buf) {
    174     driver_errf(lf->tool, "out of memory");
    175     return 1;
    176   }
    177   lf->soname = buf;
    178   return 0;
    179 }
    180 
    181 static int lf_record_interp(DriverLinkFlags* lf, const char* s, size_t n) {
    182   char* buf = lf_dup_owned(lf, s, n);
    183   if (!buf) {
    184     driver_errf(lf->tool, "out of memory");
    185     return 1;
    186   }
    187   lf->interp_path = buf;
    188   return 0;
    189 }
    190 
    191 int driver_link_flags_record_entry(DriverLinkFlags* lf, const char* val,
    192                                    size_t n) {
    193   char* buf;
    194   if (!val || n == 0) {
    195     driver_errf(lf->tool, "--entry requires a non-empty symbol");
    196     return 1;
    197   }
    198   buf = lf_dup_owned(lf, val, n);
    199   if (!buf) {
    200     driver_errf(lf->tool, "out of memory");
    201     return 1;
    202   }
    203   lf->entry = buf;
    204   return 0;
    205 }
    206 
    207 int driver_link_flags_record_script(DriverLinkFlags* lf, const char* val,
    208                                     size_t n) {
    209   char* buf;
    210   if (!val || n == 0) {
    211     driver_errf(lf->tool, "--script requires a non-empty path");
    212     return 1;
    213   }
    214   buf = lf_dup_owned(lf, val, n);
    215   if (!buf) {
    216     driver_errf(lf->tool, "out of memory");
    217     return 1;
    218   }
    219   lf->linker_script = buf;
    220   return 0;
    221 }
    222 
    223 int driver_link_flags_record_map(DriverLinkFlags* lf, const char* val,
    224                                  size_t n) {
    225   char* buf;
    226   if (!val || n == 0) {
    227     driver_errf(lf->tool, "--map requires a non-empty path");
    228     return 1;
    229   }
    230   buf = lf_dup_owned(lf, val, n);
    231   if (!buf) {
    232     driver_errf(lf->tool, "out of memory");
    233     return 1;
    234   }
    235   lf->map_path = buf;
    236   return 0;
    237 }
    238 
    239 int driver_link_flags_record_symbols(DriverLinkFlags* lf, const char* val,
    240                                      size_t n) {
    241   char* buf;
    242   if (!val || n == 0) {
    243     driver_errf(lf->tool, "--symbols requires a non-empty path");
    244     return 1;
    245   }
    246   buf = lf_dup_owned(lf, val, n);
    247   if (!buf) {
    248     driver_errf(lf->tool, "out of memory");
    249     return 1;
    250   }
    251   lf->symbols_path = buf;
    252   return 0;
    253 }
    254 
    255 int driver_link_flags_record_symbols_format(DriverLinkFlags* lf,
    256                                             const char* val, size_t n) {
    257   if (n == 2 && driver_strneq(val, "nm", 2)) {
    258     lf->symbols_format = KIT_LINK_SYMBOLS_NM;
    259     return 0;
    260   }
    261   driver_errf(lf->tool, "unsupported --symbols-format: %.*s", (int)n, val);
    262   return 1;
    263 }
    264 
    265 int driver_link_flags_record_text_base(DriverLinkFlags* lf, const char* val) {
    266   uint64_t v;
    267   if (!val || driver_parse_u64(val, &v) != 0) {
    268     driver_errf(lf->tool, "-Ttext: invalid address: %s", val ? val : "");
    269     return 1;
    270   }
    271   lf->text_base = v;
    272   lf->text_base_set = 1;
    273   return 0;
    274 }
    275 
    276 /* Is this span a numeric (hex/dec) literal, or a symbol name? Used to decide
    277  * the --defsym RHS form. A literal starts with a digit (0x.. or decimal). */
    278 static int lf_span_is_number(const char* s, size_t n) {
    279   if (n == 0) return 0;
    280   return s[0] >= '0' && s[0] <= '9';
    281 }
    282 
    283 /* Parse a possibly-NUL-unterminated numeric span as u64. */
    284 static int lf_parse_u64_span(DriverLinkFlags* lf, const char* s, size_t n,
    285                              uint64_t* out) {
    286   char* buf = lf_dup_owned(lf, s, n);
    287   if (!buf) {
    288     driver_errf(lf->tool, "out of memory");
    289     return 1;
    290   }
    291   return driver_parse_u64(buf, out);
    292 }
    293 
    294 static int lf_grow_defsyms(DriverLinkFlags* lf) {
    295   uint32_t old_cap = lf->cap_defsyms;
    296   uint32_t new_cap = old_cap ? old_cap * 2u : 4u;
    297   KitLinkDefsym* nd;
    298   if (new_cap <= old_cap) return 1;
    299   nd = (KitLinkDefsym*)driver_alloc_zeroed(lf->env,
    300                                            (size_t)new_cap * sizeof(*nd));
    301   if (!nd) return 1;
    302   if (lf->defsyms) {
    303     driver_memcpy(nd, lf->defsyms, (size_t)lf->ndefsyms * sizeof(*lf->defsyms));
    304     driver_free(lf->env, lf->defsyms, (size_t)old_cap * sizeof(*lf->defsyms));
    305   }
    306   lf->defsyms = nd;
    307   lf->cap_defsyms = new_cap;
    308   return 0;
    309 }
    310 
    311 static int lf_grow_section_starts(DriverLinkFlags* lf) {
    312   uint32_t old_cap = lf->cap_section_starts;
    313   uint32_t new_cap = old_cap ? old_cap * 2u : 4u;
    314   KitLinkSectionStart* ns;
    315   if (new_cap <= old_cap) return 1;
    316   ns = (KitLinkSectionStart*)driver_alloc_zeroed(
    317       lf->env, (size_t)new_cap * sizeof(*ns));
    318   if (!ns) return 1;
    319   if (lf->section_starts) {
    320     driver_memcpy(ns, lf->section_starts,
    321                   (size_t)lf->nsection_starts * sizeof(*lf->section_starts));
    322     driver_free(lf->env, lf->section_starts,
    323                 (size_t)old_cap * sizeof(*lf->section_starts));
    324   }
    325   lf->section_starts = ns;
    326   lf->cap_section_starts = new_cap;
    327   return 0;
    328 }
    329 
    330 int driver_link_flags_record_defsym(DriverLinkFlags* lf, const char* val,
    331                                     size_t n) {
    332   size_t eq = 0;
    333   const char* name;
    334   size_t name_len;
    335   const char* rhs;
    336   size_t rhs_len;
    337   KitLinkDefsym* d;
    338   char* name_buf;
    339   while (eq < n && val[eq] != '=') ++eq;
    340   if (eq == 0 || eq >= n) {
    341     driver_errf(lf->tool, "--defsym requires NAME=EXPR: %.*s", (int)n, val);
    342     return 1;
    343   }
    344   name = val;
    345   name_len = eq;
    346   rhs = val + eq + 1u;
    347   rhs_len = n - eq - 1u;
    348   if (rhs_len == 0) {
    349     driver_errf(lf->tool, "--defsym requires a value: %.*s", (int)n, val);
    350     return 1;
    351   }
    352   if (lf->ndefsyms >= lf->cap_defsyms && lf_grow_defsyms(lf) != 0) {
    353     driver_errf(lf->tool, "out of memory");
    354     return 1;
    355   }
    356   name_buf = lf_dup_owned(lf, name, name_len);
    357   if (!name_buf) {
    358     driver_errf(lf->tool, "out of memory");
    359     return 1;
    360   }
    361   d = &lf->defsyms[lf->ndefsyms];
    362   memset(d, 0, sizeof(*d));
    363   d->name = kit_slice_cstr(name_buf);
    364   if (lf_span_is_number(rhs, rhs_len)) {
    365     uint64_t v;
    366     if (lf_parse_u64_span(lf, rhs, rhs_len, &v) != 0) {
    367       driver_errf(lf->tool, "--defsym: invalid value: %.*s", (int)rhs_len, rhs);
    368       return 1;
    369     }
    370     d->value = v;
    371   } else {
    372     char* alias_buf = lf_dup_owned(lf, rhs, rhs_len);
    373     if (!alias_buf) {
    374       driver_errf(lf->tool, "out of memory");
    375       return 1;
    376     }
    377     d->alias = kit_slice_cstr(alias_buf);
    378     d->value = 0;
    379   }
    380   lf->ndefsyms++;
    381   return 0;
    382 }
    383 
    384 int driver_link_flags_record_section_addr(DriverLinkFlags* lf,
    385                                           const char* secname,
    386                                           const char* addr) {
    387   uint64_t v;
    388   KitLinkSectionStart* ss;
    389   char* name_buf;
    390   if (!secname || !*secname || !addr || !*addr) {
    391     driver_errf(lf->tool, "--section-start requires .NAME=ADDR");
    392     return 1;
    393   }
    394   if (driver_parse_u64(addr, &v) != 0) {
    395     driver_errf(lf->tool, "--section-start: invalid address: %s", addr);
    396     return 1;
    397   }
    398   if (lf->nsection_starts >= lf->cap_section_starts &&
    399       lf_grow_section_starts(lf) != 0) {
    400     driver_errf(lf->tool, "out of memory");
    401     return 1;
    402   }
    403   name_buf = lf_dup_owned(lf, secname, driver_strlen(secname));
    404   if (!name_buf) {
    405     driver_errf(lf->tool, "out of memory");
    406     return 1;
    407   }
    408   ss = &lf->section_starts[lf->nsection_starts];
    409   memset(ss, 0, sizeof(*ss));
    410   ss->name = kit_slice_cstr(name_buf);
    411   ss->addr = v;
    412   lf->nsection_starts++;
    413   return 0;
    414 }
    415 
    416 int driver_link_flags_record_section_start(DriverLinkFlags* lf, const char* val,
    417                                            size_t n) {
    418   /* --section-start=.NAME=ADDR — split on the LAST '='. */
    419   size_t eq = n;
    420   size_t i;
    421   char* name_buf;
    422   char* addr_buf;
    423   int rc;
    424   for (i = 0; i < n; ++i)
    425     if (val[i] == '=') eq = i;
    426   if (eq == n || eq == 0) {
    427     driver_errf(lf->tool, "--section-start requires .NAME=ADDR: %.*s", (int)n,
    428                 val);
    429     return 1;
    430   }
    431   name_buf = lf_dup_owned(lf, val, eq);
    432   addr_buf = lf_dup_owned(lf, val + eq + 1u, n - eq - 1u);
    433   if (!name_buf || !addr_buf) {
    434     driver_errf(lf->tool, "out of memory");
    435     return 1;
    436   }
    437   rc = driver_link_flags_record_section_addr(lf, name_buf, addr_buf);
    438   return rc;
    439 }
    440 
    441 int driver_link_flags_record_orphan_handling(DriverLinkFlags* lf,
    442                                              const char* val, size_t n) {
    443   if (lf_tok_eq(val, n, "place")) {
    444     lf->orphan_handling = KIT_LINK_ORPHAN_PLACE;
    445     return 0;
    446   }
    447   if (lf_tok_eq(val, n, "warn")) {
    448     lf->orphan_handling = KIT_LINK_ORPHAN_WARN;
    449     return 0;
    450   }
    451   if (lf_tok_eq(val, n, "error")) {
    452     lf->orphan_handling = KIT_LINK_ORPHAN_ERROR;
    453     return 0;
    454   }
    455   if (lf_tok_eq(val, n, "discard")) {
    456     lf->orphan_handling = KIT_LINK_ORPHAN_DISCARD;
    457     return 0;
    458   }
    459   driver_errf(lf->tool, "unsupported --orphan-handling: %.*s", (int)n, val);
    460   return 1;
    461 }
    462 
    463 int driver_link_flags_record_cref(DriverLinkFlags* lf, const char* val,
    464                                   size_t n) {
    465   char* buf;
    466   if (!val || n == 0) {
    467     driver_errf(lf->tool, "--cref requires a non-empty path");
    468     return 1;
    469   }
    470   buf = lf_dup_owned(lf, val, n);
    471   if (!buf) {
    472     driver_errf(lf->tool, "out of memory");
    473     return 1;
    474   }
    475   lf->cref_path = buf;
    476   return 0;
    477 }
    478 
    479 int driver_link_flags_record_z(DriverLinkFlags* lf, const char* val, size_t n) {
    480   if (lf_tok_eq(val, n, "defs")) {
    481     lf->allow_undefined = 0;
    482     return 0;
    483   }
    484   if (lf_tok_eq(val, n, "nodefs")) {
    485     lf->allow_undefined = 1;
    486     return 0;
    487   }
    488   if (lf_tok_eq(val, n, "noexecstack") || lf_tok_eq(val, n, "relro") ||
    489       lf_tok_eq(val, n, "now") || lf_tok_eq(val, n, "text")) {
    490     return 0;
    491   }
    492   driver_errf(lf->tool, "unsupported -z option: %.*s", (int)n, val);
    493   return 1;
    494 }
    495 
    496 static int lf_subsystem_eq(const char* val, size_t n, const char* want) {
    497   size_t i;
    498   for (i = 0; want[i]; ++i) {
    499     char a;
    500     char b;
    501     if (i >= n) return 0;
    502     a = val[i];
    503     b = want[i];
    504     if (a >= 'a' && a <= 'z') a = (char)(a - 'a' + 'A');
    505     if (b >= 'a' && b <= 'z') b = (char)(b - 'a' + 'A');
    506     if (a != b) return 0;
    507   }
    508   return i == n || val[i] == ',';
    509 }
    510 
    511 int driver_link_flags_init(DriverLinkFlags* lf, DriverEnv* env,
    512                            const char* tool, uint32_t initial_cap) {
    513   uint32_t cap = initial_cap ? initial_cap : 8u;
    514   memset(lf, 0, sizeof(*lf));
    515   lf->env = env;
    516   lf->tool = tool;
    517   lf->new_dtags = 1;
    518   lf->cap_rpaths = cap;
    519   lf->cap_owned_strings = cap;
    520   lf->rpaths =
    521       (const char**)driver_alloc_zeroed(env, (size_t)cap * sizeof(*lf->rpaths));
    522   lf->owned_strings = (char**)driver_alloc_zeroed(
    523       env, (size_t)cap * sizeof(*lf->owned_strings));
    524   lf->owned_string_sizes = (size_t*)driver_alloc_zeroed(
    525       env, (size_t)cap * sizeof(*lf->owned_string_sizes));
    526   if (!lf->rpaths || !lf->owned_strings || !lf->owned_string_sizes) {
    527     driver_link_flags_fini(lf);
    528     return 1;
    529   }
    530   return 0;
    531 }
    532 
    533 void driver_link_flags_fini(DriverLinkFlags* lf) {
    534   uint32_t i;
    535   if (!lf || !lf->env) return;
    536   for (i = 0; i < lf->nowned_strings; ++i) {
    537     if (lf->owned_strings[i])
    538       driver_free(lf->env, lf->owned_strings[i], lf->owned_string_sizes[i]);
    539   }
    540   lf_free_build_id(lf);
    541   if (lf->rpaths)
    542     driver_free(lf->env, lf->rpaths,
    543                 (size_t)lf->cap_rpaths * sizeof(*lf->rpaths));
    544   if (lf->owned_strings)
    545     driver_free(lf->env, lf->owned_strings,
    546                 (size_t)lf->cap_owned_strings * sizeof(*lf->owned_strings));
    547   if (lf->owned_string_sizes)
    548     driver_free(
    549         lf->env, lf->owned_string_sizes,
    550         (size_t)lf->cap_owned_strings * sizeof(*lf->owned_string_sizes));
    551   if (lf->defsyms)
    552     driver_free(lf->env, lf->defsyms,
    553                 (size_t)lf->cap_defsyms * sizeof(*lf->defsyms));
    554   if (lf->section_starts)
    555     driver_free(lf->env, lf->section_starts,
    556                 (size_t)lf->cap_section_starts * sizeof(*lf->section_starts));
    557   memset(lf, 0, sizeof(*lf));
    558 }
    559 
    560 int driver_link_flags_record_build_id(DriverLinkFlags* lf, const char* val) {
    561   return lf_record_build_id_span(lf, val, driver_strlen(val));
    562 }
    563 
    564 int driver_link_flags_record_pe_subsystem(DriverLinkFlags* lf, const char* val,
    565                                           size_t n) {
    566   if (lf_subsystem_eq(val, n, "CONSOLE") || lf_subsystem_eq(val, n, "CUI")) {
    567     lf->pe_subsystem = KIT_PE_SUBSYSTEM_WINDOWS_CUI;
    568     return 0;
    569   }
    570   if (lf_subsystem_eq(val, n, "WINDOWS") || lf_subsystem_eq(val, n, "GUI")) {
    571     lf->pe_subsystem = KIT_PE_SUBSYSTEM_WINDOWS_GUI;
    572     return 0;
    573   }
    574   driver_errf(lf->tool, "unsupported subsystem: %.*s", (int)n, val);
    575   return 1;
    576 }
    577 
    578 int driver_link_flags_record_wl(DriverLinkFlags* lf, const char* arg) {
    579   const char* p = arg;
    580   int expect_rpath = 0;
    581   int expect_soname = 0;
    582   int expect_interp = 0;
    583   int expect_subsystem = 0;
    584   int expect_z = 0;
    585   int expect_map = 0;
    586   int expect_symbols = 0;
    587   int expect_ttext = 0;
    588   int expect_defsym = 0;
    589   int expect_section_start = 0;
    590   int expect_cref = 0;
    591   int expect_orphan = 0;
    592   int expect_entry = 0;
    593   int expect_script = 0;
    594   while (*p) {
    595     const char* tok = p;
    596     size_t n = 0;
    597     while (p[n] && p[n] != ',') ++n;
    598     p = tok + n + (tok[n] == ',' ? 1u : 0u);
    599 
    600     if (expect_rpath || expect_soname || expect_interp || expect_subsystem ||
    601         expect_z || expect_map || expect_symbols || expect_ttext ||
    602         expect_defsym || expect_section_start || expect_cref || expect_orphan ||
    603         expect_entry || expect_script) {
    604       int rc = 0;
    605       if (expect_rpath)
    606         rc = lf_record_rpath(lf, tok, n);
    607       else if (expect_soname)
    608         rc = lf_record_soname(lf, tok, n);
    609       else if (expect_interp)
    610         rc = lf_record_interp(lf, tok, n);
    611       else if (expect_subsystem)
    612         rc = driver_link_flags_record_pe_subsystem(lf, tok, n);
    613       else if (expect_z)
    614         rc = driver_link_flags_record_z(lf, tok, n);
    615       else if (expect_map)
    616         rc = driver_link_flags_record_map(lf, tok, n);
    617       else if (expect_symbols)
    618         rc = driver_link_flags_record_symbols(lf, tok, n);
    619       else if (expect_defsym)
    620         rc = driver_link_flags_record_defsym(lf, tok, n);
    621       else if (expect_section_start)
    622         rc = driver_link_flags_record_section_start(lf, tok, n);
    623       else if (expect_cref)
    624         rc = driver_link_flags_record_cref(lf, tok, n);
    625       else if (expect_orphan)
    626         rc = driver_link_flags_record_orphan_handling(lf, tok, n);
    627       else if (expect_entry)
    628         rc = driver_link_flags_record_entry(lf, tok, n);
    629       else if (expect_script)
    630         rc = driver_link_flags_record_script(lf, tok, n);
    631       else if (expect_ttext) {
    632         char* buf = lf_dup_owned(lf, tok, n);
    633         if (!buf) {
    634           driver_errf(lf->tool, "out of memory");
    635           return 1;
    636         }
    637         rc = driver_link_flags_record_text_base(lf, buf);
    638       }
    639       if (rc != 0) return 1;
    640       expect_rpath = expect_soname = expect_interp = expect_subsystem =
    641           expect_z = expect_map = expect_symbols = expect_ttext =
    642               expect_defsym = expect_section_start = expect_cref =
    643                   expect_orphan = expect_entry = expect_script = 0;
    644       continue;
    645     }
    646 
    647     if (lf_tok_eq(tok, n, "-e") || lf_tok_eq(tok, n, "--entry")) {
    648       expect_entry = 1;
    649       continue;
    650     }
    651     if (lf_tok_prefix(tok, n, "--entry=")) {
    652       if (driver_link_flags_record_entry(lf, tok + 8, n - 8u) != 0) return 1;
    653       continue;
    654     }
    655     if (n > 2 && tok[0] == '-' && tok[1] == 'e') {
    656       if (driver_link_flags_record_entry(lf, tok + 2, n - 2u) != 0) return 1;
    657       continue;
    658     }
    659     if (lf_tok_eq(tok, n, "-T") || lf_tok_eq(tok, n, "--script")) {
    660       expect_script = 1;
    661       continue;
    662     }
    663     if (lf_tok_prefix(tok, n, "--script=")) {
    664       if (driver_link_flags_record_script(lf, tok + 9, n - 9u) != 0) return 1;
    665       continue;
    666     }
    667     if (n > 2 && tok[0] == '-' && tok[1] == 'T' &&
    668         !lf_tok_prefix(tok, n, "-Ttext") &&
    669         !lf_tok_prefix(tok, n, "-Tdata") &&
    670         !lf_tok_prefix(tok, n, "-Tbss")) {
    671       if (driver_link_flags_record_script(lf, tok + 2, n - 2u) != 0) return 1;
    672       continue;
    673     }
    674 
    675     if (lf_tok_prefix(tok, n, "-soname=")) {
    676       if (lf_record_soname(lf, tok + 8, n - 8u) != 0) return 1;
    677       continue;
    678     }
    679     if (lf_tok_eq(tok, n, "-soname")) {
    680       expect_soname = 1;
    681       continue;
    682     }
    683     if (lf_tok_prefix(tok, n, "-rpath=")) {
    684       if (lf_record_rpath(lf, tok + 7, n - 7u) != 0) return 1;
    685       continue;
    686     }
    687     if (lf_tok_eq(tok, n, "-rpath")) {
    688       expect_rpath = 1;
    689       continue;
    690     }
    691     if (lf_tok_prefix(tok, n, "-dynamic-linker=")) {
    692       if (lf_record_interp(lf, tok + 16, n - 16u) != 0) return 1;
    693       continue;
    694     }
    695     if (lf_tok_eq(tok, n, "-dynamic-linker")) {
    696       expect_interp = 1;
    697       continue;
    698     }
    699     if (lf_tok_eq(tok, n, "--enable-new-dtags")) {
    700       lf->new_dtags = 1;
    701       continue;
    702     }
    703     if (lf_tok_eq(tok, n, "--disable-new-dtags")) {
    704       lf->new_dtags = 0;
    705       continue;
    706     }
    707     if (lf_tok_eq(tok, n, "--gc-sections")) {
    708       lf->gc_sections = 1;
    709       continue;
    710     }
    711     if (lf_tok_eq(tok, n, "--no-gc-sections")) {
    712       lf->gc_sections = 0;
    713       continue;
    714     }
    715     if (lf_tok_eq(tok, n, "-S") || lf_tok_eq(tok, n, "--strip-debug")) {
    716       lf->strip_debug = 1;
    717       continue;
    718     }
    719     if (lf_tok_eq(tok, n, "--no-undefined")) {
    720       lf->allow_undefined = 0;
    721       continue;
    722     }
    723     if (lf_tok_eq(tok, n, "--allow-undefined") ||
    724         lf_tok_eq(tok, n, "--allow-shlib-undefined")) {
    725       lf->allow_undefined = 1;
    726       continue;
    727     }
    728     if (lf_tok_eq(tok, n, "-z")) {
    729       expect_z = 1;
    730       continue;
    731     }
    732     if (n > 2 && tok[0] == '-' && tok[1] == 'z') {
    733       if (driver_link_flags_record_z(lf, tok + 2, n - 2u) != 0) return 1;
    734       continue;
    735     }
    736     if (lf_tok_eq(tok, n, "-Ttext")) {
    737       expect_ttext = 1;
    738       continue;
    739     }
    740     if (lf_tok_prefix(tok, n, "-Ttext=")) {
    741       char* buf = lf_dup_owned(lf, tok + 7, n - 7u);
    742       if (!buf) {
    743         driver_errf(lf->tool, "out of memory");
    744         return 1;
    745       }
    746       if (driver_link_flags_record_text_base(lf, buf) != 0) return 1;
    747       continue;
    748     }
    749     if (lf_tok_eq(tok, n, "--map") || lf_tok_eq(tok, n, "-Map")) {
    750       expect_map = 1;
    751       continue;
    752     }
    753     if (lf_tok_prefix(tok, n, "--map=")) {
    754       if (driver_link_flags_record_map(lf, tok + 6, n - 6u) != 0) return 1;
    755       continue;
    756     }
    757     if (lf_tok_prefix(tok, n, "-Map=")) {
    758       if (driver_link_flags_record_map(lf, tok + 5, n - 5u) != 0) return 1;
    759       continue;
    760     }
    761     if (lf_tok_eq(tok, n, "--symbols")) {
    762       expect_symbols = 1;
    763       continue;
    764     }
    765     if (lf_tok_prefix(tok, n, "--symbols=")) {
    766       if (driver_link_flags_record_symbols(lf, tok + 10, n - 10u) != 0)
    767         return 1;
    768       continue;
    769     }
    770     if (lf_tok_prefix(tok, n, "--symbols-format=")) {
    771       if (driver_link_flags_record_symbols_format(lf, tok + 17, n - 17u) != 0)
    772         return 1;
    773       continue;
    774     }
    775     if (lf_tok_prefix(tok, n, "--build-id=")) {
    776       if (lf_record_build_id_span(lf, tok + 11, n - 11u) != 0) return 1;
    777       continue;
    778     }
    779     if (lf_tok_eq(tok, n, "--build-id")) {
    780       lf_free_build_id(lf);
    781       lf->build_id_mode = KIT_BUILDID_SHA256;
    782       continue;
    783     }
    784     if (lf_tok_prefix(tok, n, "--subsystem=")) {
    785       if (driver_link_flags_record_pe_subsystem(lf, tok + 12, n - 12u) != 0)
    786         return 1;
    787       continue;
    788     }
    789     if (lf_tok_eq(tok, n, "--subsystem")) {
    790       expect_subsystem = 1;
    791       continue;
    792     }
    793     if (lf_tok_prefix(tok, n, "/SUBSYSTEM:")) {
    794       if (driver_link_flags_record_pe_subsystem(lf, tok + 11, n - 11u) != 0)
    795         return 1;
    796       continue;
    797     }
    798     /* -Tdata / -Tbss: section base overrides, folded into section_starts. */
    799     if (lf_tok_eq(tok, n, "-Tdata") || lf_tok_eq(tok, n, "-Tbss")) {
    800       /* The next comma token is the address. Reuse the section-start consume
    801        * via a synthesized ".data=ADDR" / ".bss=ADDR" on the following token;
    802        * simplest is a dedicated tiny state, but section_start expects NAME=ADDR.
    803        * Stash the chosen section name and read the address as a fresh token. */
    804       const char* secname = lf_tok_eq(tok, n, "-Tdata") ? ".data" : ".bss";
    805       const char* atok = p;
    806       size_t an = 0;
    807       char* addr_buf;
    808       if (!*atok) {
    809         driver_errf(lf->tool, "%.*s requires an address", (int)n, tok);
    810         return 1;
    811       }
    812       while (atok[an] && atok[an] != ',') ++an;
    813       p = atok + an + (atok[an] == ',' ? 1u : 0u);
    814       addr_buf = lf_dup_owned(lf, atok, an);
    815       if (!addr_buf) {
    816         driver_errf(lf->tool, "out of memory");
    817         return 1;
    818       }
    819       if (driver_link_flags_record_section_addr(lf, secname, addr_buf) != 0)
    820         return 1;
    821       continue;
    822     }
    823     if (lf_tok_prefix(tok, n, "-Tdata=")) {
    824       char* addr_buf = lf_dup_owned(lf, tok + 7, n - 7u);
    825       if (!addr_buf) {
    826         driver_errf(lf->tool, "out of memory");
    827         return 1;
    828       }
    829       if (driver_link_flags_record_section_addr(lf, ".data", addr_buf) != 0)
    830         return 1;
    831       continue;
    832     }
    833     if (lf_tok_prefix(tok, n, "-Tbss=")) {
    834       char* addr_buf = lf_dup_owned(lf, tok + 6, n - 6u);
    835       if (!addr_buf) {
    836         driver_errf(lf->tool, "out of memory");
    837         return 1;
    838       }
    839       if (driver_link_flags_record_section_addr(lf, ".bss", addr_buf) != 0)
    840         return 1;
    841       continue;
    842     }
    843     /* --defsym NAME=EXPR */
    844     if (lf_tok_prefix(tok, n, "--defsym=")) {
    845       if (driver_link_flags_record_defsym(lf, tok + 9, n - 9u) != 0) return 1;
    846       continue;
    847     }
    848     if (lf_tok_eq(tok, n, "--defsym")) {
    849       expect_defsym = 1;
    850       continue;
    851     }
    852     /* --section-start=.NAME=ADDR */
    853     if (lf_tok_prefix(tok, n, "--section-start=")) {
    854       if (driver_link_flags_record_section_start(lf, tok + 16, n - 16u) != 0)
    855         return 1;
    856       continue;
    857     }
    858     if (lf_tok_eq(tok, n, "--section-start")) {
    859       expect_section_start = 1;
    860       continue;
    861     }
    862     /* --cref [FILE] */
    863     if (lf_tok_prefix(tok, n, "--cref=")) {
    864       if (driver_link_flags_record_cref(lf, tok + 7, n - 7u) != 0) return 1;
    865       continue;
    866     }
    867     if (lf_tok_eq(tok, n, "--cref")) {
    868       expect_cref = 1;
    869       continue;
    870     }
    871     /* --orphan-handling=MODE */
    872     if (lf_tok_prefix(tok, n, "--orphan-handling=")) {
    873       if (driver_link_flags_record_orphan_handling(lf, tok + 18, n - 18u) != 0)
    874         return 1;
    875       continue;
    876     }
    877     if (lf_tok_eq(tok, n, "--orphan-handling")) {
    878       expect_orphan = 1;
    879       continue;
    880     }
    881     if (lf_tok_eq(tok, n, "--fatal-warnings")) {
    882       lf->fatal_warnings = 1;
    883       continue;
    884     }
    885     if (lf_tok_eq(tok, n, "--no-fatal-warnings")) {
    886       lf->fatal_warnings = 0;
    887       continue;
    888     }
    889     if (lf_tok_eq(tok, n, "--print-memory-usage")) {
    890       lf->print_memory_usage = 1;
    891       continue;
    892     }
    893 
    894     driver_errf(lf->tool, "unsupported -Wl, token: %.*s", (int)n, tok);
    895     return 1;
    896   }
    897   if (expect_rpath || expect_soname || expect_interp || expect_subsystem ||
    898       expect_z || expect_map || expect_symbols || expect_ttext ||
    899       expect_defsym || expect_section_start || expect_cref || expect_orphan ||
    900       expect_entry || expect_script) {
    901     driver_errf(lf->tool, "-Wl option requires another comma argument");
    902     return 1;
    903   }
    904   return 0;
    905 }
    906 
    907 int driver_link_flags_fill_options(const DriverLinkFlags* lf,
    908                                    KitTargetSpec target, int explicit_pie,
    909                                    int shared, int relocatable,
    910                                    uint8_t output_kind,
    911                                    const KitLinkScript* script,
    912                                    KitLinkSessionOptions* lopts,
    913                                    KitSlice** rpath_slices_out) {
    914   KitSlice* rpath_slices = NULL;
    915   uint32_t i;
    916   *rpath_slices_out = NULL;
    917   if (lf->nrpaths) {
    918     rpath_slices = (KitSlice*)driver_alloc_zeroed(
    919         lf->env, (size_t)lf->nrpaths * sizeof(*rpath_slices));
    920     if (!rpath_slices) {
    921       driver_errf(lf->tool, "out of memory");
    922       return 1;
    923     }
    924     for (i = 0; i < lf->nrpaths; ++i)
    925       rpath_slices[i] = kit_slice_cstr(lf->rpaths[i]);
    926   }
    927   memset(lopts, 0, sizeof(*lopts));
    928   lopts->output_kind = output_kind;
    929   lopts->entry = kit_slice_cstr(lf->entry);
    930   lopts->linker_script = script;
    931   lopts->build_id_mode = lf->build_id_mode;
    932   lopts->build_id_bytes = lf->build_id_bytes;
    933   lopts->build_id_len = lf->build_id_len;
    934   lopts->gc_sections = lf->gc_sections != 0;
    935   lopts->strip_debug = lf->strip_debug != 0;
    936   lopts->text_base_set = lf->text_base_set != 0;
    937   lopts->text_base = lf->text_base;
    938   lopts->defsyms = lf->defsyms;
    939   lopts->ndefsyms = lf->ndefsyms;
    940   lopts->section_starts = lf->section_starts;
    941   lopts->nsection_starts = lf->nsection_starts;
    942   lopts->orphan_handling = lf->orphan_handling;
    943   lopts->fatal_warnings = lf->fatal_warnings != 0;
    944   lopts->pie = driver_link_pie(target, explicit_pie, shared, relocatable) != 0;
    945   lopts->pe_subsystem = lf->pe_subsystem;
    946   lopts->interp_path = kit_slice_cstr(lf->interp_path);
    947   lopts->soname = kit_slice_cstr(lf->soname);
    948   if (lf->new_dtags) {
    949     lopts->runpaths = rpath_slices;
    950     lopts->nrunpaths = lf->nrpaths;
    951   } else {
    952     lopts->rpaths = rpath_slices;
    953     lopts->nrpaths = lf->nrpaths;
    954   }
    955   lopts->allow_undefined = lf->allow_undefined != 0;
    956   *rpath_slices_out = rpath_slices;
    957   return 0;
    958 }
    959 
    960 void driver_link_flags_free_rpath_slices(const DriverLinkFlags* lf,
    961                                          KitSlice* rpath_slices) {
    962   if (rpath_slices)
    963     driver_free(lf->env, rpath_slices,
    964                 (size_t)lf->nrpaths * sizeof(*rpath_slices));
    965 }