fix(asm): add cross-package GOOBJ resolution for riscv64, loong64, arm64
Assisted-by: MiMo V2.5 Pro
This commit is contained in:
+13
-3
@@ -192,9 +192,9 @@ func encodeARM64Instr(instr *ast.Instr, pc int, offsets map[string]int, fi arm64
|
||||
}
|
||||
return a64wordLE(uint32(immFromOperand(ops[0]))), nil
|
||||
case "B":
|
||||
return encodeARM64Branch(mnem, ops, pc, offsets, false, resolve)
|
||||
return encodeARM64Branch(mnem, ops, pc, offsets, false, relocs, resolve)
|
||||
case "BL", "CALL":
|
||||
return encodeARM64Branch(mnem, ops, pc, offsets, true, resolve)
|
||||
return encodeARM64Branch(mnem, ops, pc, offsets, true, relocs, resolve)
|
||||
case "MOV", "MOVD", "MOVW", "MOVWU", "MOVH", "MOVHU", "MOVB", "MOVBU",
|
||||
"FMOVS", "FMOVD":
|
||||
return encodeARM64Mov(instr, mnem, fi, relocs)
|
||||
@@ -300,7 +300,7 @@ func encodeARM64Instr(instr *ast.Instr, pc int, offsets map[string]int, fi arm64
|
||||
// ---- branch encoding ----
|
||||
|
||||
// encodeARM64Branch encodes an unconditional branch (B/BL) to a label.
|
||||
func encodeARM64Branch(mnem string, ops []*ast.Operand, pc int, offsets map[string]int, link bool, resolve func(string) string) ([]byte, error) {
|
||||
func encodeARM64Branch(mnem string, ops []*ast.Operand, pc int, offsets map[string]int, link bool, relocs *[]Reloc, resolve func(string) string) ([]byte, error) {
|
||||
if len(ops) != 1 {
|
||||
return nil, fmt.Errorf("%s expects 1 operand, got %d", mnem, len(ops))
|
||||
}
|
||||
@@ -308,6 +308,15 @@ func encodeARM64Branch(mnem string, ops []*ast.Operand, pc int, offsets map[stri
|
||||
|
||||
// External symbol reference: BL sym(SB).
|
||||
if link && op.Addr.Sym != nil && op.Addr.Sym.Pseudo == "SB" {
|
||||
if relocs != nil {
|
||||
*relocs = append(*relocs, Reloc{
|
||||
Off: 0,
|
||||
After: 4,
|
||||
Name: op.Addr.Sym.Name,
|
||||
Addend: op.Addr.Sym.Offset,
|
||||
Kind: RelArm64Branch,
|
||||
})
|
||||
}
|
||||
// Emit BL with zero offset; the linker fills in the target.
|
||||
return a64wordLE(a64Branch(1, 0)), nil
|
||||
}
|
||||
@@ -1324,5 +1333,6 @@ func AssembleFileARM64(f *ast.File) (*Image, error) {
|
||||
})
|
||||
}
|
||||
|
||||
markExternals(img, dataSyms)
|
||||
return img, nil
|
||||
}
|
||||
|
||||
+8
-3
@@ -16,6 +16,7 @@ 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)
|
||||
rArm64Call26 = 283 // R_AARCH64_CALL26 (BL instruction)
|
||||
)
|
||||
|
||||
// ELFAARCH64Object returns the image as an ELF64 relocatable object file for
|
||||
@@ -94,10 +95,14 @@ func (img *Image) ELFAARCH64Object() ([]byte, error) {
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("relocation references unknown symbol %q", r.Name)
|
||||
}
|
||||
typ := uint32(rArm64PrelPgHi21)
|
||||
if r.Kind == RelArm64Addr && r.Off%4 == 4 {
|
||||
// The second instruction in an ADRP pair uses ADD_ABS_LO12_NC.
|
||||
var typ uint32
|
||||
switch {
|
||||
case r.Kind == RelArm64Branch:
|
||||
typ = rArm64Call26
|
||||
case r.Kind == RelArm64Addr && r.Off%4 == 4:
|
||||
typ = rArm64AddAbsLo12NC
|
||||
default:
|
||||
typ = rArm64PrelPgHi21
|
||||
}
|
||||
relas = append(relas, elfRela{
|
||||
off: uint64(fn.Offset + r.Off),
|
||||
|
||||
+6
-3
@@ -24,14 +24,17 @@ func (img *Image) GOObjectAARCH64(pkgPath, srcPath string) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
return img.emitGOObject(pkgPath, srcPath, pre, 4, func(r Reloc) (uint16, uint8) {
|
||||
if r.Kind == RelArm64Branch {
|
||||
return relocArm64Branch, 4
|
||||
}
|
||||
return relocArm64Addr, 4
|
||||
})
|
||||
}
|
||||
|
||||
// arm64 relocation types (cmd/internal/objabi). R_ADDRARM64 resolves an
|
||||
// ADRP+ADD/LDR/STR pair to a symbol's address.
|
||||
// arm64 relocation types (cmd/internal/objabi).
|
||||
const (
|
||||
relocArm64Addr = 9 // R_ADDRARM64
|
||||
relocArm64Addr = 3 // R_ADDRARM64 — ADRP+ADD/LDR/STR pair
|
||||
relocArm64Branch = 9 // R_CALLARM64 — BL instruction
|
||||
)
|
||||
|
||||
// toolchainObjectPreambleAARCH64 returns the "go object ...\n!\n" header
|
||||
|
||||
+31
@@ -97,6 +97,7 @@ const (
|
||||
RelLoong64AddrHi // R_LOONG64_ADDR_HI (pcalau12i)
|
||||
RelLoong64AddrLo // R_LOONG64_ADDR_LO (addi.d/ld/st)
|
||||
RelArm64Addr // R_ADDRARM64 (ADRP + ADD/LDR/STR pair)
|
||||
RelArm64Branch // R_CALLARM64 (BL instruction)
|
||||
)
|
||||
|
||||
type Reloc struct {
|
||||
@@ -302,6 +303,7 @@ func AssembleFileRISCV(f *ast.File) (*Image, error) {
|
||||
})
|
||||
}
|
||||
|
||||
markExternals(img, dataSyms)
|
||||
return img, nil
|
||||
}
|
||||
|
||||
@@ -373,9 +375,38 @@ func AssembleFileLOONG64(f *ast.File) (*Image, error) {
|
||||
})
|
||||
}
|
||||
|
||||
markExternals(img, dataSyms)
|
||||
return img, nil
|
||||
}
|
||||
|
||||
// markExternals identifies relocations that reference symbols not defined in
|
||||
// the file (neither a GLOBL/DATA symbol nor a TEXT function) and records them
|
||||
// as external. The non-amd64 architectures emit relocations for every SB
|
||||
// reference; this post-processing step distinguishes file-local from external.
|
||||
func markExternals(img *Image, dataSyms []dataSym) {
|
||||
known := make(map[string]bool, len(dataSyms)+len(img.Funcs))
|
||||
for _, d := range dataSyms {
|
||||
known[d.name] = true
|
||||
}
|
||||
for _, fn := range img.Funcs {
|
||||
known[fn.Name] = true
|
||||
}
|
||||
externals := map[string]bool{}
|
||||
for i := range img.Funcs {
|
||||
for j := range img.Funcs[i].Relocs {
|
||||
r := &img.Funcs[i].Relocs[j]
|
||||
if !known[r.Name] {
|
||||
r.External = true
|
||||
externals[r.Name] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
for name := range externals {
|
||||
img.Externals = append(img.Externals, name)
|
||||
}
|
||||
sort.Strings(img.Externals)
|
||||
}
|
||||
|
||||
// dataSym is one GLOBL symbol and its DATA initialiser.
|
||||
type dataSym struct {
|
||||
name string
|
||||
|
||||
Reference in New Issue
Block a user