commit cb415ed9fc863e0bb9281b4aa2526d8ef01e4cb0
parent 33f151e8d12d1f3341e5d0a0218fc54549d53279
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 10 Jun 2026 05:53:10 -0700
cleanup wave: ELF dedups (C.5 float-abi helper, C.4 rv32 maps/PLT, F.2 strtab)
C.5: extract elf_riscv_float_abi_to_e_flags (reloc_riscv64.c, inverse of the
existing decoder) and call it from the ET_REL (emit.c) and ET_EXEC (link.c)
writers instead of inlining the KitFloatAbi->EF_RISCV_FLOAT_ABI_* mapping in the
format-generic ELF layer.
C.4: reloc_riscv32.c no longer clones the rv64 reloc switches — it delegates to
elf_riscv64_reloc_to/from and only filters the three 64-bit-only kinds (R_ABS64/
ADD64/SUB64 <-> ELF_R_RISCV_64/ADD64/SUB64). The rv64/rv32 PLT-entry and
IPLT-stub emitters collapse to shared rv_emit_{plt_entry,iplt_stub} taking an
xlen8 flag (LD vs LW via rv_load_slot); the four LinkArchDesc-registered
functions become thin wrappers.
F.2: elf/link.c drops its private StrBuilder reimplementation and uses the
shared ObjByteBuf dedup builder (objbb_*), seeding each table with a leading
NUL. Adds objbb_append_cstr to obj/bytebuf.h.
Verified: test-elf, test-link, test-link-reloc-apply, test-smoke-rv32
(ilp32 + ilp32f, -O0/-O1), test-smoke-rv64 all green.
Diffstat:
7 files changed, 99 insertions(+), 279 deletions(-)
diff --git a/src/arch/riscv/link.c b/src/arch/riscv/link.c
@@ -46,63 +46,62 @@ static void rv64_emit_plt0(u8* dst, u64 plt0_vaddr, u64 gotplt_vaddr) {
* (R_RISCV_JUMP_SLOT) and tail-call through it. t1 is the standard
* psABI scratch for the trampoline return-address (clobbered by the
* lazy resolver in the non-BIND_NOW path); t3 holds the slot pointer. */
-static void rv64_emit_plt_entry(u8* dst, u64 entry_vaddr, u64 slot_vaddr) {
+/* Load a GOT/.igot.plt slot into `reg`: 8-byte slot (LD) on RV64, 4-byte
+ * slot (LW) on RV32. The only XLEN-divergent instruction in the PLT/IPLT. */
+static u32 rv_load_slot(u32 reg, i32 imm12, int xlen8) {
+ return xlen8 ? rv_ld(reg, reg, imm12) : rv_lw(reg, reg, imm12);
+}
+
+/* Per-import PLT entry (shared rv64/rv32): load the GOT slot pre-filled by
+ * the loader (R_RISCV_JUMP_SLOT) and tail-call through it. t1 is the standard
+ * psABI scratch for the trampoline return address (clobbered by the lazy
+ * resolver in the non-BIND_NOW path); t3 holds the slot pointer. 16 bytes /
+ * 4 insns; the AUIPC + (hi20,lo12) split is XLEN-neutral. */
+static void rv_emit_plt_entry(u8* dst, u64 entry_vaddr, u64 slot_vaddr,
+ int xlen8) {
i64 disp = (i64)slot_vaddr - (i64)entry_vaddr;
u32 hi20;
u32 lo12;
rv64_split_pcrel(disp, &hi20, &lo12);
wr_u32_le(dst + 0, rv_auipc(RV_T3, hi20));
- wr_u32_le(dst + 4, rv_ld(RV_T3, RV_T3, (i32)lo12));
+ wr_u32_le(dst + 4, rv_load_slot(RV_T3, (i32)lo12, xlen8));
wr_u32_le(dst + 8, rv_jalr(RV_T1, RV_T3, 0));
wr_u32_le(dst + 12, rv_nop());
}
-/* IPLT stub: load .igot.plt[i] (filled at startup by the resolver) and
- * tail-call to it. The stub->slot displacement is invariant under the
- * segment-base shift (both addresses live in the same image), so we
- * bake it directly into the instructions and report zero apply-time
- * relocs — unlike aarch64, which cannot encode a 32-bit pcrel inline. */
-static u32 rv64_emit_iplt_stub(u8* dst, u64 stub_vaddr, u64 slot_vaddr,
- LinkArchIPltReloc out[2]) {
+/* IPLT stub (shared rv64/rv32): load .igot.plt[i] (filled at startup by the
+ * resolver) and tail-call to it. The stub->slot displacement is invariant
+ * under the segment-base shift (both addresses live in the same image), so we
+ * bake it directly into the instructions and report zero apply-time relocs —
+ * unlike aarch64, which cannot encode a 32-bit pcrel inline. 12 bytes / 3
+ * insns. */
+static u32 rv_emit_iplt_stub(u8* dst, u64 stub_vaddr, u64 slot_vaddr,
+ int xlen8) {
i64 disp = (i64)slot_vaddr - (i64)stub_vaddr;
u32 hi20;
u32 lo12;
- (void)out;
rv64_split_pcrel(disp, &hi20, &lo12);
wr_u32_le(dst + 0, rv_auipc(RV_T1, hi20));
- wr_u32_le(dst + 4, rv_ld(RV_T1, RV_T1, (i32)lo12));
+ wr_u32_le(dst + 4, rv_load_slot(RV_T1, (i32)lo12, xlen8));
wr_u32_le(dst + 8, rv_jr(RV_T1));
return 0u;
}
-/* RV32 PLT entry: identical to rv64_emit_plt_entry except the GOT slot
- * is 4 bytes (one XLEN word), so the load is LW not LD. Entry stays
- * 16 bytes / 4 insns; the AUIPC + (hi20,lo12) split is XLEN-neutral. */
+static void rv64_emit_plt_entry(u8* dst, u64 entry_vaddr, u64 slot_vaddr) {
+ rv_emit_plt_entry(dst, entry_vaddr, slot_vaddr, 1);
+}
static void rv32_emit_plt_entry(u8* dst, u64 entry_vaddr, u64 slot_vaddr) {
- i64 disp = (i64)slot_vaddr - (i64)entry_vaddr;
- u32 hi20;
- u32 lo12;
- rv64_split_pcrel(disp, &hi20, &lo12);
- wr_u32_le(dst + 0, rv_auipc(RV_T3, hi20));
- wr_u32_le(dst + 4, rv_lw(RV_T3, RV_T3, (i32)lo12));
- wr_u32_le(dst + 8, rv_jalr(RV_T1, RV_T3, 0));
- wr_u32_le(dst + 12, rv_nop());
+ rv_emit_plt_entry(dst, entry_vaddr, slot_vaddr, 0);
+}
+static u32 rv64_emit_iplt_stub(u8* dst, u64 stub_vaddr, u64 slot_vaddr,
+ LinkArchIPltReloc out[2]) {
+ (void)out;
+ return rv_emit_iplt_stub(dst, stub_vaddr, slot_vaddr, 1);
}
-
-/* RV32 IPLT stub: identical to rv64_emit_iplt_stub except the
- * .igot.plt slot is 4 bytes, so LW not LD. Stub stays 12 bytes /
- * 3 insns; displacement is baked inline, so zero apply-time relocs. */
static u32 rv32_emit_iplt_stub(u8* dst, u64 stub_vaddr, u64 slot_vaddr,
LinkArchIPltReloc out[2]) {
- i64 disp = (i64)slot_vaddr - (i64)stub_vaddr;
- u32 hi20;
- u32 lo12;
(void)out;
- rv64_split_pcrel(disp, &hi20, &lo12);
- wr_u32_le(dst + 0, rv_auipc(RV_T1, hi20));
- wr_u32_le(dst + 4, rv_lw(RV_T1, RV_T1, (i32)lo12));
- wr_u32_le(dst + 8, rv_jr(RV_T1));
- return 0u;
+ return rv_emit_iplt_stub(dst, stub_vaddr, slot_vaddr, 0);
}
/* Width + classification rows for RISC-V's relocation kinds (shared by rv64
diff --git a/src/obj/bytebuf.h b/src/obj/bytebuf.h
@@ -108,4 +108,9 @@ static inline u32 objbb_append_str(ObjByteBuf* b, const char* s, u32 n) {
return objbb_str(b, s, n);
}
+/* objbb_append_str for a NUL-terminated C string. */
+static inline u32 objbb_append_cstr(ObjByteBuf* b, const char* s) {
+ return objbb_append_str(b, s, (u32)strlen(s));
+}
+
#endif
diff --git a/src/obj/elf/elf.h b/src/obj/elf/elf.h
@@ -461,6 +461,7 @@ u32 elf_riscv32_reloc_from(u32 elf_type);
* rv32 arch-ops descriptors. */
const char* elf_riscv_reloc_name(u32 elf_type);
KitFloatAbi elf_riscv_float_abi_from_e_flags(u32 e_flags);
+u32 elf_riscv_float_abi_to_e_flags(KitFloatAbi abi);
/* ---- little-endian byte writers (Writer-based) ----
* Writes go through the shared writer_u*_le helpers (core/bytes.h); the
diff --git a/src/obj/elf/emit.c b/src/obj/elf/emit.c
@@ -700,13 +700,7 @@ void emit_elf(Compiler* c, ObjBuilder* ob, Writer* w) {
if (e_machine == EM_RISCV) {
Compiler* ec = obj_compiler(ob);
if (ec && ec->target.ptr_size == 4u) {
- u32 fa = EF_RISCV_FLOAT_ABI_SOFT;
- if (ec->target.float_abi == KIT_FLOAT_ABI_SINGLE)
- fa = EF_RISCV_FLOAT_ABI_SINGLE;
- else if (ec->target.float_abi == KIT_FLOAT_ABI_DOUBLE)
- fa = EF_RISCV_FLOAT_ABI_DOUBLE;
- else if (ec->target.float_abi == KIT_FLOAT_ABI_DEFAULT)
- fa = EF_RISCV_FLOAT_ABI_SINGLE; /* rv32 default profile is ilp32f */
+ u32 fa = elf_riscv_float_abi_to_e_flags(ec->target.float_abi);
e_flags = (e_flags & ~(u32)EF_RISCV_FLOAT_ABI_MASK) | fa;
}
}
diff --git a/src/obj/elf/link.c b/src/obj/elf/link.c
@@ -56,6 +56,7 @@
#include "core/vec.h"
#include "link/link_arch.h"
#include "link/link_internal.h"
+#include "obj/bytebuf.h"
#include "obj/elf/elf.h"
#include "obj/elf/link_dyn.h"
#include "obj/format.h"
@@ -640,60 +641,9 @@ static void apply_all_relocs(LinkImage* img, u64 img_base) {
* see link_image_id_compute in link_image_id.c. Mach-O wraps the
* same bytes in LC_UUID; ELF wraps them in a .note.gnu.build-id. */
-/* ---- string-table builder ---- */
-
-typedef struct StrBuilder {
- Heap* heap;
- u8* data;
- u32 len;
- u32 cap;
-} StrBuilder;
-
-static void strb_init(StrBuilder* s, Heap* h, u32 reserve) {
- s->heap = h;
- s->cap = reserve > 16u ? reserve : 16u;
- s->data = (u8*)h->alloc(h, s->cap, 1);
- if (!s->data) s->cap = 0;
- s->len = 0;
- if (s->cap) {
- s->data[0] = 0;
- s->len = 1;
- } /* leading NUL */
-}
-
-static void strb_fini(StrBuilder* s) {
- if (s->data) s->heap->free(s->heap, s->data, s->cap);
- s->data = NULL;
- s->cap = s->len = 0;
-}
-
-static void strb_grow(StrBuilder* s, u32 need) {
- (void)VEC_GROW(s->heap, s->data, s->cap, need);
-}
-
-static u32 strb_add(StrBuilder* s, const char* str, u32 slen) {
- u32 off;
- if (slen == 0) return 0;
- /* Linear dedup: scan existing data for a matching NUL-terminated
- * substring. Strtabs are small enough to make this acceptable. */
- if (s->len > slen) {
- u32 i;
- for (i = 0; i + slen < s->len; ++i) {
- if (s->data[i + slen] == 0 && memcmp(s->data + i, str, slen) == 0)
- return i;
- }
- }
- off = s->len;
- strb_grow(s, s->len + slen + 1u);
- memcpy(s->data + s->len, str, slen);
- s->data[s->len + slen] = 0;
- s->len += slen + 1u;
- return off;
-}
-
-static u32 strb_add_cstr(StrBuilder* s, const char* str) {
- return strb_add(s, str, (u32)slice_from_cstr(str).len);
-}
+/* String tables (.shstrtab / .strtab) use the shared ObjByteBuf dedup builder
+ * (objbb_*, obj/bytebuf.h). Both must lead with a NUL so name offset 0 reads as
+ * the empty string, so each is seeded with objbb_u8(&b, 0) right after init. */
/* ---- symtab builder ---- */
@@ -1223,13 +1173,15 @@ void link_emit_elf(LinkImage* img, Writer* w) {
}
/* ---- build .shstrtab ---- */
- StrBuilder shstrtab;
- strb_init(&shstrtab, heap, 128);
- u32 sh_name_symtab = strb_add_cstr(&shstrtab, ".symtab");
- u32 sh_name_strtab = strb_add_cstr(&shstrtab, ".strtab");
- u32 sh_name_shstrtab = strb_add_cstr(&shstrtab, ".shstrtab");
+ ObjByteBuf shstrtab;
+ objbb_init(&shstrtab, heap);
+ objbb_reserve(&shstrtab, 128);
+ objbb_u8(&shstrtab, 0); /* leading NUL: name offset 0 = empty string */
+ u32 sh_name_symtab = objbb_append_cstr(&shstrtab, ".symtab");
+ u32 sh_name_strtab = objbb_append_cstr(&shstrtab, ".strtab");
+ u32 sh_name_shstrtab = objbb_append_cstr(&shstrtab, ".shstrtab");
u32 sh_name_buildid =
- scripted ? 0u : strb_add_cstr(&shstrtab, ".note.gnu.build-id");
+ scripted ? 0u : objbb_append_cstr(&shstrtab, ".note.gnu.build-id");
/* Per-output-shdr names — interned strings from input section names. */
u32* outshdr_name_off =
(u32*)heap->alloc(heap, sizeof(u32) * (noutshdr + 1u), _Alignof(u32));
@@ -1244,7 +1196,7 @@ void link_emit_elf(LinkImage* img, Writer* w) {
const char* nm = nm_s.s;
size_t nlen = nm_s.len;
outshdr_name_off[i] =
- nm && nlen ? strb_add(&shstrtab, nm, (u32)nlen) : 0;
+ nm && nlen ? objbb_append_str(&shstrtab, nm, (u32)nlen) : 0;
} else {
outshdr_name_off[i] = 0;
}
@@ -1265,8 +1217,10 @@ void link_emit_elf(LinkImage* img, Writer* w) {
* records keep their own LinkSymId after resolve_undefs's
* "copy fields from canonical def" step. sh_info = first non-local
* idx. */
- StrBuilder strtab;
- strb_init(&strtab, heap, 256);
+ ObjByteBuf strtab;
+ objbb_init(&strtab, heap);
+ objbb_reserve(&strtab, 256);
+ objbb_u8(&strtab, 0); /* leading NUL: name offset 0 = empty string */
SymRec* recs = (SymRec*)heap->alloc(
heap, sizeof(*recs) * (LinkSyms_count(&img->syms) + 1u),
@@ -1323,7 +1277,8 @@ void link_emit_elf(LinkImage* img, Writer* w) {
st_bind = sym_bind_to_st_bind(s->bind);
r = &recs[nsyms_emit++];
memset(r, 0, sizeof(*r));
- r->st_name = (nm && namelen) ? strb_add(&strtab, nm, (u32)namelen) : 0;
+ r->st_name =
+ (nm && namelen) ? objbb_append_str(&strtab, nm, (u32)namelen) : 0;
r->st_info = ELF64_ST_INFO(st_bind, st_type);
r->st_other = STV_DEFAULT;
r->st_shndx = shndx;
@@ -1553,13 +1508,7 @@ void link_emit_elf(LinkImage* img, Writer* w) {
* bits are a placeholder. Override them from -mabi so the executable's ABI
* matches its objects (and a soft ilp32 image isn't mislabelled single). */
if (e_machine == EM_RISCV && class32) {
- u32 fa = EF_RISCV_FLOAT_ABI_SOFT;
- if (c->target.float_abi == KIT_FLOAT_ABI_SINGLE)
- fa = EF_RISCV_FLOAT_ABI_SINGLE;
- else if (c->target.float_abi == KIT_FLOAT_ABI_DOUBLE)
- fa = EF_RISCV_FLOAT_ABI_DOUBLE;
- else if (c->target.float_abi == KIT_FLOAT_ABI_DEFAULT)
- fa = EF_RISCV_FLOAT_ABI_SINGLE;
+ u32 fa = elf_riscv_float_abi_to_e_flags(c->target.float_abi);
ehdr.e_flags = (ehdr.e_flags & ~(u32)EF_RISCV_FLOAT_ABI_MASK) | fa;
}
ehdr.e_ehsize = (u16)ehdr_sz;
@@ -1825,6 +1774,6 @@ void link_emit_elf(LinkImage* img, Writer* w) {
heap->free(heap, outshdrs, sizeof(*outshdrs) * outshdr_cap);
if (outshdr_name_off)
heap->free(heap, outshdr_name_off, sizeof(u32) * (noutshdr + 1u));
- strb_fini(&strtab);
- strb_fini(&shstrtab);
+ objbb_fini(&strtab);
+ objbb_fini(&shstrtab);
}
diff --git a/src/obj/elf/reloc_riscv32.c b/src/obj/elf/reloc_riscv32.c
@@ -1,175 +1,27 @@
/* RelocKind <-> RISC-V ELF reloc-type mapping (ELFCLASS32 / RV32 ILP32*).
*
- * Clone of reloc_riscv64.c. The RISC-V reloc type codes are XLEN-neutral
- * and fit in the 8-bit ELF32 r_info type field, so every code-relative /
- * data-relative kind is reused verbatim. The only divergences are the
- * 64-bit-wide kinds:
- * - R_ABS64 -> unsupported on RV32 (ELF_R_RISCV_NONE)
- * - R_RV_ADD64 / R_RV_SUB64 -> unsupported on RV32 (ELF_R_RISCV_NONE)
- * and, on the read side, ELF_R_RISCV_64 / ADD64 / SUB64 map to the
- * (u32)-1 sentinel so the reader diagnoses them rather than silently
- * fabricating a 64-bit RelocKind for a 32-bit object.
- *
- * R_ABS32 -> ELF_R_RISCV_32 is the RV32 primary absolute reloc. */
+ * The RISC-V reloc type codes are XLEN-neutral and fit the 8-bit ELF32 r_info
+ * type field, so every code-/data-relative kind is shared verbatim with the
+ * rv64 maps in reloc_riscv64.c — these wrappers just delegate. The only
+ * divergence is the 64-bit-wide kinds (R_ABS64 / R_ADD64 / R_SUB64 <->
+ * ELF_R_RISCV_64 / ADD64 / SUB64): not valid in an ELFCLASS32 object, so the
+ * write side maps them to ELF_R_RISCV_NONE (emit_elf flags them) and the read
+ * side to the (u32)-1 sentinel (the reader diagnoses them rather than
+ * fabricating a 64-bit RelocKind for a 32-bit object). */
#include "obj/elf/elf.h"
u32 elf_riscv32_reloc_to(u32 kind /* RelocKind */) {
- switch (kind) {
- case R_NONE:
- return ELF_R_RISCV_NONE;
- /* R_ABS64 / R_RV_ADD64 / R_RV_SUB64 are 64-bit-only: unsupported on
- * RV32 (fall through to NONE so emit_elf flags them). */
- case R_ABS32:
- return ELF_R_RISCV_32;
- case R_PC32:
- return ELF_R_RISCV_32_PCREL;
- case R_RV_HI20:
- return ELF_R_RISCV_HI20;
- case R_RV_LO12_I:
- return ELF_R_RISCV_LO12_I;
- case R_RV_LO12_S:
- return ELF_R_RISCV_LO12_S;
- case R_RV_BRANCH:
- return ELF_R_RISCV_BRANCH;
- case R_RV_JAL:
- return ELF_R_RISCV_JAL;
- case R_RV_CALL:
- return ELF_R_RISCV_CALL;
- case R_PLT32:
- return ELF_R_RISCV_CALL_PLT;
- case R_RV_PCREL_HI20:
- return ELF_R_RISCV_PCREL_HI20;
- case R_RV_PCREL_LO12_I:
- return ELF_R_RISCV_PCREL_LO12_I;
- case R_RV_PCREL_LO12_S:
- return ELF_R_RISCV_PCREL_LO12_S;
- case R_RV_GOT_HI20:
- return ELF_R_RISCV_GOT_HI20;
- case R_RV_TLS_GOT_HI20:
- return ELF_R_RISCV_TLS_GOT_HI20;
- case R_RV_TPREL_HI20:
- return ELF_R_RISCV_TPREL_HI20;
- case R_RV_TPREL_LO12_I:
- return ELF_R_RISCV_TPREL_LO12_I;
- case R_RV_TPREL_LO12_S:
- return ELF_R_RISCV_TPREL_LO12_S;
- case R_RV_TPREL_ADD:
- return ELF_R_RISCV_TPREL_ADD;
- case R_ADD8:
- return ELF_R_RISCV_ADD8;
- case R_ADD16:
- return ELF_R_RISCV_ADD16;
- case R_ADD32:
- return ELF_R_RISCV_ADD32;
- case R_SUB8:
- return ELF_R_RISCV_SUB8;
- case R_SUB16:
- return ELF_R_RISCV_SUB16;
- case R_SUB32:
- return ELF_R_RISCV_SUB32;
- case R_RV_ALIGN:
- return ELF_R_RISCV_ALIGN;
- case R_RV_RVC_BRANCH:
- return ELF_R_RISCV_RVC_BRANCH;
- case R_RV_RVC_JUMP:
- return ELF_R_RISCV_RVC_JUMP;
- case R_RV_RELAX:
- return ELF_R_RISCV_RELAX;
- case R_SUB6:
- return ELF_R_RISCV_SUB6;
- case R_SET6:
- return ELF_R_RISCV_SET6;
- case R_ABS8:
- return ELF_R_RISCV_SET8;
- case R_ABS16:
- return ELF_R_RISCV_SET16;
- case R_SET_ULEB128:
- return ELF_R_RISCV_SET_ULEB128;
- case R_SUB_ULEB128:
- return ELF_R_RISCV_SUB_ULEB128;
- default:
- return ELF_R_RISCV_NONE;
- }
+ /* 64-bit-only kinds are unrepresentable on RV32. */
+ if (kind == R_ABS64 || kind == R_ADD64 || kind == R_SUB64)
+ return ELF_R_RISCV_NONE;
+ return elf_riscv64_reloc_to(kind);
}
u32 elf_riscv32_reloc_from(u32 elf_type) {
- switch (elf_type) {
- case ELF_R_RISCV_NONE:
- return R_NONE;
- /* ELF_R_RISCV_64 / ADD64 / SUB64 are 64-bit-only: not valid in an
- * ELFCLASS32 object — fall through to the (u32)-1 sentinel. */
- case ELF_R_RISCV_32:
- return R_ABS32;
- case ELF_R_RISCV_32_PCREL:
- return R_PC32;
- case ELF_R_RISCV_HI20:
- return R_RV_HI20;
- case ELF_R_RISCV_LO12_I:
- return R_RV_LO12_I;
- case ELF_R_RISCV_LO12_S:
- return R_RV_LO12_S;
- case ELF_R_RISCV_BRANCH:
- return R_RV_BRANCH;
- case ELF_R_RISCV_JAL:
- return R_RV_JAL;
- case ELF_R_RISCV_CALL:
- return R_RV_CALL;
- case ELF_R_RISCV_CALL_PLT:
- return R_PLT32;
- case ELF_R_RISCV_PCREL_HI20:
- return R_RV_PCREL_HI20;
- case ELF_R_RISCV_PCREL_LO12_I:
- return R_RV_PCREL_LO12_I;
- case ELF_R_RISCV_PCREL_LO12_S:
- return R_RV_PCREL_LO12_S;
- case ELF_R_RISCV_GOT_HI20:
- return R_RV_GOT_HI20;
- case ELF_R_RISCV_TLS_GOT_HI20:
- return R_RV_TLS_GOT_HI20;
- case ELF_R_RISCV_TPREL_HI20:
- return R_RV_TPREL_HI20;
- case ELF_R_RISCV_TPREL_LO12_I:
- return R_RV_TPREL_LO12_I;
- case ELF_R_RISCV_TPREL_LO12_S:
- return R_RV_TPREL_LO12_S;
- case ELF_R_RISCV_TPREL_ADD:
- return R_RV_TPREL_ADD;
- case ELF_R_RISCV_ADD8:
- return R_ADD8;
- case ELF_R_RISCV_ADD16:
- return R_ADD16;
- case ELF_R_RISCV_ADD32:
- return R_ADD32;
- case ELF_R_RISCV_SUB8:
- return R_SUB8;
- case ELF_R_RISCV_SUB16:
- return R_SUB16;
- case ELF_R_RISCV_SUB32:
- return R_SUB32;
- case ELF_R_RISCV_ALIGN:
- return R_RV_ALIGN;
- case ELF_R_RISCV_RVC_BRANCH:
- return R_RV_RVC_BRANCH;
- case ELF_R_RISCV_RVC_JUMP:
- return R_RV_RVC_JUMP;
- case ELF_R_RISCV_RELAX:
- return R_RV_RELAX;
- case ELF_R_RISCV_SUB6:
- return R_SUB6;
- case ELF_R_RISCV_SET6:
- return R_SET6;
- case ELF_R_RISCV_SET8:
- return R_ABS8;
- case ELF_R_RISCV_SET16:
- return R_ABS16;
- case ELF_R_RISCV_SET32:
- return R_ABS32;
- case ELF_R_RISCV_SET_ULEB128:
- return R_SET_ULEB128;
- case ELF_R_RISCV_SUB_ULEB128:
- return R_SUB_ULEB128;
- default:
- return (u32)-1; /* sentinel */
- }
+ /* 64-bit-only wire types are not valid in an ELFCLASS32 object. */
+ if (elf_type == ELF_R_RISCV_64 || elf_type == ELF_R_RISCV_ADD64 ||
+ elf_type == ELF_R_RISCV_SUB64)
+ return (u32)-1;
+ return elf_riscv64_reloc_from(elf_type);
}
diff --git a/src/obj/elf/reloc_riscv64.c b/src/obj/elf/reloc_riscv64.c
@@ -292,3 +292,23 @@ KitFloatAbi elf_riscv_float_abi_from_e_flags(u32 e_flags) {
return KIT_FLOAT_ABI_DEFAULT;
}
}
+
+/* Encode the float ABI into RISC-V ELF e_flags (the EF_RISCV_FLOAT_ABI_* bits;
+ * caller masks them into e_flags with EF_RISCV_FLOAT_ABI_MASK). Inverse of
+ * elf_riscv_float_abi_from_e_flags, kept here so the format-generic ELF writers
+ * (emit.c ET_REL, link.c ET_EXEC) don't inline the mapping. KIT_FLOAT_ABI_DEFAULT
+ * resolves to SINGLE: the rv32 ilp32/ilp32f pair shares one KitArchKind, so the
+ * static descriptor's float bits are a placeholder and -mabi DEFAULT means the
+ * rv32 default profile (ilp32f). XLEN-neutral; only the rv32 writers call it. */
+u32 elf_riscv_float_abi_to_e_flags(KitFloatAbi abi) {
+ switch (abi) {
+ case KIT_FLOAT_ABI_SINGLE:
+ return EF_RISCV_FLOAT_ABI_SINGLE;
+ case KIT_FLOAT_ABI_DOUBLE:
+ return EF_RISCV_FLOAT_ABI_DOUBLE;
+ case KIT_FLOAT_ABI_DEFAULT:
+ return EF_RISCV_FLOAT_ABI_SINGLE;
+ default:
+ return EF_RISCV_FLOAT_ABI_SOFT;
+ }
+}