"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/loadelf"
- "cmd/link/internal/loadelfold"
"cmd/link/internal/loader"
"cmd/link/internal/loadmacho"
"cmd/link/internal/loadpe"
}
// Process cgo directives (has to be done before host object loading).
- newCgo := (ctxt.IsELF && *FlagNewLdElf) || ctxt.HeadType == objabi.Hdarwin
- ctxt.loadcgodirectives(newCgo)
+ ctxt.loadcgodirectives(ctxt.loaderSupport())
// Conditionally load host objects, or setup for external linking.
hostobjs(ctxt)
// If we have any undefined symbols in external
// objects, try to read them from the libgcc file.
any := false
- if ctxt.IsELF && *FlagNewLdElf {
+ if ctxt.loaderSupport() {
undefs := ctxt.loader.UndefinedRelocTargets(1)
if len(undefs) > 0 {
any = true
// Set up flags and special symbols depending on the platform build mode.
// This version works with loader.Loader.
func (ctxt *Link) linksetup() {
- if !*FlagNewLdElf {
- panic("should not get here, -newldelf not on")
- }
switch ctxt.BuildMode {
case BuildModeCShared, BuildModePlugin:
symIdx := ctxt.loader.LookupOrCreateSym("runtime.islibrary", 0)
magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
if magic == 0x7f454c46 { // \x7F E L F
- if *FlagNewLdElf {
- ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.Syms.IncVersion(), f, pkg, length, pn, ehdr.flags)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- ehdr.flags = flags
- ctxt.Textp2 = append(ctxt.Textp2, textp...)
- }
- return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
- } else {
- ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, flags, err := loadelfold.Load(ctxt.loader, ctxt.Arch, ctxt.Syms.IncVersion(), f, pkg, length, pn, ehdr.flags)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- ehdr.flags = flags
- ctxt.Textp = append(ctxt.Textp, textp...)
+ ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
+ textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.Syms.IncVersion(), f, pkg, length, pn, ehdr.flags)
+ if err != nil {
+ Errorf(nil, "%v", err)
+ return
}
- return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
+ ehdr.flags = flags
+ ctxt.Textp2 = append(ctxt.Textp2, textp...)
}
+ return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
}
if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
Errorf(nil, "cannot read symbols from shared library: %s", libpath)
return
}
- gcdataLocations := make(map[uint64]*sym.Symbol)
- gcdataLocations2 := make(map[uint64]loader.Sym)
+ gcdataLocations := make(map[uint64]loader.Sym)
for _, elfsym := range syms {
if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
continue
ver = sym.SymVerABIInternal
}
- if *FlagNewLdElf {
- l := ctxt.loader
- symIdx := l.LookupOrCreateSym(elfsym.Name, ver)
-
- // Because loadlib above loads all .a files before loading
- // any shared libraries, any non-dynimport symbols we find
- // that duplicate symbols already loaded should be ignored
- // (the symbols from the .a files "win").
- if l.SymType(symIdx) != 0 && l.SymType(symIdx) != sym.SDYNIMPORT {
- continue
- }
- su, s := l.MakeSymbolUpdater(symIdx)
- su.SetType(sym.SDYNIMPORT)
- l.SetSymElfType(s, elf.ST_TYPE(elfsym.Info))
- su.SetSize(int64(elfsym.Size))
- if elfsym.Section != elf.SHN_UNDEF {
- // If it's not undefined, mark the symbol as reachable
- // so as to protect it from dead code elimination,
- // even if there aren't any explicit references to it.
- // Under the previous sym.Symbol based regime this
- // wasn't necessary, but for the loader-based deadcode
- // it is definitely needed.
- //
- // FIXME: have a more general/flexible mechanism for this?
- //
- l.SetAttrReachable(s, true)
-
- // Set .File for the library that actually defines the symbol.
- l.SetSymFile(s, libpath)
-
- // The decodetype_* functions in decodetype.go need access to
- // the type data.
- sname := l.SymName(s)
- if strings.HasPrefix(sname, "type.") && !strings.HasPrefix(sname, "type..") {
- su.SetData(readelfsymboldata(ctxt, f, &elfsym))
- gcdataLocations2[elfsym.Value+2*uint64(ctxt.Arch.PtrSize)+8+1*uint64(ctxt.Arch.PtrSize)] = s
- }
- }
+ l := ctxt.loader
+ symIdx := l.LookupOrCreateSym(elfsym.Name, ver)
- // For function symbols, we don't know what ABI is
- // available, so alias it under both ABIs.
+ // Because loadlib above loads all .a files before loading
+ // any shared libraries, any non-dynimport symbols we find
+ // that duplicate symbols already loaded should be ignored
+ // (the symbols from the .a files "win").
+ if l.SymType(symIdx) != 0 && l.SymType(symIdx) != sym.SDYNIMPORT {
+ continue
+ }
+ su, s := l.MakeSymbolUpdater(symIdx)
+ su.SetType(sym.SDYNIMPORT)
+ l.SetSymElfType(s, elf.ST_TYPE(elfsym.Info))
+ su.SetSize(int64(elfsym.Size))
+ if elfsym.Section != elf.SHN_UNDEF {
+ // If it's not undefined, mark the symbol as reachable
+ // so as to protect it from dead code elimination,
+ // even if there aren't any explicit references to it.
+ // Under the previous sym.Symbol based regime this
+ // wasn't necessary, but for the loader-based deadcode
+ // it is definitely needed.
//
- // TODO(austin): This is almost certainly wrong once
- // the ABIs are actually different. We might have to
- // mangle Go function names in the .so to include the
- // ABI.
- if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && ver == 0 {
- alias := ctxt.loader.LookupOrCreateSym(elfsym.Name, sym.SymVerABIInternal)
- if l.SymType(alias) != 0 {
- continue
- }
- su, _ := l.MakeSymbolUpdater(alias)
- su.SetType(sym.SABIALIAS)
- su.AddReloc(loader.Reloc{Sym: s})
+ // FIXME: have a more general/flexible mechanism for this?
+ //
+ l.SetAttrReachable(s, true)
+
+ // Set .File for the library that actually defines the symbol.
+ l.SetSymFile(s, libpath)
+
+ // The decodetype_* functions in decodetype.go need access to
+ // the type data.
+ sname := l.SymName(s)
+ if strings.HasPrefix(sname, "type.") && !strings.HasPrefix(sname, "type..") {
+ su.SetData(readelfsymboldata(ctxt, f, &elfsym))
+ gcdataLocations[elfsym.Value+2*uint64(ctxt.Arch.PtrSize)+8+1*uint64(ctxt.Arch.PtrSize)] = s
}
- } else {
- lsym := ctxt.loader.LookupOrCreate(elfsym.Name, ver)
+ }
- // Because loadlib above loads all .a files before loading any shared
- // libraries, any non-dynimport symbols we find that duplicate symbols
- // already loaded should be ignored (the symbols from the .a files
- // "win").
- if lsym.Type != 0 && lsym.Type != sym.SDYNIMPORT {
+ // For function symbols, we don't know what ABI is
+ // available, so alias it under both ABIs.
+ //
+ // TODO(austin): This is almost certainly wrong once
+ // the ABIs are actually different. We might have to
+ // mangle Go function names in the .so to include the
+ // ABI.
+ if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && ver == 0 {
+ alias := ctxt.loader.LookupOrCreateSym(elfsym.Name, sym.SymVerABIInternal)
+ if l.SymType(alias) != 0 {
continue
}
- lsym.Type = sym.SDYNIMPORT
- lsym.SetElfType(elf.ST_TYPE(elfsym.Info))
- lsym.Size = int64(elfsym.Size)
- if elfsym.Section != elf.SHN_UNDEF {
- // Set .File for the library that actually defines the symbol.
- lsym.File = libpath
- // The decodetype_* functions in decodetype.go need access to
- // the type data.
- if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") {
- lsym.P = readelfsymboldata(ctxt, f, &elfsym)
- gcdataLocations[elfsym.Value+2*uint64(ctxt.Arch.PtrSize)+8+1*uint64(ctxt.Arch.PtrSize)] = lsym
- }
- }
- // For function symbols, we don't know what ABI is
- // available, so alias it under both ABIs.
- //
- // TODO(austin): This is almost certainly wrong once
- // the ABIs are actually different. We might have to
- // mangle Go function names in the .so to include the
- // ABI.
- if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && ver == 0 {
- alias := ctxt.loader.LookupOrCreate(elfsym.Name, sym.SymVerABIInternal)
- if alias.Type != 0 {
- continue
- }
- alias.Type = sym.SABIALIAS
- alias.R = []sym.Reloc{{Sym: lsym}}
- }
+ su, _ := l.MakeSymbolUpdater(alias)
+ su.SetType(sym.SABIALIAS)
+ su.AddReloc(loader.Reloc{Sym: s})
}
}
- gcdataAddresses := make(map[*sym.Symbol]uint64)
- gcdataAddresses2 := make(map[loader.Sym]uint64)
if ctxt.Arch.Family == sys.ARM64 {
for _, sect := range f.Sections {
if sect.Type == elf.SHT_RELA {
if t != elf.R_AARCH64_RELATIVE {
continue
}
- if *FlagNewLdElf {
- if symIdx, ok := gcdataLocations2[rela.Off]; ok {
- gcdataAddresses2[symIdx] = uint64(rela.Addend)
- }
- } else {
- if lsym, ok := gcdataLocations[rela.Off]; ok {
- gcdataAddresses[lsym] = uint64(rela.Addend)
- }
- }
}
}
}
}
- ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, gcdataAddresses: gcdataAddresses, gcdataAddresses2: gcdataAddresses2})
+ ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f})
}
func addsection(arch *sys.Arch, seg *sym.Segment, name string, rwx int) *sym.Section {
+++ /dev/null
-// Copyright 2017 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package loadelf implements an ELF file reader.
-// This is the legacy sym.Symbol based reader, to be deprecated
-// once the loader.Loader version is completely on line.
-package loadelfold
-
-import (
- "bytes"
- "cmd/internal/bio"
- "cmd/internal/objabi"
- "cmd/internal/sys"
- "cmd/link/internal/loader"
- "cmd/link/internal/sym"
- "debug/elf"
- "encoding/binary"
- "fmt"
- "io"
- "log"
- "sort"
- "strings"
-)
-
-/*
-Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
-http://code.swtch.com/plan9port/src/tip/src/libmach/
-
- Copyright © 2004 Russ Cox.
- Portions Copyright © 2008-2010 Google Inc.
- Portions Copyright © 2010 The Go Authors.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-const (
- ElfClassNone = 0
- ElfClass32 = 1
- ElfClass64 = 2
-)
-
-const (
- ElfDataNone = 0
- ElfDataLsb = 1
- ElfDataMsb = 2
-)
-
-const (
- ElfTypeNone = 0
- ElfTypeRelocatable = 1
- ElfTypeExecutable = 2
- ElfTypeSharedObject = 3
- ElfTypeCore = 4
-)
-
-const (
- ElfMachNone = 0
- ElfMach32100 = 1
- ElfMachSparc = 2
- ElfMach386 = 3
- ElfMach68000 = 4
- ElfMach88000 = 5
- ElfMach486 = 6
- ElfMach860 = 7
- ElfMachMips = 8
- ElfMachS370 = 9
- ElfMachMipsLe = 10
- ElfMachParisc = 15
- ElfMachVpp500 = 17
- ElfMachSparc32Plus = 18
- ElfMach960 = 19
- ElfMachPower = 20
- ElfMachPower64 = 21
- ElfMachS390 = 22
- ElfMachV800 = 36
- ElfMachFr20 = 37
- ElfMachRh32 = 38
- ElfMachRce = 39
- ElfMachArm = 40
- ElfMachAlpha = 41
- ElfMachSH = 42
- ElfMachSparc9 = 43
- ElfMachAmd64 = 62
- ElfMachArm64 = 183
-)
-
-const (
- ElfAbiNone = 0
- ElfAbiSystemV = 0
- ElfAbiHPUX = 1
- ElfAbiNetBSD = 2
- ElfAbiLinux = 3
- ElfAbiSolaris = 6
- ElfAbiAix = 7
- ElfAbiIrix = 8
- ElfAbiFreeBSD = 9
- ElfAbiTru64 = 10
- ElfAbiModesto = 11
- ElfAbiOpenBSD = 12
- ElfAbiARM = 97
- ElfAbiEmbedded = 255
-)
-
-const (
- ElfSectNone = 0
- ElfSectProgbits = 1
- ElfSectSymtab = 2
- ElfSectStrtab = 3
- ElfSectRela = 4
- ElfSectHash = 5
- ElfSectDynamic = 6
- ElfSectNote = 7
- ElfSectNobits = 8
- ElfSectRel = 9
- ElfSectShlib = 10
- ElfSectDynsym = 11
- ElfSectFlagWrite = 0x1
- ElfSectFlagAlloc = 0x2
- ElfSectFlagExec = 0x4
-)
-
-const (
- ElfSymBindLocal = 0
- ElfSymBindGlobal = 1
- ElfSymBindWeak = 2
-)
-
-const (
- ElfSymTypeNone = 0
- ElfSymTypeObject = 1
- ElfSymTypeFunc = 2
- ElfSymTypeSection = 3
- ElfSymTypeFile = 4
- ElfSymTypeCommon = 5
- ElfSymTypeTLS = 6
-)
-
-const (
- ElfSymShnNone = 0
- ElfSymShnAbs = 0xFFF1
- ElfSymShnCommon = 0xFFF2
-)
-
-const (
- ElfProgNone = 0
- ElfProgLoad = 1
- ElfProgDynamic = 2
- ElfProgInterp = 3
- ElfProgNote = 4
- ElfProgShlib = 5
- ElfProgPhdr = 6
- ElfProgFlagExec = 0x1
- ElfProgFlagWrite = 0x2
- ElfProgFlagRead = 0x4
-)
-
-const (
- ElfNotePrStatus = 1
- ElfNotePrFpreg = 2
- ElfNotePrPsinfo = 3
- ElfNotePrTaskstruct = 4
- ElfNotePrAuxv = 6
- ElfNotePrXfpreg = 0x46e62b7f
-)
-
-// TODO(crawshaw): de-duplicate with cmd/link/internal/ld/elf.go.
-const (
- ELF64SYMSIZE = 24
- ELF32SYMSIZE = 16
-
- SHT_ARM_ATTRIBUTES = 0x70000003
-)
-
-type ElfHdrBytes struct {
- Ident [16]uint8
- Type [2]uint8
- Machine [2]uint8
- Version [4]uint8
- Entry [4]uint8
- Phoff [4]uint8
- Shoff [4]uint8
- Flags [4]uint8
- Ehsize [2]uint8
- Phentsize [2]uint8
- Phnum [2]uint8
- Shentsize [2]uint8
- Shnum [2]uint8
- Shstrndx [2]uint8
-}
-
-type ElfSectBytes struct {
- Name [4]uint8
- Type [4]uint8
- Flags [4]uint8
- Addr [4]uint8
- Off [4]uint8
- Size [4]uint8
- Link [4]uint8
- Info [4]uint8
- Align [4]uint8
- Entsize [4]uint8
-}
-
-type ElfProgBytes struct {
-}
-
-type ElfSymBytes struct {
- Name [4]uint8
- Value [4]uint8
- Size [4]uint8
- Info uint8
- Other uint8
- Shndx [2]uint8
-}
-
-type ElfHdrBytes64 struct {
- Ident [16]uint8
- Type [2]uint8
- Machine [2]uint8
- Version [4]uint8
- Entry [8]uint8
- Phoff [8]uint8
- Shoff [8]uint8
- Flags [4]uint8
- Ehsize [2]uint8
- Phentsize [2]uint8
- Phnum [2]uint8
- Shentsize [2]uint8
- Shnum [2]uint8
- Shstrndx [2]uint8
-}
-
-type ElfSectBytes64 struct {
- Name [4]uint8
- Type [4]uint8
- Flags [8]uint8
- Addr [8]uint8
- Off [8]uint8
- Size [8]uint8
- Link [4]uint8
- Info [4]uint8
- Align [8]uint8
- Entsize [8]uint8
-}
-
-type ElfProgBytes64 struct {
-}
-
-type ElfSymBytes64 struct {
- Name [4]uint8
- Info uint8
- Other uint8
- Shndx [2]uint8
- Value [8]uint8
- Size [8]uint8
-}
-
-type ElfSect struct {
- name string
- nameoff uint32
- type_ uint32
- flags uint64
- addr uint64
- off uint64
- size uint64
- link uint32
- info uint32
- align uint64
- entsize uint64
- base []byte
- sym *sym.Symbol
-}
-
-type ElfObj struct {
- f *bio.Reader
- base int64 // offset in f where ELF begins
- length int64 // length of ELF
- is64 int
- name string
- e binary.ByteOrder
- sect []ElfSect
- nsect uint
- nsymtab int
- symtab *ElfSect
- symstr *ElfSect
- type_ uint32
- machine uint32
- version uint32
- entry uint64
- phoff uint64
- shoff uint64
- flags uint32
- ehsize uint32
- phentsize uint32
- phnum uint32
- shentsize uint32
- shnum uint32
- shstrndx uint32
-}
-
-type ElfSym struct {
- name string
- value uint64
- size uint64
- bind uint8
- type_ uint8
- other uint8
- shndx uint16
- sym *sym.Symbol
-}
-
-var ElfMagic = [4]uint8{0x7F, 'E', 'L', 'F'}
-
-const (
- TagFile = 1
- TagCPUName = 4
- TagCPURawName = 5
- TagCompatibility = 32
- TagNoDefaults = 64
- TagAlsoCompatibleWith = 65
- TagABIVFPArgs = 28
-)
-
-type elfAttribute struct {
- tag uint64
- sval string
- ival uint64
-}
-
-type elfAttributeList struct {
- data []byte
- err error
-}
-
-func (a *elfAttributeList) string() string {
- if a.err != nil {
- return ""
- }
- nul := bytes.IndexByte(a.data, 0)
- if nul < 0 {
- a.err = io.EOF
- return ""
- }
- s := string(a.data[:nul])
- a.data = a.data[nul+1:]
- return s
-}
-
-func (a *elfAttributeList) uleb128() uint64 {
- if a.err != nil {
- return 0
- }
- v, size := binary.Uvarint(a.data)
- a.data = a.data[size:]
- return v
-}
-
-// Read an elfAttribute from the list following the rules used on ARM systems.
-func (a *elfAttributeList) armAttr() elfAttribute {
- attr := elfAttribute{tag: a.uleb128()}
- switch {
- case attr.tag == TagCompatibility:
- attr.ival = a.uleb128()
- attr.sval = a.string()
-
- case attr.tag == 64: // Tag_nodefaults has no argument
-
- case attr.tag == 65: // Tag_also_compatible_with
- // Not really, but we don't actually care about this tag.
- attr.sval = a.string()
-
- // Tag with string argument
- case attr.tag == TagCPUName || attr.tag == TagCPURawName || (attr.tag >= 32 && attr.tag&1 != 0):
- attr.sval = a.string()
-
- default: // Tag with integer argument
- attr.ival = a.uleb128()
- }
- return attr
-}
-
-func (a *elfAttributeList) done() bool {
- if a.err != nil || len(a.data) == 0 {
- return true
- }
- return false
-}
-
-// Look for the attribute that indicates the object uses the hard-float ABI (a
-// file-level attribute with tag Tag_VFP_arch and value 1). Unfortunately the
-// format used means that we have to parse all of the file-level attributes to
-// find the one we are looking for. This format is slightly documented in "ELF
-// for the ARM Architecture" but mostly this is derived from reading the source
-// to gold and readelf.
-func parseArmAttributes(e binary.ByteOrder, data []byte) (found bool, ehdrFlags uint32, err error) {
- found = false
- if data[0] != 'A' {
- return false, 0, fmt.Errorf(".ARM.attributes has unexpected format %c\n", data[0])
- }
- data = data[1:]
- for len(data) != 0 {
- sectionlength := e.Uint32(data)
- sectiondata := data[4:sectionlength]
- data = data[sectionlength:]
-
- nulIndex := bytes.IndexByte(sectiondata, 0)
- if nulIndex < 0 {
- return false, 0, fmt.Errorf("corrupt .ARM.attributes (section name not NUL-terminated)\n")
- }
- name := string(sectiondata[:nulIndex])
- sectiondata = sectiondata[nulIndex+1:]
-
- if name != "aeabi" {
- continue
- }
- for len(sectiondata) != 0 {
- subsectiontag, sz := binary.Uvarint(sectiondata)
- subsectionsize := e.Uint32(sectiondata[sz:])
- subsectiondata := sectiondata[sz+4 : subsectionsize]
- sectiondata = sectiondata[subsectionsize:]
-
- if subsectiontag != TagFile {
- continue
- }
- attrList := elfAttributeList{data: subsectiondata}
- for !attrList.done() {
- attr := attrList.armAttr()
- if attr.tag == TagABIVFPArgs && attr.ival == 1 {
- found = true
- ehdrFlags = 0x5000402 // has entry point, Version5 EABI, hard-float ABI
- }
- }
- if attrList.err != nil {
- return false, 0, fmt.Errorf("could not parse .ARM.attributes\n")
- }
- }
- }
- return found, ehdrFlags, nil
-}
-
-// Load loads the ELF file pn from f.
-// Symbols are written into syms, and a slice of the text symbols is returned.
-//
-// On ARM systems, Load will attempt to determine what ELF header flags to
-// emit by scanning the attributes in the ELF file being loaded. The
-// parameter initEhdrFlags contains the current header flags for the output
-// object, and the returned ehdrFlags contains what this Load function computes.
-// TODO: find a better place for this logic.
-func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, pkg string, length int64, pn string, initEhdrFlags uint32) (textp []*sym.Symbol, ehdrFlags uint32, err error) {
- newSym := func(name string, version int) *sym.Symbol {
- return l.Create(name)
- }
- lookup := func(name string, version int) *sym.Symbol {
- return l.LookupOrCreate(name, version)
- }
- errorf := func(str string, args ...interface{}) ([]*sym.Symbol, uint32, error) {
- return nil, 0, fmt.Errorf("loadelf: %s: %v", pn, fmt.Sprintf(str, args...))
- }
-
- base := f.Offset()
-
- var hdrbuf [64]uint8
- if _, err := io.ReadFull(f, hdrbuf[:]); err != nil {
- return errorf("malformed elf file: %v", err)
- }
- hdr := new(ElfHdrBytes)
- binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter
- if string(hdr.Ident[:4]) != "\x7FELF" {
- return errorf("malformed elf file, bad header")
- }
- var e binary.ByteOrder
- switch hdr.Ident[5] {
- case ElfDataLsb:
- e = binary.LittleEndian
-
- case ElfDataMsb:
- e = binary.BigEndian
-
- default:
- return errorf("malformed elf file, unknown header")
- }
-
- // read header
- elfobj := new(ElfObj)
-
- elfobj.e = e
- elfobj.f = f
- elfobj.base = base
- elfobj.length = length
- elfobj.name = pn
-
- is64 := 0
- if hdr.Ident[4] == ElfClass64 {
- is64 = 1
- hdr := new(ElfHdrBytes64)
- binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter
- elfobj.type_ = uint32(e.Uint16(hdr.Type[:]))
- elfobj.machine = uint32(e.Uint16(hdr.Machine[:]))
- elfobj.version = e.Uint32(hdr.Version[:])
- elfobj.phoff = e.Uint64(hdr.Phoff[:])
- elfobj.shoff = e.Uint64(hdr.Shoff[:])
- elfobj.flags = e.Uint32(hdr.Flags[:])
- elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:]))
- elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:]))
- elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:]))
- elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:]))
- elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:]))
- elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:]))
- } else {
- elfobj.type_ = uint32(e.Uint16(hdr.Type[:]))
- elfobj.machine = uint32(e.Uint16(hdr.Machine[:]))
- elfobj.version = e.Uint32(hdr.Version[:])
- elfobj.entry = uint64(e.Uint32(hdr.Entry[:]))
- elfobj.phoff = uint64(e.Uint32(hdr.Phoff[:]))
- elfobj.shoff = uint64(e.Uint32(hdr.Shoff[:]))
- elfobj.flags = e.Uint32(hdr.Flags[:])
- elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:]))
- elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:]))
- elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:]))
- elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:]))
- elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:]))
- elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:]))
- }
-
- elfobj.is64 = is64
-
- if v := uint32(hdr.Ident[6]); v != elfobj.version {
- return errorf("malformed elf version: got %d, want %d", v, elfobj.version)
- }
-
- if e.Uint16(hdr.Type[:]) != ElfTypeRelocatable {
- return errorf("elf but not elf relocatable object")
- }
-
- switch arch.Family {
- default:
- return errorf("elf %s unimplemented", arch.Name)
-
- case sys.MIPS:
- if elfobj.machine != ElfMachMips || hdr.Ident[4] != ElfClass32 {
- return errorf("elf object but not mips")
- }
-
- case sys.MIPS64:
- if elfobj.machine != ElfMachMips || hdr.Ident[4] != ElfClass64 {
- return errorf("elf object but not mips64")
- }
-
- case sys.ARM:
- if e != binary.LittleEndian || elfobj.machine != ElfMachArm || hdr.Ident[4] != ElfClass32 {
- return errorf("elf object but not arm")
- }
-
- case sys.AMD64:
- if e != binary.LittleEndian || elfobj.machine != ElfMachAmd64 || hdr.Ident[4] != ElfClass64 {
- return errorf("elf object but not amd64")
- }
-
- case sys.ARM64:
- if e != binary.LittleEndian || elfobj.machine != ElfMachArm64 || hdr.Ident[4] != ElfClass64 {
- return errorf("elf object but not arm64")
- }
-
- case sys.I386:
- if e != binary.LittleEndian || elfobj.machine != ElfMach386 || hdr.Ident[4] != ElfClass32 {
- return errorf("elf object but not 386")
- }
-
- case sys.PPC64:
- if elfobj.machine != ElfMachPower64 || hdr.Ident[4] != ElfClass64 {
- return errorf("elf object but not ppc64")
- }
-
- case sys.S390X:
- if elfobj.machine != ElfMachS390 || hdr.Ident[4] != ElfClass64 {
- return errorf("elf object but not s390x")
- }
- }
-
- // load section list into memory.
- elfobj.sect = make([]ElfSect, elfobj.shnum)
-
- elfobj.nsect = uint(elfobj.shnum)
- for i := 0; uint(i) < elfobj.nsect; i++ {
- f.MustSeek(int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0)
- sect := &elfobj.sect[i]
- if is64 != 0 {
- var b ElfSectBytes64
-
- if err := binary.Read(f, e, &b); err != nil {
- return errorf("malformed elf file: %v", err)
- }
-
- sect.nameoff = e.Uint32(b.Name[:])
- sect.type_ = e.Uint32(b.Type[:])
- sect.flags = e.Uint64(b.Flags[:])
- sect.addr = e.Uint64(b.Addr[:])
- sect.off = e.Uint64(b.Off[:])
- sect.size = e.Uint64(b.Size[:])
- sect.link = e.Uint32(b.Link[:])
- sect.info = e.Uint32(b.Info[:])
- sect.align = e.Uint64(b.Align[:])
- sect.entsize = e.Uint64(b.Entsize[:])
- } else {
- var b ElfSectBytes
-
- if err := binary.Read(f, e, &b); err != nil {
- return errorf("malformed elf file: %v", err)
- }
-
- sect.nameoff = e.Uint32(b.Name[:])
- sect.type_ = e.Uint32(b.Type[:])
- sect.flags = uint64(e.Uint32(b.Flags[:]))
- sect.addr = uint64(e.Uint32(b.Addr[:]))
- sect.off = uint64(e.Uint32(b.Off[:]))
- sect.size = uint64(e.Uint32(b.Size[:]))
- sect.link = e.Uint32(b.Link[:])
- sect.info = e.Uint32(b.Info[:])
- sect.align = uint64(e.Uint32(b.Align[:]))
- sect.entsize = uint64(e.Uint32(b.Entsize[:]))
- }
- }
-
- // read section string table and translate names
- if elfobj.shstrndx >= uint32(elfobj.nsect) {
- return errorf("malformed elf file: shstrndx out of range %d >= %d", elfobj.shstrndx, elfobj.nsect)
- }
-
- sect := &elfobj.sect[elfobj.shstrndx]
- if err := elfmap(elfobj, sect); err != nil {
- return errorf("malformed elf file: %v", err)
- }
- for i := 0; uint(i) < elfobj.nsect; i++ {
- if elfobj.sect[i].nameoff != 0 {
- elfobj.sect[i].name = cstring(sect.base[elfobj.sect[i].nameoff:])
- }
- }
-
- // load string table for symbols into memory.
- elfobj.symtab = section(elfobj, ".symtab")
-
- if elfobj.symtab == nil {
- // our work is done here - no symbols means nothing can refer to this file
- return
- }
-
- if elfobj.symtab.link <= 0 || elfobj.symtab.link >= uint32(elfobj.nsect) {
- return errorf("elf object has symbol table with invalid string table link")
- }
-
- elfobj.symstr = &elfobj.sect[elfobj.symtab.link]
- if is64 != 0 {
- elfobj.nsymtab = int(elfobj.symtab.size / ELF64SYMSIZE)
- } else {
- elfobj.nsymtab = int(elfobj.symtab.size / ELF32SYMSIZE)
- }
-
- if err := elfmap(elfobj, elfobj.symtab); err != nil {
- return errorf("malformed elf file: %v", err)
- }
- if err := elfmap(elfobj, elfobj.symstr); err != nil {
- return errorf("malformed elf file: %v", err)
- }
-
- // load text and data segments into memory.
- // they are not as small as the section lists, but we'll need
- // the memory anyway for the symbol images, so we might
- // as well use one large chunk.
-
- // create symbols for elfmapped sections
- sectsymNames := make(map[string]bool)
- counter := 0
- for i := 0; uint(i) < elfobj.nsect; i++ {
- sect = &elfobj.sect[i]
- if sect.type_ == SHT_ARM_ATTRIBUTES && sect.name == ".ARM.attributes" {
- if err := elfmap(elfobj, sect); err != nil {
- return errorf("%s: malformed elf file: %v", pn, err)
- }
- // We assume the soft-float ABI unless we see a tag indicating otherwise.
- if initEhdrFlags == 0x5000002 {
- ehdrFlags = 0x5000202
- } else {
- ehdrFlags = initEhdrFlags
- }
- found, newEhdrFlags, err := parseArmAttributes(e, sect.base[:sect.size])
- if err != nil {
- // TODO(dfc) should this return an error?
- log.Printf("%s: %v", pn, err)
- }
- if found {
- ehdrFlags = newEhdrFlags
- }
- }
- if (sect.type_ != ElfSectProgbits && sect.type_ != ElfSectNobits) || sect.flags&ElfSectFlagAlloc == 0 {
- continue
- }
- if sect.type_ != ElfSectNobits {
- if err := elfmap(elfobj, sect); err != nil {
- return errorf("%s: malformed elf file: %v", pn, err)
- }
- }
-
- name := fmt.Sprintf("%s(%s)", pkg, sect.name)
- for sectsymNames[name] {
- counter++
- name = fmt.Sprintf("%s(%s%d)", pkg, sect.name, counter)
- }
- sectsymNames[name] = true
-
- s := lookup(name, localSymVersion)
-
- switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
- default:
- return errorf("%s: unexpected flags for ELF section %s", pn, sect.name)
-
- case ElfSectFlagAlloc:
- s.Type = sym.SRODATA
-
- case ElfSectFlagAlloc + ElfSectFlagWrite:
- if sect.type_ == ElfSectNobits {
- s.Type = sym.SNOPTRBSS
- } else {
- s.Type = sym.SNOPTRDATA
- }
-
- case ElfSectFlagAlloc + ElfSectFlagExec:
- s.Type = sym.STEXT
- }
-
- if sect.name == ".got" || sect.name == ".toc" {
- s.Type = sym.SELFGOT
- }
- if sect.type_ == ElfSectProgbits {
- s.P = sect.base
- s.P = s.P[:sect.size]
- }
-
- s.Size = int64(sect.size)
- s.Align = int32(sect.align)
- sect.sym = s
- }
-
- // enter sub-symbols into symbol table.
- // symbol 0 is the null symbol.
- symbols := make([]*sym.Symbol, elfobj.nsymtab)
-
- for i := 1; i < elfobj.nsymtab; i++ {
- var elfsym ElfSym
- if err := readelfsym(newSym, lookup, arch, elfobj, i, &elfsym, 1, localSymVersion); err != nil {
- return errorf("%s: malformed elf file: %v", pn, err)
- }
- symbols[i] = elfsym.sym
- if elfsym.type_ != ElfSymTypeFunc && elfsym.type_ != ElfSymTypeObject && elfsym.type_ != ElfSymTypeNone && elfsym.type_ != ElfSymTypeCommon {
- continue
- }
- if elfsym.shndx == ElfSymShnCommon || elfsym.type_ == ElfSymTypeCommon {
- s := elfsym.sym
- if uint64(s.Size) < elfsym.size {
- s.Size = int64(elfsym.size)
- }
- if s.Type == 0 || s.Type == sym.SXREF {
- s.Type = sym.SNOPTRBSS
- }
- continue
- }
-
- if uint(elfsym.shndx) >= elfobj.nsect || elfsym.shndx == 0 {
- continue
- }
-
- // even when we pass needSym == 1 to readelfsym, it might still return nil to skip some unwanted symbols
- if elfsym.sym == nil {
- continue
- }
- sect = &elfobj.sect[elfsym.shndx]
- if sect.sym == nil {
- if strings.HasPrefix(elfsym.name, ".Linfo_string") { // clang does this
- continue
- }
-
- if elfsym.name == "" && elfsym.type_ == 0 && sect.name == ".debug_str" {
- // This reportedly happens with clang 3.7 on ARM.
- // See issue 13139.
- continue
- }
-
- if strings.HasPrefix(elfsym.name, "$d") && elfsym.type_ == 0 && sect.name == ".debug_frame" {
- // "$d" is a marker, not a real symbol.
- // This happens with gcc on ARM64.
- // See https://sourceware.org/bugzilla/show_bug.cgi?id=21809
- continue
- }
-
- if strings.HasPrefix(elfsym.name, ".LASF") { // gcc on s390x does this
- continue
- }
- return errorf("%v: sym#%d: ignoring symbol in section %d (type %d)", elfsym.sym, i, elfsym.shndx, elfsym.type_)
- }
-
- s := elfsym.sym
- if s.Outer != nil {
- if s.Attr.DuplicateOK() {
- continue
- }
- return errorf("duplicate symbol reference: %s in both %s and %s", s.Name, s.Outer.Name, sect.sym.Name)
- }
-
- s.Sub = sect.sym.Sub
- sect.sym.Sub = s
- s.Type = sect.sym.Type
- s.Attr |= sym.AttrSubSymbol
- if !s.Attr.CgoExportDynamic() {
- s.SetDynimplib("") // satisfy dynimport
- }
- s.Value = int64(elfsym.value)
- s.Size = int64(elfsym.size)
- s.Outer = sect.sym
- if sect.sym.Type == sym.STEXT {
- if s.Attr.External() && !s.Attr.DuplicateOK() {
- return errorf("%v: duplicate symbol definition", s)
- }
- s.Attr |= sym.AttrExternal
- }
-
- if elfobj.machine == ElfMachPower64 {
- flag := int(elfsym.other) >> 5
- if 2 <= flag && flag <= 6 {
- s.SetLocalentry(1 << uint(flag-2))
- } else if flag == 7 {
- return errorf("%v: invalid sym.other 0x%x", s, elfsym.other)
- }
- }
- }
-
- // Sort outer lists by address, adding to textp.
- // This keeps textp in increasing address order.
- for i := uint(0); i < elfobj.nsect; i++ {
- s := elfobj.sect[i].sym
- if s == nil {
- continue
- }
- if s.Sub != nil {
- s.Sub = sym.SortSub(s.Sub)
- }
- if s.Type == sym.STEXT {
- if s.Attr.OnList() {
- return errorf("symbol %s listed multiple times", s.Name)
- }
- s.Attr |= sym.AttrOnList
- textp = append(textp, s)
- for s = s.Sub; s != nil; s = s.Sub {
- if s.Attr.OnList() {
- return errorf("symbol %s listed multiple times", s.Name)
- }
- s.Attr |= sym.AttrOnList
- textp = append(textp, s)
- }
- }
- }
-
- // load relocations
- for i := uint(0); i < elfobj.nsect; i++ {
- rsect := &elfobj.sect[i]
- if rsect.type_ != ElfSectRela && rsect.type_ != ElfSectRel {
- continue
- }
- if rsect.info >= uint32(elfobj.nsect) || elfobj.sect[rsect.info].base == nil {
- continue
- }
- sect = &elfobj.sect[rsect.info]
- if err := elfmap(elfobj, rsect); err != nil {
- return errorf("malformed elf file: %v", err)
- }
- rela := 0
- if rsect.type_ == ElfSectRela {
- rela = 1
- }
- n := int(rsect.size / uint64(4+4*is64) / uint64(2+rela))
- r := make([]sym.Reloc, n)
- p := rsect.base
- for j := 0; j < n; j++ {
- var add uint64
- rp := &r[j]
- var info uint64
- if is64 != 0 {
- // 64-bit rel/rela
- rp.Off = int32(e.Uint64(p))
-
- p = p[8:]
- info = e.Uint64(p)
- p = p[8:]
- if rela != 0 {
- add = e.Uint64(p)
- p = p[8:]
- }
- } else {
- // 32-bit rel/rela
- rp.Off = int32(e.Uint32(p))
-
- p = p[4:]
- info = uint64(e.Uint32(p))
- info = info>>8<<32 | info&0xff // convert to 64-bit info
- p = p[4:]
- if rela != 0 {
- add = uint64(e.Uint32(p))
- p = p[4:]
- }
- }
-
- if info&0xffffffff == 0 { // skip R_*_NONE relocation
- j--
- n--
- continue
- }
-
- if info>>32 == 0 { // absolute relocation, don't bother reading the null symbol
- rp.Sym = nil
- } else {
- var elfsym ElfSym
- if err := readelfsym(newSym, lookup, arch, elfobj, int(info>>32), &elfsym, 0, 0); err != nil {
- return errorf("malformed elf file: %v", err)
- }
- elfsym.sym = symbols[info>>32]
- if elfsym.sym == nil {
- return errorf("malformed elf file: %s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect.sym.Name, j, int(info>>32), elfsym.name, elfsym.shndx, elfsym.type_)
- }
-
- rp.Sym = elfsym.sym
- }
-
- rp.Type = objabi.ElfRelocOffset + objabi.RelocType(info)
- rp.Siz, err = relSize(arch, pn, uint32(info))
- if err != nil {
- return nil, 0, err
- }
- if rela != 0 {
- rp.Add = int64(add)
- } else {
- // load addend from image
- if rp.Siz == 4 {
- rp.Add = int64(e.Uint32(sect.base[rp.Off:]))
- } else if rp.Siz == 8 {
- rp.Add = int64(e.Uint64(sect.base[rp.Off:]))
- } else {
- return errorf("invalid rela size %d", rp.Siz)
- }
- }
-
- if rp.Siz == 2 {
- rp.Add = int64(int16(rp.Add))
- }
- if rp.Siz == 4 {
- rp.Add = int64(int32(rp.Add))
- }
- }
-
- //print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
- sort.Sort(sym.RelocByOff(r[:n]))
- // just in case
-
- s := sect.sym
- s.R = r
- s.R = s.R[:n]
- }
-
- return textp, ehdrFlags, nil
-}
-
-func section(elfobj *ElfObj, name string) *ElfSect {
- for i := 0; uint(i) < elfobj.nsect; i++ {
- if elfobj.sect[i].name != "" && name != "" && elfobj.sect[i].name == name {
- return &elfobj.sect[i]
- }
- }
- return nil
-}
-
-func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) {
- if sect.base != nil {
- return nil
- }
-
- if sect.off+sect.size > uint64(elfobj.length) {
- err = fmt.Errorf("elf section past end of file")
- return err
- }
-
- sect.base = make([]byte, sect.size)
- elfobj.f.MustSeek(int64(uint64(elfobj.base)+sect.off), 0)
- if _, err := io.ReadFull(elfobj.f, sect.base); err != nil {
- return fmt.Errorf("short read: %v", err)
- }
-
- return nil
-}
-
-func readelfsym(newSym, lookup func(string, int) *sym.Symbol, arch *sys.Arch, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int, localSymVersion int) (err error) {
- if i >= elfobj.nsymtab || i < 0 {
- err = fmt.Errorf("invalid elf symbol index")
- return err
- }
-
- if i == 0 {
- return fmt.Errorf("readym: read null symbol!")
- }
-
- if elfobj.is64 != 0 {
- b := new(ElfSymBytes64)
- binary.Read(bytes.NewReader(elfobj.symtab.base[i*ELF64SYMSIZE:(i+1)*ELF64SYMSIZE]), elfobj.e, b)
- elfsym.name = cstring(elfobj.symstr.base[elfobj.e.Uint32(b.Name[:]):])
- elfsym.value = elfobj.e.Uint64(b.Value[:])
- elfsym.size = elfobj.e.Uint64(b.Size[:])
- elfsym.shndx = elfobj.e.Uint16(b.Shndx[:])
- elfsym.bind = b.Info >> 4
- elfsym.type_ = b.Info & 0xf
- elfsym.other = b.Other
- } else {
- b := new(ElfSymBytes)
- binary.Read(bytes.NewReader(elfobj.symtab.base[i*ELF32SYMSIZE:(i+1)*ELF32SYMSIZE]), elfobj.e, b)
- elfsym.name = cstring(elfobj.symstr.base[elfobj.e.Uint32(b.Name[:]):])
- elfsym.value = uint64(elfobj.e.Uint32(b.Value[:]))
- elfsym.size = uint64(elfobj.e.Uint32(b.Size[:]))
- elfsym.shndx = elfobj.e.Uint16(b.Shndx[:])
- elfsym.bind = b.Info >> 4
- elfsym.type_ = b.Info & 0xf
- elfsym.other = b.Other
- }
-
- var s *sym.Symbol
- if elfsym.name == "_GLOBAL_OFFSET_TABLE_" {
- elfsym.name = ".got"
- }
- if elfsym.name == ".TOC." {
- // Magic symbol on ppc64. Will be set to this object
- // file's .got+0x8000.
- elfsym.bind = ElfSymBindLocal
- }
-
- switch elfsym.type_ {
- case ElfSymTypeSection:
- s = elfobj.sect[elfsym.shndx].sym
-
- case ElfSymTypeObject, ElfSymTypeFunc, ElfSymTypeNone, ElfSymTypeCommon:
- switch elfsym.bind {
- case ElfSymBindGlobal:
- if needSym != 0 {
- s = lookup(elfsym.name, 0)
-
- // for global scoped hidden symbols we should insert it into
- // symbol hash table, but mark them as hidden.
- // __i686.get_pc_thunk.bx is allowed to be duplicated, to
- // workaround that we set dupok.
- // TODO(minux): correctly handle __i686.get_pc_thunk.bx without
- // set dupok generally. See https://golang.org/cl/5823055
- // comment #5 for details.
- if s != nil && elfsym.other == 2 {
- s.Attr |= sym.AttrDuplicateOK | sym.AttrVisibilityHidden
- }
- }
-
- case ElfSymBindLocal:
- if (arch.Family == sys.ARM || arch.Family == sys.ARM64) && (strings.HasPrefix(elfsym.name, "$a") || strings.HasPrefix(elfsym.name, "$d") || strings.HasPrefix(elfsym.name, "$x")) {
- // binutils for arm and arm64 generate these mapping
- // symbols, ignore these
- break
- }
-
- if elfsym.name == ".TOC." {
- // We need to be able to look this up,
- // so put it in the hash table.
- if needSym != 0 {
- s = lookup(elfsym.name, localSymVersion)
- s.Attr |= sym.AttrVisibilityHidden
- }
-
- break
- }
-
- if needSym != 0 {
- // local names and hidden global names are unique
- // and should only be referenced by their index, not name, so we
- // don't bother to add them into the hash table
- // FIXME: pass empty string here for name? This would
- // reduce mem use, but also (possibly) make it harder
- // to debug problems.
- s = newSym(elfsym.name, localSymVersion)
-
- s.Attr |= sym.AttrVisibilityHidden
- }
-
- case ElfSymBindWeak:
- if needSym != 0 {
- s = lookup(elfsym.name, 0)
- if elfsym.other == 2 {
- s.Attr |= sym.AttrVisibilityHidden
- }
-
- // Allow weak symbols to be duplicated when already defined.
- if s.Outer != nil {
- s.Attr |= sym.AttrDuplicateOK
- }
- }
-
- default:
- err = fmt.Errorf("%s: invalid symbol binding %d", elfsym.name, elfsym.bind)
- return err
- }
- }
-
- // TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
- // sense and should be removed when someone has thought about it properly.
- if s != nil && s.Type == 0 && !s.Attr.VisibilityHidden() && elfsym.type_ != ElfSymTypeSection {
- s.Type = sym.SXREF
- }
- elfsym.sym = s
-
- return nil
-}
-
-func relSize(arch *sys.Arch, pn string, elftype uint32) (uint8, error) {
- // TODO(mdempsky): Replace this with a struct-valued switch statement
- // once golang.org/issue/15164 is fixed or found to not impair cmd/link
- // performance.
-
- const (
- AMD64 = uint32(sys.AMD64)
- ARM = uint32(sys.ARM)
- ARM64 = uint32(sys.ARM64)
- I386 = uint32(sys.I386)
- PPC64 = uint32(sys.PPC64)
- S390X = uint32(sys.S390X)
- )
-
- switch uint32(arch.Family) | elftype<<16 {
- default:
- return 0, fmt.Errorf("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype)
-
- case S390X | uint32(elf.R_390_8)<<16:
- return 1, nil
-
- case PPC64 | uint32(elf.R_PPC64_TOC16)<<16,
- PPC64 | uint32(elf.R_PPC64_TOC16_LO)<<16,
- PPC64 | uint32(elf.R_PPC64_TOC16_HI)<<16,
- PPC64 | uint32(elf.R_PPC64_TOC16_HA)<<16,
- PPC64 | uint32(elf.R_PPC64_TOC16_DS)<<16,
- PPC64 | uint32(elf.R_PPC64_TOC16_LO_DS)<<16,
- PPC64 | uint32(elf.R_PPC64_REL16_LO)<<16,
- PPC64 | uint32(elf.R_PPC64_REL16_HI)<<16,
- PPC64 | uint32(elf.R_PPC64_REL16_HA)<<16,
- S390X | uint32(elf.R_390_16)<<16,
- S390X | uint32(elf.R_390_GOT16)<<16,
- S390X | uint32(elf.R_390_PC16)<<16,
- S390X | uint32(elf.R_390_PC16DBL)<<16,
- S390X | uint32(elf.R_390_PLT16DBL)<<16:
- return 2, nil
-
- case ARM | uint32(elf.R_ARM_ABS32)<<16,
- ARM | uint32(elf.R_ARM_GOT32)<<16,
- ARM | uint32(elf.R_ARM_PLT32)<<16,
- ARM | uint32(elf.R_ARM_GOTOFF)<<16,
- ARM | uint32(elf.R_ARM_GOTPC)<<16,
- ARM | uint32(elf.R_ARM_THM_PC22)<<16,
- ARM | uint32(elf.R_ARM_REL32)<<16,
- ARM | uint32(elf.R_ARM_CALL)<<16,
- ARM | uint32(elf.R_ARM_V4BX)<<16,
- ARM | uint32(elf.R_ARM_GOT_PREL)<<16,
- ARM | uint32(elf.R_ARM_PC24)<<16,
- ARM | uint32(elf.R_ARM_JUMP24)<<16,
- ARM64 | uint32(elf.R_AARCH64_CALL26)<<16,
- ARM64 | uint32(elf.R_AARCH64_ADR_GOT_PAGE)<<16,
- ARM64 | uint32(elf.R_AARCH64_LD64_GOT_LO12_NC)<<16,
- ARM64 | uint32(elf.R_AARCH64_ADR_PREL_PG_HI21)<<16,
- ARM64 | uint32(elf.R_AARCH64_ADD_ABS_LO12_NC)<<16,
- ARM64 | uint32(elf.R_AARCH64_LDST8_ABS_LO12_NC)<<16,
- ARM64 | uint32(elf.R_AARCH64_LDST32_ABS_LO12_NC)<<16,
- ARM64 | uint32(elf.R_AARCH64_LDST64_ABS_LO12_NC)<<16,
- ARM64 | uint32(elf.R_AARCH64_LDST128_ABS_LO12_NC)<<16,
- ARM64 | uint32(elf.R_AARCH64_PREL32)<<16,
- ARM64 | uint32(elf.R_AARCH64_JUMP26)<<16,
- AMD64 | uint32(elf.R_X86_64_PC32)<<16,
- AMD64 | uint32(elf.R_X86_64_PLT32)<<16,
- AMD64 | uint32(elf.R_X86_64_GOTPCREL)<<16,
- AMD64 | uint32(elf.R_X86_64_GOTPCRELX)<<16,
- AMD64 | uint32(elf.R_X86_64_REX_GOTPCRELX)<<16,
- I386 | uint32(elf.R_386_32)<<16,
- I386 | uint32(elf.R_386_PC32)<<16,
- I386 | uint32(elf.R_386_GOT32)<<16,
- I386 | uint32(elf.R_386_PLT32)<<16,
- I386 | uint32(elf.R_386_GOTOFF)<<16,
- I386 | uint32(elf.R_386_GOTPC)<<16,
- I386 | uint32(elf.R_386_GOT32X)<<16,
- PPC64 | uint32(elf.R_PPC64_REL24)<<16,
- PPC64 | uint32(elf.R_PPC_REL32)<<16,
- S390X | uint32(elf.R_390_32)<<16,
- S390X | uint32(elf.R_390_PC32)<<16,
- S390X | uint32(elf.R_390_GOT32)<<16,
- S390X | uint32(elf.R_390_PLT32)<<16,
- S390X | uint32(elf.R_390_PC32DBL)<<16,
- S390X | uint32(elf.R_390_PLT32DBL)<<16,
- S390X | uint32(elf.R_390_GOTPCDBL)<<16,
- S390X | uint32(elf.R_390_GOTENT)<<16:
- return 4, nil
-
- case AMD64 | uint32(elf.R_X86_64_64)<<16,
- AMD64 | uint32(elf.R_X86_64_PC64)<<16,
- ARM64 | uint32(elf.R_AARCH64_ABS64)<<16,
- ARM64 | uint32(elf.R_AARCH64_PREL64)<<16,
- PPC64 | uint32(elf.R_PPC64_ADDR64)<<16,
- S390X | uint32(elf.R_390_GLOB_DAT)<<16,
- S390X | uint32(elf.R_390_RELATIVE)<<16,
- S390X | uint32(elf.R_390_GOTOFF)<<16,
- S390X | uint32(elf.R_390_GOTPC)<<16,
- S390X | uint32(elf.R_390_64)<<16,
- S390X | uint32(elf.R_390_PC64)<<16,
- S390X | uint32(elf.R_390_GOT64)<<16,
- S390X | uint32(elf.R_390_PLT64)<<16:
- return 8, nil
- }
-}
-
-func cstring(x []byte) string {
- i := bytes.IndexByte(x, '\x00')
- if i >= 0 {
- x = x[:i]
- }
- return string(x)
-}