kit

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

emit.c (32176B)


      1 /* ELF ET_REL writer. Walks a finalized ObjBuilder and emits a 64-bit
      2  * little-endian relocatable object via the supplied Writer.
      3  *
      4  * Layout strategy:
      5  *   1. plan ELF section headers (one per obj section, plus synthesized
      6  *      .symtab / .strtab / .shstrtab and one .rela.<name> per obj section
      7  *      that carries relocations);
      8  *   2. build .symtab + .strtab content (locals first — STT_SECTION
      9  *      synthesized for every input section, then ordinary locals, then
     10  *      globals/weaks);
     11  *   3. build .rela.* content using the per-arch reloc map (selected
     12  *      by Compiler.target.arch);
     13  *   4. build .shstrtab;
     14  *   5. assign file offsets sequentially, respecting per-section
     15  *      addralign;
     16  *   6. write Ehdr, then each section's bytes (seeking to its sh_offset),
     17  *      then the section header table.
     18  *
     19  * 64-bit little-endian only. Per-arch reloc tables (elf_reloc_<arch>.c)
     20  * supply the RelocKind -> ELF type mapping; e_machine is selected from
     21  * Compiler.target.arch. Big-endian / 32-bit ELF panic at entry.
     22  *
     23  * See doc/DESIGN.md §5.5 for the round-trip invariant: read_elf of this
     24  * output must produce an ObjBuilder shape-equivalent to the input,
     25  * modulo (a) section ordering and (b) the synthesized STT_SECTION
     26  * symbols (which are visible to read_elf but were not in the input). */
     27 
     28 #include <string.h>
     29 
     30 #include "core/arena.h"
     31 #include "core/buf.h"
     32 #include "core/heap.h"
     33 #include "core/pool.h"
     34 #include "core/slice.h"
     35 #include "core/util.h"
     36 #include "obj/elf/elf.h"
     37 #include "obj/format.h"
     38 
     39 /* ---- per-ELF-section plan record ---- */
     40 
     41 /* Internal section descriptor used during planning. Mirrors Elf64_Shdr
     42  * but with an explicit pointer to the source bytes (either an obj
     43  * Section's chunked Buf or a synthesized linear buffer). NOBITS sections
     44  * have no source bytes and consume no file space. */
     45 typedef struct ElfSec {
     46   /* Final shdr fields (little-endian-encoded at write time). */
     47   u32 sh_name; /* offset into shstrtab */
     48   u32 sh_type;
     49   u64 sh_flags;
     50   u64 sh_addr; /* always 0 for ET_REL */
     51   u64 sh_offset;
     52   u64 sh_size;
     53   u32 sh_link;
     54   u32 sh_info;
     55   u64 sh_addralign;
     56   u64 sh_entsize;
     57 
     58   /* Section name. The name string lives in scratch (synthesized) or in
     59    * the global pool (obj-section names); buf-source is set for sections
     60    * carrying obj-section bytes, raw_bytes for synthesized. */
     61   const char* name;
     62   u32 name_len;
     63 
     64   const Buf* obj_bytes; /* one of these three is set: */
     65   const u8* raw_bytes;  /*                            */
     66   int is_nobits;        /*                            */
     67 } ElfSec;
     68 
     69 /* ---- emit ---- */
     70 
     71 static u32 sec_flags_to_elf(u16 flags) {
     72   u64 r = 0;
     73   if (flags & SF_ALLOC) r |= SHF_ALLOC;
     74   if (flags & SF_EXEC) r |= SHF_EXECINSTR;
     75   if (flags & SF_WRITE) r |= SHF_WRITE;
     76   if (flags & SF_TLS) r |= SHF_TLS;
     77   if (flags & SF_MERGE) r |= SHF_MERGE;
     78   if (flags & SF_STRINGS) r |= SHF_STRINGS;
     79   if (flags & SF_GROUP) r |= SHF_GROUP;
     80   if (flags & SF_LINK_ORDER) r |= SHF_LINK_ORDER;
     81   if (flags & SF_RETAIN) r |= SHF_GNU_RETAIN;
     82   return (u32)r;
     83 }
     84 
     85 static u32 sec_sem_to_elf(u16 sem) {
     86   switch (sem) {
     87     case SSEM_PROGBITS:
     88       return SHT_PROGBITS;
     89     case SSEM_NOBITS:
     90       return SHT_NOBITS;
     91     case SSEM_SYMTAB:
     92       return SHT_SYMTAB;
     93     case SSEM_STRTAB:
     94       return SHT_STRTAB;
     95     case SSEM_RELA:
     96       return SHT_RELA;
     97     case SSEM_REL:
     98       return SHT_REL;
     99     case SSEM_NOTE:
    100       return SHT_NOTE;
    101     case SSEM_INIT_ARRAY:
    102       return SHT_INIT_ARRAY;
    103     case SSEM_FINI_ARRAY:
    104       return SHT_FINI_ARRAY;
    105     case SSEM_PREINIT_ARRAY:
    106       return SHT_PREINIT_ARRAY;
    107     case SSEM_GROUP:
    108       return SHT_GROUP;
    109     default:
    110       return SHT_PROGBITS;
    111   }
    112 }
    113 
    114 static u8 sym_bind_to_elf(u16 bind) { return elf_st_bind((u8)bind); }
    115 
    116 /* SK_COMMON -> STT_OBJECT: real ELF emitters (clang, gcc, GNU as) write
    117  * tentative definitions as STT_OBJECT with shndx=SHN_COMMON. STT_COMMON
    118  * is a near-extinct convention that llvm-readelf renders as the literal
    119  * type name "COMMON" — emitting it breaks roundtrip against any
    120  * toolchain-produced .o. The shared elf.h table encodes this directly. */
    121 static u8 sym_kind_to_elf(u16 kind) { return elf_st_type((u8)kind); }
    122 
    123 static u8 sym_vis_to_elf(u8 vis) { return elf_st_other(vis); }
    124 
    125 static u16 sym_shndx(const ObjSym* s, const u32* obj_to_elf, u32 nsec) {
    126   if (s->kind == SK_COMMON) return (u16)SHN_COMMON;
    127   if (s->kind == SK_ABS) return (u16)SHN_ABS;
    128   /* STT_FILE conventionally carries SHN_ABS as its shndx — its value
    129    * field is not an address. Match clang/binutils. */
    130   if (s->kind == SK_FILE) return (u16)SHN_ABS;
    131   if (s->section_id == OBJ_SEC_NONE) return (u16)SHN_UNDEF;
    132   if (s->section_id >= nsec) return (u16)SHN_UNDEF;
    133   return (u16)obj_to_elf[s->section_id];
    134 }
    135 
    136 static int obj_has_section_name(Compiler* c, ObjBuilder* ob, const char* name) {
    137   u32 want = (u32)strlen(name);
    138   u32 nsec = obj_section_count(ob);
    139   for (u32 i = 1; i < nsec; ++i) {
    140     const Section* s = obj_section_get(ob, i);
    141     if (!s || s->removed) continue;
    142     Slice sl = pool_slice(c->global, s->name);
    143     if (sl.len == want && sl.s && memcmp(sl.s, name, want) == 0) return 1;
    144   }
    145   return 0;
    146 }
    147 
    148 const u8* elf_arm_build_attributes(Compiler* c, u32* size_out) {
    149   static const u8 kArm32Attrs[] = {
    150       'A',
    151       0x42, 0x00, 0x00, 0x00,             /* vendor subsection length */
    152       'a',  'e',  'a',  'b',  'i',  0x00, /* vendor */
    153       0x01,                               /* Tag_File */
    154       0x38, 0x00, 0x00, 0x00,             /* file attributes length */
    155       0x43, '2',  '.',  '0',  '9',  0x00, /* Tag_conformance */
    156       0x05, 'c',  'o',  'r',  't',  'e',  'x',  '-', 'm', '3', 0x00,
    157       0x06, 0x0a,                         /* Tag_CPU_arch = v7-M */
    158       0x07, 0x4d,                         /* Tag_CPU_arch_profile = M */
    159       0x08, 0x00,                         /* Tag_ARM_ISA_use = none */
    160       0x09, 0x02,                         /* Tag_THUMB_ISA_use = Thumb-2 */
    161       0x0e, 0x00,                         /* Tag_ABI_PCS_R9_use = v6 */
    162       0x11, 0x01,                         /* Tag_ABI_PCS_GOT_use */
    163       0x12, 0x04,                         /* Tag_ABI_PCS_wchar_t = 4 */
    164       0x14, 0x01,                         /* Tag_ABI_FP_denormal */
    165       0x15, 0x00,                         /* Tag_ABI_FP_exceptions */
    166       0x17, 0x03,                         /* Tag_ABI_FP_number_model */
    167       0x18, 0x01,                         /* Tag_ABI_align_needed */
    168       0x19, 0x01,                         /* Tag_ABI_align_preserved */
    169       0x1a, 0x02,                         /* Tag_ABI_enum_size */
    170       0x1c, 0x00,                         /* Tag_ABI_VFP_args = base */
    171       0x1e, 0x06,                         /* Tag_ABI_optimization_goals */
    172       0x22, 0x01,                         /* Tag_CPU_unaligned_access */
    173       0x26, 0x01,                         /* Tag_ABI_FP_16bit_format */
    174   };
    175   u8* out = (u8*)arena_alloc(c->scratch, sizeof kArm32Attrs, 1);
    176   memcpy(out, kArm32Attrs, sizeof kArm32Attrs);
    177   *size_out = (u32)sizeof kArm32Attrs;
    178   return out;
    179 }
    180 
    181 static const char* sym_to_str(Compiler* c, Sym n, u32* len_out) {
    182   Slice sl = pool_slice(c->global, n);
    183   const char* s = sl.s;
    184   if (!s) {
    185     *len_out = 0;
    186     return "";
    187   }
    188   *len_out = (u32)sl.len;
    189   return s;
    190 }
    191 
    192 /* The string table dedup + build moved to the shared ObjStrtab (obj.h): the
    193  * former per-add buf_flatten + linear substring scan here was O(n^2) in the
    194  * symbol count (31% of instructions compiling sqlite to ELF). */
    195 
    196 void emit_elf(Compiler* c, ObjBuilder* ob, Writer* w) {
    197   Heap* h = (Heap*)c->ctx->heap;
    198 
    199   /* Run the tombstone sweep before any iteration: cascades removed
    200    * sections into their defining symbols, drops dangling relocs,
    201    * compacts groups, and absorbs the historical UNDEF prune. After this
    202    * call every direct ID-based access below must skip entries whose
    203    * `removed` bit is set. */
    204   obj_sweep_dead(ob);
    205 
    206   /* ---- target validation ------------------------------------------ */
    207   const ObjFormatImpl* fmt = obj_format_lookup(KIT_OBJ_ELF);
    208   const ObjElfArchOps* elf =
    209       fmt && fmt->elf_arch ? fmt->elf_arch(c->target.arch) : NULL;
    210   u32 e_machine;
    211   u32 (*reloc_to)(u32);
    212   if (!elf || !elf->reloc_to) {
    213     compiler_panic(c, SRCLOC_NONE, "emit_elf: unsupported target arch %u",
    214                    (u32)c->target.arch);
    215   }
    216   e_machine = elf->e_machine;
    217   reloc_to = elf->reloc_to;
    218   if (c->target.big_endian) {
    219     compiler_panic(c, SRCLOC_NONE, "emit_elf: big-endian ELF not supported");
    220   }
    221   /* is32 selects ELFCLASS32 (RV32) record widths/layouts everywhere
    222    * below; ptr_size==8 is the established ELFCLASS64 path. */
    223   if (c->target.ptr_size != 8 && c->target.ptr_size != 4) {
    224     compiler_panic(c, SRCLOC_NONE, "emit_elf: ptr_size %u (expected 4 or 8)",
    225                    (u32)c->target.ptr_size);
    226   }
    227   int is32 = (c->target.ptr_size == 4);
    228   /* SHT_REL vs SHT_RELA: ARM EABI (AAELF32) carries the addend in the
    229    * relocated field (8-byte Elf32_Rel, no r_addend slot); every other arch
    230    * uses RELA. `uses_rel` is set per-arch in obj_elf_arch_ops. When set the
    231    * reloc records below omit r_addend and the section is named ".rel.*". */
    232   int uses_rel = elf->uses_rel != 0;
    233   u32 sym_size = is32 ? ELF32_SYM_SIZE : ELF64_SYM_SIZE;
    234   u32 rela_size = is32 ? ELF32_RELA_SIZE : ELF64_RELA_SIZE;
    235   /* Bytes per relocation entry actually emitted (REL = 8, RELA = 12/24). */
    236   u32 reloc_ent_size = uses_rel ? ELF32_REL_SIZE : rela_size;
    237   u32 ehdr_size = is32 ? ELF32_EHDR_SIZE : ELF64_EHDR_SIZE;
    238   u32 shdr_size = is32 ? ELF32_SHDR_SIZE : ELF64_SHDR_SIZE;
    239 
    240   /* ---- pass 1: plan ELF section list ------------------------------ */
    241 
    242   u32 nobjsec = obj_section_count(ob);
    243 
    244   u32 nobjgrp = obj_group_count(ob);
    245   /* Synthesize the arch's ELF vendor build-attributes section (ARM's
    246    * `.ARM.attributes`) when the arch provides a builder and the object doesn't
    247    * already carry one. The gate hangs off the per-arch ObjElfArchOps vtable
    248    * (build_attributes is non-NULL only for arm32) rather than e_machine. */
    249   int synth_arm_attrs = elf->build_attributes &&
    250                         !obj_has_section_name(c, ob, ".ARM.attributes");
    251   /* Upper bound on ELF section count:
    252    *   1 (SHN_UNDEF)
    253    * + nobjsec - 1 (one ELF entry per real obj section)
    254    * + nobjsec - 1 (worst case: a .rela.<name> per obj section)
    255    * + nobjgrp - 1 (one synthesized SHT_GROUP per ObjGroup)
    256    * + 1 (optional .ARM.attributes)
    257    * + 3 (.symtab, .strtab, .shstrtab)
    258    */
    259   u32 max_secs =
    260       1 + (nobjsec - 1) + (nobjsec - 1) + (nobjgrp ? nobjgrp - 1 : 0) +
    261       (synth_arm_attrs ? 1u : 0u) + 3;
    262   if (max_secs < 4) max_secs = 4;
    263   ElfSec* secs = arena_array(c->scratch, ElfSec, max_secs);
    264   u32 nsecs = 0;
    265   memset(&secs[nsecs++], 0, sizeof secs[0]); /* index 0 = SHN_UNDEF */
    266 
    267   /* Map obj section id -> ELF section index. */
    268   u32* obj_to_elf = arena_zarray(c->scratch, u32, nobjsec);
    269 
    270   for (u32 i = 1; i < nobjsec; ++i) {
    271     const Section* s = obj_section_get(ob, i);
    272     if (s->removed) continue; /* tombstone — see obj_sweep_dead */
    273     ElfSec* es = &secs[nsecs];
    274     memset(es, 0, sizeof *es);
    275     u32 nlen;
    276     es->name = sym_to_str(c, s->name, &nlen);
    277     es->name_len = nlen;
    278     /* Honor format-specific overrides preserved by the reader for
    279      * sh_type/sh_flags bits the canonical SecSem/SecFlag enums
    280      * don't model (e.g. SHT_LLVM_ADDRSIG, SHF_EXCLUDE). */
    281     es->sh_type = (s->ext_kind == OBJ_EXT_ELF && s->ext_type)
    282                       ? s->ext_type
    283                       : sec_sem_to_elf(s->sem);
    284     es->sh_flags = sec_flags_to_elf(s->flags);
    285     if (s->ext_kind == OBJ_EXT_ELF) es->sh_flags |= s->ext_flags;
    286     es->sh_addr = 0;
    287     es->sh_addralign = s->align ? s->align : 1;
    288     es->sh_entsize = s->entsize;
    289     es->sh_link = 0;
    290     es->sh_info = 0;
    291     if (s->sem == SSEM_NOBITS) {
    292       es->is_nobits = 1;
    293       es->sh_size = s->bss_size;
    294     } else {
    295       es->obj_bytes = &s->bytes;
    296       es->sh_size = s->bytes.total;
    297     }
    298     obj_to_elf[i] = nsecs++;
    299   }
    300 
    301   if (synth_arm_attrs) {
    302     u32 attr_size;
    303     const u8* attr = elf->build_attributes(c, &attr_size);
    304     ElfSec* es = &secs[nsecs];
    305     memset(es, 0, sizeof *es);
    306     es->name = ".ARM.attributes";
    307     es->name_len = 15;
    308     es->sh_type = SHT_ARM_ATTRIBUTES;
    309     es->sh_flags = 0;
    310     es->sh_addralign = 1;
    311     es->raw_bytes = attr;
    312     es->sh_size = attr_size;
    313     nsecs++;
    314   }
    315 
    316   /* ---- pass 2: build .symtab + .strtab content -------------------- */
    317 
    318   /* .strtab: leading NUL byte. Then a name per emitted symbol. */
    319   ObjStrtab strtab;
    320   obj_strtab_init(&strtab, h, /*dedup=*/1);
    321   {
    322     u8 z = 0;
    323     obj_strtab_put_raw(&strtab, &z, 1);
    324   }
    325 
    326   /* The .symtab is built into a contiguous arena buffer of fixed-size
    327    * 24-byte records. We don't know the count up front; bound by
    328    * (nobjsec section symbols) + (obj symbol count). */
    329   u32 nobjsym = 0;
    330   {
    331     ObjSymIter* it = obj_symiter_new(ob);
    332     ObjSymEntry e;
    333     while (obj_symiter_next(it, &e)) ++nobjsym;
    334     obj_symiter_free(it);
    335   }
    336   u32 max_syms = 1 + (nobjsec - 1) + nobjsym;
    337   u8* symtab =
    338       (u8*)arena_alloc(c->scratch, (size_t)sym_size * max_syms, _Alignof(u64));
    339   u32 nsyms = 0;
    340   memset(&symtab[nsyms * sym_size], 0, sym_size);
    341   nsyms = 1; /* index 0: STN_UNDEF */
    342 
    343 /* Helper to emit one symbol record at index `idx` into symtab.
    344  * Elf64_Sym (24B) and Elf32_Sym (16B) REORDER fields: ELF32 places
    345  * st_value/st_size BEFORE st_info/st_other/st_shndx, so select the byte
    346  * layout by `is32` rather than just narrowing widths. */
    347 #define WRITE_SYM(idx, st_name, st_info, st_other, st_shndx, st_value, \
    348                   st_size)                                             \
    349   do {                                                                 \
    350     u8* slot = &symtab[(idx) * sym_size];                              \
    351     if (is32) {                                                        \
    352       slot[0] = (u8)((st_name));                                       \
    353       slot[1] = (u8)((st_name) >> 8);                                  \
    354       slot[2] = (u8)((st_name) >> 16);                                 \
    355       slot[3] = (u8)((st_name) >> 24);                                 \
    356       for (int _b = 0; _b < 4; ++_b)                                   \
    357         slot[4 + _b] = (u8)((u64)(st_value) >> (_b * 8));              \
    358       for (int _b = 0; _b < 4; ++_b)                                   \
    359         slot[8 + _b] = (u8)((u64)(st_size) >> (_b * 8));               \
    360       slot[12] = (u8)((st_info));                                      \
    361       slot[13] = (u8)((st_other));                                     \
    362       slot[14] = (u8)((st_shndx));                                     \
    363       slot[15] = (u8)((st_shndx) >> 8);                                \
    364     } else {                                                           \
    365       slot[0] = (u8)((st_name));                                       \
    366       slot[1] = (u8)((st_name) >> 8);                                  \
    367       slot[2] = (u8)((st_name) >> 16);                                 \
    368       slot[3] = (u8)((st_name) >> 24);                                 \
    369       slot[4] = (u8)((st_info));                                       \
    370       slot[5] = (u8)((st_other));                                      \
    371       slot[6] = (u8)((st_shndx));                                      \
    372       slot[7] = (u8)((st_shndx) >> 8);                                 \
    373       for (int _b = 0; _b < 8; ++_b)                                   \
    374         slot[8 + _b] = (u8)((u64)(st_value) >> (_b * 8));              \
    375       for (int _b = 0; _b < 8; ++_b)                                   \
    376         slot[16 + _b] = (u8)((u64)(st_size) >> (_b * 8));              \
    377     }                                                                  \
    378   } while (0)
    379 
    380   /* No automatic STT_SECTION synthesis. Section symbols are emitted
    381    * iff they are present in the input ObjBuilder (typically as
    382    * SK_SECTION ObjSyms preserved by read_elf, or added explicitly by
    383    * a hand-built caller that needs to reference a section by sym).
    384    * This matches clang's output: only sections referenced by section
    385    * symbols carry one. */
    386 
    387   /* Map obj symbol id -> elf symbol index. */
    388   u32* sym_to_elf = arena_zarray(c->scratch, u32, nobjsym + 2);
    389 
    390   /* Two passes over obj symbols: locals, then globals/weak.
    391    * sh_info on .symtab is the index of the first non-local symbol;
    392    * since pass 0 emits exactly the LOCAL non-removed symbols, count
    393    * them inline (seeded with 1 for STN_UNDEF) instead of re-walking. */
    394   u32 nlocals = 1;
    395   for (int pass = 0; pass < 2; ++pass) {
    396     ObjSymIter* it = obj_symiter_new(ob);
    397     ObjSymEntry e;
    398     while (obj_symiter_next(it, &e)) {
    399       const ObjSym* s = e.sym;
    400       if (s->removed) continue; /* spurious-UNDEF prune + explicit removal */
    401       int is_local = (s->bind == SB_LOCAL);
    402       if ((pass == 0) != is_local) continue;
    403       u32 nlen;
    404       const char* nm = sym_to_str(c, s->name, &nlen);
    405       u32 nameoff = nlen ? obj_strtab_add(&strtab, nm, nlen) : 0;
    406       u8 info =
    407           ELF64_ST_INFO(sym_bind_to_elf(s->bind), sym_kind_to_elf(s->kind));
    408       u8 other = sym_vis_to_elf(s->vis);
    409       u16 shndx = sym_shndx(s, obj_to_elf, nobjsec);
    410       u64 value = (s->kind == SK_COMMON) ? s->common_align : s->value;
    411       WRITE_SYM(nsyms, nameoff, info, other, shndx, value, s->size);
    412       sym_to_elf[e.id] = nsyms;
    413       nsyms++;
    414       if (pass == 0) ++nlocals;
    415     }
    416     obj_symiter_free(it);
    417   }
    418 #undef WRITE_SYM
    419 
    420   /* Append .symtab + .strtab + .shstrtab planning records.
    421    * sh_link/sh_info for .symtab and .rela.* are filled in once we know
    422    * each section's elf index. */
    423   u32 idx_symtab = 0, idx_strtab = 0, idx_shstrtab = 0;
    424 
    425   /* ---- pass 2.5: synthesize SHT_GROUP sections from ObjGroups ----
    426    * Append one SHT_GROUP section per ObjGroup. The body is a 4-byte LE
    427    * flags word followed by the elf section index of each member.
    428    * Placed before relas so the file layout has data sections, then
    429    * groups, then relas/symtab/strtab — matching clang's ordering and
    430    * keeping data-section offsets independent of group presence. */
    431   u32* group_elf_idx =
    432       nobjgrp > 1 ? arena_array(c->scratch, u32, nobjgrp) : NULL;
    433   if (group_elf_idx) memset(group_elf_idx, 0, sizeof(u32) * nobjgrp);
    434   for (u32 gi = 1; gi < nobjgrp; ++gi) {
    435     const ObjGroup* g = obj_group_get(ob, gi);
    436     if (!g || g->removed) continue;
    437 
    438     u32 body_size = 4u + 4u * g->nsections;
    439     u8* body = (u8*)arena_alloc(c->scratch, body_size, _Alignof(u32));
    440     u32 gflags = g->flags ? g->flags : 1u; /* GRP_COMDAT default */
    441     body[0] = (u8)(gflags);
    442     body[1] = (u8)(gflags >> 8);
    443     body[2] = (u8)(gflags >> 16);
    444     body[3] = (u8)(gflags >> 24);
    445     for (u32 j = 0; j < g->nsections; ++j) {
    446       ObjSecId sid = g->sections[j];
    447       u32 eidx = (sid && sid < nobjsec) ? obj_to_elf[sid] : 0;
    448       u8* slot = body + 4 + j * 4;
    449       slot[0] = (u8)(eidx);
    450       slot[1] = (u8)(eidx >> 8);
    451       slot[2] = (u8)(eidx >> 16);
    452       slot[3] = (u8)(eidx >> 24);
    453     }
    454 
    455     u32 nlen;
    456     const char* gname = sym_to_str(c, g->name, &nlen);
    457     if (nlen == 0) {
    458       gname = ".group";
    459       nlen = 6;
    460     }
    461 
    462     ElfSec* es = &secs[nsecs];
    463     memset(es, 0, sizeof *es);
    464     es->name = gname;
    465     es->name_len = nlen;
    466     es->sh_type = SHT_GROUP;
    467     es->sh_flags = 0;
    468     es->sh_addralign = 4;
    469     es->sh_entsize = 4;
    470     es->sh_info = (g->signature && g->signature < nobjsym + 2)
    471                       ? sym_to_elf[g->signature]
    472                       : 0;
    473     /* sh_link patched below once idx_symtab is known. */
    474     es->raw_bytes = body;
    475     es->sh_size = body_size;
    476     group_elf_idx[gi] = nsecs;
    477     nsecs++;
    478   }
    479 
    480   /* ---- pass 3: build .rela.<name> contents ------------------------ */
    481 
    482   /* Allocate one .rela section per obj section that has any relocs. */
    483   typedef struct RelaPlan {
    484     u32 obj_section; /* obj section the rela applies to */
    485     u8* bytes;       /* arena-allocated rela/rel bytes */
    486     u32 size;        /* bytes count = nrelocs * reloc_ent_size */
    487   } RelaPlan;
    488 
    489   RelaPlan* rela_plans = arena_zarray(c->scratch, RelaPlan, nobjsec);
    490   u32 nrela_plans = 0;
    491 
    492   for (u32 si = 1; si < nobjsec; ++si) {
    493     const Section* host = obj_section_get(ob, si);
    494     if (!host || host->removed) continue;
    495     u32 nr;
    496     const u32* rix = obj_reloc_section(ob, si, &nr);
    497     if (!nr) continue;
    498     u8* buf =
    499         (u8*)arena_alloc(c->scratch, (size_t)reloc_ent_size * nr, _Alignof(u64));
    500     u32 j = 0;
    501     /* rix[] lists section si's live relocs in ascending global order. */
    502     for (u32 k = 0; k < nr; ++k) {
    503       const Reloc* r = obj_reloc_at(ob, rix[k]);
    504       u32 etype = reloc_to(r->kind);
    505       if (etype == ELF_R_AARCH64_NONE /* == ELF_R_X86_64_NONE == 0 */ &&
    506           r->kind != R_NONE) {
    507         compiler_panic(c, SRCLOC_NONE,
    508                        "emit_elf: unsupported relocation kind %u for arch %u",
    509                        (u32)r->kind, (u32)c->target.arch);
    510       }
    511       u32 sym_elf_idx;
    512       if (r->sym == OBJ_SYM_NONE) {
    513         /* Reloc against a section: use the synthesized
    514          * STT_SECTION symbol if the obj reloc carries a
    515          * section_id-equivalent; otherwise 0. */
    516         sym_elf_idx = 0;
    517       } else {
    518         sym_elf_idx = sym_to_elf[r->sym];
    519       }
    520       /* Elf32_Rel (8B): r_offset@0, r_info@4 — addend lives in the relocated
    521        * field (ARM EABI). Elf32_Rela (12B): + r_addend@8. Elf64_Rela (24B):
    522        * all 8-byte. The addend is already present in the section field for
    523        * REL: data words carry it (api_data_encode_addend), and the Thumb-2
    524        * branch / MOVW-MOVT placeholders encode the (addend 0) baseline; a
    525        * non-zero MOVW/MOVT addend is folded in at the arm32 emit site. */
    526       u8* slot = &buf[j * reloc_ent_size];
    527       if (is32) {
    528         for (int b = 0; b < 4; ++b) slot[b] = (u8)((u32)r->offset >> (b * 8));
    529         u32 info = ELF32_R_INFO(sym_elf_idx, etype);
    530         for (int b = 0; b < 4; ++b) slot[4 + b] = (u8)(info >> (b * 8));
    531         if (!uses_rel)
    532           for (int b = 0; b < 4; ++b)
    533             slot[8 + b] = (u8)((u32)r->addend >> (b * 8));
    534       } else {
    535         for (int b = 0; b < 8; ++b) slot[b] = (u8)((u64)r->offset >> (b * 8));
    536         u64 info = ELF64_R_INFO(sym_elf_idx, etype);
    537         for (int b = 0; b < 8; ++b) slot[8 + b] = (u8)(info >> (b * 8));
    538         for (int b = 0; b < 8; ++b)
    539           slot[16 + b] = (u8)((u64)r->addend >> (b * 8));
    540       }
    541       ++j;
    542     }
    543     rela_plans[nrela_plans].obj_section = si;
    544     rela_plans[nrela_plans].bytes = buf;
    545     rela_plans[nrela_plans].size = nr * reloc_ent_size;
    546     nrela_plans++;
    547   }
    548 
    549   /* Append ElfSec entries for each reloc section. Names are ".rel"/".rela"
    550    * + the obj section name (REL for ARM, RELA otherwise); allocate in
    551    * scratch. */
    552   const char* rel_prefix = uses_rel ? ".rel" : ".rela";
    553   u32 prefix_len = uses_rel ? 4u : 5u;
    554   u32* rela_elf_idx = arena_array(c->scratch, u32, nrela_plans + 1);
    555   for (u32 ri = 0; ri < nrela_plans; ++ri) {
    556     u32 si = rela_plans[ri].obj_section;
    557     const Section* s = obj_section_get(ob, si);
    558     u32 base_len;
    559     const char* base = sym_to_str(c, s->name, &base_len);
    560     u32 nlen = prefix_len + base_len; /* ".rel"/".rela" + base */
    561     char* nm = (char*)arena_alloc(c->scratch, nlen + 1, 1);
    562     memcpy(nm, rel_prefix, prefix_len);
    563     memcpy(nm + prefix_len, base, base_len);
    564     nm[nlen] = 0;
    565 
    566     ElfSec* es = &secs[nsecs];
    567     memset(es, 0, sizeof *es);
    568     es->name = nm;
    569     es->name_len = nlen;
    570     es->sh_type = uses_rel ? SHT_REL : SHT_RELA;
    571     es->sh_flags = SHF_INFO_LINK;
    572     es->sh_addralign = is32 ? 4 : 8;
    573     es->sh_entsize = reloc_ent_size;
    574     es->sh_info = obj_to_elf[si]; /* section the relas apply to */
    575     /* sh_link filled below once we know symtab's elf index. */
    576     es->raw_bytes = rela_plans[ri].bytes;
    577     es->sh_size = rela_plans[ri].size;
    578     rela_elf_idx[ri] = nsecs;
    579     nsecs++;
    580   }
    581 
    582   /* Append .symtab. */
    583   {
    584     ElfSec* es = &secs[nsecs];
    585     memset(es, 0, sizeof *es);
    586     es->name = ".symtab";
    587     es->name_len = 7;
    588     es->sh_type = SHT_SYMTAB;
    589     es->sh_flags = 0;
    590     es->sh_addralign = is32 ? 4 : 8;
    591     es->sh_entsize = sym_size;
    592     es->raw_bytes = symtab;
    593     es->sh_size = (u64)nsyms * sym_size;
    594     es->sh_info = nlocals; /* first non-local symbol */
    595     idx_symtab = nsecs;
    596     nsecs++;
    597   }
    598 
    599   /* Patch sh_link on each .rela section now that we have idx_symtab. */
    600   for (u32 ri = 0; ri < nrela_plans; ++ri) {
    601     secs[rela_elf_idx[ri]].sh_link = idx_symtab;
    602   }
    603   /* SHT_GROUP also points its sh_link at .symtab (the symtab the
    604    * signature symbol's index in sh_info refers to). */
    605   for (u32 gi = 1; gi < nobjgrp; ++gi) {
    606     if (group_elf_idx && group_elf_idx[gi]) {
    607       secs[group_elf_idx[gi]].sh_link = idx_symtab;
    608     }
    609   }
    610 
    611   /* ---- pass 4: append section names to the same strtab and emit it.
    612    *
    613    * clang reuses .strtab for both symbol names and section names —
    614    * e_shstrndx and .symtab.sh_link both point at it. Match that
    615    * convention: continue appending into `strtab` (which already
    616    * contains the symbol names), then emit one STRTAB section. */
    617 
    618   /* secs[0] (SHN_UNDEF) carries name "" → offset 0. */
    619   secs[0].sh_name = 0;
    620   for (u32 i = 1; i < nsecs; ++i) {
    621     secs[i].sh_name = obj_strtab_add(&strtab, secs[i].name, secs[i].name_len);
    622   }
    623 
    624   /* Append the .strtab section record itself; its own name lands in
    625    * the same buffer (so the strtab is self-describing). */
    626   {
    627     const char* nm = ".strtab";
    628     u32 nlen = 7;
    629     u32 nameoff = obj_strtab_add(&strtab, nm, nlen);
    630     u32 sz = obj_strtab_size(&strtab);
    631     u8* flat = (u8*)arena_alloc(c->scratch, sz, 1);
    632     memcpy(flat, obj_strtab_data(&strtab), sz);
    633     obj_strtab_fini(&strtab);
    634 
    635     ElfSec* es = &secs[nsecs];
    636     memset(es, 0, sizeof *es);
    637     es->name = nm;
    638     es->name_len = nlen;
    639     es->sh_name = nameoff;
    640     es->sh_type = SHT_STRTAB;
    641     es->sh_addralign = 1;
    642     es->raw_bytes = flat;
    643     es->sh_size = sz;
    644     idx_strtab = nsecs;
    645     idx_shstrtab = nsecs; /* same section serves both roles */
    646     nsecs++;
    647   }
    648   secs[idx_symtab].sh_link = idx_strtab;
    649 
    650   /* ---- pass 5: assign file offsets -------------------------------- */
    651 
    652   u64 cur = ehdr_size;
    653   for (u32 i = 1; i < nsecs; ++i) {
    654     ElfSec* es = &secs[i];
    655     if (es->is_nobits) {
    656       /* sh_offset for NOBITS is conventionally where the next
    657        * non-NOBITS section begins; we set it to cur without
    658        * advancing. */
    659       es->sh_offset = cur;
    660       continue;
    661     }
    662     u64 a = es->sh_addralign ? es->sh_addralign : 1;
    663     cur = ALIGN_UP(cur, a);
    664     es->sh_offset = cur;
    665     cur += es->sh_size;
    666   }
    667   /* ELF32 toolchains conventionally align the SHT to 4; ELF64 to 8. */
    668   cur = ALIGN_UP(cur, (u64)(is32 ? 4 : 8));
    669   u64 e_shoff = cur;
    670 
    671   /* ---- pass 6: write Ehdr ----------------------------------------- */
    672 
    673   u8 ident[EI_NIDENT] = {0};
    674   ident[EI_MAG0] = ELFMAG0;
    675   ident[EI_MAG1] = ELFMAG1;
    676   ident[EI_MAG2] = ELFMAG2;
    677   ident[EI_MAG3] = ELFMAG3;
    678   ident[EI_CLASS] = is32 ? ELFCLASS32 : ELFCLASS64;
    679   ident[EI_DATA] = ELFDATA2LSB;
    680   ident[EI_VERSION] = EV_CURRENT;
    681   /* SysV is the canonical OSABI for Linux relocatable .o files. Targets that
    682    * would otherwise be ambiguous after object detection get explicit badges:
    683    * freestanding uses kit's private STANDALONE byte, and FreeBSD uses the
    684    * standard FreeBSD OSABI so `kit ld` can select FreeBSD runtime/link policy
    685    * from a plain relocatable input.
    686    *
    687    * GNU extensions (STT_GNU_IFUNC, SHF_GNU_RETAIN, ...) upgrade Linux/SysV and
    688    * freestanding objects to ELFOSABI_GNU below. FreeBSD keeps its OSABI badge;
    689    * GNU-flavored symbol/section kinds do not make the target Linux. */
    690   {
    691     Compiler* osc = obj_compiler(ob);
    692     if (osc && osc->target.os == KIT_OS_FREESTANDING)
    693       ident[EI_OSABI] = ELFOSABI_STANDALONE;
    694     else if (osc && osc->target.os == KIT_OS_FREEBSD)
    695       ident[EI_OSABI] = ELFOSABI_FREEBSD;
    696     else
    697       ident[EI_OSABI] = ELFOSABI_NONE;
    698   }
    699   {
    700     ObjSymIter* it = obj_symiter_new(ob);
    701     ObjSymEntry e;
    702     u32 nsec = obj_section_count(ob), si;
    703     while (obj_symiter_next(it, &e)) {
    704       if (e.sym->removed) continue;
    705       if (e.sym->kind == SK_IFUNC) {
    706         if (ident[EI_OSABI] != ELFOSABI_FREEBSD) ident[EI_OSABI] = ELFOSABI_GNU;
    707         break;
    708       }
    709     }
    710     obj_symiter_free(it);
    711     if (ident[EI_OSABI] != ELFOSABI_GNU &&
    712         ident[EI_OSABI] != ELFOSABI_FREEBSD) {
    713       for (si = 1; si < nsec; ++si) {
    714         const Section* sec = obj_section_get(ob, si);
    715         if (sec && !sec->removed && (sec->flags & SF_RETAIN)) {
    716           ident[EI_OSABI] = ELFOSABI_GNU;
    717           break;
    718         }
    719       }
    720     }
    721   }
    722   /* e_flags: prefer the value preserved from a prior read (round-trip);
    723    * otherwise derive the RISC-V ABI/features from the resolved target rather
    724    * than the arch descriptor's default profile. */
    725   u32 e_flags;
    726   if (!obj_get_elf_e_flags(ob, &e_flags)) {
    727     e_flags = elf->e_flags;
    728     /* Both XLENs expose multiple psABIs through -mabi. The static descriptors
    729      * describe only their default profiles, so replace the float bits and the
    730      * RVC presence bit with the resolved target values. */
    731     if (e_machine == EM_RISCV) {
    732       Compiler* ec = obj_compiler(ob);
    733       if (ec) {
    734         u32 fa = elf_riscv_float_abi_to_e_flags(ec->target.float_abi);
    735         e_flags = (e_flags & ~(u32)EF_RISCV_FLOAT_ABI_MASK) | fa;
    736         if (ec->target_ref &&
    737             kit_target_has_feature(ec->target_ref, KIT_SLICE_LIT("c")))
    738           e_flags |= EF_RISCV_RVC;
    739         else
    740           e_flags &= ~(u32)EF_RISCV_RVC;
    741       }
    742     }
    743     /* ARM: keep the EABI version (top byte) from the descriptor and override
    744      * the two float-ABI flag bits from -mfloat-abi (float_abi). */
    745     if (e_machine == EM_ARM) {
    746       Compiler* ec = obj_compiler(ob);
    747       u32 fa = ec ? elf_arm_float_abi_to_e_flags(ec->target.float_abi)
    748                   : EF_ARM_ABI_FLOAT_SOFT;
    749       e_flags = (e_flags & ~(u32)(EF_ARM_ABI_FLOAT_SOFT | EF_ARM_ABI_FLOAT_HARD)) |
    750                 fa;
    751     }
    752   }
    753 
    754   kit_writer_seek(w, 0);
    755   kit_writer_write(w, ident, EI_NIDENT);
    756   elf_wr_u16(w, ET_REL);
    757   elf_wr_u16(w, (u16)e_machine);
    758   elf_wr_u32(w, EV_CURRENT);
    759   /* e_entry/e_phoff/e_shoff are native-width (4B on ELF32, 8B on ELF64);
    760    * the field ORDER is identical, only the widths shrink. */
    761   elf_wr_addr(w, is32, 0);          /* e_entry */
    762   elf_wr_addr(w, is32, 0);          /* e_phoff */
    763   elf_wr_addr(w, is32, e_shoff);    /* e_shoff */
    764   elf_wr_u32(w, e_flags);           /* e_flags */
    765   elf_wr_u16(w, (u16)ehdr_size);    /* e_ehsize */
    766   elf_wr_u16(w, 0);                 /* e_phentsize */
    767   elf_wr_u16(w, 0);                 /* e_phnum */
    768   elf_wr_u16(w, (u16)shdr_size);    /* e_shentsize */
    769   elf_wr_u16(w, (u16)nsecs);        /* e_shnum */
    770   elf_wr_u16(w, (u16)idx_shstrtab); /* e_shstrndx */
    771 
    772   /* ---- pass 7: write each section's bytes ------------------------- */
    773 
    774   for (u32 i = 1; i < nsecs; ++i) {
    775     ElfSec* es = &secs[i];
    776     if (es->is_nobits || es->sh_size == 0) continue;
    777     kit_writer_seek(w, es->sh_offset);
    778     if (es->obj_bytes) {
    779       u32 sz = es->obj_bytes->total;
    780       u8* tmp = (u8*)h->alloc(h, sz ? sz : 1, 1);
    781       if (sz) buf_flatten(es->obj_bytes, tmp);
    782       kit_writer_write(w, tmp, sz);
    783       h->free(h, tmp, sz ? sz : 1);
    784     } else if (es->raw_bytes) {
    785       kit_writer_write(w, es->raw_bytes, (size_t)es->sh_size);
    786     }
    787   }
    788 
    789   /* ---- pass 8: write section header table ------------------------- */
    790 
    791   kit_writer_seek(w, e_shoff);
    792   for (u32 i = 0; i < nsecs; ++i) {
    793     const ElfSec* es = &secs[i];
    794     /* Elf32_Shdr (40B) and Elf64_Shdr (64B) share field ORDER; only
    795      * sh_flags/sh_addr/sh_offset/sh_size/sh_addralign/sh_entsize narrow
    796      * from u64 to u32 under is32. */
    797     elf_wr_u32(w, es->sh_name);
    798     elf_wr_u32(w, es->sh_type);
    799     elf_wr_addr(w, is32, es->sh_flags);
    800     elf_wr_addr(w, is32, es->sh_addr);
    801     elf_wr_addr(w, is32, es->sh_offset);
    802     elf_wr_addr(w, is32, es->sh_size);
    803     elf_wr_u32(w, es->sh_link);
    804     elf_wr_u32(w, es->sh_info);
    805     elf_wr_addr(w, is32, es->sh_addralign);
    806     elf_wr_addr(w, is32, es->sh_entsize);
    807   }
    808 }