]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj, cmd/link: record ABIs and aliases in Go obj files
authorAustin Clements <austin@google.com>
Fri, 26 Oct 2018 17:53:02 +0000 (13:53 -0400)
committerAustin Clements <austin@google.com>
Mon, 12 Nov 2018 20:46:48 +0000 (20:46 +0000)
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>
src/cmd/internal/goobj/read.go
src/cmd/internal/obj/link.go
src/cmd/internal/obj/objfile.go
src/cmd/internal/objabi/doc.go
src/cmd/link/internal/objfile/objfile.go
src/cmd/link/internal/sym/symbol.go

index 2d618eefa557a1c9951b559ce3cd0edc00d5cbab..2081098ca8f80c862e137474a82b4a2ed25d2ba8 100644 (file)
@@ -288,18 +288,31 @@ func (r *objReader) readSymID() SymID {
 }
 
 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
        // prefix for the package in which the object file has been found.
        // Expand it.
        name = strings.ReplaceAll(name, `"".`, r.pkgprefix)
 
-       // An individual object file only records version 0 (extern) or 1 (static).
-       // To make static symbols unique across all files being read, we
-       // replace version 1 with the version corresponding to the current
-       // file number. The number is incremented on each call to parseObject.
-       if vers != 0 {
+       // The ABI field records either the ABI or -1 for static symbols.
+       //
+       // To distinguish different static symbols with the same name,
+       // we use the symbol "version". Version 0 corresponds to
+       // 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
        }
        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
 
        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)
        }
 
@@ -602,7 +615,7 @@ func (r *objReader) parseObject(prefix []byte) error {
        }
 
        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)
        }
 
index d3721dd0234662ffd0a9bb5d922ebbc82900240d..2989831a0a63bddc833faeaeda5881138659989e 100644 (file)
@@ -432,7 +432,7 @@ const (
 )
 
 // Attribute is a set of symbol attributes.
-type Attribute int16
+type Attribute uint16
 
 const (
        AttrDuplicateOK Attribute = 1 << iota
@@ -468,6 +468,13 @@ const (
        // For function symbols; indicates that the specified function was the
        // target of an inline during compilation
        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 }
@@ -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 {
        bit Attribute
        s   string
@@ -524,6 +537,12 @@ func (a Attribute) TextAttrString() string {
                        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 {
                s += fmt.Sprintf("UnknownAttribute(%d)|", a)
        }
@@ -606,6 +625,16 @@ type Link struct {
        // state for writing objects
        Text []*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{}) {
index 3c72f543ccb3707e18e86192c11599917e625dd6..94334d8361b5ed42f163a869f02b2ebcd3d4d96c 100644 (file)
@@ -82,7 +82,7 @@ func WriteObjFile(ctxt *Link, b *bufio.Writer) {
        w := newObjWriter(ctxt, b)
 
        // Magic header
-       w.wr.WriteString("\x00\x00go19ld")
+       w.wr.WriteString("\x00go112ld")
 
        // Version
        w.wr.WriteByte(1)
@@ -102,6 +102,10 @@ func WriteObjFile(ctxt *Link, b *bufio.Writer) {
                w.writeRefs(s)
                w.addLengths(s)
        }
+       for _, s := range ctxt.ABIAliases {
+               w.writeRefs(s)
+               w.addLengths(s)
+       }
        // End symbol references
        w.wr.WriteByte(0xff)
 
@@ -137,9 +141,12 @@ func WriteObjFile(ctxt *Link, b *bufio.Writer) {
        for _, s := range ctxt.Data {
                w.writeSym(s)
        }
+       for _, s := range ctxt.ABIAliases {
+               w.writeSym(s)
+       }
 
        // 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.
@@ -155,8 +162,12 @@ func (w *objWriter) writeRef(s *LSym, isPath bool) {
        } else {
                w.writeString(s.Name)
        }
-       // Write "version".
-       w.writeBool(s.Static())
+       // Write ABI/static information.
+       abi := int64(s.ABI())
+       if s.Static() {
+               abi = -1
+       }
+       w.writeInt(abi)
        w.nRefs++
        s.RefIdx = w.nRefs
 }
index 7bd5ff63e562c7a47ab73e18f3ab7c8bde2db242..03dc9fb88bc769157b2cd4414e843f0a607052b9 100644 (file)
@@ -22,7 +22,7 @@
 //
 // The file format is:
 //
-//     - magic header: "\x00\x00go19ld"
+//     - magic header: "\x00go112ld"
 //     - byte 1 - version number
 //     - sequence of strings giving dependencies (imported packages)
 //     - empty string (marks end of sequence)
@@ -38,7 +38,7 @@
 //     - data, the content of the defined symbols
 //     - sequence of defined symbols
 //     - byte 0xff (marks end of sequence)
-//     - magic footer: "\xff\xffgo19ld"
+//     - magic footer: "\xffgo112ld"
 //
 // All integers are stored in a zigzag varint format.
 // See golang.org/s/go12symtab for a definition.
@@ -46,7 +46,7 @@
 // Data blocks and strings are both stored as an integer
 // 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
 // reference sequence. Index 0 corresponds to a nil symbol pointer.
@@ -57,7 +57,7 @@
 //
 //     - byte 0xfe (sanity check for synchronization)
 //     - type [byte]
-//     - name & version [symref index]
+//     - name & ABI [symref index]
 //     - flags [int]
 //             1<<0 dupok
 //             1<<1 local
index 3a8923b07333f4d7004e9cf11ffd342f39db0212..77c3a7f9148c40c15430b84d96650286a514262d 100644 (file)
@@ -13,6 +13,7 @@ import (
        "bytes"
        "cmd/internal/bio"
        "cmd/internal/dwarf"
+       "cmd/internal/obj"
        "cmd/internal/objabi"
        "cmd/internal/sys"
        "cmd/link/internal/sym"
@@ -23,8 +24,8 @@ import (
 )
 
 const (
-       startmagic = "\x00\x00go19ld"
-       endmagic   = "\xff\xffgo19ld"
+       startmagic = "\x00go112ld"
+       endmagic   = "\xffgo112ld"
 )
 
 var emptyPkg = []byte(`"".`)
@@ -382,17 +383,20 @@ func (r *objReader) readRef() {
                log.Fatalf("readSym out of sync")
        }
        name := r.readSymName()
-       v := r.readInt()
-       if v != 0 && v != 1 {
-               log.Fatalf("invalid symbol version for %q: %d", name, v)
-       }
-       if v == 1 {
+       var v int
+       if abi := r.readInt(); abi == -1 {
+               // Static
                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)
        r.refs = append(r.refs, s)
 
-       if s == nil || v != 0 {
+       if s == nil || v == r.localSymVersion {
                return
        }
        if s.Name[0] == '$' && len(s.Name) > 5 && s.Type == 0 && len(s.P) == 0 {
index 4faa991463b080c2d103cbbeb84dec52c27196de..5e5fca467da2e84c01ea8f5f2ee36f6733d982b6 100644 (file)
@@ -5,6 +5,7 @@
 package sym
 
 import (
+       "cmd/internal/obj"
        "cmd/internal/objabi"
        "cmd/internal/sys"
        "debug/elf"
@@ -52,9 +53,21 @@ type AuxSymbol struct {
 }
 
 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 {
        if s.Version == 0 {
                return s.Name