mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/link: move ldmacho to its own package
For #22095 Change-Id: I660080279692b74669c45f42c28cccff71bd33b5 Reviewed-on: https://go-review.googlesource.com/68930 Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: David Crawshaw <crawshaw@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
840f2c167f
commit
f7ad3a04f9
8 changed files with 180 additions and 179 deletions
1
src/cmd/dist/buildtool.go
vendored
1
src/cmd/dist/buildtool.go
vendored
|
|
@ -67,6 +67,7 @@ var bootstrapDirs = []string{
|
||||||
"cmd/link/internal/arm",
|
"cmd/link/internal/arm",
|
||||||
"cmd/link/internal/arm64",
|
"cmd/link/internal/arm64",
|
||||||
"cmd/link/internal/ld",
|
"cmd/link/internal/ld",
|
||||||
|
"cmd/link/internal/loadmacho",
|
||||||
"cmd/link/internal/mips",
|
"cmd/link/internal/mips",
|
||||||
"cmd/link/internal/mips64",
|
"cmd/link/internal/mips64",
|
||||||
"cmd/link/internal/objfile",
|
"cmd/link/internal/objfile",
|
||||||
|
|
|
||||||
|
|
@ -45,83 +45,6 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
* divide-and-conquer list-link (by Sub) sort of sym.Symbol* by Value.
|
|
||||||
* Used for sub-symbols when loading host objects (see e.g. ldelf.go).
|
|
||||||
*/
|
|
||||||
|
|
||||||
func listsort(l *sym.Symbol) *sym.Symbol {
|
|
||||||
if l == nil || l.Sub == nil {
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
l1 := l
|
|
||||||
l2 := l
|
|
||||||
for {
|
|
||||||
l2 = l2.Sub
|
|
||||||
if l2 == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
l2 = l2.Sub
|
|
||||||
if l2 == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
l1 = l1.Sub
|
|
||||||
}
|
|
||||||
|
|
||||||
l2 = l1.Sub
|
|
||||||
l1.Sub = nil
|
|
||||||
l1 = listsort(l)
|
|
||||||
l2 = listsort(l2)
|
|
||||||
|
|
||||||
/* set up lead element */
|
|
||||||
if l1.Value < l2.Value {
|
|
||||||
l = l1
|
|
||||||
l1 = l1.Sub
|
|
||||||
} else {
|
|
||||||
l = l2
|
|
||||||
l2 = l2.Sub
|
|
||||||
}
|
|
||||||
|
|
||||||
le := l
|
|
||||||
|
|
||||||
for {
|
|
||||||
if l1 == nil {
|
|
||||||
for l2 != nil {
|
|
||||||
le.Sub = l2
|
|
||||||
le = l2
|
|
||||||
l2 = l2.Sub
|
|
||||||
}
|
|
||||||
|
|
||||||
le.Sub = nil
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if l2 == nil {
|
|
||||||
for l1 != nil {
|
|
||||||
le.Sub = l1
|
|
||||||
le = l1
|
|
||||||
l1 = l1.Sub
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if l1.Value < l2.Value {
|
|
||||||
le.Sub = l1
|
|
||||||
le = l1
|
|
||||||
l1 = l1.Sub
|
|
||||||
} else {
|
|
||||||
le.Sub = l2
|
|
||||||
le = l2
|
|
||||||
l2 = l2.Sub
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
le.Sub = nil
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
// isRuntimeDepPkg returns whether pkg is the runtime package or its dependency
|
// isRuntimeDepPkg returns whether pkg is the runtime package or its dependency
|
||||||
func isRuntimeDepPkg(pkg string) bool {
|
func isRuntimeDepPkg(pkg string) bool {
|
||||||
switch pkg {
|
switch pkg {
|
||||||
|
|
|
||||||
|
|
@ -832,7 +832,7 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if s.Sub != nil {
|
if s.Sub != nil {
|
||||||
s.Sub = listsort(s.Sub)
|
s.Sub = sym.SortSub(s.Sub)
|
||||||
}
|
}
|
||||||
if s.Type == sym.STEXT {
|
if s.Type == sym.STEXT {
|
||||||
if s.Attr.OnList() {
|
if s.Attr.OnList() {
|
||||||
|
|
@ -947,7 +947,7 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
|
//print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
|
||||||
sort.Sort(rbyoff(r[:n]))
|
sort.Sort(sym.RelocByOff(r[:n]))
|
||||||
// just in case
|
// just in case
|
||||||
|
|
||||||
s := sect.sym
|
s := sect.sym
|
||||||
|
|
@ -1100,28 +1100,6 @@ func readelfsym(ctxt *Link, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type rbyoff []sym.Reloc
|
|
||||||
|
|
||||||
func (x rbyoff) Len() int {
|
|
||||||
return len(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x rbyoff) Swap(i, j int) {
|
|
||||||
x[i], x[j] = x[j], x[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x rbyoff) Less(i, j int) bool {
|
|
||||||
a := &x[i]
|
|
||||||
b := &x[j]
|
|
||||||
if a.Off < b.Off {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if a.Off > b.Off {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func relSize(ctxt *Link, pn string, elftype uint32) uint8 {
|
func relSize(ctxt *Link, pn string, elftype uint32) uint8 {
|
||||||
// TODO(mdempsky): Replace this with a struct-valued switch statement
|
// TODO(mdempsky): Replace this with a struct-valued switch statement
|
||||||
// once golang.org/issue/15164 is fixed or found to not impair cmd/link
|
// once golang.org/issue/15164 is fixed or found to not impair cmd/link
|
||||||
|
|
|
||||||
|
|
@ -272,7 +272,7 @@ func ldpeError(ctxt *Link, input *bio.Reader, pkg string, length int64, pn strin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(rbyoff(rs[:rsect.NumberOfRelocations]))
|
sort.Sort(sym.RelocByOff(rs[:rsect.NumberOfRelocations]))
|
||||||
|
|
||||||
s := sectsyms[rsect]
|
s := sectsyms[rsect]
|
||||||
s.R = rs
|
s.R = rs
|
||||||
|
|
@ -367,7 +367,7 @@ func ldpeError(ctxt *Link, input *bio.Reader, pkg string, length int64, pn strin
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if s.Sub != nil {
|
if s.Sub != nil {
|
||||||
s.Sub = listsort(s.Sub)
|
s.Sub = sym.SortSub(s.Sub)
|
||||||
}
|
}
|
||||||
if s.Type == sym.STEXT {
|
if s.Type == sym.STEXT {
|
||||||
if s.Attr.OnList() {
|
if s.Attr.OnList() {
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import (
|
||||||
"cmd/internal/bio"
|
"cmd/internal/bio"
|
||||||
"cmd/internal/objabi"
|
"cmd/internal/objabi"
|
||||||
"cmd/internal/sys"
|
"cmd/internal/sys"
|
||||||
|
"cmd/link/internal/loadmacho"
|
||||||
"cmd/link/internal/objfile"
|
"cmd/link/internal/objfile"
|
||||||
"cmd/link/internal/sym"
|
"cmd/link/internal/sym"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
|
@ -1384,6 +1385,14 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
|
||||||
}
|
}
|
||||||
|
|
||||||
if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
|
if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
|
||||||
|
ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
|
textp, err := loadmacho.Load(ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
|
||||||
|
if err != nil {
|
||||||
|
Errorf(nil, "%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctxt.Textp = append(ctxt.Textp, textp...)
|
||||||
|
}
|
||||||
return ldhostobj(ldmacho, f, pkg, length, pn, file)
|
return ldhostobj(ldmacho, f, pkg, length, pn, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
package ld
|
// 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 loadmacho implements a Mach-O file reader.
|
||||||
|
package loadmacho
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"cmd/internal/bio"
|
"cmd/internal/bio"
|
||||||
"cmd/internal/objabi"
|
"cmd/internal/objabi"
|
||||||
"cmd/internal/sys"
|
"cmd/internal/sys"
|
||||||
|
|
@ -8,7 +14,6 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -44,6 +49,13 @@ const (
|
||||||
N_STAB = 0xe0
|
N_STAB = 0xe0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld
|
||||||
|
const (
|
||||||
|
MACHO_X86_64_RELOC_UNSIGNED = 0
|
||||||
|
MACHO_X86_64_RELOC_SIGNED = 1
|
||||||
|
MACHO_FAKE_GOTPCREL = 100
|
||||||
|
)
|
||||||
|
|
||||||
type ldMachoObj struct {
|
type ldMachoObj struct {
|
||||||
f *bio.Reader
|
f *bio.Reader
|
||||||
base int64 // off in f where Mach-O begins
|
base int64 // off in f where Mach-O begins
|
||||||
|
|
@ -411,8 +423,9 @@ func macholoadsym(m *ldMachoObj, symtab *ldMachoSymtab) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
// Load loads the Mach-O file pn from f.
|
||||||
var err error
|
// Symbols are written into syms, and a slice of the text symbols is returned.
|
||||||
|
func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
|
||||||
var j int
|
var j int
|
||||||
var is64 bool
|
var is64 bool
|
||||||
var secaddr uint64
|
var secaddr uint64
|
||||||
|
|
@ -439,10 +452,14 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
var rp *sym.Reloc
|
var rp *sym.Reloc
|
||||||
var name string
|
var name string
|
||||||
|
|
||||||
localSymVersion := ctxt.Syms.IncVersion()
|
errorf := func(str string, args ...interface{}) ([]*sym.Symbol, error) {
|
||||||
|
return nil, fmt.Errorf("loadmacho: %v: %v", pn, fmt.Sprintf(str, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
localSymVersion := syms.IncVersion()
|
||||||
base := f.Offset()
|
base := f.Offset()
|
||||||
if _, err := io.ReadFull(f, hdr[:]); err != nil {
|
if _, err := io.ReadFull(f, hdr[:]); err != nil {
|
||||||
goto bad
|
return errorf("%v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if binary.BigEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
|
if binary.BigEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
|
||||||
|
|
@ -450,16 +467,14 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
} else if binary.LittleEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
|
} else if binary.LittleEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
|
||||||
e = binary.LittleEndian
|
e = binary.LittleEndian
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("bad magic - not mach-o file")
|
return errorf("bad magic - not mach-o file")
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is64 = e.Uint32(hdr[:]) == 0xFEEDFACF
|
is64 = e.Uint32(hdr[:]) == 0xFEEDFACF
|
||||||
ncmd = e.Uint32(hdr[4*4:])
|
ncmd = e.Uint32(hdr[4*4:])
|
||||||
cmdsz = e.Uint32(hdr[5*4:])
|
cmdsz = e.Uint32(hdr[5*4:])
|
||||||
if ncmd > 0x10000 || cmdsz >= 0x01000000 {
|
if ncmd > 0x10000 || cmdsz >= 0x01000000 {
|
||||||
err = fmt.Errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz)
|
return errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz)
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if is64 {
|
if is64 {
|
||||||
|
|
@ -480,21 +495,18 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
m.length = length
|
m.length = length
|
||||||
m.name = pn
|
m.name = pn
|
||||||
|
|
||||||
switch ctxt.Arch.Family {
|
switch arch.Family {
|
||||||
default:
|
default:
|
||||||
Errorf(nil, "%s: mach-o %s unimplemented", pn, ctxt.Arch.Name)
|
return errorf("mach-o %s unimplemented", arch.Name)
|
||||||
return
|
|
||||||
|
|
||||||
case sys.AMD64:
|
case sys.AMD64:
|
||||||
if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
|
if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
|
||||||
Errorf(nil, "%s: mach-o object but not amd64", pn)
|
return errorf("mach-o object but not amd64")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case sys.I386:
|
case sys.I386:
|
||||||
if e != binary.LittleEndian || m.cputype != LdMachoCpu386 {
|
if e != binary.LittleEndian || m.cputype != LdMachoCpu386 {
|
||||||
Errorf(nil, "%s: mach-o object but not 386", pn)
|
return errorf("mach-o object but not 386")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -502,8 +514,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
off = uint32(len(hdr))
|
off = uint32(len(hdr))
|
||||||
cmdp = make([]byte, cmdsz)
|
cmdp = make([]byte, cmdsz)
|
||||||
if _, err2 := io.ReadFull(f, cmdp); err2 != nil {
|
if _, err2 := io.ReadFull(f, cmdp); err2 != nil {
|
||||||
err = fmt.Errorf("reading cmds: %v", err)
|
return errorf("reading cmds: %v", err)
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// read and parse load commands
|
// read and parse load commands
|
||||||
|
|
@ -521,8 +532,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
off += sz
|
off += sz
|
||||||
if ty == LdMachoCmdSymtab {
|
if ty == LdMachoCmdSymtab {
|
||||||
if symtab != nil {
|
if symtab != nil {
|
||||||
err = fmt.Errorf("multiple symbol tables")
|
return errorf("multiple symbol tables")
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
symtab = &m.cmd[i].sym
|
symtab = &m.cmd[i].sym
|
||||||
|
|
@ -536,8 +546,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
|
|
||||||
if (is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment) {
|
if (is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment) {
|
||||||
if c != nil {
|
if c != nil {
|
||||||
err = fmt.Errorf("multiple load commands")
|
return errorf("multiple load commands")
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c = &m.cmd[i]
|
c = &m.cmd[i]
|
||||||
|
|
@ -549,8 +558,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
// the memory anyway for the symbol images, so we might
|
// the memory anyway for the symbol images, so we might
|
||||||
// as well use one large chunk.
|
// as well use one large chunk.
|
||||||
if c == nil {
|
if c == nil {
|
||||||
err = fmt.Errorf("no load command")
|
return errorf("no load command")
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if symtab == nil {
|
if symtab == nil {
|
||||||
|
|
@ -559,18 +567,15 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if int64(c.seg.fileoff+c.seg.filesz) >= length {
|
if int64(c.seg.fileoff+c.seg.filesz) >= length {
|
||||||
err = fmt.Errorf("load segment out of range")
|
return errorf("load segment out of range")
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dat = make([]byte, c.seg.filesz)
|
dat = make([]byte, c.seg.filesz)
|
||||||
if f.Seek(m.base+int64(c.seg.fileoff), 0) < 0 {
|
if f.Seek(m.base+int64(c.seg.fileoff), 0) < 0 {
|
||||||
err = fmt.Errorf("cannot load object data: %v", err)
|
return errorf("cannot load object data: %v", err)
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
if _, err2 := io.ReadFull(f, dat); err2 != nil {
|
if _, err2 := io.ReadFull(f, dat); err2 != nil {
|
||||||
err = fmt.Errorf("cannot load object data: %v", err)
|
return errorf("cannot load object data: %v", err)
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; uint32(i) < c.seg.nsect; i++ {
|
for i := 0; uint32(i) < c.seg.nsect; i++ {
|
||||||
|
|
@ -582,10 +587,9 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
name = fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
|
name = fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
|
||||||
s = ctxt.Syms.Lookup(name, localSymVersion)
|
s = syms.Lookup(name, localSymVersion)
|
||||||
if s.Type != 0 {
|
if s.Type != 0 {
|
||||||
err = fmt.Errorf("duplicate %s/%s", sect.segname, sect.name)
|
return errorf("duplicate %s/%s", sect.segname, sect.name)
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if sect.flags&0xff == 1 { // S_ZEROFILL
|
if sect.flags&0xff == 1 { // S_ZEROFILL
|
||||||
|
|
@ -631,7 +635,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
if machsym.type_&N_EXT == 0 {
|
if machsym.type_&N_EXT == 0 {
|
||||||
v = localSymVersion
|
v = localSymVersion
|
||||||
}
|
}
|
||||||
s = ctxt.Syms.Lookup(name, v)
|
s = syms.Lookup(name, v)
|
||||||
if machsym.type_&N_EXT == 0 {
|
if machsym.type_&N_EXT == 0 {
|
||||||
s.Attr |= sym.AttrDuplicateOK
|
s.Attr |= sym.AttrDuplicateOK
|
||||||
}
|
}
|
||||||
|
|
@ -640,22 +644,20 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if uint32(machsym.sectnum) > c.seg.nsect {
|
if uint32(machsym.sectnum) > c.seg.nsect {
|
||||||
err = fmt.Errorf("reference to invalid section %d", machsym.sectnum)
|
return errorf("reference to invalid section %d", machsym.sectnum)
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sect = &c.seg.sect[machsym.sectnum-1]
|
sect = &c.seg.sect[machsym.sectnum-1]
|
||||||
outer = sect.sym
|
outer = sect.sym
|
||||||
if outer == nil {
|
if outer == nil {
|
||||||
err = fmt.Errorf("reference to invalid section %s/%s", sect.segname, sect.name)
|
return errorf("reference to invalid section %s/%s", sect.segname, sect.name)
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Outer != nil {
|
if s.Outer != nil {
|
||||||
if s.Attr.DuplicateOK() {
|
if s.Attr.DuplicateOK() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
|
return errorf("duplicate symbol reference: %s in both %s and %s", s.Name, s.Outer.Name, sect.sym.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Type = outer.Type | sym.SSUB
|
s.Type = outer.Type | sym.SSUB
|
||||||
|
|
@ -668,7 +670,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
}
|
}
|
||||||
if outer.Type == sym.STEXT {
|
if outer.Type == sym.STEXT {
|
||||||
if s.Attr.External() && !s.Attr.DuplicateOK() {
|
if s.Attr.External() && !s.Attr.DuplicateOK() {
|
||||||
Errorf(s, "%s: duplicate symbol definition", pn)
|
return errorf("%v: duplicate symbol definition", s)
|
||||||
}
|
}
|
||||||
s.Attr |= sym.AttrExternal
|
s.Attr |= sym.AttrExternal
|
||||||
}
|
}
|
||||||
|
|
@ -685,7 +687,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if s.Sub != nil {
|
if s.Sub != nil {
|
||||||
s.Sub = listsort(s.Sub)
|
s.Sub = sym.SortSub(s.Sub)
|
||||||
|
|
||||||
// assign sizes, now that we know symbols in sorted order.
|
// assign sizes, now that we know symbols in sorted order.
|
||||||
for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
|
for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
|
||||||
|
|
@ -699,16 +701,16 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
|
|
||||||
if s.Type == sym.STEXT {
|
if s.Type == sym.STEXT {
|
||||||
if s.Attr.OnList() {
|
if s.Attr.OnList() {
|
||||||
log.Fatalf("symbol %s listed multiple times", s.Name)
|
return errorf("symbol %s listed multiple times", s.Name)
|
||||||
}
|
}
|
||||||
s.Attr |= sym.AttrOnList
|
s.Attr |= sym.AttrOnList
|
||||||
ctxt.Textp = append(ctxt.Textp, s)
|
textp = append(textp, s)
|
||||||
for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
|
for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
|
||||||
if s1.Attr.OnList() {
|
if s1.Attr.OnList() {
|
||||||
log.Fatalf("symbol %s listed multiple times", s1.Name)
|
return errorf("symbol %s listed multiple times", s1.Name)
|
||||||
}
|
}
|
||||||
s1.Attr |= sym.AttrOnList
|
s1.Attr |= sym.AttrOnList
|
||||||
ctxt.Textp = append(ctxt.Textp, s1)
|
textp = append(textp, s1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -731,10 +733,9 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
rp = &r[rpi]
|
rp = &r[rpi]
|
||||||
rel = §.rel[j]
|
rel = §.rel[j]
|
||||||
if rel.scattered != 0 {
|
if rel.scattered != 0 {
|
||||||
if ctxt.Arch.Family != sys.I386 {
|
if arch.Family != sys.I386 {
|
||||||
// mach-o only uses scattered relocation on 32-bit platforms
|
// mach-o only uses scattered relocation on 32-bit platforms
|
||||||
Errorf(s, "unexpected scattered relocation")
|
return errorf("%v: unexpected scattered relocation", s)
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// on 386, rewrite scattered 4/1 relocation and some
|
// on 386, rewrite scattered 4/1 relocation and some
|
||||||
|
|
@ -743,13 +744,11 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
// assume that the second in the pair is in this section
|
// assume that the second in the pair is in this section
|
||||||
// and use that as the pc-relative base.
|
// and use that as the pc-relative base.
|
||||||
if uint32(j+1) >= sect.nreloc {
|
if uint32(j+1) >= sect.nreloc {
|
||||||
err = fmt.Errorf("unsupported scattered relocation %d", int(rel.type_))
|
return errorf("unsupported scattered relocation %d", int(rel.type_))
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if sect.rel[j+1].scattered == 0 || sect.rel[j+1].type_ != 1 || (rel.type_ != 4 && rel.type_ != 2) || uint64(sect.rel[j+1].value) < sect.addr || uint64(sect.rel[j+1].value) >= sect.addr+sect.size {
|
if sect.rel[j+1].scattered == 0 || sect.rel[j+1].type_ != 1 || (rel.type_ != 4 && rel.type_ != 2) || uint64(sect.rel[j+1].value) < sect.addr || uint64(sect.rel[j+1].value) >= sect.addr+sect.size {
|
||||||
err = fmt.Errorf("unsupported scattered relocation %d/%d", int(rel.type_), int(sect.rel[j+1].type_))
|
return errorf("unsupported scattered relocation %d/%d", int(rel.type_), int(sect.rel[j+1].type_))
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rp.Siz = rel.length
|
rp.Siz = rel.length
|
||||||
|
|
@ -792,20 +791,17 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
// load indirect table for __pointers
|
// load indirect table for __pointers
|
||||||
// fetch symbol number
|
// fetch symbol number
|
||||||
if dsymtab == nil || k < 0 || uint32(k) >= dsymtab.nindirectsyms || dsymtab.indir == nil {
|
if dsymtab == nil || k < 0 || uint32(k) >= dsymtab.nindirectsyms || dsymtab.indir == nil {
|
||||||
err = fmt.Errorf("invalid scattered relocation: indirect symbol reference out of range")
|
return errorf("invalid scattered relocation: indirect symbol reference out of range")
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
k = int(dsymtab.indir[k])
|
k = int(dsymtab.indir[k])
|
||||||
if k < 0 || uint32(k) >= symtab.nsym {
|
if k < 0 || uint32(k) >= symtab.nsym {
|
||||||
err = fmt.Errorf("invalid scattered relocation: symbol reference out of range")
|
return errorf("invalid scattered relocation: symbol reference out of range")
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rp.Sym = symtab.sym[k].sym
|
rp.Sym = symtab.sym[k].sym
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("unsupported scattered relocation: reference to %s/%s", ks.segname, ks.name)
|
return errorf("unsupported scattered relocation: reference to %s/%s", ks.segname, ks.name)
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rpi++
|
rpi++
|
||||||
|
|
@ -817,8 +813,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = fmt.Errorf("unsupported scattered relocation: invalid address %#x", rel.addr)
|
return errorf("unsupported scattered relocation: invalid address %#x", rel.addr)
|
||||||
goto bad
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -827,7 +822,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
rp.Off = int32(rel.addr)
|
rp.Off = int32(rel.addr)
|
||||||
|
|
||||||
// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
|
// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
|
||||||
if ctxt.Arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_SIGNED {
|
if arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_SIGNED {
|
||||||
// Calculate the addend as the offset into the section.
|
// Calculate the addend as the offset into the section.
|
||||||
//
|
//
|
||||||
// The rip-relative offset stored in the object file is encoded
|
// The rip-relative offset stored in the object file is encoded
|
||||||
|
|
@ -852,7 +847,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
|
|
||||||
// An unsigned internal relocation has a value offset
|
// An unsigned internal relocation has a value offset
|
||||||
// by the section address.
|
// by the section address.
|
||||||
if ctxt.Arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_UNSIGNED {
|
if arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_UNSIGNED {
|
||||||
secaddr = c.seg.sect[rel.symnum-1].addr
|
secaddr = c.seg.sect[rel.symnum-1].addr
|
||||||
rp.Add -= int64(secaddr)
|
rp.Add -= int64(secaddr)
|
||||||
}
|
}
|
||||||
|
|
@ -860,32 +855,29 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
// For i386 Mach-O PC-relative, the addend is written such that
|
// For i386 Mach-O PC-relative, the addend is written such that
|
||||||
// it *is* the PC being subtracted. Use that to make
|
// it *is* the PC being subtracted. Use that to make
|
||||||
// it match our version of PC-relative.
|
// it match our version of PC-relative.
|
||||||
if rel.pcrel != 0 && ctxt.Arch.Family == sys.I386 {
|
if rel.pcrel != 0 && arch.Family == sys.I386 {
|
||||||
rp.Add += int64(rp.Off) + int64(rp.Siz)
|
rp.Add += int64(rp.Off) + int64(rp.Siz)
|
||||||
}
|
}
|
||||||
if rel.extrn == 0 {
|
if rel.extrn == 0 {
|
||||||
if rel.symnum < 1 || rel.symnum > c.seg.nsect {
|
if rel.symnum < 1 || rel.symnum > c.seg.nsect {
|
||||||
err = fmt.Errorf("invalid relocation: section reference out of range %d vs %d", rel.symnum, c.seg.nsect)
|
return errorf("invalid relocation: section reference out of range %d vs %d", rel.symnum, c.seg.nsect)
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rp.Sym = c.seg.sect[rel.symnum-1].sym
|
rp.Sym = c.seg.sect[rel.symnum-1].sym
|
||||||
if rp.Sym == nil {
|
if rp.Sym == nil {
|
||||||
err = fmt.Errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name)
|
return errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name)
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// References to symbols in other sections
|
// References to symbols in other sections
|
||||||
// include that information in the addend.
|
// include that information in the addend.
|
||||||
// We only care about the delta from the
|
// We only care about the delta from the
|
||||||
// section base.
|
// section base.
|
||||||
if ctxt.Arch.Family == sys.I386 {
|
if arch.Family == sys.I386 {
|
||||||
rp.Add -= int64(c.seg.sect[rel.symnum-1].addr)
|
rp.Add -= int64(c.seg.sect[rel.symnum-1].addr)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if rel.symnum >= symtab.nsym {
|
if rel.symnum >= symtab.nsym {
|
||||||
err = fmt.Errorf("invalid relocation: symbol reference out of range")
|
return errorf("invalid relocation: symbol reference out of range")
|
||||||
goto bad
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rp.Sym = symtab.sym[rel.symnum].sym
|
rp.Sym = symtab.sym[rel.symnum].sym
|
||||||
|
|
@ -894,13 +886,18 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||||
rpi++
|
rpi++
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(rbyoff(r[:rpi]))
|
sort.Sort(sym.RelocByOff(r[:rpi]))
|
||||||
s.R = r
|
s.R = r
|
||||||
s.R = s.R[:rpi]
|
s.R = s.R[:rpi]
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return textp, nil
|
||||||
|
}
|
||||||
bad:
|
|
||||||
Errorf(nil, "%s: malformed mach-o file: %v", pn, err)
|
func cstring(x []byte) string {
|
||||||
|
i := bytes.IndexByte(x, '\x00')
|
||||||
|
if i >= 0 {
|
||||||
|
x = x[:i]
|
||||||
|
}
|
||||||
|
return string(x)
|
||||||
}
|
}
|
||||||
|
|
@ -95,3 +95,22 @@ func RelocName(arch *sys.Arch, r objabi.RelocType) string {
|
||||||
|
|
||||||
return r.String()
|
return r.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RelocByOff implements sort.Interface for sorting relocations by offset.
|
||||||
|
type RelocByOff []Reloc
|
||||||
|
|
||||||
|
func (x RelocByOff) Len() int { return len(x) }
|
||||||
|
|
||||||
|
func (x RelocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||||
|
|
||||||
|
func (x RelocByOff) Less(i, j int) bool {
|
||||||
|
a := &x[i]
|
||||||
|
b := &x[j]
|
||||||
|
if a.Off < b.Off {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if a.Off > b.Off {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -264,6 +264,80 @@ func (s *Symbol) setUintXX(arch *sys.Arch, off int64, v uint64, wid int64) int64
|
||||||
return off + wid
|
return off + wid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SortSub sorts a linked-list (by Sub) of *Symbol by Value.
|
||||||
|
// Used for sub-symbols when loading host objects (see e.g. ldelf.go).
|
||||||
|
func SortSub(l *Symbol) *Symbol {
|
||||||
|
if l == nil || l.Sub == nil {
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
l1 := l
|
||||||
|
l2 := l
|
||||||
|
for {
|
||||||
|
l2 = l2.Sub
|
||||||
|
if l2 == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
l2 = l2.Sub
|
||||||
|
if l2 == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
l1 = l1.Sub
|
||||||
|
}
|
||||||
|
|
||||||
|
l2 = l1.Sub
|
||||||
|
l1.Sub = nil
|
||||||
|
l1 = SortSub(l)
|
||||||
|
l2 = SortSub(l2)
|
||||||
|
|
||||||
|
/* set up lead element */
|
||||||
|
if l1.Value < l2.Value {
|
||||||
|
l = l1
|
||||||
|
l1 = l1.Sub
|
||||||
|
} else {
|
||||||
|
l = l2
|
||||||
|
l2 = l2.Sub
|
||||||
|
}
|
||||||
|
|
||||||
|
le := l
|
||||||
|
|
||||||
|
for {
|
||||||
|
if l1 == nil {
|
||||||
|
for l2 != nil {
|
||||||
|
le.Sub = l2
|
||||||
|
le = l2
|
||||||
|
l2 = l2.Sub
|
||||||
|
}
|
||||||
|
|
||||||
|
le.Sub = nil
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if l2 == nil {
|
||||||
|
for l1 != nil {
|
||||||
|
le.Sub = l1
|
||||||
|
le = l1
|
||||||
|
l1 = l1.Sub
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if l1.Value < l2.Value {
|
||||||
|
le.Sub = l1
|
||||||
|
le = l1
|
||||||
|
l1 = l1.Sub
|
||||||
|
} else {
|
||||||
|
le.Sub = l2
|
||||||
|
le = l2
|
||||||
|
l2 = l2.Sub
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
le.Sub = nil
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
type FuncInfo struct {
|
type FuncInfo struct {
|
||||||
Args int32
|
Args int32
|
||||||
Locals int32
|
Locals int32
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue