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