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:
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);
}