]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: move ldmacho to its own package
authorDavid Crawshaw <crawshaw@golang.org>
Fri, 6 Oct 2017 15:53:52 +0000 (11:53 -0400)
committerDavid Crawshaw <crawshaw@golang.org>
Fri, 6 Oct 2017 22:01:22 +0000 (22:01 +0000)
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>

src/cmd/dist/buildtool.go
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/ldelf.go
src/cmd/link/internal/ld/ldpe.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/loadmacho/ldmacho.go [moved from src/cmd/link/internal/ld/ldmacho.go with 84% similarity]
src/cmd/link/internal/sym/reloc.go
src/cmd/link/internal/sym/symbol.go

index cdecbc20b21d28f3f8c9f76d852986c603bc9fab..6b3fa81de5f6a13f9fae82ef913bed78b29bbf82 100644 (file)
@@ -67,6 +67,7 @@ var bootstrapDirs = []string{
        "cmd/link/internal/arm",
        "cmd/link/internal/arm64",
        "cmd/link/internal/ld",
+       "cmd/link/internal/loadmacho",
        "cmd/link/internal/mips",
        "cmd/link/internal/mips64",
        "cmd/link/internal/objfile",
index 5908fc1798258e768938535433709da3f11f9596..88e9193f58b85dc274156c105d5e162629455b08 100644 (file)
@@ -45,83 +45,6 @@ import (
        "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
 func isRuntimeDepPkg(pkg string) bool {
        switch pkg {
index c700d6269705bdf4641678c9804b3cbe7739f5b0..7882ffc232c460780c9ea5a9b34e94d98630ca50 100644 (file)
@@ -832,7 +832,7 @@ func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
                        continue
                }
                if s.Sub != nil {
-                       s.Sub = listsort(s.Sub)
+                       s.Sub = sym.SortSub(s.Sub)
                }
                if s.Type == sym.STEXT {
                        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);
-               sort.Sort(rbyoff(r[:n]))
+               sort.Sort(sym.RelocByOff(r[:n]))
                // just in case
 
                s := sect.sym
@@ -1100,28 +1100,6 @@ func readelfsym(ctxt *Link, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int,
        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 {
        // TODO(mdempsky): Replace this with a struct-valued switch statement
        // once golang.org/issue/15164 is fixed or found to not impair cmd/link
index ec960fe9d3cc138f90e77b665d1645519c9dd9c3..5a76f768768a5c69c7e69e573b094eb5a2d6d74c 100644 (file)
@@ -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.R = rs
@@ -367,7 +367,7 @@ func ldpeError(ctxt *Link, input *bio.Reader, pkg string, length int64, pn strin
                        continue
                }
                if s.Sub != nil {
-                       s.Sub = listsort(s.Sub)
+                       s.Sub = sym.SortSub(s.Sub)
                }
                if s.Type == sym.STEXT {
                        if s.Attr.OnList() {
index 237be4a2f3e7e8b9330557d52d5c640924f32917..ef94f8e3392925c05145a8bcde2342233a950cf8 100644 (file)
@@ -36,6 +36,7 @@ import (
        "cmd/internal/bio"
        "cmd/internal/objabi"
        "cmd/internal/sys"
+       "cmd/link/internal/loadmacho"
        "cmd/link/internal/objfile"
        "cmd/link/internal/sym"
        "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 {
+               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)
        }
 
similarity index 84%
rename from src/cmd/link/internal/ld/ldmacho.go
rename to src/cmd/link/internal/loadmacho/ldmacho.go
index 598dba27276a5edb5069e6c50816640f6666c116..12b48832f5af8a96c17cc7fc7c0aa3e256bcd3b9 100644 (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 (
+       "bytes"
        "cmd/internal/bio"
        "cmd/internal/objabi"
        "cmd/internal/sys"
@@ -8,7 +14,6 @@ import (
        "encoding/binary"
        "fmt"
        "io"
-       "log"
        "sort"
 )
 
@@ -44,6 +49,13 @@ const (
        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 {
        f          *bio.Reader
        base       int64 // off in f where Mach-O begins
@@ -411,8 +423,9 @@ func macholoadsym(m *ldMachoObj, symtab *ldMachoSymtab) int {
        return 0
 }
 
-func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
-       var err error
+// Load loads the Mach-O file pn from f.
+// 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 is64 bool
        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 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()
        if _, err := io.ReadFull(f, hdr[:]); err != nil {
-               goto bad
+               return errorf("%v", err)
        }
 
        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 {
                e = binary.LittleEndian
        } else {
-               err = fmt.Errorf("bad magic - not mach-o file")
-               goto bad
+               return errorf("bad magic - not mach-o file")
        }
 
        is64 = e.Uint32(hdr[:]) == 0xFEEDFACF
        ncmd = e.Uint32(hdr[4*4:])
        cmdsz = e.Uint32(hdr[5*4:])
        if ncmd > 0x10000 || cmdsz >= 0x01000000 {
-               err = fmt.Errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz)
-               goto bad
+               return errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz)
        }
 
        if is64 {
@@ -480,21 +495,18 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
        m.length = length
        m.name = pn
 
-       switch ctxt.Arch.Family {
+       switch arch.Family {
        default:
-               Errorf(nil, "%s: mach-o %s unimplemented", pn, ctxt.Arch.Name)
-               return
+               return errorf("mach-o %s unimplemented", arch.Name)
 
        case sys.AMD64:
                if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
-                       Errorf(nil, "%s: mach-o object but not amd64", pn)
-                       return
+                       return errorf("mach-o object but not amd64")
                }
 
        case sys.I386:
                if e != binary.LittleEndian || m.cputype != LdMachoCpu386 {
-                       Errorf(nil, "%s: mach-o object but not 386", pn)
-                       return
+                       return errorf("mach-o object but not 386")
                }
        }
 
@@ -502,8 +514,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
        off = uint32(len(hdr))
        cmdp = make([]byte, cmdsz)
        if _, err2 := io.ReadFull(f, cmdp); err2 != nil {
-               err = fmt.Errorf("reading cmds: %v", err)
-               goto bad
+               return errorf("reading cmds: %v", err)
        }
 
        // read and parse load commands
@@ -521,8 +532,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
                off += sz
                if ty == LdMachoCmdSymtab {
                        if symtab != nil {
-                               err = fmt.Errorf("multiple symbol tables")
-                               goto bad
+                               return errorf("multiple symbol tables")
                        }
 
                        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 c != nil {
-                               err = fmt.Errorf("multiple load commands")
-                               goto bad
+                               return errorf("multiple load commands")
                        }
 
                        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
        // as well use one large chunk.
        if c == nil {
-               err = fmt.Errorf("no load command")
-               goto bad
+               return errorf("no load command")
        }
 
        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 {
-               err = fmt.Errorf("load segment out of range")
-               goto bad
+               return errorf("load segment out of range")
        }
 
        dat = make([]byte, c.seg.filesz)
        if f.Seek(m.base+int64(c.seg.fileoff), 0) < 0 {
-               err = fmt.Errorf("cannot load object data: %v", err)
-               goto bad
+               return errorf("cannot load object data: %v", err)
        }
        if _, err2 := io.ReadFull(f, dat); err2 != nil {
-               err = fmt.Errorf("cannot load object data: %v", err)
-               goto bad
+               return errorf("cannot load object data: %v", err)
        }
 
        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
                }
                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 {
-                       err = fmt.Errorf("duplicate %s/%s", sect.segname, sect.name)
-                       goto bad
+                       return errorf("duplicate %s/%s", sect.segname, sect.name)
                }
 
                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 {
                        v = localSymVersion
                }
-               s = ctxt.Syms.Lookup(name, v)
+               s = syms.Lookup(name, v)
                if machsym.type_&N_EXT == 0 {
                        s.Attr |= sym.AttrDuplicateOK
                }
@@ -640,22 +644,20 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
                        continue
                }
                if uint32(machsym.sectnum) > c.seg.nsect {
-                       err = fmt.Errorf("reference to invalid section %d", machsym.sectnum)
-                       goto bad
+                       return errorf("reference to invalid section %d", machsym.sectnum)
                }
 
                sect = &c.seg.sect[machsym.sectnum-1]
                outer = sect.sym
                if outer == nil {
-                       err = fmt.Errorf("reference to invalid section %s/%s", sect.segname, sect.name)
-                       continue
+                       return errorf("reference to invalid section %s/%s", sect.segname, sect.name)
                }
 
                if s.Outer != nil {
                        if s.Attr.DuplicateOK() {
                                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
@@ -668,7 +670,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
                }
                if outer.Type == sym.STEXT {
                        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
                }
@@ -685,7 +687,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
                        continue
                }
                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.
                        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.Attr.OnList() {
-                               log.Fatalf("symbol %s listed multiple times", s.Name)
+                               return errorf("symbol %s listed multiple times", s.Name)
                        }
                        s.Attr |= sym.AttrOnList
-                       ctxt.Textp = append(ctxt.Textp, s)
+                       textp = append(textp, s)
                        for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
                                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
-                               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]
                        rel = &sect.rel[j]
                        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
-                                       Errorf(s, "unexpected scattered relocation")
-                                       continue
+                                       return errorf("%v: unexpected scattered relocation", s)
                                }
 
                                // 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
                                // and use that as the pc-relative base.
                                if uint32(j+1) >= sect.nreloc {
-                                       err = fmt.Errorf("unsupported scattered relocation %d", int(rel.type_))
-                                       goto bad
+                                       return errorf("unsupported scattered relocation %d", int(rel.type_))
                                }
 
                                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_))
-                                       goto bad
+                                       return errorf("unsupported scattered relocation %d/%d", int(rel.type_), int(sect.rel[j+1].type_))
                                }
 
                                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
                                                        // fetch symbol number
                                                        if dsymtab == nil || k < 0 || uint32(k) >= dsymtab.nindirectsyms || dsymtab.indir == nil {
-                                                               err = fmt.Errorf("invalid scattered relocation: indirect symbol reference out of range")
-                                                               goto bad
+                                                               return errorf("invalid scattered relocation: indirect symbol reference out of range")
                                                        }
 
                                                        k = int(dsymtab.indir[k])
                                                        if k < 0 || uint32(k) >= symtab.nsym {
-                                                               err = fmt.Errorf("invalid scattered relocation: symbol reference out of range")
-                                                               goto bad
+                                                               return errorf("invalid scattered relocation: symbol reference out of range")
                                                        }
 
                                                        rp.Sym = symtab.sym[k].sym
                                                } else {
-                                                       err = fmt.Errorf("unsupported scattered relocation: reference to %s/%s", ks.segname, ks.name)
-                                                       goto bad
+                                                       return errorf("unsupported scattered relocation: reference to %s/%s", ks.segname, ks.name)
                                                }
 
                                                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)
-                               goto bad
+                               return errorf("unsupported scattered relocation: invalid address %#x", rel.addr)
 
                        }
 
