void MachObject::classicBindExterns()
{
    const uintptr_t relocBase = getClassicRelocBase();

    const relocation_info* const relocsStart =
        (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);

    const relocation_info* const relocsEnd =
        &relocsStart[fDynamicInfo->nextrel];

    for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc)
    {
        if (reloc->r_length == RELOC_SIZE) {
            if (reloc->r_type == POINTER_RELOC)
            {
                const struct nlist* undefinedSymbol = &fSymtab[reloc->r_symbolnum];
                uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
                uintptr_t value = *location;

                if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0) ) {
                    value -= (undefinedSymbol->n_value+1);

                    lnk::halt("weird arm thumb thing detected!");
                }
                else {
                    /* is undefined or non-weak symbol, so do subtraction to get addend */
                    value -= undefinedSymbol->n_value;
                }

                const char* symbolName = &fStrings[undefinedSymbol->n_un.n_strx];
                uint8_t symbolFlags = 0; /* currently unused */
                uint8_t ord = GET_LIBRARY_ORDINAL(undefinedSymbol->n_desc);

                //lnk::log("classicBindExtern: %s, ord: %d:(%s)", symbolName, ord, fDependencies[ord-1]->getShortName());

                /* bind */
                bind((uintptr_t)location,
                     BIND_TYPE_POINTER,
                     symbolName,
                     symbolFlags,
                     value,
                     ord,
                     "extern");
            }
            else
            {
                lnk::halt("unknown reloc type!");
            }
        }
        else
        {
            lnk::halt("bad reloc size!");
        }
    }
}
Exemple #2
0
MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime, uid_t uid)
 : fPath(path), fOffset(offset), fArchPair(0,0), fMTime(modTime), fInode(inode), fHasSplitSegInfo(false), fRootOwned(uid==0),
   fShareableLocation(false), fDynamicLookupLinkage(false), fMainExecutableLookupLinkage(false), fIsDylib(false), 
	fHasDyldInfo(false), fDyldInfoExports(NULL)
{
	fDylibID.name = NULL;
	fDylibID.currentVersion = 0;
	fDylibID.compatibilityVersion = 0;
	bzero(fUUID, sizeof(fUUID));
	
	const macho_header<P>* mh = (const macho_header<P>*)machHeader;
	if ( mh->cputype() != arch() )
		throw "Layout object is wrong architecture";
	switch ( mh->filetype() ) {
		case MH_DYLIB:
			fIsDylib = true;
			break;
		case MH_BUNDLE:
		case MH_EXECUTE:
		case MH_DYLIB_STUB:
		case MH_DYLINKER:
			break;
		default:
			throw "file is not a mach-o final linked image";
	}
	fFlags = mh->flags();
	fFileType = mh->filetype();
	fArchPair.arch = mh->cputype();
	fArchPair.subtype = mh->cpusubtype();
	
	const macho_dyld_info_command<P>* dyldInfo = NULL;
	const macho_symtab_command<P>* symbolTableCmd = NULL;
	const macho_dysymtab_command<P>* dynamicSymbolTableCmd = NULL;
	const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)mh + sizeof(macho_header<P>));
	const uint32_t cmd_count = mh->ncmds();
	const macho_load_command<P>* cmd = cmds;
	for (uint32_t i = 0; i < cmd_count; ++i) {
		switch ( cmd->cmd() ) {
			case LC_ID_DYLIB:	
				{
					macho_dylib_command<P>* dylib  = (macho_dylib_command<P>*)cmd;
					fDylibID.name = strdup(dylib->name());
					fDylibID.currentVersion = dylib->current_version();
					fDylibID.compatibilityVersion = dylib->compatibility_version();
					fNameFileOffset = dylib->name() - (char*)machHeader;
					fShareableLocation = ( (strncmp(fDylibID.name, "/usr/lib/", 9) == 0) || (strncmp(fDylibID.name, "/System/Library/", 16) == 0) );
				}
				break;
			case LC_LOAD_DYLIB:
			case LC_LOAD_WEAK_DYLIB:
			case LC_REEXPORT_DYLIB:
			case LC_LOAD_UPWARD_DYLIB:
				{
					macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
					Library lib;
					lib.name = strdup(dylib->name());
					lib.currentVersion = dylib->current_version();
					lib.compatibilityVersion = dylib->compatibility_version();
					lib.weakImport = ( cmd->cmd() == LC_LOAD_WEAK_DYLIB );
					fLibraries.push_back(lib);
				}
				break;
			case LC_SEGMENT_SPLIT_INFO:
				fHasSplitSegInfo = true;
				break;
			case macho_segment_command<P>::CMD:
				{
					macho_segment_command<P>* segCmd = (macho_segment_command<P>*)cmd;
					fSegments.push_back(Segment(segCmd->vmaddr(), segCmd->vmsize(), segCmd->fileoff(), 
								segCmd->filesize(), segCmd->initprot(), segCmd->segname()));
				}
				break;
			case LC_SYMTAB:
				symbolTableCmd = (macho_symtab_command<P>*)cmd;
				break;
			case LC_DYSYMTAB:
				dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)cmd;
				break;
			case LC_DYLD_INFO:
			case LC_DYLD_INFO_ONLY:
				fHasDyldInfo = true;
				dyldInfo = (struct macho_dyld_info_command<P>*)cmd;
				break;
			case LC_UUID:
				{
					const macho_uuid_command<P>* uc = (macho_uuid_command<P>*)cmd;
					memcpy(&fUUID, uc->uuid(), 16);
				}
				break;
		}
		cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
	}

	fLowSegment = NULL;
	fLowExecutableSegment = NULL;
	fLowWritableSegment = NULL;
	fLowReadOnlySegment = NULL;
	fVMExecutableSize = 0;
	fVMWritablSize = 0;
	fVMReadOnlySize = 0;
	fVMSize = 0;
	const Segment* highSegment = NULL;
	for(std::vector<Segment>::const_iterator it = fSegments.begin(); it != fSegments.end(); ++it) {
		const Segment& seg = *it;
		if ( (fLowSegment == NULL) || (seg.address() < fLowSegment->address()) )
			fLowSegment = &seg;
		if ( (highSegment == NULL) || (seg.address() > highSegment->address()) )
			highSegment = &seg;
		if ( seg.executable() ) {
			if ( (fLowExecutableSegment == NULL) || (seg.address() < fLowExecutableSegment->address()) )
				fLowExecutableSegment = &seg;
			fVMExecutableSize += seg.size();
		}
		else if ( seg.writable()) {
			if ( (fLowWritableSegment == NULL) || (seg.address() < fLowWritableSegment->address()) )
				fLowWritableSegment = &seg;
			fVMWritablSize += seg.size();
		}
		else {
			if ( (fLowReadOnlySegment == NULL) || (seg.address() < fLowReadOnlySegment->address()) )
				fLowReadOnlySegment = &seg;
			fVMReadOnlySize += seg.size();
		}		
	}
	if ( (highSegment != NULL) && (fLowSegment != NULL) )
		fVMSize = (highSegment->address() + highSegment->size() - fLowSegment->address() + 4095) & (-4096);			
	
	// scan undefines looking, for magic ordinals
	if ( (symbolTableCmd != NULL) && (dynamicSymbolTableCmd != NULL) ) {
		const macho_nlist<P>* symbolTable = (macho_nlist<P>*)((uint8_t*)machHeader + symbolTableCmd->symoff());
		const uint32_t startUndefs = dynamicSymbolTableCmd->iundefsym();
		const uint32_t endUndefs = startUndefs + dynamicSymbolTableCmd->nundefsym();
		for (uint32_t i=startUndefs; i < endUndefs; ++i) {
			uint8_t ordinal = GET_LIBRARY_ORDINAL(symbolTable[i].n_desc());
			if ( ordinal == DYNAMIC_LOOKUP_ORDINAL )
				fDynamicLookupLinkage = true;
			else if ( ordinal == EXECUTABLE_ORDINAL )
				fMainExecutableLookupLinkage = true;
		}
	}
	
	if ( dyldInfo != NULL ) {
		if ( dyldInfo->export_off() != 0 ) {
			fDyldInfoExports = (uint8_t*)machHeader + dyldInfo->export_off();
		}
	}

}
void MachObject::classicBindIndirect()
{
    const uint32_t cmd_count = fHeader->ncmds;
    const struct load_command* const cmds = (struct load_command*)(fHeader+1);
    const struct load_command* cmd = cmds;
    const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
    bool bindNonLazys = true;
    bool bindLazys = true;

    for (uint32_t i = 0; i < cmd_count; ++i)
    {
        if (cmd->cmd == LC_SEGMENT_COMMAND) {
            const macho_segment_command* seg =
                (macho_segment_command*)cmd;

            const macho_section* const sectionsStart =
                (macho_section*)((char*)seg + sizeof(macho_segment_command));

            const  macho_section* const sectionsEnd =
                &sectionsStart[seg->nsects];

            for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect)
            {
                bool isLazySymbol = false;
                const uint8_t type = sect->flags & SECTION_TYPE;
                uint32_t elementSize = sizeof(uintptr_t);
                uint32_t elementCount = sect->size / elementSize;

                if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
                    if ( ! bindNonLazys )
                        continue;
                }
                else if ( type == S_LAZY_SYMBOL_POINTERS ) {
                    // process each symbol pointer in this section
                    isLazySymbol = true;
                    if ( ! bindLazys )
                        continue;
                }
                else {
                    continue;
                }

                const uint32_t indirectTableOffset = sect->reserved1;
                uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide);
                for (uint32_t j=0; j < elementCount; ++j, ptrToBind += elementSize) {
                    uint32_t symbolIndex = indirectTable[indirectTableOffset + j];
                    if ( symbolIndex == INDIRECT_SYMBOL_LOCAL) {

                        /* LOCA PEOPLE! */
                        //lnk::log("classicBindIndirect: [local] *%p = %p", ptrToBind, *ptrToBind);

                        *((uintptr_t*)ptrToBind) += this->fSlide;
                    }
                    else if ( symbolIndex == INDIRECT_SYMBOL_ABS) {
                        // do nothing since already has absolute address
                        lnk::halt("ABS!");
                    }
                    else {
                        const struct nlist* sym = &fSymtab[symbolIndex];
                        if ( symbolIndex == 0 ) {
                            lnk::halt("malformed classic image!");
                        }

                        /* actually do stuff */
                        const char* symbolName = &fStrings[sym->n_un.n_strx];
                        uint8_t symbolFlags = 0; /* currently unused */
                        uint8_t ord = GET_LIBRARY_ORDINAL(sym->n_desc);

                        //lnk::log("classicBindIndirect: %s, ord: %d:(%s)", symbolName, ord, fDependencies[ord-1]->getShortName());

                        bind((uintptr_t)ptrToBind,
                             BIND_TYPE_POINTER,
                             symbolName,
                             symbolFlags,
                             0,
                             ord,
                             "indirect");
                    }
                }
            }
        }

        cmd = (const struct load_command*)(((char*)cmd) + cmd->cmdsize);
    }
}