| 1 | // Copyright 2009 The Go Authors. All rights reserved. |
|---|---|
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | // Mach-O header data structures |
| 6 | // http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html |
| 7 | |
| 8 | package macho |
| 9 | |
| 10 | import ( |
| 11 | "encoding/binary" |
| 12 | "strconv" |
| 13 | ) |
| 14 | |
| 15 | // A FileHeader represents a Mach-O file header. |
| 16 | type FileHeader struct { |
| 17 | Magic uint32 |
| 18 | Cpu Cpu |
| 19 | SubCpu uint32 |
| 20 | Type HdrType |
| 21 | NCommands uint32 // number of load commands |
| 22 | SizeCommands uint32 // size of all the load commands, not including this header. |
| 23 | Flags HdrFlags |
| 24 | } |
| 25 | |
| 26 | func (h *FileHeader) Put(b []byte, o binary.ByteOrder) int { |
| 27 | o.PutUint32(b[0:], h.Magic) |
| 28 | o.PutUint32(b[4:], uint32(h.Cpu)) |
| 29 | o.PutUint32(b[8:], h.SubCpu) |
| 30 | o.PutUint32(b[12:], uint32(h.Type)) |
| 31 | o.PutUint32(b[16:], h.NCommands) |
| 32 | o.PutUint32(b[20:], h.SizeCommands) |
| 33 | o.PutUint32(b[24:], uint32(h.Flags)) |
| 34 | if h.Magic == Magic32 { |
| 35 | return 28 |
| 36 | } |
| 37 | o.PutUint32(b[28:], 0) |
| 38 | return 32 |
| 39 | } |
| 40 | |
| 41 | const ( |
| 42 | fileHeaderSize32 = 7 * 4 |
| 43 | fileHeaderSize64 = 8 * 4 |
| 44 | ) |
| 45 | |
| 46 | const ( |
| 47 | Magic32 uint32 = 0xfeedface |
| 48 | Magic64 uint32 = 0xfeedfacf |
| 49 | MagicFat uint32 = 0xcafebabe |
| 50 | ) |
| 51 | |
| 52 | type HdrFlags uint32 |
| 53 | type SegFlags uint32 |
| 54 | type SecFlags uint32 |
| 55 | |
| 56 | // A HdrType is the Mach-O file type, e.g. an object file, executable, or dynamic library. |
| 57 | type HdrType uint32 |
| 58 | |
| 59 | const ( // SNAKE_CASE to CamelCase translation from C names |
| 60 | MhObject HdrType = 1 |
| 61 | MhExecute HdrType = 2 |
| 62 | MhCore HdrType = 4 |
| 63 | MhDylib HdrType = 6 |
| 64 | MhBundle HdrType = 8 |
| 65 | MhDsym HdrType = 0xa |
| 66 | ) |
| 67 | |
| 68 | var typeStrings = []intName{ |
| 69 | {uint32(MhObject), "Obj"}, |
| 70 | {uint32(MhExecute), "Exec"}, |
| 71 | {uint32(MhDylib), "Dylib"}, |
| 72 | {uint32(MhBundle), "Bundle"}, |
| 73 | {uint32(MhDsym), "Dsym"}, |
| 74 | } |
| 75 | |
| 76 | func (t HdrType) String() string { return stringName(uint32(t), typeStrings, false) } |
| 77 | func (t HdrType) GoString() string { return stringName(uint32(t), typeStrings, true) } |
| 78 | |
| 79 | // A Cpu is a Mach-O cpu type. |
| 80 | type Cpu uint32 |
| 81 | |
| 82 | const cpuArch64 = 0x01000000 |
| 83 | |
| 84 | const ( |
| 85 | Cpu386 Cpu = 7 |
| 86 | CpuAmd64 Cpu = Cpu386 | cpuArch64 |
| 87 | CpuArm Cpu = 12 |
| 88 | CpuArm64 Cpu = CpuArm | cpuArch64 |
| 89 | CpuPpc Cpu = 18 |
| 90 | CpuPpc64 Cpu = CpuPpc | cpuArch64 |
| 91 | ) |
| 92 | |
| 93 | var cpuStrings = []intName{ |
| 94 | {uint32(Cpu386), "Cpu386"}, |
| 95 | {uint32(CpuAmd64), "CpuAmd64"}, |
| 96 | {uint32(CpuArm), "CpuArm"}, |
| 97 | {uint32(CpuArm64), "CpuArm64"}, |
| 98 | {uint32(CpuPpc), "CpuPpc"}, |
| 99 | {uint32(CpuPpc64), "CpuPpc64"}, |
| 100 | } |
| 101 | |
| 102 | func (i Cpu) String() string { return stringName(uint32(i), cpuStrings, false) } |
| 103 | func (i Cpu) GoString() string { return stringName(uint32(i), cpuStrings, true) } |
| 104 | |
| 105 | // A LoadCmd is a Mach-O load command. |
| 106 | type LoadCmd uint32 |
| 107 | |
| 108 | func (c LoadCmd) Command() LoadCmd { return c } |
| 109 | |
| 110 | const ( // SNAKE_CASE to CamelCase translation from C names |
| 111 | // Note 3 and 8 are obsolete |
| 112 | LcSegment LoadCmd = 0x1 |
| 113 | LcSymtab LoadCmd = 0x2 |
| 114 | LcThread LoadCmd = 0x4 |
| 115 | LcUnixthread LoadCmd = 0x5 // thread+stack |
| 116 | LcDysymtab LoadCmd = 0xb |
| 117 | LcDylib LoadCmd = 0xc // load dylib command |
| 118 | LcIdDylib LoadCmd = 0xd // dynamically linked shared lib ident |
| 119 | LcLoadDylinker LoadCmd = 0xe // load a dynamic linker |
| 120 | LcIdDylinker LoadCmd = 0xf // id dylinker command (not load dylinker command) |
| 121 | LcSegment64 LoadCmd = 0x19 |
| 122 | LcUuid LoadCmd = 0x1b |
| 123 | LcCodeSignature LoadCmd = 0x1d |
| 124 | LcSegmentSplitInfo LoadCmd = 0x1e |
| 125 | LcRpath LoadCmd = 0x8000001c |
| 126 | LcEncryptionInfo LoadCmd = 0x21 |
| 127 | LcDyldInfo LoadCmd = 0x22 |
| 128 | LcDyldInfoOnly LoadCmd = 0x80000022 |
| 129 | LcVersionMinMacosx LoadCmd = 0x24 |
| 130 | LcVersionMinIphoneos LoadCmd = 0x25 |
| 131 | LcFunctionStarts LoadCmd = 0x26 |
| 132 | LcDyldEnvironment LoadCmd = 0x27 |
| 133 | LcMain LoadCmd = 0x80000028 // replacement for UnixThread |
| 134 | LcDataInCode LoadCmd = 0x29 // There are non-instructions in text |
| 135 | LcSourceVersion LoadCmd = 0x2a // Source version used to build binary |
| 136 | LcDylibCodeSignDrs LoadCmd = 0x2b |
| 137 | LcEncryptionInfo64 LoadCmd = 0x2c |
| 138 | LcVersionMinTvos LoadCmd = 0x2f |
| 139 | LcVersionMinWatchos LoadCmd = 0x30 |
| 140 | ) |
| 141 | |
| 142 | var cmdStrings = []intName{ |
| 143 | {uint32(LcSegment), "LoadCmdSegment"}, |
| 144 | {uint32(LcThread), "LoadCmdThread"}, |
| 145 | {uint32(LcUnixthread), "LoadCmdUnixThread"}, |
| 146 | {uint32(LcDylib), "LoadCmdDylib"}, |
| 147 | {uint32(LcIdDylib), "LoadCmdIdDylib"}, |
| 148 | {uint32(LcLoadDylinker), "LoadCmdLoadDylinker"}, |
| 149 | {uint32(LcIdDylinker), "LoadCmdIdDylinker"}, |
| 150 | {uint32(LcSegment64), "LoadCmdSegment64"}, |
| 151 | {uint32(LcUuid), "LoadCmdUuid"}, |
| 152 | {uint32(LcRpath), "LoadCmdRpath"}, |
| 153 | {uint32(LcDyldEnvironment), "LoadCmdDyldEnv"}, |
| 154 | {uint32(LcMain), "LoadCmdMain"}, |
| 155 | {uint32(LcDataInCode), "LoadCmdDataInCode"}, |
| 156 | {uint32(LcSourceVersion), "LoadCmdSourceVersion"}, |
| 157 | {uint32(LcDyldInfo), "LoadCmdDyldInfo"}, |
| 158 | {uint32(LcDyldInfoOnly), "LoadCmdDyldInfoOnly"}, |
| 159 | {uint32(LcVersionMinMacosx), "LoadCmdMinOsx"}, |
| 160 | {uint32(LcFunctionStarts), "LoadCmdFunctionStarts"}, |
| 161 | } |
| 162 | |
| 163 | func (i LoadCmd) String() string { return stringName(uint32(i), cmdStrings, false) } |
| 164 | func (i LoadCmd) GoString() string { return stringName(uint32(i), cmdStrings, true) } |
| 165 | |
| 166 | type ( |
| 167 | // A Segment32 is a 32-bit Mach-O segment load command. |
| 168 | Segment32 struct { |
| 169 | LoadCmd |
| 170 | Len uint32 |
| 171 | Name [16]byte |
| 172 | Addr uint32 |
| 173 | Memsz uint32 |
| 174 | Offset uint32 |
| 175 | Filesz uint32 |
| 176 | Maxprot uint32 |
| 177 | Prot uint32 |
| 178 | Nsect uint32 |
| 179 | Flag SegFlags |
| 180 | } |
| 181 | |
| 182 | // A Segment64 is a 64-bit Mach-O segment load command. |
| 183 | Segment64 struct { |
| 184 | LoadCmd |
| 185 | Len uint32 |
| 186 | Name [16]byte |
| 187 | Addr uint64 |
| 188 | Memsz uint64 |
| 189 | Offset uint64 |
| 190 | Filesz uint64 |
| 191 | Maxprot uint32 |
| 192 | Prot uint32 |
| 193 | Nsect uint32 |
| 194 | Flag SegFlags |
| 195 | } |
| 196 | |
| 197 | // A SymtabCmd is a Mach-O symbol table command. |
| 198 | SymtabCmd struct { |
| 199 | LoadCmd |
| 200 | Len uint32 |
| 201 | Symoff uint32 |
| 202 | Nsyms uint32 |
| 203 | Stroff uint32 |
| 204 | Strsize uint32 |
| 205 | } |
| 206 | |
| 207 | // A DysymtabCmd is a Mach-O dynamic symbol table command. |
| 208 | DysymtabCmd struct { |
| 209 | LoadCmd |
| 210 | Len uint32 |
| 211 | Ilocalsym uint32 |
| 212 | Nlocalsym uint32 |
| 213 | Iextdefsym uint32 |
| 214 | Nextdefsym uint32 |
| 215 | Iundefsym uint32 |
| 216 | Nundefsym uint32 |
| 217 | Tocoffset uint32 |
| 218 | Ntoc uint32 |
| 219 | Modtaboff uint32 |
| 220 | Nmodtab uint32 |
| 221 | Extrefsymoff uint32 |
| 222 | Nextrefsyms uint32 |
| 223 | Indirectsymoff uint32 |
| 224 | Nindirectsyms uint32 |
| 225 | Extreloff uint32 |
| 226 | Nextrel uint32 |
| 227 | Locreloff uint32 |
| 228 | Nlocrel uint32 |
| 229 | } |
| 230 | |
| 231 | // A DylibCmd is a Mach-O load dynamic library command. |
| 232 | DylibCmd struct { |
| 233 | LoadCmd |
| 234 | Len uint32 |
| 235 | Name uint32 |
| 236 | Time uint32 |
| 237 | CurrentVersion uint32 |
| 238 | CompatVersion uint32 |
| 239 | } |
| 240 | |
| 241 | // A DylinkerCmd is a Mach-O load dynamic linker or environment command. |
| 242 | DylinkerCmd struct { |
| 243 | LoadCmd |
| 244 | Len uint32 |
| 245 | Name uint32 |
| 246 | } |
| 247 | |
| 248 | // A RpathCmd is a Mach-O rpath command. |
| 249 | RpathCmd struct { |
| 250 | LoadCmd |
| 251 | Len uint32 |
| 252 | Path uint32 |
| 253 | } |
| 254 | |
| 255 | // A Thread is a Mach-O thread state command. |
| 256 | Thread struct { |
| 257 | LoadCmd |
| 258 | Len uint32 |
| 259 | Type uint32 |
| 260 | Data []uint32 |
| 261 | } |
| 262 | |
| 263 | // LC_DYLD_INFO, LC_DYLD_INFO_ONLY |
| 264 | DyldInfoCmd struct { |
| 265 | LoadCmd |
| 266 | Len uint32 |
| 267 | RebaseOff, RebaseLen uint32 // file offset and length; data contains segment indices |
| 268 | BindOff, BindLen uint32 // file offset and length; data contains segment indices |
| 269 | WeakBindOff, WeakBindLen uint32 // file offset and length |
| 270 | LazyBindOff, LazyBindLen uint32 // file offset and length |
| 271 | ExportOff, ExportLen uint32 // file offset and length |
| 272 | } |
| 273 | |
| 274 | // LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS |
| 275 | LinkEditDataCmd struct { |
| 276 | LoadCmd |
| 277 | Len uint32 |
| 278 | DataOff, DataLen uint32 // file offset and length |
| 279 | } |
| 280 | |
| 281 | // LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64 |
| 282 | EncryptionInfoCmd struct { |
| 283 | LoadCmd |
| 284 | Len uint32 |
| 285 | CryptOff, CryptLen uint32 // file offset and length |
| 286 | CryptId uint32 |
| 287 | } |
| 288 | |
| 289 | UuidCmd struct { |
| 290 | LoadCmd |
| 291 | Len uint32 |
| 292 | Id [16]byte |
| 293 | } |
| 294 | |
| 295 | // TODO Commands below not fully supported yet. |
| 296 | |
| 297 | EntryPointCmd struct { |
| 298 | LoadCmd |
| 299 | Len uint32 |
| 300 | EntryOff uint64 // file offset |
| 301 | StackSize uint64 // if not zero, initial stack size |
| 302 | } |
| 303 | |
| 304 | NoteCmd struct { |
| 305 | LoadCmd |
| 306 | Len uint32 |
| 307 | Name [16]byte |
| 308 | Offset, Filesz uint64 // file offset and length |
| 309 | } |
| 310 | ) |
| 311 | |
| 312 | const ( |
| 313 | FlagNoUndefs HdrFlags = 0x1 |
| 314 | FlagIncrLink HdrFlags = 0x2 |
| 315 | FlagDyldLink HdrFlags = 0x4 |
| 316 | FlagBindAtLoad HdrFlags = 0x8 |
| 317 | FlagPrebound HdrFlags = 0x10 |
| 318 | FlagSplitSegs HdrFlags = 0x20 |
| 319 | FlagLazyInit HdrFlags = 0x40 |
| 320 | FlagTwoLevel HdrFlags = 0x80 |
| 321 | FlagForceFlat HdrFlags = 0x100 |
| 322 | FlagNoMultiDefs HdrFlags = 0x200 |
| 323 | FlagNoFixPrebinding HdrFlags = 0x400 |
| 324 | FlagPrebindable HdrFlags = 0x800 |
| 325 | FlagAllModsBound HdrFlags = 0x1000 |
| 326 | FlagSubsectionsViaSymbols HdrFlags = 0x2000 |
| 327 | FlagCanonical HdrFlags = 0x4000 |
| 328 | FlagWeakDefines HdrFlags = 0x8000 |
| 329 | FlagBindsToWeak HdrFlags = 0x10000 |
| 330 | FlagAllowStackExecution HdrFlags = 0x20000 |
| 331 | FlagRootSafe HdrFlags = 0x40000 |
| 332 | FlagSetuidSafe HdrFlags = 0x80000 |
| 333 | FlagNoReexportedDylibs HdrFlags = 0x100000 |
| 334 | FlagPIE HdrFlags = 0x200000 |
| 335 | FlagDeadStrippableDylib HdrFlags = 0x400000 |
| 336 | FlagHasTLVDescriptors HdrFlags = 0x800000 |
| 337 | FlagNoHeapExecution HdrFlags = 0x1000000 |
| 338 | FlagAppExtensionSafe HdrFlags = 0x2000000 |
| 339 | ) |
| 340 | |
| 341 | // A Section32 is a 32-bit Mach-O section header. |
| 342 | type Section32 struct { |
| 343 | Name [16]byte |
| 344 | Seg [16]byte |
| 345 | Addr uint32 |
| 346 | Size uint32 |
| 347 | Offset uint32 |
| 348 | Align uint32 |
| 349 | Reloff uint32 |
| 350 | Nreloc uint32 |
| 351 | Flags SecFlags |
| 352 | Reserve1 uint32 |
| 353 | Reserve2 uint32 |
| 354 | } |
| 355 | |
| 356 | // A Section64 is a 64-bit Mach-O section header. |
| 357 | type Section64 struct { |
| 358 | Name [16]byte |
| 359 | Seg [16]byte |
| 360 | Addr uint64 |
| 361 | Size uint64 |
| 362 | Offset uint32 |
| 363 | Align uint32 |
| 364 | Reloff uint32 |
| 365 | Nreloc uint32 |
| 366 | Flags SecFlags |
| 367 | Reserve1 uint32 |
| 368 | Reserve2 uint32 |
| 369 | Reserve3 uint32 |
| 370 | } |
| 371 | |
| 372 | // An Nlist32 is a Mach-O 32-bit symbol table entry. |
| 373 | type Nlist32 struct { |
| 374 | Name uint32 |
| 375 | Type uint8 |
| 376 | Sect uint8 |
| 377 | Desc uint16 |
| 378 | Value uint32 |
| 379 | } |
| 380 | |
| 381 | // An Nlist64 is a Mach-O 64-bit symbol table entry. |
| 382 | type Nlist64 struct { |
| 383 | Name uint32 |
| 384 | Type uint8 |
| 385 | Sect uint8 |
| 386 | Desc uint16 |
| 387 | Value uint64 |
| 388 | } |
| 389 | |
| 390 | func (n *Nlist64) Put64(b []byte, o binary.ByteOrder) uint32 { |
| 391 | o.PutUint32(b[0:], n.Name) |
| 392 | b[4] = byte(n.Type) |
| 393 | b[5] = byte(n.Sect) |
| 394 | o.PutUint16(b[6:], n.Desc) |
| 395 | o.PutUint64(b[8:], n.Value) |
| 396 | return 8 + 8 |
| 397 | } |
| 398 | |
| 399 | func (n *Nlist64) Put32(b []byte, o binary.ByteOrder) uint32 { |
| 400 | o.PutUint32(b[0:], n.Name) |
| 401 | b[4] = byte(n.Type) |
| 402 | b[5] = byte(n.Sect) |
| 403 | o.PutUint16(b[6:], n.Desc) |
| 404 | o.PutUint32(b[8:], uint32(n.Value)) |
| 405 | return 8 + 4 |
| 406 | } |
| 407 | |
| 408 | // Regs386 is the Mach-O 386 register structure. |
| 409 | type Regs386 struct { |
| 410 | AX uint32 |
| 411 | BX uint32 |
| 412 | CX uint32 |
| 413 | DX uint32 |
| 414 | DI uint32 |
| 415 | SI uint32 |
| 416 | BP uint32 |
| 417 | SP uint32 |
| 418 | SS uint32 |
| 419 | FLAGS uint32 |
| 420 | IP uint32 |
| 421 | CS uint32 |
| 422 | DS uint32 |
| 423 | ES uint32 |
| 424 | FS uint32 |
| 425 | GS uint32 |
| 426 | } |
| 427 | |
| 428 | // RegsAMD64 is the Mach-O AMD64 register structure. |
| 429 | type RegsAMD64 struct { |
| 430 | AX uint64 |
| 431 | BX uint64 |
| 432 | CX uint64 |
| 433 | DX uint64 |
| 434 | DI uint64 |
| 435 | SI uint64 |
| 436 | BP uint64 |
| 437 | SP uint64 |
| 438 | R8 uint64 |
| 439 | R9 uint64 |
| 440 | R10 uint64 |
| 441 | R11 uint64 |
| 442 | R12 uint64 |
| 443 | R13 uint64 |
| 444 | R14 uint64 |
| 445 | R15 uint64 |
| 446 | IP uint64 |
| 447 | FLAGS uint64 |
| 448 | CS uint64 |
| 449 | FS uint64 |
| 450 | GS uint64 |
| 451 | } |
| 452 | |
| 453 | type intName struct { |
| 454 | i uint32 |
| 455 | s string |
| 456 | } |
| 457 | |
| 458 | func stringName(i uint32, names []intName, goSyntax bool) string { |
| 459 | for _, n := range names { |
| 460 | if n.i == i { |
| 461 | if goSyntax { |
| 462 | return "macho." + n.s |
| 463 | } |
| 464 | return n.s |
| 465 | } |
| 466 | } |
| 467 | return "0x" + strconv.FormatUint(uint64(i), 16) |
| 468 | } |
| 469 |
Members