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
|
return a64wordLE(uint32(immFromOperand(ops[0]))), nil
|
||||||
case "B":
|
case "B":
|
||||||
return encodeARM64Branch(mnem, ops, pc, offsets, false, resolve)
|
return encodeARM64Branch(mnem, ops, pc, offsets, false, relocs, resolve)
|
||||||
case "BL", "CALL":
|
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",
|
case "MOV", "MOVD", "MOVW", "MOVWU", "MOVH", "MOVHU", "MOVB", "MOVBU",
|
||||||
"FMOVS", "FMOVD":
|
"FMOVS", "FMOVD":
|
||||||
return encodeARM64Mov(instr, mnem, fi, relocs)
|
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 ----
|
// ---- branch encoding ----
|
||||||
|
|
||||||
// encodeARM64Branch encodes an unconditional branch (B/BL) to a label.
|
// 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 {
|
if len(ops) != 1 {
|
||||||
return nil, fmt.Errorf("%s expects 1 operand, got %d", mnem, len(ops))
|
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).
|
// External symbol reference: BL sym(SB).
|
||||||
if link && op.Addr.Sym != nil && op.Addr.Sym.Pseudo == "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.
|
// Emit BL with zero offset; the linker fills in the target.
|
||||||
return a64wordLE(a64Branch(1, 0)), nil
|
return a64wordLE(a64Branch(1, 0)), nil
|
||||||
}
|
}
|
||||||
@@ -1324,5 +1333,6 @@ func AssembleFileARM64(f *ast.File) (*Image, error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
markExternals(img, dataSyms)
|
||||||
return img, nil
|
return img, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-3
@@ -16,6 +16,7 @@ const (
|
|||||||
// AArch64 relocation types (the ELF psABI).
|
// AArch64 relocation types (the ELF psABI).
|
||||||
rArm64PrelPgHi21 = 275 // R_AARCH64_ADR_PREL_PG_HI21 (ADRP page)
|
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/STR/LDR page offset)
|
||||||
|
rArm64Call26 = 283 // R_AARCH64_CALL26 (BL instruction)
|
||||||
)
|
)
|
||||||
|
|
||||||
// ELFAARCH64Object returns the image as an ELF64 relocatable object file for
|
// ELFAARCH64Object returns the image as an ELF64 relocatable object file for
|
||||||
@@ -94,10 +95,14 @@ func (img *Image) ELFAARCH64Object() ([]byte, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("relocation references unknown symbol %q", r.Name)
|
return nil, fmt.Errorf("relocation references unknown symbol %q", r.Name)
|
||||||
}
|
}
|
||||||
typ := uint32(rArm64PrelPgHi21)
|
var typ uint32
|
||||||
if r.Kind == RelArm64Addr && r.Off%4 == 4 {
|
switch {
|
||||||
// The second instruction in an ADRP pair uses ADD_ABS_LO12_NC.
|
case r.Kind == RelArm64Branch:
|
||||||
|
typ = rArm64Call26
|
||||||
|
case r.Kind == RelArm64Addr && r.Off%4 == 4:
|
||||||
typ = rArm64AddAbsLo12NC
|
typ = rArm64AddAbsLo12NC
|
||||||
|
default:
|
||||||
|
typ = rArm64PrelPgHi21
|
||||||
}
|
}
|
||||||
relas = append(relas, elfRela{
|
relas = append(relas, elfRela{
|
||||||
off: uint64(fn.Offset + r.Off),
|
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 nil, err
|
||||||
}
|
}
|
||||||
return img.emitGOObject(pkgPath, srcPath, pre, 4, func(r Reloc) (uint16, uint8) {
|
return img.emitGOObject(pkgPath, srcPath, pre, 4, func(r Reloc) (uint16, uint8) {
|
||||||
|
if r.Kind == RelArm64Branch {
|
||||||
|
return relocArm64Branch, 4
|
||||||
|
}
|
||||||
return relocArm64Addr, 4
|
return relocArm64Addr, 4
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// arm64 relocation types (cmd/internal/objabi). R_ADDRARM64 resolves an
|
// arm64 relocation types (cmd/internal/objabi).
|
||||||
// ADRP+ADD/LDR/STR pair to a symbol's address.
|
|
||||||
const (
|
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
|
// toolchainObjectPreambleAARCH64 returns the "go object ...\n!\n" header
|
||||||
|
|||||||
+31
@@ -97,6 +97,7 @@ const (
|
|||||||
RelLoong64AddrHi // R_LOONG64_ADDR_HI (pcalau12i)
|
RelLoong64AddrHi // R_LOONG64_ADDR_HI (pcalau12i)
|
||||||
RelLoong64AddrLo // R_LOONG64_ADDR_LO (addi.d/ld/st)
|
RelLoong64AddrLo // R_LOONG64_ADDR_LO (addi.d/ld/st)
|
||||||
RelArm64Addr // R_ADDRARM64 (ADRP + ADD/LDR/STR pair)
|
RelArm64Addr // R_ADDRARM64 (ADRP + ADD/LDR/STR pair)
|
||||||
|
RelArm64Branch // R_CALLARM64 (BL instruction)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Reloc struct {
|
type Reloc struct {
|
||||||
@@ -302,6 +303,7 @@ func AssembleFileRISCV(f *ast.File) (*Image, error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
markExternals(img, dataSyms)
|
||||||
return img, nil
|
return img, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,9 +375,38 @@ func AssembleFileLOONG64(f *ast.File) (*Image, error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
markExternals(img, dataSyms)
|
||||||
return img, nil
|
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.
|
// dataSym is one GLOBL symbol and its DATA initialiser.
|
||||||
type dataSym struct {
|
type dataSym struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
Reference in New Issue
Block a user