diff options
| author | Than McIntosh <thanm@google.com> | 2019-12-06 20:11:36 -0500 |
|---|---|---|
| committer | Than McIntosh <thanm@google.com> | 2020-01-09 20:48:48 +0000 |
| commit | fa284af7201c5ce246bd5fcac485a5445717c452 (patch) | |
| tree | 59e8832726183e6b1f36fbaa07f8a66ac6692a4a /src/cmd/link/internal/loadelf | |
| parent | 161e0a54978549a61e96673c89bfe212347f5857 (diff) | |
| download | go-fa284af7201c5ce246bd5fcac485a5445717c452.tar.xz | |
[dev.link] cmd/link: convert ELF host object loading to new loader
This is a rewrite of the ELF host object loader to use just the Loader
interfaces for symbol creation, without constructing sym.Symbols. At
the moment this is gated under the temporary linker command line
option "-newldelf". This version is able to get through all.bash
on linux/amd64.
Change-Id: I99f41368f75b0df9e35ef3c2cf2a702b732540c6
Reviewed-on: https://go-review.googlesource.com/c/go/+/210779
Run-TryBot: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/cmd/link/internal/loadelf')
| -rw-r--r-- | src/cmd/link/internal/loadelf/ldelf.go | 187 |
1 files changed, 99 insertions, 88 deletions
diff --git a/src/cmd/link/internal/loadelf/ldelf.go b/src/cmd/link/internal/loadelf/ldelf.go index 2ee8af6bc9..7d613c7a6d 100644 --- a/src/cmd/link/internal/loadelf/ldelf.go +++ b/src/cmd/link/internal/loadelf/ldelf.go @@ -1,4 +1,4 @@ -// Copyright 2017 The Go Authors. All rights reserved. +// Copyright 2019 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. @@ -282,7 +282,7 @@ type ElfSect struct { align uint64 entsize uint64 base []byte - sym *sym.Symbol + sym loader.Sym } type ElfObj struct { @@ -320,7 +320,7 @@ type ElfSym struct { type_ uint8 other uint8 shndx uint16 - sym *sym.Symbol + sym loader.Sym } var ElfMagic = [4]uint8{0x7F, 'E', 'L', 'F'} @@ -453,21 +453,21 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) (found bool, ehdrFlags } // Load loads the ELF file pn from f. -// Symbols are written into syms, and a slice of the text symbols is returned. +// Symbols are installed into the loader, 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) +func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, pkg string, length int64, pn string, initEhdrFlags uint32) (textp []loader.Sym, ehdrFlags uint32, err error) { + newSym := func(name string, version int) loader.Sym { + return l.CreateExtSym(name) } - lookup := func(name string, version int) *sym.Symbol { - return l.LookupOrCreate(name, version) + lookup := func(name string, version int) loader.Sym { + return l.LookupOrCreateSym(name, version) } - errorf := func(str string, args ...interface{}) ([]*sym.Symbol, uint32, error) { + errorf := func(str string, args ...interface{}) ([]loader.Sym, uint32, error) { return nil, 0, fmt.Errorf("loadelf: %s: %v", pn, fmt.Sprintf(str, args...)) } @@ -721,46 +721,46 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, } sectsymNames[name] = true - s := lookup(name, localSymVersion) + sb, _ := l.MakeSymbolUpdater(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 + sb.SetType(sym.SRODATA) case ElfSectFlagAlloc + ElfSectFlagWrite: if sect.type_ == ElfSectNobits { - s.Type = sym.SNOPTRBSS + sb.SetType(sym.SNOPTRBSS) } else { - s.Type = sym.SNOPTRDATA + sb.SetType(sym.SNOPTRDATA) } case ElfSectFlagAlloc + ElfSectFlagExec: - s.Type = sym.STEXT + sb.SetType(sym.STEXT) } if sect.name == ".got" || sect.name == ".toc" { - s.Type = sym.SELFGOT + sb.SetType(sym.SELFGOT) } if sect.type_ == ElfSectProgbits { - s.P = sect.base - s.P = s.P[:sect.size] + sb.SetData(sect.base[:sect.size]) } - s.Size = int64(sect.size) - s.Align = int32(sect.align) - sect.sym = s + sb.SetSize(int64(sect.size)) + sb.SetAlign(int32(sect.align)) + + sect.sym = sb.Sym() } // enter sub-symbols into symbol table. // symbol 0 is the null symbol. - symbols := make([]*sym.Symbol, elfobj.nsymtab) + symbols := make([]loader.Sym, 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 { + if err := readelfsym(newSym, lookup, l, arch, elfobj, i, &elfsym, 1, localSymVersion); err != nil { return errorf("%s: malformed elf file: %v", pn, err) } symbols[i] = elfsym.sym @@ -768,13 +768,15 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, continue } if elfsym.shndx == ElfSymShnCommon || elfsym.type_ == ElfSymTypeCommon { - s := elfsym.sym - if uint64(s.Size) < elfsym.size { - s.Size = int64(elfsym.size) + sb, ns := l.MakeSymbolUpdater(elfsym.sym) + if uint64(sb.Size()) < elfsym.size { + sb.SetSize(int64(elfsym.size)) } - if s.Type == 0 || s.Type == sym.SXREF { - s.Type = sym.SNOPTRBSS + if sb.Type() == 0 || sb.Type() == sym.SXREF { + sb.SetType(sym.SNOPTRBSS) } + symbols[i] = ns + elfsym.sym = ns continue } @@ -783,11 +785,11 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, } // even when we pass needSym == 1 to readelfsym, it might still return nil to skip some unwanted symbols - if elfsym.sym == nil { + if elfsym.sym == 0 { continue } sect = &elfobj.sect[elfsym.shndx] - if sect.sym == nil { + if sect.sym == 0 { if strings.HasPrefix(elfsym.name, ".Linfo_string") { // clang does this continue } @@ -812,36 +814,37 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, } s := elfsym.sym - if s.Outer != nil { - if s.Attr.DuplicateOK() { + if l.OuterSym(s) != 0 { + if l.AttrDuplicateOK(s) { continue } - return errorf("duplicate symbol reference: %s in both %s and %s", s.Name, s.Outer.Name, sect.sym.Name) + return errorf("duplicate symbol reference: %s in both %s and %s", + l.SymName(s), l.SymName(l.OuterSym(s)), l.SymName(sect.sym)) } - 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 + sectsb, _ := l.MakeSymbolUpdater(sect.sym) + sb, _ := l.MakeSymbolUpdater(s) + + sb.SetType(sectsb.Type()) + sectsb.PrependSub(s) + if !l.AttrCgoExportDynamic(s) { + sb.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) + sb.SetValue(int64(elfsym.value)) + sb.SetSize(int64(elfsym.size)) + if sectsb.Type() == sym.STEXT { + if l.AttrExternal(s) && !l.AttrDuplicateOK(s) { + return errorf("%s: duplicate symbol definition", sb.Name()) } - s.Attr |= sym.AttrExternal + l.SetAttrExternal(s, true) } if elfobj.machine == ElfMachPower64 { flag := int(elfsym.other) >> 5 if 2 <= flag && flag <= 6 { - s.SetLocalentry(1 << uint(flag-2)) + l.SetSymLocalentry(s, 1<<uint(flag-2)) } else if flag == 7 { - return errorf("%v: invalid sym.other 0x%x", s, elfsym.other) + return errorf("%s: invalid sym.other 0x%x", sb.Name(), elfsym.other) } } } @@ -850,24 +853,28 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, // This keeps textp in increasing address order. for i := uint(0); i < elfobj.nsect; i++ { s := elfobj.sect[i].sym - if s == nil { + if s == 0 { continue } - if s.Sub != nil { - s.Sub = sym.SortSub(s.Sub) + sb, _ := l.MakeSymbolUpdater(s) + s = sb.Sym() + if l.SubSym(s) != 0 { + sb.SortSub() } - if s.Type == sym.STEXT { - if s.Attr.OnList() { - return errorf("symbol %s listed multiple times", s.Name) + if sb.Type() == sym.STEXT { + if l.AttrOnList(s) { + return errorf("symbol %s listed multiple times", + l.SymName(s)) } - s.Attr |= sym.AttrOnList + l.SetAttrOnList(s, true) 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) + for ss := l.SubSym(s); ss != 0; ss = l.SubSym(ss) { + if l.AttrOnList(ss) { + return errorf("symbol %s listed multiple times", + l.SymName(ss)) } - s.Attr |= sym.AttrOnList - textp = append(textp, s) + l.SetAttrOnList(ss, true) + textp = append(textp, ss) } } } @@ -890,7 +897,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, rela = 1 } n := int(rsect.size / uint64(4+4*is64) / uint64(2+rela)) - r := make([]sym.Reloc, n) + r := make([]loader.Reloc, n) p := rsect.base for j := 0; j < n; j++ { var add uint64 @@ -928,22 +935,22 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, } if info>>32 == 0 { // absolute relocation, don't bother reading the null symbol - rp.Sym = nil + rp.Sym = 0 } else { var elfsym ElfSym - if err := readelfsym(newSym, lookup, arch, elfobj, int(info>>32), &elfsym, 0, 0); err != nil { + if err := readelfsym(newSym, lookup, l, 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_) + if elfsym.sym == 0 { + return errorf("malformed elf file: %s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", l.SymName(sect.sym), 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)) + rp.Size, err = relSize(arch, pn, uint32(info)) if err != nil { return nil, 0, err } @@ -951,30 +958,30 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, rp.Add = int64(add) } else { // load addend from image - if rp.Siz == 4 { + if rp.Size == 4 { rp.Add = int64(e.Uint32(sect.base[rp.Off:])) - } else if rp.Siz == 8 { + } else if rp.Size == 8 { rp.Add = int64(e.Uint64(sect.base[rp.Off:])) } else { - return errorf("invalid rela size %d", rp.Siz) + return errorf("invalid rela size %d", rp.Size) } } - if rp.Siz == 2 { + if rp.Size == 2 { rp.Add = int64(int16(rp.Add)) } - if rp.Siz == 4 { + if rp.Size == 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])) + sort.Sort(loader.RelocByOff(r[:n])) // just in case - s := sect.sym - s.R = r - s.R = s.R[:n] + sb, _ := l.MakeSymbolUpdater(sect.sym) + r = r[:n] + sb.SetRelocs(r) } return textp, ehdrFlags, nil @@ -1008,7 +1015,7 @@ func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) { 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) { +func readelfsym(newSym, lookup func(string, int) loader.Sym, l *loader.Loader, 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 @@ -1040,7 +1047,8 @@ func readelfsym(newSym, lookup func(string, int) *sym.Symbol, arch *sys.Arch, el elfsym.other = b.Other } - var s *sym.Symbol + var s loader.Sym + if elfsym.name == "_GLOBAL_OFFSET_TABLE_" { elfsym.name = ".got" } @@ -1067,8 +1075,12 @@ func readelfsym(newSym, lookup func(string, int) *sym.Symbol, arch *sys.Arch, el // 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 + if s != 0 && elfsym.other == 2 { + if !l.IsExternal(s) { + _, s = l.MakeSymbolUpdater(s) + } + l.SetAttrDuplicateOK(s, true) + l.SetAttrVisibilityHidden(s, true) } } @@ -1084,9 +1096,8 @@ func readelfsym(newSym, lookup func(string, int) *sym.Symbol, arch *sys.Arch, el // so put it in the hash table. if needSym != 0 { s = lookup(elfsym.name, localSymVersion) - s.Attr |= sym.AttrVisibilityHidden + l.SetAttrVisibilityHidden(s, true) } - break } @@ -1098,20 +1109,19 @@ func readelfsym(newSym, lookup func(string, int) *sym.Symbol, arch *sys.Arch, el // reduce mem use, but also (possibly) make it harder // to debug problems. s = newSym(elfsym.name, localSymVersion) - - s.Attr |= sym.AttrVisibilityHidden + l.SetAttrVisibilityHidden(s, true) } case ElfSymBindWeak: if needSym != 0 { s = lookup(elfsym.name, 0) if elfsym.other == 2 { - s.Attr |= sym.AttrVisibilityHidden + l.SetAttrVisibilityHidden(s, true) } // Allow weak symbols to be duplicated when already defined. - if s.Outer != nil { - s.Attr |= sym.AttrDuplicateOK + if l.OuterSym(s) != 0 { + l.SetAttrDuplicateOK(s, true) } } @@ -1123,8 +1133,9 @@ func readelfsym(newSym, lookup func(string, int) *sym.Symbol, arch *sys.Arch, el // 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 + if s != 0 && l.SymType(s) == 0 && !l.AttrVisibilityHidden(s) && elfsym.type_ != ElfSymTypeSection { + sb, _ := l.MakeSymbolUpdater(s) + sb.SetType(sym.SXREF) } elfsym.sym = s |
