kit

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

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:
Msrc/arch/riscv/link.c | 67+++++++++++++++++++++++++++++++++----------------------------------
Msrc/obj/bytebuf.h | 5+++++
Msrc/obj/elf/elf.h | 1+
Msrc/obj/elf/emit.c | 8+-------
Msrc/obj/elf/link.c | 95+++++++++++++++++++------------------------------------------------------------
Msrc/obj/elf/reloc_riscv32.c | 182++++++++-----------------------------------------------------------------------
Msrc/obj/elf/reloc_riscv64.c | 20++++++++++++++++++++
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; + } +}