mirror of
https://github.com/golang/go.git
synced 2025-05-07 08:32:59 +00:00
cmd/internal/obj, cmd/link: record ABIs and aliases in Go obj files
This repurposes the "version" field of a symbol reference in the Go object file format to be an ABI field. Currently, this is just 0 or 1 depending on whether the symbol is static (the linker turns it into a different internal version number), so it's already only tenuously a symbol version. We change this to be -1 for static symbols and otherwise by the ABI number. This also adds a separate list of ABI alias symbols to be recorded in the object file. The ABI aliases must be a separate list and not just part of the symbol definitions because it's possible to have a symbol defined in one package and the alias "defined" in a different package. For example, this can happen if a symbol is defined in assembly in one package and stubbed in a different package. The stub triggers the generation of the ABI alias, but in a different package from the definition. For #27539. Change-Id: I015c9fe54690c027de6ef77e22b5585976a01587 Reviewed-on: https://go-review.googlesource.com/c/147157 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
07544c7e80
commit
c5718b6b26
@ -288,18 +288,31 @@ func (r *objReader) readSymID() SymID {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *objReader) readRef() {
|
func (r *objReader) readRef() {
|
||||||
name, vers := r.readString(), r.readInt()
|
name, abiOrStatic := r.readString(), r.readInt()
|
||||||
|
|
||||||
// In a symbol name in an object file, "". denotes the
|
// In a symbol name in an object file, "". denotes the
|
||||||
// prefix for the package in which the object file has been found.
|
// prefix for the package in which the object file has been found.
|
||||||
// Expand it.
|
// Expand it.
|
||||||
name = strings.ReplaceAll(name, `"".`, r.pkgprefix)
|
name = strings.ReplaceAll(name, `"".`, r.pkgprefix)
|
||||||
|
|
||||||
// An individual object file only records version 0 (extern) or 1 (static).
|
// The ABI field records either the ABI or -1 for static symbols.
|
||||||
// To make static symbols unique across all files being read, we
|
//
|
||||||
// replace version 1 with the version corresponding to the current
|
// To distinguish different static symbols with the same name,
|
||||||
// file number. The number is incremented on each call to parseObject.
|
// we use the symbol "version". Version 0 corresponds to
|
||||||
if vers != 0 {
|
// global symbols, and each file has a unique version > 0 for
|
||||||
|
// all of its static symbols. The version is incremented on
|
||||||
|
// each call to parseObject.
|
||||||
|
//
|
||||||
|
// For global symbols, we currently ignore the ABI.
|
||||||
|
//
|
||||||
|
// TODO(austin): Record the ABI in SymID. Since this is a
|
||||||
|
// public API, we'll have to keep Version as 0 and record the
|
||||||
|
// ABI in a new field (which differs from how the linker does
|
||||||
|
// this, but that's okay). Show the ABI in things like
|
||||||
|
// objdump.
|
||||||
|
var vers int64
|
||||||
|
if abiOrStatic == -1 {
|
||||||
|
// Static symbol
|
||||||
vers = r.p.MaxVersion
|
vers = r.p.MaxVersion
|
||||||
}
|
}
|
||||||
r.p.SymRefs = append(r.p.SymRefs, SymID{name, vers})
|
r.p.SymRefs = append(r.p.SymRefs, SymID{name, vers})
|
||||||
@ -487,7 +500,7 @@ func (r *objReader) parseObject(prefix []byte) error {
|
|||||||
// TODO: extract OS + build ID if/when we need it
|
// TODO: extract OS + build ID if/when we need it
|
||||||
|
|
||||||
r.readFull(r.tmp[:8])
|
r.readFull(r.tmp[:8])
|
||||||
if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go19ld")) {
|
if !bytes.Equal(r.tmp[:8], []byte("\x00go112ld")) {
|
||||||
return r.error(errCorruptObject)
|
return r.error(errCorruptObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -602,7 +615,7 @@ func (r *objReader) parseObject(prefix []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
r.readFull(r.tmp[:7])
|
r.readFull(r.tmp[:7])
|
||||||
if !bytes.Equal(r.tmp[:7], []byte("\xffgo19ld")) {
|
if !bytes.Equal(r.tmp[:7], []byte("go112ld")) {
|
||||||
return r.error(errCorruptObject)
|
return r.error(errCorruptObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,7 +432,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Attribute is a set of symbol attributes.
|
// Attribute is a set of symbol attributes.
|
||||||
type Attribute int16
|
type Attribute uint16
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AttrDuplicateOK Attribute = 1 << iota
|
AttrDuplicateOK Attribute = 1 << iota
|
||||||
@ -468,6 +468,13 @@ const (
|
|||||||
// For function symbols; indicates that the specified function was the
|
// For function symbols; indicates that the specified function was the
|
||||||
// target of an inline during compilation
|
// target of an inline during compilation
|
||||||
AttrWasInlined
|
AttrWasInlined
|
||||||
|
|
||||||
|
// attrABIBase is the value at which the ABI is encoded in
|
||||||
|
// Attribute. This must be last; all bits after this are
|
||||||
|
// assumed to be an ABI value.
|
||||||
|
//
|
||||||
|
// MUST BE LAST since all bits above this comprise the ABI.
|
||||||
|
attrABIBase
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 }
|
func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 }
|
||||||
@ -493,6 +500,12 @@ func (a *Attribute) Set(flag Attribute, value bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a Attribute) ABI() ABI { return ABI(a / attrABIBase) }
|
||||||
|
func (a *Attribute) SetABI(abi ABI) {
|
||||||
|
const mask = 1 // Only one ABI bit for now.
|
||||||
|
*a = (*a &^ (mask * attrABIBase)) | Attribute(abi)*attrABIBase
|
||||||
|
}
|
||||||
|
|
||||||
var textAttrStrings = [...]struct {
|
var textAttrStrings = [...]struct {
|
||||||
bit Attribute
|
bit Attribute
|
||||||
s string
|
s string
|
||||||
@ -524,6 +537,12 @@ func (a Attribute) TextAttrString() string {
|
|||||||
a &^= x.bit
|
a &^= x.bit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
switch a.ABI() {
|
||||||
|
case ABI0:
|
||||||
|
case ABIInternal:
|
||||||
|
s += "ABIInternal|"
|
||||||
|
a.SetABI(0) // Clear ABI so we don't print below.
|
||||||
|
}
|
||||||
if a != 0 {
|
if a != 0 {
|
||||||
s += fmt.Sprintf("UnknownAttribute(%d)|", a)
|
s += fmt.Sprintf("UnknownAttribute(%d)|", a)
|
||||||
}
|
}
|
||||||
@ -606,6 +625,16 @@ type Link struct {
|
|||||||
// state for writing objects
|
// state for writing objects
|
||||||
Text []*LSym
|
Text []*LSym
|
||||||
Data []*LSym
|
Data []*LSym
|
||||||
|
|
||||||
|
// ABIAliases are text symbols that should be aliased to all
|
||||||
|
// ABIs. These symbols may only be referenced and not defined
|
||||||
|
// by this object, since the need for an alias may appear in a
|
||||||
|
// different object than the definition. Hence, this
|
||||||
|
// information can't be carried in the symbol definition.
|
||||||
|
//
|
||||||
|
// TODO(austin): Replace this with ABI wrappers once the ABIs
|
||||||
|
// actually diverge.
|
||||||
|
ABIAliases []*LSym
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctxt *Link) Diag(format string, args ...interface{}) {
|
func (ctxt *Link) Diag(format string, args ...interface{}) {
|
||||||
|
@ -82,7 +82,7 @@ func WriteObjFile(ctxt *Link, b *bufio.Writer) {
|
|||||||
w := newObjWriter(ctxt, b)
|
w := newObjWriter(ctxt, b)
|
||||||
|
|
||||||
// Magic header
|
// Magic header
|
||||||
w.wr.WriteString("\x00\x00go19ld")
|
w.wr.WriteString("\x00go112ld")
|
||||||
|
|
||||||
// Version
|
// Version
|
||||||
w.wr.WriteByte(1)
|
w.wr.WriteByte(1)
|
||||||
@ -102,6 +102,10 @@ func WriteObjFile(ctxt *Link, b *bufio.Writer) {
|
|||||||
w.writeRefs(s)
|
w.writeRefs(s)
|
||||||
w.addLengths(s)
|
w.addLengths(s)
|
||||||
}
|
}
|
||||||
|
for _, s := range ctxt.ABIAliases {
|
||||||
|
w.writeRefs(s)
|
||||||
|
w.addLengths(s)
|
||||||
|
}
|
||||||
// End symbol references
|
// End symbol references
|
||||||
w.wr.WriteByte(0xff)
|
w.wr.WriteByte(0xff)
|
||||||
|
|
||||||
@ -137,9 +141,12 @@ func WriteObjFile(ctxt *Link, b *bufio.Writer) {
|
|||||||
for _, s := range ctxt.Data {
|
for _, s := range ctxt.Data {
|
||||||
w.writeSym(s)
|
w.writeSym(s)
|
||||||
}
|
}
|
||||||
|
for _, s := range ctxt.ABIAliases {
|
||||||
|
w.writeSym(s)
|
||||||
|
}
|
||||||
|
|
||||||
// Magic footer
|
// Magic footer
|
||||||
w.wr.WriteString("\xff\xffgo19ld")
|
w.wr.WriteString("\xffgo112ld")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Symbols are prefixed so their content doesn't get confused with the magic footer.
|
// Symbols are prefixed so their content doesn't get confused with the magic footer.
|
||||||
@ -155,8 +162,12 @@ func (w *objWriter) writeRef(s *LSym, isPath bool) {
|
|||||||
} else {
|
} else {
|
||||||
w.writeString(s.Name)
|
w.writeString(s.Name)
|
||||||
}
|
}
|
||||||
// Write "version".
|
// Write ABI/static information.
|
||||||
w.writeBool(s.Static())
|
abi := int64(s.ABI())
|
||||||
|
if s.Static() {
|
||||||
|
abi = -1
|
||||||
|
}
|
||||||
|
w.writeInt(abi)
|
||||||
w.nRefs++
|
w.nRefs++
|
||||||
s.RefIdx = w.nRefs
|
s.RefIdx = w.nRefs
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
//
|
//
|
||||||
// The file format is:
|
// The file format is:
|
||||||
//
|
//
|
||||||
// - magic header: "\x00\x00go19ld"
|
// - magic header: "\x00go112ld"
|
||||||
// - byte 1 - version number
|
// - byte 1 - version number
|
||||||
// - sequence of strings giving dependencies (imported packages)
|
// - sequence of strings giving dependencies (imported packages)
|
||||||
// - empty string (marks end of sequence)
|
// - empty string (marks end of sequence)
|
||||||
@ -38,7 +38,7 @@
|
|||||||
// - data, the content of the defined symbols
|
// - data, the content of the defined symbols
|
||||||
// - sequence of defined symbols
|
// - sequence of defined symbols
|
||||||
// - byte 0xff (marks end of sequence)
|
// - byte 0xff (marks end of sequence)
|
||||||
// - magic footer: "\xff\xffgo19ld"
|
// - magic footer: "\xffgo112ld"
|
||||||
//
|
//
|
||||||
// All integers are stored in a zigzag varint format.
|
// All integers are stored in a zigzag varint format.
|
||||||
// See golang.org/s/go12symtab for a definition.
|
// See golang.org/s/go12symtab for a definition.
|
||||||
@ -46,7 +46,7 @@
|
|||||||
// Data blocks and strings are both stored as an integer
|
// Data blocks and strings are both stored as an integer
|
||||||
// followed by that many bytes.
|
// followed by that many bytes.
|
||||||
//
|
//
|
||||||
// A symbol reference is a string name followed by a version.
|
// A symbol reference is a string name followed by an ABI or -1 for static.
|
||||||
//
|
//
|
||||||
// A symbol points to other symbols using an index into the symbol
|
// A symbol points to other symbols using an index into the symbol
|
||||||
// reference sequence. Index 0 corresponds to a nil symbol pointer.
|
// reference sequence. Index 0 corresponds to a nil symbol pointer.
|
||||||
@ -57,7 +57,7 @@
|
|||||||
//
|
//
|
||||||
// - byte 0xfe (sanity check for synchronization)
|
// - byte 0xfe (sanity check for synchronization)
|
||||||
// - type [byte]
|
// - type [byte]
|
||||||
// - name & version [symref index]
|
// - name & ABI [symref index]
|
||||||
// - flags [int]
|
// - flags [int]
|
||||||
// 1<<0 dupok
|
// 1<<0 dupok
|
||||||
// 1<<1 local
|
// 1<<1 local
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"cmd/internal/bio"
|
"cmd/internal/bio"
|
||||||
"cmd/internal/dwarf"
|
"cmd/internal/dwarf"
|
||||||
|
"cmd/internal/obj"
|
||||||
"cmd/internal/objabi"
|
"cmd/internal/objabi"
|
||||||
"cmd/internal/sys"
|
"cmd/internal/sys"
|
||||||
"cmd/link/internal/sym"
|
"cmd/link/internal/sym"
|
||||||
@ -23,8 +24,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
startmagic = "\x00\x00go19ld"
|
startmagic = "\x00go112ld"
|
||||||
endmagic = "\xff\xffgo19ld"
|
endmagic = "\xffgo112ld"
|
||||||
)
|
)
|
||||||
|
|
||||||
var emptyPkg = []byte(`"".`)
|
var emptyPkg = []byte(`"".`)
|
||||||
@ -382,17 +383,20 @@ func (r *objReader) readRef() {
|
|||||||
log.Fatalf("readSym out of sync")
|
log.Fatalf("readSym out of sync")
|
||||||
}
|
}
|
||||||
name := r.readSymName()
|
name := r.readSymName()
|
||||||
v := r.readInt()
|
var v int
|
||||||
if v != 0 && v != 1 {
|
if abi := r.readInt(); abi == -1 {
|
||||||
log.Fatalf("invalid symbol version for %q: %d", name, v)
|
// Static
|
||||||
}
|
|
||||||
if v == 1 {
|
|
||||||
v = r.localSymVersion
|
v = r.localSymVersion
|
||||||
|
} else if abiver := sym.ABIToVersion(obj.ABI(abi)); abiver != -1 {
|
||||||
|
// Note that data symbols are "ABI0", which maps to version 0.
|
||||||
|
v = abiver
|
||||||
|
} else {
|
||||||
|
log.Fatalf("invalid symbol ABI for %q: %d", name, abi)
|
||||||
}
|
}
|
||||||
s := r.syms.Lookup(name, v)
|
s := r.syms.Lookup(name, v)
|
||||||
r.refs = append(r.refs, s)
|
r.refs = append(r.refs, s)
|
||||||
|
|
||||||
if s == nil || v != 0 {
|
if s == nil || v == r.localSymVersion {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.Name[0] == '$' && len(s.Name) > 5 && s.Type == 0 && len(s.P) == 0 {
|
if s.Name[0] == '$' && len(s.Name) > 5 && s.Type == 0 && len(s.P) == 0 {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package sym
|
package sym
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
"cmd/internal/objabi"
|
"cmd/internal/objabi"
|
||||||
"cmd/internal/sys"
|
"cmd/internal/sys"
|
||||||
"debug/elf"
|
"debug/elf"
|
||||||
@ -52,9 +53,21 @@ type AuxSymbol struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SymVerStatic = 10 // Minimum version used by static (file-local) syms
|
SymVerABI0 = 0
|
||||||
|
SymVerABIInternal = 1
|
||||||
|
SymVerStatic = 10 // Minimum version used by static (file-local) syms
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ABIToVersion(abi obj.ABI) int {
|
||||||
|
switch abi {
|
||||||
|
case obj.ABI0:
|
||||||
|
return SymVerABI0
|
||||||
|
case obj.ABIInternal:
|
||||||
|
return SymVerABIInternal
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Symbol) String() string {
|
func (s *Symbol) String() string {
|
||||||
if s.Version == 0 {
|
if s.Version == 0 {
|
||||||
return s.Name
|
return s.Name
|
||||||
|
Loading…
x
Reference in New Issue
Block a user