kit

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

commit a135713defeb03f4aca798cc4257b0f66efdae97
parent 79d6c9e94abf68d5d27abbd8dff18fcf582da12b
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed,  3 Jun 2026 10:45:12 -0700

link: single-source synthetic-region builder + ObjSym classification

Refactor 1 — synthetic regions: add link_synth_region (page-aligned
segment + single covering section + zero-filled byte buffer) and
link_emit_internal_abs64 (8-byte ABS64 slot fill), both over the existing
link_iplt_alloc_segments/sections helpers. Rewrite link_layout_jit_stubs,
link_layout_got, and link_layout_iplt to call them; the per-stub
variable-width apply loop shared by jit_stubs and iplt becomes
emit_stub_apply_relocs. The commons no-RW-segment path in link_layout.c
adopts only the segment-array growth helper (it is BSS: no byte buffer,
sizes grow with its section).

Refactor 2 — ObjSym classification: promote bind_strength / sym_is_def /
spurious_undef (3 verbatim copies across link_resolve.c,
link_relocatable.c, link_jit.c) to static inlines in link_internal.h
(link_bind_strength takes u16 to match ObjSym.bind); route every lane
through them. Drop the file-static on section_size_for_link, declare it
in link_internal.h, delete the jit copy.

Net -304 LOC. make lib && make bin clean; test-link test-link-x64
test-elf test-rv64-tls-link test-smoke-x64 all green.

(cherry picked from commit 65f0dbd775c8f99319e8918d15b8bb52fc71cc09)

Diffstat:
Msrc/link/link_internal.h | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/link/link_jit.c | 52+++++++++++-----------------------------------------
Msrc/link/link_layout.c | 47+++++++++++++----------------------------------
Msrc/link/link_reloc_layout.c | 616++++++++++++++++++++++---------------------------------------------------------
Msrc/link/link_relocatable.c | 41++++++++---------------------------------
Msrc/link/link_resolve.c | 60+++++++++++++++++++++---------------------------------------
6 files changed, 290 insertions(+), 594 deletions(-)

