mirror of
https://github.com/golang/go
synced 2024-11-13 12:40:26 -07:00
cmd/internal/macho: new package for handling mach-o files in toolchain
Currently the linker has some code handling and manipulating Mach-O files. Specifically, it augments the debug/macho package with file offset and length, so the content can be handled or updated easily with the file. Move this code to an internal package, so it can be used by other part of the toolchain, e.g. buildid computation. For #68678. Cq-Include-Trybots: luci.golang.try:gotip-darwin-amd64_14,gotip-darwin-arm64_13 Change-Id: I2311af0a06441b7fd887ca5c6ed9e6fc44670a16 Reviewed-on: https://go-review.googlesource.com/c/go/+/618596 Reviewed-by: Than McIntosh <thanm@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
20ed603118
commit
f2d9f5ffca
1
src/cmd/dist/buildtool.go
vendored
1
src/cmd/dist/buildtool.go
vendored
@ -46,6 +46,7 @@ var bootstrapDirs = []string{
|
||||
"cmd/internal/gcprog",
|
||||
"cmd/internal/goobj",
|
||||
"cmd/internal/hash",
|
||||
"cmd/internal/macho",
|
||||
"cmd/internal/obj/...",
|
||||
"cmd/internal/objabi",
|
||||
"cmd/internal/pgo",
|
||||
|
134
src/cmd/internal/macho/macho.go
Normal file
134
src/cmd/internal/macho/macho.go
Normal file
@ -0,0 +1,134 @@
|
||||
// Copyright 2024 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 macho provides functionalities to handle Mach-O
|
||||
// beyond the debug/macho package, for the toolchain.
|
||||
package macho
|
||||
|
||||
import (
|
||||
"debug/macho"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
LC_SEGMENT = 0x1
|
||||
LC_SYMTAB = 0x2
|
||||
LC_SYMSEG = 0x3
|
||||
LC_THREAD = 0x4
|
||||
LC_UNIXTHREAD = 0x5
|
||||
LC_LOADFVMLIB = 0x6
|
||||
LC_IDFVMLIB = 0x7
|
||||
LC_IDENT = 0x8
|
||||
LC_FVMFILE = 0x9
|
||||
LC_PREPAGE = 0xa
|
||||
LC_DYSYMTAB = 0xb
|
||||
LC_LOAD_DYLIB = 0xc
|
||||
LC_ID_DYLIB = 0xd
|
||||
LC_LOAD_DYLINKER = 0xe
|
||||
LC_ID_DYLINKER = 0xf
|
||||
LC_PREBOUND_DYLIB = 0x10
|
||||
LC_ROUTINES = 0x11
|
||||
LC_SUB_FRAMEWORK = 0x12
|
||||
LC_SUB_UMBRELLA = 0x13
|
||||
LC_SUB_CLIENT = 0x14
|
||||
LC_SUB_LIBRARY = 0x15
|
||||
LC_TWOLEVEL_HINTS = 0x16
|
||||
LC_PREBIND_CKSUM = 0x17
|
||||
LC_LOAD_WEAK_DYLIB = 0x80000018
|
||||
LC_SEGMENT_64 = 0x19
|
||||
LC_ROUTINES_64 = 0x1a
|
||||
LC_UUID = 0x1b
|
||||
LC_RPATH = 0x8000001c
|
||||
LC_CODE_SIGNATURE = 0x1d
|
||||
LC_SEGMENT_SPLIT_INFO = 0x1e
|
||||
LC_REEXPORT_DYLIB = 0x8000001f
|
||||
LC_LAZY_LOAD_DYLIB = 0x20
|
||||
LC_ENCRYPTION_INFO = 0x21
|
||||
LC_DYLD_INFO = 0x22
|
||||
LC_DYLD_INFO_ONLY = 0x80000022
|
||||
LC_LOAD_UPWARD_DYLIB = 0x80000023
|
||||
LC_VERSION_MIN_MACOSX = 0x24
|
||||
LC_VERSION_MIN_IPHONEOS = 0x25
|
||||
LC_FUNCTION_STARTS = 0x26
|
||||
LC_DYLD_ENVIRONMENT = 0x27
|
||||
LC_MAIN = 0x80000028
|
||||
LC_DATA_IN_CODE = 0x29
|
||||
LC_SOURCE_VERSION = 0x2A
|
||||
LC_DYLIB_CODE_SIGN_DRS = 0x2B
|
||||
LC_ENCRYPTION_INFO_64 = 0x2C
|
||||
LC_LINKER_OPTION = 0x2D
|
||||
LC_LINKER_OPTIMIZATION_HINT = 0x2E
|
||||
LC_VERSION_MIN_TVOS = 0x2F
|
||||
LC_VERSION_MIN_WATCHOS = 0x30
|
||||
LC_VERSION_NOTE = 0x31
|
||||
LC_BUILD_VERSION = 0x32
|
||||
LC_DYLD_EXPORTS_TRIE = 0x80000033
|
||||
LC_DYLD_CHAINED_FIXUPS = 0x80000034
|
||||
)
|
||||
|
||||
// LoadCmd is macho.LoadCmd with its length, which is also
|
||||
// the load command header in the Mach-O file.
|
||||
type LoadCmd struct {
|
||||
Cmd macho.LoadCmd
|
||||
Len uint32
|
||||
}
|
||||
|
||||
type LoadCmdReader struct {
|
||||
offset, next int64
|
||||
f io.ReadSeeker
|
||||
order binary.ByteOrder
|
||||
}
|
||||
|
||||
func NewLoadCmdReader(f io.ReadSeeker, order binary.ByteOrder, nextOffset int64) LoadCmdReader {
|
||||
return LoadCmdReader{next: nextOffset, f: f, order: order}
|
||||
}
|
||||
|
||||
func (r *LoadCmdReader) Next() (LoadCmd, error) {
|
||||
var cmd LoadCmd
|
||||
|
||||
r.offset = r.next
|
||||
if _, err := r.f.Seek(r.offset, 0); err != nil {
|
||||
return cmd, err
|
||||
}
|
||||
if err := binary.Read(r.f, r.order, &cmd); err != nil {
|
||||
return cmd, err
|
||||
}
|
||||
r.next = r.offset + int64(cmd.Len)
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func (r LoadCmdReader) ReadAt(offset int64, data interface{}) error {
|
||||
if _, err := r.f.Seek(r.offset+offset, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return binary.Read(r.f, r.order, data)
|
||||
}
|
||||
|
||||
func (r LoadCmdReader) Offset() int64 { return r.offset }
|
||||
|
||||
type LoadCmdUpdater struct {
|
||||
LoadCmdReader
|
||||
}
|
||||
|
||||
func NewLoadCmdUpdater(f io.ReadWriteSeeker, order binary.ByteOrder, nextOffset int64) LoadCmdUpdater {
|
||||
return LoadCmdUpdater{NewLoadCmdReader(f, order, nextOffset)}
|
||||
}
|
||||
|
||||
func (u LoadCmdUpdater) WriteAt(offset int64, data interface{}) error {
|
||||
if _, err := u.f.Seek(u.offset+offset, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return binary.Write(u.f.(io.Writer), u.order, data)
|
||||
}
|
||||
|
||||
func FileHeaderSize(f *macho.File) int64 {
|
||||
offset := int64(unsafe.Sizeof(f.FileHeader))
|
||||
if is64bit := f.Magic == macho.Magic64; is64bit {
|
||||
// mach_header_64 has one extra uint32.
|
||||
offset += 4
|
||||
}
|
||||
return offset
|
||||
}
|
@ -7,6 +7,7 @@ package ld
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/codesign"
|
||||
imacho "cmd/internal/macho"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loader"
|
||||
@ -127,62 +128,6 @@ const (
|
||||
MH_PIE = 0x200000
|
||||
)
|
||||
|
||||
const (
|
||||
LC_SEGMENT = 0x1
|
||||
LC_SYMTAB = 0x2
|
||||
LC_SYMSEG = 0x3
|
||||
LC_THREAD = 0x4
|
||||
LC_UNIXTHREAD = 0x5
|
||||
LC_LOADFVMLIB = 0x6
|
||||
LC_IDFVMLIB = 0x7
|
||||
LC_IDENT = 0x8
|
||||
LC_FVMFILE = 0x9
|
||||
LC_PREPAGE = 0xa
|
||||
LC_DYSYMTAB = 0xb
|
||||
LC_LOAD_DYLIB = 0xc
|
||||
LC_ID_DYLIB = 0xd
|
||||
LC_LOAD_DYLINKER = 0xe
|
||||
LC_ID_DYLINKER = 0xf
|
||||
LC_PREBOUND_DYLIB = 0x10
|
||||
LC_ROUTINES = 0x11
|
||||
LC_SUB_FRAMEWORK = 0x12
|
||||
LC_SUB_UMBRELLA = 0x13
|
||||
LC_SUB_CLIENT = 0x14
|
||||
LC_SUB_LIBRARY = 0x15
|
||||
LC_TWOLEVEL_HINTS = 0x16
|
||||
LC_PREBIND_CKSUM = 0x17
|
||||
LC_LOAD_WEAK_DYLIB = 0x80000018
|
||||
LC_SEGMENT_64 = 0x19
|
||||
LC_ROUTINES_64 = 0x1a
|
||||
LC_UUID = 0x1b
|
||||
LC_RPATH = 0x8000001c
|
||||
LC_CODE_SIGNATURE = 0x1d
|
||||
LC_SEGMENT_SPLIT_INFO = 0x1e
|
||||
LC_REEXPORT_DYLIB = 0x8000001f
|
||||
LC_LAZY_LOAD_DYLIB = 0x20
|
||||
LC_ENCRYPTION_INFO = 0x21
|
||||
LC_DYLD_INFO = 0x22
|
||||
LC_DYLD_INFO_ONLY = 0x80000022
|
||||
LC_LOAD_UPWARD_DYLIB = 0x80000023
|
||||
LC_VERSION_MIN_MACOSX = 0x24
|
||||
LC_VERSION_MIN_IPHONEOS = 0x25
|
||||
LC_FUNCTION_STARTS = 0x26
|
||||
LC_DYLD_ENVIRONMENT = 0x27
|
||||
LC_MAIN = 0x80000028
|
||||
LC_DATA_IN_CODE = 0x29
|
||||
LC_SOURCE_VERSION = 0x2A
|
||||
LC_DYLIB_CODE_SIGN_DRS = 0x2B
|
||||
LC_ENCRYPTION_INFO_64 = 0x2C
|
||||
LC_LINKER_OPTION = 0x2D
|
||||
LC_LINKER_OPTIMIZATION_HINT = 0x2E
|
||||
LC_VERSION_MIN_TVOS = 0x2F
|
||||
LC_VERSION_MIN_WATCHOS = 0x30
|
||||
LC_VERSION_NOTE = 0x31
|
||||
LC_BUILD_VERSION = 0x32
|
||||
LC_DYLD_EXPORTS_TRIE = 0x80000033
|
||||
LC_DYLD_CHAINED_FIXUPS = 0x80000034
|
||||
)
|
||||
|
||||
const (
|
||||
S_REGULAR = 0x0
|
||||
S_ZEROFILL = 0x1
|
||||
@ -387,7 +332,7 @@ func machowrite(ctxt *Link, arch *sys.Arch, out *OutBuf, linkmode LinkMode) int
|
||||
for i := 0; i < nseg; i++ {
|
||||
s := &seg[i]
|
||||
if arch.PtrSize == 8 {
|
||||
out.Write32(LC_SEGMENT_64)
|
||||
out.Write32(imacho.LC_SEGMENT_64)
|
||||
out.Write32(72 + 80*s.nsect)
|
||||
out.WriteStringN(s.name, 16)
|
||||
out.Write64(s.vaddr)
|
||||
@ -399,7 +344,7 @@ func machowrite(ctxt *Link, arch *sys.Arch, out *OutBuf, linkmode LinkMode) int
|
||||
out.Write32(s.nsect)
|
||||
out.Write32(s.flag)
|
||||
} else {
|
||||
out.Write32(LC_SEGMENT)
|
||||
out.Write32(imacho.LC_SEGMENT)
|
||||
out.Write32(56 + 68*s.nsect)
|
||||
out.WriteStringN(s.name, 16)
|
||||
out.Write32(uint32(s.vaddr))
|
||||
@ -488,7 +433,7 @@ func (ctxt *Link) domacho() {
|
||||
// In general this can be the most recent supported macOS version.
|
||||
version = 11<<16 | 0<<8 | 0<<0 // 11.0.0
|
||||
}
|
||||
ml := newMachoLoad(ctxt.Arch, LC_BUILD_VERSION, 4)
|
||||
ml := newMachoLoad(ctxt.Arch, imacho.LC_BUILD_VERSION, 4)
|
||||
ml.data[0] = uint32(machoPlatform)
|
||||
ml.data[1] = version // OS version
|
||||
ml.data[2] = version // SDK version
|
||||
@ -778,14 +723,14 @@ func asmbMacho(ctxt *Link) {
|
||||
Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
|
||||
|
||||
case sys.AMD64:
|
||||
ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 42+2)
|
||||
ml := newMachoLoad(ctxt.Arch, imacho.LC_UNIXTHREAD, 42+2)
|
||||
ml.data[0] = 4 /* thread type */
|
||||
ml.data[1] = 42 /* word count */
|
||||
ml.data[2+32] = uint32(Entryvalue(ctxt)) /* start pc */
|
||||
ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
|
||||
|
||||
case sys.ARM64:
|
||||
ml := newMachoLoad(ctxt.Arch, LC_MAIN, 4)
|
||||
ml := newMachoLoad(ctxt.Arch, imacho.LC_MAIN, 4)
|
||||
ml.data[0] = uint32(uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR)))
|
||||
ml.data[1] = uint32((uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) >> 32)
|
||||
}
|
||||
@ -815,7 +760,7 @@ func asmbMacho(ctxt *Link) {
|
||||
}
|
||||
|
||||
if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() {
|
||||
ml := newMachoLoad(ctxt.Arch, LC_DYLD_INFO_ONLY, 10)
|
||||
ml := newMachoLoad(ctxt.Arch, imacho.LC_DYLD_INFO_ONLY, 10)
|
||||
ml.data[0] = uint32(linkoff) // rebase off
|
||||
ml.data[1] = uint32(s1) // rebase size
|
||||
ml.data[2] = uint32(linkoff + s1) // bind off
|
||||
@ -828,7 +773,7 @@ func asmbMacho(ctxt *Link) {
|
||||
ml.data[9] = 0 // export size
|
||||
}
|
||||
|
||||
ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4)
|
||||
ml := newMachoLoad(ctxt.Arch, imacho.LC_SYMTAB, 4)
|
||||
ml.data[0] = uint32(linkoff + s1 + s2) /* symoff */
|
||||
ml.data[1] = uint32(nsortsym) /* nsyms */
|
||||
ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5) /* stroff */
|
||||
@ -837,12 +782,12 @@ func asmbMacho(ctxt *Link) {
|
||||
if ctxt.LinkMode != LinkExternal {
|
||||
machodysymtab(ctxt, linkoff+s1+s2)
|
||||
|
||||
ml := newMachoLoad(ctxt.Arch, LC_LOAD_DYLINKER, 6)
|
||||
ml := newMachoLoad(ctxt.Arch, imacho.LC_LOAD_DYLINKER, 6)
|
||||
ml.data[0] = 12 /* offset to string */
|
||||
stringtouint32(ml.data[1:], "/usr/lib/dyld")
|
||||
|
||||
for _, lib := range dylib {
|
||||
ml = newMachoLoad(ctxt.Arch, LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2)
|
||||
ml = newMachoLoad(ctxt.Arch, imacho.LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2)
|
||||
ml.data[0] = 24 /* offset of string from beginning of load */
|
||||
ml.data[1] = 0 /* time stamp */
|
||||
ml.data[2] = 0 /* version */
|
||||
@ -852,7 +797,7 @@ func asmbMacho(ctxt *Link) {
|
||||
}
|
||||
|
||||
if ctxt.IsInternal() && len(buildinfo) > 0 {
|
||||
ml := newMachoLoad(ctxt.Arch, LC_UUID, 4)
|
||||
ml := newMachoLoad(ctxt.Arch, imacho.LC_UUID, 4)
|
||||
// Mach-O UUID is 16 bytes
|
||||
if len(buildinfo) < 16 {
|
||||
buildinfo = append(buildinfo, make([]byte, 16)...)
|
||||
@ -866,7 +811,7 @@ func asmbMacho(ctxt *Link) {
|
||||
}
|
||||
|
||||
if ctxt.IsInternal() && ctxt.NeedCodeSign() {
|
||||
ml := newMachoLoad(ctxt.Arch, LC_CODE_SIGNATURE, 2)
|
||||
ml := newMachoLoad(ctxt.Arch, imacho.LC_CODE_SIGNATURE, 2)
|
||||
ml.data[0] = uint32(codesigOff)
|
||||
ml.data[1] = uint32(s7)
|
||||
}
|
||||
@ -1126,7 +1071,7 @@ func machosymtab(ctxt *Link) {
|
||||
}
|
||||
|
||||
func machodysymtab(ctxt *Link, base int64) {
|
||||
ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18)
|
||||
ml := newMachoLoad(ctxt.Arch, imacho.LC_DYSYMTAB, 18)
|
||||
|
||||
n := 0
|
||||
ml.data[0] = uint32(n) /* ilocalsym */
|
||||
@ -1339,15 +1284,15 @@ func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) {
|
||||
data := raw[8:]
|
||||
var p MachoPlatform
|
||||
switch ml.type_ {
|
||||
case LC_VERSION_MIN_IPHONEOS:
|
||||
case imacho.LC_VERSION_MIN_IPHONEOS:
|
||||
p = PLATFORM_IOS
|
||||
case LC_VERSION_MIN_MACOSX:
|
||||
case imacho.LC_VERSION_MIN_MACOSX:
|
||||
p = PLATFORM_MACOS
|
||||
case LC_VERSION_MIN_WATCHOS:
|
||||
case imacho.LC_VERSION_MIN_WATCHOS:
|
||||
p = PLATFORM_WATCHOS
|
||||
case LC_VERSION_MIN_TVOS:
|
||||
case imacho.LC_VERSION_MIN_TVOS:
|
||||
p = PLATFORM_TVOS
|
||||
case LC_BUILD_VERSION:
|
||||
case imacho.LC_BUILD_VERSION:
|
||||
p = MachoPlatform(m.ByteOrder.Uint32(data))
|
||||
default:
|
||||
continue
|
||||
@ -1536,7 +1481,7 @@ func machoCodeSign(ctxt *Link, fname string) error {
|
||||
for _, l := range mf.Loads {
|
||||
data := l.Raw()
|
||||
cmd, sz := get32(data), get32(data[4:])
|
||||
if cmd == LC_CODE_SIGNATURE {
|
||||
if cmd == imacho.LC_CODE_SIGNATURE {
|
||||
sigOff = int64(get32(data[8:]))
|
||||
sigSz = int64(get32(data[12:]))
|
||||
csCmdOff = loadOff
|
||||
|
@ -5,6 +5,8 @@
|
||||
package ld
|
||||
|
||||
import (
|
||||
imacho "cmd/internal/macho"
|
||||
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"debug/macho"
|
||||
@ -16,11 +18,6 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type loadCmd struct {
|
||||
Cmd macho.LoadCmd
|
||||
Len uint32
|
||||
}
|
||||
|
||||
type dyldInfoCmd struct {
|
||||
Cmd macho.LoadCmd
|
||||
Len uint32
|
||||
@ -50,40 +47,6 @@ type uuidCmd struct {
|
||||
Uuid [16]byte
|
||||
}
|
||||
|
||||
type loadCmdReader struct {
|
||||
offset, next int64
|
||||
f *os.File
|
||||
order binary.ByteOrder
|
||||
}
|
||||
|
||||
func (r *loadCmdReader) Next() (loadCmd, error) {
|
||||
var cmd loadCmd
|
||||
|
||||
r.offset = r.next
|
||||
if _, err := r.f.Seek(r.offset, 0); err != nil {
|
||||
return cmd, err
|
||||
}
|
||||
if err := binary.Read(r.f, r.order, &cmd); err != nil {
|
||||
return cmd, err
|
||||
}
|
||||
r.next = r.offset + int64(cmd.Len)
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func (r loadCmdReader) ReadAt(offset int64, data interface{}) error {
|
||||
if _, err := r.f.Seek(r.offset+offset, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return binary.Read(r.f, r.order, data)
|
||||
}
|
||||
|
||||
func (r loadCmdReader) WriteAt(offset int64, data interface{}) error {
|
||||
if _, err := r.f.Seek(r.offset+offset, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return binary.Write(r.f, r.order, data)
|
||||
}
|
||||
|
||||
// machoCombineDwarf merges dwarf info generated by dsymutil into a macho executable.
|
||||
//
|
||||
// With internal linking, DWARF is embedded into the executable, this lets us do the
|
||||
@ -182,11 +145,7 @@ func machoCombineDwarf(ctxt *Link, exef *os.File, exem *macho.File, dsym, outexe
|
||||
return fmt.Errorf("missing __text section")
|
||||
}
|
||||
|
||||
cmdOffset := unsafe.Sizeof(exem.FileHeader)
|
||||
if is64bit := exem.Magic == macho.Magic64; is64bit {
|
||||
// mach_header_64 has one extra uint32.
|
||||
cmdOffset += unsafe.Sizeof(exem.Magic)
|
||||
}
|
||||
cmdOffset := imacho.FileHeaderSize(exem)
|
||||
dwarfCmdOffset := uint32(cmdOffset) + exem.FileHeader.Cmdsz
|
||||
availablePadding := textsect.Offset - dwarfCmdOffset
|
||||
if availablePadding < realdwarf.Len {
|
||||
@ -210,7 +169,7 @@ func machoCombineDwarf(ctxt *Link, exef *os.File, exem *macho.File, dsym, outexe
|
||||
return err
|
||||
}
|
||||
|
||||
reader := loadCmdReader{next: int64(cmdOffset), f: outf, order: exem.ByteOrder}
|
||||
reader := imacho.NewLoadCmdUpdater(outf, exem.ByteOrder, cmdOffset)
|
||||
for i := uint32(0); i < exem.Ncmd; i++ {
|
||||
cmd, err := reader.Next()
|
||||
if err != nil {
|
||||
@ -222,18 +181,18 @@ func machoCombineDwarf(ctxt *Link, exef *os.File, exem *macho.File, dsym, outexe
|
||||
err = machoUpdateSegment(reader, linkseg, linkoffset)
|
||||
case macho.LoadCmdSegment:
|
||||
panic("unexpected 32-bit segment")
|
||||
case LC_DYLD_INFO, LC_DYLD_INFO_ONLY:
|
||||
case imacho.LC_DYLD_INFO, imacho.LC_DYLD_INFO_ONLY:
|
||||
err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &dyldInfoCmd{}, "RebaseOff", "BindOff", "WeakBindOff", "LazyBindOff", "ExportOff")
|
||||
case macho.LoadCmdSymtab:
|
||||
err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &macho.SymtabCmd{}, "Symoff", "Stroff")
|
||||
case macho.LoadCmdDysymtab:
|
||||
err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &macho.DysymtabCmd{}, "Tocoffset", "Modtaboff", "Extrefsymoff", "Indirectsymoff", "Extreloff", "Locreloff")
|
||||
case LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS,
|
||||
LC_DYLD_EXPORTS_TRIE, LC_DYLD_CHAINED_FIXUPS:
|
||||
case imacho.LC_CODE_SIGNATURE, imacho.LC_SEGMENT_SPLIT_INFO, imacho.LC_FUNCTION_STARTS, imacho.LC_DATA_IN_CODE, imacho.LC_DYLIB_CODE_SIGN_DRS,
|
||||
imacho.LC_DYLD_EXPORTS_TRIE, imacho.LC_DYLD_CHAINED_FIXUPS:
|
||||
err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &linkEditDataCmd{}, "DataOff")
|
||||
case LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64:
|
||||
case imacho.LC_ENCRYPTION_INFO, imacho.LC_ENCRYPTION_INFO_64:
|
||||
err = machoUpdateLoadCommand(reader, linkseg, linkoffset, &encryptionInfoCmd{}, "CryptOff")
|
||||
case LC_UUID:
|
||||
case imacho.LC_UUID:
|
||||
var u uuidCmd
|
||||
err = reader.ReadAt(0, &u)
|
||||
if err == nil {
|
||||
@ -241,13 +200,13 @@ func machoCombineDwarf(ctxt *Link, exef *os.File, exem *macho.File, dsym, outexe
|
||||
err = reader.WriteAt(0, &u)
|
||||
}
|
||||
case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread,
|
||||
LC_PREBOUND_DYLIB, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION,
|
||||
LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH, LC_ID_DYLIB,
|
||||
LC_SYMSEG, LC_LOADFVMLIB, LC_IDFVMLIB, LC_IDENT, LC_FVMFILE, LC_PREPAGE, LC_ID_DYLINKER,
|
||||
LC_ROUTINES, LC_SUB_FRAMEWORK, LC_SUB_UMBRELLA, LC_SUB_CLIENT, LC_SUB_LIBRARY, LC_TWOLEVEL_HINTS,
|
||||
LC_PREBIND_CKSUM, LC_ROUTINES_64, LC_LAZY_LOAD_DYLIB, LC_LOAD_UPWARD_DYLIB, LC_DYLD_ENVIRONMENT,
|
||||
LC_LINKER_OPTION, LC_LINKER_OPTIMIZATION_HINT, LC_VERSION_MIN_TVOS, LC_VERSION_MIN_WATCHOS,
|
||||
LC_VERSION_NOTE, LC_BUILD_VERSION:
|
||||
imacho.LC_PREBOUND_DYLIB, imacho.LC_VERSION_MIN_MACOSX, imacho.LC_VERSION_MIN_IPHONEOS, imacho.LC_SOURCE_VERSION,
|
||||
imacho.LC_MAIN, imacho.LC_LOAD_DYLINKER, imacho.LC_LOAD_WEAK_DYLIB, imacho.LC_REEXPORT_DYLIB, imacho.LC_RPATH, imacho.LC_ID_DYLIB,
|
||||
imacho.LC_SYMSEG, imacho.LC_LOADFVMLIB, imacho.LC_IDFVMLIB, imacho.LC_IDENT, imacho.LC_FVMFILE, imacho.LC_PREPAGE, imacho.LC_ID_DYLINKER,
|
||||
imacho.LC_ROUTINES, imacho.LC_SUB_FRAMEWORK, imacho.LC_SUB_UMBRELLA, imacho.LC_SUB_CLIENT, imacho.LC_SUB_LIBRARY, imacho.LC_TWOLEVEL_HINTS,
|
||||
imacho.LC_PREBIND_CKSUM, imacho.LC_ROUTINES_64, imacho.LC_LAZY_LOAD_DYLIB, imacho.LC_LOAD_UPWARD_DYLIB, imacho.LC_DYLD_ENVIRONMENT,
|
||||
imacho.LC_LINKER_OPTION, imacho.LC_LINKER_OPTIMIZATION_HINT, imacho.LC_VERSION_MIN_TVOS, imacho.LC_VERSION_MIN_WATCHOS,
|
||||
imacho.LC_VERSION_NOTE, imacho.LC_BUILD_VERSION:
|
||||
// Nothing to update
|
||||
default:
|
||||
err = fmt.Errorf("unknown load command 0x%x (%s)", int(cmd.Cmd), cmd.Cmd)
|
||||
@ -330,7 +289,7 @@ func machoCompressSection(sectBytes []byte) (compressed bool, contents []byte, e
|
||||
|
||||
// machoUpdateSegment updates the load command for a moved segment.
|
||||
// Only the linkedit segment should move, and it should have 0 sections.
|
||||
func machoUpdateSegment(r loadCmdReader, linkseg *macho.Segment, linkoffset uint64) error {
|
||||
func machoUpdateSegment(r imacho.LoadCmdUpdater, linkseg *macho.Segment, linkoffset uint64) error {
|
||||
var seg macho.Segment64
|
||||
if err := r.ReadAt(0, &seg); err != nil {
|
||||
return err
|
||||
@ -348,7 +307,7 @@ func machoUpdateSegment(r loadCmdReader, linkseg *macho.Segment, linkoffset uint
|
||||
return machoUpdateSections(r, &seg, linkoffset, nil)
|
||||
}
|
||||
|
||||
func machoUpdateSections(r loadCmdReader, seg *macho.Segment64, deltaOffset uint64, compressedSects []*macho.Section) error {
|
||||
func machoUpdateSections(r imacho.LoadCmdUpdater, seg *macho.Segment64, deltaOffset uint64, compressedSects []*macho.Section) error {
|
||||
nsect := seg.Nsect
|
||||
if nsect == 0 {
|
||||
return nil
|
||||
@ -388,7 +347,7 @@ func machoUpdateSections(r loadCmdReader, seg *macho.Segment64, deltaOffset uint
|
||||
}
|
||||
|
||||
// machoUpdateDwarfHeader updates the DWARF segment load command.
|
||||
func machoUpdateDwarfHeader(r *loadCmdReader, compressedSects []*macho.Section, dwarfsize uint64, dwarfstart int64, realdwarf *macho.Segment) error {
|
||||
func machoUpdateDwarfHeader(r *imacho.LoadCmdUpdater, compressedSects []*macho.Section, dwarfsize uint64, dwarfstart int64, realdwarf *macho.Segment) error {
|
||||
cmd, err := r.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -432,7 +391,7 @@ func machoUpdateDwarfHeader(r *loadCmdReader, compressedSects []*macho.Section,
|
||||
return machoUpdateSections(*r, &seg, uint64(dwarfstart)-realdwarf.Offset, compressedSects)
|
||||
}
|
||||
|
||||
func machoUpdateLoadCommand(r loadCmdReader, linkseg *macho.Segment, linkoffset uint64, cmd interface{}, fields ...string) error {
|
||||
func machoUpdateLoadCommand(r imacho.LoadCmdUpdater, linkseg *macho.Segment, linkoffset uint64, cmd interface{}, fields ...string) error {
|
||||
if err := r.ReadAt(0, cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -19,10 +19,11 @@ package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/hash"
|
||||
imacho "cmd/internal/macho"
|
||||
|
||||
"debug/macho"
|
||||
"io"
|
||||
"os"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// uuidFromGoBuildId hashes the Go build ID and returns a slice of 16
|
||||
@ -66,26 +67,21 @@ func machoRewriteUuid(ctxt *Link, exef *os.File, exem *macho.File, outexe string
|
||||
}
|
||||
|
||||
// Locate the portion of the binary containing the load commands.
|
||||
cmdOffset := unsafe.Sizeof(exem.FileHeader)
|
||||
if is64bit := exem.Magic == macho.Magic64; is64bit {
|
||||
// mach_header_64 has one extra uint32.
|
||||
cmdOffset += unsafe.Sizeof(exem.Magic)
|
||||
}
|
||||
if _, err := outf.Seek(int64(cmdOffset), 0); err != nil {
|
||||
cmdOffset := imacho.FileHeaderSize(exem)
|
||||
if _, err := outf.Seek(cmdOffset, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read the load commands, looking for the LC_UUID cmd. If/when we
|
||||
// locate it, overwrite it with a new value produced by
|
||||
// uuidFromGoBuildId.
|
||||
reader := loadCmdReader{next: int64(cmdOffset),
|
||||
f: outf, order: exem.ByteOrder}
|
||||
reader := imacho.NewLoadCmdUpdater(outf, exem.ByteOrder, cmdOffset)
|
||||
for i := uint32(0); i < exem.Ncmd; i++ {
|
||||
cmd, err := reader.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cmd.Cmd == LC_UUID {
|
||||
if cmd.Cmd == imacho.LC_UUID {
|
||||
var u uuidCmd
|
||||
if err := reader.ReadAt(0, &u); err != nil {
|
||||
return err
|
||||
|
Loading…
Reference in New Issue
Block a user