emit.c (26378B)
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; /* 0 for .obj (VirtualSize is image-only) */ 70 u32 size_of_raw_data; /* section size, incl. NOBITS (bss) size */ 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 /* The string-table dedup + build moved to the shared ObjStrtab (obj.h); the 128 * former per-add buf_flatten + linear substring scan here was the same O(n^2) 129 * the ELF writer had. The COFF strtab keeps its leading 4-byte size field (a 130 * raw prefix the dedup never targets, see obj_strtab_put_raw). */ 131 132 /* Encode an 8-byte Name field. If the name fits in 8 bytes, copy 133 * verbatim and zero-pad. Otherwise allocate the name in `strtab` and 134 * write "/<decimal-offset>" (NUL-padded to 8 bytes). */ 135 static void encode_name8(char out[8], const char* name, u32 nlen, 136 ObjStrtab* strtab) { 137 memset(out, 0, 8); 138 if (nlen <= 8) { 139 if (nlen) memcpy(out, name, nlen); 140 return; 141 } 142 u32 off = obj_strtab_add(strtab, name, nlen); 143 /* "/<decimal-offset>" — up to 7 decimal digits leaves room for the 144 * leading slash within 8 bytes. COFF .obj strtabs are < 1 MiB in 145 * practice, so 7 digits is plenty. */ 146 char tmp[16]; 147 int n = 0; 148 tmp[n++] = '/'; 149 /* Decimal-format off into tmp+1. */ 150 char dig[12]; 151 int d = 0; 152 u32 v = off; 153 if (v == 0) { 154 dig[d++] = '0'; 155 } else { 156 while (v) { 157 dig[d++] = (char)('0' + (v % 10u)); 158 v /= 10u; 159 } 160 } 161 while (d > 0 && n < (int)sizeof tmp) tmp[n++] = dig[--d]; 162 if (n > 8) n = 8; 163 memcpy(out, tmp, (size_t)n); 164 } 165 166 /* Write one 18-byte IMAGE_SYMBOL record into `dst`. */ 167 static void wr_sym(u8* dst, const char ShortName[8], u32 Zeroes, u32 Offset, 168 u32 Value, i16 SectionNumber, u16 Type, u8 StorageClass, 169 u8 NumberOfAuxSymbols) { 170 if (Zeroes == 0 && Offset != 0) { 171 /* LongName form: 4 zero bytes then 4-byte LE strtab offset. */ 172 memset(dst, 0, 4); 173 wr_u32_le(dst + 4, Offset); 174 } else { 175 memcpy(dst, ShortName, 8); 176 } 177 wr_u32_le(dst + 8, Value); 178 wr_u16_le(dst + 12, (u16)SectionNumber); 179 wr_u16_le(dst + 14, Type); 180 dst[16] = StorageClass; 181 dst[17] = NumberOfAuxSymbols; 182 } 183 184 /* Write a section-definition aux record (18 bytes). */ 185 static void wr_aux_secdef(u8* dst, u32 Length, u16 NumberOfRelocations, 186 u16 NumberOfLinenumbers, u32 CheckSum, u16 Number, 187 u8 Selection) { 188 wr_u32_le(dst + 0, Length); 189 wr_u16_le(dst + 4, NumberOfRelocations); 190 wr_u16_le(dst + 6, NumberOfLinenumbers); 191 wr_u32_le(dst + 8, CheckSum); 192 wr_u16_le(dst + 12, Number); 193 dst[14] = Selection; 194 dst[15] = 0; 195 dst[16] = 0; 196 dst[17] = 0; 197 } 198 199 /* Write a weak-externals aux record (18 bytes). */ 200 static void wr_aux_weak(u8* dst, u32 TagIndex, u32 Characteristics) { 201 wr_u32_le(dst + 0, TagIndex); 202 wr_u32_le(dst + 4, Characteristics); 203 memset(dst + 8, 0, 10); 204 } 205 206 /* Look up the pool-interned string for a Sym. */ 207 static const char* sym_to_str(Compiler* c, Sym n, u32* len_out) { 208 Slice sl = pool_slice(c->global, n); 209 const char* s = sl.s; 210 if (!s) { 211 *len_out = 0; 212 return ""; 213 } 214 *len_out = (u32)sl.len; 215 return s; 216 } 217 218 void emit_coff(Compiler* c, ObjBuilder* ob, Writer* w) { 219 Heap* h = (Heap*)c->ctx->heap; 220 221 /* Tombstone sweep — see obj_sweep_dead. */ 222 obj_sweep_dead(ob); 223 224 /* ---- target validation ----------------------------------------- */ 225 const ObjFormatImpl* fmt = obj_format_lookup(KIT_OBJ_COFF); 226 const ObjCoffArchOps* coff = 227 fmt && fmt->coff_arch ? fmt->coff_arch(c->target.arch) : NULL; 228 if (!coff || !coff->reloc_to) { 229 compiler_panic(c, SRCLOC_NONE, "emit_coff: unsupported target arch %u", 230 (u32)c->target.arch); 231 } 232 u16 machine = coff->machine; 233 u32 (*reloc_to)(u32) = coff->reloc_to; 234 if (c->target.big_endian) { 235 compiler_panic(c, SRCLOC_NONE, "emit_coff: big-endian COFF not supported"); 236 } 237 if (c->target.ptr_size != 8) { 238 compiler_panic(c, SRCLOC_NONE, "emit_coff: ptr_size %u (expected 8)", 239 (u32)c->target.ptr_size); 240 } 241 242 /* ---- pass 1: plan sections ------------------------------------- */ 243 u32 nobjsec = obj_section_count(ob); 244 CSec* secs = arena_zarray(c->scratch, CSec, nobjsec ? nobjsec : 1); 245 u32* obj_to_coff = arena_zarray(c->scratch, u32, nobjsec ? nobjsec : 1); 246 u32 nsecs = 0; 247 248 /* String table — leading 4-byte size placeholder. Real strings start 249 * at offset 4. */ 250 ObjStrtab strtab; 251 obj_strtab_init(&strtab, h, /*dedup=*/1); 252 { 253 u8 zero4[COFF_STRTAB_SIZE_FIELD_BYTES] = {0, 0, 0, 0}; 254 obj_strtab_put_raw(&strtab, zero4, COFF_STRTAB_SIZE_FIELD_BYTES); 255 } 256 257 for (u32 i = 1; i < nobjsec; ++i) { 258 const Section* s = obj_section_get(ob, i); 259 if (s->removed) continue; 260 /* Skip ELF-style synthetic sections (a reader from another format 261 * may have surfaced them) — COFF stores symtab/strtab/relocs 262 * out-of-band, not as named sections. */ 263 if (s->sem == SSEM_SYMTAB || s->sem == SSEM_STRTAB || s->sem == SSEM_RELA || 264 s->sem == SSEM_REL || s->sem == SSEM_GROUP) { 265 continue; 266 } 267 268 CSec* cs = &secs[nsecs]; 269 u32 nlen; 270 const char* nm = sym_to_str(c, s->name, &nlen); 271 encode_name8(cs->name8, nm, nlen, &strtab); 272 273 cs->obj_sec = i; 274 cs->group_id = s->group_id; 275 cs->align = s->align ? s->align : 1; 276 277 int in_group = (s->group_id != OBJ_GROUP_NONE); 278 u32 ch = sec_characteristics(s, in_group); 279 /* Alignment lives in bits 20..23. Cap at log2(8192)=13 -> nibble 280 * value 14 (IMAGE_SCN_ALIGN_8192BYTES). */ 281 u32 lg = log2_align(cs->align); 282 if (lg > 13) lg = 13; 283 ch &= ~IMAGE_SCN_ALIGN_MASK; 284 ch |= IMAGE_SCN_ALIGN_FROM_LOG2(lg); 285 cs->characteristics = ch; 286 287 if (s->sem == SSEM_NOBITS || s->kind == SEC_BSS) { 288 cs->is_nobits = 1; 289 /* COFF object files carry the section size in SizeOfRawData (with 290 * PointerToRawData=0 / no file bytes for uninitialized data) and 291 * keep VirtualSize=0 — VirtualSize is meaningful only for linked 292 * images. lld / link.exe treat a section with SizeOfRawData==0 as 293 * empty and discard it, orphaning every symbol defined there and 294 * breaking relocations that target them ("relocation against 295 * symbol in discarded section"). Match clang/MSVC: size in 296 * SizeOfRawData, VirtualSize 0, no raw data. */ 297 cs->virtual_size = 0; 298 cs->size_of_raw_data = s->bss_size; 299 cs->obj_bytes = NULL; 300 } else { 301 cs->is_nobits = 0; 302 cs->virtual_size = 0; 303 cs->size_of_raw_data = s->bytes.total; 304 cs->obj_bytes = &s->bytes; 305 } 306 307 obj_to_coff[i] = nsecs + 1; /* 1-based; matches SectionNumber. */ 308 nsecs++; 309 } 310 311 /* ---- pass 2: count and assign per-section reloc counts --------- */ 312 /* COFF stores NumberOfRelocations as u16; sections with > 65535 313 * relocs use the IMAGE_SCN_LNK_NRELOC_OVFL extension which we don't 314 * implement in v1. Panic if any single section exceeds the limit. */ 315 for (u32 ci = 0; ci < nsecs; ++ci) { 316 CSec* cs = &secs[ci]; 317 u32 nr = obj_reloc_count(ob, cs->obj_sec); 318 if (nr > 0xFFFFu) { 319 compiler_panic(c, SRCLOC_NONE, 320 "emit_coff: section %u has %u relocs (max 65535)", 321 (u32)cs->obj_sec, nr); 322 } 323 cs->number_of_relocations = (u16)nr; 324 } 325 326 /* ---- pass 3: build the symbol table ---------------------------- */ 327 /* Count ObjSyms (incl. tombstoned — we'll skip those when emitting). */ 328 u32 nobjsym = 0; 329 { 330 ObjSymIter* it = obj_symiter_new(ob); 331 ObjSymEntry e; 332 while (obj_symiter_next(it, &e)) ++nobjsym; 333 obj_symiter_free(it); 334 } 335 336 /* Upper bound on symbol-table records (including aux slots): 337 * - 2 records per section symbol (primary + 1 aux secdef) 338 * - 2 records per ObjSym (primary + up to 1 weak aux) 339 * - +2 spare for safety 340 * Worst case is generous; we trim by tracking nrecords as we emit. */ 341 u32 max_records = 2u * nsecs + 2u * nobjsym + 4u; 342 u8* symtab = 343 (u8*)arena_zarray(c->scratch, u8, (size_t)COFF_SYMBOL_SIZE * max_records); 344 u32 nrecords = 0; 345 346 /* obj_id -> COFF symbol index (including aux slots). Index 0 is 347 * reserved as "none" in our internal map (a real COFF symbol may 348 * legitimately live at index 0, but no ObjSym ever maps there since 349 * we never put OBJ_SYM_NONE through). */ 350 u32* sym_to_coff = arena_zarray(c->scratch, u32, nobjsym + 2); 351 352 /* Section symbols first — one STATIC per kept obj section, each 353 * followed by a SECTION DEFINITION aux. Reloc-against-section in 354 * other tools' output uses these; emitting them unconditionally 355 * matches what clang / mingw emit and gives readers a stable target. */ 356 u32* secsym_index = arena_zarray(c->scratch, u32, nsecs + 1); 357 for (u32 ci = 0; ci < nsecs; ++ci) { 358 CSec* cs = &secs[ci]; 359 char short_name[8]; 360 /* The section symbol's name is the section's own name (truncated 361 * to 8 bytes — section symbols never use the strtab spill form in 362 * MSVC/clang output). */ 363 memcpy(short_name, cs->name8, 8); 364 365 u8* slot = symtab + (size_t)nrecords * COFF_SYMBOL_SIZE; 366 wr_sym(slot, short_name, /*Zeroes*/ 1, /*Offset*/ 0, 367 /*Value*/ 0, 368 /*SectionNumber*/ (i16)(ci + 1), 369 /*Type*/ IMAGE_SYM_TYPE_NULL, 370 /*StorageClass*/ IMAGE_SYM_CLASS_STATIC, 371 /*NumberOfAuxSymbols*/ 1); 372 secsym_index[ci] = nrecords; 373 nrecords++; 374 375 /* Section-definition aux. For COMDAT members we encode the 376 * Selection from the group; default to SELECT_ANY which is what 377 * gcc/clang emit unless the user requests a specific selection 378 * mode. The associated-section Number is left at 0 (kit does 379 * not produce associative-COMDAT chains today). */ 380 u8 selection = 0; 381 if (cs->group_id != OBJ_GROUP_NONE) { 382 const ObjGroup* g = obj_group_get(ob, cs->group_id); 383 if (g && !g->removed) { 384 selection = g->flags ? (u8)IMAGE_COMDAT_SELECT_ANY 385 : (u8)IMAGE_COMDAT_SELECT_ANY; 386 } 387 } 388 u8* aux = symtab + (size_t)nrecords * COFF_SYMBOL_SIZE; 389 wr_aux_secdef(aux, /*Length*/ cs->size_of_raw_data, 390 /*NumberOfRelocations*/ cs->number_of_relocations, 391 /*NumberOfLinenumbers*/ 0, 392 /*CheckSum*/ 0, 393 /*Number*/ 0, 394 /*Selection*/ selection); 395 nrecords++; 396 } 397 398 /* File / regular symbols. */ 399 { 400 ObjSymIter* it = obj_symiter_new(ob); 401 ObjSymEntry e; 402 while (obj_symiter_next(it, &e)) { 403 const ObjSym* s = e.sym; 404 if (s->removed) continue; 405 if (s->kind == SK_IFUNC) { 406 compiler_panic(c, SRCLOC_NONE, 407 "emit_coff: SK_IFUNC has no PE/COFF representation"); 408 } 409 /* Don't re-emit SK_SECTION symbols — section symbols are 410 * synthesized above. Map any input-side SK_SECTION onto the 411 * already-emitted one. */ 412 if (s->kind == SK_SECTION) { 413 if (s->section_id && s->section_id < nobjsec) { 414 u32 ci = obj_to_coff[s->section_id]; 415 if (ci) sym_to_coff[e.id] = secsym_index[ci - 1]; 416 } 417 continue; 418 } 419 420 u32 nlen; 421 const char* nm = sym_to_str(c, s->name, &nlen); 422 423 if (s->kind == SK_FILE) { 424 /* File symbol: name ".file" (short), section IMAGE_SYM_DEBUG, 425 * storage class FILE, followed by aux records carrying the 426 * NUL-padded file path (18 bytes per aux). */ 427 u32 file_len = nlen; 428 u32 naux = 429 file_len ? (file_len + COFF_AUX_FILE_SIZE - 1u) / COFF_AUX_FILE_SIZE 430 : 1u; 431 char short_name[8] = {'.', 'f', 'i', 'l', 'e', 0, 0, 0}; 432 u8* slot = symtab + (size_t)nrecords * COFF_SYMBOL_SIZE; 433 wr_sym(slot, short_name, 1, 0, /*Value*/ 0, 434 /*SectionNumber*/ (i16)IMAGE_SYM_DEBUG, 435 /*Type*/ IMAGE_SYM_TYPE_NULL, 436 /*StorageClass*/ IMAGE_SYM_CLASS_FILE, 437 /*NumberOfAuxSymbols*/ (u8)naux); 438 sym_to_coff[e.id] = nrecords; 439 nrecords++; 440 for (u32 a = 0; a < naux; ++a) { 441 u8* aux = symtab + (size_t)nrecords * COFF_SYMBOL_SIZE; 442 memset(aux, 0, COFF_AUX_FILE_SIZE); 443 u32 off = a * COFF_AUX_FILE_SIZE; 444 u32 copy = file_len > off ? file_len - off : 0; 445 if (copy > COFF_AUX_FILE_SIZE) copy = COFF_AUX_FILE_SIZE; 446 if (copy) memcpy(aux, nm + off, copy); 447 nrecords++; 448 } 449 continue; 450 } 451 452 /* Regular symbol. */ 453 char short_name[8]; 454 u32 zeroes = 1, offset = 0; 455 memset(short_name, 0, 8); 456 if (nlen <= 8) { 457 if (nlen) memcpy(short_name, nm, nlen); 458 } else { 459 zeroes = 0; 460 offset = obj_strtab_add(&strtab, nm, nlen); 461 } 462 463 i16 section_number = 0; 464 u32 value = 0; 465 u8 storage_class = IMAGE_SYM_CLASS_NULL; 466 u16 type = IMAGE_SYM_TYPE_NULL; 467 u8 naux = 0; 468 int emit_weak_aux = 0; 469 470 switch (s->kind) { 471 case SK_ABS: 472 section_number = (i16)IMAGE_SYM_ABSOLUTE; 473 value = (u32)s->value; 474 break; 475 case SK_COMMON: 476 /* COFF lacks a per-common alignment field; encode size in 477 * Value with SectionNumber=UNDEFINED and rely on the linker 478 * to pick a default alignment. (kit's frontend uses 479 * COMMON only via __attribute__((common)) which is rare on 480 * PE/COFF targets.) */ 481 section_number = (i16)IMAGE_SYM_UNDEFINED; 482 value = (u32)s->size; 483 break; 484 default: 485 if (s->section_id == OBJ_SEC_NONE) { 486 section_number = (i16)IMAGE_SYM_UNDEFINED; 487 value = 0; 488 } else if (s->section_id < nobjsec && obj_to_coff[s->section_id]) { 489 section_number = (i16)obj_to_coff[s->section_id]; 490 value = (u32)s->value; 491 } else { 492 section_number = (i16)IMAGE_SYM_UNDEFINED; 493 value = 0; 494 } 495 break; 496 } 497 498 if (s->kind == SK_FUNC) type = (u16)COFF_SYM_TYPE_FUNCTION; 499 500 switch (s->bind) { 501 case SB_LOCAL: 502 storage_class = IMAGE_SYM_CLASS_STATIC; 503 break; 504 case SB_GLOBAL: 505 storage_class = IMAGE_SYM_CLASS_EXTERNAL; 506 break; 507 case SB_WEAK: 508 /* mingw / clang spell weak as EXTERNAL with a WeakExternal 509 * aux that points at the fallback symbol. kit's obj layer 510 * doesn't carry a separate fallback symbol today, so we emit 511 * a self-referential weak aux (TagIndex=0) which the linker 512 * treats as "weak, no fallback" — equivalent to ELF STB_WEAK. */ 513 storage_class = IMAGE_SYM_CLASS_WEAK_EXTERNAL; 514 emit_weak_aux = 1; 515 naux = 1; 516 break; 517 default: 518 storage_class = IMAGE_SYM_CLASS_STATIC; 519 break; 520 } 521 522 u8* slot = symtab + (size_t)nrecords * COFF_SYMBOL_SIZE; 523 wr_sym(slot, short_name, zeroes, offset, value, section_number, type, 524 storage_class, naux); 525 sym_to_coff[e.id] = nrecords; 526 nrecords++; 527 if (emit_weak_aux) { 528 u8* aux = symtab + (size_t)nrecords * COFF_SYMBOL_SIZE; 529 wr_aux_weak(aux, /*TagIndex*/ 0, 530 /*Characteristics*/ IMAGE_WEAK_EXTERN_SEARCH_LIBRARY); 531 nrecords++; 532 } 533 } 534 obj_symiter_free(it); 535 } 536 537 /* ---- pass 4: build per-section relocation tables --------------- */ 538 for (u32 ci = 0; ci < nsecs; ++ci) { 539 CSec* cs = &secs[ci]; 540 u32 nr; 541 const u32* rix = obj_reloc_section(ob, cs->obj_sec, &nr); 542 if (!nr) continue; 543 u8* buf = (u8*)arena_alloc(c->scratch, (size_t)COFF_RELOC_SIZE * nr, 544 _Alignof(u32)); 545 u32 j = 0; 546 /* rix[] lists this section's live relocs in ascending global order. */ 547 for (u32 k = 0; k < nr; ++k) { 548 const Reloc* r = obj_reloc_at(ob, rix[k]); 549 if (r->sym == OBJ_SYM_NONE) { 550 compiler_panic(c, SRCLOC_NONE, 551 "emit_coff: reloc without symbol not supported " 552 "(sec=%u offset=%u kind=%u)", 553 (u32)r->section_id, (u32)r->offset, (u32)r->kind); 554 } 555 if (r->has_explicit_addend && r->addend != 0 && 556 !coff_rel32_absorbs_minus4(c->target.arch, (RelocKind)r->kind, 557 r->addend)) { 558 /* v1 limitation: COFF carries the addend in the patched bytes, 559 * and we don't currently mutate the obj's section bytes to 560 * encode a separate explicit addend. kit's MCEmitter writes 561 * the addend inline for COFF targets, so this branch only 562 * fires for inputs synthesized by external tools. */ 563 compiler_panic(c, SRCLOC_NONE, 564 "emit_coff: explicit nonzero addend not supported " 565 "(sec=%u offset=%u kind=%u addend=%lld)", 566 (u32)r->section_id, (u32)r->offset, (u32)r->kind, 567 (long long)r->addend); 568 } 569 u32 wire = reloc_to(r->kind); 570 /* Both arch translators use 0 (IMAGE_REL_*_ABSOLUTE) as the 571 * unsupported-input sentinel; treat that as a panic unless the 572 * input really is R_NONE. */ 573 if (wire == 0 && r->kind != R_NONE) { 574 compiler_panic(c, SRCLOC_NONE, 575 "emit_coff: unsupported relocation kind %u for arch %u", 576 (u32)r->kind, (u32)c->target.arch); 577 } 578 u32 sym_idx = sym_to_coff[r->sym]; 579 u8* slot = buf + (size_t)j * COFF_RELOC_SIZE; 580 wr_u32_le(slot + 0, r->offset); 581 wr_u32_le(slot + 4, sym_idx); 582 wr_u16_le(slot + 8, (u16)wire); 583 ++j; 584 } 585 cs->reloc_bytes = buf; 586 /* If a tombstoned reloc was skipped between count and emit, j may 587 * be less than nr; trust the latter count for the wire field. */ 588 if (j != nr) cs->number_of_relocations = (u16)j; 589 } 590 591 /* ---- pass 5: assign file offsets ------------------------------- */ 592 /* Layout: 593 * [file header] [section headers] [per-section: bytes, relocs]* 594 * [symbol table] [string table] */ 595 u64 cur = 596 (u64)COFF_FILE_HEADER_SIZE + (u64)COFF_SECTION_HEADER_SIZE * (u64)nsecs; 597 598 for (u32 ci = 0; ci < nsecs; ++ci) { 599 CSec* cs = &secs[ci]; 600 /* Raw data offset. NOBITS contributes nothing on disk. */ 601 if (cs->is_nobits || cs->size_of_raw_data == 0) { 602 cs->pointer_to_raw_data = 0; 603 } else { 604 cur = ALIGN_UP(cur, (u64)cs->align); 605 cs->pointer_to_raw_data = (u32)cur; 606 cur += cs->size_of_raw_data; 607 } 608 /* Reloc table. COFF doesn't mandate alignment for the reloc array, 609 * but llvm and binutils emit them naturally byte-packed; we 4-align 610 * for tidiness. */ 611 if (cs->number_of_relocations) { 612 cur = ALIGN_UP(cur, (u64)4); 613 cs->pointer_to_relocations = (u32)cur; 614 cur += (u64)cs->number_of_relocations * COFF_RELOC_SIZE; 615 } else { 616 cs->pointer_to_relocations = 0; 617 } 618 } 619 620 cur = ALIGN_UP(cur, (u64)4); 621 u64 symtab_off = cur; 622 cur += (u64)nrecords * COFF_SYMBOL_SIZE; 623 624 /* String table starts immediately after the symtab. Patch the 4-byte 625 * size prefix (inclusive). */ 626 u32 strtab_size = obj_strtab_size(&strtab); 627 /* The size field is part of the on-disk strtab and is the total 628 * inclusive byte count. Patch it now. */ 629 { 630 u8 sz_le[4]; 631 wr_u32_le(sz_le, strtab_size); 632 /* Buf doesn't expose in-place patch; flatten, patch, re-emit when 633 * we write. Just remember the value. */ 634 (void)sz_le; 635 } 636 u64 strtab_off = cur; 637 cur += strtab_size; 638 639 /* ---- pass 6: write the file ------------------------------------ */ 640 kit_writer_seek(w, 0); 641 642 /* IMAGE_FILE_HEADER */ 643 coff_wr_u16(w, machine); 644 coff_wr_u16(w, (u16)nsecs); 645 coff_wr_u32(w, 0); /* TimeDateStamp: reproducible */ 646 coff_wr_u32(w, (u32)symtab_off); 647 coff_wr_u32(w, nrecords); 648 coff_wr_u16(w, 0); /* SizeOfOptionalHeader: 0 for .obj */ 649 coff_wr_u16(w, IMAGE_FILE_LARGE_ADDRESS_AWARE); 650 651 /* Section headers — one 40-byte block immediately after the file 652 * header. */ 653 for (u32 ci = 0; ci < nsecs; ++ci) { 654 const CSec* cs = &secs[ci]; 655 kit_writer_write(w, cs->name8, 8); 656 coff_wr_u32(w, cs->virtual_size); 657 coff_wr_u32(w, 0); /* VirtualAddress: 0 for .obj */ 658 coff_wr_u32(w, cs->size_of_raw_data); 659 coff_wr_u32(w, cs->pointer_to_raw_data); 660 coff_wr_u32(w, cs->pointer_to_relocations); 661 coff_wr_u32(w, 0); /* PointerToLinenumbers: 0 */ 662 coff_wr_u16(w, cs->number_of_relocations); 663 coff_wr_u16(w, 0); /* NumberOfLinenumbers: 0 */ 664 coff_wr_u32(w, cs->characteristics); 665 } 666 667 /* Section bytes + relocs (interleaved). */ 668 for (u32 ci = 0; ci < nsecs; ++ci) { 669 const CSec* cs = &secs[ci]; 670 if (!cs->is_nobits && cs->size_of_raw_data && cs->obj_bytes) { 671 kit_writer_seek(w, cs->pointer_to_raw_data); 672 u32 sz = cs->obj_bytes->total; 673 u8* tmp = (u8*)h->alloc(h, sz ? sz : 1, 1); 674 if (sz) buf_flatten(cs->obj_bytes, tmp); 675 kit_writer_write(w, tmp, sz); 676 h->free(h, tmp, sz ? sz : 1); 677 } 678 if (cs->number_of_relocations && cs->reloc_bytes) { 679 kit_writer_seek(w, cs->pointer_to_relocations); 680 kit_writer_write(w, cs->reloc_bytes, 681 (size_t)cs->number_of_relocations * COFF_RELOC_SIZE); 682 } 683 } 684 685 /* Symbol table. */ 686 kit_writer_seek(w, symtab_off); 687 kit_writer_write(w, symtab, (size_t)nrecords * COFF_SYMBOL_SIZE); 688 689 /* String table: 4-byte total size (inclusive) followed by the body. 690 * `strtab` was initialized with 4 placeholder zero bytes; rewrite 691 * them with the real size before flushing. */ 692 { 693 u8* flat = (u8*)arena_alloc(c->scratch, strtab_size ? strtab_size : 1, 1); 694 if (strtab_size) memcpy(flat, obj_strtab_data(&strtab), strtab_size); 695 /* Patch the 4-byte size prefix in place. */ 696 if (strtab_size >= COFF_STRTAB_SIZE_FIELD_BYTES) { 697 wr_u32_le(flat, strtab_size); 698 } 699 kit_writer_seek(w, strtab_off); 700 kit_writer_write(w, flat, strtab_size); 701 } 702 obj_strtab_fini(&strtab); 703 }