kit

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

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:
Mlang/c/parse/parse_init.c | 2+-
Mlang/c/parse/parse_priv.h | 15+++++++++------
Msrc/arch/rv64/emit.c | 9+++++++--
Msrc/link/link_relocatable.c | 46++++++++++++++++++++++++++++++++++++----------
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);