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
8package macho
9
10import (
11	"encoding/binary"
12	"strconv"
13)
14
15// A FileHeader represents a Mach-O file header.
16type 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
26func (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
41const (
42	fileHeaderSize32 = 7 * 4
43	fileHeaderSize64 = 8 * 4
44)
45
46const (
47	Magic32  uint32 = 0xfeedface
48	Magic64  uint32 = 0xfeedfacf
49	MagicFat uint32 = 0xcafebabe
50)
51
52type HdrFlags uint32
53type SegFlags uint32
54type SecFlags uint32
55
56// A HdrType is the Mach-O file type, e.g. an object file, executable, or dynamic library.
57type HdrType uint32
58
59const ( // 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
68var typeStrings = []intName{
69	{uint32(MhObject), "Obj"},
70	{uint32(MhExecute), "Exec"},
71	{uint32(MhDylib), "Dylib"},
72	{uint32(MhBundle), "Bundle"},
73	{uint32(MhDsym), "Dsym"},
74}
75
76func (t HdrType) String() string   { return stringName(uint32(t), typeStrings, false) }
77func (t HdrType) GoString() string { return stringName(uint32(t), typeStrings, true) }
78
79// A Cpu is a Mach-O cpu type.
80type Cpu uint32
81
82const cpuArch64 = 0x01000000
83
84const (
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
93var 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
102func (i Cpu) String() string   { return stringName(uint32(i), cpuStrings, false) }
103func (i Cpu) GoString() string { return stringName(uint32(i), cpuStrings, true) }
104
105// A LoadCmd is a Mach-O load command.
106type LoadCmd uint32
107
108func (c LoadCmd) Command() LoadCmd { return c }
109
110const ( // 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
142var 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
163func (i LoadCmd) String() string   { return stringName(uint32(i), cmdStrings, false) }
164func (i LoadCmd) GoString() string { return stringName(uint32(i), cmdStrings, true) }
165
166type (
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
312const (
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.
342type 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.
357type 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.
373type 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.
382type Nlist64 struct {
383	Name  uint32
384	Type  uint8
385	Sect  uint8
386	Desc  uint16
387	Value uint64
388}
389
390func (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
399func (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.
409type 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.
429type 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
453type intName struct {
454	i uint32
455	s string
456}
457
458func 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