link_layout.c (93303B)
1 /* link_layout.c — section bucketing, vaddr assignment, scripted layout, 2 * COMMON BSS allocation, segment-byte copying, and the top-level 3 * link_resolve orchestration function. 4 * 5 * Image-relative discipline: every vaddr / file_offset on the produced 6 * image treats the image as based at 0. Consumers (link_emit_elf, 7 * kit_jit_from_image) add their own runtime base before patching 8 * relocations or writing PT_LOAD headers. Segment byte buffers hold raw 9 * input section bytes — no relocations are applied here, in line with 10 * the incremental-link discipline (link.h:136). */ 11 12 #include <kit/core.h> 13 #include <kit/jit.h> 14 #include <stdarg.h> 15 #include <string.h> 16 17 #include "core/buf.h" 18 #include "core/bytes.h" 19 #include "core/diag.h" 20 #include "core/heap.h" 21 #include "core/metrics.h" 22 #include "core/pool.h" 23 #include "core/slice.h" 24 #include "core/util.h" 25 #include "core/vec.h" 26 #include "link/link.h" 27 #include "link/link_arch.h" 28 #include "link/link_internal.h" 29 #include "obj/format.h" 30 31 LinkImage* link_image_alloc(Compiler*); /* defined in link.c */ 32 33 #define LINK_ELF_SHF_COMPRESSED 0x800u 34 35 /* Page size used for ELF segment alignment. We pull from env->execmem 36 * when present (matches the eventual JIT mapping granularity) and fall 37 * back to 16 KiB otherwise — large enough for any current Linux/aarch64 38 * loader. A future cross-link with mismatched host/target page sizes 39 * will need a target-derived value here instead. */ 40 u64 link_layout_page_size(Linker* l) { 41 const KitExecMem* m = (l && l->jit_host) ? l->jit_host->execmem : NULL; 42 if (m && m->page_size) return (u64)m->page_size; 43 return 0x4000u; 44 } 45 46 /* Four-bucket segment partitioning: see SegBucket in link_internal.h. */ 47 48 int link_section_kept(const Section* s) { 49 /* This cut keeps allocatable progbits/nobits sections only. Debug, 50 * symtab/strtab, group, and note sections are dropped — none of 51 * them participate in a static ET_EXEC layout. */ 52 if (!(s->flags & SF_ALLOC)) return 0; 53 if (s->sem == SSEM_PROGBITS || s->sem == SSEM_NOBITS || s->sem == SSEM_NOTE) 54 return 1; 55 if (s->sem == SSEM_INIT_ARRAY || s->sem == SSEM_FINI_ARRAY || 56 s->sem == SSEM_PREINIT_ARRAY) 57 return 1; 58 return 0; 59 } 60 61 int link_section_kept_fileonly(const Section* s) { 62 /* Non-allocatable .debug_* sections. They get no PT_LOAD segment but 63 * are carried through to the file so addr2line / gdb resolve 64 * file:line on the linked image. 65 * 66 * ELF SHF_COMPRESSED debug sections carry compressed bytes but relocation 67 * offsets refer to the uncompressed DWARF stream. Until the object model has 68 * a decompression/recompression path, dropping them is the only safe linked 69 * executable behavior. */ 70 return s && !s->removed && s->kind == SEC_DEBUG && 71 !(s->ext_kind == OBJ_EXT_ELF && 72 (s->ext_flags & LINK_ELF_SHF_COMPRESSED)); 73 } 74 75 SegBucket link_bucket_for(u16 flags) { 76 if (flags & SF_TLS) return SEG_TLS; 77 if (flags & SF_EXEC) return SEG_RX; 78 if (flags & SF_WRITE) return SEG_RW; 79 return SEG_R; 80 } 81 82 /* PIE `.data.rel.ro` placement: a read-only data section that carries an 83 * absolute (abs32/abs64) reloc cannot stay in a never-writable PT_LOAD. 84 * In PIE the linker rewrites those relocs into dynamic records — a 85 * RELATIVE for an internal target, a GLOB_DAT for an import — and the 86 * loader *writes* the resolved pointer into the slot at load time. A 87 * PF_R-only segment faults that store (manifesting as a SIGSEGV in the 88 * dynamic loader). Jump tables, @labeladdr arrays, and const pointer 89 * initializers all land here. Promote such sections to the writable 90 * segment; we forgo the post-relocation RELRO re-protection that a full 91 * toolchain would apply via PT_GNU_RELRO. */ 92 static int link_pie_ro_section_needs_write(const ObjBuilder* ob, ObjSecId sid) { 93 u32 i, total = obj_reloc_total(ob); 94 for (i = 0; i < total; ++i) { 95 const Reloc* r = obj_reloc_at(ob, i); 96 if (!r || r->removed || r->section_id != sid) continue; 97 if (r->kind == R_ABS64 || r->kind == R_ABS32) return 1; 98 } 99 return 0; 100 } 101 102 /* ---- LinkImage growth helpers ---- 103 * 104 * syms / relocs back onto SegVec — pointers stay stable across pushes, 105 * so callers may stash LinkSymbol/LinkRelocApply references and 106 * re-enter mutation without invalidation. */ 107 108 static LinkSymbol* append_symbol_slot(LinkImage* img) { 109 u32 idx; 110 LinkSymbol* s = LinkSyms_push(&img->syms, &idx); 111 if (!s) compiler_panic(img->c, SRCLOC_NONE, "link: oom growing symbols"); 112 s->id = (LinkSymId)(idx + 1u); 113 return s; 114 } 115 116 LinkSymId link_append_symbol(LinkImage* img, const LinkSymbol* tmpl) { 117 LinkSymbol* s = append_symbol_slot(img); 118 LinkSymId id = s->id; 119 *s = *tmpl; 120 s->id = id; 121 return id; 122 } 123 124 LinkRelocApply* link_append_reloc_slot(LinkImage* img) { 125 LinkRelocApply* r = LinkRelocs_push(&img->relocs, NULL); 126 if (!r) compiler_panic(img->c, SRCLOC_NONE, "link: oom growing relocs"); 127 return r; 128 } 129 130 /* ---- pass 2: section assignment + segment layout ---- */ 131 132 typedef struct SecRef { 133 u32 input_idx; 134 ObjSecId obj_sec_id; 135 LinkSectionId link_sec_id; 136 } SecRef; 137 138 #define PLACE_NONE ((u32)~0u) 139 140 /* Within a bucket, input sections sharing a name are placed contiguously 141 * — the standard "merge sections by name" rule. Without this the .init 142 * prologue from crti.o and the matching epilogue from crtn.o (both in 143 * a .init section) get separated by intervening .text, and `_init` is 144 * no longer a contiguous function. Placement walk: 145 * 146 * 1. Build a flat list of (input_idx, obj_sec_id) for kept+live 147 * sections. 148 * 2. While collecting, append each section to an O(1)-expected lookup 149 * keyed by (bucket, name). The group array is append-only, so group 150 * order is still first occurrence; each group's linked list preserves 151 * input order. 152 * 3. Lay out groups in first-occurrence order. 153 */ 154 typedef struct PlaceEntry { 155 u32 input_idx; 156 ObjSecId obj_sec_id; 157 ObjAtomId obj_atom_id; 158 u32 obj_offset; 159 u32 size; 160 Sym name; 161 SegBucket bucket; 162 u32 next; 163 } PlaceEntry; 164 165 typedef struct PlaceGroup { 166 u32 head; 167 u32 tail; 168 } PlaceGroup; 169 170 static inline u32 place_group_hash_(u64 key) { return hash_u64(key); } 171 HASHMAP_DEFINE(PlaceGroupHash, u64, u32, place_group_hash_); 172 173 static u64 place_group_key(Sym name, SegBucket bucket) { 174 return (((u64)name + 1u) << 3) | ((u64)bucket + 1u); 175 } 176 177 static u32 place_group_hash_cap(u32 n) { 178 u32 cap = KIT_HASHMAP_INIT_CAP; 179 while (cap < 0x80000000u && (cap - cap / 4u) < n) cap <<= 1; 180 return cap; 181 } 182 183 static int live_section_units(const GcLive* g, const InputMap* m, u32 ii, 184 ObjBuilder* ob, ObjSecId sid) { 185 u32 n = 0, first, count, i; 186 if (link_input_section_has_atoms(m, sid)) { 187 link_input_section_atoms(m, sid, &first, &count); 188 for (i = 0; i < count; ++i) { 189 ObjAtomId aid = m->section_atom_ids[first + i]; 190 const ObjAtom* a = obj_atom_get(ob, aid); 191 if (!a || a->removed) continue; 192 if (link_gc_atom_live_get(g, ii, aid)) ++n; 193 } 194 return n; 195 } 196 return link_gc_live_get(g, ii, sid) ? 1 : 0; 197 } 198 199 static void map_placed_unit(InputMap* m, ObjSecId sid, ObjAtomId aid, 200 LinkSectionId lsid) { 201 if (aid != OBJ_ATOM_NONE) { 202 m->atom[aid] = lsid; 203 if (m->section[sid] == LINK_SEC_NONE) m->section[sid] = lsid; 204 return; 205 } 206 m->section[sid] = lsid; 207 } 208 209 static void link_layout_sections_scripted(Linker* l, LinkImage* img, 210 const GcLive* g); 211 212 void link_layout_sections(Linker* l, LinkImage* img, const GcLive* g) { 213 if (l->script) { 214 link_layout_sections_scripted(l, img, g); 215 return; 216 } 217 Heap* h = img->heap; 218 u32 ii, j; 219 u32 total_kept = 0; 220 221 /* Pass 0: count kept sections (filtered by GC liveness). */ 222 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 223 ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; 224 for (j = 1; j < obj_section_count(ob); ++j) { 225 const Section* s = obj_section_get(ob, j); 226 InputMap* m = &img->input_maps[ii]; 227 if (s && link_section_kept(s) && !m->comdat_discarded[j]) 228 total_kept += live_section_units(g, m, ii, ob, j); 229 } 230 } 231 232 img->sections = total_kept ? (LinkSection*)h->alloc( 233 h, sizeof(*img->sections) * total_kept, 234 _Alignof(LinkSection)) 235 : NULL; 236 if (total_kept && !img->sections) 237 compiler_panic(img->c, SRCLOC_NONE, "link: oom on sections"); 238 239 /* Pass 1: collect kept sections into a flat list. */ 240 PlaceEntry* entries = 241 total_kept ? (PlaceEntry*)h->alloc(h, sizeof(*entries) * total_kept, 242 _Alignof(PlaceEntry)) 243 : NULL; 244 PlaceGroup* groups = 245 total_kept ? (PlaceGroup*)h->alloc(h, sizeof(*groups) * total_kept, 246 _Alignof(PlaceGroup)) 247 : NULL; 248 PlaceGroupHash group_map; 249 u32 ngroups = 0; 250 if (total_kept && !entries) 251 compiler_panic(img->c, SRCLOC_NONE, "link: oom on placement entries"); 252 if (total_kept && !groups) 253 compiler_panic(img->c, SRCLOC_NONE, "link: oom on placement groups"); 254 if (total_kept) { 255 PlaceGroupHash_init_cap(&group_map, h, place_group_hash_cap(total_kept)); 256 if (!group_map.slots) 257 compiler_panic(img->c, SRCLOC_NONE, "link: oom on placement group map"); 258 } 259 { 260 u32 e = 0; 261 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 262 ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; 263 InputMap* m = &img->input_maps[ii]; 264 for (j = 1; j < obj_section_count(ob); ++j) { 265 const Section* s = obj_section_get(ob, j); 266 u64 key; 267 u32* hit; 268 u32 group_idx; 269 if (!s || !link_section_kept(s) || m->comdat_discarded[j]) continue; 270 u32 first = 0, count = 1, ai; 271 int has_atoms = link_input_section_has_atoms(m, j); 272 if (has_atoms) link_input_section_atoms(m, j, &first, &count); 273 for (ai = 0; ai < count; ++ai) { 274 ObjAtomId aid = 275 has_atoms ? m->section_atom_ids[first + ai] : OBJ_ATOM_NONE; 276 const ObjAtom* a = has_atoms ? obj_atom_get(ob, aid) : NULL; 277 if (has_atoms) { 278 if (!a || a->removed) continue; 279 if (!link_gc_atom_live_get(g, ii, aid)) continue; 280 } else if (!link_gc_live_get(g, ii, j)) { 281 continue; 282 } 283 entries[e].input_idx = ii; 284 entries[e].obj_sec_id = j; 285 entries[e].obj_atom_id = has_atoms ? aid : OBJ_ATOM_NONE; 286 entries[e].obj_offset = has_atoms ? a->offset : 0u; 287 entries[e].size = has_atoms ? a->size : link_section_size_for_link(s); 288 entries[e].name = s->name; 289 entries[e].bucket = link_bucket_for(s->flags); 290 if (l->emit_pie && entries[e].bucket == SEG_R && 291 link_pie_ro_section_needs_write(ob, j)) 292 entries[e].bucket = SEG_RW; 293 entries[e].next = PLACE_NONE; 294 295 key = place_group_key(entries[e].name, entries[e].bucket); 296 hit = PlaceGroupHash_get(&group_map, key); 297 if (hit) { 298 group_idx = *hit - 1u; 299 } else { 300 group_idx = ngroups++; 301 groups[group_idx].head = PLACE_NONE; 302 groups[group_idx].tail = PLACE_NONE; 303 PlaceGroupHash_set(&group_map, key, group_idx + 1u); 304 } 305 if (groups[group_idx].tail == PLACE_NONE) { 306 groups[group_idx].head = e; 307 } else { 308 entries[groups[group_idx].tail].next = e; 309 } 310 groups[group_idx].tail = e; 311 ++e; 312 } 313 } 314 } 315 } 316 317 /* Four segment buckets; tracks per-bucket size during scan and 318 * per-section file_offset within the bucket. */ 319 u64 seg_size[SEG_NBUCKETS] = {0}; 320 u32 seg_align[SEG_NBUCKETS] = {1, 1, 1, 1}; 321 u32 seg_count[SEG_NBUCKETS] = {0}; 322 /* Track trailing NOBITS so segment mem_size > file_size: SEG_RW 323 * for .bss / COMMON, SEG_TLS for .tbss. */ 324 u64 seg_bss_extra[SEG_NBUCKETS] = {0}; 325 326 /* Pass 2: place sections, grouped by name within each bucket and 327 * in first-occurrence order across groups. NOBITS (.bss/.tbss) sections 328 * are placed in a second sub-pass so every bucket's file image stays a 329 * contiguous prefix: ELF requires bss to trail, and for TLS specifically 330 * a .tbss ahead of .tdata makes the loader copy garbage file bytes as the 331 * zero-init image (FreeBSD/riscv _init_tls then crashes on a stale TLS 332 * pointer). */ 333 for (int bss_phase = 0; bss_phase < 2; ++bss_phase) { 334 for (u32 gi = 0; gi < ngroups; ++gi) { 335 for (u32 k = groups[gi].head; k != PLACE_NONE; k = entries[k].next) { 336 PlaceEntry* pe = &entries[k]; 337 SegBucket bucket = pe->bucket; 338 339 ObjBuilder* ob = LinkInputs_at(&l->inputs, pe->input_idx)->obj; 340 InputMap* m = &img->input_maps[pe->input_idx]; 341 const Section* s = obj_section_get(ob, pe->obj_sec_id); 342 u32 align = s->align ? s->align : 1u; 343 u64 ofs; 344 LinkSection* ls; 345 LinkSectionId lsid; 346 int is_bss = (s->sem == SSEM_NOBITS || s->kind == SEC_BSS); 347 348 if (is_bss != bss_phase) continue; 349 if (is_bss) { 350 u64 cursor = seg_size[bucket] + seg_bss_extra[bucket]; 351 cursor = ALIGN_UP(cursor, (u64)(align)); 352 seg_bss_extra[bucket] = cursor + (u64)pe->size - seg_size[bucket]; 353 ofs = cursor; 354 } else { 355 seg_size[bucket] += seg_bss_extra[bucket]; 356 seg_bss_extra[bucket] = 0; 357 ofs = ALIGN_UP(seg_size[bucket], (u64)(align)); 358 seg_size[bucket] = ofs + (u64)pe->size; 359 } 360 361 if (align > seg_align[bucket]) seg_align[bucket] = align; 362 seg_count[bucket]++; 363 364 lsid = (LinkSectionId)(img->nsections + 1u); 365 ls = &img->sections[img->nsections++]; 366 memset(ls, 0, sizeof(*ls)); 367 ls->id = lsid; 368 ls->input_id = LinkInputs_at(&l->inputs, pe->input_idx)->id; 369 ls->obj_section_id = pe->obj_sec_id; 370 ls->obj_atom_id = pe->obj_atom_id; 371 ls->segment_id = LINK_SEG_NONE; 372 ls->obj_offset = pe->obj_offset; 373 ls->input_offset = ofs; 374 ls->file_offset = ofs; 375 ls->vaddr = ofs; 376 ls->size = pe->size; 377 ls->flags = s->flags; 378 ls->align = align; 379 ls->name = s->name; 380 ls->sem = (s->kind == SEC_BSS) ? SSEM_NOBITS : s->sem; 381 ls->segment_id = (LinkSegmentId)(bucket + 1u); /* 1..3 sentinel */ 382 map_placed_unit(m, pe->obj_sec_id, pe->obj_atom_id, lsid); 383 } 384 } 385 } 386 387 if (total_kept) PlaceGroupHash_fini(&group_map); 388 if (groups) h->free(h, groups, sizeof(*groups) * total_kept); 389 if (entries) h->free(h, entries, sizeof(*entries) * total_kept); 390 391 /* Materialize one LinkSegment per non-empty bucket, then assign 392 * absolute (image-relative) vaddr/file_offset to each segment and 393 * fix up section.{vaddr,file_offset,segment_id}. */ 394 { 395 LinkSegmentId bucket_seg[SEG_NBUCKETS] = {0}; 396 u64 cursor = 0; 397 u32 b; 398 u32 nseg = 0; 399 for (b = 0; b < SEG_NBUCKETS; ++b) 400 if (seg_count[b]) ++nseg; 401 402 img->segments = 403 nseg ? (LinkSegment*)h->alloc(h, sizeof(*img->segments) * nseg, 404 _Alignof(LinkSegment)) 405 : NULL; 406 img->segment_bytes = 407 nseg ? (u8**)h->alloc(h, sizeof(*img->segment_bytes) * nseg, 408 _Alignof(u8*)) 409 : NULL; 410 img->segment_bytes_cap = 411 nseg ? (size_t*)h->alloc(h, sizeof(*img->segment_bytes_cap) * nseg, 412 _Alignof(size_t)) 413 : NULL; 414 if (nseg && 415 (!img->segments || !img->segment_bytes || !img->segment_bytes_cap)) 416 compiler_panic(img->c, SRCLOC_NONE, "link: oom on segments"); 417 if (nseg) { 418 memset(img->segment_bytes, 0, sizeof(*img->segment_bytes) * nseg); 419 memset(img->segment_bytes_cap, 0, sizeof(*img->segment_bytes_cap) * nseg); 420 } 421 422 for (b = 0; b < SEG_NBUCKETS; ++b) { 423 LinkSegment* seg; 424 u64 file_size, mem_size, align; 425 u32 nat_align; 426 u32 perms; 427 if (!seg_count[b]) continue; 428 nat_align = seg_align[b] ? seg_align[b] : 1u; 429 align = (u64)nat_align; 430 if (align < link_layout_page_size(l)) align = link_layout_page_size(l); 431 cursor = ALIGN_UP(cursor, (u64)(align)); 432 433 seg = &img->segments[img->nsegments]; 434 file_size = seg_size[b]; 435 mem_size = seg_size[b] + seg_bss_extra[b]; 436 perms = SF_ALLOC; 437 if (b == SEG_RX) perms |= SF_EXEC; 438 if (b == SEG_RW) perms |= SF_WRITE; 439 if (b == SEG_TLS) perms |= SF_TLS; 440 441 memset(seg, 0, sizeof(*seg)); 442 seg->id = (LinkSegmentId)(img->nsegments + 1u); 443 seg->flags = perms; 444 seg->file_offset = cursor; 445 seg->vaddr = cursor; 446 seg->paddr = cursor; 447 seg->mem_size = mem_size; 448 seg->file_size = file_size; 449 seg->align = (u32)align; 450 seg->nsections = seg_count[b]; 451 bucket_seg[b] = seg->id; 452 if (b == SEG_TLS) { 453 /* Record TLS image span for PT_TLS emission and TLSLE 454 * reloc apply. tls_align preserves the natural section 455 * alignment (PT_TLS p_align), distinct from the 456 * containing PT_LOAD's page align. */ 457 img->tls_vaddr = cursor; 458 img->tls_filesz = file_size; 459 img->tls_memsz = mem_size; 460 img->tls_align = nat_align; 461 } 462 cursor += mem_size; 463 img->nsegments++; 464 } 465 466 /* Allocate segment buffers and fix up section offsets/vaddrs. The 467 * JIT lane maps input section bytes directly into execmem, so ordinary 468 * segment payload buffers would be copied only to be copied again. */ 469 for (b = 0; b < SEG_NBUCKETS; ++b) { 470 if (!bucket_seg[b]) continue; 471 { 472 LinkSegment* seg = &img->segments[bucket_seg[b] - 1]; 473 if (seg->file_size && !l->jit_mode) { 474 img->segment_bytes[bucket_seg[b] - 1] = 475 (u8*)h->alloc(h, (size_t)seg->file_size, 16); 476 if (!img->segment_bytes[bucket_seg[b] - 1]) 477 compiler_panic(img->c, SRCLOC_NONE, "link: oom on segment bytes"); 478 img->segment_bytes_cap[bucket_seg[b] - 1] = (size_t)seg->file_size; 479 memset(img->segment_bytes[bucket_seg[b] - 1], 0, 480 (size_t)seg->file_size); 481 } 482 } 483 } 484 485 for (j = 0; j < img->nsections; ++j) { 486 LinkSection* ls = &img->sections[j]; 487 u32 b2 = (u32)(ls->segment_id - 1u); /* sentinel-stash */ 488 LinkSegment* seg = &img->segments[bucket_seg[b2] - 1]; 489 ls->segment_id = seg->id; 490 ls->vaddr += seg->vaddr; 491 ls->file_offset += seg->file_offset; 492 } 493 } 494 } 495 496 /* ---- scripted layout (linker-script driven) ---- 497 * 498 * Walks the KitLinkScript's output sections in declaration order, 499 * placing matched input sections at the dot location counter. One 500 * LinkSegment per non-DISCARD output section maps 1:1 to a PT_LOAD on 501 * emit. Symbol assignments (top-level and in-section) materialize as 502 * defined LinkSymbol globals via link_emit_boundary_sym. 503 * 504 * Discard handling: `/DISCARD/` matches input sections by glob and 505 * leaves their per-input m->section[id] entry as LINK_SEC_NONE — the 506 * downstream emit_reloc_records / link_assign_symbol_vaddrs passes 507 * already treat that as "section dropped" so they're naturally 508 * excluded from segments, gc, and reloc apply. */ 509 510 /* `*` is the only metachar. Supported forms in the kernel.lds-style 511 * subset: trailing star (".text*"), leading star ("*COMMON" — not in 512 * kernel.lds but cheap), and exact literal. */ 513 static int match_glob(const char* pat, const char* name) { 514 size_t plen, nlen; 515 if (!pat || !name) return 0; 516 plen = slice_from_cstr(pat).len; 517 nlen = slice_from_cstr(name).len; 518 if (plen == 1 && pat[0] == '*') return 1; 519 if (plen >= 2 && pat[plen - 1] == '*') { 520 if (nlen + 1 < plen) return 0; 521 return memcmp(pat, name, plen - 1) == 0; 522 } 523 if (plen >= 2 && pat[0] == '*') { 524 if (nlen + 1 < plen) return 0; 525 return memcmp(pat + 1, name + (nlen - (plen - 1)), plen - 1) == 0; 526 } 527 return plen == nlen && memcmp(pat, name, plen) == 0; 528 } 529 530 typedef struct ScriptOutInfo { 531 KitSlice name; 532 u64 vma; 533 u64 lma; 534 u64 size; 535 int defined; 536 } ScriptOutInfo; 537 538 static const KitLinkRegion* script_find_region(const KitLinkScript* script, 539 KitSlice name) { 540 u32 i; 541 if (!script || !name.s) return NULL; 542 for (i = 0; i < script->nregions; ++i) 543 if (slice_eq(script->regions[i].name, name)) return &script->regions[i]; 544 return NULL; 545 } 546 547 static int script_region_index(const KitLinkScript* script, KitSlice name, 548 u32* out) { 549 u32 i; 550 if (!script || !name.s) return 0; 551 for (i = 0; i < script->nregions; ++i) { 552 if (slice_eq(script->regions[i].name, name)) { 553 if (out) *out = i; 554 return 1; 555 } 556 } 557 return 0; 558 } 559 560 static const ScriptOutInfo* script_find_out(const ScriptOutInfo* outs, 561 u32 nouts, KitSlice name) { 562 u32 i; 563 if (!name.s) return NULL; 564 for (i = 0; i < nouts; ++i) 565 if (outs[i].defined && slice_eq(outs[i].name, name)) return &outs[i]; 566 return NULL; 567 } 568 569 static const KitLinkPhdr* script_find_phdr(const KitLinkScript* script, 570 KitSlice name) { 571 u32 i; 572 if (!script || !name.s) return NULL; 573 for (i = 0; i < script->nphdrs; ++i) 574 if (slice_eq(script->phdrs[i].name, name)) return &script->phdrs[i]; 575 return NULL; 576 } 577 578 static u64 script_sizeof_headers(Linker* l) { 579 const KitLinkScript* s = l ? l->script : NULL; 580 u32 nph = 0; 581 u32 i; 582 u64 eh = (l && l->c && l->c->target.ptr_size == 4) ? 52u : 64u; 583 u64 ph = (l && l->c && l->c->target.ptr_size == 4) ? 32u : 56u; 584 if (!s) return eh; 585 for (i = 0; i < s->nsections; ++i) 586 if (!slice_eq_cstr(s->sections[i].name, "/DISCARD/")) ++nph; 587 if (s->nphdrs > nph) nph = s->nphdrs; 588 return eh + (u64)nph * ph; 589 } 590 591 static char script_ascii_lower(char c) { 592 return (c >= 'A' && c <= 'Z') ? (char)(c + ('a' - 'A')) : c; 593 } 594 595 static int script_slice_contains_lit_ci(KitSlice s, const char* lit) { 596 size_t lit_len = 0; 597 size_t i, j; 598 if (!s.s || !lit) return 0; 599 while (lit[lit_len]) ++lit_len; 600 if (lit_len == 0 || s.len < lit_len) return 0; 601 for (i = 0; i <= s.len - lit_len; ++i) { 602 for (j = 0; j < lit_len; ++j) { 603 if (script_ascii_lower(s.s[i + j]) != script_ascii_lower(lit[j])) 604 break; 605 } 606 if (j == lit_len) return 1; 607 } 608 return 0; 609 } 610 611 static int script_format_name(KitSlice name, KitObjFmt* out) { 612 if (script_slice_contains_lit_ci(name, "elf")) { 613 *out = KIT_OBJ_ELF; 614 return 1; 615 } 616 if (script_slice_contains_lit_ci(name, "mach-o") || 617 script_slice_contains_lit_ci(name, "macho")) { 618 *out = KIT_OBJ_MACHO; 619 return 1; 620 } 621 if (script_slice_contains_lit_ci(name, "coff") || 622 script_slice_contains_lit_ci(name, "pei-") || 623 script_slice_contains_lit_ci(name, "pe-")) { 624 *out = KIT_OBJ_COFF; 625 return 1; 626 } 627 if (script_slice_contains_lit_ci(name, "wasm")) { 628 *out = KIT_OBJ_WASM; 629 return 1; 630 } 631 return 0; 632 } 633 634 static int script_arch_name(KitSlice name, KitArchKind* out) { 635 if (script_slice_contains_lit_ci(name, "aarch64") || 636 script_slice_contains_lit_ci(name, "arm64")) { 637 *out = KIT_ARCH_ARM_64; 638 return 1; 639 } 640 if (script_slice_contains_lit_ci(name, "x86_64") || 641 script_slice_contains_lit_ci(name, "x86-64") || 642 script_slice_contains_lit_ci(name, "amd64")) { 643 *out = KIT_ARCH_X86_64; 644 return 1; 645 } 646 if (script_slice_contains_lit_ci(name, "riscv64") || 647 script_slice_contains_lit_ci(name, "rv64")) { 648 *out = KIT_ARCH_RV64; 649 return 1; 650 } 651 if (script_slice_contains_lit_ci(name, "riscv32") || 652 script_slice_contains_lit_ci(name, "rv32")) { 653 *out = KIT_ARCH_RV32; 654 return 1; 655 } 656 if (script_slice_contains_lit_ci(name, "wasm")) { 657 *out = KIT_ARCH_WASM; 658 return 1; 659 } 660 if (script_slice_contains_lit_ci(name, "i386") || 661 script_slice_contains_lit_ci(name, "i686") || 662 script_slice_contains_lit_ci(name, "x86")) { 663 *out = KIT_ARCH_X86_32; 664 return 1; 665 } 666 if (script_slice_contains_lit_ci(name, "arm")) { 667 *out = KIT_ARCH_ARM_32; 668 return 1; 669 } 670 return 0; 671 } 672 673 static void validate_script_target(Linker* l, const KitLinkScript* script) { 674 KitObjFmt fmt; 675 KitArchKind arch; 676 if (!l || !script) return; 677 if (script->output_format.s && script->output_format.len && 678 script_format_name(script->output_format, &fmt) && 679 fmt != l->c->target.obj) { 680 compiler_panic(l->c, SRCLOC_NONE, 681 "linker script: OUTPUT_FORMAT '%.*s' does not match target", 682 SLICE_ARG(script->output_format)); 683 } 684 if (script->output_arch.s && script->output_arch.len && 685 script_arch_name(script->output_arch, &arch) && 686 arch != l->c->target.arch) { 687 compiler_panic(l->c, SRCLOC_NONE, 688 "linker script: OUTPUT_ARCH '%.*s' does not match target", 689 SLICE_ARG(script->output_arch)); 690 } 691 } 692 693 /* Maximum link-script expression evaluation depth — mirrors the parser's 694 * LSP_MAX_EXPR_DEPTH so eval fails cleanly (sets *err) instead of overflowing 695 * the stack on a pathologically nested expression. */ 696 #define EVAL_LINK_MAX_DEPTH 256 697 698 static u64 eval_link_expr_rec(Linker* l, LinkImage* img, u64 dot, 699 const ScriptOutInfo* outs, u32 nouts, 700 int depth, const KitLinkExpr* e, int* err) { 701 if (!e) { 702 *err = 1; 703 return 0; 704 } 705 if (depth > EVAL_LINK_MAX_DEPTH) { 706 *err = 1; 707 return 0; 708 } 709 switch ((KitLinkExprKind)e->kind) { 710 case KIT_LE_INT: 711 return (u64)e->v.int_val; 712 case KIT_LE_DOT: 713 return dot; 714 case KIT_LE_SYM: { 715 Sym name = pool_intern_slice(l->c->global, e->v.name); 716 LinkSymId id = symhash_get(&img->globals, name); 717 if (id == LINK_SYM_NONE) { 718 compiler_panic(l->c, SRCLOC_NONE, 719 "linker script: undefined symbol '%.*s' in expression", 720 SLICE_ARG(pool_slice(l->c->global, name))); 721 } 722 return LinkSyms_at(&img->syms, id - 1)->vaddr; 723 } 724 case KIT_LE_NEG: 725 return (u64)(-(i64)eval_link_expr_rec(l, img, dot, outs, nouts, 726 depth + 1, e->v.align.val, err)); 727 case KIT_LE_ADD: 728 return eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.lhs, err) + 729 eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.rhs, err); 730 case KIT_LE_SUB: 731 return eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.lhs, err) - 732 eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.rhs, err); 733 case KIT_LE_MUL: 734 return eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.lhs, err) * 735 eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.rhs, err); 736 case KIT_LE_DIV: { 737 u64 rhs = eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.rhs, err); 738 if (rhs == 0) { 739 *err = 1; 740 return 0; 741 } 742 return eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.lhs, err) / rhs; 743 } 744 case KIT_LE_AND: 745 return eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.lhs, err) & 746 eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.rhs, err); 747 case KIT_LE_OR: 748 return eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.lhs, err) | 749 eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.rhs, err); 750 case KIT_LE_XOR: 751 return eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.lhs, err) ^ 752 eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.rhs, err); 753 case KIT_LE_SHL: 754 return eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.lhs, err) 755 << eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.rhs, err); 756 case KIT_LE_SHR: 757 return eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.lhs, err) >> 758 eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.rhs, err); 759 case KIT_LE_MAX: { 760 u64 a = eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.lhs, err); 761 u64 b = eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.rhs, err); 762 return a > b ? a : b; 763 } 764 case KIT_LE_MIN: { 765 u64 a = eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.lhs, err); 766 u64 b = eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.bin.rhs, err); 767 return a < b ? a : b; 768 } 769 case KIT_LE_ALIGN: { 770 u64 v = eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.align.val, err); 771 u64 a = 772 eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.align.align, err); 773 if (a == 0) return v; 774 return ALIGN_UP(v, a); 775 } 776 case KIT_LE_BLOCK: { 777 u64 v = eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.align.val, err); 778 u64 a = 779 eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.align.align, err); 780 if (a == 0) return v; 781 return ALIGN_UP(v, a); 782 } 783 case KIT_LE_REGION_ORIGIN: { 784 const KitLinkRegion* r = script_find_region(l->script, e->v.name); 785 if (!r) { 786 compiler_panic(l->c, SRCLOC_NONE, 787 "linker script: unknown MEMORY region '%.*s'", 788 SLICE_ARG(e->v.name)); 789 } 790 return r->origin; 791 } 792 case KIT_LE_REGION_LENGTH: { 793 const KitLinkRegion* r = script_find_region(l->script, e->v.name); 794 if (!r) { 795 compiler_panic(l->c, SRCLOC_NONE, 796 "linker script: unknown MEMORY region '%.*s'", 797 SLICE_ARG(e->v.name)); 798 } 799 return r->length; 800 } 801 case KIT_LE_ADDR: { 802 const ScriptOutInfo* info = script_find_out(outs, nouts, e->v.name); 803 if (!info) 804 compiler_panic(l->c, SRCLOC_NONE, 805 "linker script: ADDR of unknown output section '%.*s'", 806 SLICE_ARG(e->v.name)); 807 return info->vma; 808 } 809 case KIT_LE_LOADADDR: { 810 const ScriptOutInfo* info = script_find_out(outs, nouts, e->v.name); 811 if (!info) 812 compiler_panic( 813 l->c, SRCLOC_NONE, 814 "linker script: LOADADDR of unknown output section '%.*s'", 815 SLICE_ARG(e->v.name)); 816 return info->lma; 817 } 818 case KIT_LE_SIZEOF: { 819 const ScriptOutInfo* info = script_find_out(outs, nouts, e->v.name); 820 if (!info) 821 compiler_panic(l->c, SRCLOC_NONE, 822 "linker script: SIZEOF of unknown output section '%.*s'", 823 SLICE_ARG(e->v.name)); 824 return info->size; 825 } 826 case KIT_LE_SIZEOF_HEADERS: 827 return script_sizeof_headers(l); 828 case KIT_LE_DEFINED: { 829 Sym name = pool_intern_slice(l->c->global, e->v.name); 830 LinkSymId id = symhash_get(&img->globals, name); 831 const LinkSymbol* s = 832 (id != LINK_SYM_NONE) ? LinkSyms_at(&img->syms, id - 1) : NULL; 833 return (s && s->defined) ? 1u : 0u; 834 } 835 case KIT_LE_ABSOLUTE: 836 return eval_link_expr_rec(l, img, dot, outs, nouts, depth + 1, e->v.align.val, err); 837 default: 838 compiler_panic(l->c, SRCLOC_NONE, 839 "linker script: expression kind %u not supported", 840 (unsigned)e->kind); 841 return 0; 842 } 843 } 844 845 /* Depth-tracked entry point: callers evaluate from depth 0. */ 846 static u64 eval_link_expr(Linker* l, LinkImage* img, u64 dot, 847 const ScriptOutInfo* outs, u32 nouts, 848 const KitLinkExpr* e, int* err) { 849 return eval_link_expr_rec(l, img, dot, outs, nouts, 0, e, err); 850 } 851 852 /* Set a segment's phdr attributes (type/filehdr/phdrs/flags) from the named 853 * PHDRS entry `name`. Panics if the name is unknown. `dot`/`outs`/`nouts` are 854 * forwarded to the FLAGS() expression evaluation. */ 855 static void script_apply_phdr(Linker* l, LinkImage* img, 856 const KitLinkScript* script, LinkSegment* seg, 857 KitSlice name, u64 dot, const ScriptOutInfo* outs, 858 u32 nouts) { 859 const KitLinkPhdr* ph = script_find_phdr(script, name); 860 if (!ph) 861 compiler_panic(l->c, SRCLOC_NONE, "linker script: unknown PHDR '%.*s'", 862 SLICE_ARG(name)); 863 seg->phdr_type = ph->type; 864 seg->phdr_filehdr = ph->filehdr ? 1u : 0u; 865 seg->phdr_phdrs = ph->phdrs ? 1u : 0u; 866 if (ph->flags) { 867 int err = 0; 868 seg->phdr_flags = (u32)eval_link_expr(l, img, dot, outs, nouts, ph->flags, 869 &err); 870 if (err) 871 compiler_panic(l->c, SRCLOC_NONE, 872 "linker script: invalid PHDR FLAGS for '%.*s'", 873 SLICE_ARG(ph->name)); 874 seg->phdr_flags_set = 1u; 875 } 876 } 877 878 /* Format-aware C-symbol mangling for linker-synthesized boundaries. */ 879 static Sym boundary_name(Linker* l, const char* name) { 880 return obj_format_c_mangle(l->c, name); 881 } 882 883 /* Upsert a global boundary symbol. Satisfies any prior undef ref in place; fans 884 * out to per-input duplicate name slots. `section_id` is LINK_SEC_NONE for 885 * absolute boundaries, or the owning LinkSectionId for boundaries that must 886 * follow a format-specific section relayout. */ 887 static void link_emit_boundary_sym_ex(Linker* l, LinkImage* img, 888 const char* name, u64 vaddr, 889 LinkSectionId section_id, u64 value) { 890 Sym sym = boundary_name(l, name); 891 LinkSymId id = symhash_get(&img->globals, sym); 892 LinkSymId canonical_id = id; 893 LinkSymbol rec; 894 u8 kind = SK_OBJ; 895 int fmt_kind; 896 u32 i, n; 897 /* Some formats own specific boundary symbols with a fixed SymKind 898 * (PE/COFF `__ImageBase` / `_tls_used` are SK_ABS). Ask the format 899 * instead of matching names here. */ 900 if (obj_format_boundary_sym_kind(l->c, slice_from_cstr(name), &fmt_kind)) 901 kind = (u8)fmt_kind; 902 memset(&rec, 0, sizeof(rec)); 903 rec.name = sym; 904 rec.kind = kind; 905 rec.defined = 1; 906 rec.section_id = section_id; 907 rec.value = value; 908 rec.vaddr = vaddr; 909 rec.bind = SB_GLOBAL; 910 if (id != LINK_SYM_NONE) { 911 *LinkSyms_at(&img->syms, id - 1) = rec; 912 LinkSyms_at(&img->syms, id - 1)->id = id; 913 } else { 914 LinkSymId fresh = link_append_symbol(img, &rec); 915 symhash_insert(&img->globals, sym, fresh, &id); 916 canonical_id = fresh; 917 } 918 n = LinkSyms_count(&img->syms); 919 for (i = 0; i < n; ++i) { 920 LinkSymbol* s = LinkSyms_at(&img->syms, i); 921 if (s->name != sym) continue; 922 if (s->id == canonical_id) continue; 923 if (s->bind == SB_LOCAL) continue; 924 s->section_id = section_id; 925 s->value = value; 926 s->vaddr = vaddr; 927 s->kind = kind; 928 s->defined = 1; 929 s->imported = 0; 930 } 931 } 932 933 void link_emit_boundary_sym(Linker* l, LinkImage* img, const char* name, 934 u64 vaddr) { 935 link_emit_boundary_sym_ex(l, img, name, vaddr, LINK_SEC_NONE, 0); 936 } 937 938 void link_emit_section_boundary_sym(Linker* l, LinkImage* img, const char* name, 939 LinkSectionId section_id, u64 value) { 940 const LinkSection* sec; 941 u64 vaddr; 942 if (section_id == LINK_SEC_NONE || section_id > img->nsections) 943 compiler_panic(img->c, SRCLOC_NONE, 944 "link: boundary symbol '%.*s' has no containing section", 945 SLICE_ARG(slice_from_cstr(name))); 946 sec = &img->sections[section_id - 1]; 947 vaddr = sec->vaddr + (value - sec->obj_offset); 948 link_emit_boundary_sym_ex(l, img, name, vaddr, section_id, value); 949 } 950 951 /* link_define_boundary: public alias used by link_dyn.c. */ 952 void link_define_boundary(Linker* l, LinkImage* img, const char* name, 953 u64 vaddr) { 954 link_emit_boundary_sym(l, img, name, vaddr); 955 } 956 957 /* Upsert a global symbol (mirror of emit_boundary_sym, used by apply_asn). */ 958 static void upsert_global_sym(Linker* l, LinkImage* img, KitSlice name, 959 u64 vaddr) { 960 /* Script sym slices are arena-interned and NUL-terminated; the boundary 961 * emitter mangles via obj_format_c_mangle which needs a C string. */ 962 link_emit_boundary_sym(l, img, name.s, vaddr); 963 } 964 965 /* Apply one KitLinkAssignment. */ 966 static int script_symbol_defined(Linker* l, LinkImage* img, KitSlice name) { 967 Sym sym; 968 LinkSymId id; 969 const LinkSymbol* s; 970 if (!name.s) return 0; 971 sym = pool_intern_slice(l->c->global, name); 972 id = symhash_get(&img->globals, sym); 973 if (id == LINK_SYM_NONE) return 0; 974 s = LinkSyms_at(&img->syms, id - 1); 975 return s && s->defined; 976 } 977 978 static void apply_asn(Linker* l, LinkImage* img, u64* dot, 979 const ScriptOutInfo* outs, u32 nouts, 980 const KitLinkAssignment* asn) { 981 int err = 0; 982 u64 v = eval_link_expr(l, img, *dot, outs, nouts, asn->expr, &err); 983 if (err) return; 984 switch ((KitLinkAsnKind)asn->kind) { 985 case KIT_LAS_DOT: 986 if (v < *dot) 987 compiler_panic(l->c, SRCLOC_NONE, 988 "linker script: dot moved backwards (%llu -> %llu)", 989 (unsigned long long)*dot, (unsigned long long)v); 990 *dot = v; 991 break; 992 case KIT_LAS_SYM: 993 case KIT_LAS_HIDDEN: 994 if (asn->sym.s) upsert_global_sym(l, img, asn->sym, v); 995 break; 996 case KIT_LAS_PROVIDE: 997 case KIT_LAS_PROVIDE_HIDDEN: 998 if (asn->sym.s && !script_symbol_defined(l, img, asn->sym)) 999 upsert_global_sym(l, img, asn->sym, v); 1000 break; 1001 } 1002 } 1003 1004 /* Apply every KIT_LAS_DOT top-level assignment whose textual `seq` is below 1005 * `seq_limit` and that has not yet been applied (tracked by *cursor), so the 1006 * location counter advances at the assignment's source position. top_asns is 1007 * already in textual order, so a single forward cursor suffices. Non-DOT 1008 * top-level assignments (symbol defs / PROVIDE) are applied in a later pass 1009 * once all section addresses are known. */ 1010 static void apply_dot_asns_before(Linker* l, LinkImage* img, u64* dot, 1011 const ScriptOutInfo* outs, u32 nouts, 1012 const KitLinkScript* script, u32* cursor, 1013 u32 seq_limit) { 1014 while (*cursor < script->ntop_asns && 1015 script->top_asns[*cursor].seq < seq_limit) { 1016 const KitLinkAssignment* a = &script->top_asns[*cursor]; 1017 if (a->kind == KIT_LAS_DOT) apply_asn(l, img, dot, outs, nouts, a); 1018 ++*cursor; 1019 } 1020 } 1021 1022 static const char* link_basename(const char* s) { 1023 const char* base = s; 1024 if (!s) return NULL; 1025 for (; *s; ++s) 1026 if (*s == '/' || *s == '\\') base = s + 1; 1027 return base; 1028 } 1029 1030 static int input_match_file(Linker* l, u32 ii, const KitLinkInputMatch* m) { 1031 const LinkInput* in; 1032 Slice name = SLICE_NULL; 1033 const char* full; 1034 const char* base; 1035 u32 i; 1036 if (!m->file_pattern.s && m->nexclude_file_patterns == 0) return 1; 1037 if (ii >= LinkInputs_count(&l->inputs)) return 0; 1038 in = LinkInputs_at(&l->inputs, ii); 1039 if (in->name) name = pool_slice(l->c->global, in->name); 1040 full = name.s; 1041 base = link_basename(full); 1042 if (m->file_pattern.s) { 1043 if (!full) return 0; 1044 if (!match_glob(m->file_pattern.s, full) && 1045 !match_glob(m->file_pattern.s, base)) 1046 return 0; 1047 } 1048 for (i = 0; i < m->nexclude_file_patterns; ++i) { 1049 const char* pat = m->exclude_file_patterns[i].s; 1050 if (!pat || !full) continue; 1051 if (match_glob(pat, full) || match_glob(pat, base)) return 0; 1052 } 1053 return 1; 1054 } 1055 1056 static int input_match_section(Linker* l, u32 ii, const KitLinkInputMatch* m, 1057 const char* nm) { 1058 /* section_pattern is an arena-interned, NUL-terminated span of the 1059 * script text; match_glob scans it as a C string. */ 1060 return input_match_file(l, ii, m) && match_glob(m->section_pattern.s, nm); 1061 } 1062 1063 /* Fill `n` bytes of `dst` with the linker-script FILL pattern. GNU ld lays a 1064 * fill value down as a big-endian byte pattern of `width` bytes (the value's 1065 * significant byte count; default 4) repeated across the region. The pattern 1066 * is phase-aligned to the start of the buffer, so gaps anywhere in a section 1067 * see a consistent repeat. width is clamped to [1,8]. */ 1068 static void script_pattern_fill(u8* dst, size_t n, u64 value, u32 width) { 1069 size_t i; 1070 u8 pat[8]; 1071 u32 w = width ? (width > 8u ? 8u : width) : 1u; 1072 u32 b; 1073 /* big-endian: most-significant of the `w` low bytes first */ 1074 for (b = 0; b < w; ++b) 1075 pat[b] = (u8)(value >> (8u * (w - 1u - b))); 1076 for (i = 0; i < n; ++i) dst[i] = pat[i % w]; 1077 } 1078 1079 static u32 script_output_input_align(Linker* l, LinkImage* img, 1080 const GcLive* g, 1081 const KitLinkOutputSection* os, 1082 u8** claimed) { 1083 u32 align_max = 1; 1084 u32 mi, ii, j; 1085 for (mi = 0; mi < os->ninputs; ++mi) { 1086 const KitLinkInputMatch* im = &os->inputs[mi]; 1087 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 1088 ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; 1089 InputMap* m = &img->input_maps[ii]; 1090 for (j = 1; j < obj_section_count(ob); ++j) { 1091 const Section* s; 1092 const char* nm; 1093 u32 align; 1094 if (claimed[ii][j]) continue; 1095 if (m->comdat_discarded[j]) continue; 1096 s = obj_section_get(ob, j); 1097 if (!s || !link_section_kept(s)) continue; 1098 nm = pool_slice(l->c->global, s->name).s; 1099 if (!nm) continue; 1100 if (!input_match_section(l, ii, im, nm)) continue; 1101 if (!live_section_units(g, m, ii, ob, j)) continue; 1102 align = s->align ? s->align : 1u; 1103 if (align > align_max) align_max = align; 1104 } 1105 } 1106 } 1107 return align_max; 1108 } 1109 1110 static void link_layout_sections_scripted(Linker* l, LinkImage* img, 1111 const GcLive* g) { 1112 Heap* h = img->heap; 1113 const KitLinkScript* script = l->script; 1114 u64 dot = 0; 1115 u64 file_cursor = 0; 1116 u32 ii, j, k, si; 1117 u32 total_kept = 0; 1118 1119 img->scripted = 1; 1120 validate_script_target(l, script); 1121 1122 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 1123 ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; 1124 InputMap* m = &img->input_maps[ii]; 1125 for (j = 1; j < obj_section_count(ob); ++j) { 1126 const Section* s = obj_section_get(ob, j); 1127 if (s && link_section_kept(s) && !m->comdat_discarded[j]) 1128 total_kept += live_section_units(g, m, ii, ob, j); 1129 } 1130 } 1131 1132 img->sections = total_kept ? (LinkSection*)h->alloc( 1133 h, sizeof(*img->sections) * total_kept, 1134 _Alignof(LinkSection)) 1135 : NULL; 1136 if (total_kept && !img->sections) 1137 compiler_panic(img->c, SRCLOC_NONE, "link: oom on sections"); 1138 1139 u8** claimed = NULL; 1140 ScriptOutInfo* outs = NULL; 1141 u64* region_cursor = NULL; 1142 u64* load_region_cursor = NULL; 1143 if (LinkInputs_count(&l->inputs)) { 1144 u32 ni = LinkInputs_count(&l->inputs); 1145 claimed = (u8**)h->alloc(h, sizeof(*claimed) * ni, _Alignof(u8*)); 1146 if (!claimed) compiler_panic(img->c, SRCLOC_NONE, "link: oom on claim map"); 1147 for (ii = 0; ii < ni; ++ii) { 1148 ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; 1149 u32 nsec = obj_section_count(ob); 1150 claimed[ii] = (u8*)h->alloc(h, nsec, 1); 1151 if (!claimed[ii]) 1152 compiler_panic(img->c, SRCLOC_NONE, "link: oom on claim row"); 1153 memset(claimed[ii], 0, nsec); 1154 } 1155 } 1156 if (script->nsections) { 1157 outs = (ScriptOutInfo*)h->alloc(h, sizeof(*outs) * script->nsections, 1158 _Alignof(ScriptOutInfo)); 1159 if (!outs) compiler_panic(img->c, SRCLOC_NONE, "link: oom on script map"); 1160 memset(outs, 0, sizeof(*outs) * script->nsections); 1161 } 1162 if (script->nregions) { 1163 region_cursor = 1164 (u64*)h->alloc(h, sizeof(*region_cursor) * script->nregions, 1165 _Alignof(u64)); 1166 load_region_cursor = 1167 (u64*)h->alloc(h, sizeof(*load_region_cursor) * script->nregions, 1168 _Alignof(u64)); 1169 if (!region_cursor || !load_region_cursor) 1170 compiler_panic(img->c, SRCLOC_NONE, "link: oom on region cursors"); 1171 for (ii = 0; ii < script->nregions; ++ii) { 1172 region_cursor[ii] = script->regions[ii].origin; 1173 load_region_cursor[ii] = script->regions[ii].origin; 1174 } 1175 } 1176 1177 /* Inter-section dot assignments (`. = ALIGN(N)` / `. = expr` written 1178 * between two output sections) must advance the location counter at their 1179 * textual position. top_asns and sections each carry a shared `seq`; walk 1180 * the DOT assignments in seq order, applying those that precede the next 1181 * section right before that section is laid out. dot_cursor tracks the 1182 * next unapplied top_asn. */ 1183 u32 dot_cursor = 0; 1184 1185 /* Upper bound on segments: each non-discard section contributes at least 1186 * one, plus one per *additional* :phdr it names (a section listing several 1187 * phdrs appears under each as its own program header). Coalescing sections 1188 * that share a phdr only reduces the count, so this stays an upper bound. */ 1189 u32 nseg_max = 0; 1190 for (si = 0; si < script->nsections; ++si) { 1191 const KitLinkOutputSection* os_ = &script->sections[si]; 1192 if (slice_eq_cstr(os_->name, "/DISCARD/")) continue; 1193 nseg_max += os_->nphdrs ? os_->nphdrs : 1u; 1194 } 1195 img->segments = 1196 nseg_max ? (LinkSegment*)h->alloc(h, sizeof(*img->segments) * nseg_max, 1197 _Alignof(LinkSegment)) 1198 : NULL; 1199 img->segment_bytes = 1200 nseg_max ? (u8**)h->alloc(h, sizeof(*img->segment_bytes) * nseg_max, 1201 _Alignof(u8*)) 1202 : NULL; 1203 img->segment_bytes_cap = 1204 nseg_max 1205 ? (size_t*)h->alloc(h, sizeof(*img->segment_bytes_cap) * nseg_max, 1206 _Alignof(size_t)) 1207 : NULL; 1208 if (nseg_max && 1209 (!img->segments || !img->segment_bytes || !img->segment_bytes_cap)) 1210 compiler_panic(img->c, SRCLOC_NONE, "link: oom on segments"); 1211 if (nseg_max) { 1212 memset(img->segment_bytes, 0, sizeof(*img->segment_bytes) * nseg_max); 1213 memset(img->segment_bytes_cap, 0, 1214 sizeof(*img->segment_bytes_cap) * nseg_max); 1215 } 1216 1217 /* Per-segment primary :phdr name (parallel to img->segments while we build 1218 * it); a new section naming the same phdr as the currently-open segment and 1219 * vaddr-contiguous with it coalesces into that one PT_LOAD. Kept local — no 1220 * LinkSegment field needed. open_seg is the index of the coalescable open 1221 * segment, or (u32)-1 when none can be extended. */ 1222 KitSlice* seg_phdr_name = NULL; 1223 u32 open_seg = (u32)-1; 1224 if (nseg_max) { 1225 seg_phdr_name = 1226 (KitSlice*)h->alloc(h, sizeof(*seg_phdr_name) * nseg_max, 1227 _Alignof(KitSlice)); 1228 if (!seg_phdr_name) 1229 compiler_panic(img->c, SRCLOC_NONE, "link: oom on segment phdr names"); 1230 memset(seg_phdr_name, 0, sizeof(*seg_phdr_name) * nseg_max); 1231 } 1232 1233 for (si = 0; si < script->nsections; ++si) { 1234 const KitLinkOutputSection* os = &script->sections[si]; 1235 int is_discard = slice_eq_cstr(os->name, "/DISCARD/"); 1236 /* Apply any inter-section dot assignments that textually precede this 1237 * output section before placing it. */ 1238 apply_dot_asns_before(l, img, &dot, outs, script->nsections, script, 1239 &dot_cursor, os->seq); 1240 if (outs) outs[si].name = os->name; 1241 1242 if (is_discard) { 1243 u32 mi; 1244 for (mi = 0; mi < os->ninputs; ++mi) { 1245 const KitLinkInputMatch* im = &os->inputs[mi]; 1246 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 1247 ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; 1248 for (j = 1; j < obj_section_count(ob); ++j) { 1249 const Section* s; 1250 const char* nm; 1251 if (claimed[ii][j]) continue; 1252 s = obj_section_get(ob, j); 1253 if (!s) continue; 1254 { 1255 nm = pool_slice(l->c->global, s->name).s; 1256 } 1257 if (!nm) continue; 1258 if (input_match_section(l, ii, im, nm)) claimed[ii][j] = 1; 1259 } 1260 } 1261 } 1262 continue; 1263 } 1264 1265 u64 sec_start_dot; 1266 u64 lma_start; 1267 u64 subalign_val = 0; 1268 /* GNU ld fill: a big-endian byte pattern repeated across gaps; a plain 1269 * integer FILL value is 4 bytes wide. fill_value carries the full value; 1270 * fill_width its significant byte count (default 4). */ 1271 u64 fill_value = 0; 1272 u32 fill_width = 4; 1273 u32 perms = 0; 1274 LinkSegmentId seg_id = (LinkSegmentId)(img->nsegments + 1u); 1275 LinkSegment* seg; 1276 u64 file_size_accum = 0; 1277 u64 mem_size_accum = 0; 1278 u32 align_max = 1; 1279 u32 nsec_in_seg = 0; 1280 u32 first_section_idx = img->nsections; 1281 u32 region_idx = 0; 1282 u32 load_region_idx = 0; 1283 int has_region = 0; 1284 int has_load_region = 0; 1285 1286 if (os->region.s) { 1287 has_region = script_region_index(script, os->region, ®ion_idx); 1288 if (!has_region) 1289 compiler_panic(l->c, SRCLOC_NONE, 1290 "linker script: unknown MEMORY region '%.*s'", 1291 SLICE_ARG(os->region)); 1292 } 1293 if (os->load_region.s) { 1294 has_load_region = 1295 script_region_index(script, os->load_region, &load_region_idx); 1296 if (!has_load_region) 1297 compiler_panic(l->c, SRCLOC_NONE, 1298 "linker script: unknown load MEMORY region '%.*s'", 1299 SLICE_ARG(os->load_region)); 1300 } 1301 1302 align_max = script_output_input_align(l, img, g, os, claimed); 1303 if (os->vma) { 1304 int err = 0; 1305 dot = eval_link_expr(l, img, dot, outs, script->nsections, os->vma, &err); 1306 if (err) 1307 compiler_panic(l->c, SRCLOC_NONE, 1308 "linker script: invalid VMA expression for '%.*s'", 1309 SLICE_ARG(os->name)); 1310 } else if (has_region) { 1311 dot = region_cursor[region_idx]; 1312 } 1313 dot = ALIGN_UP(dot, (u64)align_max); 1314 if (os->subalign) { 1315 int err = 0; 1316 subalign_val = 1317 eval_link_expr(l, img, dot, outs, script->nsections, os->subalign, 1318 &err); 1319 if (err) 1320 compiler_panic(l->c, SRCLOC_NONE, 1321 "linker script: invalid SUBALIGN for '%.*s'", 1322 SLICE_ARG(os->name)); 1323 } 1324 if (os->fill) { 1325 int err = 0; 1326 u64 fv = 1327 eval_link_expr(l, img, dot, outs, script->nsections, os->fill, &err); 1328 if (err) 1329 compiler_panic(l->c, SRCLOC_NONE, 1330 "linker script: invalid fill expression for '%.*s'", 1331 SLICE_ARG(os->name)); 1332 fill_value = fv; 1333 } 1334 /* Body command 0: the injected `: ALIGN(N)` header (if any) sets the 1335 * section base before any content is placed. Apply only body_seq-0 1336 * assignments here, then capture sec_start_dot. The remaining body 1337 * commands (input-section globs and interior `sym = .` / `. = expr` 1338 * assignments) execute below in true source order. */ 1339 for (k = 0; k < os->nasns; ++k) { 1340 if (os->asns[k].body_seq == 0) 1341 apply_asn(l, img, &dot, outs, script->nsections, &os->asns[k]); 1342 } 1343 sec_start_dot = dot; 1344 1345 /* Interleave input-section placement and interior assignments by their 1346 * source-order body_seq. GNU ld executes section-body commands in order, 1347 * so a `sym = .` after a `*(.data*)` glob captures `.` AFTER the glob's 1348 * content, and a `. = ALIGN(N)` after the last glob extends the section. 1349 * Both os->asns (body_seq >= 1) and os->inputs are stamped in ascending 1350 * source order, so a single forward cursor over each suffices. */ 1351 { 1352 u32 ak = 0; 1353 u32 mi = 0; 1354 /* Skip past the body_seq-0 header assignments already applied above. */ 1355 while (ak < os->nasns && os->asns[ak].body_seq == 0) ++ak; 1356 for (;;) { 1357 int have_asn = ak < os->nasns; 1358 int have_in = mi < os->ninputs; 1359 if (!have_asn && !have_in) break; 1360 /* Apply the assignment whose body_seq is strictly before the next 1361 * pending input command (or all trailing assignments when no inputs 1362 * remain). */ 1363 if (have_asn && 1364 (!have_in || os->asns[ak].body_seq < os->inputs[mi].body_seq)) { 1365 apply_asn(l, img, &dot, outs, script->nsections, &os->asns[ak]); 1366 /* A `. = expr` that advances dot past the placed content extends the 1367 * section span (GNU ld grows the output section to the new dot). The 1368 * gap also becomes interior file padding when it follows emitted 1369 * PROGBITS bytes in a loadable section (file_size_accum already 1370 * nonzero); a gap before any file content stays bss-like. */ 1371 if (dot - sec_start_dot > mem_size_accum) 1372 mem_size_accum = dot - sec_start_dot; 1373 if (!os->noload && file_size_accum && 1374 dot - sec_start_dot > file_size_accum) 1375 file_size_accum = dot - sec_start_dot; 1376 ++ak; 1377 continue; 1378 } 1379 { 1380 const KitLinkInputMatch* im = &os->inputs[mi]; 1381 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 1382 ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; 1383 InputMap* m = &img->input_maps[ii]; 1384 for (j = 1; j < obj_section_count(ob); ++j) { 1385 const Section* s; 1386 const char* nm; 1387 u32 align; 1388 u32 first = 0, count = 1, ai; 1389 int has_atoms; 1390 if (claimed[ii][j]) continue; 1391 if (m->comdat_discarded[j]) continue; 1392 s = obj_section_get(ob, j); 1393 if (!s || !link_section_kept(s)) continue; 1394 { 1395 nm = pool_slice(l->c->global, s->name).s; 1396 } 1397 if (!nm) continue; 1398 if (!input_match_section(l, ii, im, nm)) continue; 1399 1400 align = 1401 subalign_val ? (u32)subalign_val : (s->align ? s->align : 1u); 1402 has_atoms = link_input_section_has_atoms(m, j); 1403 if (has_atoms) link_input_section_atoms(m, j, &first, &count); 1404 for (ai = 0; ai < count; ++ai) { 1405 ObjAtomId aid = 1406 has_atoms ? m->section_atom_ids[first + ai] : OBJ_ATOM_NONE; 1407 const ObjAtom* atom = has_atoms ? obj_atom_get(ob, aid) : NULL; 1408 u64 ofs; 1409 LinkSection* ls; 1410 LinkSectionId lsid; 1411 u64 obj_offset; 1412 u64 size; 1413 if (has_atoms) { 1414 if (!atom || atom->removed) continue; 1415 if (!link_gc_atom_live_get(g, ii, aid)) continue; 1416 obj_offset = atom->offset; 1417 size = atom->size; 1418 } else if (!link_gc_live_get(g, ii, j)) { 1419 continue; 1420 } else { 1421 obj_offset = 0u; 1422 size = link_section_size_for_link(s); 1423 } 1424 if (align > align_max) align_max = align; 1425 dot = ALIGN_UP(dot, (u64)align); 1426 ofs = dot; 1427 1428 lsid = (LinkSectionId)(img->nsections + 1u); 1429 ls = &img->sections[img->nsections++]; 1430 memset(ls, 0, sizeof(*ls)); 1431 ls->id = lsid; 1432 ls->input_id = LinkInputs_at(&l->inputs, ii)->id; 1433 ls->obj_section_id = j; 1434 ls->obj_atom_id = aid; 1435 ls->segment_id = seg_id; 1436 ls->obj_offset = obj_offset; 1437 ls->vaddr = ofs; 1438 ls->size = size; 1439 ls->flags = s->flags; 1440 ls->align = align; 1441 ls->name = s->name; 1442 /* A (NOLOAD) output section produces no file bytes regardless 1443 * of the input section's PROGBITS/NOBITS semantics: mark every 1444 * placed unit NOBITS so the byte-copy 1445 * (link_emit_segment_bytes) and the segment shape below both 1446 * treat it as bss. */ 1447 ls->sem = (os->noload || s->kind == SEC_BSS) ? SSEM_NOBITS 1448 : s->sem; 1449 ls->file_offset = ofs - sec_start_dot; 1450 ls->input_offset = ls->file_offset; 1451 map_placed_unit(m, j, aid, lsid); 1452 1453 dot += ls->size; 1454 mem_size_accum = dot - sec_start_dot; 1455 if (!os->noload && ls->sem != SSEM_NOBITS) 1456 file_size_accum = dot - sec_start_dot; 1457 perms |= (s->flags & (SF_EXEC | SF_WRITE | SF_TLS)); 1458 ++nsec_in_seg; 1459 } 1460 claimed[ii][j] = 1; 1461 } 1462 } 1463 ++mi; 1464 } 1465 } 1466 } 1467 1468 if (os->lma) { 1469 int err = 0; 1470 lma_start = 1471 eval_link_expr(l, img, dot, outs, script->nsections, os->lma, &err); 1472 if (err) 1473 compiler_panic(l->c, SRCLOC_NONE, 1474 "linker script: invalid AT() expression for '%.*s'", 1475 SLICE_ARG(os->name)); 1476 } else if (has_load_region) { 1477 lma_start = ALIGN_UP(load_region_cursor[load_region_idx], 1478 (u64)(align_max ? align_max : 1u)); 1479 load_region_cursor[load_region_idx] = lma_start + file_size_accum; 1480 } else { 1481 lma_start = sec_start_dot; 1482 if (has_region && load_region_cursor) { 1483 u64 lend = lma_start + file_size_accum; 1484 if (lend > load_region_cursor[region_idx]) 1485 load_region_cursor[region_idx] = lend; 1486 } 1487 } 1488 1489 if (has_region) { 1490 const KitLinkRegion* r = &script->regions[region_idx]; 1491 u64 end = dot; 1492 /* Bug 3: a section spanning [sec_start_dot, end) fits region r iff 1493 * sec_start_dot >= origin and (end - origin) <= length. Compute the 1494 * end-fits test by subtraction, never `origin + length`, which wraps to 1495 * 0 for a canonical high-half region (e.g. ORIGIN=0xFFFFFFFF80000000, 1496 * LENGTH=0x80000000) and would falsely flag a legal placement. */ 1497 if (sec_start_dot < r->origin || end < r->origin || 1498 end - r->origin > r->length) 1499 compiler_panic( 1500 l->c, SRCLOC_NONE, 1501 "linker script: section '%.*s' overflows MEMORY region '%.*s'", 1502 SLICE_ARG(os->name), SLICE_ARG(r->name)); 1503 region_cursor[region_idx] = end; 1504 } 1505 if (has_load_region && file_size_accum) { 1506 const KitLinkRegion* r = &script->regions[load_region_idx]; 1507 u64 lend = lma_start + file_size_accum; 1508 /* Bug 3: same wrap-safe form for the load image [lma_start, lend). */ 1509 if (lma_start < r->origin || lend < r->origin || 1510 lend - r->origin > r->length) 1511 compiler_panic( 1512 l->c, SRCLOC_NONE, 1513 "linker script: load image for '%.*s' overflows MEMORY region " 1514 "'%.*s'", 1515 SLICE_ARG(os->name), SLICE_ARG(r->name)); 1516 } 1517 if (outs) { 1518 outs[si].vma = sec_start_dot; 1519 outs[si].lma = lma_start; 1520 outs[si].size = mem_size_accum; 1521 outs[si].defined = 1; 1522 } 1523 1524 if (nsec_in_seg == 0) { 1525 continue; 1526 } 1527 1528 /* (a) Coalesce: if this section's PRIMARY :phdr matches the currently-open 1529 * segment and the section is vaddr-contiguous with it, extend that segment 1530 * into one PT_LOAD instead of opening a new one. A section listing several 1531 * phdrs may still coalesce its primary here; its additional phdrs become 1532 * alias program headers below covering just this section's range. FLAGS() 1533 * / AT() seal a segment (they override the geometry) and never coalesce. */ 1534 KitSlice primary_phdr = os->nphdrs ? os->phdrs[0] : KIT_SLICE_NULL; 1535 int can_coalesce = 1536 open_seg != (u32)-1 && primary_phdr.s && seg_phdr_name[open_seg].s && 1537 slice_eq(seg_phdr_name[open_seg], primary_phdr) && 1538 sec_start_dot == img->segments[open_seg].vaddr + 1539 img->segments[open_seg].mem_size && 1540 /* Bug 1: never coalesce onto an open segment that ends in an internal 1541 * NOBITS (bss) tail. Coalescing packs the follower's file bytes 1542 * file-contiguously (after oseg->file_size) while it keeps its 1543 * mem-contiguous vaddr; with file_size < mem_size that skews the 1544 * follower's loaded bytes down by the tail size. Falling through to 1545 * the else branch opens a correct, separate page-aligned PT_LOAD. */ 1546 img->segments[open_seg].file_size == 1547 img->segments[open_seg].mem_size && 1548 !os->lma && !os->flags; 1549 1550 /* Per-section file geometry (used by both the primary placement and the 1551 * alias program headers, which describe only this section's range). */ 1552 u64 this_file_off; 1553 u64 this_vaddr = sec_start_dot; 1554 u64 this_paddr = lma_start; 1555 1556 if (can_coalesce) { 1557 LinkSegment* oseg = &img->segments[open_seg]; 1558 u64 prev_file = oseg->file_size; 1559 u64 new_file = prev_file + file_size_accum; 1560 seg = oseg; 1561 this_file_off = seg->file_offset + prev_file; 1562 seg->mem_size += mem_size_accum; 1563 /* This section's bytes follow the open segment's directly (no page 1564 * break); rebase its LinkSections into the open segment. */ 1565 { 1566 u32 fi; 1567 for (fi = first_section_idx; fi < img->nsections; ++fi) { 1568 LinkSection* ls = &img->sections[fi]; 1569 ls->segment_id = seg->id; 1570 ls->file_offset = this_file_off + ls->file_offset; 1571 } 1572 } 1573 file_cursor += file_size_accum; 1574 if (file_size_accum && !l->jit_mode) { 1575 u8* grown = (u8*)h->realloc(h, img->segment_bytes[open_seg], 1576 img->segment_bytes_cap[open_seg], 1577 (size_t)new_file, 16); 1578 if (!grown) 1579 compiler_panic(img->c, SRCLOC_NONE, 1580 "link: oom growing coalesced segment bytes"); 1581 img->segment_bytes[open_seg] = grown; 1582 img->segment_bytes_cap[open_seg] = (size_t)new_file; 1583 script_pattern_fill(grown + prev_file, (size_t)file_size_accum, 1584 fill_value, fill_width); 1585 } 1586 seg->file_size = new_file; 1587 seg->nsections += nsec_in_seg; 1588 /* Bug 2: a FLAGS-less PHDRS PT_LOAD maps p_flags from seg->flags 1589 * (perms_to_pflags); a coalesced PT_LOAD must carry the UNION of all its 1590 * mapped sections' perms (GNU-ld behavior), not just the first section's 1591 * (set once at segment creation). Union only the p_flags-relevant bits 1592 * (R/W/X) — a PT_LOAD's flags must never include SF_TLS, which the 1593 * emitter treats specially (p_memsz collapses to file_size for SF_TLS 1594 * segments); TLS sizing is owned by the dedicated PT_TLS segment. 1595 * (Defensive: the scripted layout does not currently route SF_TLS into a 1596 * coalesced section's perms, so this only narrows intent.) */ 1597 seg->flags |= SF_ALLOC | (perms & (SF_EXEC | SF_WRITE)); 1598 } else { 1599 seg = &img->segments[img->nsegments]; 1600 memset(seg, 0, sizeof(*seg)); 1601 seg->id = seg_id; 1602 seg->flags = SF_ALLOC | perms; 1603 seg->vaddr = sec_start_dot; 1604 seg->paddr = lma_start; 1605 file_cursor = ALIGN_UP(file_cursor, (u64)PAGE_SIZE); 1606 seg->file_offset = file_cursor; 1607 this_file_off = seg->file_offset; 1608 seg->mem_size = mem_size_accum; 1609 seg->file_size = file_size_accum; 1610 seg->align = align_max; 1611 seg->nsections = nsec_in_seg; 1612 /* Primary phdr names the segment's program-header attributes; the name 1613 * is recorded so a following same-phdr contiguous section coalesces. */ 1614 if (os->nphdrs) { 1615 script_apply_phdr(l, img, script, seg, os->phdrs[0], dot, outs, 1616 script->nsections); 1617 seg_phdr_name[img->nsegments] = os->phdrs[0]; 1618 } else { 1619 seg_phdr_name[img->nsegments] = KIT_SLICE_NULL; 1620 } 1621 if (os->flags) { 1622 int err = 0; 1623 seg->phdr_flags = 1624 (u32)eval_link_expr(l, img, dot, outs, script->nsections, 1625 os->flags, &err); 1626 if (err) 1627 compiler_panic(l->c, SRCLOC_NONE, 1628 "linker script: invalid FLAGS for section '%.*s'", 1629 SLICE_ARG(os->name)); 1630 seg->phdr_flags_set = 1u; 1631 } 1632 file_cursor += file_size_accum; 1633 if (file_size_accum && !l->jit_mode) { 1634 img->segment_bytes[img->nsegments] = 1635 (u8*)h->alloc(h, (size_t)file_size_accum, 16); 1636 if (!img->segment_bytes[img->nsegments]) 1637 compiler_panic(img->c, SRCLOC_NONE, 1638 "link: oom on scripted segment bytes"); 1639 img->segment_bytes_cap[img->nsegments] = (size_t)file_size_accum; 1640 script_pattern_fill(img->segment_bytes[img->nsegments], 1641 (size_t)file_size_accum, fill_value, fill_width); 1642 } 1643 { 1644 u32 fi; 1645 for (fi = first_section_idx; fi < img->nsections; ++fi) { 1646 LinkSection* ls = &img->sections[fi]; 1647 ls->file_offset = seg->file_offset + (ls->file_offset); 1648 } 1649 } 1650 /* A primary segment (phdr-named, no FLAGS/AT) is coalescable by a 1651 * following same-phdr contiguous section. No-phdr / FLAGS / AT segments 1652 * are sealed (NULL name never matches a phdr-named follower, matching 1653 * the pre-coalesce per-section behavior). */ 1654 open_seg = (os->nphdrs && !os->flags && !os->lma) ? img->nsegments 1655 : (u32)-1; 1656 img->nsegments++; 1657 } 1658 1659 /* (b) Each ADDITIONAL :phdr the section names yields an alias program 1660 * header covering only THIS section's vaddr/file range, with no byte 1661 * buffer of its own (the bytes are on disk via the primary; the ELF byte 1662 * writer skips NULL-buffer segments). */ 1663 { 1664 u32 pi; 1665 for (pi = 1; pi < os->nphdrs; ++pi) { 1666 LinkSegment* aseg = &img->segments[img->nsegments]; 1667 memset(aseg, 0, sizeof(*aseg)); 1668 aseg->id = (LinkSegmentId)(img->nsegments + 1u); 1669 aseg->flags = SF_ALLOC | perms; 1670 aseg->vaddr = this_vaddr; 1671 aseg->paddr = this_paddr; 1672 aseg->file_offset = this_file_off; 1673 aseg->mem_size = mem_size_accum; 1674 aseg->file_size = file_size_accum; 1675 aseg->align = align_max; 1676 aseg->nsections = 0; /* aliases own no sections */ 1677 script_apply_phdr(l, img, script, aseg, os->phdrs[pi], dot, outs, 1678 script->nsections); 1679 seg_phdr_name[img->nsegments] = os->phdrs[pi]; 1680 img->segment_bytes[img->nsegments] = NULL; 1681 img->segment_bytes_cap[img->nsegments] = 0; 1682 img->nsegments++; 1683 } 1684 } 1685 } 1686 1687 /* Apply any trailing dot assignments after the last output section. */ 1688 apply_dot_asns_before(l, img, &dot, outs, script->nsections, script, 1689 &dot_cursor, UINT32_MAX); 1690 1691 for (k = 0; k < script->ntop_asns; ++k) { 1692 const KitLinkAssignment* a = &script->top_asns[k]; 1693 if (a->kind != KIT_LAS_DOT) 1694 apply_asn(l, img, &dot, outs, script->nsections, a); 1695 } 1696 1697 for (k = 0; k < script->nasserts; ++k) { 1698 int err = 0; 1699 u64 ok = eval_link_expr(l, img, dot, outs, script->nsections, 1700 script->asserts[k].expr, &err); 1701 if (err || !ok) { 1702 KitSlice msg = script->asserts[k].message; 1703 compiler_panic(l->c, SRCLOC_NONE, "linker script ASSERT failed: %.*s", 1704 SLICE_ARG(msg)); 1705 } 1706 } 1707 1708 if (claimed) { 1709 u32 ni = LinkInputs_count(&l->inputs); 1710 for (ii = 0; ii < ni; ++ii) { 1711 ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; 1712 h->free(h, claimed[ii], obj_section_count(ob)); 1713 } 1714 h->free(h, claimed, sizeof(*claimed) * ni); 1715 } 1716 if (outs) h->free(h, outs, sizeof(*outs) * script->nsections); 1717 if (seg_phdr_name) 1718 h->free(h, seg_phdr_name, sizeof(*seg_phdr_name) * nseg_max); 1719 if (region_cursor) 1720 h->free(h, region_cursor, sizeof(*region_cursor) * script->nregions); 1721 if (load_region_cursor) 1722 h->free(h, load_region_cursor, 1723 sizeof(*load_region_cursor) * script->nregions); 1724 } 1725 1726 /* ---- pass 2b: COMMON symbol BSS allocation ---- */ 1727 1728 void link_layout_commons(Linker* l, LinkImage* img) { 1729 u32 i; 1730 (void)l; 1731 LinkSegment* rw_seg = NULL; 1732 1733 for (i = 0; i < img->nsegments; ++i) { 1734 if (img->segments[i].flags & SF_WRITE) { 1735 rw_seg = &img->segments[i]; 1736 break; 1737 } 1738 } 1739 1740 { 1741 int has_common = 0; 1742 for (i = 0; i < LinkSyms_count(&img->syms); ++i) 1743 if (LinkSyms_at(&img->syms, i)->kind == SK_COMMON && 1744 LinkSyms_at(&img->syms, i)->defined) { 1745 has_common = 1; 1746 break; 1747 } 1748 if (!has_common) return; 1749 } 1750 1751 if (!rw_seg) { 1752 /* No writable PT_LOAD yet — synthesize a zero-size BSS segment for the 1753 * COMMON section. This is a NOBITS region (no byte buffer, file/mem 1754 * size grow with the section below), so it adopts only the array- 1755 * growth helper, not the fixed-size region builder. */ 1756 u32 seg_idx = link_iplt_alloc_segments(img, 1u); 1757 u64 vaddr = 0; 1758 for (i = 0; i < img->nsegments; ++i) { 1759 u64 end = img->segments[i].vaddr + img->segments[i].mem_size; 1760 if (end > vaddr) vaddr = end; 1761 } 1762 vaddr = ALIGN_UP(vaddr, (u64)(link_layout_page_size(l))); 1763 rw_seg = &img->segments[seg_idx]; 1764 memset(rw_seg, 0, sizeof(*rw_seg)); 1765 rw_seg->id = (LinkSegmentId)(seg_idx + 1u); 1766 rw_seg->flags = SF_ALLOC | SF_WRITE; 1767 rw_seg->vaddr = vaddr; 1768 rw_seg->paddr = vaddr; 1769 rw_seg->file_offset = vaddr; 1770 rw_seg->file_size = 0; 1771 rw_seg->mem_size = 0; 1772 rw_seg->align = (u32)link_layout_page_size(l); 1773 img->segment_bytes[seg_idx] = NULL; 1774 img->segment_bytes_cap[seg_idx] = 0; 1775 img->nsegments++; 1776 } 1777 1778 { 1779 Heap* h = img->heap; 1780 u64 bss_start = rw_seg->vaddr + rw_seg->mem_size; 1781 u64 bss_cursor = bss_start; 1782 u32 max_align = 1u; 1783 LinkSection* commsec; 1784 LinkSectionId comm_lsid; 1785 1786 for (i = 0; i < LinkSyms_count(&img->syms); ++i) { 1787 LinkSymbol* s = LinkSyms_at(&img->syms, i); 1788 u32 align; 1789 if (s->kind != SK_COMMON || !s->defined) continue; 1790 align = s->common_align ? s->common_align : 1u; 1791 if (align > max_align) max_align = align; 1792 bss_cursor = ALIGN_UP(bss_cursor, (u64)(align)); 1793 s->value = bss_cursor - bss_start; 1794 bss_cursor += s->size ? s->size : 1u; 1795 } 1796 1797 { 1798 u32 new_nsec = img->nsections + 1u; 1799 LinkSection* nsec = (LinkSection*)h->realloc( 1800 h, img->sections, sizeof(*img->sections) * img->nsections, 1801 sizeof(*img->sections) * new_nsec, _Alignof(LinkSection)); 1802 if (!nsec) 1803 compiler_panic(img->c, SRCLOC_NONE, "link: oom on common section"); 1804 img->sections = nsec; 1805 } 1806 commsec = &img->sections[img->nsections]; 1807 memset(commsec, 0, sizeof(*commsec)); 1808 comm_lsid = (LinkSectionId)(img->nsections + 1u); 1809 commsec->id = comm_lsid; 1810 commsec->input_id = LINK_INPUT_NONE; 1811 commsec->obj_section_id = OBJ_SEC_NONE; 1812 commsec->segment_id = rw_seg->id; 1813 commsec->input_offset = 0; 1814 commsec->file_offset = bss_start; 1815 commsec->vaddr = bss_start; 1816 commsec->size = bss_cursor - bss_start; 1817 commsec->flags = SF_ALLOC | SF_WRITE; 1818 commsec->align = max_align; 1819 commsec->name = pool_intern_slice(img->c->global, SLICE_LIT(".bss.common")); 1820 commsec->sem = SSEM_NOBITS; 1821 img->nsections++; 1822 1823 for (i = 0; i < LinkSyms_count(&img->syms); ++i) { 1824 LinkSymbol* s = LinkSyms_at(&img->syms, i); 1825 if (s->kind != SK_COMMON || !s->defined) continue; 1826 s->section_id = comm_lsid; 1827 s->vaddr = bss_start + s->value; 1828 s->kind = SK_OBJ; 1829 } 1830 1831 rw_seg->mem_size = bss_cursor - rw_seg->vaddr; 1832 rw_seg->nsections++; 1833 } 1834 } 1835 1836 /* Copy each input section's bytes into its segment buffer. */ 1837 void link_emit_segment_bytes(Linker* l, LinkImage* img) { 1838 u32 j; 1839 (void)l; 1840 for (j = 0; j < img->nsections; ++j) { 1841 LinkSection* ls = &img->sections[j]; 1842 ObjBuilder* ob; 1843 if (ls->input_id == LINK_INPUT_NONE) continue; 1844 ob = LinkInputs_at(&l->inputs, ls->input_id - 1)->obj; 1845 const Section* s = obj_section_get(ob, ls->obj_section_id); 1846 LinkSegment* seg = &img->segments[ls->segment_id - 1]; 1847 u8* dst; 1848 /* ls->sem carries the OUTPUT-section decision (e.g. (NOLOAD) forces 1849 * NOBITS even for PROGBITS input), so check it too — the segment it 1850 * lives in has no file bytes to copy into. */ 1851 if (!s || s->sem == SSEM_NOBITS || s->kind == SEC_BSS || 1852 ls->sem == SSEM_NOBITS) 1853 continue; 1854 if (ls->size == 0) continue; 1855 dst = img->segment_bytes[seg->id - 1] + 1856 (size_t)(ls->file_offset - seg->file_offset); 1857 buf_read(&s->bytes, (u32)ls->obj_offset, dst, (size_t)ls->size); 1858 } 1859 } 1860 1861 /* ---- pass 2c: file-only debug sections ---- 1862 * 1863 * Carry every surviving .debug_* section through to the linked image as 1864 * a non-segment, file-resident LinkSection so addr2line / gdb resolve 1865 * file:line on the output. Contributions of the same name are assigned 1866 * a per-name cumulative `vaddr` (the DWARF-section-relative base: 0 for 1867 * the first input, size0 for the second, …); the ELF emitter merges 1868 * same-name contributions into one output .debug_X section, and the 1869 * per-input base makes SK_SECTION cross-section R_ABS32 offsets land in 1870 * the merged section. Each contribution keeps its own byte buffer in 1871 * the debug registry, with relocations applied in place at reloc-offset. 1872 * 1873 * Runs after link_emit_segment_bytes (so the segment-byte copy never 1874 * sees these segment-less sections) and before link_assign_symbol_vaddrs 1875 * (so the SK_SECTION debug symbols pick up their section_id + base). */ 1876 1877 /* Per-output-name cumulative base tracker. Debug section names are few 1878 * (.debug_info/.debug_line/.debug_abbrev/.debug_str/...), so a linear 1879 * scan is fine. */ 1880 typedef struct DbgNameAcc { 1881 Sym name; 1882 u64 cum; /* running total size for this name */ 1883 } DbgNameAcc; 1884 1885 void link_layout_debug(Linker* l, LinkImage* img) { 1886 Heap* h = img->heap; 1887 u32 ii, j; 1888 u32 ndbg = 0; 1889 1890 /* Pass 0: count surviving debug contributions. */ 1891 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 1892 ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; 1893 InputMap* m = &img->input_maps[ii]; 1894 for (j = 1; j < obj_section_count(ob); ++j) { 1895 const Section* s = obj_section_get(ob, j); 1896 if (link_section_kept_fileonly(s) && !m->comdat_discarded[j] && 1897 link_section_size_for_link(s) > 0) 1898 ++ndbg; 1899 } 1900 } 1901 if (ndbg == 0) return; 1902 1903 /* Grow img->sections to hold the new file-only sections appended after 1904 * the existing allocatable + common sections. */ 1905 { 1906 u32 new_nsec = img->nsections + ndbg; 1907 LinkSection* ns = (LinkSection*)h->realloc( 1908 h, img->sections, sizeof(*img->sections) * img->nsections, 1909 sizeof(*img->sections) * new_nsec, _Alignof(LinkSection)); 1910 if (!ns) compiler_panic(img->c, SRCLOC_NONE, "link: oom on debug sections"); 1911 img->sections = ns; 1912 } 1913 1914 img->dbg_bytes = 1915 (u8**)h->alloc(h, sizeof(*img->dbg_bytes) * ndbg, _Alignof(u8*)); 1916 img->dbg_size = 1917 (u64*)h->alloc(h, sizeof(*img->dbg_size) * ndbg, _Alignof(u64)); 1918 DbgNameAcc* acc = 1919 (DbgNameAcc*)h->alloc(h, sizeof(*acc) * ndbg, _Alignof(DbgNameAcc)); 1920 if (!img->dbg_bytes || !img->dbg_size || !acc) 1921 compiler_panic(img->c, SRCLOC_NONE, "link: oom on debug registry"); 1922 memset(img->dbg_bytes, 0, sizeof(*img->dbg_bytes) * ndbg); 1923 memset(img->dbg_size, 0, sizeof(*img->dbg_size) * ndbg); 1924 1925 img->dbg_first_lsid = (LinkSectionId)(img->nsections + 1u); 1926 img->dbg_count = 0; 1927 u32 nacc = 0; 1928 1929 /* Pass 1: append one file-only LinkSection per contribution, assign 1930 * per-name cumulative base, and copy bytes into the registry. */ 1931 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 1932 ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; 1933 InputMap* m = &img->input_maps[ii]; 1934 for (j = 1; j < obj_section_count(ob); ++j) { 1935 const Section* s = obj_section_get(ob, j); 1936 u32 size; 1937 u64 base; 1938 u32 ai, slot; 1939 LinkSection* ls; 1940 LinkSectionId lsid; 1941 u8* buf; 1942 if (!link_section_kept_fileonly(s) || m->comdat_discarded[j]) continue; 1943 size = link_section_size_for_link(s); 1944 if (size == 0) continue; 1945 1946 /* Per-name cumulative base. */ 1947 for (ai = 0; ai < nacc; ++ai) 1948 if (acc[ai].name == s->name) break; 1949 if (ai == nacc) { 1950 acc[nacc].name = s->name; 1951 acc[nacc].cum = 0; 1952 ai = nacc++; 1953 } 1954 base = acc[ai].cum; 1955 acc[ai].cum += size; 1956 1957 slot = img->dbg_count; 1958 lsid = (LinkSectionId)(img->nsections + 1u); 1959 ls = &img->sections[img->nsections++]; 1960 memset(ls, 0, sizeof(*ls)); 1961 ls->id = lsid; 1962 ls->input_id = LinkInputs_at(&l->inputs, ii)->id; 1963 ls->obj_section_id = j; 1964 ls->obj_atom_id = OBJ_ATOM_NONE; 1965 ls->segment_id = LINK_SEG_NONE; 1966 ls->obj_offset = 0; 1967 ls->input_offset = 0; 1968 ls->file_offset = 0; /* assigned by the ELF emitter */ 1969 ls->vaddr = base; /* DWARF-section-relative base */ 1970 ls->size = size; 1971 ls->flags = s->flags; 1972 ls->align = s->align ? s->align : 1u; 1973 ls->name = s->name; 1974 ls->sem = SSEM_PROGBITS; 1975 ls->file_only = 1u; 1976 1977 /* Copy this contribution's bytes into its own registry buffer. */ 1978 buf = (u8*)h->alloc(h, size, 1); 1979 if (!buf) compiler_panic(img->c, SRCLOC_NONE, "link: oom on debug bytes"); 1980 buf_read(&s->bytes, 0u, buf, (size_t)size); 1981 img->dbg_bytes[slot] = buf; 1982 img->dbg_size[slot] = size; 1983 img->dbg_count++; 1984 1985 /* Map the input's section id to this LinkSection so the SK_SECTION 1986 * debug symbol resolves (assign_symbol_vaddrs) and its relocations 1987 * route here (emit_relocations). */ 1988 map_placed_unit(m, j, OBJ_ATOM_NONE, lsid); 1989 } 1990 } 1991 1992 h->free(h, acc, sizeof(*acc) * ndbg); 1993 } 1994 1995 u8* link_fileonly_bytes(LinkImage* img, LinkSectionId id) { 1996 if (!img || id == LINK_SEC_NONE || id < img->dbg_first_lsid) return NULL; 1997 { 1998 u32 idx = (u32)(id - img->dbg_first_lsid); 1999 if (idx >= img->dbg_count) return NULL; 2000 return img->dbg_bytes[idx]; 2001 } 2002 } 2003 2004 /* ---- linker flags, policy, and strict validation (kernel-C work) ---- 2005 * 2006 * These run inside link_resolve after layout (so alias targets / section 2007 * vaddrs are known) and after symbol resolution (so dynamic-artifact and 2008 * cross-input checks see every input). They are deliberately self-contained 2009 * and only consult the borrowed option arrays plumbed onto the Linker. */ 2010 2011 /* Emit a non-fatal linker warning. With --fatal-warnings the warning is 2012 * promoted to a hard error (compiler_panic, which unwinds the link). */ 2013 static void link_warn(Linker* l, const char* fmt, ...) { 2014 va_list ap; 2015 if (l->fatal_warnings) { 2016 va_start(ap, fmt); 2017 compiler_panicv(l->c, SRCLOC_NONE, fmt, ap); 2018 va_end(ap); /* unreachable; compiler_panicv is _Noreturn */ 2019 } 2020 if (l->c && l->c->ctx && l->c->ctx->diag) { 2021 va_start(ap, fmt); 2022 diag_emitv(l->c->ctx->diag, DIAG_WARN, SRCLOC_NONE, fmt, ap); 2023 va_end(ap); 2024 } 2025 } 2026 2027 /* --defsym: define each requested symbol. Two forms: 2028 * NAME=0x1234 — an absolute symbol carrying the literal value verbatim. 2029 * NAME=othersym — an alias that resolves to othersym's address (+optional 2030 * bias). The alias copies the target's kind/section/value so 2031 * it rebases identically at emit (matching GNU ld, where the 2032 * alias takes the target's final address). Run after layout 2033 * and undef resolution so the target has a settled vaddr. */ 2034 static void link_apply_defsyms(Linker* l, LinkImage* img) { 2035 u32 i; 2036 for (i = 0; i < l->ndefsyms; ++i) { 2037 const KitLinkDefsym* d = &l->defsyms[i]; 2038 char namebuf[256]; 2039 size_t nlen; 2040 Sym sym; 2041 LinkSymId existing; 2042 LinkSymbol rec; 2043 if (!d->name.s || d->name.len == 0) continue; 2044 nlen = 2045 d->name.len < sizeof(namebuf) - 1u ? d->name.len : sizeof(namebuf) - 1u; 2046 memcpy(namebuf, d->name.s, nlen); 2047 namebuf[nlen] = '\0'; 2048 memset(&rec, 0, sizeof(rec)); 2049 sym = pool_intern_slice(l->c->global, (Slice){.s = namebuf, .len = (u32)nlen}); 2050 rec.name = sym; 2051 rec.bind = SB_GLOBAL; 2052 rec.defined = 1; 2053 if (d->alias.s && d->alias.len) { 2054 Sym tgt = pool_intern_slice(l->c->global, 2055 (Slice){.s = d->alias.s, .len = d->alias.len}); 2056 LinkSymId tid = symhash_get(&img->globals, tgt); 2057 const LinkSymbol* t; 2058 if (tid == LINK_SYM_NONE) { 2059 compiler_panic(l->c, SRCLOC_NONE, 2060 "link: --defsym '%s': undefined alias target '%.*s'", 2061 namebuf, (int)d->alias.len, d->alias.s); 2062 } 2063 t = LinkSyms_at(&img->syms, tid - 1); 2064 /* Inherit the target's placement so the alias rebases identically. */ 2065 rec.kind = t->kind; 2066 rec.section_id = t->section_id; 2067 rec.value = t->value; 2068 rec.vaddr = t->vaddr + d->value; 2069 rec.imported = t->imported; 2070 rec.dso_input_id = t->dso_input_id; 2071 } else { 2072 rec.kind = SK_ABS; 2073 rec.vaddr = d->value; 2074 rec.value = d->value; 2075 } 2076 existing = symhash_get(&img->globals, sym); 2077 if (existing != LINK_SYM_NONE) { 2078 rec.id = existing; 2079 *LinkSyms_at(&img->syms, existing - 1) = rec; 2080 } else { 2081 LinkSymId fresh = link_append_symbol(img, &rec); 2082 symhash_insert(&img->globals, sym, fresh, &existing); 2083 } 2084 } 2085 } 2086 2087 /* --section-start / -Tdata / -Tbss: force a named output section's *final* 2088 * runtime address to exactly the requested value (GNU-ld semantics). The actual 2089 * placement is deferred to the format emitter (ELF: link_apply_section_starts 2090 * in src/obj/elf/link.c, applied AFTER shift_image_addresses so the headers 2091 * load-page and the runtime image base both fall out of the delta) — at layout 2092 * time we only validate, since the image-relative vaddr here is not yet in the 2093 * final coordinate system. Ignored under a script (which pins addresses 2094 * itself). This pass emits the diagnostics (it has Linker / link_warn); the 2095 * matched section's segment is shifted by the emitter to land it exactly. */ 2096 static void link_apply_section_starts(Linker* l, LinkImage* img) { 2097 u32 i, j; 2098 if (l->script) { 2099 if (l->nsection_starts) 2100 link_warn(l, 2101 "link: --section-start/-Tdata/-Tbss ignored under a linker " 2102 "script"); 2103 return; 2104 } 2105 for (i = 0; i < l->nsection_starts; ++i) { 2106 const KitLinkSectionStart* ss = &l->section_starts[i]; 2107 int matched = 0; 2108 if (!ss->name.s || ss->name.len == 0) continue; 2109 for (j = 0; j < img->nsections; ++j) { 2110 LinkSection* sec = &img->sections[j]; 2111 Slice nm = sec->name ? pool_slice(l->c->global, sec->name) : SLICE_NULL; 2112 if (!nm.s || nm.len != ss->name.len || 2113 memcmp(nm.s, ss->name.s, nm.len) != 0) 2114 continue; 2115 matched = 1; 2116 } 2117 if (!matched) 2118 link_warn(l, "link: --section-start: no output section named '%.*s'", 2119 (int)ss->name.len, ss->name.s); 2120 } 2121 } 2122 2123 /* Strict freestanding validation: reject dynamic-link artifacts on a 2124 * freestanding/static-non-PIE link. Runs after symbol resolution so every 2125 * input (and any DT_NEEDED-style import) is visible. The DSO-input and 2126 * dynamic-section checks generalize the existing relocatable-only DSO guard 2127 * to the freestanding executable case. --allow-undefined remains the escape 2128 * hatch for undefined references, but it does not relax these structural 2129 * rejections (a freestanding image has no dynamic loader to honor them). */ 2130 static int link_section_name_is_dynamic(Slice nm) { 2131 /* The dynamic-link sections a freestanding static image must not carry. */ 2132 static const char* const dyn[] = {".dynamic", ".dynsym", ".dynstr", 2133 ".rela.plt", ".rel.plt", ".plt", 2134 ".got.plt", ".rela.dyn", ".rel.dyn", 2135 ".interp"}; 2136 u32 i; 2137 if (!nm.s || nm.len == 0) return 0; 2138 for (i = 0; i < (u32)(sizeof(dyn) / sizeof(dyn[0])); ++i) { 2139 size_t dl = strlen(dyn[i]); 2140 if (nm.len == dl && memcmp(nm.s, dyn[i], dl) == 0) return 1; 2141 } 2142 return 0; 2143 } 2144 2145 static void link_validate_freestanding(Linker* l) { 2146 u32 ii; 2147 if (!l->freestanding_strict) return; 2148 2149 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 2150 LinkInput* in = LinkInputs_at(&l->inputs, ii); 2151 ObjBuilder* ob = in->obj; 2152 Slice inname = in->name ? pool_slice(l->c->global, in->name) : SLICE_NULL; 2153 const char* label = inname.s ? inname.s : "<input>"; 2154 u32 j; 2155 2156 /* (c) DSO inputs: a shared object has no place in a freestanding image. */ 2157 if (in->kind == LINK_INPUT_DSO_BYTES) { 2158 compiler_panic(l->c, SRCLOC_NONE, 2159 "link: freestanding link rejects shared-object input " 2160 "'%s' (no dynamic loader)", 2161 label); 2162 } 2163 if (!ob) continue; 2164 2165 /* (a)+(b) dynamic-interpreter / dynamic-section / PLT-GOT-import inputs. 2166 * A freestanding static image must not pull in .interp (PT_INTERP) or any 2167 * .dynamic/.dynsym/.plt/.got.plt artifact. */ 2168 for (j = 1; j < obj_section_count(ob); ++j) { 2169 const Section* s = obj_section_get(ob, j); 2170 Slice nm; 2171 if (!s || s->removed) continue; 2172 nm = s->name ? pool_slice(l->c->global, s->name) : SLICE_NULL; 2173 if (link_section_name_is_dynamic(nm)) { 2174 compiler_panic(l->c, SRCLOC_NONE, 2175 "link: freestanding link rejects dynamic section '%.*s' " 2176 "from input '%s'", 2177 (int)nm.len, nm.s, label); 2178 } 2179 } 2180 } 2181 } 2182 2183 /* ---- public orchestration ---- */ 2184 2185 LinkImage* link_resolve(Linker* l) { 2186 LinkImage* img; 2187 Heap* h; 2188 2189 metrics_scope_begin(l->c, "link.resolve.total"); 2190 /* Inject any format-owned synthetic input before symbol resolution. 2191 * Only the COFF format registers a hook (link_synth_coff_ctor_dtor_list); 2192 * the dispatcher is a no-op for every other format. */ 2193 obj_format_synth_inputs(l->c, l); 2194 metrics_scope_begin(l->c, "link.ingest_archives"); 2195 link_ingest_archives(l); 2196 metrics_scope_end(l->c, "link.ingest_archives"); 2197 2198 img = link_image_alloc(l->c); 2199 h = img->heap; 2200 img->linker = l; 2201 img->text_base_set = l->text_base_set; 2202 img->text_base = l->text_base; 2203 img->shared = l->emit_shared; 2204 img->elf_e_flags = l->elf_e_flags; 2205 img->have_elf_e_flags = l->have_elf_e_flags; 2206 2207 img->ninput_maps = LinkInputs_count(&l->inputs); 2208 metrics_count(l->c, "link.inputs", img->ninput_maps); 2209 img->input_maps = 2210 LinkInputs_count(&l->inputs) 2211 ? (InputMap*)h->alloc( 2212 h, sizeof(*img->input_maps) * LinkInputs_count(&l->inputs), 2213 _Alignof(InputMap)) 2214 : NULL; 2215 if (LinkInputs_count(&l->inputs) && !img->input_maps) 2216 compiler_panic(l->c, SRCLOC_NONE, "link: oom on input maps"); 2217 if (LinkInputs_count(&l->inputs)) 2218 memset(img->input_maps, 0, 2219 sizeof(*img->input_maps) * LinkInputs_count(&l->inputs)); 2220 2221 metrics_scope_begin(l->c, "link.resolve_symbols"); 2222 link_resolve_symbols(l, img); 2223 metrics_scope_end(l->c, "link.resolve_symbols"); 2224 /* Strict freestanding policy: reject dynamic-link artifacts and cross-input 2225 * mismatches before laying anything out. DSO inputs / dynamic sections have 2226 * no home in a freestanding static image (no dynamic loader). */ 2227 link_validate_freestanding(l); 2228 { 2229 GcLive g = {0}; 2230 metrics_scope_begin(l->c, "link.gc"); 2231 link_gc_live_alloc(&g, l, h); 2232 link_gc_compute(l, img, &g); 2233 metrics_scope_end(l->c, "link.gc"); 2234 metrics_scope_begin(l->c, "link.layout_sections"); 2235 link_layout_sections(l, img, &g); 2236 link_layout_commons(l, img); 2237 metrics_count(l->c, "link.sections", img->nsections); 2238 metrics_count(l->c, "link.segments", img->nsegments); 2239 metrics_scope_end(l->c, "link.layout_sections"); 2240 metrics_scope_begin(l->c, "link.emit_segment_bytes"); 2241 if (!l->jit_mode) link_emit_segment_bytes(l, img); 2242 metrics_scope_end(l->c, "link.emit_segment_bytes"); 2243 /* Carry .debug_* through as file-only sections. ELF places them in 2244 * non-alloc sections; Mach-O in a __DWARF segment. The JIT path 2245 * serves debug via kit_jit_view instead, and COFF emit doesn't yet 2246 * handle file-only sections. */ 2247 metrics_scope_begin(l->c, "link.layout_debug"); 2248 if (!l->strip_debug && !l->jit_mode && 2249 obj_format_carries_file_only_debug(l->c)) 2250 link_layout_debug(l, img); 2251 metrics_scope_end(l->c, "link.layout_debug"); 2252 /* --section-start / -Tdata / -Tbss: pin chosen output sections to fixed 2253 * addresses before symbol vaddrs are derived from them. */ 2254 link_apply_section_starts(l, img); 2255 metrics_scope_begin(l->c, "link.assign_vaddrs"); 2256 link_assign_symbol_vaddrs(l, img); 2257 metrics_scope_end(l->c, "link.assign_vaddrs"); 2258 metrics_scope_begin(l->c, "link.emit_boundaries"); 2259 link_emit_array_boundaries(l, img); 2260 link_emit_tls_boundaries(l, img); 2261 link_emit_encoding_section_boundaries(l, img); 2262 link_emit_boundary_sym(l, img, "__dso_handle", 0); 2263 /* `_DYNAMIC` marks the dynamic section; in a static image it must be 2264 * absolute 0 so libc's static-vs-dynamic probe (FreeBSD's __libc_start1 2265 * gates _init_tls() on `&_DYNAMIC != NULL`) takes the static path. Only 2266 * define it for dynamic output, where layout_dyn places it at the real 2267 * .dynamic vaddr; for static, the weak undef from crt/libc already 2268 * resolved to SK_ABS 0, and defining it here as a rebased SK_OBJ symbol 2269 * would wrongly make `&_DYNAMIC` non-zero. */ 2270 if (l->emit_pie || l->emit_shared) 2271 link_emit_boundary_sym(l, img, "_DYNAMIC", 0); 2272 link_emit_boundary_sym(l, img, "_GLOBAL_OFFSET_TABLE_", 0); 2273 /* PE/COFF: mingw CRT references `__ImageBase` for ASLR-relative 2274 * addressing and base-relocation bookkeeping. The PE emitter 2275 * writes LINK_PE_IMAGE_BASE into the optional header; expose the 2276 * same value as a linker-defined symbol so input objects resolve. 2277 * Driven by the format claiming `__ImageBase` (the same hook that 2278 * fixes its SymKind) rather than a target.obj switch. */ 2279 { 2280 int fmt_kind; 2281 if (obj_format_boundary_sym_kind(l->c, SLICE_LIT("__ImageBase"), 2282 &fmt_kind)) { 2283 link_emit_boundary_sym(l, img, "__ImageBase", LINK_PE_IMAGE_BASE); 2284 if (img->tls_memsz) link_emit_boundary_sym(l, img, "_tls_used", 0); 2285 } 2286 } 2287 { 2288 const LinkArchDesc* arch = link_arch_desc_for(l->c); 2289 u32 si; 2290 u64 gp_vaddr = 0; 2291 if (arch && arch->global_pointer_symbol) { 2292 for (si = 0; si < img->nsegments; ++si) { 2293 if (img->segments[si].flags & SF_WRITE) { 2294 gp_vaddr = img->segments[si].vaddr + arch->global_pointer_rw_offset; 2295 break; 2296 } 2297 } 2298 link_emit_boundary_sym(l, img, arch->global_pointer_symbol, gp_vaddr); 2299 } 2300 } 2301 metrics_scope_end(l->c, "link.emit_boundaries"); 2302 metrics_scope_begin(l->c, "link.resolve_undefs"); 2303 link_resolve_undefs(l, img); 2304 metrics_scope_end(l->c, "link.resolve_undefs"); 2305 /* --defsym: define absolute / alias linker symbols now that layout and 2306 * undef resolution are done (an alias target's vaddr is known). Runs 2307 * before relocations so a defsym can satisfy a reference, and before 2308 * entry resolution so a defsym can name the entry point. */ 2309 link_apply_defsyms(l, img); 2310 metrics_scope_begin(l->c, "link.gc_drop_dead"); 2311 link_gc_drop_dead_globals(l, img, &g); 2312 metrics_scope_end(l->c, "link.gc_drop_dead"); 2313 metrics_scope_begin(l->c, "link.layout_iplt"); 2314 link_layout_iplt(l, img); 2315 if (img->niplt) link_emit_array_boundaries(l, img); 2316 metrics_scope_end(l->c, "link.layout_iplt"); 2317 { 2318 LinkSymId* got_map = NULL; 2319 LinkSymId* stub_map = NULL; 2320 u32 map_size = LinkSyms_count(&img->syms) + 1u; 2321 metrics_scope_begin(l->c, "link.layout_jit_stubs"); 2322 link_layout_jit_stubs(l, img, map_size, &stub_map); 2323 metrics_scope_end(l->c, "link.layout_jit_stubs"); 2324 metrics_scope_begin(l->c, "link.layout_got"); 2325 /* Skip the link-time static GOT only for formats that build their own 2326 * static GOT / non-lazy pointer table (Mach-O) in a static image. */ 2327 if (!obj_format_builds_own_static_got(l->c) || !l->emit_static_exe) 2328 link_layout_got(l, img, map_size, &got_map); 2329 metrics_scope_end(l->c, "link.layout_got"); 2330 metrics_scope_begin(l->c, "link.emit_relocations"); 2331 link_emit_relocations(l, img, got_map, stub_map); 2332 metrics_count(l->c, "link.syms", LinkSyms_count(&img->syms)); 2333 metrics_count(l->c, "link.relocs", LinkRelocs_count(&img->relocs)); 2334 metrics_scope_end(l->c, "link.emit_relocations"); 2335 if (got_map) h->free(h, got_map, sizeof(*got_map) * map_size); 2336 if (stub_map) h->free(h, stub_map, sizeof(*stub_map) * map_size); 2337 } 2338 { 2339 const ObjFormatImpl* fmt = obj_format_lookup(l->c->target.obj); 2340 metrics_scope_begin(l->c, "link.layout_dyn"); 2341 if (fmt && fmt->layout_dyn) fmt->layout_dyn(l, img); 2342 metrics_scope_end(l->c, "link.layout_dyn"); 2343 } 2344 metrics_scope_begin(l->c, "link.resolve_entry"); 2345 link_resolve_entry(l, img); 2346 metrics_scope_end(l->c, "link.resolve_entry"); 2347 link_gc_live_free(&g, h); 2348 } 2349 2350 metrics_scope_begin(l->c, "link.capture_debug"); 2351 link_capture_debug_inputs(l, img); 2352 metrics_scope_end(l->c, "link.capture_debug"); 2353 2354 metrics_scope_end(l->c, "link.resolve.total"); 2355 return img; 2356 }