emit.c (26582B)
1 /* PE/COFF relocatable .obj writer. Walks a finalized ObjBuilder and 2 * emits a 64-bit little-endian relocatable object via the supplied 3 * Writer. Counterpart to emit_elf / emit_macho. 4 * 5 * Layout strategy: 6 * 1. plan COFF sections (one per kept obj section), assigning 7 * Characteristics, alignment, raw size, and per-section reloc 8 * counts; 9 * 2. build the symbol table (synthesized per-section static symbols 10 * with section-definition aux records, plus file symbols and 11 * every ObjSym kept after sweep); 12 * 3. build per-section relocation records via the per-arch 13 * translator (arch_for_compiler(c)->coff->reloc_to); 14 * 4. assign file offsets: 15 * file header | section headers | (bytes + relocs)* | symtab | strtab 16 * 5. write the file in that order. 17 * 18 * 64-bit little-endian only — IMAGE_FILE_MACHINE_AMD64 (x86_64) and 19 * IMAGE_FILE_MACHINE_ARM64 (aarch64). Big-endian / ptr_size != 8 panic 20 * at entry. 21 * 22 * Section name mapping policy: we pass the kit Section.name through 23 * verbatim to the COFF Name field. Callers / readers are expected to 24 * have stored COFF-shaped names (".text", ".rdata", ".tls$", etc.) at 25 * the obj layer; emit_coff does not rewrite ELF-style spellings like 26 * ".rodata" -> ".rdata". Names longer than 8 bytes spill into the 27 * string table with the "/<decimal-offset>" encoding. 28 * 29 * Addend handling: COFF stores the addend inline in the patched bytes 30 * (there is no addend field in IMAGE_RELOCATION). The ObjBuilder 31 * caller is responsible for having written the addend into the section 32 * bytes already — matching how MSVC / mingw emit. A nonzero 33 * Reloc::addend with has_explicit_addend set is rejected here as a 34 * known v1 limitation. */ 35 36 #include <string.h> 37 38 #include "core/arena.h" 39 #include "core/buf.h" 40 #include "core/heap.h" 41 #include "core/pool.h" 42 #include "core/slice.h" 43 #include "core/util.h" 44 #include "obj/coff/coff.h" 45 #include "obj/format.h" 46 47 static int coff_rel32_absorbs_minus4(KitArchKind arch, RelocKind kind, 48 i64 addend) { 49 if (arch != KIT_ARCH_X86_64 || addend != -4) return 0; 50 switch (kind) { 51 case R_PC32: 52 case R_REL32: 53 case R_PLT32: 54 case R_X64_PLT32: 55 case R_X64_GOTPCREL: 56 case R_X64_GOTPCRELX: 57 case R_X64_REX_GOTPCRELX: 58 return 1; 59 default: 60 return 0; 61 } 62 } 63 64 /* ---- per-COFF-section plan record ---- */ 65 66 typedef struct CSec { 67 /* IMAGE_SECTION_HEADER fields (little-endian-encoded at write time). */ 68 char name8[8]; /* Name field bytes; "/N" form if long name */ 69 u32 virtual_size; /* nonzero for NOBITS (bss size) */ 70 u32 size_of_raw_data; /* zero for NOBITS */ 71 u32 pointer_to_raw_data; 72 u32 pointer_to_relocations; 73 u16 number_of_relocations; 74 u32 characteristics; /* IMAGE_SCN_* | ALIGN nibble */ 75 76 /* Planning state. */ 77 u32 align; /* in bytes, power of two */ 78 u32 obj_sec; /* originating ObjSecId */ 79 int is_nobits; 80 const Buf* obj_bytes; /* NULL when nobits */ 81 u8* reloc_bytes; /* arena-allocated, nreloc * 10 bytes */ 82 ObjGroupId group_id; /* OBJ_GROUP_NONE if not in a group */ 83 } CSec; 84 85 /* ---- emit ---- */ 86 87 static u32 log2_align(u32 a) { 88 u32 r = 0; 89 while ((1u << r) < a) ++r; 90 return r; 91 } 92 93 /* Map kit section flags/sem to IMAGE_SCN_* Characteristics, leaving 94 * the alignment nibble for the caller to OR in. */ 95 static u32 sec_characteristics(const Section* s, int in_group) { 96 u32 r = 0; 97 int is_bss = (s->kind == SEC_BSS) || (s->sem == SSEM_NOBITS); 98 if (s->flags & SF_EXEC) { 99 r |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE; 100 } else if (is_bss) { 101 r |= IMAGE_SCN_CNT_UNINITIALIZED_DATA; 102 } else if (s->flags & SF_WRITE) { 103 r |= IMAGE_SCN_CNT_INITIALIZED_DATA; 104 } else if (s->flags & SF_ALLOC) { 105 /* Read-only allocated data (.rdata). */ 106 r |= IMAGE_SCN_CNT_INITIALIZED_DATA; 107 } 108 if (s->flags & SF_ALLOC) r |= IMAGE_SCN_MEM_READ; 109 if (s->flags & SF_WRITE) r |= IMAGE_SCN_MEM_WRITE; 110 if (in_group) r |= IMAGE_SCN_LNK_COMDAT; 111 /* When a reader stashed format-specific flag bits on a COFF-origin 112 * section, OR them back in here. ext_type carries the raw 113 * Characteristics value (or zero if no override); ext_flags is a 114 * sibling bag for any bits the canonical mapping above would lose. */ 115 if (s->ext_kind == OBJ_EXT_COFF) { 116 if (s->ext_type) { 117 /* Preserve the raw characteristics verbatim — overrides the 118 * canonical mapping. Keeps round-trip byte-stable for sections 119 * carrying CNT_INFO / LNK_REMOVE / MEM_DISCARDABLE / etc. */ 120 r = s->ext_type & ~IMAGE_SCN_ALIGN_MASK; 121 } 122 r |= s->ext_flags; 123 } 124 return r; 125 } 126 127 /* Append `len` bytes of `s` followed by a single NUL to `b`, returning 128 * the offset at which `s` was placed. Dedupe linearly — strtabs are 129 * small enough that this is fine without a hash table, and the 130 * dedupe matches what binutils / llvm-objcopy emit. Mirror of the 131 * helper in elf_emit. */ 132 static u32 strtab_add(Buf* b, const char* s, u32 len) { 133 if (len == 0) return 0; 134 u32 total = buf_pos(b); 135 if (total > len) { 136 u8 stack[256]; 137 u8* tmp = 138 total <= sizeof stack ? stack : (u8*)b->heap->alloc(b->heap, total, 1); 139 if (tmp) { 140 buf_flatten(b, tmp); 141 /* Skip the first 4 bytes (the size-prefix placeholder) when 142 * searching for matches. */ 143 u32 start = COFF_STRTAB_SIZE_FIELD_BYTES; 144 if (total > start + len) { 145 for (u32 i = start; i + len < total; ++i) { 146 if (tmp[i + len] == 0 && memcmp(tmp + i, s, len) == 0) { 147 if (tmp != stack) b->heap->free(b->heap, tmp, total); 148 return i; 149 } 150 } 151 } 152 if (tmp != stack) b->heap->free(b->heap, tmp, total); 153 } 154 } 155 u32 off = total; 156 buf_write(b, s, len); 157 { 158 u8 z = 0; 159 buf_write(b, &z, 1); 160 } 161 return off; 162 } 163 164 /* Encode an 8-byte Name field. If the name fits in 8 bytes, copy 165 * verbatim and zero-pad. Otherwise allocate the name in `strtab` and 166 * write "/<decimal-offset>" (NUL-padded to 8 bytes). */ 167 static void encode_name8(char out[8], const char* name, u32 nlen, Buf* strtab) { 168 memset(out, 0, 8); 169 if (nlen <= 8) { 170 if (nlen) memcpy(out, name, nlen); 171 return; 172 } 173 u32 off = strtab_add(strtab, name, nlen); 174 /* "/<decimal-offset>" — up to 7 decimal digits leaves room for the 175 * leading slash within 8 bytes. COFF .obj strtabs are < 1 MiB in 176 * practice, so 7 digits is plenty. */ 177 char tmp[16]; 178 int n = 0; 179 tmp[n++] = '/'; 180 /* Decimal-format off into tmp+1. */ 181 char dig[12]; 182 int d = 0; 183 u32 v = off; 184 if (v == 0) { 185 dig[d++] = '0'; 186 } else { 187 while (v) { 188 dig[d++] = (char)('0' + (v % 10u)); 189 v /= 10u; 190 } 191 } 192 while (d > 0 && n < (int)sizeof tmp) tmp[n++] = dig[--d]; 193 if (n > 8) n = 8; 194 memcpy(out, tmp, (size_t)n); 195 } 196 197 /* Write one 18-byte IMAGE_SYMBOL record into `dst`. */ 198 static void wr_sym(u8* dst, const char ShortName[8], u32 Zeroes, u32 Offset, 199 u32 Value, i16 SectionNumber, u16 Type, u8 StorageClass, 200 u8 NumberOfAuxSymbols) { 201 if (Zeroes == 0 && Offset != 0) { 202 /* LongName form: 4 zero bytes then 4-byte LE strtab offset. */ 203 memset(dst, 0, 4); 204 wr_u32_le(dst + 4, Offset); 205 } else { 206 memcpy(dst, ShortName, 8); 207 } 208 wr_u32_le(dst + 8, Value); 209 wr_u16_le(dst + 12, (u16)SectionNumber); 210 wr_u16_le(dst + 14, Type); 211 dst[16] = StorageClass; 212 dst[17] = NumberOfAuxSymbols; 213 } 214 215 /* Write a section-definition aux record (18 bytes). */ 216 static void wr_aux_secdef(u8* dst, u32 Length, u16 NumberOfRelocations, 217 u16 NumberOfLinenumbers, u32 CheckSum, u16 Number, 218 u8 Selection) { 219 wr_u32_le(dst + 0, Length); 220 wr_u16_le(dst + 4, NumberOfRelocations); 221 wr_u16_le(dst + 6, NumberOfLinenumbers); 222 wr_u32_le(dst + 8, CheckSum); 223 wr_u16_le(dst + 12, Number); 224 dst[14] = Selection; 225 dst[15] = 0; 226 dst[16] = 0; 227 dst[17] = 0; 228 } 229 230 /* Write a weak-externals aux record (18 bytes). */ 231 static void wr_aux_weak(u8* dst, u32 TagIndex, u32 Characteristics) { 232 wr_u32_le(dst + 0, TagIndex); 233 wr_u32_le(dst + 4, Characteristics); 234 memset(dst + 8, 0, 10); 235 } 236 237 /* Look up the pool-interned string for a Sym. */ 238 static const char* sym_to_str(Compiler* c, Sym n, u32* len_out) { 239 Slice sl = pool_slice(c->global, n); 240 const char* s = sl.s; 241 if (!s) { 242 *len_out = 0; 243 return ""; 244 } 245 *len_out = (u32)sl.len; 246 return s; 247 } 248 249 void emit_coff(Compiler* c, ObjBuilder* ob, Writer* w) { 250 Heap* h = (Heap*)c->ctx->heap; 251 252 /* Tombstone sweep — see obj_sweep_dead. */ 253 obj_sweep_dead(ob); 254 255 /* ---- target validation ----------------------------------------- */ 256 const ObjFormatImpl* fmt = obj_format_lookup(KIT_OBJ_COFF); 257 const ObjCoffArchOps* coff = 258 fmt && fmt->coff_arch ? fmt->coff_arch(c->target.arch) : NULL; 259 if (!coff || !coff->reloc_to) { 260 compiler_panic(c, SRCLOC_NONE, "emit_coff: unsupported target arch %u", 261 (u32)c->target.arch); 262 } 263 u16 machine = coff->machine; 264 u32 (*reloc_to)(u32) = coff->reloc_to; 265 if (c->target.big_endian) { 266 compiler_panic(c, SRCLOC_NONE, "emit_coff: big-endian COFF not supported"); 267 } 268 if (c->target.ptr_size != 8) { 269 compiler_panic(c, SRCLOC_NONE, "emit_coff: ptr_size %u (expected 8)", 270 (u32)c->target.ptr_size); 271 } 272 273 /* ---- pass 1: plan sections ------------------------------------- */ 274 u32 nobjsec = obj_section_count(ob); 275 CSec* secs = arena_zarray(c->scratch, CSec, nobjsec ? nobjsec : 1); 276 u32* obj_to_coff = arena_zarray(c->scratch, u32, nobjsec ? nobjsec : 1); 277 u32 nsecs = 0; 278 279 /* String table — leading 4-byte size placeholder. Real strings start 280 * at offset 4. */ 281 Buf strtab; 282 buf_init(&strtab, h); 283 { 284 u8 zero4[COFF_STRTAB_SIZE_FIELD_BYTES] = {0, 0, 0, 0}; 285 buf_write(&strtab, zero4, COFF_STRTAB_SIZE_FIELD_BYTES); 286 } 287 288 for (u32 i = 1; i < nobjsec; ++i) { 289 const Section* s = obj_section_get(ob, i); 290 if (s->removed) continue; 291 /* Skip ELF-style synthetic sections (a reader from another format 292 * may have surfaced them) — COFF stores symtab/strtab/relocs 293 * out-of-band, not as named sections. */ 294 if (s->sem == SSEM_SYMTAB || s->sem == SSEM_STRTAB || s->sem == SSEM_RELA || 295 s->sem == SSEM_REL || s->sem == SSEM_GROUP) { 296 continue; 297 } 298 299 CSec* cs = &secs[nsecs]; 300 u32 nlen; 301 const char* nm = sym_to_str(c, s->name, &nlen); 302 encode_name8(cs->name8, nm, nlen, &strtab); 303 304 cs->obj_sec = i; 305 cs->group_id = s->group_id; 306 cs->align = s->align ? s->align : 1; 307 308 int in_group = (s->group_id != OBJ_GROUP_NONE); 309 u32 ch = sec_characteristics(s, in_group); 310 /* Alignment lives in bits 20..23. Cap at log2(8192)=13 -> nibble 311 * value 14 (IMAGE_SCN_ALIGN_8192BYTES). */ 312 u32 lg = log2_align(cs->align); 313 if (lg > 13) lg = 13; 314 ch &= ~IMAGE_SCN_ALIGN_MASK; 315 ch |= IMAGE_SCN_ALIGN_FROM_LOG2(lg); 316 cs->characteristics = ch; 317 318 if (s->sem == SSEM_NOBITS || s->kind == SEC_BSS) { 319 cs->is_nobits = 1; 320 cs->virtual_size = s->bss_size; 321 cs->size_of_raw_data = 0; 322 cs->obj_bytes = NULL; 323 } else { 324 cs->is_nobits = 0; 325 cs->virtual_size = 0; 326 cs->size_of_raw_data = s->bytes.total; 327 cs->obj_bytes = &s->bytes; 328 } 329 330 obj_to_coff[i] = nsecs + 1; /* 1-based; matches SectionNumber. */ 331 nsecs++; 332 } 333 334 /* ---- pass 2: count and assign per-section reloc counts --------- */ 335 /* COFF stores NumberOfRelocations as u16; sections with > 65535 336 * relocs use the IMAGE_SCN_LNK_NRELOC_OVFL extension which we don't 337 * implement in v1. Panic if any single section exceeds the limit. */ 338 u32 total_relocs = obj_reloc_total(ob); 339 for (u32 ci = 0; ci < nsecs; ++ci) { 340 CSec* cs = &secs[ci]; 341 u32 nr = obj_reloc_count(ob, cs->obj_sec); 342 if (nr > 0xFFFFu) { 343 compiler_panic(c, SRCLOC_NONE, 344 "emit_coff: section %u has %u relocs (max 65535)", 345 (u32)cs->obj_sec, nr); 346 } 347 cs->number_of_relocations = (u16)nr; 348 } 349 350 /* ---- pass 3: build the symbol table ---------------------------- */ 351 /* Count ObjSyms (incl. tombstoned — we'll skip those when emitting). */ 352 u32 nobjsym = 0; 353 { 354 ObjSymIter* it = obj_symiter_new(ob); 355 ObjSymEntry e; 356 while (obj_symiter_next(it, &e)) ++nobjsym; 357 obj_symiter_free(it); 358 } 359 360 /* Upper bound on symbol-table records (including aux slots): 361 * - 2 records per section symbol (primary + 1 aux secdef) 362 * - 2 records per ObjSym (primary + up to 1 weak aux) 363 * - +2 spare for safety 364 * Worst case is generous; we trim by tracking nrecords as we emit. */ 365 u32 max_records = 2u * nsecs + 2u * nobjsym + 4u; 366 u8* symtab = 367 (u8*)arena_zarray(c->scratch, u8, (size_t)COFF_SYMBOL_SIZE * max_records); 368 u32 nrecords = 0; 369 370 /* obj_id -> COFF symbol index (including aux slots). Index 0 is 371 * reserved as "none" in our internal map (a real COFF symbol may 372 * legitimately live at index 0, but no ObjSym ever maps there since 373 * we never put OBJ_SYM_NONE through). */ 374 u32* sym_to_coff = arena_zarray(c->scratch, u32, nobjsym + 2); 375 376 /* Section symbols first — one STATIC per kept obj section, each 377 * followed by a SECTION DEFINITION aux. Reloc-against-section in 378 * other tools' output uses these; emitting them unconditionally 379 * matches what clang / mingw emit and gives readers a stable target. */ 380 u32* secsym_index = arena_zarray(c->scratch, u32, nsecs + 1); 381 for (u32 ci = 0; ci < nsecs; ++ci) { 382 CSec* cs = &secs[ci]; 383 char short_name[8]; 384 /* The section symbol's name is the section's own name (truncated 385 * to 8 bytes — section symbols never use the strtab spill form in 386 * MSVC/clang output). */ 387 memcpy(short_name, cs->name8, 8); 388 389 u8* slot = symtab + (size_t)nrecords * COFF_SYMBOL_SIZE; 390 wr_sym(slot, short_name, /*Zeroes*/ 1, /*Offset*/ 0, 391 /*Value*/ 0, 392 /*SectionNumber*/ (i16)(ci + 1), 393 /*Type*/ IMAGE_SYM_TYPE_NULL, 394 /*StorageClass*/ IMAGE_SYM_CLASS_STATIC, 395 /*NumberOfAuxSymbols*/ 1); 396 secsym_index[ci] = nrecords; 397 nrecords++; 398 399 /* Section-definition aux. For COMDAT members we encode the 400 * Selection from the group; default to SELECT_ANY which is what 401 * gcc/clang emit unless the user requests a specific selection 402 * mode. The associated-section Number is left at 0 (kit does 403 * not produce associative-COMDAT chains today). */ 404 u8 selection = 0; 405 if (cs->group_id != OBJ_GROUP_NONE) { 406 const ObjGroup* g = obj_group_get(ob, cs->group_id); 407 if (g && !g->removed) { 408 selection = g->flags ? (u8)IMAGE_COMDAT_SELECT_ANY 409 : (u8)IMAGE_COMDAT_SELECT_ANY; 410 } 411 } 412 u8* aux = symtab + (size_t)nrecords * COFF_SYMBOL_SIZE; 413 wr_aux_secdef(aux, /*Length*/ cs->size_of_raw_data, 414 /*NumberOfRelocations*/ cs->number_of_relocations, 415 /*NumberOfLinenumbers*/ 0, 416 /*CheckSum*/ 0, 417 /*Number*/ 0, 418 /*Selection*/ selection); 419 nrecords++; 420 } 421 422 /* File / regular symbols. */ 423 { 424 ObjSymIter* it = obj_symiter_new(ob); 425 ObjSymEntry e; 426 while (obj_symiter_next(it, &e)) { 427 const ObjSym* s = e.sym; 428 if (s->removed) continue; 429 if (s->kind == SK_IFUNC) { 430 compiler_panic(c, SRCLOC_NONE, 431 "emit_coff: SK_IFUNC has no PE/COFF representation"); 432 } 433 /* Don't re-emit SK_SECTION symbols — section symbols are 434 * synthesized above. Map any input-side SK_SECTION onto the 435 * already-emitted one. */ 436 if (s->kind == SK_SECTION) { 437 if (s->section_id && s->section_id < nobjsec) { 438 u32 ci = obj_to_coff[s->section_id]; 439 if (ci) sym_to_coff[e.id] = secsym_index[ci - 1]; 440 } 441 continue; 442 } 443 444 u32 nlen; 445 const char* nm = sym_to_str(c, s->name, &nlen); 446 447 if (s->kind == SK_FILE) { 448 /* File symbol: name ".file" (short), section IMAGE_SYM_DEBUG, 449 * storage class FILE, followed by aux records carrying the 450 * NUL-padded file path (18 bytes per aux). */ 451 u32 file_len = nlen; 452 u32 naux = 453 file_len ? (file_len + COFF_AUX_FILE_SIZE - 1u) / COFF_AUX_FILE_SIZE 454 : 1u; 455 char short_name[8] = {'.', 'f', 'i', 'l', 'e', 0, 0, 0}; 456 u8* slot = symtab + (size_t)nrecords * COFF_SYMBOL_SIZE; 457 wr_sym(slot, short_name, 1, 0, /*Value*/ 0, 458 /*SectionNumber*/ (i16)IMAGE_SYM_DEBUG, 459 /*Type*/ IMAGE_SYM_TYPE_NULL, 460 /*StorageClass*/ IMAGE_SYM_CLASS_FILE, 461 /*NumberOfAuxSymbols*/ (u8)naux); 462 sym_to_coff[e.id] = nrecords; 463 nrecords++; 464 for (u32 a = 0; a < naux; ++a) { 465 u8* aux = symtab + (size_t)nrecords * COFF_SYMBOL_SIZE; 466 memset(aux, 0, COFF_AUX_FILE_SIZE); 467 u32 off = a * COFF_AUX_FILE_SIZE; 468 u32 copy = file_len > off ? file_len - off : 0; 469 if (copy > COFF_AUX_FILE_SIZE) copy = COFF_AUX_FILE_SIZE; 470 if (copy) memcpy(aux, nm + off, copy); 471 nrecords++; 472 } 473 continue; 474 } 475 476 /* Regular symbol. */ 477 char short_name[8]; 478 u32 zeroes = 1, offset = 0; 479 memset(short_name, 0, 8); 480 if (nlen <= 8) { 481 if (nlen) memcpy(short_name, nm, nlen); 482 } else { 483 zeroes = 0; 484 offset = strtab_add(&strtab, nm, nlen); 485 } 486 487 i16 section_number = 0; 488 u32 value = 0; 489 u8 storage_class = IMAGE_SYM_CLASS_NULL; 490 u16 type = IMAGE_SYM_TYPE_NULL; 491 u8 naux = 0; 492 int emit_weak_aux = 0; 493 494 switch (s->kind) { 495 case SK_ABS: 496 section_number = (i16)IMAGE_SYM_ABSOLUTE; 497 value = (u32)s->value; 498 break; 499 case SK_COMMON: 500 /* COFF lacks a per-common alignment field; encode size in 501 * Value with SectionNumber=UNDEFINED and rely on the linker 502 * to pick a default alignment. (kit's frontend uses 503 * COMMON only via __attribute__((common)) which is rare on 504 * PE/COFF targets.) */ 505 section_number = (i16)IMAGE_SYM_UNDEFINED; 506 value = (u32)s->size; 507 break; 508 default: 509 if (s->section_id == OBJ_SEC_NONE) { 510 section_number = (i16)IMAGE_SYM_UNDEFINED; 511 value = 0; 512 } else if (s->section_id < nobjsec && obj_to_coff[s->section_id]) { 513 section_number = (i16)obj_to_coff[s->section_id]; 514 value = (u32)s->value; 515 } else { 516 section_number = (i16)IMAGE_SYM_UNDEFINED; 517 value = 0; 518 } 519 break; 520 } 521 522 if (s->kind == SK_FUNC) type = (u16)COFF_SYM_TYPE_FUNCTION; 523 524 switch (s->bind) { 525 case SB_LOCAL: 526 storage_class = IMAGE_SYM_CLASS_STATIC; 527 break; 528 case SB_GLOBAL: 529 storage_class = IMAGE_SYM_CLASS_EXTERNAL; 530 break; 531 case SB_WEAK: 532 /* mingw / clang spell weak as EXTERNAL with a WeakExternal 533 * aux that points at the fallback symbol. kit's obj layer 534 * doesn't carry a separate fallback symbol today, so we emit 535 * a self-referential weak aux (TagIndex=0) which the linker 536 * treats as "weak, no fallback" — equivalent to ELF STB_WEAK. */ 537 storage_class = IMAGE_SYM_CLASS_WEAK_EXTERNAL; 538 emit_weak_aux = 1; 539 naux = 1; 540 break; 541 default: 542 storage_class = IMAGE_SYM_CLASS_STATIC; 543 break; 544 } 545 546 u8* slot = symtab + (size_t)nrecords * COFF_SYMBOL_SIZE; 547 wr_sym(slot, short_name, zeroes, offset, value, section_number, type, 548 storage_class, naux); 549 sym_to_coff[e.id] = nrecords; 550 nrecords++; 551 if (emit_weak_aux) { 552 u8* aux = symtab + (size_t)nrecords * COFF_SYMBOL_SIZE; 553 wr_aux_weak(aux, /*TagIndex*/ 0, 554 /*Characteristics*/ IMAGE_WEAK_EXTERN_SEARCH_LIBRARY); 555 nrecords++; 556 } 557 } 558 obj_symiter_free(it); 559 } 560 561 /* ---- pass 4: build per-section relocation tables --------------- */ 562 for (u32 ci = 0; ci < nsecs; ++ci) { 563 CSec* cs = &secs[ci]; 564 u32 nr = cs->number_of_relocations; 565 if (!nr) continue; 566 u8* buf = (u8*)arena_alloc(c->scratch, (size_t)COFF_RELOC_SIZE * nr, 567 _Alignof(u32)); 568 u32 j = 0; 569 for (u32 ri = 0; ri < total_relocs; ++ri) { 570 const Reloc* r = obj_reloc_at(ob, ri); 571 if (r->removed) continue; 572 if (r->section_id != cs->obj_sec) continue; 573 if (r->sym == OBJ_SYM_NONE) { 574 compiler_panic(c, SRCLOC_NONE, 575 "emit_coff: reloc without symbol not supported " 576 "(sec=%u offset=%u kind=%u)", 577 (u32)r->section_id, (u32)r->offset, (u32)r->kind); 578 } 579 if (r->has_explicit_addend && r->addend != 0 && 580 !coff_rel32_absorbs_minus4(c->target.arch, (RelocKind)r->kind, 581 r->addend)) { 582 /* v1 limitation: COFF carries the addend in the patched bytes, 583 * and we don't currently mutate the obj's section bytes to 584 * encode a separate explicit addend. kit's MCEmitter writes 585 * the addend inline for COFF targets, so this branch only 586 * fires for inputs synthesized by external tools. */ 587 compiler_panic(c, SRCLOC_NONE, 588 "emit_coff: explicit nonzero addend not supported " 589 "(sec=%u offset=%u kind=%u addend=%lld)", 590 (u32)r->section_id, (u32)r->offset, (u32)r->kind, 591 (long long)r->addend); 592 } 593 u32 wire = reloc_to(r->kind); 594 /* Both arch translators use 0 (IMAGE_REL_*_ABSOLUTE) as the 595 * unsupported-input sentinel; treat that as a panic unless the 596 * input really is R_NONE. */ 597 if (wire == 0 && r->kind != R_NONE) { 598 compiler_panic(c, SRCLOC_NONE, 599 "emit_coff: unsupported relocation kind %u for arch %u", 600 (u32)r->kind, (u32)c->target.arch); 601 } 602 u32 sym_idx = sym_to_coff[r->sym]; 603 u8* slot = buf + (size_t)j * COFF_RELOC_SIZE; 604 wr_u32_le(slot + 0, r->offset); 605 wr_u32_le(slot + 4, sym_idx); 606 wr_u16_le(slot + 8, (u16)wire); 607 ++j; 608 } 609 cs->reloc_bytes = buf; 610 /* If a tombstoned reloc was skipped between count and emit, j may 611 * be less than nr; trust the latter count for the wire field. */ 612 if (j != nr) cs->number_of_relocations = (u16)j; 613 } 614 615 /* ---- pass 5: assign file offsets ------------------------------- */ 616 /* Layout: 617 * [file header] [section headers] [per-section: bytes, relocs]* 618 * [symbol table] [string table] */ 619 u64 cur = 620 (u64)COFF_FILE_HEADER_SIZE + (u64)COFF_SECTION_HEADER_SIZE * (u64)nsecs; 621 622 for (u32 ci = 0; ci < nsecs; ++ci) { 623 CSec* cs = &secs[ci]; 624 /* Raw data offset. NOBITS contributes nothing on disk. */ 625 if (cs->is_nobits || cs->size_of_raw_data == 0) { 626 cs->pointer_to_raw_data = 0; 627 } else { 628 cur = ALIGN_UP(cur, (u64)cs->align); 629 cs->pointer_to_raw_data = (u32)cur; 630 cur += cs->size_of_raw_data; 631 } 632 /* Reloc table. COFF doesn't mandate alignment for the reloc array, 633 * but llvm and binutils emit them naturally byte-packed; we 4-align 634 * for tidiness. */ 635 if (cs->number_of_relocations) { 636 cur = ALIGN_UP(cur, (u64)4); 637 cs->pointer_to_relocations = (u32)cur; 638 cur += (u64)cs->number_of_relocations * COFF_RELOC_SIZE; 639 } else { 640 cs->pointer_to_relocations = 0; 641 } 642 } 643 644 cur = ALIGN_UP(cur, (u64)4); 645 u64 symtab_off = cur; 646 cur += (u64)nrecords * COFF_SYMBOL_SIZE; 647 648 /* String table starts immediately after the symtab. Patch the 4-byte 649 * size prefix (inclusive). */ 650 u32 strtab_size = buf_pos(&strtab); 651 /* The size field is part of the on-disk strtab and is the total 652 * inclusive byte count. Patch it now. */ 653 { 654 u8 sz_le[4]; 655 wr_u32_le(sz_le, strtab_size); 656 /* Buf doesn't expose in-place patch; flatten, patch, re-emit when 657 * we write. Just remember the value. */ 658 (void)sz_le; 659 } 660 u64 strtab_off = cur; 661 cur += strtab_size; 662 663 /* ---- pass 6: write the file ------------------------------------ */ 664 kit_writer_seek(w, 0); 665 666 /* IMAGE_FILE_HEADER */ 667 coff_wr_u16(w, machine); 668 coff_wr_u16(w, (u16)nsecs); 669 coff_wr_u32(w, 0); /* TimeDateStamp: reproducible */ 670 coff_wr_u32(w, (u32)symtab_off); 671 coff_wr_u32(w, nrecords); 672 coff_wr_u16(w, 0); /* SizeOfOptionalHeader: 0 for .obj */ 673 coff_wr_u16(w, IMAGE_FILE_LARGE_ADDRESS_AWARE); 674 675 /* Section headers — one 40-byte block immediately after the file 676 * header. */ 677 for (u32 ci = 0; ci < nsecs; ++ci) { 678 const CSec* cs = &secs[ci]; 679 kit_writer_write(w, cs->name8, 8); 680 coff_wr_u32(w, cs->virtual_size); 681 coff_wr_u32(w, 0); /* VirtualAddress: 0 for .obj */ 682 coff_wr_u32(w, cs->size_of_raw_data); 683 coff_wr_u32(w, cs->pointer_to_raw_data); 684 coff_wr_u32(w, cs->pointer_to_relocations); 685 coff_wr_u32(w, 0); /* PointerToLinenumbers: 0 */ 686 coff_wr_u16(w, cs->number_of_relocations); 687 coff_wr_u16(w, 0); /* NumberOfLinenumbers: 0 */ 688 coff_wr_u32(w, cs->characteristics); 689 } 690 691 /* Section bytes + relocs (interleaved). */ 692 for (u32 ci = 0; ci < nsecs; ++ci) { 693 const CSec* cs = &secs[ci]; 694 if (!cs->is_nobits && cs->size_of_raw_data && cs->obj_bytes) { 695 kit_writer_seek(w, cs->pointer_to_raw_data); 696 u32 sz = cs->obj_bytes->total; 697 u8* tmp = (u8*)h->alloc(h, sz ? sz : 1, 1); 698 if (sz) buf_flatten(cs->obj_bytes, tmp); 699 kit_writer_write(w, tmp, sz); 700 h->free(h, tmp, sz ? sz : 1); 701 } 702 if (cs->number_of_relocations && cs->reloc_bytes) { 703 kit_writer_seek(w, cs->pointer_to_relocations); 704 kit_writer_write(w, cs->reloc_bytes, 705 (size_t)cs->number_of_relocations * COFF_RELOC_SIZE); 706 } 707 } 708 709 /* Symbol table. */ 710 kit_writer_seek(w, symtab_off); 711 kit_writer_write(w, symtab, (size_t)nrecords * COFF_SYMBOL_SIZE); 712 713 /* String table: 4-byte total size (inclusive) followed by the body. 714 * `strtab` was initialized with 4 placeholder zero bytes; rewrite 715 * them with the real size before flushing. */ 716 { 717 u8* flat = (u8*)arena_alloc(c->scratch, strtab_size ? strtab_size : 1, 1); 718 if (strtab_size) buf_flatten(&strtab, flat); 719 /* Patch the 4-byte size prefix in place. */ 720 if (strtab_size >= COFF_STRTAB_SIZE_FIELD_BYTES) { 721 wr_u32_le(flat, strtab_size); 722 } 723 kit_writer_seek(w, strtab_off); 724 kit_writer_write(w, flat, strtab_size); 725 } 726 buf_fini(&strtab); 727 }