commit 7619cde3e256a2fe323e1d029c0c0ec999b8f986
parent bc66028c74e6c565488300fd72ba18d3718c3055
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Mon, 25 May 2026 13:51:30 -0700
Fix bootstrap partial linking issues
Diffstat:
4 files changed, 53 insertions(+), 19 deletions(-)
diff --git a/lang/c/parse/parse_init.c b/lang/c/parse/parse_init.c
@@ -964,7 +964,7 @@ void srl_push(Parser* p, u32 offset, u32 size, ObjSymId target, i64 addend) {
if (p->static_relocs_len == p->static_relocs_cap) {
u32 nc = p->static_relocs_cap ? p->static_relocs_cap * 2u : 4u;
void* nb =
- arena_array(p->pool->arena, char, nc * sizeof(*p->static_relocs));
+ arena_array(p->pool->arena, StaticReloc, nc);
if (!nb) perr(p, "out of memory recording static relocs");
if (p->static_relocs && p->static_relocs_len) {
memcpy(nb, p->static_relocs,
diff --git a/lang/c/parse/parse_priv.h b/lang/c/parse/parse_priv.h
@@ -89,6 +89,7 @@ typedef enum SymEntryKind {
typedef struct SymEntry SymEntry;
typedef struct VLABound VLABound;
typedef struct ExternalFuncDecl ExternalFuncDecl;
+typedef struct StaticReloc StaticReloc;
struct VLABound {
const Type* array_ty;
FrameSlot byte_slot;
@@ -104,6 +105,13 @@ struct ParamVLABoundExpr {
u8 pad[3];
};
+struct StaticReloc {
+ u32 offset;
+ u32 size;
+ ObjSymId target;
+ i64 addend;
+};
+
struct SymEntry {
Sym name;
u8 kind; /* SymEntryKind */
@@ -314,12 +322,7 @@ typedef struct Parser {
u32 replay_pos;
u8 replay_active;
- struct {
- u32 offset;
- u32 size;
- ObjSymId target;
- i64 addend;
- }* static_relocs;
+ StaticReloc* static_relocs;
u32 static_relocs_len;
u32 static_relocs_cap;
} Parser;
diff --git a/src/arch/rv64/emit.c b/src/arch/rv64/emit.c
@@ -71,14 +71,19 @@ int fits_signed32(i64 v) {
return v >= (i64)(i32)0x80000000 && v <= (i64)(i32)0x7fffffff;
}
+static i64 floor_div_4096(i64 v) {
+ if (v >= 0) return v / 4096;
+ return -((-v + 4095) / 4096);
+}
+
void emit_li_32(MCEmitter *mc, u32 rd, i32 imm) {
if (imm >= -2048 && imm <= 2047) {
rv64_emit32(mc, rv_addi(rd, RV_ZERO, imm));
return;
}
/* hi20 + lo12, with 0x800 bias to compensate ADDIW's sign-ext. */
- i64 hi64 = ((i64)imm + 0x800) >> 12;
- i64 lo64 = (i64)imm - (hi64 << 12);
+ i64 hi64 = floor_div_4096((i64)imm + 0x800);
+ i64 lo64 = (i64)imm - hi64 * 4096;
i32 hi = (i32)hi64;
i32 lo = (i32)lo64;
rv64_emit32(mc, rv_lui(rd, (u32)hi & 0xfffffu));
diff --git a/src/link/link_relocatable.c b/src/link/link_relocatable.c
@@ -240,6 +240,27 @@ static ObjSymId rel_global_out(Linker* l, ObjBuilder* out, RelInputMap* maps,
return g->out_sym;
}
+static int rel_sections_compatible(const Section* a, const Section* b) {
+ if (!a || !b) return 0;
+ if (a->group_id != OBJ_GROUP_NONE || b->group_id != OBJ_GROUP_NONE) return 0;
+ if (a->link != OBJ_SEC_NONE || b->link != OBJ_SEC_NONE) return 0;
+ if (a->info || b->info) return 0;
+ return a->name == b->name && a->kind == b->kind && a->sem == b->sem &&
+ a->flags == b->flags && a->ext_kind == b->ext_kind &&
+ a->ext_type == b->ext_type && a->ext_flags == b->ext_flags &&
+ a->entsize == b->entsize;
+}
+
+static ObjSecId rel_find_compatible_section(ObjBuilder* out,
+ const Section* src) {
+ u32 nsec = obj_section_count(out);
+ for (u32 i = 1; i < nsec; ++i) {
+ const Section* dst = obj_section_get(out, (ObjSecId)i);
+ if (rel_sections_compatible(dst, src)) return (ObjSecId)i;
+ }
+ return OBJ_SEC_NONE;
+}
+
static void rel_copy_sections(Linker* l, ObjBuilder* out, RelInputMap* maps,
u32 ninputs) {
u32 ii, j;
@@ -271,17 +292,22 @@ static void rel_copy_sections(Linker* l, ObjBuilder* out, RelInputMap* maps,
for (j = 1; j < nsec; ++j) {
const Section* s = obj_section_get(ob, (ObjSecId)j);
ObjSecId out_sec;
+ u32 delta;
if (!s) continue;
- out_sec =
- obj_section_ex(out, s->name, (SecKind)s->kind, (SecSem)s->sem,
- s->flags, s->align, s->entsize, OBJ_SEC_NONE, s->info);
- if (out_sec == OBJ_SEC_NONE)
- compiler_panic(l->c, no_loc(), "link -r: oom copying section");
- if (s->ext_kind != OBJ_EXT_NONE || s->ext_type || s->ext_flags)
- obj_section_set_ext(out, out_sec, (ObjExtKind)s->ext_kind, s->ext_type,
- s->ext_flags);
+ out_sec = rel_find_compatible_section(out, s);
+ if (out_sec == OBJ_SEC_NONE) {
+ out_sec = obj_section_ex(out, s->name, (SecKind)s->kind,
+ (SecSem)s->sem, s->flags, s->align,
+ s->entsize, OBJ_SEC_NONE, s->info);
+ if (out_sec == OBJ_SEC_NONE)
+ compiler_panic(l->c, no_loc(), "link -r: oom copying section");
+ if (s->ext_kind != OBJ_EXT_NONE || s->ext_type || s->ext_flags)
+ obj_section_set_ext(out, out_sec, (ObjExtKind)s->ext_kind,
+ s->ext_type, s->ext_flags);
+ }
+ delta = obj_align_to(out, out_sec, s->align);
if (s->sem == SSEM_NOBITS || s->kind == SEC_BSS) {
- obj_reserve_bss(out, out_sec, s->bss_size, s->align);
+ obj_reserve_bss(out, out_sec, delta + s->bss_size, s->align);
} else if (s->bytes.total) {
u8* flat = (u8*)l->heap->alloc(l->heap, s->bytes.total, 1u);
if (!flat)
@@ -291,7 +317,7 @@ static void rel_copy_sections(Linker* l, ObjBuilder* out, RelInputMap* maps,
l->heap->free(l->heap, flat, s->bytes.total);
}
maps[ii].section[j].out_sec = out_sec;
- maps[ii].section[j].delta = 0;
+ maps[ii].section[j].delta = delta;
}
}
if (have_eflags) obj_set_elf_e_flags(out, eflags);