fix(asm): encode RISC-V CALL sym(SB) as JAL
Assisted-by: DeepSeek V4 Pro
This commit is contained in:
+86
-4
@@ -5,6 +5,7 @@ package asm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -15,10 +16,64 @@ import (
|
||||
"sourcedock.dev/petrbalvin/gasm-devkit/parser"
|
||||
)
|
||||
|
||||
// TestGOObjectRISCVStructure checks the emitted RISC-V object's relocations:
|
||||
// each AUIPC + second-instruction pair carries a single 8-byte
|
||||
// R_RISCV_PCREL_ITYPE/STYPE relocation, exactly as `go tool asm` models it
|
||||
// (rather than the ELF HI20/LO12 pair).
|
||||
// TestGOObjectRISCVCallReloc checks that CALL sym(SB) emits a single JAL
|
||||
// instruction carrying an R_RISCV_JAL relocation (4-byte field) in both the
|
||||
// GOOBJ and ELF object emitters.
|
||||
func TestGOObjectRISCVCallReloc(t *testing.T) {
|
||||
f, errs := parser.Parse("k_riscv64.s", `
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·c(SB), NOSPLIT, $0-0
|
||||
CALL callee<>(SB)
|
||||
RET
|
||||
|
||||
GLOBL callee<>(SB), RODATA, $8
|
||||
DATA callee<>+0(SB)/8, $42
|
||||
`)
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("parse: %v", errs)
|
||||
}
|
||||
img, err := AssembleFileRISCV(f)
|
||||
if err != nil {
|
||||
t.Fatalf("AssembleFileRISCV: %v", err)
|
||||
}
|
||||
fn := img.Funcs[0]
|
||||
if len(fn.Relocs) != 1 {
|
||||
t.Fatalf("relocs = %d, want 1", len(fn.Relocs))
|
||||
}
|
||||
r := fn.Relocs[0]
|
||||
if r.Kind != RelRISCVJal || r.Off != 8 || r.After != 12 || r.Name != "callee" || r.Addend != 0 || r.External {
|
||||
t.Errorf("reloc = {kind %v off %d after %d name %q addend %d external %v}", r.Kind, r.Off, r.After, r.Name, r.Addend, r.External)
|
||||
}
|
||||
|
||||
obj, err := img.GOObjectRISCV("testpkg", "k_riscv64.s")
|
||||
if err != nil {
|
||||
t.Fatalf("GOObjectRISCV: %v", err)
|
||||
}
|
||||
v := openGoobj(t, obj)
|
||||
relocIdx := v.blk(blkRelocIdx)
|
||||
relocs := v.blk(blkReloc)
|
||||
// The function is the last non-package symbol: 4 package defs, then the
|
||||
// 4 pc tables and the function.
|
||||
first := int(binary.LittleEndian.Uint32(relocIdx[(4+4)*4:]))
|
||||
if (first+1)*23 > len(relocs) {
|
||||
t.Fatalf("reloc block too short: first=%d len=%d", first, len(relocs))
|
||||
}
|
||||
e := relocs[first*23:]
|
||||
le := binary.LittleEndian
|
||||
if int32(le.Uint32(e[0:])) != 8 || e[4] != 4 || le.Uint16(e[5:]) != relocRISCVJal || le.Uint32(e[15:]) != pkgIdxSelf || le.Uint32(e[19:]) != 0 {
|
||||
t.Errorf("GOOBJ reloc = off %d size %d type %d pkg %d sym %d", int32(le.Uint32(e[0:])), e[4], le.Uint16(e[5:]), le.Uint32(e[15:]), le.Uint32(e[19:]))
|
||||
}
|
||||
|
||||
// The ELF object must carry a single R_RISCV_JAL relocation in .rela.text.
|
||||
elfObj, err := img.ELFRISCVObject()
|
||||
if err != nil {
|
||||
t.Fatalf("ELFRISCVObject: %v", err)
|
||||
}
|
||||
if !hasELFRISCVJAL(t, elfObj) {
|
||||
t.Error("ELF object missing R_RISCV_JAL relocation")
|
||||
}
|
||||
}
|
||||
func TestGOObjectRISCVStructure(t *testing.T) {
|
||||
f, errs := parser.Parse("k_riscv64.s", `
|
||||
#include "textflag.h"
|
||||
@@ -262,3 +317,30 @@ func main() {
|
||||
t.Errorf("main.add not found in linked binary:\n%s", nmOut)
|
||||
}
|
||||
}
|
||||
|
||||
// hasELFRISCVJAL reports whether the ELF object carries an R_RISCV_JAL
|
||||
// relocation in its .rela.text section.
|
||||
func hasELFRISCVJAL(t *testing.T, data []byte) bool {
|
||||
t.Helper()
|
||||
f, err := elf.NewFile(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
t.Fatalf("parse ELF: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
rela := f.Section(".rela.text")
|
||||
if rela == nil {
|
||||
return false
|
||||
}
|
||||
b, err := rela.Data()
|
||||
if err != nil {
|
||||
t.Fatalf(".rela.text data: %v", err)
|
||||
}
|
||||
const rRISCVJAL = 17
|
||||
for i := 0; i+24 <= len(b); i += 24 {
|
||||
info := binary.LittleEndian.Uint64(b[i+8:])
|
||||
if uint32(info) == rRISCVJAL {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user