kit

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

elf_version_import_test.c (4212B)


      1 /* ELF explicit-version import resolution.
      2  *
      3  * FreeBSD Rust std carries undefined references such as fstat@FBSD_1.0 while
      4  * libc.so.7 exports both fstat@FBSD_1.0 and fstat@@FBSD_1.5. The linker must
      5  * resolve the undefined against the exact DSO version, rewrite the runtime
      6  * symbol name to the base name, and keep the requested version for
      7  * .gnu.version_r emission.
      8  *
      9  * This unit stays at resolver depth: it builds one object with an undefined
     10  * fstat@FBSD_1.0 and one synthetic DSO input whose dynsym has base-name fstat
     11  * tagged as hidden FBSD_1.0, then runs link_resolve_symbols/undefs directly. */
     12 
     13 #include <kit/core.h>
     14 #include <string.h>
     15 
     16 #include "core/core.h"
     17 #include "core/heap.h"
     18 #include "core/pool.h"
     19 #include "lib/kit_unit.h"
     20 #include "link/link.h"
     21 #include "link/link_internal.h"
     22 #include "obj/obj.h"
     23 
     24 static KitUnit g_u;
     25 #define EXPECT(cond, ...) CU_EXPECT(&g_u, cond, __VA_ARGS__)
     26 
     27 static Sym intern(Compiler* c, const char* s) {
     28   return pool_intern_slice(c->global, (Slice){.s = s, .len = (u32)strlen(s)});
     29 }
     30 
     31 static ObjBuilder* make_ref(Compiler* c, Sym name) {
     32   ObjBuilder* ob = obj_new(c);
     33   ObjSymId id;
     34   if (!ob) return NULL;
     35   id = obj_symbol_ex(ob, name, SB_GLOBAL, SV_DEFAULT, SK_UNDEF, OBJ_SEC_NONE, 0,
     36                      0, 0);
     37   obj_sym_mark_referenced(ob, id);
     38   obj_finalize(ob);
     39   return ob;
     40 }
     41 
     42 static ObjBuilder* make_dso(Compiler* c, Sym soname, Sym name, Sym version) {
     43   ObjBuilder* ob = obj_new(c);
     44   ObjImage* im;
     45   ObjImageSym ds;
     46   if (!ob) return NULL;
     47   im = obj_image_ensure(ob, OBJ_KIND_DYN);
     48   obj_image_set_soname(im, soname);
     49   memset(&ds, 0, sizeof(ds));
     50   ds.name = name;
     51   ds.bind = SB_GLOBAL;
     52   ds.kind = SK_FUNC;
     53   ds.section = OBJ_SEC_NONE;
     54   ds.version = version;
     55   ds.version_hidden = 1;
     56   obj_image_add_dynsym(im, &ds);
     57   obj_finalize(ob);
     58   return ob;
     59 }
     60 
     61 static LinkImage* make_resolve_image(Compiler* c, Linker* l) {
     62   LinkImage* img = link_image_alloc(c);
     63   Heap* h = img->heap;
     64   img->linker = l;
     65   img->ninput_maps = LinkInputs_count(&l->inputs);
     66   if (img->ninput_maps) {
     67     img->input_maps = (InputMap*)h->alloc(
     68         h, sizeof(*img->input_maps) * img->ninput_maps, _Alignof(InputMap));
     69     EXPECT(img->input_maps != NULL, "input map allocation failed");
     70     if (img->input_maps)
     71       memset(img->input_maps, 0, sizeof(*img->input_maps) * img->ninput_maps);
     72   }
     73   return img;
     74 }
     75 
     76 int main(void) {
     77   KitCompiler* kc = NULL;
     78   Linker* l = NULL;
     79   LinkImage* img = NULL;
     80   ObjBuilder* ref = NULL;
     81   ObjBuilder* dso = NULL;
     82   LinkInputId dso_id;
     83   Sym base, full, version, soname;
     84   int found = 0;
     85 
     86   kit_unit_init(&g_u);
     87   {
     88     KitTargetSpec t =
     89         kit_unit_target(KIT_ARCH_X86_64, KIT_OS_FREEBSD, KIT_OBJ_ELF);
     90     if (kit_unit_compiler_new(&g_u, t, &kc) != KIT_OK || !kc) {
     91       fprintf(stderr, "compiler_new failed\n");
     92       return 2;
     93     }
     94   }
     95   Compiler* c = kc;
     96 
     97   base = intern(c, "fstat");
     98   full = intern(c, "fstat@FBSD_1.0");
     99   version = intern(c, "FBSD_1.0");
    100   soname = intern(c, "libc.so.7");
    101   ref = make_ref(c, full);
    102   dso = make_dso(c, soname, base, version);
    103   EXPECT(ref != NULL, "reference object allocation failed");
    104   EXPECT(dso != NULL, "DSO object allocation failed");
    105 
    106   l = link_new(c);
    107   EXPECT(l != NULL, "link_new failed");
    108   if (l && ref && dso) {
    109     link_add_obj(l, ref);
    110     dso_id = link_add_obj(l, dso);
    111     LinkInput* din = LinkInputs_at(&l->inputs, dso_id - 1u);
    112     din->kind = LINK_INPUT_DSO_BYTES;
    113     din->soname = soname;
    114 
    115     img = make_resolve_image(c, l);
    116     link_resolve_symbols(l, img);
    117     link_resolve_undefs(l, img);
    118 
    119     for (u32 i = 0; i < LinkSyms_count(&img->syms); ++i) {
    120       LinkSymbol* s = LinkSyms_at(&img->syms, i);
    121       if (!s->imported || s->name != base) continue;
    122       found = 1;
    123       EXPECT(s->dso_input_id == dso_id, "versioned import bound wrong DSO");
    124       EXPECT(s->elf_version == version, "explicit ELF version was not kept");
    125       EXPECT(s->kind == SK_FUNC, "DSO export kind was not copied");
    126     }
    127     EXPECT(found, "fstat@FBSD_1.0 did not resolve as imported fstat");
    128   }
    129 
    130   if (img) link_image_free(img);
    131   if (l) link_free(l);
    132   if (ref) obj_free(ref);
    133   kit_unit_summary(&g_u, "elf_version_import_test");
    134   return kit_unit_status(&g_u);
    135 }