kit

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

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 }