align_4k.c (4963B)
1 /* Hand-built KitObjBuilder roundtrip — verifies large sh_addralign. 2 * 3 * Builds an ELF with a .text section aligned to 4096 (page size), 4 * emits and reads it back, asserts the align field round-trips. 5 * Clang doesn't emit such large alignments naturally for .o files, 6 * so this gap can only be covered by a hand-built case. */ 7 8 #include <kit/core.h> 9 #include <kit/object.h> 10 #include <stdarg.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 15 #include "lib/kit_test_target.h" 16 17 static void* heap_alloc(KitHeap* h, size_t n, size_t a) { 18 (void)h; 19 (void)a; 20 return n ? malloc(n) : NULL; 21 } 22 static void* heap_realloc(KitHeap* h, void* p, size_t o, size_t n, size_t a) { 23 (void)h; 24 (void)o; 25 (void)a; 26 return realloc(p, n); 27 } 28 static void heap_free(KitHeap* h, void* p, size_t n) { 29 (void)h; 30 (void)n; 31 free(p); 32 } 33 static KitHeap g_heap = {heap_alloc, heap_realloc, heap_free, NULL}; 34 35 static void diag_emit(KitDiagSink* s, KitDiagKind k, KitSrcLoc loc, 36 const char* fmt, va_list ap) { 37 static const char* names[] = {"note", "warning", "error", "fatal"}; 38 (void)s; 39 (void)loc; 40 fprintf(stderr, "%s: ", names[k]); 41 vfprintf(stderr, fmt, ap); 42 fputc('\n', stderr); 43 } 44 static KitDiagSink g_diag = {diag_emit, NULL, 0, 0}; 45 46 static int g_failures; 47 #define CHECK(cond, ...) \ 48 do { \ 49 if (!(cond)) { \ 50 fprintf(stderr, "FAIL %s:%d: ", __FILE__, __LINE__); \ 51 fprintf(stderr, __VA_ARGS__); \ 52 fputc('\n', stderr); \ 53 g_failures++; \ 54 } \ 55 } while (0) 56 57 /* mov w0, #0 ; ret */ 58 static const uint8_t TEXT_BYTES[8] = { 59 0x00, 0x00, 0x80, 0x52, 0xc0, 0x03, 0x5f, 0xd6, 60 }; 61 62 #define WANT_ALIGN 4096u 63 64 int main(void) { 65 KitTargetSpec target; 66 if (kit_test_target_init(&target) != 0) { 67 fprintf(stderr, "FAIL: kit_test_target_init\n"); 68 return 1; 69 } 70 71 KitContext ctx = {.heap = &g_heap, 72 .file_io = NULL, 73 .diag = &g_diag, 74 .metrics = NULL, 75 .now = -1}; 76 KitTargetOptions target_opts; 77 memset(&target_opts, 0, sizeof target_opts); 78 target_opts.spec = target; 79 KitTarget* kt = NULL; 80 if (kit_target_new(&ctx, &target_opts, &kt) != KIT_OK || !kt) { 81 fprintf(stderr, "FAIL: kit_target_new\n"); 82 return 1; 83 } 84 KitCompiler* cc = NULL; 85 if (kit_compiler_new(kt, &ctx, &cc) != KIT_OK || !cc) { 86 fprintf(stderr, "FAIL: kit_compiler_new\n"); 87 kit_target_free(kt); 88 return 1; 89 } 90 KitObjBuilder* in = NULL; 91 CHECK(kit_obj_builder_new(cc, &in) == KIT_OK && in, "kit_obj_builder_new"); 92 93 KitObjSection sec = KIT_SECTION_NONE; 94 KitObjSectionDesc text_desc = { 95 .name = kit_sym_intern(cc, KIT_SLICE_LIT(".text")), 96 .kind = KIT_SEC_TEXT, 97 .flags = KIT_SF_ALLOC | KIT_SF_EXEC, 98 .align = WANT_ALIGN, 99 .entsize = 0, 100 }; 101 CHECK(kit_obj_builder_section(in, &text_desc, &sec) == KIT_OK, 102 "section .text"); 103 CHECK(kit_obj_builder_write(in, sec, TEXT_BYTES, sizeof TEXT_BYTES) == KIT_OK, 104 "write .text"); 105 KitObjSymbol sym_f = KIT_OBJ_SYMBOL_NONE; 106 KitObjSymbolDesc f_desc = { 107 .name = kit_sym_intern(cc, KIT_SLICE_LIT("f")), 108 .bind = KIT_SB_GLOBAL, 109 .kind = KIT_SK_FUNC, 110 .section = sec, 111 .value = 0, 112 .size = sizeof TEXT_BYTES, 113 }; 114 CHECK(kit_obj_builder_symbol(in, &f_desc, &sym_f) == KIT_OK, "symbol f"); 115 CHECK(kit_obj_builder_finalize(in) == KIT_OK, "finalize"); 116 117 KitWriter* w = NULL; 118 (void)kit_writer_mem(&g_heap, &w); 119 CHECK(kit_obj_builder_emit(in, w) == KIT_OK, "emit"); 120 size_t out_len = 0; 121 const uint8_t* out_data = kit_writer_mem_bytes(w, &out_len); 122 uint8_t* roundtrip = (uint8_t*)malloc(out_len); 123 memcpy(roundtrip, out_data, out_len); 124 kit_writer_close(w); 125 126 KitSlice input = {.data = roundtrip, .len = out_len}; 127 KitObjFile* back = NULL; 128 CHECK( 129 kit_obj_open(&ctx, KIT_SLICE_LIT("align_4k"), &input, &back) == KIT_OK && 130 back, 131 "kit_obj_open failed"); 132 133 /* Locate .text by name. */ 134 int found = 0; 135 if (back) { 136 KitObjSection text = KIT_SECTION_NONE; 137 if (kit_obj_section_by_name(back, KIT_SLICE_LIT(".text"), &text) == 138 KIT_OK) { 139 KitObjSecInfo si; 140 CHECK(kit_obj_section(back, text, &si) == KIT_OK, "section info .text"); 141 found = 1; 142 CHECK(si.align == WANT_ALIGN, ".text align=%u after roundtrip, want %u", 143 si.align, WANT_ALIGN); 144 } 145 } 146 CHECK(found, ".text not present after roundtrip"); 147 148 if (back) kit_obj_free(back); 149 free(roundtrip); 150 kit_obj_builder_free(in); 151 kit_compiler_free(cc); 152 kit_target_free(kt); 153 154 if (g_failures) { 155 fprintf(stderr, "%d failure(s)\n", g_failures); 156 return 1; 157 } 158 fputs("align_4k: OK\n", stderr); 159 return 0; 160 }