VirtualBox

source: kStuff/trunk/kLdr/kLdrModMachO.c@ 28

Last change on this file since 28 was 28, checked in by bird, 16 years ago

shut up gcc warnings.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette