commit 516e7b47cb094dd0efd52a836af95a5a45672102
parent 3e9ce3177b318a8cf1e867589ab9f7a4628715fc
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Thu, 4 Jun 2026 16:37:08 -0700
elf: add hosted FreeBSD relocation primitives
Diffstat:
8 files changed, 102 insertions(+), 24 deletions(-)
diff --git a/src/obj/elf/elf.h b/src/obj/elf/elf.h
@@ -46,6 +46,10 @@
3 /* a.k.a. ELFOSABI_LINUX — required when \
the file uses STT_GNU_IFUNC / STB_GNU_UNIQUE. */
#define ELFOSABI_LINUX ELFOSABI_GNU
+/* FreeBSD brand. The kernel matches EI_OSABI for hosted executables;
+ * without it a static binary is rejected even when crt1.o carries the
+ * FreeBSD ABI note. */
+#define ELFOSABI_FREEBSD 9
/* ---- e_type ---- */
#define ET_NONE 0
@@ -156,11 +160,11 @@
* symbol writer overrides COMMON to STT_NOTYPE at its call site. */
static inline u8 elf_st_type(u8 kind /* SymKind */) {
static const u8 kElfStType[] = {
- [SK_UNDEF] = STT_NOTYPE, [SK_FUNC] = STT_FUNC,
- [SK_OBJ] = STT_OBJECT, [SK_SECTION] = STT_SECTION,
- [SK_FILE] = STT_FILE, [SK_COMMON] = STT_OBJECT,
- [SK_TLS] = STT_TLS, [SK_ABS] = STT_NOTYPE,
- [SK_NOTYPE] = STT_NOTYPE, [SK_IFUNC] = STT_GNU_IFUNC,
+ [SK_UNDEF] = STT_NOTYPE, [SK_FUNC] = STT_FUNC,
+ [SK_OBJ] = STT_OBJECT, [SK_SECTION] = STT_SECTION,
+ [SK_FILE] = STT_FILE, [SK_COMMON] = STT_OBJECT,
+ [SK_TLS] = STT_TLS, [SK_ABS] = STT_NOTYPE,
+ [SK_NOTYPE] = STT_NOTYPE, [SK_IFUNC] = STT_GNU_IFUNC,
};
if (kind >= (u8)(sizeof kElfStType / sizeof kElfStType[0])) return STT_NOTYPE;
return kElfStType[kind];
@@ -183,7 +187,8 @@ static inline u8 elf_st_other(u8 vis /* SymVis */) {
[SV_PROTECTED] = STV_PROTECTED,
[SV_INTERNAL] = STV_INTERNAL,
};
- if (vis >= (u8)(sizeof kElfStOther / sizeof kElfStOther[0])) return STV_DEFAULT;
+ if (vis >= (u8)(sizeof kElfStOther / sizeof kElfStOther[0]))
+ return STV_DEFAULT;
return kElfStOther[vis];
}
@@ -284,6 +289,9 @@ static inline u8 elf_st_other(u8 vis /* SymVis */) {
#define ELF_R_AARCH64_LDST128_ABS_LO12_NC 299
#define ELF_R_AARCH64_ADR_GOT_PAGE 311
#define ELF_R_AARCH64_LD64_GOT_LO12_NC 312
+/* TLS Initial-Exec: ADRP/LDR of a GOT slot holding the symbol's tpoff. */
+#define ELF_R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541
+#define ELF_R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542
/* AArch64 dynamic-only reloc types: generated by the linker into
* .rela.dyn / .rela.plt and processed by the runtime loader. */
@@ -291,6 +299,7 @@ static inline u8 elf_st_other(u8 vis /* SymVis */) {
#define ELF_R_AARCH64_GLOB_DAT 1025
#define ELF_R_AARCH64_JUMP_SLOT 1026
#define ELF_R_AARCH64_RELATIVE 1027
+#define ELF_R_AARCH64_IRELATIVE 1032
/* AArch64 TLS Local-Exec (static linking model: each TLV is at a fixed
* offset from the thread pointer, computed at link time). */
@@ -333,6 +342,7 @@ u32 elf_aarch64_reloc_from(u32 elf_type);
#define ELF_R_X86_64_GLOB_DAT 6
#define ELF_R_X86_64_JUMP_SLOT 7
#define ELF_R_X86_64_RELATIVE 8
+#define ELF_R_X86_64_IRELATIVE 37
#define ELF_R_X86_64_GOTPCREL 9
#define ELF_R_X86_64_32 10
#define ELF_R_X86_64_32S 11
@@ -369,6 +379,7 @@ u32 elf_x86_64_reloc_from(u32 elf_type);
#define ELF_R_RISCV_RELATIVE 3
#define ELF_R_RISCV_COPY 4
#define ELF_R_RISCV_JUMP_SLOT 5
+#define ELF_R_RISCV_IRELATIVE 58
#define ELF_R_RISCV_BRANCH 16
#define ELF_R_RISCV_JAL 17
#define ELF_R_RISCV_CALL 18
diff --git a/src/obj/elf/read.c b/src/obj/elf/read.c
@@ -250,6 +250,24 @@ static Sym intern_cstr(Compiler* c, const char* s) {
return pool_intern_slice(c->global, (Slice){.s = s, .len = (u32)strlen(s)});
}
+/* ELF default-version normalization. A symbol "base@@VERSION" is the *default*
+ * version of `base`: an unversioned reference binds to it. GNU as emits the
+ * literal "@@" into a relocatable object's .symtab string (e.g. FreeBSD
+ * libc.a's openat@@FBSD_1.2 / setcontext / swapcontext). Trim to the base so
+ * kit's name-based resolution matches plain references. A single-'@'
+ * (non-default) version is left intact -- those are inert compatibility
+ * aliases (e.g. fstat@FBSD_1.0) that must NOT shadow the modern base symbol.
+ * Shared-library exports keep their version in .gnu.version_d rather than the
+ * name string, so this only fires for relocatable .symtab reads. Returns the
+ * length of the base name (== nlen when there is no "@@"). */
+static u32 elf_default_version_namelen(const char* nm, u32 nlen) {
+ u32 i;
+ if (!nm) return nlen;
+ for (i = 1; i + 1 < nlen; ++i)
+ if (nm[i] == '@' && nm[i + 1] == '@') return i;
+ return nlen;
+}
+
/* Populate the builder's ObjImage from an ET_EXEC / ET_DYN input: the
* program-header segment table (+ interp + image base), the .dynamic
* dependency view (DT_NEEDED / DT_SONAME / DT_RPATH / DT_RUNPATH), the
@@ -614,7 +632,8 @@ ObjBuilder* read_elf(Compiler* c, const char* name, const u8* data,
obj_section_ex(ob, sym, (SecKind)sec_kind, (SecSem)sec_sem, flags,
align, (u32)sh->sh_entsize, sh->sh_link, sh->sh_info);
if (id == OBJ_SEC_NONE)
- compiler_panic(c, SRCLOC_NONE, "read_elf: obj_section_ex failed for '%.*s'",
+ compiler_panic(c, SRCLOC_NONE,
+ "read_elf: obj_section_ex failed for '%.*s'",
SLICE_ARG(((Slice){.s = nm, .len = nlen})));
elf_to_obj[i] = id;
@@ -673,8 +692,8 @@ ObjBuilder* read_elf(Compiler* c, const char* name, const u8* data,
"read_elf: .symtab size %llu not a multiple of %u",
(unsigned long long)sh->sh_size, sym_size);
if (sh->sh_link >= e_shnum)
- compiler_panic(c, SRCLOC_NONE, "read_elf: .symtab sh_link %u out of range",
- sh->sh_link);
+ compiler_panic(c, SRCLOC_NONE,
+ "read_elf: .symtab sh_link %u out of range", sh->sh_link);
const ShdrRec* str_sh = &shdrs[sh->sh_link];
if (str_sh->sh_offset + str_sh->sh_size > len)
compiler_panic(c, SRCLOC_NONE, "read_elf: .strtab out of range");
@@ -699,6 +718,7 @@ ObjBuilder* read_elf(Compiler* c, const char* name, const u8* data,
u32 nlen;
const char* nm = strtab_lookup(strtab, strtab_sz, st_name, &nlen);
+ nlen = elf_default_version_namelen(nm, nlen);
Sym sn = nlen
? pool_intern_slice(c->global, (Slice){.s = nm, .len = nlen})
: 0;
@@ -881,7 +901,8 @@ ObjBuilder* read_elf_dso(Compiler* c, const char* name, const u8* data,
if (soname_out) *soname_out = 0;
if (len < ELF64_EHDR_SIZE)
- compiler_panic(c, SRCLOC_NONE, "read_elf_dso: input shorter than ELF header");
+ compiler_panic(c, SRCLOC_NONE,
+ "read_elf_dso: input shorter than ELF header");
if (data[EI_MAG0] != ELFMAG0 || data[EI_MAG1] != ELFMAG1 ||
data[EI_MAG2] != ELFMAG2 || data[EI_MAG3] != ELFMAG3)
compiler_panic(c, SRCLOC_NONE, "read_elf_dso: bad ELF magic");
@@ -892,8 +913,8 @@ ObjBuilder* read_elf_dso(Compiler* c, const char* name, const u8* data,
u16 e_type = rd_u16_le(data + 16);
if (e_type != ET_DYN)
- compiler_panic(c, SRCLOC_NONE, "read_elf_dso: expected ET_DYN, got e_type=%u",
- (u32)e_type);
+ compiler_panic(c, SRCLOC_NONE,
+ "read_elf_dso: expected ET_DYN, got e_type=%u", (u32)e_type);
u16 e_machine = rd_u16_le(data + 18);
{
@@ -937,7 +958,8 @@ ObjBuilder* read_elf_dso(Compiler* c, const char* name, const u8* data,
}
if (!dynsym_idx)
- compiler_panic(c, SRCLOC_NONE, "read_elf_dso: no SHT_DYNSYM in shared object");
+ compiler_panic(c, SRCLOC_NONE,
+ "read_elf_dso: no SHT_DYNSYM in shared object");
/* Parse PT_DYNAMIC for DT_SONAME. The .dynamic section gives us the
* dynstr to resolve the SONAME's offset; if there's no .dynamic
@@ -951,12 +973,14 @@ ObjBuilder* read_elf_dso(Compiler* c, const char* name, const u8* data,
dsh->sh_link);
const ShdrRec* str_sh = &shdrs[dsh->sh_link];
if (str_sh->sh_offset + str_sh->sh_size > len)
- compiler_panic(c, SRCLOC_NONE, "read_elf_dso: .dynamic strtab out of range");
+ compiler_panic(c, SRCLOC_NONE,
+ "read_elf_dso: .dynamic strtab out of range");
const u8* dynstr = data + str_sh->sh_offset;
u64 dynstr_sz = str_sh->sh_size;
if (dsh->sh_offset + dsh->sh_size > len)
- compiler_panic(c, SRCLOC_NONE, "read_elf_dso: .dynamic body out of range");
+ compiler_panic(c, SRCLOC_NONE,
+ "read_elf_dso: .dynamic body out of range");
const u8* dynp = data + dsh->sh_offset;
u64 dynsz = dsh->sh_size;
/* DT entries are 16 bytes: (d_tag: u64, d_un: u64). */
@@ -992,7 +1016,8 @@ ObjBuilder* read_elf_dso(Compiler* c, const char* name, const u8* data,
compiler_panic(c, SRCLOC_NONE,
"read_elf_dso: .dynsym size not multiple of entry size");
if (sh->sh_link >= e_shnum)
- compiler_panic(c, SRCLOC_NONE, "read_elf_dso: .dynsym sh_link out of range");
+ compiler_panic(c, SRCLOC_NONE,
+ "read_elf_dso: .dynsym sh_link out of range");
const ShdrRec* str_sh = &shdrs[sh->sh_link];
if (str_sh->sh_offset + str_sh->sh_size > len)
compiler_panic(c, SRCLOC_NONE, "read_elf_dso: .dynstr out of range");
diff --git a/src/obj/elf/reloc_aarch64.c b/src/obj/elf/reloc_aarch64.c
@@ -63,6 +63,10 @@ u32 elf_aarch64_reloc_to(u32 kind /* RelocKind */) {
return ELF_R_AARCH64_ADR_GOT_PAGE;
case R_AARCH64_LD64_GOT_LO12_NC:
return ELF_R_AARCH64_LD64_GOT_LO12_NC;
+ case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ return ELF_R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21;
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ return ELF_R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
return ELF_R_AARCH64_TLSLE_ADD_TPREL_HI12;
case R_AARCH64_TLSLE_ADD_TPREL_LO12:
@@ -146,6 +150,10 @@ u32 elf_aarch64_reloc_from(u32 elf_type) {
return R_AARCH64_ADR_GOT_PAGE;
case ELF_R_AARCH64_LD64_GOT_LO12_NC:
return R_AARCH64_LD64_GOT_LO12_NC;
+ case ELF_R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ return R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21;
+ case ELF_R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ return R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC;
case ELF_R_AARCH64_TLSLE_ADD_TPREL_HI12:
return R_AARCH64_TLSLE_ADD_TPREL_HI12;
case ELF_R_AARCH64_TLSLE_ADD_TPREL_LO12:
diff --git a/src/obj/format.h b/src/obj/format.h
@@ -41,6 +41,7 @@ typedef struct ObjElfArchOps {
u32 r_relative;
u32 r_glob_dat;
u32 r_jump_slot;
+ u32 r_irelative; /* R_*_IRELATIVE static-IFUNC resolver reloc (__rela_iplt). */
u32 (*reloc_to)(u32 kind);
u32 (*reloc_from)(u32 wire_type);
} ObjElfArchOps;
diff --git a/src/obj/obj.c b/src/obj/obj.c
@@ -1026,6 +1026,9 @@ const char* reloc_kind_name(RelocKind k) {
_CASE(R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC);
_CASE(R_AARCH64_TLSLE_LDST64_TPREL_LO12);
_CASE(R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC);
+ _CASE(R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21);
+ _CASE(R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC);
+ _CASE(R_AARCH64_TPOFF64);
_CASE(R_AARCH64_GLOB_DAT);
_CASE(R_AARCH64_JUMP_SLOT);
_CASE(R_AARCH64_RELATIVE);
diff --git a/src/obj/obj.h b/src/obj/obj.h
@@ -266,6 +266,17 @@ typedef enum RelocKind {
* discarded — fine for any .tls section under 16 MiB. */
R_COFF_AARCH64_SECREL_LOW12A,
R_COFF_AARCH64_SECREL_HIGH12A,
+ /* AArch64 TLS Initial-Exec. The ADRP/LDR pair loads the symbol's
+ * TP-relative offset from a GOT slot; the linker fills that slot with a
+ * 64-bit tpoff (R_AARCH64_TPOFF64) and redirects these to the slot, so they
+ * apply exactly like the regular ADR_GOT_PAGE / LD64_GOT_LO12_NC pair.
+ * Appended at the enum tail so the public KIT_RELOC_* values (object.h)
+ * keep their pinned numbering. */
+ R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21,
+ R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC,
+ /* Internal-only: a raw 64-bit AArch64/RISC-V local-exec tpoff written into
+ * a TLS GOT slot ((target - tls_vaddr) + TCB). Never appears on the wire. */
+ R_AARCH64_TPOFF64,
} RelocKind;
typedef struct Section {
diff --git a/src/obj/registry.c b/src/obj/registry.c
@@ -74,6 +74,7 @@ static const ObjElfArchOps obj_elf_arch_ops[] = {
.r_relative = ELF_R_AARCH64_RELATIVE,
.r_glob_dat = ELF_R_AARCH64_GLOB_DAT,
.r_jump_slot = ELF_R_AARCH64_JUMP_SLOT,
+ .r_irelative = ELF_R_AARCH64_IRELATIVE,
.reloc_to = elf_aarch64_reloc_to,
.reloc_from = elf_aarch64_reloc_from,
},
@@ -87,6 +88,7 @@ static const ObjElfArchOps obj_elf_arch_ops[] = {
.r_relative = ELF_R_X86_64_RELATIVE,
.r_glob_dat = ELF_R_X86_64_GLOB_DAT,
.r_jump_slot = ELF_R_X86_64_JUMP_SLOT,
+ .r_irelative = ELF_R_X86_64_IRELATIVE,
.reloc_to = elf_x86_64_reloc_to,
.reloc_from = elf_x86_64_reloc_from,
},
@@ -100,6 +102,7 @@ static const ObjElfArchOps obj_elf_arch_ops[] = {
.r_relative = ELF_R_RISCV_RELATIVE,
.r_glob_dat = ELF_R_RISCV_64,
.r_jump_slot = ELF_R_RISCV_JUMP_SLOT,
+ .r_irelative = ELF_R_RISCV_IRELATIVE,
.reloc_to = elf_riscv64_reloc_to,
.reloc_from = elf_riscv64_reloc_from,
},
@@ -117,11 +120,12 @@ static const ObjElfArchOps obj_elf_arch_ops[] = {
.r_relative = ELF_R_RISCV_RELATIVE,
.r_glob_dat = ELF_R_RISCV_32,
.r_jump_slot = ELF_R_RISCV_JUMP_SLOT,
+ .r_irelative = ELF_R_RISCV_IRELATIVE,
.reloc_to = elf_riscv32_reloc_to,
.reloc_from = elf_riscv32_reloc_from,
},
#endif
-#if !KIT_ARCH_AA64_ENABLED && !KIT_ARCH_X64_ENABLED && \
+#if !KIT_ARCH_AA64_ENABLED && !KIT_ARCH_X64_ENABLED && \
!KIT_ARCH_RV64_ENABLED && !KIT_ARCH_RV32_ENABLED
{.arch = KIT_ARCH_WASM},
#endif
diff --git a/src/obj/reloc_apply.c b/src/obj/reloc_apply.c
@@ -96,6 +96,7 @@ void link_reloc_apply(Compiler* c, RelocKind k, u8* P_bytes, u64 S, i64 A,
}
case R_ABS64:
case R_X64_TPOFF64:
+ case R_AARCH64_TPOFF64:
case R_X64_RELATIVE: {
/* R_X64_RELATIVE: (S + A) — for static-with-relocs paths the
* linker writes the relocated value directly; the dynamic
@@ -123,7 +124,12 @@ void link_reloc_apply(Compiler* c, RelocKind k, u8* P_bytes, u64 S, i64 A,
case R_X64_GOTPCREL:
case R_X64_GOTPCRELX:
case R_X64_REX_GOTPCRELX:
- case R_X64_GOTPC32: {
+ case R_X64_GOTPC32:
+ case R_X64_GOTTPOFF: {
+ /* GOTTPOFF (TLS Initial-Exec) is a RIP-relative load of a GOT slot
+ * that the linker fills with the symbol's TP-relative offset; the
+ * fixup is identical to GOTPCREL once the target has been redirected
+ * to that slot (see link_layout_got). */
/* AArch64 ELF: PREL32 maps to either of these; both encode a
* 32-bit signed PC-relative displacement. The kit-canonical
* distinction (section-relative vs PC-relative) collapses on
@@ -189,7 +195,8 @@ void link_reloc_apply(Compiler* c, RelocKind k, u8* P_bytes, u64 S, i64 A,
if (disp & 3)
compiler_panic(c, SRCLOC_NONE, "link: TSTBR14 misaligned displacement");
if (disp < -(i64)(1 << 15) || disp >= (i64)(1 << 15))
- compiler_panic(c, SRCLOC_NONE, "link: TSTBR14 out of range (need ±32KiB)");
+ compiler_panic(c, SRCLOC_NONE,
+ "link: TSTBR14 out of range (need ±32KiB)");
imm14 = (u32)((disp >> 2) & 0x3fffu);
instr = rd_u32_le(P_bytes);
instr = (instr & ~(0x3fffu << 5)) | (imm14 << 5);
@@ -223,7 +230,8 @@ void link_reloc_apply(Compiler* c, RelocKind k, u8* P_bytes, u64 S, i64 A,
if (disp & 3)
compiler_panic(c, SRCLOC_NONE, "link: CALL26 misaligned displacement");
if (disp < -(i64)(1 << 27) || disp >= (i64)(1 << 27))
- compiler_panic(c, SRCLOC_NONE, "link: CALL26 out of range (need ±128MiB)");
+ compiler_panic(c, SRCLOC_NONE,
+ "link: CALL26 out of range (need ±128MiB)");
imm26 = (u32)((disp >> 2) & 0x3ffffffu);
instr = rd_u32_le(P_bytes);
instr = (instr & 0xfc000000u) | imm26;
@@ -232,6 +240,7 @@ void link_reloc_apply(Compiler* c, RelocKind k, u8* P_bytes, u64 S, i64 A,
}
case R_AARCH64_TLVP_LOAD_PAGE21:
case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_ADR_PREL_PG_HI21_NC: {
/* ADRP — page-relative imm21, encoded as immlo[30:29] +
@@ -288,6 +297,7 @@ void link_reloc_apply(Compiler* c, RelocKind k, u8* P_bytes, u64 S, i64 A,
case R_AARCH64_LDST64_ABS_LO12_NC:
case R_AARCH64_LDST128_ABS_LO12_NC:
case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
case R_AARCH64_TLVP_LOAD_PAGEOFF12: {
/* LDR/STR with imm12 at bits [21:10]; the imm is scaled by the
* access size, so we right-shift the low 12 bits of (S+A) by
@@ -300,6 +310,7 @@ void link_reloc_apply(Compiler* c, RelocKind k, u8* P_bytes, u64 S, i64 A,
: (k == R_AARCH64_LDST32_ABS_LO12_NC) ? 2u
: (k == R_AARCH64_LDST64_ABS_LO12_NC ||
k == R_AARCH64_LD64_GOT_LO12_NC ||
+ k == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC ||
k == R_AARCH64_TLVP_LOAD_PAGEOFF12)
? 3u
: 4u;
@@ -330,7 +341,8 @@ void link_reloc_apply(Compiler* c, RelocKind k, u8* P_bytes, u64 S, i64 A,
return;
}
case R_RV_PCREL_HI20:
- case R_RV_GOT_HI20: {
+ case R_RV_GOT_HI20:
+ case R_RV_TLS_GOT_HI20: {
/* AUIPC pc-relative HI20: same encoding as HI20 but the
* displacement is (S + A) - P. The paired PCREL_LO12 reloc at
* the ADDI/load below recovers the low 12 bits of the same
@@ -375,7 +387,8 @@ void link_reloc_apply(Compiler* c, RelocKind k, u8* P_bytes, u64 S, i64 A,
u32 instr;
u32 b;
if (disp & 1)
- compiler_panic(c, SRCLOC_NONE, "link: RV BRANCH misaligned displacement");
+ compiler_panic(c, SRCLOC_NONE,
+ "link: RV BRANCH misaligned displacement");
if (disp < -(i64)(1 << 12) || disp >= (i64)(1 << 12))
compiler_panic(c, SRCLOC_NONE,
"link: RV BRANCH out of range (need ±4KiB)");
@@ -400,7 +413,8 @@ void link_reloc_apply(Compiler* c, RelocKind k, u8* P_bytes, u64 S, i64 A,
if (disp & 1)
compiler_panic(c, SRCLOC_NONE, "link: RV JAL misaligned displacement");
if (disp < -(i64)(1 << 20) || disp >= (i64)(1 << 20))
- compiler_panic(c, SRCLOC_NONE, "link: RV JAL out of range (need ±1MiB)");
+ compiler_panic(c, SRCLOC_NONE,
+ "link: RV JAL out of range (need ±1MiB)");
b = (u32)((u64)disp & 0x1ffffeu) | ((u32)(((u64)disp >> 11) & 1u) << 11) |
((u32)(((u64)disp >> 20) & 1u) << 20);
instr = rd_u32_le(P_bytes);
@@ -429,7 +443,8 @@ void link_reloc_apply(Compiler* c, RelocKind k, u8* P_bytes, u64 S, i64 A,
u32 auipc = rd_u32_le(P_bytes);
u32 jalr = rd_u32_le(P_bytes + 4);
if (disp < -(i64)(1ll << 31) || disp >= (i64)(1ll << 31))
- compiler_panic(c, SRCLOC_NONE, "link: RV CALL out of range (need ±2GiB)");
+ compiler_panic(c, SRCLOC_NONE,
+ "link: RV CALL out of range (need ±2GiB)");
auipc = (auipc & 0x00000fffu) | (hi20 << 12);
jalr = (jalr & 0x000fffffu) | (lo12 << 20);
wr_u32_le(P_bytes, auipc);