diff --git a/src/link/link_internal.h b/src/link/link_internal.h @@ -97,6 +97,53 @@ static inline LinkSectionId link_input_symbol_section(const InputMap* m, return m->section[s->section_id]; } +/* ---- ObjSym classification (single source of truth) --------------------- + * + * The linker's three lanes (AOT exe/shared in link_resolve.c, `-r` + * relocatable in link_relocatable.c, in-process JIT in link_jit.c) all + * classify input symbols the same way. These predicates are the one + * authority; every lane routes through them. */ + +/* Defined-symbol replacement policy: a stronger binding wins. Takes u16 + * to match ObjSym.bind. */ +static inline int link_bind_strength(u16 bind) { + switch (bind) { + case SB_GLOBAL: + return 3; + case SB_WEAK: + return 2; + case SB_LOCAL: + return 1; + default: + return 0; + } +} + +/* A symbol that contributes a definition: not SK_UNDEF, and either an + * absolute/common/file pseudo-def or anchored to a real section. */ +static inline int link_sym_is_def(const ObjSym* s) { + return s && s->kind != SK_UNDEF && + (s->kind == SK_ABS || s->kind == SK_COMMON || s->kind == SK_FILE || + s->section_id != OBJ_SEC_NONE); +} + +/* An unreferenced global/weak extern declaration: a header artifact, not + * a real demand. The frontend synthesizes one per visible prototype, so + * pruning these keeps unused archive members from being pulled in. */ +static inline int link_sym_is_spurious_undef(const ObjSym* s) { + return s && s->section_id == OBJ_SEC_NONE && s->kind != SK_ABS && + s->kind != SK_COMMON && !s->referenced && + (s->bind == SB_GLOBAL || s->bind == SB_WEAK); +} + +/* In-section byte count for an input section: BSS/NOBITS report their + * zero-fill size, everything else its emitted byte total + * (link_layout.c / link_jit.c). */ +static inline u32 link_section_size_for_link(const Section* s) { + return (s->sem == SSEM_NOBITS || s->kind == SEC_BSS) ? s->bss_size + : s->bytes.total; +} + /* Open-addressed name -> LinkSymId hash for global / weak definitions * and lookups (kit_jit_lookup, entry-symbol resolution). Locals never * land in this table. Sym 0 is the empty-slot sentinel (it's also the @@ -259,6 +306,27 @@ int link_gc_atom_live_get(const GcLive* g, u32 ii, ObjAtomId j); u32 link_iplt_alloc_segments(LinkImage* img, u32 nseg); u32 link_iplt_alloc_sections(LinkImage* img, u32 nsec); +/* Append one fixed-size synthetic region to the image: a fresh + * page-aligned PT_LOAD segment plus its single covering section, sized + * `size` with permissions `perms` (SF_* flags) and section semantics + * `sem`. The region is placed at page-align(max segment end) so it never + * overlaps existing content. A zero-filled byte buffer of `size` bytes is + * allocated for the segment; *out_vaddr receives the image-relative base + * and *out_bytes the buffer. `sec_align` sets the section's alignment + * (the segment always aligns to the page). Returns the new section's id. + * Backs the GOT / JIT-call-stub / IPLT layout passes + * (link_reloc_layout.c). */ +LinkSectionId link_synth_region(LinkImage* img, Linker* l, Sym name, u16 perms, + u16 sem, u64 size, u32 sec_align, u64* out_vaddr, + u8** out_bytes); + +/* Append one fixed 8-byte ABS64 reloc-apply record targeting `target` at + * `offset` within synthetic section `lsid` (write_vaddr == its file + * offset, as every synthetic region is identity-mapped at layout time). + * Backs the GOT / IPLT / JIT-slot fills (link_reloc_layout.c). */ +void link_emit_internal_abs64(LinkImage* img, LinkSectionId lsid, u32 offset, + u64 write_vaddr, LinkSymId target); + /* ---- Public entries (link_resolve.c) -------------------------------------- */ void link_ingest_archives(struct Linker*); diff --git a/src/link/link_jit.c b/src/link/link_jit.c @@ -809,31 +809,6 @@ typedef struct JitAppendSec { SEGVEC_DEFINE(JitAppendSecs, JitAppendSec, 4); -static int jit_bind_strength(u8 bind) { - switch (bind) { - case SB_GLOBAL: - return 3; - case SB_WEAK: - return 2; - case SB_LOCAL: - return 1; - default: - return 0; - } -} - -static int jit_obj_sym_is_def(const ObjSym* s) { - return s && s->kind != SK_UNDEF && - (s->kind == SK_ABS || s->kind == SK_COMMON || s->kind == SK_FILE || - s->section_id != OBJ_SEC_NONE); -} - -static int jit_obj_sym_is_spurious_undef(const ObjSym* s) { - return s && s->section_id == OBJ_SEC_NONE && s->kind != SK_ABS && - s->kind != SK_COMMON && !s->referenced && - (s->bind == SB_GLOBAL || s->bind == SB_WEAK); -} - static u8 jit_reloc_width_local(RelocKind k) { switch (k) { case R_ABS64: @@ -857,11 +832,6 @@ static u8 jit_reloc_width_local(RelocKind k) { } } -static u32 jit_section_size_for_link(const Section* s) { - return (s->sem == SSEM_NOBITS || s->kind == SEC_BSS) ? s->bss_size - : s->bytes.total; -} - static InputMap jit_input_map_alloc(KitJit* jit, ObjBuilder* ob) { InputMap m; ObjSymIter* it; @@ -977,15 +947,15 @@ static void jit_append_obj_inner(KitJit* jit, ObjBuilder* ob) { it = obj_symiter_new(ob); while (obj_symiter_next(it, &e)) { const ObjSym* s = e.sym; - if (jit_obj_sym_is_spurious_undef(s)) continue; - if (jit_obj_sym_is_def(s) && s->name != 0 && + if (link_sym_is_spurious_undef(s)) continue; + if (link_sym_is_def(s) && s->name != 0 && (s->bind == SB_GLOBAL || s->bind == SB_WEAK)) { LinkSymId existing = symhash_get(&img->globals, s->name); if (existing != LINK_SYM_NONE) { LinkSymbol* prev = LinkSyms_at(&img->syms, existing - 1); if (prev && prev->defined && - jit_bind_strength((u8)s->bind) == jit_bind_strength(SB_GLOBAL) && - jit_bind_strength(prev->bind) == jit_bind_strength(SB_GLOBAL)) { + link_bind_strength((u8)s->bind) == link_bind_strength(SB_GLOBAL) && + link_bind_strength(prev->bind) == link_bind_strength(SB_GLOBAL)) { Slice nm_s = pool_slice(jit->c->global, s->name); const char* nm = nm_s.s; size_t namelen = nm_s.len; @@ -996,7 +966,7 @@ static void jit_append_obj_inner(KitJit* jit, ObjBuilder* ob) { (int)namelen, nm); } } - } else if (!jit_obj_sym_is_def(s) && s->name != 0) { + } else if (!link_sym_is_def(s) && s->name != 0) { LinkSymId hit = symhash_get(&img->globals, s->name); int ok = 0; if (hit != LINK_SYM_NONE) { @@ -1008,7 +978,7 @@ static void jit_append_obj_inner(KitJit* jit, ObjBuilder* ob) { ObjSymEntry e2; while (obj_symiter_next(it2, &e2)) { const ObjSym* d = e2.sym; - if (d && d->name == s->name && jit_obj_sym_is_def(d) && + if (d && d->name == s->name && link_sym_is_def(d) && (d->bind == SB_GLOBAL || d->bind == SB_WEAK)) { ok = 1; break; @@ -1066,7 +1036,7 @@ static void jit_append_obj_inner(KitJit* jit, ObjBuilder* ob) { size = atom->size; } else { obj_offset = 0u; - size = jit_section_size_for_link(s); + size = link_section_size_for_link(s); } if (size == 0) continue; b = link_bucket_for(s->flags); @@ -1107,16 +1077,16 @@ static void jit_append_obj_inner(KitJit* jit, ObjBuilder* ob) { while (obj_symiter_next(it, &e)) { const ObjSym* s = e.sym; int is_def; - if (e.id >= m.nsym || jit_obj_sym_is_spurious_undef(s)) continue; - is_def = jit_obj_sym_is_def(s); + if (e.id >= m.nsym || link_sym_is_spurious_undef(s)) continue; + is_def = link_sym_is_def(s); if (is_def && (s->bind == SB_GLOBAL || s->bind == SB_WEAK) && s->name != 0) { LinkSymId existing = symhash_get(&img->globals, s->name); if (existing != LINK_SYM_NONE) { LinkSymbol* prev = LinkSyms_at(&img->syms, existing - 1); if (prev && prev->defined && - jit_bind_strength((u8)s->bind) == jit_bind_strength(SB_GLOBAL) && - jit_bind_strength(prev->bind) == jit_bind_strength(SB_GLOBAL)) { + link_bind_strength((u8)s->bind) == link_bind_strength(SB_GLOBAL) && + link_bind_strength(prev->bind) == link_bind_strength(SB_GLOBAL)) { Slice nm_s = pool_slice(jit->c->global, s->name); const char* nm = nm_s.s; size_t namelen = nm_s.len; diff --git a/src/link/link_layout.c b/src/link/link_layout.c @@ -171,11 +171,6 @@ static u32 place_group_hash_cap(u32 n) { return cap; } -static u32 section_size_for_link(const Section* s) { - return (s->sem == SSEM_NOBITS || s->kind == SEC_BSS) ? s->bss_size - : s->bytes.total; -} - static int live_section_units(const GcLive* g, const InputMap* m, u32 ii, ObjBuilder* ob, ObjSecId sid) { u32 n = 0, first, count, i; @@ -280,7 +275,7 @@ void link_layout_sections(Linker* l, LinkImage* img, const GcLive* g) { entries[e].obj_sec_id = j; entries[e].obj_atom_id = has_atoms ? aid : OBJ_ATOM_NONE; entries[e].obj_offset = has_atoms ? a->offset : 0u; - entries[e].size = has_atoms ? a->size : section_size_for_link(s); + entries[e].size = has_atoms ? a->size : link_section_size_for_link(s); entries[e].name = s->name; entries[e].bucket = link_bucket_for(s->flags); if (l->emit_pie && entries[e].bucket == SEG_R && @@ -831,7 +826,7 @@ static void link_layout_sections_scripted(Linker* l, LinkImage* img, continue; } else { obj_offset = 0u; - size = section_size_for_link(s); + size = link_section_size_for_link(s); } if (align > align_max) align_max = align; dot = ALIGN_UP(dot, (u64)align); @@ -946,44 +941,28 @@ void link_layout_commons(Linker* l, LinkImage* img) { } if (!rw_seg) { - u32 nseg = img->nsegments + 1u; - LinkSegment* segs; - u8** sbufs; - size_t* scaps; + /* No writable PT_LOAD yet — synthesize a zero-size BSS segment for the + * COMMON section. This is a NOBITS region (no byte buffer, file/mem + * size grow with the section below), so it adopts only the array- + * growth helper, not the fixed-size region builder. */ + u32 seg_idx = link_iplt_alloc_segments(img, 1u); u64 vaddr = 0; for (i = 0; i < img->nsegments; ++i) { u64 end = img->segments[i].vaddr + img->segments[i].mem_size; if (end > vaddr) vaddr = end; } vaddr = ALIGN_UP(vaddr, (u64)(link_layout_page_size(l))); - segs = (LinkSegment*)img->heap->realloc( - img->heap, img->segments, sizeof(*img->segments) * img->nsegments, - sizeof(*img->segments) * nseg, _Alignof(LinkSegment)); - sbufs = (u8**)img->heap->realloc( - img->heap, img->segment_bytes, - sizeof(*img->segment_bytes) * img->nsegments, - sizeof(*img->segment_bytes) * nseg, _Alignof(u8*)); - scaps = (size_t*)img->heap->realloc( - img->heap, img->segment_bytes_cap, - sizeof(*img->segment_bytes_cap) * img->nsegments, - sizeof(*img->segment_bytes_cap) * nseg, _Alignof(size_t)); - if (!segs || !sbufs || !scaps) - compiler_panic(img->c, no_loc(), - "link: oom on new RW segment for COMMON"); - img->segments = segs; - img->segment_bytes = sbufs; - img->segment_bytes_cap = scaps; - rw_seg = &img->segments[img->nsegments]; + rw_seg = &img->segments[seg_idx]; memset(rw_seg, 0, sizeof(*rw_seg)); - rw_seg->id = (LinkSegmentId)(img->nsegments + 1u); + rw_seg->id = (LinkSegmentId)(seg_idx + 1u); rw_seg->flags = SF_ALLOC | SF_WRITE; rw_seg->vaddr = vaddr; rw_seg->file_offset = vaddr; rw_seg->file_size = 0; rw_seg->mem_size = 0; rw_seg->align = (u32)link_layout_page_size(l); - img->segment_bytes[img->nsegments] = NULL; - img->segment_bytes_cap[img->nsegments] = 0; + img->segment_bytes[seg_idx] = NULL; + img->segment_bytes_cap[seg_idx] = 0; img->nsegments++; } @@ -1101,7 +1080,7 @@ void link_layout_debug(Linker* l, LinkImage* img) { for (j = 1; j < obj_section_count(ob); ++j) { const Section* s = obj_section_get(ob, j); if (link_section_kept_fileonly(s) && !m->comdat_discarded[j] && - section_size_for_link(s) > 0) + link_section_size_for_link(s) > 0) ++ndbg; } } @@ -1147,7 +1126,7 @@ void link_layout_debug(Linker* l, LinkImage* img) { LinkSectionId lsid; u8* buf; if (!link_section_kept_fileonly(s) || m->comdat_discarded[j]) continue; - size = section_size_for_link(s); + size = link_section_size_for_link(s); if (size == 0) continue; /* Per-name cumulative base. */ diff --git a/src/link/link_reloc_layout.c b/src/link/link_reloc_layout.c @@ -424,6 +424,119 @@ u32 link_iplt_alloc_sections(LinkImage* img, u32 nsec) { return base; } +/* ---- synthetic region builder ---- + * + * The GOT, JIT-call-stub, and IPLT passes all need the same shape: a + * fresh page-aligned segment carrying a single fixed-size section with a + * zero-filled byte buffer. This is the one place that grows the segment / + * section arrays for those regions, fills both records, and allocates the + * buffer; callers vary only by name / perms / sem / size / section align. + * Sequential calls chain naturally — each placement scans the current + * max segment end, so a region appended after another lands just past it + * (page-aligned), matching the hand-rolled ALIGN_UP(prev_end, page). */ +LinkSectionId link_synth_region(LinkImage* img, Linker* l, Sym name, u16 perms, + u16 sem, u64 size, u32 sec_align, u64* out_vaddr, + u8** out_bytes) { + Heap* h = img->heap; + u64 page = link_layout_page_size(l); + u64 base_vaddr = 0; + u32 seg_idx, sec_idx, i; + LinkSegment* seg; + LinkSection* sec; + u8* bytes; + + for (i = 0; i < img->nsegments; ++i) { + u64 end = img->segments[i].vaddr + img->segments[i].mem_size; + if (end > base_vaddr) base_vaddr = end; + } + base_vaddr = ALIGN_UP(base_vaddr, (u64)page); + + seg_idx = link_iplt_alloc_segments(img, 1u); + seg = &img->segments[seg_idx]; + memset(seg, 0, sizeof(*seg)); + seg->id = (LinkSegmentId)(seg_idx + 1u); + seg->flags = perms; + seg->file_offset = base_vaddr; + seg->vaddr = base_vaddr; + seg->file_size = size; + seg->mem_size = size; + seg->align = (u32)page; + seg->nsections = 1; + bytes = (u8*)h->alloc(h, (size_t)size, 16); + img->segment_bytes[seg_idx] = bytes; + img->segment_bytes_cap[seg_idx] = (size_t)size; + if (!bytes) compiler_panic(img->c, no_loc(), "link: oom on synth region bytes"); + memset(bytes, 0, (size_t)size); + img->nsegments += 1u; + + sec_idx = link_iplt_alloc_sections(img, 1u); + sec = &img->sections[sec_idx]; + memset(sec, 0, sizeof(*sec)); + sec->id = (LinkSectionId)(sec_idx + 1u); + sec->input_id = LINK_INPUT_NONE; + sec->obj_section_id = OBJ_SEC_NONE; + sec->segment_id = seg->id; + sec->input_offset = 0; + sec->file_offset = base_vaddr; + sec->vaddr = base_vaddr; + sec->size = size; + sec->flags = perms; + sec->align = sec_align; + sec->name = name; + sec->sem = sem; + img->nsections += 1u; + + if (out_vaddr) *out_vaddr = base_vaddr; + if (out_bytes) *out_bytes = bytes; + return sec->id; +} + +/* One fixed 8-byte ABS64 reloc-apply record for a synthetic slot. */ +void link_emit_internal_abs64(LinkImage* img, LinkSectionId lsid, u32 offset, + u64 write_vaddr, LinkSymId target) { + LinkRelocApply rrec; + memset(&rrec, 0, sizeof(rrec)); + rrec.input_id = LINK_INPUT_NONE; + rrec.section_id = OBJ_SEC_NONE; + rrec.link_section_id = lsid; + rrec.offset = offset; + rrec.width = 8; + rrec.write_vaddr = write_vaddr; + rrec.write_file_offset = write_vaddr; + rrec.kind = R_ABS64; + rrec.target = target; + rrec.addend = 0; + *link_append_reloc_slot(img) = rrec; +} + +/* Record the per-stub reloc-apply slots the arch's emit_iplt_stub asks + * for: each entry's kind / width / offset_in_stub is variable, so this + * mirrors the records the JIT-call-stub and IPLT passes build verbatim. + * `stub_base_offset` is the stub's byte offset within its section, + * `stub_vaddr` its image-relative base; every record points at the same + * `slot_target` GOT slot. */ +static void emit_stub_apply_relocs(LinkImage* img, LinkSectionId stub_lsid, + u32 stub_base_offset, u64 stub_vaddr, + const LinkArchIPltReloc* relocs, + u32 nrelocs, LinkSymId slot_target) { + u32 ri; + for (ri = 0; ri < nrelocs; ++ri) { + LinkRelocApply rrec; + memset(&rrec, 0, sizeof(rrec)); + rrec.input_id = LINK_INPUT_NONE; + rrec.section_id = OBJ_SEC_NONE; + rrec.link_section_id = stub_lsid; + rrec.offset = stub_base_offset + relocs[ri].offset_in_stub; + rrec.width = relocs[ri].width; + rrec.write_vaddr = stub_vaddr + relocs[ri].offset_in_stub; + rrec.write_file_offset = rrec.write_vaddr; + rrec.kind = relocs[ri].kind; + rrec.target = slot_target; + rrec.addend = 0; + *link_append_reloc_slot(img) = rrec; + } +} + /* ---- pass: JIT call stubs ---- */ void link_layout_jit_stubs(Linker* l, LinkImage* img, u32 map_size, @@ -434,16 +547,9 @@ void link_layout_jit_stubs(Linker* l, LinkImage* img, u32 map_size, LinkSymId* targets = NULL; u32 ntarget = 0, tcap = 0; u32 ii, k, i; - u64 page; - u64 base_vaddr = 0; u64 stubs_vaddr, slots_vaddr; u64 stubs_size, slots_size; - u32 stubs_seg_idx, slots_seg_idx; - u32 seg_base, sec_base; - LinkSegment* stubs_seg; - LinkSegment* slots_seg; - LinkSection* stubs_sec; - LinkSection* slots_sec; + LinkSectionId stubs_sec_id, slots_sec_id; u8* stubs_bytes; *stub_map_out = NULL; @@ -490,89 +596,17 @@ void link_layout_jit_stubs(Linker* l, LinkImage* img, u32 map_size, } for (i = 0; i < ntarget; ++i) stub_map[targets[i]] = LINK_SYM_NONE; - page = link_layout_page_size(l); - for (i = 0; i < img->nsegments; ++i) { - u64 end = img->segments[i].vaddr + img->segments[i].mem_size; - if (end > base_vaddr) base_vaddr = end; - } - base_vaddr = ALIGN_UP(base_vaddr, (u64)page); - stubs_vaddr = base_vaddr; stubs_size = (u64)ntarget * (u64)arch->iplt_stub_size; - slots_vaddr = ALIGN_UP(stubs_vaddr + stubs_size, (u64)page); slots_size = (u64)ntarget * 8u; - seg_base = link_iplt_alloc_segments(img, 2u); - stubs_seg_idx = seg_base + 0u; - slots_seg_idx = seg_base + 1u; - - stubs_seg = &img->segments[stubs_seg_idx]; - memset(stubs_seg, 0, sizeof(*stubs_seg)); - stubs_seg->id = (LinkSegmentId)(stubs_seg_idx + 1u); - stubs_seg->flags = SF_ALLOC | SF_EXEC; - stubs_seg->file_offset = stubs_vaddr; - stubs_seg->vaddr = stubs_vaddr; - stubs_seg->file_size = stubs_size; - stubs_seg->mem_size = stubs_size; - stubs_seg->align = (u32)page; - stubs_seg->nsections = 1; - img->segment_bytes[stubs_seg_idx] = (u8*)h->alloc(h, (size_t)stubs_size, 16); - img->segment_bytes_cap[stubs_seg_idx] = (size_t)stubs_size; - if (!img->segment_bytes[stubs_seg_idx]) - compiler_panic(img->c, no_loc(), "link: oom on jit stubs bytes"); - memset(img->segment_bytes[stubs_seg_idx], 0, (size_t)stubs_size); - - slots_seg = &img->segments[slots_seg_idx]; - memset(slots_seg, 0, sizeof(*slots_seg)); - slots_seg->id = (LinkSegmentId)(slots_seg_idx + 1u); - slots_seg->flags = SF_ALLOC | SF_WRITE; - slots_seg->file_offset = slots_vaddr; - slots_seg->vaddr = slots_vaddr; - slots_seg->file_size = slots_size; - slots_seg->mem_size = slots_size; - slots_seg->align = (u32)page; - slots_seg->nsections = 1; - img->segment_bytes[slots_seg_idx] = (u8*)h->alloc(h, (size_t)slots_size, 16); - img->segment_bytes_cap[slots_seg_idx] = (size_t)slots_size; - if (!img->segment_bytes[slots_seg_idx]) - compiler_panic(img->c, no_loc(), "link: oom on jit stub slots bytes"); - memset(img->segment_bytes[slots_seg_idx], 0, (size_t)slots_size); - img->nsegments += 2u; - - sec_base = link_iplt_alloc_sections(img, 2u); - stubs_sec = &img->sections[sec_base + 0u]; - memset(stubs_sec, 0, sizeof(*stubs_sec)); - stubs_sec->id = (LinkSectionId)(sec_base + 0u + 1u); - stubs_sec->input_id = LINK_INPUT_NONE; - stubs_sec->obj_section_id = OBJ_SEC_NONE; - stubs_sec->segment_id = stubs_seg->id; - stubs_sec->input_offset = 0; - stubs_sec->file_offset = stubs_vaddr; - stubs_sec->vaddr = stubs_vaddr; - stubs_sec->size = stubs_size; - stubs_sec->flags = SF_ALLOC | SF_EXEC; - stubs_sec->align = 4; - stubs_sec->name = - pool_intern_slice(l->c->global, SLICE_LIT(".kit_jit_call_stubs")); - stubs_sec->sem = SSEM_PROGBITS; - - slots_sec = &img->sections[sec_base + 1u]; - memset(slots_sec, 0, sizeof(*slots_sec)); - slots_sec->id = (LinkSectionId)(sec_base + 1u + 1u); - slots_sec->input_id = LINK_INPUT_NONE; - slots_sec->obj_section_id = OBJ_SEC_NONE; - slots_sec->segment_id = slots_seg->id; - slots_sec->input_offset = 0; - slots_sec->file_offset = slots_vaddr; - slots_sec->vaddr = slots_vaddr; - slots_sec->size = slots_size; - slots_sec->flags = SF_ALLOC | SF_WRITE; - slots_sec->align = 8; - slots_sec->name = - pool_intern_slice(l->c->global, SLICE_LIT(".kit_jit_call_slots")); - slots_sec->sem = SSEM_PROGBITS; - img->nsections += 2u; - - stubs_bytes = img->segment_bytes[stubs_seg_idx]; + stubs_sec_id = link_synth_region( + img, l, pool_intern_slice(l->c->global, SLICE_LIT(".kit_jit_call_stubs")), + SF_ALLOC | SF_EXEC, SSEM_PROGBITS, stubs_size, 4, &stubs_vaddr, + &stubs_bytes); + slots_sec_id = link_synth_region( + img, l, pool_intern_slice(l->c->global, SLICE_LIT(".kit_jit_call_slots")), + SF_ALLOC | SF_WRITE, SSEM_PROGBITS, slots_size, 8, &slots_vaddr, NULL); + for (i = 0; i < ntarget; ++i) { LinkSymId orig = targets[i]; LinkSymbol* orig_sym = LinkSyms_at(&img->syms, orig - 1); @@ -582,9 +616,7 @@ void link_layout_jit_stubs(Linker* l, LinkImage* img, u32 map_size, LinkSymId slot_id, resolver_id, stub_id; LinkArchIPltReloc stub_relocs[2]; u32 nstub_relocs; - LinkRelocApply rrec; u8* stub_dst = stubs_bytes + (size_t)i * (size_t)arch->iplt_stub_size; - u32 ri; nstub_relocs = arch->emit_iplt_stub(stub_dst, stub_vaddr, slot_vaddr, stub_relocs); @@ -593,7 +625,7 @@ void link_layout_jit_stubs(Linker* l, LinkImage* img, u32 map_size, slot_rec.kind = SK_OBJ; slot_rec.bind = SB_LOCAL; slot_rec.defined = 1; - slot_rec.section_id = slots_sec->id; + slot_rec.section_id = slots_sec_id; slot_rec.vaddr = slot_vaddr; slot_rec.size = 8; slot_id = link_append_symbol(img, &slot_rec); @@ -609,40 +641,18 @@ void link_layout_jit_stubs(Linker* l, LinkImage* img, u32 map_size, stub_rec.kind = SK_FUNC; stub_rec.bind = SB_LOCAL; stub_rec.defined = 1; - stub_rec.section_id = stubs_sec->id; + stub_rec.section_id = stubs_sec_id; stub_rec.vaddr = stub_vaddr; stub_rec.size = arch->iplt_stub_size; stub_id = link_append_symbol(img, &stub_rec); stub_map[orig] = stub_id; - for (ri = 0; ri < nstub_relocs; ++ri) { - memset(&rrec, 0, sizeof(rrec)); - rrec.input_id = LINK_INPUT_NONE; - rrec.section_id = OBJ_SEC_NONE; - rrec.link_section_id = stubs_sec->id; - rrec.offset = - (u32)(i * arch->iplt_stub_size) + stub_relocs[ri].offset_in_stub; - rrec.width = stub_relocs[ri].width; - rrec.write_vaddr = stub_vaddr + stub_relocs[ri].offset_in_stub; - rrec.write_file_offset = rrec.write_vaddr; - rrec.kind = stub_relocs[ri].kind; - rrec.target = slot_id; - rrec.addend = 0; - *link_append_reloc_slot(img) = rrec; - } + emit_stub_apply_relocs(img, stubs_sec_id, + (u32)(i * arch->iplt_stub_size), stub_vaddr, + stub_relocs, nstub_relocs, slot_id); - memset(&rrec, 0, sizeof(rrec)); - rrec.input_id = LINK_INPUT_NONE; - rrec.section_id = OBJ_SEC_NONE; - rrec.link_section_id = slots_sec->id; - rrec.offset = (u32)(i * 8u); - rrec.width = 8; - rrec.write_vaddr = slot_vaddr; - rrec.write_file_offset = slot_vaddr; - rrec.kind = R_ABS64; - rrec.target = resolver_id; - rrec.addend = 0; - *link_append_reloc_slot(img) = rrec; + link_emit_internal_abs64(img, slots_sec_id, (u32)(i * 8u), slot_vaddr, + resolver_id); } if (targets) h->free(h, targets, sizeof(*targets) * tcap); @@ -658,13 +668,10 @@ void link_layout_got(Linker* l, LinkImage* img, u32 map_size, LinkSymId* slot_targets = NULL; u32 slot_cap = 0; u32 nslot = 0; - u32 ii, j, k; - u64 page; - u64 base_vaddr = 0; + u32 ii, k; + u64 base_vaddr; u64 got_size; - LinkSegment* gotseg; - LinkSection* gotsec; - u32 gotseg_idx; + LinkSectionId got_sec_id; u32 si; *got_map_out = NULL; @@ -707,82 +714,15 @@ void link_layout_got(Linker* l, LinkImage* img, u32 map_size, for (si = 0; si < nslot; ++si) got_map[slot_targets[si]] = LINK_SYM_NONE; - page = link_layout_page_size(l); - for (j = 0; j < img->nsegments; ++j) { - u64 end = img->segments[j].vaddr + img->segments[j].mem_size; - if (end > base_vaddr) base_vaddr = end; - } - base_vaddr = ALIGN_UP(base_vaddr, (u64)(page)); got_size = (u64)nslot * 8u; - - { - u32 new_nseg = img->nsegments + 1u; - LinkSegment* nsegs = (LinkSegment*)h->realloc( - h, img->segments, sizeof(*img->segments) * img->nsegments, - sizeof(*img->segments) * new_nseg, _Alignof(LinkSegment)); - u8** nsbufs = (u8**)h->realloc( - h, img->segment_bytes, sizeof(*img->segment_bytes) * img->nsegments, - sizeof(*img->segment_bytes) * new_nseg, _Alignof(u8*)); - size_t* nscaps = (size_t*)h->realloc( - h, img->segment_bytes_cap, - sizeof(*img->segment_bytes_cap) * img->nsegments, - sizeof(*img->segment_bytes_cap) * new_nseg, _Alignof(size_t)); - if (!nsegs || !nsbufs || !nscaps) - compiler_panic(img->c, no_loc(), "link: oom on got segment"); - img->segments = nsegs; - img->segment_bytes = nsbufs; - img->segment_bytes_cap = nscaps; - } - - gotseg_idx = img->nsegments; - gotseg = &img->segments[gotseg_idx]; - memset(gotseg, 0, sizeof(*gotseg)); - gotseg->id = (LinkSegmentId)(gotseg_idx + 1u); - gotseg->flags = SF_ALLOC | SF_WRITE; - gotseg->file_offset = base_vaddr; - gotseg->vaddr = base_vaddr; - gotseg->file_size = got_size; - gotseg->mem_size = got_size; - gotseg->align = (u32)page; - gotseg->nsections = 1; - - img->segment_bytes[gotseg_idx] = (u8*)h->alloc(h, (size_t)got_size, 16); - img->segment_bytes_cap[gotseg_idx] = (size_t)got_size; - if (!img->segment_bytes[gotseg_idx]) - compiler_panic(img->c, no_loc(), "link: oom on got bytes"); - memset(img->segment_bytes[gotseg_idx], 0, (size_t)got_size); - img->nsegments++; - - { - u32 new_nsec = img->nsections + 1u; - LinkSection* nsections = (LinkSection*)h->realloc( - h, img->sections, sizeof(*img->sections) * img->nsections, - sizeof(*img->sections) * new_nsec, _Alignof(LinkSection)); - if (!nsections) - compiler_panic(img->c, no_loc(), "link: oom on got section"); - img->sections = nsections; - } - gotsec = &img->sections[img->nsections]; - memset(gotsec, 0, sizeof(*gotsec)); - gotsec->id = (LinkSectionId)(img->nsections + 1u); - gotsec->input_id = LINK_INPUT_NONE; - gotsec->obj_section_id = OBJ_SEC_NONE; - gotsec->segment_id = gotseg->id; - gotsec->input_offset = 0; - gotsec->file_offset = base_vaddr; - gotsec->vaddr = base_vaddr; - gotsec->size = got_size; - gotsec->flags = SF_ALLOC | SF_WRITE; - gotsec->align = 8; - gotsec->name = pool_intern_slice(img->c->global, SLICE_LIT(".got")); - gotsec->sem = SSEM_PROGBITS; - img->nsections++; + got_sec_id = link_synth_region( + img, l, pool_intern_slice(img->c->global, SLICE_LIT(".got")), + SF_ALLOC | SF_WRITE, SSEM_PROGBITS, got_size, 8, &base_vaddr, NULL); for (si = 0; si < nslot; ++si) { LinkSymId orig = slot_targets[si]; u64 slot_vaddr = base_vaddr + (u64)si * 8u; LinkSymbol sym_rec; - LinkRelocApply rrec; LinkSymId slot_id; memset(&sym_rec, 0, sizeof(sym_rec)); @@ -790,24 +730,13 @@ void link_layout_got(Linker* l, LinkImage* img, u32 map_size, sym_rec.kind = SK_OBJ; sym_rec.bind = SB_LOCAL; sym_rec.defined = 1; - sym_rec.section_id = gotsec->id; + sym_rec.section_id = got_sec_id; sym_rec.vaddr = slot_vaddr; sym_rec.size = 8; slot_id = link_append_symbol(img, &sym_rec); got_map[orig] = slot_id; - memset(&rrec, 0, sizeof(rrec)); - rrec.input_id = LINK_INPUT_NONE; - rrec.section_id = OBJ_SEC_NONE; - rrec.link_section_id = gotsec->id; - rrec.offset = (u32)(si * 8u); - rrec.width = 8; - rrec.write_vaddr = slot_vaddr; - rrec.write_file_offset = base_vaddr + (u64)si * 8u; - rrec.kind = R_ABS64; - rrec.target = orig; - rrec.addend = 0; - *link_append_reloc_slot(img) = rrec; + link_emit_internal_abs64(img, got_sec_id, (u32)(si * 8u), slot_vaddr, orig); } if (slot_targets) h->free(h, slot_targets, sizeof(*slot_targets) * slot_cap); @@ -821,29 +750,15 @@ void link_layout_iplt(Linker* l, LinkImage* img) { Heap* h = img->heap; u32 i; u32 nifunc = 0; - u64 page; - u64 base_vaddr = 0; u64 iplt_vaddr, igot_vaddr, pairs_vaddr; u64 iplt_size, igot_size, pairs_size; u64 init_vaddr = 0, init_size = 0; - u32 iplt_seg_idx, igot_seg_idx, pairs_seg_idx; - u32 init_seg_idx = 0; - u32 seg_base, sec_base; - LinkSegment* iplt_seg; - LinkSegment* igot_seg; - LinkSegment* pairs_seg; - LinkSegment* init_seg = NULL; - LinkSection* iplt_sec; - LinkSection* igot_sec; - LinkSection* pairs_sec; - LinkSection* init_sec = NULL; + LinkSectionId iplt_sec_id, igot_sec_id, pairs_sec_id, init_sec_id = 0; u8* iplt_bytes; u32 slot_idx; int emit_init_array = l->emit_static_exe; LinkSymId ifunc_init_sym = LINK_SYM_NONE; Sym ifunc_init_name = 0; - Sym pairs_section_name; - Sym init_section_name; const LinkArchDesc* arch = link_arch_desc_for(l->c); if (!arch) compiler_panic(img->c, no_loc(), "link: layout_iplt: no arch descriptor"); @@ -859,21 +774,12 @@ void link_layout_iplt(Linker* l, LinkImage* img) { } if (nifunc == 0) return; - page = link_layout_page_size(l); - - for (i = 0; i < img->nsegments; ++i) { - u64 end = img->segments[i].vaddr + img->segments[i].mem_size; - if (end > base_vaddr) base_vaddr = end; - } - - base_vaddr = ALIGN_UP(base_vaddr, (u64)(page)); - iplt_vaddr = base_vaddr; iplt_size = (u64)nifunc * (u64)arch->iplt_stub_size; - igot_vaddr = ALIGN_UP(iplt_vaddr + iplt_size, (u64)(page)); igot_size = (u64)nifunc * 8u; - pairs_vaddr = ALIGN_UP(igot_vaddr + igot_size, (u64)(page)); pairs_size = (u64)nifunc * 16u; + /* Validate the ctor target before mutating the image: the panic must + * fire ahead of any synthetic region being appended. */ if (emit_init_array) { ifunc_init_name = pool_intern_slice(l->c->global, SLICE_LIT("__kit_ifunc_init")); @@ -885,157 +791,23 @@ void link_layout_iplt(Linker* l, LinkImage* img) { "to be defined (link in libkit_rt.a or provide " "your own implementation)"); } - init_vaddr = ALIGN_UP(pairs_vaddr + pairs_size, (u64)(page)); init_size = 8u; } - { - u32 nseg = emit_init_array ? 4u : 3u; - seg_base = link_iplt_alloc_segments(img, nseg); - } - iplt_seg_idx = seg_base + 0u; - igot_seg_idx = seg_base + 1u; - pairs_seg_idx = seg_base + 2u; - if (emit_init_array) init_seg_idx = seg_base + 3u; - - iplt_seg = &img->segments[iplt_seg_idx]; - memset(iplt_seg, 0, sizeof(*iplt_seg)); - iplt_seg->id = (LinkSegmentId)(iplt_seg_idx + 1u); - iplt_seg->flags = SF_ALLOC | SF_EXEC; - iplt_seg->file_offset = iplt_vaddr; - iplt_seg->vaddr = iplt_vaddr; - iplt_seg->file_size = iplt_size; - iplt_seg->mem_size = iplt_size; - iplt_seg->align = (u32)page; - iplt_seg->nsections = 1; - img->segment_bytes[iplt_seg_idx] = (u8*)h->alloc(h, (size_t)iplt_size, 16); - img->segment_bytes_cap[iplt_seg_idx] = (size_t)iplt_size; - if (!img->segment_bytes[iplt_seg_idx]) - compiler_panic(img->c, no_loc(), "link: oom on iplt bytes"); - memset(img->segment_bytes[iplt_seg_idx], 0, (size_t)iplt_size); - - igot_seg = &img->segments[igot_seg_idx]; - memset(igot_seg, 0, sizeof(*igot_seg)); - igot_seg->id = (LinkSegmentId)(igot_seg_idx + 1u); - igot_seg->flags = SF_ALLOC | SF_WRITE; - igot_seg->file_offset = igot_vaddr; - igot_seg->vaddr = igot_vaddr; - igot_seg->file_size = igot_size; - igot_seg->mem_size = igot_size; - igot_seg->align = (u32)page; - igot_seg->nsections = 1; - img->segment_bytes[igot_seg_idx] = (u8*)h->alloc(h, (size_t)igot_size, 16); - img->segment_bytes_cap[igot_seg_idx] = (size_t)igot_size; - if (!img->segment_bytes[igot_seg_idx]) - compiler_panic(img->c, no_loc(), "link: oom on igot bytes"); - memset(img->segment_bytes[igot_seg_idx], 0, (size_t)igot_size); - - pairs_seg = &img->segments[pairs_seg_idx]; - memset(pairs_seg, 0, sizeof(*pairs_seg)); - pairs_seg->id = (LinkSegmentId)(pairs_seg_idx + 1u); - pairs_seg->flags = SF_ALLOC | SF_WRITE; - pairs_seg->file_offset = pairs_vaddr; - pairs_seg->vaddr = pairs_vaddr; - pairs_seg->file_size = pairs_size; - pairs_seg->mem_size = pairs_size; - pairs_seg->align = (u32)page; - pairs_seg->nsections = 1; - img->segment_bytes[pairs_seg_idx] = (u8*)h->alloc(h, (size_t)pairs_size, 16); - img->segment_bytes_cap[pairs_seg_idx] = (size_t)pairs_size; - if (!img->segment_bytes[pairs_seg_idx]) - compiler_panic(img->c, no_loc(), "link: oom on iplt.pairs bytes"); - memset(img->segment_bytes[pairs_seg_idx], 0, (size_t)pairs_size); - - if (emit_init_array) { - init_seg = &img->segments[init_seg_idx]; - memset(init_seg, 0, sizeof(*init_seg)); - init_seg->id = (LinkSegmentId)(init_seg_idx + 1u); - init_seg->flags = SF_ALLOC | SF_WRITE; - init_seg->file_offset = init_vaddr; - init_seg->vaddr = init_vaddr; - init_seg->file_size = init_size; - init_seg->mem_size = init_size; - init_seg->align = (u32)page; - init_seg->nsections = 1; - img->segment_bytes[init_seg_idx] = (u8*)h->alloc(h, (size_t)init_size, 16); - img->segment_bytes_cap[init_seg_idx] = (size_t)init_size; - if (!img->segment_bytes[init_seg_idx]) - compiler_panic(img->c, no_loc(), "link: oom on iplt init_array bytes"); - memset(img->segment_bytes[init_seg_idx], 0, (size_t)init_size); - } - img->nsegments += emit_init_array ? 4u : 3u; - - { - u32 nsec = emit_init_array ? 4u : 3u; - sec_base = link_iplt_alloc_sections(img, nsec); - } - - pairs_section_name = - pool_intern_slice(l->c->global, SLICE_LIT(".iplt.pairs")); - init_section_name = obj_secname_preinit_array(l->c); - - iplt_sec = &img->sections[sec_base + 0u]; - memset(iplt_sec, 0, sizeof(*iplt_sec)); - iplt_sec->id = (LinkSectionId)(sec_base + 0u + 1u); - iplt_sec->input_id = LINK_INPUT_NONE; - iplt_sec->obj_section_id = OBJ_SEC_NONE; - iplt_sec->segment_id = iplt_seg->id; - iplt_sec->input_offset = 0; - iplt_sec->file_offset = iplt_vaddr; - iplt_sec->vaddr = iplt_vaddr; - iplt_sec->size = iplt_size; - iplt_sec->flags = SF_ALLOC | SF_EXEC; - iplt_sec->align = 4; - iplt_sec->name = pool_intern_slice(l->c->global, SLICE_LIT(".iplt")); - iplt_sec->sem = SSEM_PROGBITS; - - igot_sec = &img->sections[sec_base + 1u]; - memset(igot_sec, 0, sizeof(*igot_sec)); - igot_sec->id = (LinkSectionId)(sec_base + 1u + 1u); - igot_sec->input_id = LINK_INPUT_NONE; - igot_sec->obj_section_id = OBJ_SEC_NONE; - igot_sec->segment_id = igot_seg->id; - igot_sec->input_offset = 0; - igot_sec->file_offset = igot_vaddr; - igot_sec->vaddr = igot_vaddr; - igot_sec->size = igot_size; - igot_sec->flags = SF_ALLOC | SF_WRITE; - igot_sec->align = 8; - igot_sec->name = pool_intern_slice(l->c->global, SLICE_LIT(".igot.plt")); - igot_sec->sem = SSEM_PROGBITS; - - pairs_sec = &img->sections[sec_base + 2u]; - memset(pairs_sec, 0, sizeof(*pairs_sec)); - pairs_sec->id = (LinkSectionId)(sec_base + 2u + 1u); - pairs_sec->input_id = LINK_INPUT_NONE; - pairs_sec->obj_section_id = OBJ_SEC_NONE; - pairs_sec->segment_id = pairs_seg->id; - pairs_sec->input_offset = 0; - pairs_sec->file_offset = pairs_vaddr; - pairs_sec->vaddr = pairs_vaddr; - pairs_sec->size = pairs_size; - pairs_sec->flags = SF_ALLOC | SF_WRITE; - pairs_sec->align = 8; - pairs_sec->name = pairs_section_name; - pairs_sec->sem = SSEM_PROGBITS; - - if (emit_init_array) { - init_sec = &img->sections[sec_base + 3u]; - memset(init_sec, 0, sizeof(*init_sec)); - init_sec->id = (LinkSectionId)(sec_base + 3u + 1u); - init_sec->input_id = LINK_INPUT_NONE; - init_sec->obj_section_id = OBJ_SEC_NONE; - init_sec->segment_id = init_seg->id; - init_sec->input_offset = 0; - init_sec->file_offset = init_vaddr; - init_sec->vaddr = init_vaddr; - init_sec->size = init_size; - init_sec->flags = SF_ALLOC | SF_WRITE; - init_sec->align = 8; - init_sec->name = init_section_name; - init_sec->sem = SSEM_PREINIT_ARRAY; - } - img->nsections += emit_init_array ? 4u : 3u; + iplt_sec_id = link_synth_region( + img, l, pool_intern_slice(l->c->global, SLICE_LIT(".iplt")), + SF_ALLOC | SF_EXEC, SSEM_PROGBITS, iplt_size, 4, &iplt_vaddr, &iplt_bytes); + igot_sec_id = link_synth_region( + img, l, pool_intern_slice(l->c->global, SLICE_LIT(".igot.plt")), + SF_ALLOC | SF_WRITE, SSEM_PROGBITS, igot_size, 8, &igot_vaddr, NULL); + pairs_sec_id = link_synth_region( + img, l, pool_intern_slice(l->c->global, SLICE_LIT(".iplt.pairs")), + SF_ALLOC | SF_WRITE, SSEM_PROGBITS, pairs_size, 8, &pairs_vaddr, NULL); + if (emit_init_array) + init_sec_id = + link_synth_region(img, l, obj_secname_preinit_array(l->c), + SF_ALLOC | SF_WRITE, SSEM_PREINIT_ARRAY, init_size, 8, + &init_vaddr, NULL); link_emit_boundary_sym(l, img, "__start_iplt_pairs", pairs_vaddr); link_emit_boundary_sym(l, img, "__stop_iplt_pairs", pairs_vaddr + pairs_size); @@ -1046,7 +818,6 @@ void link_layout_iplt(Linker* l, LinkImage* img) { compiler_panic(img->c, no_loc(), "link: oom on iplt pairs"); img->niplt = nifunc; - iplt_bytes = img->segment_bytes[iplt_seg_idx]; slot_idx = 0; for (i = 0; i < LinkSyms_count(&img->syms); ++i) { @@ -1061,7 +832,8 @@ void link_layout_iplt(Linker* l, LinkImage* img) { LinkSymbol resolver_rec; LinkSymId slot_id; LinkSymId resolver_id; - LinkRelocApply rrec; + LinkArchIPltReloc iplt_relocs[2]; + u32 niplt_relocs; u8* stub_dst; if (s->kind != SK_IFUNC || !s->defined) continue; @@ -1081,8 +853,7 @@ void link_layout_iplt(Linker* l, LinkImage* img) { img->iplt_pairs[2u * slot_idx + 1] = slot_vaddr; stub_dst = iplt_bytes + (size_t)slot_idx * (size_t)arch->iplt_stub_size; - LinkArchIPltReloc iplt_relocs[2]; - u32 niplt_relocs = + niplt_relocs = arch->emit_iplt_stub(stub_dst, stub_vaddr, slot_vaddr, iplt_relocs); memset(&slot_rec, 0, sizeof(slot_rec)); @@ -1090,7 +861,7 @@ void link_layout_iplt(Linker* l, LinkImage* img) { slot_rec.kind = SK_OBJ; slot_rec.bind = SB_LOCAL; slot_rec.defined = 1; - slot_rec.section_id = igot_sec->id; + slot_rec.section_id = igot_sec_id; slot_rec.vaddr = slot_vaddr; slot_rec.size = 8; slot_id = link_append_symbol(img, &slot_rec); @@ -1106,53 +877,17 @@ void link_layout_iplt(Linker* l, LinkImage* img) { resolver_rec.size = 0; resolver_id = link_append_symbol(img, &resolver_rec); - { - u32 ri; - for (ri = 0; ri < niplt_relocs; ++ri) { - memset(&rrec, 0, sizeof(rrec)); - rrec.input_id = LINK_INPUT_NONE; - rrec.section_id = OBJ_SEC_NONE; - rrec.link_section_id = iplt_sec->id; - rrec.offset = (u32)(slot_idx * arch->iplt_stub_size) + - iplt_relocs[ri].offset_in_stub; - rrec.width = iplt_relocs[ri].width; - rrec.write_vaddr = stub_vaddr + iplt_relocs[ri].offset_in_stub; - rrec.write_file_offset = rrec.write_vaddr; - rrec.kind = iplt_relocs[ri].kind; - rrec.target = slot_id; - rrec.addend = 0; - *link_append_reloc_slot(img) = rrec; - } - } - - memset(&rrec, 0, sizeof(rrec)); - rrec.input_id = LINK_INPUT_NONE; - rrec.section_id = OBJ_SEC_NONE; - rrec.link_section_id = pairs_sec->id; - rrec.offset = (u32)(slot_idx * 16u); - rrec.width = 8; - rrec.write_vaddr = pair_vaddr; - rrec.write_file_offset = pair_vaddr; - rrec.kind = R_ABS64; - rrec.target = resolver_id; - rrec.addend = 0; - *link_append_reloc_slot(img) = rrec; + emit_stub_apply_relocs(img, iplt_sec_id, + (u32)(slot_idx * arch->iplt_stub_size), stub_vaddr, + iplt_relocs, niplt_relocs, slot_id); - memset(&rrec, 0, sizeof(rrec)); - rrec.input_id = LINK_INPUT_NONE; - rrec.section_id = OBJ_SEC_NONE; - rrec.link_section_id = pairs_sec->id; - rrec.offset = (u32)(slot_idx * 16u + 8u); - rrec.width = 8; - rrec.write_vaddr = pair_vaddr + 8u; - rrec.write_file_offset = pair_vaddr + 8u; - rrec.kind = R_ABS64; - rrec.target = slot_id; - rrec.addend = 0; - *link_append_reloc_slot(img) = rrec; + link_emit_internal_abs64(img, pairs_sec_id, (u32)(slot_idx * 16u), + pair_vaddr, resolver_id); + link_emit_internal_abs64(img, pairs_sec_id, (u32)(slot_idx * 16u + 8u), + pair_vaddr + 8u, slot_id); s->kind = SK_FUNC; - s->section_id = iplt_sec->id; + s->section_id = iplt_sec_id; s->value = (u64)slot_idx * (u64)arch->iplt_stub_size; s->vaddr = stub_vaddr; s->size = arch->iplt_stub_size; @@ -1160,21 +895,8 @@ void link_layout_iplt(Linker* l, LinkImage* img) { ++slot_idx; } - if (emit_init_array) { - LinkRelocApply rrec; - memset(&rrec, 0, sizeof(rrec)); - rrec.input_id = LINK_INPUT_NONE; - rrec.section_id = OBJ_SEC_NONE; - rrec.link_section_id = init_sec->id; - rrec.offset = 0; - rrec.width = 8; - rrec.write_vaddr = init_vaddr; - rrec.write_file_offset = init_vaddr; - rrec.kind = R_ABS64; - rrec.target = ifunc_init_sym; - rrec.addend = 0; - *link_append_reloc_slot(img) = rrec; - } + if (emit_init_array) + link_emit_internal_abs64(img, init_sec_id, 0, init_vaddr, ifunc_init_sym); { u32 n = LinkSyms_count(&img->syms); @@ -1186,7 +908,7 @@ void link_layout_iplt(Linker* l, LinkImage* img) { canonical = symhash_get(&img->globals, s->name); if (canonical == LINK_SYM_NONE || canonical == s->id) continue; def = LinkSyms_at(&img->syms, canonical - 1); - if (def->section_id != iplt_sec->id) continue; + if (def->section_id != iplt_sec_id) continue; s->section_id = def->section_id; s->value = def->value; s->vaddr = def->vaddr; diff --git a/src/link/link_relocatable.c b/src/link/link_relocatable.c @@ -47,31 +47,6 @@ typedef struct RelGlobal { ObjSymId out_sym; } RelGlobal; -static int rel_bind_strength(u16 bind) { - switch (bind) { - case SB_GLOBAL: - return 3; - case SB_WEAK: - return 2; - case SB_LOCAL: - return 1; - default: - return 0; - } -} - -static int rel_sym_is_def(const ObjSym* s) { - return s && s->kind != SK_UNDEF && - (s->kind == SK_ABS || s->kind == SK_COMMON || s->kind == SK_FILE || - s->section_id != OBJ_SEC_NONE); -} - -static int rel_sym_is_spurious_undef(const ObjSym* s) { - return s && s->section_id == OBJ_SEC_NONE && s->kind != SK_ABS && - s->kind != SK_COMMON && !s->referenced && - (s->bind == SB_GLOBAL || s->bind == SB_WEAK); -} - static u32 rel_symbol_count(ObjBuilder* ob) { ObjSymIter* it; ObjSymEntry e; @@ -127,11 +102,11 @@ static void rel_record_global(Linker* l, RelGlobal** globals, u32* nglobals, ObjSymId id, const ObjSym* s) { RelGlobal* g; if (!s || s->name == 0 || s->bind == SB_LOCAL) return; - if (rel_sym_is_spurious_undef(s)) return; + if (link_sym_is_spurious_undef(s)) return; g = rel_global_for(l, globals, nglobals, cap, by_name, s->name); - if (!rel_sym_is_def(s)) { + if (!link_sym_is_def(s)) { if (!g->has_undef || - rel_bind_strength(s->bind) > rel_bind_strength(g->undef_bind)) { + link_bind_strength(s->bind) > link_bind_strength(g->undef_bind)) { g->undef_bind = (u8)s->bind; } g->has_undef = 1u; @@ -151,8 +126,8 @@ static void rel_record_global(Linker* l, RelGlobal** globals, u32* nglobals, { const ObjSym* prev = rel_input_sym(l, g->def_input_idx, g->def_sym); - int old_strength = prev ? rel_bind_strength(prev->bind) : 0; - int new_strength = rel_bind_strength(s->bind); + int old_strength = prev ? link_bind_strength(prev->bind) : 0; + int new_strength = link_bind_strength(s->bind); if (prev && prev->kind == SK_COMMON && s->kind == SK_COMMON) { if (s->size > g->common_size) g->common_size = s->size; if (s->common_align > g->common_align) g->common_align = s->common_align; @@ -171,7 +146,7 @@ static void rel_record_global(Linker* l, RelGlobal** globals, u32* nglobals, g->def_input_idx = input_idx; g->def_sym = id; } else if (new_strength == old_strength && - new_strength == rel_bind_strength(SB_GLOBAL)) { + new_strength == link_bind_strength(SB_GLOBAL)) { Slice nm_s = pool_slice(l->c->global, s->name); const char* nm = nm_s.s; size_t namelen = nm_s.len; @@ -203,7 +178,7 @@ static ObjSymId rel_copy_symbol(Linker* l, ObjBuilder* out, value = 0; align = common_align; } - if (rel_sym_is_def(s) && (s->vis == SV_HIDDEN || s->vis == SV_INTERNAL)) { + if (link_sym_is_def(s) && (s->vis == SV_HIDDEN || s->vis == SV_INTERNAL)) { bind = SB_LOCAL; vis = SV_DEFAULT; } @@ -373,7 +348,7 @@ static void rel_copy_symbols(Linker* l, ObjBuilder* out, RelInputMap* maps, while (obj_symiter_next(it, &e)) { const ObjSym* s = e.sym; if (e.id >= nsym) continue; - if (rel_sym_is_spurious_undef(s)) continue; + if (link_sym_is_spurious_undef(s)) continue; if (s->name != 0 && s->bind != SB_LOCAL) { LinkSymId rec_idx = symhash_get(globals_by_name, s->name); if (rec_idx != LINK_SYM_NONE) diff --git a/src/link/link_resolve.c b/src/link/link_resolve.c @@ -195,20 +195,12 @@ void link_input_map_alloc(LinkImage* img, InputMap* m, ObjBuilder* ob, /* ---- pass 1: collect symbols ---- */ -/* Defined-symbol replacement policy: a stronger binding wins. */ -static int bind_strength(u8 bind) { - switch (bind) { - case SB_GLOBAL: - return 3; - case SB_WEAK: - return 2; - case SB_LOCAL: - return 1; - default: - return 0; - } -} - +/* A symbol with no home section and no absolute/common pseudo-value: the + * importer's view of an undefined reference (or a DSO export). Distinct + * from link_sym_is_def — SK_FILE symbols are logical undefs here but + * defs there. Used only by scan_presence_before to split logical undefs + * from logical defs; the spurious-undef prune routes through the shared + * link_sym_is_spurious_undef. */ static int obj_sym_is_logical_undef(const ObjSym* s) { return s && s->section_id == OBJ_SEC_NONE && s->kind != SK_ABS && s->kind != SK_COMMON; @@ -251,16 +243,8 @@ void link_resolve_symbols(Linker* l, LinkImage* img) { const ObjSym* s = e.sym; LinkSymbol rec; LinkSymId existing; - { - int is_logical_undef = obj_sym_is_logical_undef(s); - if (is_logical_undef && !s->referenced && - (s->bind == SB_GLOBAL || s->bind == SB_WEAK)) { - continue; - } - } - int is_def = (s->kind != SK_UNDEF) && - (s->kind == SK_ABS || s->kind == SK_COMMON || - s->kind == SK_FILE || s->section_id != OBJ_SEC_NONE); + if (link_sym_is_spurious_undef(s)) continue; + int is_def = link_sym_is_def(s); memset(&rec, 0, sizeof(rec)); rec.name = s->name; @@ -283,8 +267,8 @@ void link_resolve_symbols(Linker* l, LinkImage* img) { m->sym[e.id] = link_append_symbol(img, &rec); } else { LinkSymbol* prev = LinkSyms_at(&img->syms, existing - 1); - int new_strength = bind_strength((u8)s->bind); - int old_strength = bind_strength(prev->bind); + int new_strength = link_bind_strength(s->bind); + int old_strength = link_bind_strength(prev->bind); if (prev->kind == SK_COMMON && rec.kind == SK_COMMON) { if (rec.size > prev->size) { u32 new_align = (rec.common_align > prev->common_align) @@ -306,7 +290,7 @@ void link_resolve_symbols(Linker* l, LinkImage* img) { *prev = rec; m->sym[e.id] = existing; } else if (new_strength == old_strength && - new_strength == bind_strength(SB_GLOBAL)) { + new_strength == link_bind_strength(SB_GLOBAL)) { /* COFF SELECTANY: if both defs are in COMDAT sections, * keep the earlier one and discard the new section. */ ObjBuilder* prev_ob = @@ -903,20 +887,18 @@ static void scan_presence_before(Linker* l, u32 max_order, SymHash* defined, if (s->kind != SK_UNDEF) symhash_set(defined, s->name, 1u); continue; } - if (obj_sym_is_logical_undef(s)) { - /* Match the spurious-UNDEF prune in link_resolve (line 109) and - * obj_sweep_dead at .o emit (obj.c:513): an unreferenced - * global/weak extern declaration is a header artifact, not a - * real demand to pull from an archive. Without this check the - * C frontend's per-extern undef synthesis (e.g. every prototype - * in <math.h>) drags in matching archive members even when the - * user's source never references them. */ - if (!s->referenced && (s->bind == SB_GLOBAL || s->bind == SB_WEAK)) - continue; + /* An unreferenced global/weak extern declaration is a header + * artifact, not a real demand to pull from an archive. Without + * this prune the C frontend's per-extern undef synthesis (e.g. + * every prototype in <math.h>) drags in matching archive members + * even when the user's source never references them. Matches the + * spurious-UNDEF prune in link_resolve_symbols and obj_sweep_dead + * at .o emit (obj.c). */ + if (link_sym_is_spurious_undef(s)) continue; + if (obj_sym_is_logical_undef(s)) symhash_set(undefs, s->name, 1u); - } else { + else symhash_set(defined, s->name, 1u); - } } obj_symiter_free(it); }