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 }