| // Copyright 2009 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. | |
| // Mach-O header data structures | |
| // http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html | |
| package macho | |
| import ( | |
| "encoding/binary" | |
| "strconv" | |
| ) | |
| // A FileHeader represents a Mach-O file header. | |
| type FileHeader struct { | |
| Magic uint32 | |
| Cpu Cpu | |
| SubCpu uint32 | |
| Type HdrType | |
| NCommands uint32 // number of load commands | |
| SizeCommands uint32 // size of all the load commands, not including this header. | |
| Flags HdrFlags | |
| } | |
| func (h *FileHeader) Put(b []byte, o binary.ByteOrder) int { | |
| o.PutUint32(b[0:], h.Magic) | |
| o.PutUint32(b[4:], uint32(h.Cpu)) | |
| o.PutUint32(b[8:], h.SubCpu) | |
| o.PutUint32(b[12:], uint32(h.Type)) | |
| o.PutUint32(b[16:], h.NCommands) | |
| o.PutUint32(b[20:], h.SizeCommands) | |
| o.PutUint32(b[24:], uint32(h.Flags)) | |
| if h.Magic == Magic32 { | |
| return 28 | |
| } | |
| o.PutUint32(b[28:], 0) | |
| return 32 | |
| } | |
| const ( | |
| fileHeaderSize32 = 7 * 4 | |
| fileHeaderSize64 = 8 * 4 | |
| ) | |
| const ( | |
| Magic32 uint32 = 0xfeedface | |
| Magic64 uint32 = 0xfeedfacf | |
| MagicFat uint32 = 0xcafebabe | |
| ) | |
| type HdrFlags uint32 | |
| type SegFlags uint32 | |
| type SecFlags uint32 | |
| // A HdrType is the Mach-O file type, e.g. an object file, executable, or dynamic library. | |
| type HdrType uint32 | |
| const ( // SNAKE_CASE to CamelCase translation from C names | |
| MhObject HdrType = 1 | |
| MhExecute HdrType = 2 | |
| MhCore HdrType = 4 | |
| MhDylib HdrType = 6 | |
| MhBundle HdrType = 8 | |
| MhDsym HdrType = 0xa | |
| ) | |
| var typeStrings = []intName{ | |
| {uint32(MhObject), "Obj"}, | |
| {uint32(MhExecute), "Exec"}, | |
| {uint32(MhDylib), "Dylib"}, | |
| {uint32(MhBundle), "Bundle"}, | |
| {uint32(MhDsym), "Dsym"}, | |
| } | |
| func (t HdrType) String() string { return stringName(uint32(t), typeStrings, false) } | |
| func (t HdrType) GoString() string { return stringName(uint32(t), typeStrings, true) } | |
| // A Cpu is a Mach-O cpu type. | |
| type Cpu uint32 | |
| const cpuArch64 = 0x01000000 | |
| const ( | |
| Cpu386 Cpu = 7 | |
| CpuAmd64 Cpu = Cpu386 | cpuArch64 | |
| CpuArm Cpu = 12 | |
| CpuArm64 Cpu = CpuArm | cpuArch64 | |
| CpuPpc Cpu = 18 | |
| CpuPpc64 Cpu = CpuPpc | cpuArch64 | |
| ) | |
| var cpuStrings = []intName{ | |
| {uint32(Cpu386), "Cpu386"}, | |
| {uint32(CpuAmd64), "CpuAmd64"}, | |
| {uint32(CpuArm), "CpuArm"}, | |
| {uint32(CpuArm64), "CpuArm64"}, | |
| {uint32(CpuPpc), "CpuPpc"}, | |
| {uint32(CpuPpc64), "CpuPpc64"}, | |
| } | |
| 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 | |
| func (c LoadCmd) Command() LoadCmd { return c } | |
| const ( // SNAKE_CASE to CamelCase translation from C names | |
| // Note 3 and 8 are obsolete | |
| LcSegment LoadCmd = 0x1 | |
| LcSymtab LoadCmd = 0x2 | |
| LcThread LoadCmd = 0x4 | |
| LcUnixthread LoadCmd = 0x5 // thread+stack | |
| LcDysymtab LoadCmd = 0xb | |
| LcDylib LoadCmd = 0xc // load dylib command | |
| LcIdDylib LoadCmd = 0xd // dynamically linked shared lib ident | |
| LcLoadDylinker LoadCmd = 0xe // load a dynamic linker | |
| LcIdDylinker LoadCmd = 0xf // id dylinker command (not load dylinker command) | |
| LcSegment64 LoadCmd = 0x19 | |
| LcUuid LoadCmd = 0x1b | |
| LcCodeSignature LoadCmd = 0x1d | |
| LcSegmentSplitInfo LoadCmd = 0x1e | |
| LcRpath LoadCmd = 0x8000001c | |
| LcEncryptionInfo LoadCmd = 0x21 | |
| LcDyldInfo LoadCmd = 0x22 | |
| LcDyldInfoOnly LoadCmd = 0x80000022 | |
| LcVersionMinMacosx LoadCmd = 0x24 | |
| LcVersionMinIphoneos LoadCmd = 0x25 | |
| LcFunctionStarts LoadCmd = 0x26 | |
| LcDyldEnvironment LoadCmd = 0x27 | |
| LcMain LoadCmd = 0x80000028 // replacement for UnixThread | |
| LcDataInCode LoadCmd = 0x29 // There are non-instructions in text | |
| LcSourceVersion LoadCmd = 0x2a // Source version used to build binary | |
| LcDylibCodeSignDrs LoadCmd = 0x2b | |
| LcEncryptionInfo64 LoadCmd = 0x2c | |
| LcVersionMinTvos LoadCmd = 0x2f | |
| LcVersionMinWatchos LoadCmd = 0x30 | |
| ) | |
| var cmdStrings = []intName{ | |
| {uint32(LcSegment), "LoadCmdSegment"}, | |
| {uint32(LcThread), "LoadCmdThread"}, | |
| {uint32(LcUnixthread), "LoadCmdUnixThread"}, | |
| {uint32(LcDylib), "LoadCmdDylib"}, | |
| {uint32(LcIdDylib), "LoadCmdIdDylib"}, | |
| {uint32(LcLoadDylinker), "LoadCmdLoadDylinker"}, | |
| {uint32(LcIdDylinker), "LoadCmdIdDylinker"}, | |
| {uint32(LcSegment64), "LoadCmdSegment64"}, | |
| {uint32(LcUuid), "LoadCmdUuid"}, | |
| {uint32(LcRpath), "LoadCmdRpath"}, | |
| {uint32(LcDyldEnvironment), "LoadCmdDyldEnv"}, | |
| {uint32(LcMain), "LoadCmdMain"}, | |
| {uint32(LcDataInCode), "LoadCmdDataInCode"}, | |
| {uint32(LcSourceVersion), "LoadCmdSourceVersion"}, | |
| {uint32(LcDyldInfo), "LoadCmdDyldInfo"}, | |
| {uint32(LcDyldInfoOnly), "LoadCmdDyldInfoOnly"}, | |
| {uint32(LcVersionMinMacosx), "LoadCmdMinOsx"}, | |
| {uint32(LcFunctionStarts), "LoadCmdFunctionStarts"}, | |
| } | |
| func (i LoadCmd) String() string { return stringName(uint32(i), cmdStrings, false) } | |
| func (i LoadCmd) GoString() string { return stringName(uint32(i), cmdStrings, true) } | |
| type ( | |
| // A Segment32 is a 32-bit Mach-O segment load command. | |
| Segment32 struct { | |
| LoadCmd | |
| Len uint32 | |
| Name [16]byte | |
| Addr uint32 | |
| Memsz uint32 | |
| Offset uint32 | |
| Filesz uint32 | |
| Maxprot uint32 | |
| Prot uint32 | |
| Nsect uint32 | |
| Flag SegFlags | |
| } | |
| // A Segment64 is a 64-bit Mach-O segment load command. | |
| Segment64 struct { | |
| LoadCmd | |
| Len uint32 | |
| Name [16]byte | |
| Addr uint64 | |
| Memsz uint64 | |
| Offset uint64 | |
| Filesz uint64 | |
| Maxprot uint32 | |
| Prot uint32 | |
| Nsect uint32 | |
| Flag SegFlags | |
| } | |
| // A SymtabCmd is a Mach-O symbol table command. | |
| SymtabCmd struct { | |
| LoadCmd | |
| Len uint32 | |
| Symoff uint32 | |
| Nsyms uint32 | |
| Stroff uint32 | |
| Strsize uint32 | |
| } | |
| // A DysymtabCmd is a Mach-O dynamic symbol table command. | |
| DysymtabCmd struct { | |
| 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 { | |
| LoadCmd | |
| Len uint32 | |
| Name uint32 | |
| Time uint32 | |
| CurrentVersion uint32 | |
| CompatVersion uint32 | |
| } | |
| // A DylinkerCmd is a Mach-O load dynamic linker or environment command. | |
| DylinkerCmd struct { | |
| LoadCmd | |
| Len uint32 | |
| Name uint32 | |
| } | |
| // A RpathCmd is a Mach-O rpath command. | |
| RpathCmd struct { | |
| LoadCmd | |
| Len uint32 | |
| Path uint32 | |
| } | |
| // A Thread is a Mach-O thread state command. | |
| Thread struct { | |
| LoadCmd | |
| Len uint32 | |
| Type uint32 | |
| Data []uint32 | |
| } | |
| // LC_DYLD_INFO, LC_DYLD_INFO_ONLY | |
| DyldInfoCmd struct { | |
| LoadCmd | |
| Len uint32 | |
| RebaseOff, RebaseLen uint32 // file offset and length; data contains segment indices | |
| BindOff, BindLen uint32 // file offset and length; data contains segment indices | |
| WeakBindOff, WeakBindLen uint32 // file offset and length | |
| LazyBindOff, LazyBindLen uint32 // file offset and length | |
| ExportOff, ExportLen uint32 // file offset and length | |
| } | |
| // LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS | |
| LinkEditDataCmd struct { | |
| LoadCmd | |
| Len uint32 | |
| DataOff, DataLen uint32 // file offset and length | |
| } | |
| // LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64 | |
| EncryptionInfoCmd struct { | |
| LoadCmd | |
| Len uint32 | |
| CryptOff, CryptLen uint32 // file offset and length | |
| CryptId uint32 | |
| } | |
| UuidCmd struct { | |
| LoadCmd | |
| Len uint32 | |
| Id [16]byte | |
| } | |
| // TODO Commands below not fully supported yet. | |
| EntryPointCmd struct { | |
| LoadCmd | |
| Len uint32 | |
| EntryOff uint64 // file offset | |
| StackSize uint64 // if not zero, initial stack size | |
| } | |
| NoteCmd struct { | |
| LoadCmd | |
| Len uint32 | |
| Name [16]byte | |
| Offset, Filesz uint64 // file offset and length | |
| } | |
| ) | |
| const ( | |
| FlagNoUndefs HdrFlags = 0x1 | |
| FlagIncrLink HdrFlags = 0x2 | |
| FlagDyldLink HdrFlags = 0x4 | |
| FlagBindAtLoad HdrFlags = 0x8 | |
| FlagPrebound HdrFlags = 0x10 | |
| FlagSplitSegs HdrFlags = 0x20 | |
| FlagLazyInit HdrFlags = 0x40 | |
| FlagTwoLevel HdrFlags = 0x80 | |
| FlagForceFlat HdrFlags = 0x100 | |
| FlagNoMultiDefs HdrFlags = 0x200 | |
| FlagNoFixPrebinding HdrFlags = 0x400 | |
| FlagPrebindable HdrFlags = 0x800 | |
| FlagAllModsBound HdrFlags = 0x1000 | |
| FlagSubsectionsViaSymbols HdrFlags = 0x2000 | |
| FlagCanonical HdrFlags = 0x4000 | |
| FlagWeakDefines HdrFlags = 0x8000 | |
| FlagBindsToWeak HdrFlags = 0x10000 | |
| FlagAllowStackExecution HdrFlags = 0x20000 | |
| FlagRootSafe HdrFlags = 0x40000 | |
| FlagSetuidSafe HdrFlags = 0x80000 | |
| FlagNoReexportedDylibs HdrFlags = 0x100000 | |
| FlagPIE HdrFlags = 0x200000 | |
| FlagDeadStrippableDylib HdrFlags = 0x400000 | |
| FlagHasTLVDescriptors HdrFlags = 0x800000 | |
| FlagNoHeapExecution HdrFlags = 0x1000000 | |
| FlagAppExtensionSafe HdrFlags = 0x2000000 | |
| ) | |
| // 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 SecFlags | |
| Reserve1 uint32 | |
| Reserve2 uint32 | |
| } | |
| // A Section64 is a 64-bit Mach-O section header. | |
| type Section64 struct { | |
| Name [16]byte | |
| Seg [16]byte | |
| Addr uint64 | |
| Size uint64 | |
| Offset uint32 | |
| Align uint32 | |
| Reloff uint32 | |
| Nreloc uint32 | |
| Flags SecFlags | |
| 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 | |
| } | |
| func (n *Nlist64) Put64(b []byte, o binary.ByteOrder) uint32 { | |
| o.PutUint32(b[0:], n.Name) | |
| b[4] = byte(n.Type) | |
| b[5] = byte(n.Sect) | |
| o.PutUint16(b[6:], n.Desc) | |
| o.PutUint64(b[8:], n.Value) | |
| return 8 + 8 | |
| } | |
| func (n *Nlist64) Put32(b []byte, o binary.ByteOrder) uint32 { | |
| o.PutUint32(b[0:], n.Name) | |
| b[4] = byte(n.Type) | |
| b[5] = byte(n.Sect) | |
| o.PutUint16(b[6:], n.Desc) | |
| o.PutUint32(b[8:], uint32(n.Value)) | |
| return 8 + 4 | |
| } | |
| // 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 "0x" + strconv.FormatUint(uint64(i), 16) | |
| } |