@@ -827,7 +822,7 @@ func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
                        rp.Off = int32(rel.addr)
 
                        // 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.
                                //
                                // 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
                        // 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
                                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
                        // it *is* the PC being subtracted. Use that to make
                        // 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)
                        }
                        if rel.extrn == 0 {
                                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)
-                                       goto bad
+                                       return errorf("invalid relocation: section reference out of range %d vs %d", rel.symnum, c.seg.nsect)
                                }
 
                                rp.Sym = c.seg.sect[rel.symnum-1].sym
                                if rp.Sym == nil {
-                                       err = fmt.Errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name)
-                                       goto bad
+                                       return errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name)
                                }
 
                                // References to symbols in other sections
                                // include that information in the addend.
                                // We only care about the delta from the
                                // section base.
-                               if ctxt.Arch.Family == sys.I386 {
+                               if arch.Family == sys.I386 {
                                        rp.Add -= int64(c.seg.sect[rel.symnum-1].addr)
                                }
                        } else {
                                if rel.symnum >= symtab.nsym {
-                                       err = fmt.Errorf("invalid relocation: symbol reference out of range")
-                                       goto bad
+                                       return errorf("invalid relocation: symbol reference out of range")
                                }
 
                                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++
                }
 
-               sort.Sort(rbyoff(r[:rpi]))
+               sort.Sort(sym.RelocByOff(r[:rpi]))
                s.R = r
                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)
 }
index e55fd27f2202584b5c5dac6fd93142af169bee79..fc62c385f4025a576822c510f92201d40b4e7a4c 100644 (file)
@@ -95,3 +95,22 @@ func RelocName(arch *sys.Arch, r objabi.RelocType) 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
+}
index 4691e3055b138ea484ecac0d8252f6b0cf779bf1..74f19a798ed6c7e94e2988d9da1cbea2df7b8fa5 100644 (file)
@@ -264,6 +264,80 @@ func (s *Symbol) setUintXX(arch *sys.Arch, off int64, v uint64, wid int64) int64
        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 {
        Args        int32
        Locals      int32