2 #include <mach-o/reloc.h>
3 #include <mach-o/loader.h>
5 typedef int (*FixupsLogFunc
)(const char*, ...);
6 static const int LogFixupsClassic
= 0;
8 // We may not have strcmp, so make our own
10 __attribute__((section(("__HIB, __text"))))
12 __attribute__((section(("__TEXT_EXEC, __text"))))
14 static int areEqualClassic(const char* a
, const char* b
) {
24 // Temporary until we have <rdar://problem/57025372>
26 __attribute__((section(("__HIB, __text"))))
28 __attribute__((section(("__TEXT_EXEC, __text"))))
30 int slideClassic(const struct mach_header
* mh
, FixupsLogFunc logFunc
) {
36 // First find the slide and dysymtab fixups load command
37 uint64_t textVMAddr
= 0;
38 uint64_t firstWritableVMAddr
= ~0ULL;
39 const struct dysymtab_command
* dynSymbolTable
= 0;
40 uint64_t linkeditVMAddr
= 0;
41 uint64_t linkeditFileOffset
= 0;
43 if (LogFixupsClassic
) {
44 logFunc("[LOG] kernel-classic-relocs: mh %p\n", mh
);
47 if (LogFixupsClassic
) {
48 logFunc("[LOG] kernel-classic-relocs: parsing load commands\n");
51 const struct load_command
* startCmds
= 0;
52 if ( mh
->magic
== MH_MAGIC_64
)
53 startCmds
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header_64
));
54 else if ( mh
->magic
== MH_MAGIC
)
55 startCmds
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header
));
57 const uint32_t* h
= (uint32_t*)mh
;
58 //diag.error("file does not start with MH_MAGIC[_64]: 0x%08X 0x%08X", h[0], h [1]);
59 return 1; // not a mach-o file
61 const struct load_command
* const cmdsEnd
= (struct load_command
*)((char*)startCmds
+ mh
->sizeofcmds
);
62 const struct load_command
* cmd
= startCmds
;
63 for (uint32_t i
= 0; i
< mh
->ncmds
; ++i
) {
64 if (LogFixupsClassic
) {
65 logFunc("[LOG] kernel-classic-relocs: parsing load command %d with cmd=0x%x\n", i
, cmd
->cmd
);
67 const struct load_command
* nextCmd
= (struct load_command
*)((char *)cmd
+ cmd
->cmdsize
);
68 if ( cmd
->cmdsize
< 8 ) {
69 //diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) too small", i, this->ncmds, cmd, this, cmd->cmdsize);
72 if ( (nextCmd
> cmdsEnd
) || (nextCmd
< startCmds
) ) {
73 //diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) is too large, load commands end at %p", i, this->ncmds, cmd, this, cmd->cmdsize, cmdsEnd);
76 if ( cmd
->cmd
== LC_DYSYMTAB
) {
77 dynSymbolTable
= (const struct dysymtab_command
*)cmd
;
78 } else if ( cmd
->cmd
== LC_SEGMENT_64
) {
79 const struct segment_command_64
* seg
= (const struct segment_command_64
*)cmd
;
80 if ( areEqualClassic(seg
->segname
, "__TEXT") ) {
81 textVMAddr
= seg
->vmaddr
;
82 } else if ( areEqualClassic(seg
->segname
, "__LINKEDIT") ) {
83 linkeditVMAddr
= seg
->vmaddr
;
84 linkeditFileOffset
= seg
->fileoff
;
86 if ( (seg
->initprot
& VM_PROT_WRITE
) && (firstWritableVMAddr
== ~0ULL) ) {
87 firstWritableVMAddr
= seg
->vmaddr
;
88 if (LogFixupsClassic
) {
89 logFunc("[LOG] kernel-classic-relocs: first writable segment %s = 0x%llx\n", seg
->segname
, seg
->vmaddr
);
96 uintptr_t slide
= (uintptr_t)mh
- textVMAddr
;
98 if (LogFixupsClassic
) {
99 logFunc("[LOG] kernel-classic-relocs: slide 0x%llx\n", slide
);
102 if ( dynSymbolTable
== 0 )
105 if ( dynSymbolTable
->nlocrel
== 0 )
108 if (LogFixupsClassic
) {
109 logFunc("[LOG] kernel-classic-relocs: found dynamic symbol table %p\n", dynSymbolTable
);
110 logFunc("[LOG] kernel-classic-relocs: found linkeditVMAddr %p\n", (void*)linkeditVMAddr
);
111 logFunc("[LOG] kernel-classic-relocs: found linkeditFileOffset %p\n", (void*)linkeditFileOffset
);
114 // Now we have the dynamic symbol table, walk it to apply all the rebases
115 uint32_t offsetInLinkedit
= dynSymbolTable
->locreloff
- linkeditFileOffset
;
116 uintptr_t linkeditStartAddr
= linkeditVMAddr
+ slide
;
117 if (LogFixupsClassic
) {
118 logFunc("[LOG] kernel-classic-relocs: offsetInLinkedit 0x%x\n", offsetInLinkedit
);
119 logFunc("[LOG] kernel-classic-relocs: linkeditStartAddr %p\n", (void*)linkeditStartAddr
);
122 const uint64_t relocsStartAddress
= firstWritableVMAddr
;
123 const struct relocation_info
* const relocsStart
= (const struct relocation_info
*)(linkeditStartAddr
+ offsetInLinkedit
);
124 const struct relocation_info
* const relocsEnd
= &relocsStart
[dynSymbolTable
->nlocrel
];
125 for (const struct relocation_info
* reloc
= relocsStart
; reloc
< relocsEnd
; ++reloc
) {
126 if ( reloc
->r_length
== 2 ) {
127 uint32_t* fixupLoc
= (uint32_t*)(relocsStartAddress
+ reloc
->r_address
+ slide
);
128 uint32_t slidValue
= *fixupLoc
+ slide
;
129 if (LogFixupsClassic
) {
130 logFunc("[LOG] kernel-classic-relocs: fixupLoc %p = 0x%x + 0x%x + 0x%x\n", fixupLoc
, relocsStartAddress
, reloc
->r_address
, slide
);
131 logFunc("[LOG] kernel-classic-relocs: slidValue *%p = 0x%x\n", fixupLoc
, slidValue
);
133 *fixupLoc
= slidValue
;
136 if ( reloc
->r_length
== 3 ) {
137 uint64_t* fixupLoc
= (uint64_t*)(relocsStartAddress
+ reloc
->r_address
+ slide
);
138 uint64_t slidValue
= *fixupLoc
+ slide
;
139 if (LogFixupsClassic
) {
140 logFunc("[LOG] kernel-classic-relocs: fixupLoc %p = 0x%x + 0x%x + 0x%x\n", fixupLoc
, relocsStartAddress
, reloc
->r_address
, slide
);
141 logFunc("[LOG] kernel-classic-relocs: slidValue *%p = 0x%llx\n", fixupLoc
, slidValue
);
143 *fixupLoc
= slidValue
;
146 logFunc("[LOG] kernel-fixups: unknown reloc size\n", reloc
->r_length
);
150 if (LogFixupsClassic
) {
151 logFunc("[LOG] kernel-classic-relocs: Done\n");