source: trunk/kLdr/kLdrModMachO.c@ 102

Last change on this file since 102 was 102, checked in by bird, 8 years ago

gcc7 warning fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 143.5 KB
Line 
1/* $Id: kLdrModMachO.c 102 2017-10-02 10:45:31Z bird $ */
2/** @file
3 * kLdr - The Module Interpreter for the MACH-O format.
4 */
5
6/*
7 * Copyright (c) 2006-2013 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include <k/kLdr.h>
35#include "kLdrInternal.h"
36#include <k/kLdrFmts/mach-o.h>
37
38
39/*******************************************************************************
40* Defined Constants And Macros *
41*******************************************************************************/
42/** @def KLDRMODMACHO_STRICT
43 * Define KLDRMODMACHO_STRICT to enabled strict checks in KLDRMODMACHO. */
44#define KLDRMODMACHO_STRICT 1
45
46/** @def KLDRMODMACHO_ASSERT
47 * Assert that an expression is true when KLDR_STRICT is defined.
48 */
49#ifdef KLDRMODMACHO_STRICT
50# define KLDRMODMACHO_ASSERT(expr) kHlpAssert(expr)
51#else
52# define KLDRMODMACHO_ASSERT(expr) do {} while (0)
53#endif
54
55/** @def KLDRMODMACHO_CHECK_RETURN
56 * Checks that an expression is true and return if it isn't.
57 * This is a debug aid.
58 */
59#ifdef KLDRMODMACHO_STRICT2
60# define KLDRMODMACHO_CHECK_RETURN(expr, rc) kHlpAssertReturn(expr, rc)
61#else
62# define KLDRMODMACHO_CHECK_RETURN(expr, rc) do { if (!(expr)) { return (rc); } } while (0)
63#endif
64
65/** @def KLDRMODMACHO_CHECK_RETURN
66 * Checks that an expression is true and return if it isn't.
67 * This is a debug aid.
68 */
69#ifdef KLDRMODMACHO_STRICT2
70# define KLDRMODMACHO_FAILED_RETURN(rc) kHlpAssertFailedReturn(rc)
71#else
72# define KLDRMODMACHO_FAILED_RETURN(rc) return (rc)
73#endif
74
75
76/*******************************************************************************
77* Structures and Typedefs *
78*******************************************************************************/
79/**
80 * Mach-O section details.
81 */
82typedef struct KLDRMODMACHOSECT
83{
84 /** The size of the section (in bytes). */
85 KLDRSIZE cb;
86 /** The link address of this section. */
87 KLDRADDR LinkAddress;
88 /** The RVA of this section. */
89 KLDRADDR RVA;
90 /** The file offset of this section.
91 * This is -1 if the section doesn't have a file backing. */
92 KLDRFOFF offFile;
93 /** The number of fixups. */
94 KU32 cFixups;
95 /** The array of fixups. (lazy loaded) */
96 macho_relocation_info_t *paFixups;
97 /** The file offset of the fixups for this section.
98 * This is -1 if the section doesn't have any fixups. */
99 KLDRFOFF offFixups;
100 /** Mach-O section flags. */
101 KU32 fFlags;
102 /** kLdr segment index. */
103 KU32 iSegment;
104 /** Pointer to the Mach-O section structure. */
105 void *pvMachoSection;
106} KLDRMODMACHOSECT, *PKLDRMODMACHOSECT;
107
108/**
109 * Extra per-segment info.
110 *
111 * This is corresponds to a kLdr segment, not a Mach-O segment!
112 */
113typedef struct KLDRMODMACHOSEG
114{
115 /** The orignal segment number (in case we had to resort it). */
116 KU32 iOrgSegNo;
117 /** The number of sections in the segment. */
118 KU32 cSections;
119 /** Pointer to the sections belonging to this segment.
120 * The array resides in the big memory chunk allocated for
121 * the module handle, so it doesn't need freeing. */
122 PKLDRMODMACHOSECT paSections;
123
124} KLDRMODMACHOSEG, *PKLDRMODMACHOSEG;
125
126/**
127 * Instance data for the Mach-O MH_OBJECT module interpreter.
128 * @todo interpret the other MH_* formats.
129 */
130typedef struct KLDRMODMACHO
131{
132 /** Pointer to the module. (Follows the section table.) */
133 PKLDRMOD pMod;
134 /** Pointer to the RDR file mapping of the raw file bits. NULL if not mapped. */
135 const void *pvBits;
136 /** Pointer to the user mapping. */
137 void *pvMapping;
138 /** The module open flags. */
139 KU32 fOpenFlags;
140
141 /** The offset of the image. (FAT fun.) */
142 KLDRFOFF offImage;
143 /** The link address. */
144 KLDRADDR LinkAddress;
145 /** The size of the mapped image. */
146 KLDRADDR cbImage;
147 /** Whether we're capable of loading the image. */
148 KBOOL fCanLoad;
149 /** Whether we're creating a global offset table segment.
150 * This dependes on the cputype and image type. */
151 KBOOL fMakeGot;
152 /** The size of a indirect GOT jump stub entry.
153 * This is 0 if not needed. */
154 KU8 cbJmpStub;
155 /** Effective file type. If the original was a MH_OBJECT file, the
156 * corresponding MH_DSYM needs the segment translation of a MH_OBJECT too.
157 * The MH_DSYM normally has a separate __DWARF segment, but this is
158 * automatically skipped during the transation. */
159 KU8 uEffFileType;
160 /** Pointer to the load commands. (endian converted) */
161 KU8 *pbLoadCommands;
162 /** The Mach-O header. (endian converted)
163 * @remark The reserved field is only valid for real 64-bit headers. */
164 mach_header_64_t Hdr;
165
166 /** The offset of the symbol table. */
167 KLDRFOFF offSymbols;
168 /** The number of symbols. */
169 KU32 cSymbols;
170 /** The pointer to the loaded symbol table. */
171 void *pvaSymbols;
172 /** The offset of the string table. */
173 KLDRFOFF offStrings;
174 /** The size of the of the string table. */
175 KU32 cchStrings;
176 /** Pointer to the loaded string table. */
177 char *pchStrings;
178
179 /** The image UUID, all zeros if not found. */
180 KU8 abImageUuid[16];
181
182 /** The RVA of the Global Offset Table. */
183 KLDRADDR GotRVA;
184 /** The RVA of the indirect GOT jump stubs. */
185 KLDRADDR JmpStubsRVA;
186
187 /** The number of sections. */
188 KU32 cSections;
189 /** Pointer to the section array running in parallel to the Mach-O one. */
190 PKLDRMODMACHOSECT paSections;
191
192 /** Array of segments parallel to the one in KLDRMOD. */
193 KLDRMODMACHOSEG aSegments[1];
194} KLDRMODMACHO, *PKLDRMODMACHO;
195
196
197
198/*******************************************************************************
199* Internal Functions *
200*******************************************************************************/
201#if 0
202static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits);
203#endif
204static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
205 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
206
207static int kldrModMachODoCreate(PKRDR pRdr, KLDRFOFF offImage, KU32 fOpenFlags, PKLDRMODMACHO *ppMod);
208static int kldrModMachOPreParseLoadCommands(KU8 *pbLoadCommands, const mach_header_32_t *pHdr, PKRDR pRdr, KLDRFOFF offImage,
209 KU32 fOpenFlags, KU32 *pcSegments, KU32 *pcSections, KU32 *pcbStringPool,
210 PKBOOL pfCanLoad, PKLDRADDR pLinkAddress, KU8 *puEffFileType);
211static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, KU32 cbStringPool);
212static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress);
213
214/*static int kldrModMachOLoadLoadCommands(PKLDRMODMACHO pModMachO);*/
215static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO);
216static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups);
217static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO);
218
219static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings,
220 KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol,
221 KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind);
222static int kldrModMachODoQuerySymbol64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings,
223 KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol,
224 KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind);
225static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms,
226 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
227 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser);
228static int kldrModMachODoEnumSymbols64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms,
229 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
230 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser);
231static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
232static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress);
233static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
234 macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress);
235static int kldrModMachOFixupSectionAMD64(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
236 macho_nlist_64_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress);
237
238static int kldrModMachOMakeGOT(PKLDRMODMACHO pModMachO, void *pvBits, KLDRADDR NewBaseAddress);
239
240/*static int kldrModMachODoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress);
241static int kldrModMachODoImports(PKLDRMODMACHO pModMachO, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);*/
242
243
244/**
245 * Create a loader module instance interpreting the executable image found
246 * in the specified file provider instance.
247 *
248 * @returns 0 on success and *ppMod pointing to a module instance.
249 * On failure, a non-zero OS specific error code is returned.
250 * @param pOps Pointer to the registered method table.
251 * @param pRdr The file provider instance to use.
252 * @param fFlags Flags, MBZ.
253 * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means
254 * anything goes, but with a preference for the current
255 * host architecture.
256 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
257 * @param ppMod Where to store the module instance pointer.
258 */
259static int kldrModMachOCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod)
260{
261 PKLDRMODMACHO pModMachO;
262 int rc;
263
264 /*
265 * Create the instance data and do a minimal header validation.
266 */
267 rc = kldrModMachODoCreate(pRdr, offNewHdr == -1 ? 0 : offNewHdr, fFlags, &pModMachO);
268 if (!rc)
269 {
270
271 /*
272 * Match up against the requested CPU architecture.
273 */
274 if ( enmCpuArch == KCPUARCH_UNKNOWN
275 || pModMachO->pMod->enmArch == enmCpuArch)
276 {
277 pModMachO->pMod->pOps = pOps;
278 pModMachO->pMod->u32Magic = KLDRMOD_MAGIC;
279 *ppMod = pModMachO->pMod;
280 return 0;
281 }
282 rc = KLDR_ERR_CPU_ARCH_MISMATCH;
283 }
284 if (pModMachO)
285 {
286 kHlpFree(pModMachO->pbLoadCommands);
287 kHlpFree(pModMachO);
288 }
289 return rc;
290}
291
292
293/**
294 * Separate function for reading creating the Mach-O module instance to
295 * simplify cleanup on failure.
296 */
297static int kldrModMachODoCreate(PKRDR pRdr, KLDRFOFF offImage, KU32 fOpenFlags, PKLDRMODMACHO *ppModMachO)
298{
299 union
300 {
301 mach_header_32_t Hdr32;
302 mach_header_64_t Hdr64;
303 } s;
304 PKLDRMODMACHO pModMachO;
305 PKLDRMOD pMod;
306 KU8 *pbLoadCommands;
307 KU32 cSegments = 0; /* (MSC maybe used uninitialized) */
308 KU32 cSections = 0; /* (MSC maybe used uninitialized) */
309 KU32 cbStringPool = 0; /* (MSC maybe used uninitialized) */
310 KSIZE cchFilename;
311 KSIZE cb;
312 KBOOL fMakeGot;
313 KBOOL fCanLoad = K_TRUE;
314 KLDRADDR LinkAddress = NIL_KLDRADDR; /* (MSC maybe used uninitialized) */
315 KU8 cbJmpStub;
316 KU8 uEffFileType = 0; /* (MSC maybe used uninitialized) */
317 int rc;
318 *ppModMachO = NULL;
319
320 kHlpAssert(&s.Hdr32.magic == &s.Hdr64.magic);
321 kHlpAssert(&s.Hdr32.flags == &s.Hdr64.flags);
322
323 /*
324 * Read the Mach-O header.
325 */
326 rc = kRdrRead(pRdr, &s, sizeof(s), offImage);
327 if (rc)
328 return rc;
329 if ( s.Hdr32.magic != IMAGE_MACHO32_SIGNATURE
330 && s.Hdr32.magic != IMAGE_MACHO64_SIGNATURE
331 )
332 {
333 if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE
334 || s.Hdr32.magic == IMAGE_MACHO64_SIGNATURE_OE)
335 return KLDR_ERR_MACHO_OTHER_ENDIAN_NOT_SUPPORTED;
336 return KLDR_ERR_UNKNOWN_FORMAT;
337 }
338
339 /* sanity checks. */
340 if ( s.Hdr32.sizeofcmds > kRdrSize(pRdr) - sizeof(mach_header_32_t)
341 || s.Hdr32.sizeofcmds < sizeof(load_command_t) * s.Hdr32.ncmds
342 || (s.Hdr32.flags & ~MH_VALID_FLAGS))
343 return KLDR_ERR_MACHO_BAD_HEADER;
344 switch (s.Hdr32.cputype)
345 {
346 case CPU_TYPE_X86:
347 fMakeGot = K_FALSE;
348 cbJmpStub = 0;
349 break;
350 case CPU_TYPE_X86_64:
351 fMakeGot = s.Hdr32.filetype == MH_OBJECT;
352 cbJmpStub = fMakeGot ? 8 : 0;
353 break;
354 default:
355 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
356 }
357 if ( s.Hdr32.filetype != MH_OBJECT
358 && s.Hdr32.filetype != MH_EXECUTE
359 && s.Hdr32.filetype != MH_DYLIB
360 && s.Hdr32.filetype != MH_BUNDLE
361 && s.Hdr32.filetype != MH_DSYM
362 && s.Hdr32.filetype != MH_KEXT_BUNDLE)
363 return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE;
364
365 /*
366 * Read and pre-parse the load commands to figure out how many segments we'll be needing.
367 */
368 pbLoadCommands = kHlpAlloc(s.Hdr32.sizeofcmds);
369 if (!pbLoadCommands)
370 return KERR_NO_MEMORY;
371 rc = kRdrRead(pRdr, pbLoadCommands, s.Hdr32.sizeofcmds,
372 s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE
373 || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE
374 ? sizeof(mach_header_32_t) + offImage
375 : sizeof(mach_header_64_t) + offImage);
376 if (!rc)
377 rc = kldrModMachOPreParseLoadCommands(pbLoadCommands, &s.Hdr32, pRdr, offImage, fOpenFlags,
378 &cSegments, &cSections, &cbStringPool, &fCanLoad, &LinkAddress, &uEffFileType);
379 if (rc)
380 {
381 kHlpFree(pbLoadCommands);
382 return rc;
383 }
384 cSegments += fMakeGot;
385
386
387 /*
388 * Calc the instance size, allocate and initialize it.
389 */
390 cchFilename = kHlpStrLen(kRdrName(pRdr));
391 cb = K_ALIGN_Z( K_OFFSETOF(KLDRMODMACHO, aSegments[cSegments])
392 + sizeof(KLDRMODMACHOSECT) * cSections, 16)
393 + K_OFFSETOF(KLDRMOD, aSegments[cSegments])
394 + cchFilename + 1
395 + cbStringPool;
396 pModMachO = (PKLDRMODMACHO)kHlpAlloc(cb);
397 if (!pModMachO)
398 return KERR_NO_MEMORY;
399 *ppModMachO = pModMachO;
400 pModMachO->pbLoadCommands = pbLoadCommands;
401 pModMachO->offImage = offImage;
402
403 /* KLDRMOD */
404 pMod = (PKLDRMOD)((KU8 *)pModMachO + K_ALIGN_Z( K_OFFSETOF(KLDRMODMACHO, aSegments[cSegments])
405 + sizeof(KLDRMODMACHOSECT) * cSections, 16));
406 pMod->pvData = pModMachO;
407 pMod->pRdr = pRdr;
408 pMod->pOps = NULL; /* set upon success. */
409 pMod->cSegments = cSegments;
410 pMod->cchFilename = (KU32)cchFilename;
411 pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments];
412 kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1);
413 pMod->pszName = kHlpGetFilename(pMod->pszFilename);
414 pMod->cchName = (KU32)(cchFilename - (pMod->pszName - pMod->pszFilename));
415 pMod->fFlags = 0;
416 switch (s.Hdr32.cputype)
417 {
418 case CPU_TYPE_X86:
419 pMod->enmArch = KCPUARCH_X86_32;
420 pMod->enmEndian = KLDRENDIAN_LITTLE;
421 switch (s.Hdr32.cpusubtype)
422 {
423 case CPU_SUBTYPE_I386_ALL: pMod->enmCpu = KCPU_X86_32_BLEND; break;
424 /*case CPU_SUBTYPE_386: ^^ pMod->enmCpu = KCPU_I386; break;*/
425 case CPU_SUBTYPE_486: pMod->enmCpu = KCPU_I486; break;
426 case CPU_SUBTYPE_486SX: pMod->enmCpu = KCPU_I486SX; break;
427 /*case CPU_SUBTYPE_586: vv */
428 case CPU_SUBTYPE_PENT: pMod->enmCpu = KCPU_I586; break;
429 case CPU_SUBTYPE_PENTPRO:
430 case CPU_SUBTYPE_PENTII_M3:
431 case CPU_SUBTYPE_PENTII_M5:
432 case CPU_SUBTYPE_CELERON:
433 case CPU_SUBTYPE_CELERON_MOBILE:
434 case CPU_SUBTYPE_PENTIUM_3:
435 case CPU_SUBTYPE_PENTIUM_3_M:
436 case CPU_SUBTYPE_PENTIUM_3_XEON: pMod->enmCpu = KCPU_I686; break;
437 case CPU_SUBTYPE_PENTIUM_M:
438 case CPU_SUBTYPE_PENTIUM_4:
439 case CPU_SUBTYPE_PENTIUM_4_M:
440 case CPU_SUBTYPE_XEON:
441 case CPU_SUBTYPE_XEON_MP: pMod->enmCpu = KCPU_P4; break;
442 break;
443
444 default:
445 /* Hack for kextutil output. */
446 if ( s.Hdr32.cpusubtype == 0
447 && s.Hdr32.filetype == MH_OBJECT)
448 break;
449 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
450 }
451 break;
452
453 case CPU_TYPE_X86_64:
454 pMod->enmArch = KCPUARCH_AMD64;
455 pMod->enmEndian = KLDRENDIAN_LITTLE;
456 switch (s.Hdr32.cpusubtype & ~CPU_SUBTYPE_MASK)
457 {
458 case CPU_SUBTYPE_X86_64_ALL: pMod->enmCpu = KCPU_AMD64_BLEND; break;
459 default:
460 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
461 }
462 break;
463
464 default:
465 return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
466 }
467
468 pMod->enmFmt = KLDRFMT_MACHO;
469 switch (s.Hdr32.filetype)
470 {
471 case MH_OBJECT: pMod->enmType = KLDRTYPE_OBJECT; break;
472 case MH_EXECUTE: pMod->enmType = KLDRTYPE_EXECUTABLE_FIXED; break;
473 case MH_DYLIB: pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break;
474 case MH_BUNDLE: pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break;
475 case MH_KEXT_BUNDLE:pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break;
476 case MH_DSYM: pMod->enmType = KLDRTYPE_DEBUG_INFO; break;
477 default:
478 return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE;
479 }
480 pMod->u32Magic = 0; /* set upon success. */
481
482 /* KLDRMODMACHO */
483 pModMachO->pMod = pMod;
484 pModMachO->pvBits = NULL;
485 pModMachO->pvMapping = NULL;
486 pModMachO->fOpenFlags = fOpenFlags;
487 pModMachO->Hdr = s.Hdr64;
488 if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE
489 || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE)
490 pModMachO->Hdr.reserved = 0;
491 pModMachO->LinkAddress = LinkAddress;
492 pModMachO->cbImage = 0;
493 pModMachO->fCanLoad = fCanLoad;
494 pModMachO->fMakeGot = fMakeGot;
495 pModMachO->cbJmpStub = cbJmpStub;
496 pModMachO->uEffFileType = uEffFileType;
497 pModMachO->offSymbols = 0;
498 pModMachO->cSymbols = 0;
499 pModMachO->pvaSymbols = NULL;
500 pModMachO->offStrings = 0;
501 pModMachO->cchStrings = 0;
502 pModMachO->pchStrings = NULL;
503 kHlpMemSet(pModMachO->abImageUuid, 0, sizeof(pModMachO->abImageUuid));
504 pModMachO->GotRVA = NIL_KLDRADDR;
505 pModMachO->JmpStubsRVA = NIL_KLDRADDR;
506 pModMachO->cSections = cSections;
507 pModMachO->paSections = (PKLDRMODMACHOSECT)&pModMachO->aSegments[pModMachO->pMod->cSegments];
508
509 /*
510 * Setup the KLDRMOD segment array.
511 */
512 rc = kldrModMachOParseLoadCommands(pModMachO, (char *)pMod->pszFilename + pMod->cchFilename + 1, cbStringPool);
513 if (rc)
514 return rc;
515
516 /*
517 * We're done.
518 */
519 return 0;
520}
521
522
523/**
524 * Converts, validates and preparses the load commands before we carve
525 * out the module instance.
526 *
527 * The conversion that's preformed is format endian to host endian. The
528 * preparsing has to do with segment counting, section counting and string pool
529 * sizing.
530 *
531 * Segment are created in two different ways, depending on the file type.
532 *
533 * For object files there is only one segment command without a given segment
534 * name. The sections inside that segment have different segment names and are
535 * not sorted by their segname attribute. We create one segment for each
536 * section, with the segment name being 'segname.sectname' in order to hopefully
537 * keep the names unique. Debug sections does not get segments.
538 *
539 * For non-object files, one kLdr segment is created for each Mach-O segment.
540 * Debug segments is not exposed by kLdr via the kLdr segment table, but via the
541 * debug enumeration callback API.
542 *
543 * @returns 0 on success.
544 * @returns KLDR_ERR_MACHO_* on failure.
545 * @param pbLoadCommands The load commands to parse.
546 * @param pHdr The header.
547 * @param pRdr The file reader.
548 * @param offImage The image header (FAT fun).
549 * @param pcSegments Where to store the segment count.
550 * @param pcSegments Where to store the section count.
551 * @param pcbStringPool Where to store the string pool size.
552 * @param pfCanLoad Where to store the can-load-image indicator.
553 * @param pLinkAddress Where to store the image link address (i.e. the
554 * lowest segment address).
555 */
556static int kldrModMachOPreParseLoadCommands(KU8 *pbLoadCommands, const mach_header_32_t *pHdr, PKRDR pRdr, KLDRFOFF offImage,
557 KU32 fOpenFlags, KU32 *pcSegments, KU32 *pcSections, KU32 *pcbStringPool,
558 PKBOOL pfCanLoad, PKLDRADDR pLinkAddress, KU8 *puEffFileType)
559{
560 union
561 {
562 KU8 *pb;
563 load_command_t *pLoadCmd;
564 segment_command_32_t *pSeg32;
565 segment_command_64_t *pSeg64;
566 thread_command_t *pThread;
567 symtab_command_t *pSymTab;
568 uuid_command_t *pUuid;
569 } u;
570 const KU64 cbFile = kRdrSize(pRdr) - offImage;
571 KU32 cSegments = 0;
572 KU32 cSections = 0;
573 KSIZE cbStringPool = 0;
574 KU32 cLeft = pHdr->ncmds;
575 KU32 cbLeft = pHdr->sizeofcmds;
576 KU8 *pb = pbLoadCommands;
577 int cSegmentCommands = 0;
578 int cSymbolTabs = 0;
579 int fConvertEndian = pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
580 || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE;
581 KU8 uEffFileType = *puEffFileType = pHdr->filetype;
582
583 *pcSegments = 0;
584 *pcSections = 0;
585 *pcbStringPool = 0;
586 *pfCanLoad = K_TRUE;
587 *pLinkAddress = ~(KLDRADDR)0;
588
589 while (cLeft-- > 0)
590 {
591 u.pb = pb;
592
593 /*
594 * Convert and validate command header.
595 */
596 KLDRMODMACHO_CHECK_RETURN(cbLeft >= sizeof(load_command_t), KLDR_ERR_MACHO_BAD_LOAD_COMMAND);
597 if (fConvertEndian)
598 {
599 u.pLoadCmd->cmd = K_E2E_U32(u.pLoadCmd->cmd);
600 u.pLoadCmd->cmdsize = K_E2E_U32(u.pLoadCmd->cmdsize);
601 }
602 KLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize <= cbLeft, KLDR_ERR_MACHO_BAD_LOAD_COMMAND);
603 cbLeft -= u.pLoadCmd->cmdsize;
604 pb += u.pLoadCmd->cmdsize;
605
606 /*
607 * Convert endian if needed, parse and validate the command.
608 */
609 switch (u.pLoadCmd->cmd)
610 {
611 case LC_SEGMENT_32:
612 {
613 segment_command_32_t *pSrcSeg = (segment_command_32_t *)u.pLoadCmd;
614 section_32_t *pFirstSect = (section_32_t *)(pSrcSeg + 1);
615 section_32_t *pSect = pFirstSect;
616 KU32 cSectionsLeft = pSrcSeg->nsects;
617 KU64 offSect = 0;
618
619 /* Convert and verify the segment. */
620 KLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize >= sizeof(segment_command_32_t), KLDR_ERR_MACHO_BAD_LOAD_COMMAND);
621 KLDRMODMACHO_CHECK_RETURN( pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
622 || pHdr->magic == IMAGE_MACHO32_SIGNATURE, KLDR_ERR_MACHO_BIT_MIX);
623 if (fConvertEndian)
624 {
625 pSrcSeg->vmaddr = K_E2E_U32(pSrcSeg->vmaddr);
626 pSrcSeg->vmsize = K_E2E_U32(pSrcSeg->vmsize);
627 pSrcSeg->fileoff = K_E2E_U32(pSrcSeg->fileoff);
628 pSrcSeg->filesize = K_E2E_U32(pSrcSeg->filesize);
629 pSrcSeg->maxprot = K_E2E_U32(pSrcSeg->maxprot);
630 pSrcSeg->initprot = K_E2E_U32(pSrcSeg->initprot);
631 pSrcSeg->nsects = K_E2E_U32(pSrcSeg->nsects);
632 pSrcSeg->flags = K_E2E_U32(pSrcSeg->flags);
633 }
634
635 /* Validation code shared with the 64-bit variant. */
636 #define VALIDATE_AND_ADD_SEGMENT(a_cBits) \
637 do { \
638 KBOOL fSkipSeg = !kHlpStrComp(pSrcSeg->segname, "__DWARF") /* Note: Not for non-object files. */ \
639 || ( !kHlpStrComp(pSrcSeg->segname, "__CTF") /* Their CTF tool did/does weird things, */ \
640 && pSrcSeg->vmsize == 0) /* overlapping vmaddr and zero vmsize. */ \
641 || (cSectionsLeft > 0 && (pFirstSect->flags & S_ATTR_DEBUG)); \
642 \
643 /* MH_DSYM files for MH_OBJECT files must have MH_OBJECT segment translation. */ \
644 if ( uEffFileType == MH_DSYM \
645 && cSegmentCommands == 0 \
646 && pSrcSeg->segname[0] == '\0') \
647 *puEffFileType = uEffFileType = MH_OBJECT; \
648 \
649 KLDRMODMACHO_CHECK_RETURN( pSrcSeg->filesize == 0 \
650 || ( pSrcSeg->fileoff <= cbFile \
651 && (KU64)pSrcSeg->fileoff + pSrcSeg->filesize <= cbFile), \
652 KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \
653 KLDRMODMACHO_CHECK_RETURN( pSrcSeg->filesize <= pSrcSeg->vmsize \
654 || (fSkipSeg && !kHlpStrComp(pSrcSeg->segname, "__CTF") /* see above */), \
655 KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \
656 KLDRMODMACHO_CHECK_RETURN(!(~pSrcSeg->maxprot & pSrcSeg->initprot), \
657 KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \
658 KLDRMODMACHO_CHECK_RETURN(!(pSrcSeg->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1)), \
659 KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \
660 KLDRMODMACHO_CHECK_RETURN( pSrcSeg->nsects * sizeof(section_##a_cBits##_t) \
661 <= u.pLoadCmd->cmdsize - sizeof(segment_command_##a_cBits##_t), \
662 KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \
663 KLDRMODMACHO_CHECK_RETURN( uEffFileType != MH_OBJECT \
664 || cSegmentCommands == 0 \
665 || ( cSegmentCommands == 1 \
666 && uEffFileType == MH_OBJECT \
667 && pHdr->filetype == MH_DSYM \
668 && fSkipSeg), \
669 KLDR_ERR_MACHO_BAD_OBJECT_FILE); \
670 cSegmentCommands++; \
671 \
672 /* Add the segment, if not object file. */ \
673 if (!fSkipSeg && uEffFileType != MH_OBJECT) \
674 { \
675 cbStringPool += kHlpStrNLen(&pSrcSeg->segname[0], sizeof(pSrcSeg->segname)) + 1; \
676 cSegments++; \
677 if (cSegments == 1) /* The link address is set by the first segment. */ \
678 *pLinkAddress = pSrcSeg->vmaddr; \
679 } \
680 } while (0)
681
682 VALIDATE_AND_ADD_SEGMENT(32);
683
684 /*
685 * Convert, validate and parse the sections.
686 */
687 cSectionsLeft = pSrcSeg->nsects;
688 pFirstSect = pSect = (section_32_t *)(pSrcSeg + 1);
689 while (cSectionsLeft-- > 0)
690 {
691 if (fConvertEndian)
692 {
693 pSect->addr = K_E2E_U32(pSect->addr);
694 pSect->size = K_E2E_U32(pSect->size);
695 pSect->offset = K_E2E_U32(pSect->offset);
696 pSect->align = K_E2E_U32(pSect->align);
697 pSect->reloff = K_E2E_U32(pSect->reloff);
698 pSect->nreloc = K_E2E_U32(pSect->nreloc);
699 pSect->flags = K_E2E_U32(pSect->flags);
700 pSect->reserved1 = K_E2E_U32(pSect->reserved1);
701 pSect->reserved2 = K_E2E_U32(pSect->reserved2);
702 }
703
704 /* Validation code shared with the 64-bit variant. */
705 #define VALIDATE_AND_ADD_SECTION(a_cBits) \
706 do { \
707 int fFileBits; \
708 \
709 /* validate */ \
710 if (uEffFileType != MH_OBJECT) \
711 KLDRMODMACHO_CHECK_RETURN(!kHlpStrComp(pSect->segname, pSrcSeg->segname),\
712 KLDR_ERR_MACHO_BAD_SECTION); \
713 \
714 switch (pSect->flags & SECTION_TYPE) \
715 { \
716 case S_ZEROFILL: \
717 KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \
718 KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \
719 fFileBits = 0; \
720 break; \
721 case S_REGULAR: \
722 case S_CSTRING_LITERALS: \
723 case S_COALESCED: \
724 case S_4BYTE_LITERALS: \
725 case S_8BYTE_LITERALS: \
726 case S_16BYTE_LITERALS: \
727 KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \
728 KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \
729 fFileBits = 1; \
730 break; \
731 \
732 case S_SYMBOL_STUBS: \
733 KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \
734 /* reserved2 == stub size. 0 has been seen (corecrypto.kext) */ \
735 KLDRMODMACHO_CHECK_RETURN(pSect->reserved2 < 64, KLDR_ERR_MACHO_BAD_SECTION); \
736 fFileBits = 1; \
737 break; \
738 \
739 case S_NON_LAZY_SYMBOL_POINTERS: \
740 case S_LAZY_SYMBOL_POINTERS: \
741 case S_LAZY_DYLIB_SYMBOL_POINTERS: \
742 /* (reserved 1 = is indirect symbol table index) */ \
743 KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \
744 *pfCanLoad = K_FALSE; \
745 fFileBits = -1; /* __DATA.__got in the 64-bit mach_kernel has bits, any things without bits? */ \
746 break; \
747 \
748 case S_MOD_INIT_FUNC_POINTERS: \
749 /** @todo this requires a query API or flag... (e.g. C++ constructors) */ \
750 KLDRMODMACHO_CHECK_RETURN(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO, \
751 KLDR_ERR_MACHO_UNSUPPORTED_INIT_SECTION); \
752 /* Falls through. */ \
753 case S_MOD_TERM_FUNC_POINTERS: \
754 /** @todo this requires a query API or flag... (e.g. C++ destructors) */ \
755 KLDRMODMACHO_CHECK_RETURN(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO, \
756 KLDR_ERR_MACHO_UNSUPPORTED_TERM_SECTION); \
757 KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \
758 KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \
759 fFileBits = 1; \
760 break; /* ignored */ \
761 \
762 case S_LITERAL_POINTERS: \
763 case S_DTRACE_DOF: \
764 KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \
765 KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \
766 fFileBits = 1; \
767 break; \
768 \
769 case S_INTERPOSING: \
770 case S_GB_ZEROFILL: \
771 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNSUPPORTED_SECTION); \
772 \
773 default: \
774 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNKNOWN_SECTION); \
775 } \
776 KLDRMODMACHO_CHECK_RETURN(!(pSect->flags & ~( S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS \
777 | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE \
778 | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC \
779 | S_ATTR_LOC_RELOC | SECTION_TYPE)), \
780 KLDR_ERR_MACHO_BAD_SECTION); \
781 KLDRMODMACHO_CHECK_RETURN((pSect->flags & S_ATTR_DEBUG) == (pFirstSect->flags & S_ATTR_DEBUG), \
782 KLDR_ERR_MACHO_MIXED_DEBUG_SECTION_FLAGS); \
783 \
784 KLDRMODMACHO_CHECK_RETURN(pSect->addr - pSrcSeg->vmaddr <= pSrcSeg->vmsize, \
785 KLDR_ERR_MACHO_BAD_SECTION); \
786 KLDRMODMACHO_CHECK_RETURN( pSect->addr - pSrcSeg->vmaddr + pSect->size <= pSrcSeg->vmsize \
787 || !kHlpStrComp(pSrcSeg->segname, "__CTF") /* see above */, \
788 KLDR_ERR_MACHO_BAD_SECTION); \
789 KLDRMODMACHO_CHECK_RETURN(pSect->align < 31, \
790 KLDR_ERR_MACHO_BAD_SECTION); \
791 /* Workaround for buggy ld64 (or as, llvm, ++) that produces a misaligned __TEXT.__unwind_info. */ \
792 /* Seen: pSect->align = 4, pSect->addr = 0x5ebe14. Just adjust the alignment down. */ \
793 if ( ((K_BIT32(pSect->align) - KU32_C(1)) & pSect->addr) \
794 && pSect->align == 4 \
795 && kHlpStrComp(pSect->sectname, "__unwind_info") == 0) \
796 pSect->align = 2; \
797 KLDRMODMACHO_CHECK_RETURN(!((K_BIT32(pSect->align) - KU32_C(1)) & pSect->addr), \
798 KLDR_ERR_MACHO_BAD_SECTION); \
799 KLDRMODMACHO_CHECK_RETURN(!((K_BIT32(pSect->align) - KU32_C(1)) & pSrcSeg->vmaddr), \
800 KLDR_ERR_MACHO_BAD_SECTION); \
801 \
802 /* Adjust the section offset before we check file offset. */ \
803 offSect = (offSect + K_BIT64(pSect->align) - KU64_C(1)) & ~(K_BIT64(pSect->align) - KU64_C(1)); \
804 if (pSect->addr) \
805 { \
806 KLDRMODMACHO_CHECK_RETURN(offSect <= pSect->addr - pSrcSeg->vmaddr, KLDR_ERR_MACHO_BAD_SECTION); \
807 if (offSect < pSect->addr - pSrcSeg->vmaddr) \
808 offSect = pSect->addr - pSrcSeg->vmaddr; \
809 } \
810 \
811 if (fFileBits && pSect->offset == 0 && pSrcSeg->fileoff == 0 && pHdr->filetype == MH_DSYM) \
812 fFileBits = 0; \
813 if (fFileBits) \
814 { \
815 if (uEffFileType != MH_OBJECT) \
816 { \
817 KLDRMODMACHO_CHECK_RETURN(pSect->offset == pSrcSeg->fileoff + offSect, \
818 KLDR_ERR_MACHO_NON_CONT_SEG_BITS); \
819 KLDRMODMACHO_CHECK_RETURN(pSect->offset - pSrcSeg->fileoff <= pSrcSeg->filesize, \
820 KLDR_ERR_MACHO_BAD_SECTION); \
821 } \
822 KLDRMODMACHO_CHECK_RETURN(pSect->offset <= cbFile, \
823 KLDR_ERR_MACHO_BAD_SECTION); \
824 KLDRMODMACHO_CHECK_RETURN((KU64)pSect->offset + pSect->size <= cbFile, \
825 KLDR_ERR_MACHO_BAD_SECTION); \
826 } \
827 else \
828 KLDRMODMACHO_CHECK_RETURN(pSect->offset == 0, KLDR_ERR_MACHO_BAD_SECTION); \
829 \
830 if (!pSect->nreloc) \
831 KLDRMODMACHO_CHECK_RETURN(!pSect->reloff, \
832 KLDR_ERR_MACHO_BAD_SECTION); \
833 else \
834 { \
835 KLDRMODMACHO_CHECK_RETURN(pSect->reloff <= cbFile, \
836 KLDR_ERR_MACHO_BAD_SECTION); \
837 KLDRMODMACHO_CHECK_RETURN( (KU64)pSect->reloff \
838 + (KLDRFOFF)pSect->nreloc * sizeof(macho_relocation_info_t) \
839 <= cbFile, \
840 KLDR_ERR_MACHO_BAD_SECTION); \
841 } \
842 \
843 /* Validate against file type (pointless?) and count the section, for object files add segment. */ \
844 switch (uEffFileType) \
845 { \
846 case MH_OBJECT: \
847 if ( !(pSect->flags & S_ATTR_DEBUG) \
848 && kHlpStrComp(pSect->segname, "__DWARF")) \
849 { \
850 cbStringPool += kHlpStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1; \
851 cbStringPool += kHlpStrNLen(&pSect->sectname[0], sizeof(pSect->sectname)) + 1; \
852 cSegments++; \
853 if (cSegments == 1) /* The link address is set by the first segment. */ \
854 *pLinkAddress = pSect->addr; \
855 } \
856 /* Falls through. */ \
857 case MH_EXECUTE: \
858 case MH_DYLIB: \
859 case MH_BUNDLE: \
860 case MH_DSYM: \
861 case MH_KEXT_BUNDLE: \
862 cSections++; \
863 break; \
864 default: \
865 KLDRMODMACHO_FAILED_RETURN(KERR_INVALID_PARAMETER); \
866 } \
867 \
868 /* Advance the section offset, since we're also aligning it. */ \
869 offSect += pSect->size; \
870 } while (0) /* VALIDATE_AND_ADD_SECTION */
871
872 VALIDATE_AND_ADD_SECTION(32);
873
874 /* next */
875 pSect++;
876 }
877 break;
878 }
879
880 case LC_SEGMENT_64:
881 {
882 segment_command_64_t *pSrcSeg = (segment_command_64_t *)u.pLoadCmd;
883 section_64_t *pFirstSect = (section_64_t *)(pSrcSeg + 1);
884 section_64_t *pSect = pFirstSect;
885 KU32 cSectionsLeft = pSrcSeg->nsects;
886 KU64 offSect = 0;
887
888 /* Convert and verify the segment. */
889 KLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize >= sizeof(segment_command_64_t), KLDR_ERR_MACHO_BAD_LOAD_COMMAND);
890 KLDRMODMACHO_CHECK_RETURN( pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE
891 || pHdr->magic == IMAGE_MACHO64_SIGNATURE, KLDR_ERR_MACHO_BIT_MIX);
892 if (fConvertEndian)
893 {
894 pSrcSeg->vmaddr = K_E2E_U64(pSrcSeg->vmaddr);
895 pSrcSeg->vmsize = K_E2E_U64(pSrcSeg->vmsize);
896 pSrcSeg->fileoff = K_E2E_U64(pSrcSeg->fileoff);
897 pSrcSeg->filesize = K_E2E_U64(pSrcSeg->filesize);
898 pSrcSeg->maxprot = K_E2E_U32(pSrcSeg->maxprot);
899 pSrcSeg->initprot = K_E2E_U32(pSrcSeg->initprot);
900 pSrcSeg->nsects = K_E2E_U32(pSrcSeg->nsects);
901 pSrcSeg->flags = K_E2E_U32(pSrcSeg->flags);
902 }
903
904 VALIDATE_AND_ADD_SEGMENT(64);
905
906 /*
907 * Convert, validate and parse the sections.
908 */
909 while (cSectionsLeft-- > 0)
910 {
911 if (fConvertEndian)
912 {
913 pSect->addr = K_E2E_U64(pSect->addr);
914 pSect->size = K_E2E_U64(pSect->size);
915 pSect->offset = K_E2E_U32(pSect->offset);
916 pSect->align = K_E2E_U32(pSect->align);
917 pSect->reloff = K_E2E_U32(pSect->reloff);
918 pSect->nreloc = K_E2E_U32(pSect->nreloc);
919 pSect->flags = K_E2E_U32(pSect->flags);
920 pSect->reserved1 = K_E2E_U32(pSect->reserved1);
921 pSect->reserved2 = K_E2E_U32(pSect->reserved2);
922 }
923
924 VALIDATE_AND_ADD_SECTION(64);
925
926 /* next */
927 pSect++;
928 }
929 break;
930 } /* LC_SEGMENT_64 */
931
932
933 case LC_SYMTAB:
934 {
935 KSIZE cbSym;
936 if (fConvertEndian)
937 {
938 u.pSymTab->symoff = K_E2E_U32(u.pSymTab->symoff);
939 u.pSymTab->nsyms = K_E2E_U32(u.pSymTab->nsyms);
940 u.pSymTab->stroff = K_E2E_U32(u.pSymTab->stroff);
941 u.pSymTab->strsize = K_E2E_U32(u.pSymTab->strsize);
942 }
943
944 /* verify */
945 cbSym = pHdr->magic == IMAGE_MACHO32_SIGNATURE
946 || pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
947 ? sizeof(macho_nlist_32_t)
948 : sizeof(macho_nlist_64_t);
949 if ( u.pSymTab->symoff >= cbFile
950 || (KU64)u.pSymTab->symoff + u.pSymTab->nsyms * cbSym > cbFile)
951 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND);
952 if ( u.pSymTab->stroff >= cbFile
953 || (KU64)u.pSymTab->stroff + u.pSymTab->strsize > cbFile)
954 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND);
955
956 /* only one string in objects, please. */
957 cSymbolTabs++;
958 if ( uEffFileType == MH_OBJECT
959 && cSymbolTabs != 1)
960 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_OBJECT_FILE);
961 break;
962 }
963
964 case LC_DYSYMTAB:
965 /** @todo deal with this! */
966 break;
967
968 case LC_THREAD:
969 case LC_UNIXTHREAD:
970 {
971 KU32 *pu32 = (KU32 *)(u.pb + sizeof(load_command_t));
972 KU32 cItemsLeft = (u.pThread->cmdsize - sizeof(load_command_t)) / sizeof(KU32);
973 while (cItemsLeft)
974 {
975 /* convert & verify header items ([0] == flavor, [1] == KU32 count). */
976 if (cItemsLeft < 2)
977 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND);
978 if (fConvertEndian)
979 {
980 pu32[0] = K_E2E_U32(pu32[0]);
981 pu32[1] = K_E2E_U32(pu32[1]);
982 }
983 if (pu32[1] + 2 > cItemsLeft)
984 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND);
985
986 /* convert & verify according to flavor. */
987 switch (pu32[0])
988 {
989 /** @todo */
990 default:
991 break;
992 }
993
994 /* next */
995 cItemsLeft -= pu32[1] + 2;
996 pu32 += pu32[1] + 2;
997 }
998 break;
999 }
1000
1001 case LC_UUID:
1002 if (u.pUuid->cmdsize != sizeof(uuid_command_t))
1003 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND);
1004 /** @todo Check anything here need converting? */
1005 break;
1006
1007 case LC_CODE_SIGNATURE:
1008 if (u.pUuid->cmdsize != sizeof(linkedit_data_command_t))
1009 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND);
1010 break;
1011
1012 case LC_VERSION_MIN_MACOSX:
1013 case LC_VERSION_MIN_IPHONEOS:
1014 if (u.pUuid->cmdsize != sizeof(version_min_command_t))
1015 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND);
1016 break;
1017
1018 case LC_SOURCE_VERSION: /* Harmless. It just gives a clue regarding the source code revision/version. */
1019 case LC_DATA_IN_CODE: /* Ignore */
1020 case LC_DYLIB_CODE_SIGN_DRS:/* Ignore */
1021 /** @todo valid command size. */
1022 break;
1023
1024 case LC_FUNCTION_STARTS: /** @todo dylib++ */
1025 /* Ignore for now. */
1026 break;
1027 case LC_ID_DYLIB: /** @todo dylib */
1028 case LC_LOAD_DYLIB: /** @todo dylib */
1029 case LC_LOAD_DYLINKER: /** @todo dylib */
1030 case LC_TWOLEVEL_HINTS: /** @todo dylib */
1031 case LC_LOAD_WEAK_DYLIB: /** @todo dylib */
1032 case LC_ID_DYLINKER: /** @todo dylib */
1033 case LC_RPATH: /** @todo dylib */
1034 case LC_SEGMENT_SPLIT_INFO: /** @todo dylib++ */
1035 case LC_REEXPORT_DYLIB: /** @todo dylib */
1036 case LC_DYLD_INFO: /** @todo dylib */
1037 case LC_DYLD_INFO_ONLY: /** @todo dylib */
1038 case LC_LOAD_UPWARD_DYLIB: /** @todo dylib */
1039 case LC_DYLD_ENVIRONMENT: /** @todo dylib */
1040 case LC_MAIN: /** @todo parse this and find and entry point or smth. */
1041 /** @todo valid command size. */
1042 if (!(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO))
1043 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND);
1044 *pfCanLoad = K_FALSE;
1045 break;
1046
1047 case LC_LOADFVMLIB:
1048 case LC_IDFVMLIB:
1049 case LC_IDENT:
1050 case LC_FVMFILE:
1051 case LC_PREPAGE:
1052 case LC_PREBOUND_DYLIB:
1053 case LC_ROUTINES:
1054 case LC_ROUTINES_64:
1055 case LC_SUB_FRAMEWORK:
1056 case LC_SUB_UMBRELLA:
1057 case LC_SUB_CLIENT:
1058 case LC_SUB_LIBRARY:
1059 case LC_PREBIND_CKSUM:
1060 case LC_SYMSEG:
1061 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND);
1062
1063 default:
1064 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND);
1065 }
1066 }
1067
1068 /* be strict. */
1069 if (cbLeft)
1070 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND);
1071
1072 switch (uEffFileType)
1073 {
1074 case MH_OBJECT:
1075 case MH_EXECUTE:
1076 case MH_DYLIB:
1077 case MH_BUNDLE:
1078 case MH_DSYM:
1079 case MH_KEXT_BUNDLE:
1080 if (!cSegments)
1081 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_OBJECT_FILE);
1082 break;
1083 }
1084
1085 *pcSegments = cSegments;
1086 *pcSections = cSections;
1087 *pcbStringPool = (KU32)cbStringPool;
1088
1089 return 0;
1090}
1091
1092
1093/**
1094 * Parses the load commands after we've carved out the module instance.
1095 *
1096 * This fills in the segment table and perhaps some other properties.
1097 *
1098 * @returns 0 on success.
1099 * @returns KLDR_ERR_MACHO_* on failure.
1100 * @param pModMachO The module.
1101 * @param pbStringPool The string pool
1102 * @param cbStringPool The size of the string pool.
1103 */
1104static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, KU32 cbStringPool)
1105{
1106 union
1107 {
1108 const KU8 *pb;
1109 const load_command_t *pLoadCmd;
1110 const segment_command_32_t *pSeg32;
1111 const segment_command_64_t *pSeg64;
1112 const symtab_command_t *pSymTab;
1113 const uuid_command_t *pUuid;
1114 } u;
1115 KU32 cLeft = pModMachO->Hdr.ncmds;
1116 KU32 cbLeft = pModMachO->Hdr.sizeofcmds;
1117 const KU8 *pb = pModMachO->pbLoadCommands;
1118 PKLDRSEG pDstSeg = &pModMachO->pMod->aSegments[0];
1119 PKLDRMODMACHOSEG pSegExtra = &pModMachO->aSegments[0];
1120 PKLDRMODMACHOSECT pSectExtra = pModMachO->paSections;
1121 const KU32 cSegments = pModMachO->pMod->cSegments;
1122 PKLDRSEG pSegItr;
1123 K_NOREF(cbStringPool);
1124
1125 while (cLeft-- > 0)
1126 {
1127 u.pb = pb;
1128 cbLeft -= u.pLoadCmd->cmdsize;
1129 pb += u.pLoadCmd->cmdsize;
1130
1131 /*
1132 * Convert endian if needed, parse and validate the command.
1133 */
1134 switch (u.pLoadCmd->cmd)
1135 {
1136 case LC_SEGMENT_32:
1137 {
1138 const segment_command_32_t *pSrcSeg = (const segment_command_32_t *)u.pLoadCmd;
1139 section_32_t *pFirstSect = (section_32_t *)(pSrcSeg + 1);
1140 section_32_t *pSect = pFirstSect;
1141 KU32 cSectionsLeft = pSrcSeg->nsects;
1142
1143 /* Adds a segment, used by the macro below and thus shared with the 64-bit segment variant. */
1144 #define NEW_SEGMENT(a_cBits, a_achName1, a_fObjFile, a_achName2, a_SegAddr, a_cbSeg, a_fFileBits, a_offFile, a_cbFile) \
1145 do { \
1146 pDstSeg->pvUser = NULL; \
1147 pDstSeg->pchName = pbStringPool; \
1148 pDstSeg->cchName = (KU32)kHlpStrNLen(a_achName1, sizeof(a_achName1)); \
1149 kHlpMemCopy(pbStringPool, a_achName1, pDstSeg->cchName); \
1150 pbStringPool += pDstSeg->cchName; \
1151 if (a_fObjFile) \
1152 { /* MH_OBJECT: Add '.sectname' - sections aren't sorted by segments. */ \
1153 KSIZE cchName2 = kHlpStrNLen(a_achName2, sizeof(a_achName2)); \
1154 *pbStringPool++ = '.'; \
1155 kHlpMemCopy(pbStringPool, a_achName2, cchName2); \
1156 pbStringPool += cchName2; \
1157 pDstSeg->cchName += (KU32)cchName2; \
1158 } \
1159 *pbStringPool++ = '\0'; \
1160 pDstSeg->SelFlat = 0; \
1161 pDstSeg->Sel16bit = 0; \
1162 pDstSeg->fFlags = 0; \
1163 pDstSeg->enmProt = KPROT_EXECUTE_WRITECOPY; /** @todo fixme! */ \
1164 pDstSeg->cb = (a_cbSeg); \
1165 pDstSeg->Alignment = 1; /* updated while parsing sections. */ \
1166 pDstSeg->LinkAddress = (a_SegAddr); \
1167 if (a_fFileBits) \
1168 { \
1169 pDstSeg->offFile = (KLDRFOFF)((a_offFile) + pModMachO->offImage); \
1170 pDstSeg->cbFile = (KLDRFOFF)(a_cbFile); \
1171 } \
1172 else \
1173 { \
1174 pDstSeg->offFile = -1; \
1175 pDstSeg->cbFile = -1; \
1176 } \
1177 pDstSeg->RVA = (a_SegAddr) - pModMachO->LinkAddress; \
1178 pDstSeg->cbMapped = 0; \
1179 pDstSeg->MapAddress = 0; \
1180 \
1181 pSegExtra->iOrgSegNo = (KU32)(pSegExtra - &pModMachO->aSegments[0]); \
1182 pSegExtra->cSections = 0; \
1183 pSegExtra->paSections = pSectExtra; \
1184 } while (0)
1185
1186 /* Closes the new segment - part of NEW_SEGMENT. */
1187 #define CLOSE_SEGMENT() \
1188 do { \
1189 pSegExtra->cSections = (KU32)(pSectExtra - pSegExtra->paSections); \
1190 pSegExtra++; \
1191 pDstSeg++; \
1192 } while (0)
1193
1194
1195 /* Shared with the 64-bit variant. */
1196 #define ADD_SEGMENT_AND_ITS_SECTIONS(a_cBits) \
1197 do { \
1198 KBOOL fAddSegOuter = K_FALSE; \
1199 \
1200 /* \
1201 * Check that the segment name is unique. We couldn't do that \
1202 * in the preparsing stage. \
1203 */ \
1204 if (pModMachO->uEffFileType != MH_OBJECT) \
1205 for (pSegItr = &pModMachO->pMod->aSegments[0]; pSegItr != pDstSeg; pSegItr++) \
1206 if (!kHlpStrNComp(pSegItr->pchName, pSrcSeg->segname, sizeof(pSrcSeg->segname))) \
1207 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_DUPLICATE_SEGMENT_NAME); \
1208 \
1209 /* \
1210 * Create a new segment, unless we're supposed to skip this one. \
1211 */ \
1212 if ( pModMachO->uEffFileType != MH_OBJECT \
1213 && (cSectionsLeft == 0 || !(pFirstSect->flags & S_ATTR_DEBUG)) \
1214 && kHlpStrComp(pSrcSeg->segname, "__DWARF") \
1215 && kHlpStrComp(pSrcSeg->segname, "__CTF") ) \
1216 { \
1217 NEW_SEGMENT(a_cBits, pSrcSeg->segname, K_FALSE /*a_fObjFile*/, 0 /*a_achName2*/, \
1218 pSrcSeg->vmaddr, pSrcSeg->vmsize, \
1219 pSrcSeg->filesize != 0, pSrcSeg->fileoff, pSrcSeg->filesize); \
1220 fAddSegOuter = K_TRUE; \
1221 } \
1222 \
1223 /* \
1224 * Convert and parse the sections. \
1225 */ \
1226 while (cSectionsLeft-- > 0) \
1227 { \
1228 /* New segment if object file. */ \
1229 KBOOL fAddSegInner = K_FALSE; \
1230 if ( pModMachO->uEffFileType == MH_OBJECT \
1231 && !(pSect->flags & S_ATTR_DEBUG) \
1232 && kHlpStrComp(pSrcSeg->segname, "__DWARF") \
1233 && kHlpStrComp(pSrcSeg->segname, "__CTF") ) \
1234 { \
1235 kHlpAssert(!fAddSegOuter); \
1236 NEW_SEGMENT(a_cBits, pSect->segname, K_TRUE /*a_fObjFile*/, pSect->sectname, \
1237 pSect->addr, pSect->size, \
1238 pSect->offset != 0, pSect->offset, pSect->size); \
1239 fAddSegInner = K_TRUE; \
1240 } \
1241 \
1242 /* Section data extract. */ \
1243 pSectExtra->cb = pSect->size; \
1244 pSectExtra->RVA = pSect->addr - pDstSeg->LinkAddress; \
1245 pSectExtra->LinkAddress = pSect->addr; \
1246 if (pSect->offset) \
1247 pSectExtra->offFile = pSect->offset + pModMachO->offImage; \
1248 else \
1249 pSectExtra->offFile = -1; \
1250 pSectExtra->cFixups = pSect->nreloc; \
1251 pSectExtra->paFixups = NULL; \
1252 if (pSect->nreloc) \
1253 pSectExtra->offFixups = pSect->reloff + pModMachO->offImage; \
1254 else \
1255 pSectExtra->offFixups = -1; \
1256 pSectExtra->fFlags = pSect->flags; \
1257 pSectExtra->iSegment = (KU32)(pSegExtra - &pModMachO->aSegments[0]); \
1258 pSectExtra->pvMachoSection = pSect; \
1259 \
1260 /* Update the segment alignment, if we're not skipping it. */ \
1261 if ( (fAddSegOuter || fAddSegInner) \
1262 && pDstSeg->Alignment < ((KLDRADDR)1 << pSect->align)) \
1263 pDstSeg->Alignment = (KLDRADDR)1 << pSect->align; \
1264 \
1265 /* Next section, and if object file next segment. */ \
1266 pSectExtra++; \
1267 pSect++; \
1268 if (fAddSegInner) \
1269 CLOSE_SEGMENT(); \
1270 } \
1271 \
1272 /* Close the segment and advance. */ \
1273 if (fAddSegOuter) \
1274 CLOSE_SEGMENT(); \
1275 } while (0) /* ADD_SEGMENT_AND_ITS_SECTIONS */
1276
1277 ADD_SEGMENT_AND_ITS_SECTIONS(32);
1278 break;
1279 }
1280
1281 case LC_SEGMENT_64:
1282 {
1283 const segment_command_64_t *pSrcSeg = (const segment_command_64_t *)u.pLoadCmd;
1284 section_64_t *pFirstSect = (section_64_t *)(pSrcSeg + 1);
1285 section_64_t *pSect = pFirstSect;
1286 KU32 cSectionsLeft = pSrcSeg->nsects;
1287
1288 ADD_SEGMENT_AND_ITS_SECTIONS(64);
1289 break;
1290 }
1291
1292 case LC_SYMTAB:
1293 switch (pModMachO->uEffFileType)
1294 {
1295 case MH_OBJECT:
1296 case MH_EXECUTE:
1297 case MH_DYLIB: /** @todo ??? */
1298 case MH_BUNDLE: /** @todo ??? */
1299 case MH_DSYM:
1300 case MH_KEXT_BUNDLE:
1301 pModMachO->offSymbols = u.pSymTab->symoff + pModMachO->offImage;
1302 pModMachO->cSymbols = u.pSymTab->nsyms;
1303 pModMachO->offStrings = u.pSymTab->stroff + pModMachO->offImage;
1304 pModMachO->cchStrings = u.pSymTab->strsize;
1305 break;
1306 }
1307 break;
1308
1309 case LC_UUID:
1310 kHlpMemCopy(pModMachO->abImageUuid, u.pUuid->uuid, sizeof(pModMachO->abImageUuid));
1311 break;
1312
1313 default:
1314 break;
1315 } /* command switch */
1316 } /* while more commands */
1317
1318 kHlpAssert(pDstSeg == &pModMachO->pMod->aSegments[cSegments - pModMachO->fMakeGot]);
1319
1320 /*
1321 * Adjust mapping addresses calculating the image size.
1322 */
1323 {
1324 KBOOL fLoadLinkEdit = K_FALSE;
1325 PKLDRMODMACHOSECT pSectExtraItr;
1326 KLDRADDR uNextRVA = 0;
1327 KLDRADDR cb;
1328 KU32 cSegmentsToAdjust = cSegments - pModMachO->fMakeGot;
1329 KU32 c;
1330
1331 for (;;)
1332 {
1333 /* Check if there is __DWARF segment at the end and make sure it's left
1334 out of the RVA negotiations and image loading. */
1335 if ( cSegmentsToAdjust > 0
1336 && !kHlpStrComp(pModMachO->pMod->aSegments[cSegmentsToAdjust - 1].pchName, "__DWARF"))
1337 {
1338 cSegmentsToAdjust--;
1339 pModMachO->pMod->aSegments[cSegmentsToAdjust].RVA = NIL_KLDRADDR;
1340 pModMachO->pMod->aSegments[cSegmentsToAdjust].cbMapped = 0;
1341 continue;
1342 }
1343
1344 /* If we're skipping the __LINKEDIT segment, check for it and adjust
1345 the number of segments we'll be messing with here. ASSUMES it's
1346 last (by now anyway). */
1347 if ( !fLoadLinkEdit
1348 && cSegmentsToAdjust > 0
1349 && !kHlpStrComp(pModMachO->pMod->aSegments[cSegmentsToAdjust - 1].pchName, "__LINKEDIT"))
1350 {
1351 cSegmentsToAdjust--;
1352 pModMachO->pMod->aSegments[cSegmentsToAdjust].RVA = NIL_KLDRADDR;
1353 pModMachO->pMod->aSegments[cSegmentsToAdjust].cbMapped = 0;
1354 continue;
1355 }
1356 break;
1357 }
1358
1359 /* Adjust RVAs. */
1360 c = cSegmentsToAdjust;
1361 for (pDstSeg = &pModMachO->pMod->aSegments[0]; c-- > 0; pDstSeg++)
1362 {
1363 cb = pDstSeg->RVA - uNextRVA;
1364 if (cb >= 0x00100000) /* 1MB */
1365 {
1366 pDstSeg->RVA = uNextRVA;
1367 pModMachO->pMod->fFlags |= KLDRMOD_FLAGS_NON_CONTIGUOUS_LINK_ADDRS;
1368 }
1369 uNextRVA = pDstSeg->RVA + KLDR_ALIGN_ADDR(pDstSeg->cb, pDstSeg->Alignment);
1370 }
1371
1372 /* Calculate the cbMapping members. */
1373 c = cSegmentsToAdjust;
1374 for (pDstSeg = &pModMachO->pMod->aSegments[0]; c-- > 1; pDstSeg++)
1375 {
1376
1377 cb = pDstSeg[1].RVA - pDstSeg->RVA;
1378 pDstSeg->cbMapped = (KSIZE)cb == cb ? (KSIZE)cb : KSIZE_MAX;
1379 }
1380
1381 cb = KLDR_ALIGN_ADDR(pDstSeg->cb, pDstSeg->Alignment);
1382 pDstSeg->cbMapped = (KSIZE)cb == cb ? (KSIZE)cb : KSIZE_MAX;
1383
1384 /* Set the image size. */
1385 pModMachO->cbImage = pDstSeg->RVA + cb;
1386
1387 /* Fixup the section RVAs (internal). */
1388 c = cSegmentsToAdjust;
1389 uNextRVA = pModMachO->cbImage;
1390 pDstSeg = &pModMachO->pMod->aSegments[0];
1391 for (pSectExtraItr = pModMachO->paSections; pSectExtraItr != pSectExtra; pSectExtraItr++)
1392 {
1393 if (pSectExtraItr->iSegment < c)
1394 pSectExtraItr->RVA += pDstSeg[pSectExtraItr->iSegment].RVA;
1395 else
1396 {
1397 pSectExtraItr->RVA = uNextRVA;
1398 uNextRVA += KLDR_ALIGN_ADDR(pSectExtraItr->cb, 64);
1399 }
1400 }
1401 }
1402
1403 /*
1404 * Make the GOT segment if necessary.
1405 */
1406 if (pModMachO->fMakeGot)
1407 {
1408 KU32 cbPtr = ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1409 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1410 ? sizeof(KU32)
1411 : sizeof(KU64);
1412 KU32 cbGot = pModMachO->cSymbols * cbPtr;
1413 KU32 cbJmpStubs;
1414
1415 pModMachO->GotRVA = pModMachO->cbImage;
1416
1417 if (pModMachO->cbJmpStub)
1418 {
1419 cbGot = K_ALIGN_Z(cbGot, 64);
1420 pModMachO->JmpStubsRVA = pModMachO->GotRVA + cbGot;
1421 cbJmpStubs = pModMachO->cbJmpStub * pModMachO->cSymbols;
1422 }
1423 else
1424 {
1425 pModMachO->JmpStubsRVA = NIL_KLDRADDR;
1426 cbJmpStubs = 0;
1427 }
1428
1429 pDstSeg = &pModMachO->pMod->aSegments[cSegments - 1];
1430 pDstSeg->pvUser = NULL;
1431 pDstSeg->pchName = "GOT";
1432 pDstSeg->cchName = 3;
1433 pDstSeg->SelFlat = 0;
1434 pDstSeg->Sel16bit = 0;
1435 pDstSeg->fFlags = 0;
1436 pDstSeg->enmProt = KPROT_READONLY;
1437 pDstSeg->cb = cbGot + cbJmpStubs;
1438 pDstSeg->Alignment = 64;
1439 pDstSeg->LinkAddress = pModMachO->LinkAddress + pModMachO->GotRVA;
1440 pDstSeg->offFile = -1;
1441 pDstSeg->cbFile = -1;
1442 pDstSeg->RVA = pModMachO->GotRVA;
1443 pDstSeg->cbMapped = (KSIZE)KLDR_ALIGN_ADDR(cbGot + cbJmpStubs, pDstSeg->Alignment);
1444 pDstSeg->MapAddress = 0;
1445
1446 pSegExtra->iOrgSegNo = KU32_MAX;
1447 pSegExtra->cSections = 0;
1448 pSegExtra->paSections = NULL;
1449
1450 pModMachO->cbImage += pDstSeg->cbMapped;
1451 }
1452
1453 return 0;
1454}
1455
1456
1457/** @copydoc KLDRMODOPS::pfnDestroy */
1458static int kldrModMachODestroy(PKLDRMOD pMod)
1459{
1460 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1461 int rc = 0;
1462 KU32 i, j;
1463 KLDRMODMACHO_ASSERT(!pModMachO->pvMapping);
1464
1465 i = pMod->cSegments;
1466 while (i-- > 0)
1467 {
1468 j = pModMachO->aSegments[i].cSections;
1469 while (j-- > 0)
1470 {
1471 kHlpFree(pModMachO->aSegments[i].paSections[j].paFixups);
1472 pModMachO->aSegments[i].paSections[j].paFixups = NULL;
1473 }
1474 }
1475
1476 if (pMod->pRdr)
1477 {
1478 rc = kRdrClose(pMod->pRdr);
1479 pMod->pRdr = NULL;
1480 }
1481 pMod->u32Magic = 0;
1482 pMod->pOps = NULL;
1483 kHlpFree(pModMachO->pbLoadCommands);
1484 pModMachO->pbLoadCommands = NULL;
1485 kHlpFree(pModMachO->pchStrings);
1486 pModMachO->pchStrings = NULL;
1487 kHlpFree(pModMachO->pvaSymbols);
1488 pModMachO->pvaSymbols = NULL;
1489 kHlpFree(pModMachO);
1490 return rc;
1491}
1492
1493
1494/**
1495 * Gets the right base address.
1496 *
1497 * @returns 0 on success.
1498 * @returns A non-zero status code if the BaseAddress isn't right.
1499 * @param pModMachO The interpreter module instance
1500 * @param pBaseAddress The base address, IN & OUT. Optional.
1501 */
1502static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress)
1503{
1504 /*
1505 * Adjust the base address.
1506 */
1507 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
1508 *pBaseAddress = pModMachO->pMod->aSegments[0].MapAddress;
1509 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
1510 *pBaseAddress = pModMachO->LinkAddress;
1511
1512 return 0;
1513}
1514
1515
1516/**
1517 * Resolves a linker generated symbol.
1518 *
1519 * The Apple linker generates symbols indicating the start and end of sections
1520 * and segments. This function checks for these and returns the right value.
1521 *
1522 * @returns 0 or KLDR_ERR_SYMBOL_NOT_FOUND.
1523 * @param pModMachO The interpreter module instance.
1524 * @param pMod The generic module instance.
1525 * @param pchSymbol The symbol.
1526 * @param cchSymbol The length of the symbol.
1527 * @param BaseAddress The base address to apply when calculating the
1528 * value.
1529 * @param puValue Where to return the symbol value.
1530 */
1531static int kldrModMachOQueryLinkerSymbol(PKLDRMODMACHO pModMachO, PKLDRMOD pMod, const char *pchSymbol, KSIZE cchSymbol,
1532 KLDRADDR BaseAddress, PKLDRADDR puValue)
1533{
1534 /*
1535 * Match possible name prefixes.
1536 */
1537 static const struct
1538 {
1539 const char *pszPrefix;
1540 KU8 cchPrefix;
1541 KBOOL fSection;
1542 KBOOL fStart;
1543 } s_aPrefixes[] =
1544 {
1545 { "section$start$", (KU8)sizeof("section$start$") - 1, K_TRUE, K_TRUE },
1546 { "section$end$", (KU8)sizeof("section$end$") - 1, K_TRUE, K_FALSE},
1547 { "segment$start$", (KU8)sizeof("segment$start$") - 1, K_FALSE, K_TRUE },
1548 { "segment$end$", (KU8)sizeof("segment$end$") - 1, K_FALSE, K_FALSE},
1549 };
1550 KSIZE cchSectName = 0;
1551 const char *pchSectName = "";
1552 KSIZE cchSegName = 0;
1553 const char *pchSegName = NULL;
1554 KU32 iPrefix = K_ELEMENTS(s_aPrefixes) - 1;
1555 KU32 iSeg;
1556 KLDRADDR uValue;
1557
1558 for (;;)
1559 {
1560 KU8 const cchPrefix = s_aPrefixes[iPrefix].cchPrefix;
1561 if ( cchSymbol > cchPrefix
1562 && kHlpStrNComp(pchSymbol, s_aPrefixes[iPrefix].pszPrefix, cchPrefix) == 0)
1563 {
1564 pchSegName = pchSymbol + cchPrefix;
1565 cchSegName = cchSymbol - cchPrefix;
1566 break;
1567 }
1568
1569 /* next */
1570 if (!iPrefix)
1571 return KLDR_ERR_SYMBOL_NOT_FOUND;
1572 iPrefix--;
1573 }
1574
1575 /*
1576 * Split the remainder into segment and section name, if necessary.
1577 */
1578 if (s_aPrefixes[iPrefix].fSection)
1579 {
1580 pchSectName = kHlpMemChr(pchSegName, '$', cchSegName);
1581 if (!pchSectName)
1582 return KLDR_ERR_SYMBOL_NOT_FOUND;
1583 cchSegName = pchSectName - pchSegName;
1584 pchSectName++;
1585 cchSectName = cchSymbol - (pchSectName - pchSymbol);
1586 }
1587
1588 /*
1589 * Locate the segment.
1590 */
1591 if (!pMod->cSegments)
1592 return KLDR_ERR_SYMBOL_NOT_FOUND;
1593 for (iSeg = 0; iSeg < pMod->cSegments; iSeg++)
1594 {
1595 if ( pMod->aSegments[iSeg].cchName >= cchSegName
1596 && kHlpMemComp(pMod->aSegments[iSeg].pchName, pchSegName, cchSegName) == 0)
1597 {
1598 section_32_t const *pSect;
1599 if ( pMod->aSegments[iSeg].cchName == cchSegName
1600 && pModMachO->Hdr.filetype != MH_OBJECT /* Good enough for __DWARF segs in MH_DHSYM, I hope. */)
1601 break;
1602
1603 pSect = (section_32_t *)pModMachO->aSegments[iSeg].paSections[0].pvMachoSection;
1604 if ( pModMachO->uEffFileType == MH_OBJECT
1605 && pMod->aSegments[iSeg].cchName > cchSegName + 1
1606 && pMod->aSegments[iSeg].pchName[cchSegName] == '.'
1607 && kHlpStrNComp(&pMod->aSegments[iSeg].pchName[cchSegName + 1], pSect->sectname, sizeof(pSect->sectname)) == 0
1608 && pMod->aSegments[iSeg].cchName - cchSegName - 1 <= sizeof(pSect->sectname) )
1609 break;
1610 }
1611 }
1612 if (iSeg >= pMod->cSegments)
1613 return KLDR_ERR_SYMBOL_NOT_FOUND;
1614
1615 if (!s_aPrefixes[iPrefix].fSection)
1616 {
1617 /*
1618 * Calculate the segment start/end address.
1619 */
1620 uValue = pMod->aSegments[iSeg].RVA;
1621 if (!s_aPrefixes[iPrefix].fStart)
1622 uValue += pMod->aSegments[iSeg].cb;
1623 }
1624 else
1625 {
1626 /*
1627 * Locate the section.
1628 */
1629 KU32 iSect = pModMachO->aSegments[iSeg].cSections;
1630 if (!iSect)
1631 return KLDR_ERR_SYMBOL_NOT_FOUND;
1632 for (;;)
1633 {
1634 section_32_t *pSect = (section_32_t *)pModMachO->aSegments[iSeg].paSections[iSect].pvMachoSection;
1635 if ( cchSectName <= sizeof(pSect->sectname)
1636 && kHlpMemComp(pSect->sectname, pchSectName, cchSectName) == 0
1637 && ( cchSectName == sizeof(pSect->sectname)
1638 || pSect->sectname[cchSectName] == '\0') )
1639 break;
1640 /* next */
1641 if (!iSect)
1642 return KLDR_ERR_SYMBOL_NOT_FOUND;
1643 iSect--;
1644 }
1645
1646 uValue = pModMachO->aSegments[iSeg].paSections[iSect].RVA;
1647 if (!s_aPrefixes[iPrefix].fStart)
1648 uValue += pModMachO->aSegments[iSeg].paSections[iSect].cb;
1649 }
1650
1651 /*
1652 * Convert from RVA to load address.
1653 */
1654 uValue += BaseAddress;
1655 if (puValue)
1656 *puValue = uValue;
1657
1658 return 0;
1659}
1660
1661
1662/** @copydoc kLdrModQuerySymbol */
1663static int kldrModMachOQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
1664 const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
1665 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
1666{
1667 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1668 int rc;
1669 K_NOREF(pvBits);
1670 K_NOREF(pszVersion);
1671 K_NOREF(pfnGetForwarder);
1672 K_NOREF(pvUser);
1673
1674 /*
1675 * Resolve defaults.
1676 */
1677 rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress);
1678 if (rc)
1679 return rc;
1680
1681 /*
1682 * Refuse segmented requests for now.
1683 */
1684 KLDRMODMACHO_CHECK_RETURN( !pfKind
1685 || (*pfKind & KLDRSYMKIND_REQ_TYPE_MASK) == KLDRSYMKIND_REQ_FLAT,
1686 KLDR_ERR_TODO);
1687
1688 /*
1689 * Take action according to file type.
1690 */
1691 if ( pModMachO->Hdr.filetype == MH_OBJECT
1692 || pModMachO->Hdr.filetype == MH_EXECUTE /** @todo dylib, execute, dsym: symbols */
1693 || pModMachO->Hdr.filetype == MH_DYLIB
1694 || pModMachO->Hdr.filetype == MH_BUNDLE
1695 || pModMachO->Hdr.filetype == MH_DSYM
1696 || pModMachO->Hdr.filetype == MH_KEXT_BUNDLE)
1697 {
1698 rc = kldrModMachOLoadObjSymTab(pModMachO);
1699 if (!rc)
1700 {
1701 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1702 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1703 rc = kldrModMachODoQuerySymbol32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
1704 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol,
1705 (KU32)cchSymbol, puValue, pfKind);
1706 else
1707 rc = kldrModMachODoQuerySymbol64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
1708 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol,
1709 (KU32)cchSymbol, puValue, pfKind);
1710 }
1711
1712 /*
1713 * Check for link-editor generated symbols and supply what we can.
1714 *
1715 * As small service to clients that insists on adding a '_' prefix
1716 * before querying symbols, we will ignore the prefix.
1717 */
1718 if ( rc == KLDR_ERR_SYMBOL_NOT_FOUND
1719 && cchSymbol > sizeof("section$end$") - 1
1720 && ( pchSymbol[0] == 's'
1721 || (pchSymbol[1] == 's' && pchSymbol[0] == '_') )
1722 && kHlpMemChr(pchSymbol, '$', cchSymbol) )
1723 {
1724 if (pchSymbol[0] == '_')
1725 rc = kldrModMachOQueryLinkerSymbol(pModMachO, pMod, pchSymbol + 1, cchSymbol - 1, BaseAddress, puValue);
1726 else
1727 rc = kldrModMachOQueryLinkerSymbol(pModMachO, pMod, pchSymbol, cchSymbol, BaseAddress, puValue);
1728 }
1729 }
1730 else
1731 rc = KLDR_ERR_TODO;
1732
1733 return rc;
1734}
1735
1736
1737/**
1738 * Lookup a symbol in a 32-bit symbol table.
1739 *
1740 * @returns See kLdrModQuerySymbol.
1741 * @param pModMachO
1742 * @param paSyms Pointer to the symbol table.
1743 * @param cSyms Number of symbols in the table.
1744 * @param pchStrings Pointer to the string table.
1745 * @param cchStrings Size of the string table.
1746 * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol.
1747 * @param iSymbol See kLdrModQuerySymbol.
1748 * @param pchSymbol See kLdrModQuerySymbol.
1749 * @param cchSymbol See kLdrModQuerySymbol.
1750 * @param puValue See kLdrModQuerySymbol.
1751 * @param pfKind See kLdrModQuerySymbol.
1752 */
1753static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms,
1754 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol,
1755 const char *pchSymbol, KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind)
1756{
1757 /*
1758 * Find a valid symbol matching the search criteria.
1759 */
1760 if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL)
1761 {
1762 /* simplify validation. */
1763 if (cchStrings <= cchSymbol)
1764 return KLDR_ERR_SYMBOL_NOT_FOUND;
1765 cchStrings -= cchSymbol;
1766
1767 /* external symbols are usually at the end, so search the other way. */
1768 for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--)
1769 {
1770 const char *psz;
1771
1772 /* Skip irrellevant and non-public symbols. */
1773 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1774 continue;
1775 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1776 continue;
1777 if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/
1778 continue;
1779 if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/
1780 continue;
1781
1782 /* get name */
1783 if (!paSyms[iSymbol].n_un.n_strx)
1784 continue;
1785 if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings)
1786 continue;
1787 psz = &pchStrings[paSyms[iSymbol].n_un.n_strx];
1788 if (psz[cchSymbol])
1789 continue;
1790 if (kHlpMemComp(psz, pchSymbol, cchSymbol))
1791 continue;
1792
1793 /* match! */
1794 break;
1795 }
1796 if (iSymbol == KU32_MAX)
1797 return KLDR_ERR_SYMBOL_NOT_FOUND;
1798 }
1799 else
1800 {
1801 if (iSymbol >= cSyms)
1802 return KLDR_ERR_SYMBOL_NOT_FOUND;
1803 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1804 return KLDR_ERR_SYMBOL_NOT_FOUND;
1805 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1806 return KLDR_ERR_SYMBOL_NOT_FOUND;
1807 }
1808
1809 /*
1810 * Calc the return values.
1811 */
1812 if (pfKind)
1813 {
1814 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1815 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1816 *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE;
1817 else
1818 *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE;
1819 if (paSyms[iSymbol].n_desc & N_WEAK_DEF)
1820 *pfKind |= KLDRSYMKIND_WEAK;
1821 }
1822
1823 switch (paSyms[iSymbol].n_type & MACHO_N_TYPE)
1824 {
1825 case MACHO_N_SECT:
1826 {
1827 PKLDRMODMACHOSECT pSect;
1828 KLDRADDR offSect;
1829 KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSymbol].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
1830 pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1];
1831
1832 offSect = paSyms[iSymbol].n_value - pSect->LinkAddress;
1833 KLDRMODMACHO_CHECK_RETURN( offSect <= pSect->cb
1834 || ( paSyms[iSymbol].n_sect == 1 /* special hack for __mh_execute_header */
1835 && offSect == 0U - pSect->RVA
1836 && pModMachO->uEffFileType != MH_OBJECT),
1837 KLDR_ERR_MACHO_BAD_SYMBOL);
1838 if (puValue)
1839 *puValue = BaseAddress + pSect->RVA + offSect;
1840
1841 if ( pfKind
1842 && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)))
1843 *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE;
1844 break;
1845 }
1846
1847 case MACHO_N_ABS:
1848 if (puValue)
1849 *puValue = paSyms[iSymbol].n_value;
1850 /*if (pfKind)
1851 pfKind |= KLDRSYMKIND_ABS;*/
1852 break;
1853
1854 case MACHO_N_PBUD:
1855 case MACHO_N_INDR:
1856 /** @todo implement indirect and prebound symbols. */
1857 default:
1858 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO);
1859 }
1860
1861 return 0;
1862}
1863
1864
1865/**
1866 * Lookup a symbol in a 64-bit symbol table.
1867 *
1868 * @returns See kLdrModQuerySymbol.
1869 * @param pModMachO
1870 * @param paSyms Pointer to the symbol table.
1871 * @param cSyms Number of symbols in the table.
1872 * @param pchStrings Pointer to the string table.
1873 * @param cchStrings Size of the string table.
1874 * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol.
1875 * @param iSymbol See kLdrModQuerySymbol.
1876 * @param pchSymbol See kLdrModQuerySymbol.
1877 * @param cchSymbol See kLdrModQuerySymbol.
1878 * @param puValue See kLdrModQuerySymbol.
1879 * @param pfKind See kLdrModQuerySymbol.
1880 */
1881static int kldrModMachODoQuerySymbol64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms,
1882 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol,
1883 const char *pchSymbol, KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind)
1884{
1885 /*
1886 * Find a valid symbol matching the search criteria.
1887 */
1888 if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL)
1889 {
1890 /* simplify validation. */
1891 if (cchStrings <= cchSymbol)
1892 return KLDR_ERR_SYMBOL_NOT_FOUND;
1893 cchStrings -= cchSymbol;
1894
1895 /* external symbols are usually at the end, so search the other way. */
1896 for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--)
1897 {
1898 const char *psz;
1899
1900 /* Skip irrellevant and non-public symbols. */
1901 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1902 continue;
1903 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1904 continue;
1905 if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/
1906 continue;
1907 if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/
1908 continue;
1909
1910 /* get name */
1911 if (!paSyms[iSymbol].n_un.n_strx)
1912 continue;
1913 if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings)
1914 continue;
1915 psz = &pchStrings[paSyms[iSymbol].n_un.n_strx];
1916 if (psz[cchSymbol])
1917 continue;
1918 if (kHlpMemComp(psz, pchSymbol, cchSymbol))
1919 continue;
1920
1921 /* match! */
1922 break;
1923 }
1924 if (iSymbol == KU32_MAX)
1925 return KLDR_ERR_SYMBOL_NOT_FOUND;
1926 }
1927 else
1928 {
1929 if (iSymbol >= cSyms)
1930 return KLDR_ERR_SYMBOL_NOT_FOUND;
1931 if (paSyms[iSymbol].n_type & MACHO_N_STAB)
1932 return KLDR_ERR_SYMBOL_NOT_FOUND;
1933 if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
1934 return KLDR_ERR_SYMBOL_NOT_FOUND;
1935 }
1936
1937 /*
1938 * Calc the return values.
1939 */
1940 if (pfKind)
1941 {
1942 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
1943 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
1944 *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE;
1945 else
1946 *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE;
1947 if (paSyms[iSymbol].n_desc & N_WEAK_DEF)
1948 *pfKind |= KLDRSYMKIND_WEAK;
1949 }
1950
1951 switch (paSyms[iSymbol].n_type & MACHO_N_TYPE)
1952 {
1953 case MACHO_N_SECT:
1954 {
1955 PKLDRMODMACHOSECT pSect;
1956 KLDRADDR offSect;
1957 KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSymbol].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
1958 pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1];
1959
1960 offSect = paSyms[iSymbol].n_value - pSect->LinkAddress;
1961 KLDRMODMACHO_CHECK_RETURN( offSect <= pSect->cb
1962 || ( paSyms[iSymbol].n_sect == 1 /* special hack for __mh_execute_header */
1963 && offSect == 0U - pSect->RVA
1964 && pModMachO->uEffFileType != MH_OBJECT),
1965 KLDR_ERR_MACHO_BAD_SYMBOL);
1966 if (puValue)
1967 *puValue = BaseAddress + pSect->RVA + offSect;
1968
1969 if ( pfKind
1970 && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)))
1971 *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE;
1972 break;
1973 }
1974
1975 case MACHO_N_ABS:
1976 if (puValue)
1977 *puValue = paSyms[iSymbol].n_value;
1978 /*if (pfKind)
1979 pfKind |= KLDRSYMKIND_ABS;*/
1980 break;
1981
1982 case MACHO_N_PBUD:
1983 case MACHO_N_INDR:
1984 /** @todo implement indirect and prebound symbols. */
1985 default:
1986 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO);
1987 }
1988
1989 return 0;
1990}
1991
1992
1993/** @copydoc kLdrModEnumSymbols */
1994static int kldrModMachOEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
1995 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
1996{
1997 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
1998 int rc;
1999 K_NOREF(pvBits);
2000
2001 /*
2002 * Resolve defaults.
2003 */
2004 rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress);
2005 if (rc)
2006 return rc;
2007
2008 /*
2009 * Take action according to file type.
2010 */
2011 if ( pModMachO->Hdr.filetype == MH_OBJECT
2012 || pModMachO->Hdr.filetype == MH_EXECUTE /** @todo dylib, execute, dsym: symbols */
2013 || pModMachO->Hdr.filetype == MH_DYLIB
2014 || pModMachO->Hdr.filetype == MH_BUNDLE
2015 || pModMachO->Hdr.filetype == MH_DSYM
2016 || pModMachO->Hdr.filetype == MH_KEXT_BUNDLE)
2017 {
2018 rc = kldrModMachOLoadObjSymTab(pModMachO);
2019 if (!rc)
2020 {
2021 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
2022 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
2023 rc = kldrModMachODoEnumSymbols32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
2024 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress,
2025 fFlags, pfnCallback, pvUser);
2026 else
2027 rc = kldrModMachODoEnumSymbols64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
2028 pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress,
2029 fFlags, pfnCallback, pvUser);
2030 }
2031 }
2032 else
2033 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO);
2034
2035 return rc;
2036}
2037
2038
2039/**
2040 * Enum a 32-bit symbol table.
2041 *
2042 * @returns See kLdrModQuerySymbol.
2043 * @param pModMachO
2044 * @param paSyms Pointer to the symbol table.
2045 * @param cSyms Number of symbols in the table.
2046 * @param pchStrings Pointer to the string table.
2047 * @param cchStrings Size of the string table.
2048 * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols.
2049 * @param fFlags See kLdrModEnumSymbols.
2050 * @param pfnCallback See kLdrModEnumSymbols.
2051 * @param pvUser See kLdrModEnumSymbols.
2052 */
2053static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms,
2054 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
2055 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
2056{
2057 const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
2058 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
2059 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT;
2060 KU32 iSym;
2061 int rc;
2062
2063 /*
2064 * Iterate the symbol table.
2065 */
2066 for (iSym = 0; iSym < cSyms; iSym++)
2067 {
2068 KU32 fKind;
2069 KLDRADDR uValue;
2070 const char *psz;
2071 KSIZE cch;
2072
2073 /* Skip debug symbols and undefined symbols. */
2074 if (paSyms[iSym].n_type & MACHO_N_STAB)
2075 continue;
2076 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2077 continue;
2078
2079 /* Skip non-public symbols unless they are requested explicitly. */
2080 if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL))
2081 {
2082 if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/
2083 continue;
2084 if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/
2085 continue;
2086 if (!paSyms[iSym].n_un.n_strx)
2087 continue;
2088 }
2089
2090 /*
2091 * Gather symbol info
2092 */
2093
2094 /* name */
2095 KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL);
2096 psz = &pchStrings[paSyms[iSym].n_un.n_strx];
2097 cch = kHlpStrLen(psz);
2098 if (!cch)
2099 psz = NULL;
2100
2101 /* kind & value */
2102 fKind = fKindBase;
2103 if (paSyms[iSym].n_desc & N_WEAK_DEF)
2104 fKind |= KLDRSYMKIND_WEAK;
2105 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
2106 {
2107 case MACHO_N_SECT:
2108 {
2109 PKLDRMODMACHOSECT pSect;
2110 KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSym].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
2111 pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
2112
2113 uValue = paSyms[iSym].n_value - pSect->LinkAddress;
2114 KLDRMODMACHO_CHECK_RETURN( uValue <= pSect->cb
2115 || ( paSyms[iSym].n_sect == 1 /* special hack for __mh_execute_header */
2116 && uValue == 0U - pSect->RVA
2117 && pModMachO->uEffFileType != MH_OBJECT),
2118 KLDR_ERR_MACHO_BAD_SYMBOL);
2119 uValue += BaseAddress + pSect->RVA;
2120
2121 if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))
2122 fKind |= KLDRSYMKIND_CODE;
2123 else
2124 fKind |= KLDRSYMKIND_NO_TYPE;
2125 break;
2126 }
2127
2128 case MACHO_N_ABS:
2129 uValue = paSyms[iSym].n_value;
2130 fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/;
2131 break;
2132
2133 case MACHO_N_PBUD:
2134 case MACHO_N_INDR:
2135 /** @todo implement indirect and prebound symbols. */
2136 default:
2137 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO);
2138 }
2139
2140 /*
2141 * Do callback.
2142 */
2143 rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser);
2144 if (rc)
2145 return rc;
2146 }
2147 return 0;
2148}
2149
2150
2151/**
2152 * Enum a 64-bit symbol table.
2153 *
2154 * @returns See kLdrModQuerySymbol.
2155 * @param pModMachO
2156 * @param paSyms Pointer to the symbol table.
2157 * @param cSyms Number of symbols in the table.
2158 * @param pchStrings Pointer to the string table.
2159 * @param cchStrings Size of the string table.
2160 * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols.
2161 * @param fFlags See kLdrModEnumSymbols.
2162 * @param pfnCallback See kLdrModEnumSymbols.
2163 * @param pvUser See kLdrModEnumSymbols.
2164 */
2165static int kldrModMachODoEnumSymbols64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms,
2166 const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
2167 KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
2168{
2169 const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE
2170 || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE
2171 ? KLDRSYMKIND_64BIT : KLDRSYMKIND_32BIT;
2172 KU32 iSym;
2173 int rc;
2174
2175 /*
2176 * Iterate the symbol table.
2177 */
2178 for (iSym = 0; iSym < cSyms; iSym++)
2179 {
2180 KU32 fKind;
2181 KLDRADDR uValue;
2182 const char *psz;
2183 KSIZE cch;
2184
2185 /* Skip debug symbols and undefined symbols. */
2186 if (paSyms[iSym].n_type & MACHO_N_STAB)
2187 continue;
2188 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2189 continue;
2190
2191 /* Skip non-public symbols unless they are requested explicitly. */
2192 if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL))
2193 {
2194 if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/
2195 continue;
2196 if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/
2197 continue;
2198 if (!paSyms[iSym].n_un.n_strx)
2199 continue;
2200 }
2201
2202 /*
2203 * Gather symbol info
2204 */
2205
2206 /* name */
2207 KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL);
2208 psz = &pchStrings[paSyms[iSym].n_un.n_strx];
2209 cch = kHlpStrLen(psz);
2210 if (!cch)
2211 psz = NULL;
2212
2213 /* kind & value */
2214 fKind = fKindBase;
2215 if (paSyms[iSym].n_desc & N_WEAK_DEF)
2216 fKind |= KLDRSYMKIND_WEAK;
2217 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
2218 {
2219 case MACHO_N_SECT:
2220 {
2221 PKLDRMODMACHOSECT pSect;
2222 KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSym].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
2223 pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
2224
2225 uValue = paSyms[iSym].n_value - pSect->LinkAddress;
2226 KLDRMODMACHO_CHECK_RETURN( uValue <= pSect->cb
2227 || ( paSyms[iSym].n_sect == 1 /* special hack for __mh_execute_header */
2228 && uValue == 0U - pSect->RVA
2229 && pModMachO->uEffFileType != MH_OBJECT),
2230 KLDR_ERR_MACHO_BAD_SYMBOL);
2231 uValue += BaseAddress + pSect->RVA;
2232
2233 if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))
2234 fKind |= KLDRSYMKIND_CODE;
2235 else
2236 fKind |= KLDRSYMKIND_NO_TYPE;
2237 break;
2238 }
2239
2240 case MACHO_N_ABS:
2241 uValue = paSyms[iSym].n_value;
2242 fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/;
2243 break;
2244
2245 case MACHO_N_PBUD:
2246 case MACHO_N_INDR:
2247 /** @todo implement indirect and prebound symbols. */
2248 default:
2249 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO);
2250 }
2251
2252 /*
2253 * Do callback.
2254 */
2255 rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser);
2256 if (rc)
2257 return rc;
2258 }
2259 return 0;
2260}
2261
2262
2263/** @copydoc kLdrModGetImport */
2264static int kldrModMachOGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName)
2265{
2266 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2267 K_NOREF(pvBits);
2268 K_NOREF(iImport);
2269 K_NOREF(pszName);
2270 K_NOREF(cchName);
2271
2272 if (pModMachO->Hdr.filetype == MH_OBJECT)
2273 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
2274
2275 /* later */
2276 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
2277}
2278
2279
2280/** @copydoc kLdrModNumberOfImports */
2281static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits)
2282{
2283 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2284 K_NOREF(pvBits);
2285
2286 if (pModMachO->Hdr.filetype == MH_OBJECT)
2287 return 0;
2288
2289 /* later */
2290 return 0;
2291}
2292
2293
2294/** @copydoc kLdrModGetStackInfo */
2295static int kldrModMachOGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
2296{
2297 /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/
2298 K_NOREF(pMod);
2299 K_NOREF(pvBits);
2300 K_NOREF(BaseAddress);
2301
2302 pStackInfo->Address = NIL_KLDRADDR;
2303 pStackInfo->LinkAddress = NIL_KLDRADDR;
2304 pStackInfo->cbStack = pStackInfo->cbStackThread = 0;
2305 /* later */
2306
2307 return 0;
2308}
2309
2310
2311/** @copydoc kLdrModQueryMainEntrypoint */
2312static int kldrModMachOQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
2313{
2314#if 0
2315 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2316 int rc;
2317
2318 /*
2319 * Resolve base address alias if any.
2320 */
2321 rc = kldrModMachOBitsAndBaseAddress(pModMachO, NULL, &BaseAddress);
2322 if (rc)
2323 return rc;
2324
2325 /*
2326 * Convert the address from the header.
2327 */
2328 *pMainEPAddress = pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
2329 ? BaseAddress + pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
2330 : NIL_KLDRADDR;
2331#else
2332 *pMainEPAddress = NIL_KLDRADDR;
2333 K_NOREF(pvBits);
2334 K_NOREF(BaseAddress);
2335 K_NOREF(pMod);
2336#endif
2337 return 0;
2338}
2339
2340
2341/** @copydoc kLdrModQueryImageUuid */
2342static int kldrModMachOQueryImageUuid(PKLDRMOD pMod, const void *pvBits, void *pvUuid, KSIZE cbUuid)
2343{
2344 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2345 K_NOREF(pvBits);
2346
2347 kHlpMemSet(pvUuid, 0, cbUuid);
2348 if (kHlpMemComp(pvUuid, pModMachO->abImageUuid, sizeof(pModMachO->abImageUuid)) == 0)
2349 return KLDR_ERR_NO_IMAGE_UUID;
2350
2351 kHlpMemCopy(pvUuid, pModMachO->abImageUuid, sizeof(pModMachO->abImageUuid));
2352 return 0;
2353}
2354
2355
2356/** @copydoc kLdrModEnumDbgInfo */
2357static int kldrModMachOEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
2358{
2359 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2360 int rc = 0;
2361 KU32 iSect;
2362 K_NOREF(pvBits);
2363
2364 for (iSect = 0; iSect < pModMachO->cSections; iSect++)
2365 {
2366 section_32_t *pMachOSect = pModMachO->paSections[iSect].pvMachoSection; /* (32-bit & 64-bit starts the same way) */
2367 char szTmp[sizeof(pMachOSect->sectname) + 1];
2368
2369 if (kHlpStrComp(pMachOSect->segname, "__DWARF"))
2370 continue;
2371
2372 kHlpMemCopy(szTmp, pMachOSect->sectname, sizeof(pMachOSect->sectname));
2373 szTmp[sizeof(pMachOSect->sectname)] = '\0';
2374
2375 rc = pfnCallback(pMod, iSect, KLDRDBGINFOTYPE_DWARF, 0, 0, szTmp,
2376 pModMachO->paSections[iSect].offFile,
2377 pModMachO->paSections[iSect].LinkAddress,
2378 pModMachO->paSections[iSect].cb,
2379 NULL, pvUser);
2380 if (rc != 0)
2381 break;
2382 }
2383
2384 return rc;
2385}
2386
2387
2388/** @copydoc kLdrModHasDbgInfo */
2389static int kldrModMachOHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
2390{
2391 /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/
2392
2393#if 0
2394 /*
2395 * Base this entirely on the presence of a debug directory.
2396 */
2397 if ( pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
2398 < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
2399 || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
2400 return KLDR_ERR_NO_DEBUG_INFO;
2401 return 0;
2402#else
2403 K_NOREF(pMod);
2404 K_NOREF(pvBits);
2405 return KLDR_ERR_NO_DEBUG_INFO;
2406#endif
2407}
2408
2409
2410/** @copydoc kLdrModMap */
2411static int kldrModMachOMap(PKLDRMOD pMod)
2412{
2413 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2414 unsigned fFixed;
2415 KU32 i;
2416 void *pvBase;
2417 int rc;
2418
2419 if (!pModMachO->fCanLoad)
2420 return KLDR_ERR_TODO;
2421
2422 /*
2423 * Already mapped?
2424 */
2425 if (pModMachO->pvMapping)
2426 return KLDR_ERR_ALREADY_MAPPED;
2427
2428 /*
2429 * Map it.
2430 */
2431 /* fixed image? */
2432 fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
2433 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
2434 if (!fFixed)
2435 pvBase = NULL;
2436 else
2437 {
2438 pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress;
2439 if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress)
2440 return KLDR_ERR_ADDRESS_OVERFLOW;
2441 }
2442
2443 /* try do the prepare */
2444 rc = kRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed);
2445 if (rc)
2446 return rc;
2447
2448 /*
2449 * Update the segments with their map addresses.
2450 */
2451 for (i = 0; i < pMod->cSegments; i++)
2452 {
2453 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
2454 pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA;
2455 }
2456 pModMachO->pvMapping = pvBase;
2457
2458 return 0;
2459}
2460
2461
2462/** @copydoc kLdrModUnmap */
2463static int kldrModMachOUnmap(PKLDRMOD pMod)
2464{
2465 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2466 KU32 i;
2467 int rc;
2468
2469 /*
2470 * Mapped?
2471 */
2472 if (!pModMachO->pvMapping)
2473 return KLDR_ERR_NOT_MAPPED;
2474
2475 /*
2476 * Try unmap the image.
2477 */
2478 rc = kRdrUnmap(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
2479 if (rc)
2480 return rc;
2481
2482 /*
2483 * Update the segments to reflect that they aren't mapped any longer.
2484 */
2485 pModMachO->pvMapping = NULL;
2486 for (i = 0; i < pMod->cSegments; i++)
2487 pMod->aSegments[i].MapAddress = 0;
2488
2489 return 0;
2490}
2491
2492
2493/** @copydoc kLdrModAllocTLS */
2494static int kldrModMachOAllocTLS(PKLDRMOD pMod, void *pvMapping)
2495{
2496 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2497
2498 /*
2499 * Mapped?
2500 */
2501 if ( pvMapping == KLDRMOD_INT_MAP
2502 && !pModMachO->pvMapping )
2503 return KLDR_ERR_NOT_MAPPED;
2504 return 0;
2505}
2506
2507
2508/** @copydoc kLdrModFreeTLS */
2509static void kldrModMachOFreeTLS(PKLDRMOD pMod, void *pvMapping)
2510{
2511 K_NOREF(pMod);
2512 K_NOREF(pvMapping);
2513}
2514
2515
2516/** @copydoc kLdrModReload */
2517static int kldrModMachOReload(PKLDRMOD pMod)
2518{
2519 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2520
2521 /*
2522 * Mapped?
2523 */
2524 if (!pModMachO->pvMapping)
2525 return KLDR_ERR_NOT_MAPPED;
2526
2527 /* the file provider does it all */
2528 return kRdrRefresh(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
2529}
2530
2531
2532/** @copydoc kLdrModFixupMapping */
2533static int kldrModMachOFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
2534{
2535 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
2536 int rc, rc2;
2537
2538 /*
2539 * Mapped?
2540 */
2541 if (!pModMachO->pvMapping)
2542 return KLDR_ERR_NOT_MAPPED;
2543
2544 /*
2545 * Before doing anything we'll have to make all pages writable.
2546 */
2547 rc = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
2548 if (rc)
2549 return rc;
2550
2551 /*
2552 * Resolve imports and apply base relocations.
2553 */
2554 rc = kldrModMachORelocateBits(pMod, pModMachO->pvMapping, (KUPTR)pModMachO->pvMapping, pModMachO->LinkAddress,
2555 pfnGetImport, pvUser);
2556
2557 /*
2558 * Restore protection.
2559 */
2560 rc2 = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
2561 if (!rc && rc2)
2562 rc = rc2;
2563 return rc;
2564}
2565
2566
2567/**
2568 * MH_OBJECT: Resolves undefined symbols (imports).
2569 *
2570 * @returns 0 on success, non-zero kLdr status code on failure.
2571 * @param pModMachO The Mach-O module interpreter instance.
2572 * @param pfnGetImport The callback for resolving an imported symbol.
2573 * @param pvUser User argument to the callback.
2574 */
2575static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
2576{
2577 const KU32 cSyms = pModMachO->cSymbols;
2578 KU32 iSym;
2579 int rc;
2580
2581 /*
2582 * Ensure that we've got the symbol table and section fixups handy.
2583 */
2584 rc = kldrModMachOLoadObjSymTab(pModMachO);
2585 if (rc)
2586 return rc;
2587
2588 /*
2589 * Iterate the symbol table and resolve undefined symbols.
2590 * We currently ignore REFERENCE_TYPE.
2591 */
2592 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
2593 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
2594 {
2595 macho_nlist_32_t *paSyms = (macho_nlist_32_t *)pModMachO->pvaSymbols;
2596 for (iSym = 0; iSym < cSyms; iSym++)
2597 {
2598 /* skip stabs */
2599 if (paSyms[iSym].n_type & MACHO_N_STAB)
2600 continue;
2601
2602 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2603 {
2604 const char *pszSymbol;
2605 KSIZE cchSymbol;
2606 KU32 fKind = KLDRSYMKIND_REQ_FLAT;
2607 KLDRADDR Value = NIL_KLDRADDR;
2608
2609 /** @todo Implement N_REF_TO_WEAK. */
2610 KLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), KLDR_ERR_TODO);
2611
2612 /* Get the symbol name. */
2613 KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < pModMachO->cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL);
2614 pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
2615 cchSymbol = kHlpStrLen(pszSymbol);
2616
2617 /* Check for linker defined symbols relating to sections and segments. */
2618 if ( cchSymbol > sizeof("section$end$") - 1
2619 && *pszSymbol == 's'
2620 && kHlpMemChr(pszSymbol, '$', cchSymbol))
2621 rc = kldrModMachOQueryLinkerSymbol(pModMachO, pModMachO->pMod, pszSymbol, cchSymbol, BaseAddress, &Value);
2622 else
2623 rc = KLDR_ERR_SYMBOL_NOT_FOUND;
2624
2625 /* Ask the user for an address to the symbol. */
2626 if (rc)
2627 rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
2628 &Value, &fKind, pvUser);
2629 if (rc)
2630 {
2631 /* weak reference? */
2632 if (!(paSyms[iSym].n_desc & N_WEAK_REF))
2633 break;
2634 Value = 0;
2635 }
2636
2637 /* Update the symbol. */
2638 paSyms[iSym].n_value = (KU32)Value;
2639 if (paSyms[iSym].n_value != Value)
2640 {
2641 rc = KLDR_ERR_ADDRESS_OVERFLOW;
2642 break;
2643 }
2644 }
2645 else if (paSyms[iSym].n_desc & N_WEAK_DEF)
2646 {
2647 /** @todo implement weak symbols. */
2648 /*return KLDR_ERR_TODO; - ignored for now. */
2649 }
2650 }
2651 }
2652 else
2653 {
2654 /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */
2655 macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pModMachO->pvaSymbols;
2656 for (iSym = 0; iSym < cSyms; iSym++)
2657 {
2658 /* skip stabs */
2659 if (paSyms[iSym].n_type & MACHO_N_STAB)
2660 continue;
2661
2662 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
2663 {
2664 const char *pszSymbol;
2665 KSIZE cchSymbol;
2666 KU32 fKind = KLDRSYMKIND_REQ_FLAT;
2667 KLDRADDR Value = NIL_KLDRADDR;
2668
2669 /** @todo Implement N_REF_TO_WEAK. */
2670 KLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), KLDR_ERR_TODO);
2671
2672 /* Get the symbol name. */
2673 KLDRMODMACHO_CHECK_RETURN(paSyms[iSym].n_un.n_strx < pModMachO->cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL);
2674 pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
2675 cchSymbol = kHlpStrLen(pszSymbol);
2676
2677 /* Check for linker defined symbols relating to sections and segments. */
2678 if ( cchSymbol > sizeof("section$end$") - 1
2679 && *pszSymbol == 's'
2680 && kHlpMemChr(pszSymbol, '$', cchSymbol))
2681 rc = kldrModMachOQueryLinkerSymbol(pModMachO, pModMachO->pMod, pszSymbol, cchSymbol, BaseAddress, &Value);
2682 else
2683 rc = KLDR_ERR_SYMBOL_NOT_FOUND;
2684
2685 /* Ask the user for an address to the symbol. */
2686 if (rc)
2687 rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
2688 &Value, &fKind, pvUser);
2689 if (rc)
2690 {
2691 /* weak reference? */
2692 if (!(paSyms[iSym].n_desc & N_WEAK_REF))
2693 break;
2694 Value = 0;
2695 }
2696
2697 /* Update the symbol. */
2698 paSyms[iSym].n_value = Value;
2699 if (paSyms[iSym].n_value != Value)
2700 {
2701 rc = KLDR_ERR_ADDRESS_OVERFLOW;
2702 break;
2703 }
2704 }
2705 else if (paSyms[iSym].n_desc & N_WEAK_DEF)
2706 {
2707 /** @todo implement weak symbols. */
2708 /*return KLDR_ERR_TODO; - ignored for now. */
2709 }
2710 }
2711 }
2712
2713 return rc;
2714}
2715
2716
2717/**
2718 * MH_OBJECT: Applies base relocations to a (unprotected) image mapping.
2719 *
2720 * @returns 0 on success, non-zero kLdr status code on failure.
2721 * @param pModMachO The Mach-O module interpreter instance.
2722 * @param pvMapping The mapping to fixup.
2723 * @param NewBaseAddress The address to fixup the mapping to.
2724 * @param OldBaseAddress The address the mapping is currently fixed up to.
2725 */
2726static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress)
2727{
2728 KU32 iSeg;
2729 int rc;
2730
2731
2732 /*
2733 * Ensure that we've got the symbol table and section fixups handy.
2734 */
2735 rc = kldrModMachOLoadObjSymTab(pModMachO);
2736 if (rc)
2737 return rc;
2738
2739 /*
2740 * Iterate over the segments and their sections and apply fixups.
2741 */
2742 for (iSeg = rc = 0; !rc && iSeg < pModMachO->pMod->cSegments; iSeg++)
2743 {
2744 PKLDRMODMACHOSEG pSeg = &pModMachO->aSegments[iSeg];
2745 KU32 iSect;
2746
2747 for (iSect = 0; iSect < pSeg->cSections; iSect++)
2748 {
2749 PKLDRMODMACHOSECT pSect = &pSeg->paSections[iSect];
2750 KU8 *pbSectBits;
2751
2752 /* skip sections without fixups. */
2753 if (!pSect->cFixups)
2754 continue;
2755
2756 /* lazy load (and endian convert) the fixups. */
2757 if (!pSect->paFixups)
2758 {
2759 rc = kldrModMachOLoadFixups(pModMachO, pSect->offFixups, pSect->cFixups, &pSect->paFixups);
2760 if (rc)
2761 break;
2762 }
2763
2764 /*
2765 * Apply the fixups.
2766 */
2767 pbSectBits = (KU8 *)pvMapping + (KUPTR)pSect->RVA;
2768 if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */
2769 rc = kldrModMachOFixupSectionGeneric32Bit(pModMachO, pbSectBits, pSect,
2770 (macho_nlist_32_t *)pModMachO->pvaSymbols,
2771 pModMachO->cSymbols, NewBaseAddress);
2772 else if ( pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE
2773 && pModMachO->Hdr.cputype == CPU_TYPE_X86_64)
2774 rc = kldrModMachOFixupSectionAMD64(pModMachO, pbSectBits, pSect,
2775 (macho_nlist_64_t *)pModMachO->pvaSymbols,
2776 pModMachO->cSymbols, NewBaseAddress);
2777 else
2778 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO);
2779 if (rc)
2780 break;
2781 }
2782 }
2783
2784 return rc;
2785}
2786
2787
2788/**
2789 * Applies generic fixups to a section in an image of the same endian-ness
2790 * as the host CPU.
2791 *
2792 * @returns 0 on success, non-zero kLdr status code on failure.
2793 * @param pModMachO The Mach-O module interpreter instance.
2794 * @param pbSectBits Pointer to the section bits.
2795 * @param pFixupSect The section being fixed up.
2796 * @param NewBaseAddress The new base image address.
2797 */
2798static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
2799 macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress)
2800{
2801 const macho_relocation_info_t *paFixups = pFixupSect->paFixups;
2802 const KU32 cFixups = pFixupSect->cFixups;
2803 KSIZE cbSectBits = (KSIZE)pFixupSect->cb;
2804 const KU8 *pbSectVirginBits;
2805 KU32 iFixup;
2806 KLDRPU uFixVirgin;
2807 KLDRPU uFix;
2808 KLDRADDR SymAddr = ~(KLDRADDR)0;
2809 int rc;
2810
2811 /*
2812 * Find the virgin bits.
2813 */
2814 if (pFixupSect->offFile != -1)
2815 {
2816 rc = kldrModMachOMapVirginBits(pModMachO);
2817 if (rc)
2818 return rc;
2819 pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile;
2820 }
2821 else
2822 pbSectVirginBits = NULL;
2823
2824 /*
2825 * Iterate the fixups and apply them.
2826 */
2827 for (iFixup = 0; iFixup < cFixups; iFixup++)
2828 {
2829 union
2830 {
2831 macho_relocation_info_t r;
2832 scattered_relocation_info_t s;
2833 } Fixup;
2834 Fixup.r = paFixups[iFixup];
2835
2836 if (!(Fixup.r.r_address & R_SCATTERED))
2837 {
2838 /* sanity */
2839 if ((KU32)Fixup.r.r_address >= cbSectBits)
2840 return KLDR_ERR_BAD_FIXUP;
2841
2842 /* calc fixup addresses. */
2843 uFix.pv = pbSectBits + Fixup.r.r_address;
2844 uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0;
2845
2846 /*
2847 * Calc the symbol value.
2848 */
2849 /* Calc the linked symbol address / addend. */
2850 switch (Fixup.r.r_length)
2851 {
2852 /** @todo Deal with unaligned accesses on non x86 platforms. */
2853 case 0: SymAddr = *uFixVirgin.pi8; break;
2854 case 1: SymAddr = *uFixVirgin.pi16; break;
2855 case 2: SymAddr = *uFixVirgin.pi32; break;
2856 case 3: SymAddr = *uFixVirgin.pi64; break;
2857 }
2858 if (Fixup.r.r_pcrel)
2859 SymAddr += Fixup.r.r_address + pFixupSect->LinkAddress;
2860
2861 /* Add symbol / section address. */
2862 if (Fixup.r.r_extern)
2863 {
2864 const macho_nlist_32_t *pSym;
2865 if (Fixup.r.r_symbolnum >= cSyms)
2866 return KLDR_ERR_BAD_FIXUP;
2867 pSym = &paSyms[Fixup.r.r_symbolnum];
2868
2869 if (pSym->n_type & MACHO_N_STAB)
2870 return KLDR_ERR_BAD_FIXUP;
2871
2872 switch (pSym->n_type & MACHO_N_TYPE)
2873 {
2874 case MACHO_N_SECT:
2875 {
2876 PKLDRMODMACHOSECT pSymSect;
2877 KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
2878 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
2879
2880 SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
2881 break;
2882 }
2883
2884 case MACHO_N_UNDF:
2885 case MACHO_N_ABS:
2886 SymAddr += pSym->n_value;
2887 break;
2888
2889 case MACHO_N_INDR:
2890 case MACHO_N_PBUD:
2891 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO);
2892 default:
2893 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL);
2894 }
2895 }
2896 else if (Fixup.r.r_symbolnum != R_ABS)
2897 {
2898 PKLDRMODMACHOSECT pSymSect;
2899 if (Fixup.r.r_symbolnum > pModMachO->cSections)
2900 return KLDR_ERR_BAD_FIXUP;
2901 pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1];
2902
2903 SymAddr -= pSymSect->LinkAddress;
2904 SymAddr += pSymSect->RVA + NewBaseAddress;
2905 }
2906
2907 /* adjust for PC relative */
2908 if (Fixup.r.r_pcrel)
2909 SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress;
2910 }
2911 else
2912 {
2913 PKLDRMODMACHOSECT pSymSect;
2914 KU32 iSymSect;
2915 KLDRADDR Value;
2916
2917 /* sanity */
2918 KLDRMODMACHO_ASSERT(Fixup.s.r_scattered);
2919 if ((KU32)Fixup.s.r_address >= cbSectBits)
2920 return KLDR_ERR_BAD_FIXUP;
2921
2922 /* calc fixup addresses. */
2923 uFix.pv = pbSectBits + Fixup.s.r_address;
2924 uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.s.r_address : 0;
2925
2926 /*
2927 * Calc the symbol value.
2928 */
2929 /* The addend is stored in the code. */
2930 switch (Fixup.s.r_length)
2931 {
2932 case 0: SymAddr = *uFixVirgin.pi8; break;
2933 case 1: SymAddr = *uFixVirgin.pi16; break;
2934 case 2: SymAddr = *uFixVirgin.pi32; break;
2935 case 3: SymAddr = *uFixVirgin.pi64; break;
2936 }
2937 if (Fixup.s.r_pcrel)
2938 SymAddr += Fixup.s.r_address;
2939 Value = Fixup.s.r_value;
2940 SymAddr -= Value; /* (-> addend only) */
2941
2942 /* Find the section number from the r_value. */
2943 pSymSect = NULL;
2944 for (iSymSect = 0; iSymSect < pModMachO->cSections; iSymSect++)
2945 {
2946 KLDRADDR off = Value - pModMachO->paSections[iSymSect].LinkAddress;
2947 if (off < pModMachO->paSections[iSymSect].cb)
2948 {
2949 pSymSect = &pModMachO->paSections[iSymSect];
2950 break;
2951 }
2952 else if (off == pModMachO->paSections[iSymSect].cb) /* edge case */
2953 pSymSect = &pModMachO->paSections[iSymSect];
2954 }
2955 if (!pSymSect)
2956 return KLDR_ERR_BAD_FIXUP;
2957
2958 /* Calc the symbol address. */
2959 SymAddr += Value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
2960 if (Fixup.s.r_pcrel)
2961 SymAddr -= Fixup.s.r_address + pFixupSect->RVA + NewBaseAddress;
2962
2963 Fixup.r.r_length = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_length;
2964 Fixup.r.r_type = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_type;
2965 }
2966
2967 /*
2968 * Write back the fixed up value.
2969 */
2970 if (Fixup.r.r_type == GENERIC_RELOC_VANILLA)
2971 {
2972 switch (Fixup.r.r_length)
2973 {
2974 case 0: *uFix.pu8 = (KU8)SymAddr; break;
2975 case 1: *uFix.pu16 = (KU16)SymAddr; break;
2976 case 2: *uFix.pu32 = (KU32)SymAddr; break;
2977 case 3: *uFix.pu64 = (KU64)SymAddr; break;
2978 }
2979 }
2980 else if (Fixup.r.r_type <= GENERIC_RELOC_LOCAL_SECTDIFF)
2981 return KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE;
2982 else
2983 return KLDR_ERR_BAD_FIXUP;
2984 }
2985
2986 return 0;
2987}
2988
2989
2990/**
2991 * Applies AMD64 fixups to a section.
2992 *
2993 * @returns 0 on success, non-zero kLdr status code on failure.
2994 * @param pModMachO The Mach-O module interpreter instance.
2995 * @param pbSectBits Pointer to the section bits.
2996 * @param pFixupSect The section being fixed up.
2997 * @param NewBaseAddress The new base image address.
2998 */
2999static int kldrModMachOFixupSectionAMD64(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
3000 macho_nlist_64_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress)
3001{
3002 const macho_relocation_info_t *paFixups = pFixupSect->paFixups;
3003 const KU32 cFixups = pFixupSect->cFixups;
3004 KSIZE cbSectBits = (KSIZE)pFixupSect->cb;
3005 const KU8 *pbSectVirginBits;
3006 KU32 iFixup;
3007 KLDRPU uFixVirgin;
3008 KLDRPU uFix;
3009 KLDRADDR SymAddr;
3010 int rc;
3011
3012 /*
3013 * Find the virgin bits.
3014 */
3015 if (pFixupSect->offFile != -1)
3016 {
3017 rc = kldrModMachOMapVirginBits(pModMachO);
3018 if (rc)
3019 return rc;
3020 pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile;
3021 }
3022 else
3023 pbSectVirginBits = NULL;
3024
3025 /*
3026 * Iterate the fixups and apply them.
3027 */
3028 for (iFixup = 0; iFixup < cFixups; iFixup++)
3029 {
3030 union
3031 {
3032 macho_relocation_info_t r;
3033 scattered_relocation_info_t s;
3034 } Fixup;
3035 Fixup.r = paFixups[iFixup];
3036
3037 /* AMD64 doesn't use scattered fixups. */
3038 KLDRMODMACHO_CHECK_RETURN(!(Fixup.r.r_address & R_SCATTERED), KLDR_ERR_BAD_FIXUP);
3039
3040 /* sanity */
3041 KLDRMODMACHO_CHECK_RETURN((KU32)Fixup.r.r_address < cbSectBits, KLDR_ERR_BAD_FIXUP);
3042
3043 /* calc fixup addresses. */
3044 uFix.pv = pbSectBits + Fixup.r.r_address;
3045 uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0;
3046
3047 /*
3048 * Calc the symbol value.
3049 */
3050 /* Calc the linked symbol address / addend. */
3051 switch (Fixup.r.r_length)
3052 {
3053 /** @todo Deal with unaligned accesses on non x86 platforms. */
3054 case 2: SymAddr = *uFixVirgin.pi32; break;
3055 case 3: SymAddr = *uFixVirgin.pi64; break;
3056 default:
3057 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP);
3058 }
3059
3060 /* Add symbol / section address. */
3061 if (Fixup.r.r_extern)
3062 {
3063 const macho_nlist_64_t *pSym;
3064
3065 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_symbolnum < cSyms, KLDR_ERR_BAD_FIXUP);
3066 pSym = &paSyms[Fixup.r.r_symbolnum];
3067 KLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), KLDR_ERR_BAD_FIXUP);
3068
3069 switch (Fixup.r.r_type)
3070 {
3071 /* GOT references just needs to have their symbol verified.
3072 Later, we'll optimize GOT building here using a parallel sym->got array. */
3073 case X86_64_RELOC_GOT_LOAD:
3074 case X86_64_RELOC_GOT:
3075 switch (pSym->n_type & MACHO_N_TYPE)
3076 {
3077 case MACHO_N_SECT:
3078 case MACHO_N_UNDF:
3079 case MACHO_N_ABS:
3080 break;
3081 case MACHO_N_INDR:
3082 case MACHO_N_PBUD:
3083 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO);
3084 default:
3085 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL);
3086 }
3087 SymAddr = sizeof(KU64) * Fixup.r.r_symbolnum + pModMachO->GotRVA + NewBaseAddress;
3088 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_length == 2, KLDR_ERR_BAD_FIXUP);
3089 SymAddr -= 4;
3090 break;
3091
3092 /* Verify the r_pcrel field for signed fixups on the way into the default case. */
3093 case X86_64_RELOC_BRANCH:
3094 case X86_64_RELOC_SIGNED:
3095 case X86_64_RELOC_SIGNED_1:
3096 case X86_64_RELOC_SIGNED_2:
3097 case X86_64_RELOC_SIGNED_4:
3098 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP);
3099 /* Falls through. */
3100 default:
3101 {
3102 /* Adjust with fixup specific addend and vierfy unsigned/r_pcrel. */
3103 switch (Fixup.r.r_type)
3104 {
3105 case X86_64_RELOC_UNSIGNED:
3106 KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP);
3107 break;
3108 case X86_64_RELOC_BRANCH:
3109 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_length == 2, KLDR_ERR_BAD_FIXUP);
3110 SymAddr -= 4;
3111 break;
3112 case X86_64_RELOC_SIGNED:
3113 case X86_64_RELOC_SIGNED_1:
3114 case X86_64_RELOC_SIGNED_2:
3115 case X86_64_RELOC_SIGNED_4:
3116 SymAddr -= 4;
3117 break;
3118 default:
3119 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP);
3120 }
3121
3122 switch (pSym->n_type & MACHO_N_TYPE)
3123 {
3124 case MACHO_N_SECT:
3125 {
3126 PKLDRMODMACHOSECT pSymSect;
3127 KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3128 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
3129 SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3130 break;
3131 }
3132
3133 case MACHO_N_UNDF:
3134 /* branch to an external symbol may have to take a short detour. */
3135 if ( Fixup.r.r_type == X86_64_RELOC_BRANCH
3136 && SymAddr + Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress
3137 - pSym->n_value
3138 + KU64_C(0x80000000)
3139 >= KU64_C(0xffffff20))
3140 SymAddr += pModMachO->cbJmpStub * Fixup.r.r_symbolnum + pModMachO->JmpStubsRVA + NewBaseAddress;
3141 else
3142 SymAddr += pSym->n_value;
3143 break;
3144
3145 case MACHO_N_ABS:
3146 SymAddr += pSym->n_value;
3147 break;
3148
3149 case MACHO_N_INDR:
3150 case MACHO_N_PBUD:
3151 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO);
3152 default:
3153 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL);
3154 }
3155 break;
3156 }
3157
3158 /*
3159 * This is a weird customer, it will always be follows by an UNSIGNED fixup.
3160 */
3161 case X86_64_RELOC_SUBTRACTOR:
3162 {
3163 macho_relocation_info_t Fixup2;
3164
3165 /* Deal with the SUBTRACT symbol first, by subtracting it from SymAddr. */
3166 switch (pSym->n_type & MACHO_N_TYPE)
3167 {
3168 case MACHO_N_SECT:
3169 {
3170 PKLDRMODMACHOSECT pSymSect;
3171 KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3172 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
3173 SymAddr -= pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3174 break;
3175 }
3176
3177 case MACHO_N_UNDF:
3178 case MACHO_N_ABS:
3179 SymAddr -= pSym->n_value;
3180 break;
3181
3182 case MACHO_N_INDR:
3183 case MACHO_N_PBUD:
3184 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO);
3185 default:
3186 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL);
3187 }
3188
3189 /* Load the 2nd fixup, check sanity. */
3190 iFixup++;
3191 KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel && iFixup < cFixups, KLDR_ERR_BAD_FIXUP);
3192 Fixup2 = paFixups[iFixup];
3193 KLDRMODMACHO_CHECK_RETURN( Fixup2.r_address == Fixup.r.r_address
3194 && Fixup2.r_length == Fixup.r.r_length
3195 && Fixup2.r_type == X86_64_RELOC_UNSIGNED
3196 && !Fixup2.r_pcrel
3197 && Fixup2.r_symbolnum < cSyms,
3198 KLDR_ERR_BAD_FIXUP);
3199
3200 if (Fixup2.r_extern)
3201 {
3202 KLDRMODMACHO_CHECK_RETURN(Fixup2.r_symbolnum < cSyms, KLDR_ERR_BAD_FIXUP);
3203 pSym = &paSyms[Fixup2.r_symbolnum];
3204 KLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), KLDR_ERR_BAD_FIXUP);
3205
3206 /* Add it's value to SymAddr. */
3207 switch (pSym->n_type & MACHO_N_TYPE)
3208 {
3209 case MACHO_N_SECT:
3210 {
3211 PKLDRMODMACHOSECT pSymSect;
3212 KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3213 pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
3214 SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3215 break;
3216 }
3217
3218 case MACHO_N_UNDF:
3219 case MACHO_N_ABS:
3220 SymAddr += pSym->n_value;
3221 break;
3222
3223 case MACHO_N_INDR:
3224 case MACHO_N_PBUD:
3225 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO);
3226 default:
3227 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL);
3228 }
3229 }
3230 else if (Fixup2.r_symbolnum != R_ABS)
3231 {
3232 PKLDRMODMACHOSECT pSymSect;
3233 KLDRMODMACHO_CHECK_RETURN(Fixup2.r_symbolnum <= pModMachO->cSections, KLDR_ERR_BAD_FIXUP);
3234 pSymSect = &pModMachO->paSections[Fixup2.r_symbolnum - 1];
3235 SymAddr += pSymSect->RVA + NewBaseAddress;
3236 }
3237 else
3238 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP);
3239 }
3240 break;
3241 }
3242 }
3243 else
3244 {
3245 /* verify against fixup type and make adjustments */
3246 switch (Fixup.r.r_type)
3247 {
3248 case X86_64_RELOC_UNSIGNED:
3249 KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP);
3250 break;
3251 case X86_64_RELOC_BRANCH:
3252 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP);
3253 SymAddr += 4; /* dunno what the assmbler/linker really is doing here... */
3254 break;
3255 case X86_64_RELOC_SIGNED:
3256 case X86_64_RELOC_SIGNED_1:
3257 case X86_64_RELOC_SIGNED_2:
3258 case X86_64_RELOC_SIGNED_4:
3259 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP);
3260 break;
3261 /*case X86_64_RELOC_GOT_LOAD:*/
3262 /*case X86_64_RELOC_GOT: */
3263 /*case X86_64_RELOC_SUBTRACTOR: - must be r_extern=1 says as. */
3264 default:
3265 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP);
3266 }
3267 if (Fixup.r.r_symbolnum != R_ABS)
3268 {
3269 PKLDRMODMACHOSECT pSymSect;
3270 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_symbolnum <= pModMachO->cSections, KLDR_ERR_BAD_FIXUP);
3271 pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1];
3272
3273 SymAddr -= pSymSect->LinkAddress;
3274 SymAddr += pSymSect->RVA + NewBaseAddress;
3275 if (Fixup.r.r_pcrel)
3276 SymAddr += Fixup.r.r_address;
3277 }
3278 }
3279
3280 /* adjust for PC relative */
3281 if (Fixup.r.r_pcrel)
3282 SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress;
3283
3284 /*
3285 * Write back the fixed up value.
3286 */
3287 switch (Fixup.r.r_length)
3288 {
3289 case 3:
3290 *uFix.pu64 = (KU64)SymAddr;
3291 break;
3292 case 2:
3293 KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel || Fixup.r.r_type == X86_64_RELOC_SUBTRACTOR, KLDR_ERR_BAD_FIXUP);
3294 KLDRMODMACHO_CHECK_RETURN((KI32)SymAddr == (KI64)SymAddr, KLDR_ERR_ADDRESS_OVERFLOW);
3295 *uFix.pu32 = (KU32)SymAddr;
3296 break;
3297 default:
3298 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP);
3299 }
3300 }
3301
3302 return 0;
3303}
3304
3305
3306/**
3307 * Loads the symbol table for a MH_OBJECT file.
3308 *
3309 * The symbol table is pointed to by KLDRMODMACHO::pvaSymbols.
3310 *
3311 * @returns 0 on success, non-zero kLdr status code on failure.
3312 * @param pModMachO The Mach-O module interpreter instance.
3313 */
3314static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO)
3315{
3316 int rc = 0;
3317
3318 if ( !pModMachO->pvaSymbols
3319 && pModMachO->cSymbols)
3320 {
3321 KSIZE cbSyms;
3322 KSIZE cbSym;
3323 void *pvSyms;
3324 void *pvStrings;
3325
3326 /* sanity */
3327 KLDRMODMACHO_CHECK_RETURN( pModMachO->offSymbols
3328 && (!pModMachO->cchStrings || pModMachO->offStrings),
3329 KLDR_ERR_MACHO_BAD_OBJECT_FILE);
3330
3331 /* allocate */
3332 cbSym = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
3333 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
3334 ? sizeof(macho_nlist_32_t)
3335 : sizeof(macho_nlist_64_t);
3336 cbSyms = pModMachO->cSymbols * cbSym;
3337 KLDRMODMACHO_CHECK_RETURN(cbSyms / cbSym == pModMachO->cSymbols, KLDR_ERR_SIZE_OVERFLOW);
3338 rc = KERR_NO_MEMORY;
3339 pvSyms = kHlpAlloc(cbSyms);
3340 if (pvSyms)
3341 {
3342 if (pModMachO->cchStrings)
3343 pvStrings = kHlpAlloc(pModMachO->cchStrings);
3344 else
3345 pvStrings = kHlpAllocZ(4);
3346 if (pvStrings)
3347 {
3348 /* read */
3349 rc = kRdrRead(pModMachO->pMod->pRdr, pvSyms, cbSyms, pModMachO->offSymbols);
3350 if (!rc && pModMachO->cchStrings)
3351 rc = kRdrRead(pModMachO->pMod->pRdr, pvStrings, pModMachO->cchStrings, pModMachO->offStrings);
3352 if (!rc)
3353 {
3354 pModMachO->pvaSymbols = pvSyms;
3355 pModMachO->pchStrings = (char *)pvStrings;
3356
3357 /* perform endian conversion? */
3358 if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
3359 {
3360 KU32 cLeft = pModMachO->cSymbols;
3361 macho_nlist_32_t *pSym = (macho_nlist_32_t *)pvSyms;
3362 while (cLeft-- > 0)
3363 {
3364 pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx);
3365 pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc);
3366 pSym->n_value = K_E2E_U32(pSym->n_value);
3367 pSym++;
3368 }
3369 }
3370 else if (pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
3371 {
3372 KU32 cLeft = pModMachO->cSymbols;
3373 macho_nlist_64_t *pSym = (macho_nlist_64_t *)pvSyms;
3374 while (cLeft-- > 0)
3375 {
3376 pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx);
3377 pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc);
3378 pSym->n_value = K_E2E_U64(pSym->n_value);
3379 pSym++;
3380 }
3381 }
3382
3383 return 0;
3384 }
3385 kHlpFree(pvStrings);
3386 }
3387 kHlpFree(pvSyms);
3388 }
3389 }
3390 else
3391 KLDRMODMACHO_ASSERT(pModMachO->pchStrings || pModMachO->Hdr.filetype == MH_DSYM);
3392
3393 return rc;
3394}
3395
3396
3397/**
3398 * Loads the fixups at the given address and performs endian
3399 * conversion if necessary.
3400 *
3401 * @returns 0 on success, non-zero kLdr status code on failure.
3402 * @param pModMachO The Mach-O module interpreter instance.
3403 * @param offFixups The file offset of the fixups.
3404 * @param cFixups The number of fixups to load.
3405 * @param ppaFixups Where to put the pointer to the allocated fixup array.
3406 */
3407static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups)
3408{
3409 macho_relocation_info_t *paFixups;
3410 KSIZE cbFixups;
3411 int rc;
3412
3413 /* allocate the memory. */
3414 cbFixups = cFixups * sizeof(*paFixups);
3415 KLDRMODMACHO_CHECK_RETURN(cbFixups / sizeof(*paFixups) == cFixups, KLDR_ERR_SIZE_OVERFLOW);
3416 paFixups = (macho_relocation_info_t *)kHlpAlloc(cbFixups);
3417 if (!paFixups)
3418 return KERR_NO_MEMORY;
3419
3420 /* read the fixups. */
3421 rc = kRdrRead(pModMachO->pMod->pRdr, paFixups, cbFixups, offFixups);
3422 if (!rc)
3423 {
3424 *ppaFixups = paFixups;
3425
3426 /* do endian conversion if necessary. */
3427 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
3428 || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
3429 {
3430 KU32 iFixup;
3431 for (iFixup = 0; iFixup < cFixups; iFixup++)
3432 {
3433 KU32 *pu32 = (KU32 *)&paFixups[iFixup];
3434 pu32[0] = K_E2E_U32(pu32[0]);
3435 pu32[1] = K_E2E_U32(pu32[1]);
3436 }
3437 }
3438 }
3439 else
3440 kHlpFree(paFixups);
3441 return rc;
3442}
3443
3444
3445/**
3446 * Maps the virgin file bits into memory if not already done.
3447 *
3448 * @returns 0 on success, non-zero kLdr status code on failure.
3449 * @param pModMachO The Mach-O module interpreter instance.
3450 */
3451static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO)
3452{
3453 int rc = 0;
3454 if (!pModMachO->pvBits)
3455 rc = kRdrAllMap(pModMachO->pMod->pRdr, &pModMachO->pvBits);
3456 return rc;
3457}
3458
3459
3460/** @copydoc kLdrModCallInit */
3461static int kldrModMachOCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle)
3462{
3463 /* later */
3464 K_NOREF(pMod);
3465 K_NOREF(pvMapping);
3466 K_NOREF(uHandle);
3467 return 0;
3468}
3469
3470
3471/** @copydoc kLdrModCallTerm */
3472static int kldrModMachOCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle)
3473{
3474 /* later */
3475 K_NOREF(pMod);
3476 K_NOREF(pvMapping);
3477 K_NOREF(uHandle);
3478 return 0;
3479}
3480
3481
3482/** @copydoc kLdrModCallThread */
3483static int kldrModMachOCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching)
3484{
3485 /* Relevant for Mach-O? */
3486 K_NOREF(pMod);
3487 K_NOREF(pvMapping);
3488 K_NOREF(uHandle);
3489 K_NOREF(fAttachingOrDetaching);
3490 return 0;
3491}
3492
3493
3494/** @copydoc kLdrModSize */
3495static KLDRADDR kldrModMachOSize(PKLDRMOD pMod)
3496{
3497 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
3498 return pModMachO->cbImage;
3499}
3500
3501
3502/** @copydoc kLdrModGetBits */
3503static int kldrModMachOGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
3504{
3505 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
3506 KU32 i;
3507 int rc;
3508
3509 if (!pModMachO->fCanLoad)
3510 return KLDR_ERR_TODO;
3511
3512 /*
3513 * Zero the entire buffer first to simplify things.
3514 */
3515 kHlpMemSet(pvBits, 0, (KSIZE)pModMachO->cbImage);
3516
3517 /*
3518 * When possible use the segment table to load the data.
3519 */
3520 for (i = 0; i < pMod->cSegments; i++)
3521 {
3522 /* skip it? */
3523 if ( pMod->aSegments[i].cbFile == -1
3524 || pMod->aSegments[i].offFile == -1
3525 || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR
3526 || !pMod->aSegments[i].Alignment)
3527 continue;
3528 rc = kRdrRead(pMod->pRdr,
3529 (KU8 *)pvBits + pMod->aSegments[i].RVA,
3530 pMod->aSegments[i].cbFile,
3531 pMod->aSegments[i].offFile);
3532 if (rc)
3533 return rc;
3534 }
3535
3536 /*
3537 * Perform relocations.
3538 */
3539 return kldrModMachORelocateBits(pMod, pvBits, BaseAddress, pModMachO->LinkAddress, pfnGetImport, pvUser);
3540}
3541
3542
3543/** @copydoc kLdrModRelocateBits */
3544static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
3545 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
3546{
3547 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
3548 int rc;
3549 K_NOREF(OldBaseAddress);
3550
3551 /*
3552 * Call workers to do the jobs.
3553 */
3554 if (pModMachO->Hdr.filetype == MH_OBJECT)
3555 {
3556 rc = kldrModMachOObjDoImports(pModMachO, NewBaseAddress, pfnGetImport, pvUser);
3557 if (!rc)
3558 rc = kldrModMachOObjDoFixups(pModMachO, pvBits, NewBaseAddress);
3559
3560 }
3561 else
3562 rc = KLDR_ERR_TODO;
3563 /*{
3564 rc = kldrModMachODoFixups(pModMachO, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser);
3565 if (!rc)
3566 rc = kldrModMachODoImports(pModMachO, pvBits, pfnGetImport, pvUser);
3567 }*/
3568
3569 /*
3570 * Construct the global offset table if necessary, it's always the last
3571 * segment when present.
3572 */
3573 if (!rc && pModMachO->fMakeGot)
3574 rc = kldrModMachOMakeGOT(pModMachO, pvBits, NewBaseAddress);
3575
3576 return rc;
3577}
3578
3579
3580/**
3581 * Builds the GOT.
3582 *
3583 * Assumes the symbol table has all external symbols resolved correctly and that
3584 * the bits has been cleared up front.
3585 */
3586static int kldrModMachOMakeGOT(PKLDRMODMACHO pModMachO, void *pvBits, KLDRADDR NewBaseAddress)
3587{
3588 KU32 iSym = pModMachO->cSymbols;
3589 if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
3590 || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
3591 {
3592 macho_nlist_32_t const *paSyms = (macho_nlist_32_t const *)pModMachO->pvaSymbols;
3593 KU32 *paGOT = (KU32 *)((KU8 *)pvBits + pModMachO->GotRVA);
3594 while (iSym-- > 0)
3595 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
3596 {
3597 case MACHO_N_SECT:
3598 {
3599 PKLDRMODMACHOSECT pSymSect;
3600 KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3601 pSymSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
3602 paGOT[iSym] = (KU32)(paSyms[iSym].n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress);
3603 break;
3604 }
3605
3606 case MACHO_N_UNDF:
3607 case MACHO_N_ABS:
3608 paGOT[iSym] = paSyms[iSym].n_value;
3609 break;
3610 }
3611 }
3612 else
3613 {
3614 macho_nlist_64_t const *paSyms = (macho_nlist_64_t const *)pModMachO->pvaSymbols;
3615 KU64 *paGOT = (KU64 *)((KU8 *)pvBits + pModMachO->GotRVA);
3616 while (iSym-- > 0)
3617 {
3618 switch (paSyms[iSym].n_type & MACHO_N_TYPE)
3619 {
3620 case MACHO_N_SECT:
3621 {
3622 PKLDRMODMACHOSECT pSymSect;
3623 KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL);
3624 pSymSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
3625 paGOT[iSym] = paSyms[iSym].n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
3626 break;
3627 }
3628
3629 case MACHO_N_UNDF:
3630 case MACHO_N_ABS:
3631 paGOT[iSym] = paSyms[iSym].n_value;
3632 break;
3633 }
3634 }
3635
3636 if (pModMachO->JmpStubsRVA != NIL_KLDRADDR)
3637 {
3638 iSym = pModMachO->cSymbols;
3639 switch (pModMachO->Hdr.cputype)
3640 {
3641 /*
3642 * AMD64 is simple since the GOT and the indirect jmps are parallel
3643 * arrays with entries of the same size. The relative offset will
3644 * be the the same for each entry, kind of nice. :-)
3645 */
3646 case CPU_TYPE_X86_64:
3647 {
3648 KU64 *paJmps = (KU64 *)((KU8 *)pvBits + pModMachO->JmpStubsRVA);
3649 KI32 off;
3650 KU64 u64Tmpl;
3651 union
3652 {
3653 KU8 ab[8];
3654 KU64 u64;
3655 } Tmpl;
3656
3657 /* create the template. */
3658 off = (KI32)(pModMachO->GotRVA - (pModMachO->JmpStubsRVA + 6));
3659 Tmpl.ab[0] = 0xff; /* jmp [GOT-entry wrt RIP] */
3660 Tmpl.ab[1] = 0x25;
3661 Tmpl.ab[2] = off & 0xff;
3662 Tmpl.ab[3] = (off >> 8) & 0xff;
3663 Tmpl.ab[4] = (off >> 16) & 0xff;
3664 Tmpl.ab[5] = (off >> 24) & 0xff;
3665 Tmpl.ab[6] = 0xcc;
3666 Tmpl.ab[7] = 0xcc;
3667 u64Tmpl = Tmpl.u64;
3668
3669 /* copy the template to every jmp table entry. */
3670 while (iSym-- > 0)
3671 paJmps[iSym] = u64Tmpl;
3672 break;
3673 }
3674
3675 default:
3676 KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO);
3677 }
3678 }
3679 }
3680 return 0;
3681}
3682
3683
3684/**
3685 * The Mach-O module interpreter method table.
3686 */
3687KLDRMODOPS g_kLdrModMachOOps =
3688{
3689 "Mach-O",
3690 NULL,
3691 kldrModMachOCreate,
3692 kldrModMachODestroy,
3693 kldrModMachOQuerySymbol,
3694 kldrModMachOEnumSymbols,
3695 kldrModMachOGetImport,
3696 kldrModMachONumberOfImports,
3697 NULL /* can execute one is optional */,
3698 kldrModMachOGetStackInfo,
3699 kldrModMachOQueryMainEntrypoint,
3700 kldrModMachOQueryImageUuid,
3701 NULL,
3702 NULL,
3703 kldrModMachOEnumDbgInfo,
3704 kldrModMachOHasDbgInfo,
3705 kldrModMachOMap,
3706 kldrModMachOUnmap,
3707 kldrModMachOAllocTLS,
3708 kldrModMachOFreeTLS,
3709 kldrModMachOReload,
3710 kldrModMachOFixupMapping,
3711 kldrModMachOCallInit,
3712 kldrModMachOCallTerm,
3713 kldrModMachOCallThread,
3714 kldrModMachOSize,
3715 kldrModMachOGetBits,
3716 kldrModMachORelocateBits,
3717 NULL, /** @todo mostly done */
3718 42 /* the end */
3719};
3720
Note: See TracBrowser for help on using the repository browser.