fix(asm): make arm64 and loong64 relocations match the toolchain

This commit is contained in:
2026-09-14 18:22:00 +02:00
parent c6f0286732
commit 953c258d6a
9 changed files with 286 additions and 45 deletions
+12 -3
View File
@@ -15,8 +15,9 @@ const (
// AArch64 relocation types (the ELF psABI).
rArm64PrelPgHi21 = 275 // R_AARCH64_ADR_PREL_PG_HI21 (ADRP page)
rArm64AddAbsLo12NC = 277 // R_AARCH64_ADD_ABS_LO12_NC (ADD/STR/LDR page offset)
rArm64AddAbsLo12NC = 277 // R_AARCH64_ADD_ABS_LO12_NC (ADD page offset)
rArm64Call26 = 283 // R_AARCH64_CALL26 (BL instruction)
rArm64Ldst64Lo12NC = 286 // R_AARCH64_LDST64_ABS_LO12_NC (64-bit LDR/STR page offset)
)
// ELFAARCH64Object returns the image as an ELF64 relocatable object file for
@@ -81,7 +82,13 @@ func (img *Image) ELFAARCH64Object() ([]byte, error) {
// Build relocations. Each SB reference is an ADRP pair:
// ADRP Rd, 0 → R_AARCH64_ADR_PREL_PG_HI21
// ADD/LDR/STR → R_AARCH64_ADD_ABS_LO12_NC
// ADD → R_AARCH64_ADD_ABS_LO12_NC
// LDR/STR X → R_AARCH64_LDST64_ABS_LO12_NC
// BL → R_AARCH64_CALL26
// Addends stay raw: ADR_PREL_PG_HI21 and the ABS_LO12_NC forms resolve
// against S+A, and CALL26 branches take the branch instruction's own
// place as the PC-relative base, so subtracting the field width (the
// amd64 R_PCREL convention) would misplace every branch by 4 bytes.
type elfRela struct {
off uint64
typ uint32
@@ -99,6 +106,8 @@ func (img *Image) ELFAARCH64Object() ([]byte, error) {
switch {
case r.Kind == RelArm64Branch:
typ = rArm64Call26
case r.Kind == RelArm64LDST64 && r.Off%4 == 4:
typ = rArm64Ldst64Lo12NC
case r.Kind == RelArm64Addr && r.Off%4 == 4:
typ = rArm64AddAbsLo12NC
default:
@@ -108,7 +117,7 @@ func (img *Image) ELFAARCH64Object() ([]byte, error) {
off: uint64(fn.Offset + r.Off),
typ: typ,
sym: idx,
addend: r.Addend - int64(r.After-r.Off),
addend: r.Addend,
})
}
}