kit

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

coff_archive_fixpoint_test.c (6273B)


      1 /* COFF archive global fixed-point regression.
      2  *
      3  * Rust/MinGW links can create demand for an earlier library from a later
      4  * library. ELF/Mach-O preserve positional archive semantics, but COFF linkers
      5  * search the library set as a fixed point. This test builds:
      6  *
      7  *   input.o       -> undef late
      8  *   libearly.a   -> defines early
      9  *   liblate.a    -> defines late, undef early
     10  *
     11  * Positional scanning leaves `early` unpulled; COFF global fixed point pulls
     12  * liblate.a first, then revisits libearly.a. */
     13 
     14 #include <kit/archive.h>
     15 #include <kit/core.h>
     16 #include <string.h>
     17 
     18 #include "core/core.h"
     19 #include "core/pool.h"
     20 #include "lib/kit_unit.h"
     21 #include "link/link.h"
     22 #include "link/link_internal.h"
     23 #include "obj/obj.h"
     24 
     25 static KitUnit g_u;
     26 #define EXPECT(cond, ...) CU_EXPECT(&g_u, cond, __VA_ARGS__)
     27 
     28 static Sym intern(Compiler* c, const char* s) {
     29   return pool_intern_slice(c->global, (Slice){.s = s, .len = (u32)strlen(s)});
     30 }
     31 
     32 static ObjBuilder* make_obj(Compiler* c, Sym def, Sym undef) {
     33   ObjBuilder* ob = obj_new(c);
     34   ObjSecId data;
     35   ObjSymId usym;
     36   static const u8 byte = 1;
     37   if (!ob) return NULL;
     38   if (def != 0) {
     39     data = obj_section(ob, intern(c, ".data"), SEC_DATA, SF_ALLOC | SF_WRITE,
     40                        1);
     41     obj_write(ob, data, &byte, sizeof byte);
     42     obj_symbol(ob, def, SB_GLOBAL, SK_OBJ, data, 0, sizeof byte);
     43   }
     44   if (undef != 0) {
     45     usym = obj_symbol_ex(ob, undef, SB_GLOBAL, SV_DEFAULT, SK_UNDEF,
     46                          OBJ_SEC_NONE, 0, 0, 0);
     47     obj_sym_mark_referenced(ob, usym);
     48   }
     49   obj_finalize(ob);
     50   return ob;
     51 }
     52 
     53 static u8* copy_writer_bytes(KitWriter* w, size_t* len_out) {
     54   size_t n = 0;
     55   const u8* src = kit_writer_mem_bytes(w, &n);
     56   u8* dst = (u8*)g_u.heap.alloc(&g_u.heap, n ? n : 1u, _Alignof(u8));
     57   if (dst && n) memcpy(dst, src, n);
     58   if (len_out) *len_out = n;
     59   return dst;
     60 }
     61 
     62 static u8* emit_member(Compiler* c, Sym def, Sym undef, size_t* len_out) {
     63   ObjBuilder* ob = make_obj(c, def, undef);
     64   KitWriter* w = NULL;
     65   u8* bytes = NULL;
     66   if (!ob) return NULL;
     67   if (kit_writer_mem(&g_u.heap, &w) == KIT_OK && w) {
     68     emit_coff(c, ob, w);
     69     bytes = copy_writer_bytes(w, len_out);
     70     kit_writer_close(w);
     71   }
     72   obj_free(ob);
     73   return bytes;
     74 }
     75 
     76 static u8* make_archive_bytes(const char* member_name, const u8* member,
     77                               size_t member_len, size_t* len_out) {
     78   KitArInput in;
     79   KitArWriteOptions opts;
     80   KitWriter* w = NULL;
     81   u8* bytes = NULL;
     82   memset(&in, 0, sizeof in);
     83   memset(&opts, 0, sizeof opts);
     84   in.name = kit_slice_cstr(member_name);
     85   in.bytes.data = member;
     86   in.bytes.len = member_len;
     87   if (kit_writer_mem(&g_u.heap, &w) != KIT_OK || !w) return NULL;
     88   if (kit_ar_write(w, &in, 1, &opts) == KIT_OK)
     89     bytes = copy_writer_bytes(w, len_out);
     90   kit_writer_close(w);
     91   return bytes;
     92 }
     93 
     94 static int input_has_defined(Linker* l, Sym name) {
     95   u32 i;
     96   for (i = 0; i < LinkInputs_count(&l->inputs); ++i) {
     97     LinkInput* in = LinkInputs_at(&l->inputs, i);
     98     ObjSymIter* it;
     99     ObjSymEntry e;
    100     if (!in->obj) continue;
    101     it = obj_symiter_new(in->obj);
    102     while (obj_symiter_next(it, &e)) {
    103       const ObjSym* s = e.sym;
    104       if (s->name == name && s->kind != SK_UNDEF &&
    105           (s->bind == SB_GLOBAL || s->bind == SB_WEAK)) {
    106         obj_symiter_free(it);
    107         return 1;
    108       }
    109     }
    110     obj_symiter_free(it);
    111   }
    112   return 0;
    113 }
    114 
    115 int main(void) {
    116   KitCompiler* kc = NULL;
    117   Compiler* c;
    118   Linker* l = NULL;
    119   ObjBuilder* seed = NULL;
    120   Sym early, late;
    121   u8 *early_member = NULL, *late_member = NULL;
    122   u8 *early_archive = NULL, *late_archive = NULL;
    123   size_t early_member_len = 0, late_member_len = 0;
    124   size_t early_archive_len = 0, late_archive_len = 0;
    125   int status;
    126 
    127   kit_unit_init(&g_u);
    128   {
    129     KitTargetSpec t =
    130         kit_unit_target(KIT_ARCH_X86_64, KIT_OS_WINDOWS, KIT_OBJ_COFF);
    131     if (kit_unit_compiler_new(&g_u, t, &kc) != KIT_OK || !kc) {
    132       fprintf(stderr, "compiler_new failed\n");
    133       return 2;
    134     }
    135   }
    136   c = (Compiler*)kc;
    137   early = intern(c, "early");
    138   late = intern(c, "late");
    139 
    140   seed = make_obj(c, 0, late);
    141   early_member = emit_member(c, early, 0, &early_member_len);
    142   late_member = emit_member(c, late, early, &late_member_len);
    143   EXPECT(seed != NULL, "seed object allocation failed");
    144   EXPECT(early_member != NULL && early_member_len > 0,
    145          "early member emit failed");
    146   EXPECT(late_member != NULL && late_member_len > 0, "late member emit failed");
    147 
    148   if (early_member && late_member) {
    149     early_archive = make_archive_bytes("early.o", early_member,
    150                                        early_member_len, &early_archive_len);
    151     late_archive =
    152         make_archive_bytes("late.o", late_member, late_member_len,
    153                            &late_archive_len);
    154   }
    155   EXPECT(early_archive != NULL && early_archive_len > 0,
    156          "early archive build failed");
    157   EXPECT(late_archive != NULL && late_archive_len > 0,
    158          "late archive build failed");
    159 
    160   l = link_new(c);
    161   EXPECT(l != NULL, "link_new failed");
    162   if (l && seed && early_archive && late_archive) {
    163     link_add_obj(l, seed);
    164     link_add_archive_bytes(l, "libearly.a", early_archive, early_archive_len,
    165                            0, 0, 0);
    166     link_add_archive_bytes(l, "liblate.a", late_archive, late_archive_len, 0,
    167                            0, 0);
    168     link_ingest_archives(l);
    169     EXPECT(input_has_defined(l, late), "late archive member was not pulled");
    170     EXPECT(input_has_defined(l, early),
    171            "COFF global archive fixed point did not revisit libearly.a");
    172   }
    173 
    174   if (l) link_free(l);
    175   if (seed) obj_free(seed);
    176   if (early_member)
    177     g_u.heap.free(&g_u.heap, early_member, early_member_len ? early_member_len
    178                                                            : 1u);
    179   if (late_member)
    180     g_u.heap.free(&g_u.heap, late_member, late_member_len ? late_member_len
    181                                                          : 1u);
    182   if (early_archive)
    183     g_u.heap.free(&g_u.heap, early_archive,
    184                   early_archive_len ? early_archive_len : 1u);
    185   if (late_archive)
    186     g_u.heap.free(&g_u.heap, late_archive,
    187                   late_archive_len ? late_archive_len : 1u);
    188 
    189   kit_unit_summary(&g_u, "coff_archive_fixpoint_test");
    190   status = kit_unit_status(&g_u);
    191   return status;
    192 }