- }
-
-
-
-}
-
-
-template <typename A>
-void Binder<A>::doSetPreboundUndefines()
-{
- const macho_dysymtab_command<P>* dysymtab = NULL;
- macho_nlist<P>* symbolTable = NULL;
-
- // get symbol table info
- const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
- const uint32_t cmd_count = this->fHeader->ncmds();
- const macho_load_command<P>* cmd = cmds;
- for (uint32_t i = 0; i < cmd_count; ++i) {
- switch (cmd->cmd()) {
- case LC_SYMTAB:
- {
- const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
- symbolTable = (macho_nlist<P>*)(&this->fLinkEditBase[symtab->symoff()]);
- }
- break;
- case LC_DYSYMTAB:
- dysymtab = (macho_dysymtab_command<P>*)cmd;
- break;
- }
- cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
- }
-
- // walk all undefines and set their prebound n_value
- macho_nlist<P>* const lastUndefine = &symbolTable[dysymtab->iundefsym()+dysymtab->nundefsym()];
- for (macho_nlist<P>* entry = &symbolTable[dysymtab->iundefsym()]; entry < lastUndefine; ++entry) {
- if ( entry->n_type() & N_EXT ) {
- //fprintf(stderr, "doSetPreboundUndefines: r_sym=%s, pbaddr=0x%08X, in %s\n",
- // &fStrings[entry->n_strx()], pbaddr, this->getDylibID());
- pint_t pbaddr = this->resolveUndefined(entry);
- entry->set_n_value(pbaddr);
- }
- }
-}
-
-
-template <typename A>
-void Binder<A>::doBindExternalRelocations()
-{
- // get where reloc addresses start
- // these address are always relative to first writable segment because they are in cache which always
- // has writable segments far from read-only segments
- pint_t firstWritableSegmentBaseAddress = 0;
- const std::vector<MachOLayoutAbstraction::Segment>& segments = this->fLayout.getSegments();
- for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
- const MachOLayoutAbstraction::Segment& seg = *it;
- if ( seg.writable() ) {
- firstWritableSegmentBaseAddress = seg.newAddress();
- break;
- }
- }
-
- // loop through all external relocation records and bind each
- const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&this->fLinkEditBase[fDynamicInfo->extreloff()]);
- const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicInfo->nextrel()];
- for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
- if ( reloc->r_length() != pointerRelocSize() )
- throw "bad external relocation length";
- if ( reloc->r_type() != pointerRelocType() )
- throw "unknown external relocation type";
- if ( reloc->r_pcrel() )
- throw "r_pcrel external relocaiton not supported";
-
- const macho_nlist<P>* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum()];
- pint_t* location;
- try {
- location = this->mappedAddressForNewAddress(reloc->r_address() + firstWritableSegmentBaseAddress);
- }
- catch (const char* msg) {
- throwf("%s processesing external relocation r_address 0x%08X", msg, reloc->r_address());
- }
- pint_t addend = P::getP(*location);
- if ( fOriginallyPrebound ) {
- // in a prebound binary, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
- // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
- // if mach-o relocation structs had an "addend" field this complication would not be necessary.
- addend -= undefinedSymbol->n_value();
- // To further complicate things, if this is defined symbol, then its n_value has already been adjust to the
- // new base address, so we need to back off the slide too..
- if ( (undefinedSymbol->n_type() & N_TYPE) == N_SECT ) {
- addend += this->getSlideForNewAddress(undefinedSymbol->n_value());
- }
- }
- pint_t symbolAddr = this->resolveUndefined(undefinedSymbol);
- //fprintf(stderr, "external reloc: r_address=0x%08X, r_sym=%s, symAddr=0x%08llX, addend=0x%08llX in %s\n",
- // reloc->r_address(), &fStrings[undefinedSymbol->n_strx()], (uint64_t)symbolAddr, (uint64_t)addend, this->getDylibID());
- P::setP(*location, symbolAddr + addend);
- }
-}
-
-
-// most architectures use pure code, unmodifiable stubs
-template <typename A>
-void Binder<A>::bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value)
-{
- // do nothing
-}
-
-// x86 supports fast stubs
-template <>
-void Binder<x86>::bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value)
-{
- // if the stub is not 5-bytes, it is an old slow stub
- if ( elementSize == 5 ) {
- uint32_t rel32 = value - (vmlocation + 5);
- location[0] = 0xE9; // JMP rel32
- location[1] = rel32 & 0xFF;
- location[2] = (rel32 >> 8) & 0xFF;
- location[3] = (rel32 >> 16) & 0xFF;
- location[4] = (rel32 >> 24) & 0xFF;
- }
-}
-
-template <typename A>
-void Binder<A>::doBindIndirectSymbols()
-{
- const uint32_t* const indirectTable = (uint32_t*)&this->fLinkEditBase[fDynamicInfo->indirectsymoff()];
- const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
- const uint32_t cmd_count = this->fHeader->ncmds();
- const macho_load_command<P>* cmd = cmds;
- //fprintf(stderr, "doBindIndirectSymbols() %s\n", this->fLayout.getFilePath());
- for (uint32_t i = 0; i < cmd_count; ++i) {
- if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
- const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
- const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)seg + sizeof(macho_segment_command<P>));
- const macho_section<P>* const sectionsEnd = §ionsStart[seg->nsects()];
- for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
- uint8_t elementSize = 0;
- uint8_t sectionType = sect->flags() & SECTION_TYPE;
- switch ( sectionType ) {
- case S_SYMBOL_STUBS:
- elementSize = sect->reserved2();
- break;
- case S_NON_LAZY_SYMBOL_POINTERS:
- case S_LAZY_SYMBOL_POINTERS:
- elementSize = sizeof(pint_t);
- break;
- }
- if ( elementSize != 0 ) {
- uint32_t elementCount = sect->size() / elementSize;
- const uint32_t indirectTableOffset = sect->reserved1();
- uint8_t* location = NULL;
- if ( sect->size() != 0 )
- location = (uint8_t*)this->mappedAddressForNewAddress(sect->addr());
- pint_t vmlocation = sect->addr();
- for (uint32_t j=0; j < elementCount; ++j, location += elementSize, vmlocation += elementSize) {
- uint32_t symbolIndex = E::get32(indirectTable[indirectTableOffset + j]);
- switch ( symbolIndex ) {
- case INDIRECT_SYMBOL_ABS:
- case INDIRECT_SYMBOL_LOCAL:
- break;
- default:
- const macho_nlist<P>* undefinedSymbol = &fSymbolTable[symbolIndex];
- //fprintf(stderr, " sect=%s, index=%d, symbolIndex=%d, sym=%s\n", sect->sectname(), j, symbolIndex, &fStrings[undefinedSymbol->n_strx()]);
- pint_t symbolAddr = this->resolveUndefined(undefinedSymbol);
- switch ( sectionType ) {
- case S_NON_LAZY_SYMBOL_POINTERS:
- case S_LAZY_SYMBOL_POINTERS:
- P::setP(*((pint_t*)location), symbolAddr);
- break;
- case S_SYMBOL_STUBS:
- this->bindStub(elementSize, location, vmlocation, symbolAddr);
- break;
- }
- break;
- }
- }
- }
- }
- }
- cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
- }
-}
-
-
-
-
-template <typename A>
-typename A::P::uint_t Binder<A>::resolveUndefined(const macho_nlist<P>* undefinedSymbol)
-{
- if ( (undefinedSymbol->n_type() & N_TYPE) == N_SECT ) {
- if ( (undefinedSymbol->n_type() & N_PEXT) != 0 ) {
- // is a multi-module private_extern internal reference that the linker did not optimize away
- return runtimeAddressFromNList(undefinedSymbol);
- }
- if ( (undefinedSymbol->n_desc() & N_WEAK_DEF) != 0 ) {
- // is a weak definition, we should prebind to this one in the same linkage unit
- return runtimeAddressFromNList(undefinedSymbol);
- }
- }
- const char* symbolName = &fStrings[undefinedSymbol->n_strx()];
- if ( (this->fHeader->flags() & MH_TWOLEVEL) == 0 ) {
- // flat namespace binding
- throw "flat namespace not supported";
- }
- else {
- uint8_t ordinal = GET_LIBRARY_ORDINAL(undefinedSymbol->n_desc());
- Binder<A>* binder = NULL;
- switch ( ordinal ) {
- case EXECUTABLE_ORDINAL:
- case DYNAMIC_LOOKUP_ORDINAL:
- throw "magic ordineal not supported";
- case SELF_LIBRARY_ORDINAL:
- binder = this;
- break;
- default:
- if ( ordinal > fDependentDylibs.size() )
- throw "two-level ordinal out of range";
- binder = fDependentDylibs[ordinal-1].binder;
- }
- pint_t addr;
- bool isResolver;
- bool isAbsolute;
- Binder<A>* foundIn;
- if ( ! binder->findExportedSymbolAddress(symbolName, &addr, &foundIn, &isResolver, &isAbsolute) )
- throwf("could not resolve undefined symbol %s in %s expected in %s", symbolName, this->getDylibID(), binder->getDylibID());
- return addr;