2017-10-07 00:16:47 +00:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
2012-03-27 23:13:14 +00:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// Mach-O header data structures
|
|
|
|
// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
|
|
|
|
|
|
|
|
package macho
|
|
|
|
|
|
|
|
import "strconv"
|
|
|
|
|
|
|
|
// A FileHeader represents a Mach-O file header.
|
|
|
|
type FileHeader struct {
|
|
|
|
Magic uint32
|
|
|
|
Cpu Cpu
|
|
|
|
SubCpu uint32
|
|
|
|
Type Type
|
|
|
|
Ncmd uint32
|
|
|
|
Cmdsz uint32
|
|
|
|
Flags uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
fileHeaderSize32 = 7 * 4
|
|
|
|
fileHeaderSize64 = 8 * 4
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2015-08-28 15:33:40 +00:00
|
|
|
Magic32 uint32 = 0xfeedface
|
|
|
|
Magic64 uint32 = 0xfeedfacf
|
|
|
|
MagicFat uint32 = 0xcafebabe
|
2012-03-27 23:13:14 +00:00
|
|
|
)
|
|
|
|
|
2015-08-28 15:33:40 +00:00
|
|
|
// A Type is the Mach-O file type, e.g. an object file, executable, or dynamic library.
|
2012-03-27 23:13:14 +00:00
|
|
|
type Type uint32
|
|
|
|
|
|
|
|
const (
|
2015-08-28 15:33:40 +00:00
|
|
|
TypeObj Type = 1
|
|
|
|
TypeExec Type = 2
|
|
|
|
TypeDylib Type = 6
|
|
|
|
TypeBundle Type = 8
|
2012-03-27 23:13:14 +00:00
|
|
|
)
|
|
|
|
|
2018-12-28 15:30:48 +00:00
|
|
|
var typeStrings = []intName{
|
|
|
|
{uint32(TypeObj), "Obj"},
|
|
|
|
{uint32(TypeExec), "Exec"},
|
|
|
|
{uint32(TypeDylib), "Dylib"},
|
|
|
|
{uint32(TypeBundle), "Bundle"},
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t Type) String() string { return stringName(uint32(t), typeStrings, false) }
|
|
|
|
func (t Type) GoString() string { return stringName(uint32(t), typeStrings, true) }
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
// A Cpu is a Mach-O cpu type.
|
|
|
|
type Cpu uint32
|
|
|
|
|
2015-08-28 15:33:40 +00:00
|
|
|
const cpuArch64 = 0x01000000
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
const (
|
|
|
|
Cpu386 Cpu = 7
|
2015-08-28 15:33:40 +00:00
|
|
|
CpuAmd64 Cpu = Cpu386 | cpuArch64
|
|
|
|
CpuArm Cpu = 12
|
2019-06-02 15:48:37 +00:00
|
|
|
CpuArm64 Cpu = CpuArm | cpuArch64
|
2015-08-28 15:33:40 +00:00
|
|
|
CpuPpc Cpu = 18
|
|
|
|
CpuPpc64 Cpu = CpuPpc | cpuArch64
|
2012-03-27 23:13:14 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var cpuStrings = []intName{
|
|
|
|
{uint32(Cpu386), "Cpu386"},
|
|
|
|
{uint32(CpuAmd64), "CpuAmd64"},
|
2015-08-28 15:33:40 +00:00
|
|
|
{uint32(CpuArm), "CpuArm"},
|
2019-06-02 15:48:37 +00:00
|
|
|
{uint32(CpuArm64), "CpuArm64"},
|
2015-08-28 15:33:40 +00:00
|
|
|
{uint32(CpuPpc), "CpuPpc"},
|
|
|
|
{uint32(CpuPpc64), "CpuPpc64"},
|
2012-03-27 23:13:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (i Cpu) String() string { return stringName(uint32(i), cpuStrings, false) }
|
|
|
|
func (i Cpu) GoString() string { return stringName(uint32(i), cpuStrings, true) }
|
|
|
|
|
|
|
|
// A LoadCmd is a Mach-O load command.
|
|
|
|
type LoadCmd uint32
|
|
|
|
|
|
|
|
const (
|
2018-12-28 15:30:48 +00:00
|
|
|
LoadCmdSegment LoadCmd = 0x1
|
|
|
|
LoadCmdSymtab LoadCmd = 0x2
|
|
|
|
LoadCmdThread LoadCmd = 0x4
|
|
|
|
LoadCmdUnixThread LoadCmd = 0x5 // thread+stack
|
|
|
|
LoadCmdDysymtab LoadCmd = 0xb
|
|
|
|
LoadCmdDylib LoadCmd = 0xc // load dylib command
|
|
|
|
LoadCmdDylinker LoadCmd = 0xf // id dylinker command (not load dylinker command)
|
|
|
|
LoadCmdSegment64 LoadCmd = 0x19
|
|
|
|
LoadCmdRpath LoadCmd = 0x8000001c
|
2012-03-27 23:13:14 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var cmdStrings = []intName{
|
|
|
|
{uint32(LoadCmdSegment), "LoadCmdSegment"},
|
|
|
|
{uint32(LoadCmdThread), "LoadCmdThread"},
|
|
|
|
{uint32(LoadCmdUnixThread), "LoadCmdUnixThread"},
|
|
|
|
{uint32(LoadCmdDylib), "LoadCmdDylib"},
|
|
|
|
{uint32(LoadCmdSegment64), "LoadCmdSegment64"},
|
2018-12-28 15:30:48 +00:00
|
|
|
{uint32(LoadCmdRpath), "LoadCmdRpath"},
|
2012-03-27 23:13:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (i LoadCmd) String() string { return stringName(uint32(i), cmdStrings, false) }
|
|
|
|
func (i LoadCmd) GoString() string { return stringName(uint32(i), cmdStrings, true) }
|
|
|
|
|
2018-12-28 15:30:48 +00:00
|
|
|
type (
|
|
|
|
// A Segment32 is a 32-bit Mach-O segment load command.
|
|
|
|
Segment32 struct {
|
|
|
|
Cmd LoadCmd
|
|
|
|
Len uint32
|
|
|
|
Name [16]byte
|
|
|
|
Addr uint32
|
|
|
|
Memsz uint32
|
|
|
|
Offset uint32
|
|
|
|
Filesz uint32
|
|
|
|
Maxprot uint32
|
|
|
|
Prot uint32
|
|
|
|
Nsect uint32
|
|
|
|
Flag uint32
|
|
|
|
}
|
2012-03-27 23:13:14 +00:00
|
|
|
|
2018-12-28 15:30:48 +00:00
|
|
|
// A Segment64 is a 64-bit Mach-O segment load command.
|
|
|
|
Segment64 struct {
|
|
|
|
Cmd LoadCmd
|
|
|
|
Len uint32
|
|
|
|
Name [16]byte
|
|
|
|
Addr uint64
|
|
|
|
Memsz uint64
|
|
|
|
Offset uint64
|
|
|
|
Filesz uint64
|
|
|
|
Maxprot uint32
|
|
|
|
Prot uint32
|
|
|
|
Nsect uint32
|
|
|
|
Flag uint32
|
|
|
|
}
|
2012-03-27 23:13:14 +00:00
|
|
|
|
2018-12-28 15:30:48 +00:00
|
|
|
// A SymtabCmd is a Mach-O symbol table command.
|
|
|
|
SymtabCmd struct {
|
|
|
|
Cmd LoadCmd
|
|
|
|
Len uint32
|
|
|
|
Symoff uint32
|
|
|
|
Nsyms uint32
|
|
|
|
Stroff uint32
|
|
|
|
Strsize uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// A DysymtabCmd is a Mach-O dynamic symbol table command.
|
|
|
|
DysymtabCmd struct {
|
|
|
|
Cmd LoadCmd
|
|
|
|
Len uint32
|
|
|
|
Ilocalsym uint32
|
|
|
|
Nlocalsym uint32
|
|
|
|
Iextdefsym uint32
|
|
|
|
Nextdefsym uint32
|
|
|
|
Iundefsym uint32
|
|
|
|
Nundefsym uint32
|
|
|
|
Tocoffset uint32
|
|
|
|
Ntoc uint32
|
|
|
|
Modtaboff uint32
|
|
|
|
Nmodtab uint32
|
|
|
|
Extrefsymoff uint32
|
|
|
|
Nextrefsyms uint32
|
|
|
|
Indirectsymoff uint32
|
|
|
|
Nindirectsyms uint32
|
|
|
|
Extreloff uint32
|
|
|
|
Nextrel uint32
|
|
|
|
Locreloff uint32
|
|
|
|
Nlocrel uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// A DylibCmd is a Mach-O load dynamic library command.
|
|
|
|
DylibCmd struct {
|
|
|
|
Cmd LoadCmd
|
|
|
|
Len uint32
|
|
|
|
Name uint32
|
|
|
|
Time uint32
|
|
|
|
CurrentVersion uint32
|
|
|
|
CompatVersion uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// A RpathCmd is a Mach-O rpath command.
|
|
|
|
RpathCmd struct {
|
|
|
|
Cmd LoadCmd
|
|
|
|
Len uint32
|
|
|
|
Path uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// A Thread is a Mach-O thread state command.
|
|
|
|
Thread struct {
|
|
|
|
Cmd LoadCmd
|
|
|
|
Len uint32
|
|
|
|
Type uint32
|
|
|
|
Data []uint32
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
FlagNoUndefs uint32 = 0x1
|
|
|
|
FlagIncrLink uint32 = 0x2
|
|
|
|
FlagDyldLink uint32 = 0x4
|
|
|
|
FlagBindAtLoad uint32 = 0x8
|
|
|
|
FlagPrebound uint32 = 0x10
|
|
|
|
FlagSplitSegs uint32 = 0x20
|
|
|
|
FlagLazyInit uint32 = 0x40
|
|
|
|
FlagTwoLevel uint32 = 0x80
|
|
|
|
FlagForceFlat uint32 = 0x100
|
|
|
|
FlagNoMultiDefs uint32 = 0x200
|
|
|
|
FlagNoFixPrebinding uint32 = 0x400
|
|
|
|
FlagPrebindable uint32 = 0x800
|
|
|
|
FlagAllModsBound uint32 = 0x1000
|
|
|
|
FlagSubsectionsViaSymbols uint32 = 0x2000
|
|
|
|
FlagCanonical uint32 = 0x4000
|
|
|
|
FlagWeakDefines uint32 = 0x8000
|
|
|
|
FlagBindsToWeak uint32 = 0x10000
|
|
|
|
FlagAllowStackExecution uint32 = 0x20000
|
|
|
|
FlagRootSafe uint32 = 0x40000
|
|
|
|
FlagSetuidSafe uint32 = 0x80000
|
|
|
|
FlagNoReexportedDylibs uint32 = 0x100000
|
|
|
|
FlagPIE uint32 = 0x200000
|
|
|
|
FlagDeadStrippableDylib uint32 = 0x400000
|
|
|
|
FlagHasTLVDescriptors uint32 = 0x800000
|
|
|
|
FlagNoHeapExecution uint32 = 0x1000000
|
|
|
|
FlagAppExtensionSafe uint32 = 0x2000000
|
|
|
|
)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
// A Section32 is a 32-bit Mach-O section header.
|
|
|
|
type Section32 struct {
|
|
|
|
Name [16]byte
|
|
|
|
Seg [16]byte
|
|
|
|
Addr uint32
|
|
|
|
Size uint32
|
|
|
|
Offset uint32
|
|
|
|
Align uint32
|
|
|
|
Reloff uint32
|
|
|
|
Nreloc uint32
|
|
|
|
Flags uint32
|
|
|
|
Reserve1 uint32
|
|
|
|
Reserve2 uint32
|
|
|
|
}
|
|
|
|
|
2017-10-07 00:16:47 +00:00
|
|
|
// A Section64 is a 64-bit Mach-O section header.
|
2012-03-27 23:13:14 +00:00
|
|
|
type Section64 struct {
|
|
|
|
Name [16]byte
|
|
|
|
Seg [16]byte
|
|
|
|
Addr uint64
|
|
|
|
Size uint64
|
|
|
|
Offset uint32
|
|
|
|
Align uint32
|
|
|
|
Reloff uint32
|
|
|
|
Nreloc uint32
|
|
|
|
Flags uint32
|
|
|
|
Reserve1 uint32
|
|
|
|
Reserve2 uint32
|
|
|
|
Reserve3 uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// An Nlist32 is a Mach-O 32-bit symbol table entry.
|
|
|
|
type Nlist32 struct {
|
|
|
|
Name uint32
|
|
|
|
Type uint8
|
|
|
|
Sect uint8
|
|
|
|
Desc uint16
|
|
|
|
Value uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// An Nlist64 is a Mach-O 64-bit symbol table entry.
|
|
|
|
type Nlist64 struct {
|
|
|
|
Name uint32
|
|
|
|
Type uint8
|
|
|
|
Sect uint8
|
|
|
|
Desc uint16
|
|
|
|
Value uint64
|
|
|
|
}
|
|
|
|
|
|
|
|
// Regs386 is the Mach-O 386 register structure.
|
|
|
|
type Regs386 struct {
|
|
|
|
AX uint32
|
|
|
|
BX uint32
|
|
|
|
CX uint32
|
|
|
|
DX uint32
|
|
|
|
DI uint32
|
|
|
|
SI uint32
|
|
|
|
BP uint32
|
|
|
|
SP uint32
|
|
|
|
SS uint32
|
|
|
|
FLAGS uint32
|
|
|
|
IP uint32
|
|
|
|
CS uint32
|
|
|
|
DS uint32
|
|
|
|
ES uint32
|
|
|
|
FS uint32
|
|
|
|
GS uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// RegsAMD64 is the Mach-O AMD64 register structure.
|
|
|
|
type RegsAMD64 struct {
|
|
|
|
AX uint64
|
|
|
|
BX uint64
|
|
|
|
CX uint64
|
|
|
|
DX uint64
|
|
|
|
DI uint64
|
|
|
|
SI uint64
|
|
|
|
BP uint64
|
|
|
|
SP uint64
|
|
|
|
R8 uint64
|
|
|
|
R9 uint64
|
|
|
|
R10 uint64
|
|
|
|
R11 uint64
|
|
|
|
R12 uint64
|
|
|
|
R13 uint64
|
|
|
|
R14 uint64
|
|
|
|
R15 uint64
|
|
|
|
IP uint64
|
|
|
|
FLAGS uint64
|
|
|
|
CS uint64
|
|
|
|
FS uint64
|
|
|
|
GS uint64
|
|
|
|
}
|
|
|
|
|
|
|
|
type intName struct {
|
|
|
|
i uint32
|
|
|
|
s string
|
|
|
|
}
|
|
|
|
|
|
|
|
func stringName(i uint32, names []intName, goSyntax bool) string {
|
|
|
|
for _, n := range names {
|
|
|
|
if n.i == i {
|
|
|
|
if goSyntax {
|
|
|
|
return "macho." + n.s
|
|
|
|
}
|
|
|
|
return n.s
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return strconv.FormatUint(uint64(i), 10)
|
|
|
|
}
|