From 76d097774541795877bc8a42d8679437ba5cf364 Mon Sep 17 00:00:00 2001 From: Jeremy Faller Date: Thu, 23 Jan 2020 10:39:13 -0500 Subject: [PATCH] [dev.link] cmd/link: remove flag FlagNewLdElf No real reason to keep the old code around as the new stuff is working just fine. Change-Id: I5e886f8274344738663a0ead181c5d58d9f5a45f Reviewed-on: https://go-review.googlesource.com/c/go/+/215997 Run-TryBot: Jeremy Faller TryBot-Result: Gobot Gobot Reviewed-by: Cherry Zhang --- src/cmd/dist/buildtool.go | 1 - src/cmd/link/internal/ld/ar.go | 2 +- src/cmd/link/internal/ld/decodesym.go | 5 - src/cmd/link/internal/ld/lib.go | 188 +--- src/cmd/link/internal/ld/link.go | 10 +- src/cmd/link/internal/ld/main.go | 9 +- src/cmd/link/internal/loadelfold/ldelf.go | 1243 --------------------- 7 files changed, 70 insertions(+), 1388 deletions(-) delete mode 100644 src/cmd/link/internal/loadelfold/ldelf.go diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go index 83ab61d155..12baccbc4f 100644 --- a/src/cmd/dist/buildtool.go +++ b/src/cmd/dist/buildtool.go @@ -74,7 +74,6 @@ var bootstrapDirs = []string{ "cmd/link/internal/arm64", "cmd/link/internal/ld", "cmd/link/internal/loadelf", - "cmd/link/internal/loadelfold", "cmd/link/internal/loader", "cmd/link/internal/loadmacho", "cmd/link/internal/loadpe", diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go index 74223d7752..9e770e2615 100644 --- a/src/cmd/link/internal/ld/ar.go +++ b/src/cmd/link/internal/ld/ar.go @@ -104,7 +104,7 @@ func hostArchive(ctxt *Link, name string) { any := true for any { var load []uint64 - if ctxt.IsELF && *FlagNewLdElf { + if ctxt.IsELF { returnAllUndefs := -1 undefs := ctxt.loader.UndefinedRelocTargets(returnAllUndefs) for _, symIdx := range undefs { diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index 3271c85157..50586081d3 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -125,11 +125,6 @@ func decodetypeGcprog(ctxt *Link, s *sym.Symbol) []byte { func decodetypeGcprogShlib(ctxt *Link, s *sym.Symbol) uint64 { if ctxt.Arch.Family == sys.ARM64 { - for _, shlib := range ctxt.Shlibs { - if shlib.Path == s.File { - return shlib.gcdataAddresses[s] - } - } return 0 } return decodeInuxi(ctxt.Arch, s.P[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize) diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index c1b56276b0..45c3a53d33 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -38,7 +38,6 @@ import ( "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" @@ -457,8 +456,7 @@ func (ctxt *Link) loadlib() { } // 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) @@ -471,7 +469,7 @@ func (ctxt *Link) loadlib() { // 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 @@ -629,9 +627,6 @@ func (ctxt *Link) loadcgodirectives(useLoader bool) { // 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) @@ -1857,29 +1852,16 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, 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 { @@ -2144,8 +2126,7 @@ func ldshlibsyms(ctxt *Link, shlib string) { 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 @@ -2158,103 +2139,61 @@ func ldshlibsyms(ctxt *Link, shlib string) { 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 { @@ -2272,21 +2211,12 @@ func ldshlibsyms(ctxt *Link, shlib string) { 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 { diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index fa1dc389d7..f2c512e73f 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -42,12 +42,10 @@ import ( ) type Shlib struct { - Path string - Hash []byte - Deps []string - File *elf.File - gcdataAddresses map[*sym.Symbol]uint64 - gcdataAddresses2 map[loader.Sym]uint64 + Path string + Hash []byte + Deps []string + File *elf.File } // Link holds the context for writing object code from a compiler diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index db28e2ed03..2dd495ecbf 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -87,7 +87,6 @@ var ( flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker") FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines") FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).") - FlagNewLdElf = flag.Bool("newldelf", true, "ELF host obj load with new loader") FlagRound = flag.Int("R", -1, "set address rounding `quantum`") FlagTextAddr = flag.Int64("T", -1, "set text segment `address`") @@ -98,6 +97,10 @@ var ( memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`") ) +func (ctxt *Link) loaderSupport() bool { + return ctxt.IsELF || ctxt.HeadType == objabi.Hdarwin +} + // Main is the main entry point for the linker code. func Main(arch *sys.Arch, theArch Arch) { thearch = theArch @@ -211,13 +214,13 @@ func Main(arch *sys.Arch, theArch Arch) { deadcode(ctxt) - if *FlagNewLdElf { + if ctxt.loaderSupport() { ctxt.linksetup() } ctxt.loadlibfull() // XXX do it here for now - if !*FlagNewLdElf { + if !ctxt.loaderSupport() { ctxt.linksetupold() } ctxt.dostrdata() diff --git a/src/cmd/link/internal/loadelfold/ldelf.go b/src/cmd/link/internal/loadelfold/ldelf.go deleted file mode 100644 index c5e0222828..0000000000 --- a/src/cmd/link/internal/loadelfold/ldelf.go +++ /dev/null @@ -1,1243 +0,0 @@ -// 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) -} -- 2.48.1