kit

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

groupiter.c (7552B)


      1 /* Hand-built object with a COMDAT group, exercised through the public
      2  * object builder and kit_obj_groupiter APIs.
      3  *
      4  * Steps:
      5  *   1. Build an ELF with two sections wired into one COMDAT group.
      6  *   2. Emit ELF, reopen via kit_obj_open, walk the public iter; verify
      7  *      group survives the on-disk roundtrip and section IDs are
      8  *      remapped to the public 0-based space. */
      9 
     10 #include <kit/core.h>
     11 #include <kit/object.h>
     12 #include <stdarg.h>
     13 #include <stdio.h>
     14 #include <stdlib.h>
     15 #include <string.h>
     16 
     17 #include "lib/kit_test_target.h"
     18 
     19 static void* heap_alloc(KitHeap* h, size_t n, size_t a) {
     20   (void)h;
     21   (void)a;
     22   return n ? malloc(n) : NULL;
     23 }
     24 static void* heap_realloc(KitHeap* h, void* p, size_t o, size_t n, size_t a) {
     25   (void)h;
     26   (void)o;
     27   (void)a;
     28   return realloc(p, n);
     29 }
     30 static void heap_free(KitHeap* h, void* p, size_t n) {
     31   (void)h;
     32   (void)n;
     33   free(p);
     34 }
     35 static KitHeap g_heap = {heap_alloc, heap_realloc, heap_free, NULL};
     36 
     37 static void diag_emit(KitDiagSink* s, KitDiagKind k, KitSrcLoc loc,
     38                       const char* fmt, va_list ap) {
     39   static const char* names[] = {"note", "warning", "error", "fatal"};
     40   (void)s;
     41   (void)loc;
     42   fprintf(stderr, "%s: ", names[k]);
     43   vfprintf(stderr, fmt, ap);
     44   fputc('\n', stderr);
     45 }
     46 static KitDiagSink g_diag = {diag_emit, NULL, 0, 0};
     47 
     48 static int g_failures;
     49 #define CHECK(cond, ...)                                   \
     50   do {                                                     \
     51     if (!(cond)) {                                         \
     52       fprintf(stderr, "FAIL %s:%d: ", __FILE__, __LINE__); \
     53       fprintf(stderr, __VA_ARGS__);                        \
     54       fputc('\n', stderr);                                 \
     55       g_failures++;                                        \
     56     }                                                      \
     57   } while (0)
     58 
     59 /* mov w0, #1 ; ret */
     60 static const uint8_t TEXT_BYTES[8] = {
     61     0x20, 0x00, 0x80, 0x52, 0xc0, 0x03, 0x5f, 0xd6,
     62 };
     63 
     64 static int name_eq(KitSlice s, const char* want) {
     65   return s.s && kit_slice_eq_cstr(s, want);
     66 }
     67 
     68 int main(void) {
     69   KitTargetSpec target;
     70   if (kit_test_target_init(&target) != 0) {
     71     fprintf(stderr, "FAIL: kit_test_target_init\n");
     72     return 1;
     73   }
     74 
     75   KitContext ctx = {.heap = &g_heap,
     76                     .file_io = NULL,
     77                     .diag = &g_diag,
     78                     .metrics = NULL,
     79                     .now = -1};
     80   KitTargetOptions target_opts;
     81   memset(&target_opts, 0, sizeof target_opts);
     82   target_opts.spec = target;
     83   KitTarget* kt = NULL;
     84   if (kit_target_new(&ctx, &target_opts, &kt) != KIT_OK || !kt) {
     85     fprintf(stderr, "FAIL: kit_target_new\n");
     86     return 1;
     87   }
     88   KitCompiler* cc = NULL;
     89   if (kit_compiler_new(kt, &ctx, &cc) != KIT_OK || !cc) {
     90     fprintf(stderr, "FAIL: kit_compiler_new\n");
     91     kit_target_free(kt);
     92     return 1;
     93   }
     94   /* ---- build ---- */
     95   KitObjBuilder* in = NULL;
     96   CHECK(kit_obj_builder_new(cc, &in) == KIT_OK && in, "kit_obj_builder_new");
     97 
     98   KitSym sig_nm = kit_sym_intern(cc, KIT_SLICE_LIT("comdat_sig"));
     99   KitObjSection sec_text = KIT_SECTION_NONE;
    100   KitObjSection sec_data = KIT_SECTION_NONE;
    101   KitObjSectionDesc text_desc = {
    102       .name = kit_sym_intern(cc, KIT_SLICE_LIT(".text.comdat_fn")),
    103       .kind = KIT_SEC_TEXT,
    104       .flags = KIT_SF_ALLOC | KIT_SF_EXEC,
    105       .align = 4,
    106       .entsize = 0,
    107   };
    108   KitObjSectionDesc data_desc = {
    109       .name = kit_sym_intern(cc, KIT_SLICE_LIT(".data.comdat_fn")),
    110       .kind = KIT_SEC_DATA,
    111       .flags = KIT_SF_ALLOC | KIT_SF_WRITE,
    112       .align = 8,
    113       .entsize = 0,
    114   };
    115   CHECK(kit_obj_builder_section(in, &text_desc, &sec_text) == KIT_OK,
    116         "section .text.comdat_fn");
    117   CHECK(kit_obj_builder_section(in, &data_desc, &sec_data) == KIT_OK,
    118         "section .data.comdat_fn");
    119   CHECK(kit_obj_builder_write(in, sec_text, TEXT_BYTES, sizeof TEXT_BYTES) ==
    120             KIT_OK,
    121         "write .text.comdat_fn");
    122   static const uint8_t zero8[8] = {0};
    123   CHECK(kit_obj_builder_write(in, sec_data, zero8, sizeof zero8) == KIT_OK,
    124         "write .data.comdat_fn");
    125 
    126   KitObjSymbol sig_sym = KIT_OBJ_SYMBOL_NONE;
    127   KitObjSymbolDesc sig_desc = {
    128       .name = sig_nm,
    129       .bind = KIT_SB_WEAK,
    130       .kind = KIT_SK_FUNC,
    131       .section = sec_text,
    132       .value = 0,
    133       .size = sizeof TEXT_BYTES,
    134   };
    135   CHECK(kit_obj_builder_symbol(in, &sig_desc, &sig_sym) == KIT_OK,
    136         "symbol comdat_sig");
    137 
    138   KitObjGroup gid = KIT_OBJ_GROUP_NONE;
    139   CHECK(kit_obj_builder_group(in, sig_nm, sig_sym, KIT_OBJ_GROUP_COMDAT,
    140                               &gid) == KIT_OK,
    141         "group comdat_sig");
    142   CHECK(kit_obj_builder_group_add_section(in, gid, sec_text) == KIT_OK,
    143         "group add text");
    144   CHECK(kit_obj_builder_group_add_section(in, gid, sec_data) == KIT_OK,
    145         "group add data");
    146   CHECK(kit_obj_builder_finalize(in) == KIT_OK, "finalize");
    147 
    148   /* ---- emit + public-iter readback ---- */
    149   KitWriter* w = NULL;
    150   (void)kit_writer_mem(&g_heap, &w);
    151   CHECK(kit_obj_builder_emit(in, w) == KIT_OK, "emit");
    152   size_t out_len = 0;
    153   const uint8_t* out_data = kit_writer_mem_bytes(w, &out_len);
    154   uint8_t* roundtrip = (uint8_t*)malloc(out_len ? out_len : 1);
    155   memcpy(roundtrip, out_data, out_len);
    156   kit_writer_close(w);
    157 
    158   KitSlice input = {.data = roundtrip, .len = out_len};
    159   KitObjFile* f = NULL;
    160   CHECK(
    161       kit_obj_open(&ctx, KIT_SLICE_LIT("groupiter"), &input, &f) == KIT_OK && f,
    162       "kit_obj_open failed");
    163 
    164   if (f) {
    165     /* Resolve section IDs by name so the test isn't coupled to ordering. */
    166     KitObjSection text_pub = KIT_SECTION_NONE;
    167     KitObjSection data_pub = KIT_SECTION_NONE;
    168     CHECK(kit_obj_section_by_name(f, KIT_SLICE_LIT(".text.comdat_fn"),
    169                                   &text_pub) == KIT_OK,
    170           "section_by_name .text.comdat_fn");
    171     CHECK(kit_obj_section_by_name(f, KIT_SLICE_LIT(".data.comdat_fn"),
    172                                   &data_pub) == KIT_OK,
    173           "section_by_name .data.comdat_fn");
    174 
    175     KitObjGroupIter* git = NULL;
    176     CHECK(kit_obj_groupiter_new(f, &git) == KIT_OK, "kit_obj_groupiter_new");
    177     int seen = 0;
    178     KitObjGroupInfo gi;
    179     while (kit_obj_groupiter_next(git, &gi) == KIT_ITER_ITEM) {
    180       ++seen;
    181       CHECK(name_eq(gi.name, "comdat_sig"), "public iter: name=%.*s",
    182             KIT_SLICE_ARG(gi.name));
    183       CHECK((gi.flags & KIT_OBJ_GROUP_COMDAT) != 0,
    184             "public iter: missing COMDAT flag (flags=0x%x)", gi.flags);
    185       CHECK(gi.nsections == 2, "public iter: nsections=%u, want 2",
    186             gi.nsections);
    187       CHECK(gi.sections != NULL, "public iter: NULL sections");
    188       if (gi.sections && gi.nsections == 2) {
    189         /* Order is preserved by ELF SHT_GROUP, so members[0] should be
    190          * sec_text and members[1] sec_data. */
    191         CHECK(gi.sections[0] == text_pub,
    192               "public iter: sections[0]=%u, want %u (text)", gi.sections[0],
    193               text_pub);
    194         CHECK(gi.sections[1] == data_pub,
    195               "public iter: sections[1]=%u, want %u (data)", gi.sections[1],
    196               data_pub);
    197       }
    198       /* Signature should be a valid public symbol id, not NONE. */
    199       CHECK(gi.signature != KIT_OBJ_SYMBOL_NONE,
    200             "public iter: signature is NONE");
    201     }
    202     CHECK(seen == 1, "public iter: saw %d groups, want 1", seen);
    203     kit_obj_groupiter_free(git);
    204     kit_obj_free(f);
    205   }
    206 
    207   free(roundtrip);
    208   kit_obj_builder_free(in);
    209   kit_compiler_free(cc);
    210   kit_target_free(kt);
    211 
    212   if (g_failures) {
    213     fprintf(stderr, "%d failure(s)\n", g_failures);
    214     return 1;
    215   }
    216   fputs("groupiter: OK\n", stderr);
    217   return 0;
    218 }