fix(asm): add cross-package GOOBJ resolution for riscv64, loong64, arm64

Assisted-by: MiMo V2.5 Pro
This commit is contained in:
2026-08-21 00:35:21 +02:00
parent cc50035375
commit ae550cc05a
4 changed files with 58 additions and 9 deletions
+13 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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