dyld-832.7.1.tar.gz
[apple/dyld.git] / testing / test-cases / kernel-classic-relocs.h
1
2 #include <mach-o/reloc.h>
3 #include <mach-o/loader.h>
4
5 typedef int (*FixupsLogFunc)(const char*, ...);
6 static const int LogFixupsClassic = 0;
7
8 // We may not have strcmp, so make our own
9 #if __x86_64__
10 __attribute__((section(("__HIB, __text"))))
11 #else
12 __attribute__((section(("__TEXT_EXEC, __text"))))
13 #endif
14 static int areEqualClassic(const char* a, const char* b) {
15 while (*a && *b) {
16 if (*a != *b)
17 return 0;
18 ++a;
19 ++b;
20 }
21 return *a == *b;
22 }
23
24 // Temporary until we have <rdar://problem/57025372>
25 #if __x86_64__
26 __attribute__((section(("__HIB, __text"))))
27 #else
28 __attribute__((section(("__TEXT_EXEC, __text"))))
29 #endif
30 int slideClassic(const struct mach_header* mh, FixupsLogFunc logFunc) {
31
32 #if !__x86_64__
33 return 0;
34 #endif
35
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;
42
43 if (LogFixupsClassic) {
44 logFunc("[LOG] kernel-classic-relocs: mh %p\n", mh);
45 }
46
47 if (LogFixupsClassic) {
48 logFunc("[LOG] kernel-classic-relocs: parsing load commands\n");
49 }
50
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));
56 else {
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
60 }
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);
66 }
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);
70 return 1;
71 }
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);
74 return 1;
75 }
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;
85 }
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);
90 }
91 }
92 }
93 cmd = nextCmd;
94 }
95
96 uintptr_t slide = (uintptr_t)mh - textVMAddr;
97
98 if (LogFixupsClassic) {
99 logFunc("[LOG] kernel-classic-relocs: slide 0x%llx\n", slide);
100 }
101
102 if ( dynSymbolTable == 0 )
103 return 0;
104
105 if ( dynSymbolTable->nlocrel == 0 )
106 return 0;
107
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);
112 }
113
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);
120 }
121
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);
132 }
133 *fixupLoc = slidValue;
134 continue;
135 }
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);
142 }
143 *fixupLoc = slidValue;
144 continue;
145 }
146 logFunc("[LOG] kernel-fixups: unknown reloc size\n", reloc->r_length);
147 return 1;
148 }
149
150 if (LogFixupsClassic) {
151 logFunc("[LOG] kernel-classic-relocs: Done\n");
152 }
153
154 return 0;
155 }
156
157