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 }