#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/reloc.h>
+#if !KERNEL
+#include <mach-o/swap.h>
+#include <libkern/OSByteOrder.h>
+#endif
#if KERNEL
#include <stdarg.h>
-#include <string.h>
+//#include <string.h>
#include <sys/systm.h>
#define vm_page_size page_size
-extern load_return_t fatfile_getarch(
- void * vp, // normally a (struct vnode *)
- vm_offset_t data_ptr,
- struct fat_arch * archret);
+extern void kld_error_vprintf(const char *format, va_list ap);
__private_extern__ char *strstr(const char *in, const char *str);
+extern struct mach_header _mh_execute_header;
+extern struct segment_command *getsegbyname(char *seg_name); // 32 bit only
#else /* !KERNEL */
} Data, *DataRef;
struct sectionRecord {
- const struct section *fSection;
+ const struct section *fSection; // 32 bit mach object section
DataRef fRelocCache;
};
struct patchRecord {
struct nlist *fSymbol;
+ const struct fileRecord *fFile;
enum patchState fType;
};
DataRef fSym2Strings;
struct symtab_command *fSymtab;
struct sectionRecord *fSections;
+ vm_offset_t fVMAddr, fVMEnd;
struct segment_command *fLinkEditSeg;
const char **fSymbToStringTable;
char *fStringBase;
const struct nlist *fLocalSyms;
unsigned int fNSects;
int fNLocal;
- Boolean fIsKernel, fNoKernelExecutable, fIsKmem;
+ Boolean fIsKernel, fIsReloc, fIsIncrLink, fNoKernelExecutable, fIsKmem;
Boolean fImageDirty, fSymbolsDirty;
Boolean fRemangled, fFoundOSObject;
Boolean fIgnoreFile;
+#if !KERNEL
+ Boolean fSwapped;
+#endif
const char fPath[1];
};
static DataRef sFilesTable;
static struct fileRecord *sKernelFile;
-static DataRef sMergedFiles;
-static DataRef sMergeMetaClasses;
-static Boolean sMergedKernel;
+static DataRef sMergedFiles;
+static DataRef sMergeMetaClasses;
+static Boolean sMergedKernel;
+#if !KERNEL
+static const NXArchInfo * sPreferArchInfo;
+#endif
+static const struct nlist *
+findSymbolByName(struct fileRecord *file, const char *symname);
static void errprintf(const char *fmt, ...)
{
- extern void kld_error_vprintf(const char *format, va_list ap);
-
va_list ap;
va_start(ap, fmt);
unsigned int index;
index = sym - file->fSymbolBase;
+
+ if (index && !sym->n_un.n_strx)
+ return file->fStringBase + sym->n_value;
+
if (index < file->fSymtab->nsyms)
return symNameByIndex(file, index);
close(fd);
return result;
}
+
+void
+kld_set_architecture(const NXArchInfo * arch)
+{
+ sPreferArchInfo = arch;
+}
+
+// This function can only operate on 32 bit mach-o files
+Boolean
+kld_macho_swap(struct mach_header * mh)
+{
+ struct segment_command * seg;
+ struct section * section;
+ CFIndex ncmds, cmd, sect;
+ enum NXByteOrder hostOrder = NXHostByteOrder();
+
+ if (MH_CIGAM != mh->magic)
+ return (false);
+
+ swap_mach_header(mh, hostOrder);
+
+ ncmds = mh->ncmds;
+ seg = (struct segment_command *)(mh + 1);
+ for (cmd = 0;
+ cmd < ncmds;
+ cmd++, seg = (struct segment_command *)(((vm_offset_t)seg) + seg->cmdsize))
+ {
+ if (OSSwapConstInt32(LC_SYMTAB) == seg->cmd) {
+ swap_symtab_command((struct symtab_command *) seg, hostOrder);
+ swap_nlist((struct nlist *) (((vm_offset_t) mh) + ((struct symtab_command *) seg)->symoff),
+ ((struct symtab_command *) seg)->nsyms, hostOrder);
+ continue;
+ }
+ if (OSSwapConstInt32(LC_SEGMENT) != seg->cmd) {
+ swap_load_command((struct load_command *) seg, hostOrder);
+ continue;
+ }
+ swap_segment_command(seg, hostOrder);
+ swap_section((struct section *) (seg + 1), seg->nsects, hostOrder);
+
+ section = (struct section *) (seg + 1);
+ for (sect = 0; sect < seg->nsects; sect++, section++) {
+ if (section->nreloc)
+ swap_relocation_info((struct relocation_info *) (((vm_offset_t) mh) + section->reloff),
+ section->nreloc, hostOrder);
+ }
+ }
+
+ return (true);
+}
+
+// This function can only operate on 32 bit mach-o files
+void
+kld_macho_unswap(struct mach_header * mh, Boolean didSwap, int symbols)
+{
+ // symbols == 0 => everything
+ // symbols == 1 => just nlists
+ // symbols == -1 => everything but nlists
+
+ struct segment_command * seg;
+ struct section * section;
+ unsigned long cmdsize;
+ CFIndex ncmds, cmd, sect;
+ enum NXByteOrder hostOrder = (NXHostByteOrder() == NX_LittleEndian)
+ ? NX_BigEndian : NX_LittleEndian;
+ if (!didSwap)
+ return;
+
+ ncmds = mh->ncmds;
+ seg = (struct segment_command *)(mh + 1);
+ for (cmd = 0;
+ cmd < ncmds;
+ cmd++, seg = (struct segment_command *)(((vm_offset_t)seg) + cmdsize))
+ {
+ cmdsize = seg->cmdsize;
+ if (LC_SYMTAB == seg->cmd) {
+ if (symbols >= 0)
+ swap_nlist((struct nlist *) (((vm_offset_t) mh) + ((struct symtab_command *) seg)->symoff),
+ ((struct symtab_command *) seg)->nsyms, hostOrder);
+ if (symbols > 0)
+ break;
+ swap_symtab_command((struct symtab_command *) seg, hostOrder);
+ continue;
+ }
+ if (symbols > 0)
+ continue;
+ if (LC_SEGMENT != seg->cmd) {
+ swap_load_command((struct load_command *) seg, hostOrder);
+ continue;
+ }
+
+ section = (struct section *) (seg + 1);
+ for (sect = 0; sect < seg->nsects; sect++, section++) {
+ if (section->nreloc)
+ swap_relocation_info((struct relocation_info *) (((vm_offset_t) mh) + section->reloff),
+ section->nreloc, hostOrder);
+ }
+ swap_section((struct section *) (seg + 1), seg->nsects, hostOrder);
+ swap_segment_command(seg, hostOrder);
+ }
+ if (symbols <= 0)
+ swap_mach_header(mh, hostOrder);
+}
+
#endif /* !KERNEL */
+// Note: This functions is only called from kld_file_map()
+// This function can only operate on 32 bit mach-o files
static Boolean findBestArch(struct fileRecord *file, const char *pathName)
{
unsigned long magic;
unsigned long i;
struct fat_arch *arch;
- fat->nfat_arch = NXSwapBigLongToHost(fat->nfat_arch);
+ fat->nfat_arch = OSSwapBigToHostInt32(fat->nfat_arch);
return_if(file->fMapSize < sizeof(struct fat_header)
+ fat->nfat_arch * sizeof(struct fat_arch),
false, ("%s is too fat\n", file->fPath));
arch = (struct fat_arch *) &fat[1];
for (i = 0; i < fat->nfat_arch; i++) {
- arch[i].cputype = NXSwapBigLongToHost(arch[i].cputype);
- arch[i].cpusubtype = NXSwapBigLongToHost(arch[i].cpusubtype);
- arch[i].offset = NXSwapBigLongToHost(arch[i].offset);
- arch[i].size = NXSwapBigLongToHost(arch[i].size);
- arch[i].align = NXSwapBigLongToHost(arch[i].align);
+ arch[i].cputype = OSSwapBigToHostInt32(arch[i].cputype);
+ arch[i].cpusubtype = OSSwapBigToHostInt32(arch[i].cpusubtype);
+ arch[i].offset = OSSwapBigToHostInt32(arch[i].offset);
+ arch[i].size = OSSwapBigToHostInt32(arch[i].size);
+ arch[i].align = OSSwapBigToHostInt32(arch[i].align);
}
- magic = NXSwapBigLongToHost(fat->magic);
+ magic = OSSwapBigToHostInt32(fat->magic);
}
// Now see if we can find any valid architectures
return_if(file->fMapSize < fatsize,
false, ("%s isn't a valid fat file\n", pathName));
- myArch = NXGetLocalArchInfo();
+ if (sPreferArchInfo)
+ myArch = sPreferArchInfo;
+ else
+ myArch = NXGetLocalArchInfo();
+
arch = NXFindBestFatArch(myArch->cputype, myArch->cpusubtype,
(struct fat_arch *) &fat[1], fat->nfat_arch);
return_if(!arch,
magic = ((const struct mach_header *) file->fMachO)->magic;
}
+ file->fSwapped = kld_macho_swap((struct mach_header *) file->fMachO);
+ if (file->fSwapped)
+ magic = ((const struct mach_header *) file->fMachO)->magic;
+
#endif /* KERNEL */
return_if(magic != MH_MAGIC,
return true;
}
+// This function can only operate on segments from 32 bit mach-o files
static Boolean
parseSegments(struct fileRecord *file, struct segment_command *seg)
{
sections = &file->fSections[file->fNSects];
file->fNSects += nsects;
for (i = 0, segMap = (struct segmentMap *) seg; i < nsects; i++)
+ {
sections[i].fSection = &segMap->sect[i];
+ file->fIsReloc |= (0 != segMap->sect[i].nreloc);
+ }
return true;
}
return true;
}
+// This function can only operate on symbol table files from 32 bit
+// mach-o files
static Boolean parseSymtab(struct fileRecord *file, const char *pathName)
{
const struct nlist *sym;
unsigned int i, firstlocal, nsyms;
unsigned long strsize;
const char *strbase;
- Boolean foundOSObject, found295CPP;
+ Boolean foundOSObject, found295CPP, havelocal;
// we found a link edit segment so recompute the bases
if (file->fLinkEditSeg) {
strsize = file->fSymtab->strsize;
strbase = file->fStringBase;
firstlocal = 0;
+ havelocal = false;
found295CPP = foundOSObject = false;
for (i = 0, sym = file->fSymbolBase; i < nsyms; i++, sym++) {
long strx = sym->n_un.n_strx;
return_if(((unsigned long) strx > strsize), false,
("%s has an illegal string offset in symbol %d\n", pathName, i));
+#if 0
+ // Make all syms abs
+ if (file->fIsIncrLink) {
+ if ( (sym->n_type & N_TYPE) == N_SECT) {
+ sym->n_sect = NO_SECT;
+ sym->n_type = (sym->n_type & ~N_TYPE) | N_ABS;
+ }
+ }
+#endif
+
+ if (file->fIsIncrLink && !file->fNSects)
+ {
+ // symbol set
+ struct nlist *patchsym = (struct nlist *) sym;
+ const char * lookname;
+ const struct nlist * realsym;
+
+ if ( (patchsym->n_type & N_TYPE) == N_INDR)
+ lookname = strbase + patchsym->n_value;
+ else
+ lookname = symname;
+ realsym = findSymbolByName(sKernelFile, lookname);
+
+ patchsym->n_sect = NO_SECT;
+ if (realsym)
+ {
+ patchsym->n_type = realsym->n_type;
+ patchsym->n_desc = realsym->n_desc;
+ patchsym->n_value = realsym->n_value;
+ if ((patchsym->n_type & N_TYPE) == N_SECT)
+ patchsym->n_type = (patchsym->n_type & ~N_TYPE) | N_ABS;
+ }
+ else
+ {
+ errprintf("%s: Undefined in symbol set: %s\n", pathName, symname);
+ patchsym->n_type = N_ABS;
+ patchsym->n_desc = 0;
+ patchsym->n_value = patchsym->n_un.n_strx;
+ patchsym->n_un.n_strx = 0;
+ }
+
+ if (!havelocal && (patchsym->n_type & N_EXT)) {
+ firstlocal = i;
+ havelocal = true;
+ file->fLocalSyms = patchsym;
+ }
+ continue;
+ } /* symbol set */
// Load up lookup symbol look table with sym names
file->fSymbToStringTable[i] = symname;
// Find the first exported symbol
if ( !firstlocal && (n_type & N_EXT) ) {
firstlocal = i;
+ havelocal = true;
file->fLocalSyms = sym;
}
// Finally just check if we need to remangle
symname++; // skip leading '__'
while (*symname) {
- if ('_' == *symname++ && '_' == *symname++) {
+ if ('_' == symname[0] && '_' == symname[1]) {
found295CPP = true;
break;
}
+ symname++;
}
}
}
if (!found295CPP) {
symname++; // Skip possible second '_' at start.
while (*symname) {
- if ('_' == *symname++ && '_' == *symname++) {
+ if ('_' == symname[0] && '_' == symname[1]) {
found295CPP = true;
break;
}
+ symname++;
}
}
}
return NULL;
}
+static const struct nlist *
+findSymbolByAddressInAllFiles(__unused const struct fileRecord * fromFile,
+ void *entry, const struct fileRecord **resultFile)
+{
+ int i, nfiles = 0;
+ struct fileRecord **files;
+
+ if (sFilesTable) {
+
+ // Check to see if we have already merged this file
+ nfiles = DataGetLength(sFilesTable) / sizeof(struct fileRecord *);
+ files = (struct fileRecord **) DataGetPtr(sFilesTable);
+ for (i = 0; i < nfiles; i++) {
+ if ((((vm_offset_t)entry) >= files[i]->fVMAddr)
+ && (((vm_offset_t)entry) < files[i]->fVMEnd))
+ {
+ const struct nlist * result;
+ if (resultFile)
+ *resultFile = files[i];
+ result = findSymbolByAddress(files[i], entry);
+ return result;
+ }
+ }
+ }
+
+ return NULL;
+}
+
struct searchContext {
const char *fSymname;
const struct fileRecord *fFile;
const struct searchContext *key = (const struct searchContext *) vKey;
const struct nlist *sym = (const struct nlist *) vSym;
- return strcmp(key->fSymname + 1, symbolname(key->fFile, sym) + 1);
+ return strcmp(key->fSymname, symbolname(key->fFile, sym));
}
static const struct nlist *
int nLocal = file->fNLocal + i;
for (sym = file->fLocalSyms; i < nLocal; i++, sym++)
- if (!strcmp(symNameByIndex(file, i) + 1, symname + 1))
+ if (!strcmp(symNameByIndex(file, i), symname))
return sym;
return NULL;
}
("Invalid relocation entry in %s - local\n", file->fPath));
// Find the symbol, if any, that backs this entry
- symbol = findSymbolByAddress(file, *entry);
+ void * addr = *entry;
+#if !KERNEL
+ if (file->fSwapped)
+ addr = (void *) OSSwapInt32((uint32_t) addr);
+#endif
+ symbol = findSymbolByAddress(file, addr);
}
rec->fValue = *entry; // Save the previous value
static const struct nlist *
findSymbolRefAtLocation(const struct fileRecord *file,
- struct sectionRecord *sctn, void **loc)
+ struct sectionRecord *sctn, void **loc, const struct fileRecord **foundInFile)
{
- if (file->fIsKernel) {
- if (*loc)
- return findSymbolByAddress(file, *loc);
+ const struct nlist * result;
+
+ *foundInFile = file;
+
+ if (!file->fIsReloc) {
+ if (*loc) {
+ void * addr = *loc;
+#if !KERNEL
+ if (file->fSwapped)
+ addr = (void *) OSSwapInt32((uint32_t) addr);
+#endif
+ result = findSymbolByAddress(file, addr);
+ if (!result)
+ result = findSymbolByAddressInAllFiles(file, addr, foundInFile);
+ return result;
+ }
}
else if (sctn->fRelocCache || relocateSection(file, sctn)) {
struct relocRecord *reloc = (struct relocRecord *) *loc;
char strbuffer[1024];
// Only do the work to find the super class if we are
- // not currently working on the kernel. The kernel is the end
+ // not currently working on the kernel. The kernel is the end
// of all superclass chains by definition as the kernel must be binary
// compatible with itself.
- if (!file->fIsKernel) {
+ if (file->fIsReloc) {
const char *suffix;
+ const struct fileRecord *superfile;
const struct nlist *supersym;
const struct section *section;
struct sectionRecord *sectionRec;
section = sectionRec->fSection;
location = (void **) ( file->fMachO + section->offset
+ sym->n_value - section->addr );
-
- supersym = findSymbolRefAtLocation(file, sectionRec, location);
+
+ supersym = findSymbolRefAtLocation(file, sectionRec, location, &superfile);
if (!supersym) {
result = true; // No superclass symbol then it isn't an OSObject.
goto finish;
}
// Find string in file and skip leading '_' and then find the suffix
- superstr = symbolname(file, supersym) + 1;
+ superstr = symbolname(superfile, supersym) + 1;
suffix = superstr + strlen(superstr) - sizeof(kGMetaSuffix) + 1;
if (suffix <= superstr || strcmp(suffix, kGMetaSuffix)) {
result = true; // Not an OSObject superclass so ignore it..
("Unable to allocate memory metaclass list\n", file->fPath));
}
else { /* perform a duplicate check */
- int i, j, cnt1, cnt2;
+ int k, j, cnt1, cnt2;
struct metaClassRecord **list1, **list2;
list1 = (struct metaClassRecord **) DataGetPtr(file->fClassList);
list2 = (struct metaClassRecord **) DataGetPtr(sMergeMetaClasses);
cnt2 = DataGetLength(sMergeMetaClasses) / sizeof(*list2);
- for (i = 0; i < cnt1; i++) {
+ for (k = 0; k < cnt1; k++) {
for (j = 0; j < cnt2; j++) {
- if (!strcmp(list1[i]->fClassName, list2[j]->fClassName)) {
+ if (!strcmp(list1[k]->fClassName, list2[j]->fClassName)) {
errprintf("duplicate class %s in %s & %s\n",
- list1[i]->fClassName,
+ list1[k]->fClassName,
file->fPath, list2[j]->fFile->fPath);
}
}
unsigned char *base;
sectind = symb->n_sect; // Default to symbols section
- if ((symb->n_type & N_TYPE) == N_ABS && file->fIsKernel) {
+ if ((symb->n_type & N_TYPE) == N_ABS && !file->fIsReloc) {
// Absolute symbol so we have to iterate over our sections
for (sectind = 1; sectind <= file->fNSects; sectind++) {
unsigned long start, end;
// however we don't need to check the superclass in the kernel
// as the kernel vtables are always correct wrt themselves.
// Note this ends the superclass chain recursion.
- return_if(!file->fIsKernel,
- false, ("Internal error - resolveKernelVTable not kernel\n"));
+ return_if(file->fIsReloc,
+ false, ("Internal error - resolveKernelVTable is relocateable\n"));
if (file->fNoKernelExecutable) {
// Oh dear attempt to map the kernel's VM into my memory space
curPatch = patchedVTable;
curEntry = vtableEntries + kVTablePreambleLen;
for (; *curEntry; curEntry++, curPatch++) {
+ void * addr = *curEntry;
+#if !KERNEL
+ if (file->fSwapped)
+ addr = (void *) OSSwapInt32((uint32_t) addr);
+#endif
curPatch->fSymbol = (struct nlist *)
- findSymbolByAddress(file, *curEntry);
- curPatch->fType = kSymbolLocal;
+ findSymbolByAddress(file, addr);
+ if (curPatch->fSymbol)
+ {
+ curPatch->fType = kSymbolLocal;
+ curPatch->fFile = file;
+ }
+ else
+ {
+ curPatch->fSymbol = (struct nlist *)
+ findSymbolByAddressInAllFiles(file, addr, &curPatch->fFile);
+ if (!curPatch->fSymbol) {
+ errprintf("%s: !findSymbolByAddressInAllFiles(%p)\n",
+ file->fPath, addr);
+ return false;
+ }
+ curPatch->fType = kSymbolLocal;
+ }
}
// Tag the end of the patch vtable
}
}
- // Assert that this is a vaild symbol. I need this condition to be true
- // for the later code to make non-zero. So the first time through I'd
- // better make sure that it is 0.
- return_if(reloc->fSymbol->n_sect, NULL,
- ("Undefined symbol entry with non-zero section %s:%s\n",
- file->fPath, symbolname(file, reloc->fSymbol)));
+ if (reloc->fSymbol->n_un.n_strx >= 0) {
+ // This symbol has not been previously processed, so assert that it
+ // is a valid non-local symbol. I need this condition to be true for
+ // the later code to set to -1. Now, being the first time through,
+ // I'd better make sure that n_sect is NO_SECT.
+
+ return_if(reloc->fSymbol->n_sect != NO_SECT, NULL,
+ ("Undefined symbol entry with non-zero section %s:%s\n",
+ file->fPath, symbolname(file, reloc->fSymbol)));
+
+ // Mark the original symbol entry as having been processed.
+ // This means that we wont attempt to create the symbol again
+ // in the future if we come through a different path.
+ ((struct nlist *) reloc->fSymbol)->n_un.n_strx =
+ -reloc->fSymbol->n_un.n_strx;
+
+ // Mark the old symbol as being potentially deletable I can use the
+ // n_sect field as the input symbol must be of type N_UNDF which means
+ // that the n_sect field must be set to NO_SECT otherwise it is an
+ // invalid input file.
+ ((struct nlist *) reloc->fSymbol)->n_sect = (unsigned char) -1;
+ }
// If we are here we didn't find the symbol so create a new one now
msym = (struct nlist *) malloc(sizeof(struct nlist));
newStr = addNewString(file, supername, strlen(supername));
if (!newStr)
return NULL;
+
// If we are here we didn't find the symbol so create a new one now
return_if(!DataAppendBytes(file->fSym2Strings, &newStr, sizeof(newStr)),
NULL, ("Unable to grow symbol table for %s\n", file->fPath));
msym->n_desc = 0;
msym->n_value = (unsigned long) newStr;
- // Mark the old symbol as being potentially deletable I can use the
- // n_sect field as the input symbol must be of type N_UNDF which means
- // that the n_sect field must be set to NO_SECT otherwise it is an
- // invalid input file.
- //
- // However the symbol may have been just inserted by the fixOldSymbol path.
- // If this is the case then we know it is in use and we don't have to
- // mark it as a deletable symbol.
- if (reloc->fSymbol->n_un.n_strx >= 0) {
- ((struct nlist *) reloc->fSymbol)->n_un.n_strx
- = -reloc->fSymbol->n_un.n_strx;
- ((struct nlist *) reloc->fSymbol)->n_sect = (unsigned char) -1;
- }
-
rinfo->r_symbolnum = i + file->fSymtab->nsyms;
file->fSymbolsDirty = true;
return msym;
file = metaClass->fFile;
- // If the metaClass we are being to ask is in the kernel then we
- // need to do a quick scan to grab the fPatchList in a reliable format
- // however we don't need to check the superclass in the kernel
- // as the kernel vtables are always correct wrt themselves.
- // Note this ends the superclass chain recursion.
- return_if(file->fIsKernel,
- false, ("Internal error - patchVTable shouldn't used for kernel\n"));
+ if (!file->fIsReloc)
+ {
+ // If the metaClass we are being to ask is already relocated then we
+ // need to do a quick scan to grab the fPatchList in a reliable format
+ // however we don't need to check the superclass in the already linked
+ // modules as the vtables are always correct wrt themselves.
+ // Note this ends the superclass chain recursion.
+ Boolean res;
+ res = resolveKernelVTable(metaClass);
+ return res;
+ }
if (!metaClass->fSuperName)
return false;
// Superclass recursion if necessary
if (!super->fPatchedVTable) {
Boolean res;
-
- if (super->fFile->fIsKernel)
- res = resolveKernelVTable(super);
- else
- res = patchVTable(super);
+ res = patchVTable(super);
if (!res)
return false;
}
for ( ; spp->fSymbol; curReloc++, spp++, curPatch++) {
const char *supername =
- symbolname(super->fFile, spp->fSymbol);
+ symbolname(spp->fFile, spp->fSymbol);
symbol = (struct nlist *) (*curReloc)->fSymbol;
if (symbol) {
curPatch->fSymbol = symbol;
(*curReloc)->fSymbol = symbol;
+ curPatch->fFile = file;
}
else
goto abortPatch;
// Local reloc symbols
curPatch->fType = kSymbolLocal;
curPatch->fSymbol = (struct nlist *) (*curReloc)->fSymbol;
+ curPatch->fFile = file;
}
// Tag the end of the patch vtable
endMap = (vm_address_t) file->fMap + file->fMapSize;
// Do we have room in the current mapped image
- if (endMachO < round_page(endMap)) {
+ if (endMachO < round_page_32(endMap)) {
file->fMachOSize += delta;
return true;
}
newsize = endMachO - startMachO;
- if (newsize < round_page(file->fMapSize)) {
+ if (newsize < round_page_32(file->fMapSize)) {
DEBUG_LOG(("Growing image %s by moving\n", file->fPath));
// We have room in the map if we shift the macho image within the
#endif /* KERNEL */
}
+// Note: This function is only called from kld_file_prepare_for_link()
+// This function can only operate on 32 bit mach-o files
static Boolean
prepareFileForLink(struct fileRecord *file)
{
// If we didn't even do a pseudo 'relocate' and dirty the image
// then we can just return now.
- if (!file->fImageDirty)
+ if (!file->fImageDirty) {
+#if !KERNEL
+ if (file->fSwapped) {
+ kld_macho_unswap((struct mach_header *) file->fMachO, file->fSwapped, false);
+ file->fSwapped = false;
+ }
+#endif
return true;
+ }
DEBUG_LOG(("Linking 2 %s\n", file->fPath)); // @@@ gvdl:
// We will need to repair the reloc list
for (j = 0; j < nreloc; j++, rec++) {
void **entry;
- struct nlist *sym;
+ struct nlist *repairSym;
// Repair Damage to object image
entry = (void **) (sectionBase + rec->fRInfo->r_address);
// Check if the symbol that this relocation entry points
// to is marked as erasable
- sym = (struct nlist *) rec->fSymbol;
- if (sym && sym->n_type == (N_EXT | N_UNDF)
- && sym->n_sect == (unsigned char) -1) {
+ repairSym = (struct nlist *) rec->fSymbol;
+ if (repairSym && repairSym->n_type == (N_EXT | N_UNDF)
+ && repairSym->n_sect == (unsigned char) -1) {
// It is in use so we better clear the mark
- sym->n_un.n_strx = -sym->n_un.n_strx;
- sym->n_sect = NO_SECT;
+ repairSym->n_un.n_strx = -repairSym->n_un.n_strx;
+ repairSym->n_sect = NO_SECT;
}
}
file->fImageDirty = false; // Image is clean
// If we didn't dirty the symbol table then just return
- if (!file->fSymbolsDirty)
+ if (!file->fSymbolsDirty) {
+#if !KERNEL
+ if (file->fSwapped) {
+ kld_macho_unswap((struct mach_header *) file->fMachO, file->fSwapped, false);
+ file->fSwapped = false;
+ }
+#endif
return true;
+ }
// calculate total file size increase and check against padding
if (file->fNewSymbols) {
}
// Don't need the new strings any more
- last = DataGetLength(file->fNewStringBlocks) / sizeof(DataRef);
- stringBlocks = (DataRef *) DataGetPtr(file->fNewStringBlocks);
+
+ if (file->fNewStringBlocks){
+ last = DataGetLength(file->fNewStringBlocks) / sizeof(DataRef);
+ stringBlocks = (DataRef *) DataGetPtr(file->fNewStringBlocks);
+ }
+ else{
+ last =0;
+ stringBlocks=0;
+ }
+
for (i = 0; i < last; i++)
DataRelease(stringBlocks[i]);
}
file->fSymbolsDirty = false;
-
+#if !KERNEL
+ if (file->fSwapped) {
+ kld_macho_unswap((struct mach_header *) file->fMachO, file->fSwapped, false);
+ file->fSwapped = false;
+ }
+#endif
return true;
}
+// This function can only operate on 32 bit mach-o files
Boolean
#if KERNEL
kld_file_map(const char *pathName,
struct load_command c[1];
} *machO;
const struct load_command *cmd;
- int i;
+ boolean_t lookVMRange;
+ unsigned long i;
if (!findBestArch(&file, pathName))
break;
if (file.fMachOSize < machO->h.sizeofcmds)
break;
- file.fIsKernel = (MH_EXECUTE == machO->h.filetype);
-
// If the file type is MH_EXECUTE then this must be a kernel
// as all Kernel extensions must be of type MH_OBJECT
- for (i = 0, cmd = &machO->c[0]; i < machO->h.ncmds; i++) {
+ file.fIsKernel = (MH_EXECUTE == machO->h.filetype);
+
+ for (i = 0, cmd = &machO->c[0], lookVMRange = true; i < machO->h.ncmds; i++) {
if (cmd->cmd == LC_SYMTAB)
file.fSymtab = (struct symtab_command *) cmd;
else if (cmd->cmd == LC_SEGMENT) {
struct segment_command *seg = (struct segment_command *) cmd;
int nsects = seg->nsects;
+ if (lookVMRange) {
+ if (!strcmp("__PRELINK", seg->segname))
+ // segments following __PRELINK are going to move, so ignore them
+ lookVMRange = false;
+ else if (!file.fVMAddr && !file.fVMEnd) {
+ file.fVMAddr = seg->vmaddr;
+ file.fVMEnd = seg->vmaddr + seg->vmsize;
+ } else {
+ if (seg->vmaddr < file.fVMAddr)
+ file.fVMAddr = seg->vmaddr;
+ if ((seg->vmaddr + seg->vmsize) > file.fVMEnd)
+ file.fVMEnd = seg->vmaddr + seg->vmsize;
+ }
+ }
+
if (nsects)
return_if(!parseSegments(&file, seg),
false, ("%s isn't a valid mach-o, bad segment",
pathName));
- else if (file.fIsKernel) {
+
+ if (file.fIsKernel) {
#if KERNEL
// We don't need to look for the LinkEdit segment unless
// we are running in the kernel environment.
#endif
}
}
-
cmd = (struct load_command *) ((UInt8 *) cmd + cmd->cmdsize);
}
break_if(!file.fSymtab,
("%s isn't a valid mach-o, no symbols\n", pathName));
+ if (machO->h.flags & MH_INCRLINK) {
+
+ file.fIsIncrLink = true;
+ ((struct machOMapping *) machO)->h.flags &= ~MH_INCRLINK;
+
+#if !KERNEL
+ // the symtab fileoffset is the end of seg0's vmsize,
+ // which can be (rarely) unaligned.
+ unsigned int
+ align = file.fSymtab->symoff % sizeof(long);
+ if (align != 0) {
+ align = sizeof(long) - align;
+ growImage(&file, align);
+ bcopy(file.fMachO + file.fSymtab->symoff,
+ file.fMachO + file.fSymtab->symoff + align,
+ file.fSymtab->stroff + file.fSymtab->strsize - file.fSymtab->symoff);
+ file.fSymtab->symoff += align;
+ file.fSymtab->stroff += align;
+ }
+#endif
+ }
+
if (!parseSymtab(&file, pathName))
break;
// Automatically load the kernel's link edit segment if we are
// attempting to load a driver.
if (!sKernelFile) {
- extern struct mach_header _mh_execute_header;
- extern struct segment_command *getsegbyname(char *seg_name);
-
struct segment_command *sg;
size_t kernelSize;
Boolean ret;
return true;
}
-Boolean kld_file_prepare_for_link()
+Boolean kld_file_prepare_for_link(void)
{
if (sMergedFiles) {
unsigned long i, nmerged = 0;
return true;
}
-void kld_file_cleanup_all_resources()
+void kld_file_cleanup_all_resources(void)
{
unsigned long i, nfiles;