"cmd/internal/gcprog",
"cmd/internal/goobj",
"cmd/internal/hash",
+ "cmd/internal/macho",
"cmd/internal/obj/...",
"cmd/internal/objabi",
"cmd/internal/pgo",
--- /dev/null
+// 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
+}
import (
"bytes"
"cmd/internal/codesign"
+ imacho "cmd/internal/macho"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/loader"
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
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)
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))
// 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
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)
}
}
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
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 */
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 */
}
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)...)
}
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)
}
}
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 */
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
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
package ld
import (
+ imacho "cmd/internal/macho"
+
"bytes"
"compress/zlib"
"debug/macho"
"unsafe"
)
-type loadCmd struct {
- Cmd macho.LoadCmd
- Len uint32
-}
-
type dyldInfoCmd struct {
Cmd macho.LoadCmd
Len uint32
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
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 {
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 {
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 {
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)
// 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
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
}
// 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
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
}
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
}
// 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