source: trunk/kLdr/kLdrModMachO.c@ 23

Last change on this file since 23 was 23, checked in by bird, 17 years ago

kLdrModMachO.c: (Re-)Make the GOT in the right place, generate indirect GOT jumps and send AMD64 BRANCH fixups there if the displacement is to large, some AMD64 fixup bugfixes.

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