feat(asm): resolve external GOOBJ symbols from archive data
This commit is contained in:
+47
-4
@@ -213,16 +213,50 @@ func (img *Image) GOObject(pkgPath, srcPath string) ([]byte, error) {
|
||||
})
|
||||
}
|
||||
|
||||
// Resolve external symbol references (cross-package). Build the
|
||||
// package index table and determine each external symbol's SymIdx
|
||||
// by reading the target package's export data.
|
||||
var extPkgTable []string
|
||||
var extPkgIdx map[string]int
|
||||
var extSymIdx map[string]int
|
||||
if len(img.Externals) > 0 {
|
||||
var err error
|
||||
extPkgTable, extPkgIdx, extSymIdx, err = resolveExternalSymbols(img.Externals)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GOOBJ emission: resolving external symbols: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Relocations, per defined symbol in definition order (package defs,
|
||||
// then non-package defs). Only file-local GLOBL references resolve;
|
||||
// external symbols need the import machinery of a later increment.
|
||||
// then non-package defs).
|
||||
nsyms := len(defs) + len(nps)
|
||||
symRelocs := make([][]byte, nsyms) // flat 23-byte records
|
||||
for i, fn := range img.Funcs {
|
||||
si := len(defs) + fnNpIdx[i]
|
||||
for _, r := range fn.Relocs {
|
||||
if r.External {
|
||||
return nil, fmt.Errorf("GOOBJ emission: external symbol %q is not supported yet", r.Name)
|
||||
// Split package-qualified name: "runtime·morestack" → runtime, morestack.
|
||||
pkg, name := splitQualified(r.Name)
|
||||
if pkg == "" {
|
||||
return nil, fmt.Errorf("GOOBJ emission: external symbol %q has no package prefix", r.Name)
|
||||
}
|
||||
pIdx, ok := extPkgIdx[pkg]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("GOOBJ emission: package %q not resolved", pkg)
|
||||
}
|
||||
sIdx, ok := extSymIdx[pkg+"·"+name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("GOOBJ emission: symbol %s·%s not resolved", pkg, name)
|
||||
}
|
||||
var rec [23]byte
|
||||
binary.LittleEndian.PutUint32(rec[0:], uint32(int32(r.Off)))
|
||||
rec[4] = 4 // field width
|
||||
binary.LittleEndian.PutUint16(rec[5:], relocPCRel)
|
||||
binary.LittleEndian.PutUint64(rec[7:], uint64(r.Addend))
|
||||
binary.LittleEndian.PutUint32(rec[15:], uint32(pIdx))
|
||||
binary.LittleEndian.PutUint32(rec[19:], uint32(sIdx))
|
||||
symRelocs[si] = append(symRelocs[si], rec[:]...)
|
||||
continue
|
||||
}
|
||||
di, ok := defIdx[r.Name]
|
||||
if !ok {
|
||||
@@ -291,7 +325,16 @@ func (img *Image) GOObject(pkgPath, srcPath string) ([]byte, error) {
|
||||
for _, s := range nps {
|
||||
npdefBlk = s.sym.append(npdefBlk, strOff)
|
||||
}
|
||||
pkgIdxBlk := stringRef(nil, "") // index 0: the dummy invalid package
|
||||
|
||||
// Package index table: index 0 is the dummy invalid package.
|
||||
// External packages follow, in pkgIdx order.
|
||||
for _, pkg := range extPkgTable {
|
||||
addStr(pkg)
|
||||
}
|
||||
pkgIdxBlk := stringRef(nil, "") // index 0: dummy
|
||||
for _, pkg := range extPkgTable {
|
||||
pkgIdxBlk = stringRef(pkgIdxBlk, pkg)
|
||||
}
|
||||
fileBlk := stringRef(nil, srcPath)
|
||||
|
||||
var relocBlk, auxBlk, dataBlk []byte
|
||||
|
||||
Reference in New Issue
Block a user