X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/a645023da60d22e86be13f7b4d97adeff8bc6665..afe874b1634377ecb27057ee76deb04915bb34d7:/src/ld/OutputFile.cpp diff --git a/src/ld/OutputFile.cpp b/src/ld/OutputFile.cpp index bb368c2..65e8b8c 100644 --- a/src/ld/OutputFile.cpp +++ b/src/ld/OutputFile.cpp @@ -1,6 +1,6 @@ /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-* * - * Copyright (c) 2009-2010 Apple Inc. All rights reserved. + * Copyright (c) 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -320,10 +320,25 @@ void OutputFile::setSectionSizesAndAlignments(ld::Internal& state) uint64_t offset = 0; for (std::vector::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { const ld::Atom* atom = *ait; - if ( atom->alignment().powerOf2 > maxAlignment ) - maxAlignment = atom->alignment().powerOf2; + bool pagePerAtom = false; + uint32_t atomAlignmentPowerOf2 = atom->alignment().powerOf2; + if ( _options.pageAlignDataAtoms() && ( strcmp(atom->section().segmentName(), "__DATA") == 0) ) { + switch ( atom->section().type() ) { + case ld::Section::typeUnclassified: + case ld::Section::typeTentativeDefs: + case ld::Section::typeZeroFill: + pagePerAtom = true; + if ( atomAlignmentPowerOf2 < 12 ) + atomAlignmentPowerOf2 = 12; + break; + default: + break; + } + } + if ( atomAlignmentPowerOf2 > maxAlignment ) + maxAlignment = atomAlignmentPowerOf2; // calculate section offset for this atom - uint64_t alignment = 1 << atom->alignment().powerOf2; + uint64_t alignment = 1 << atomAlignmentPowerOf2; uint64_t currentModulus = (offset % alignment); uint64_t requiredModulus = atom->alignment().modulus; if ( currentModulus != requiredModulus ) { @@ -336,6 +351,9 @@ void OutputFile::setSectionSizesAndAlignments(ld::Internal& state) if ( sect->type() != ld::Section::typeLinkEdit ) { (const_cast(atom))->setSectionOffset(offset); offset += atom->size(); + if ( pagePerAtom ) { + offset = (offset + 4095) & (-4096); // round up to end of page + } } if ( (atom->scope() == ld::Atom::scopeGlobal) && (atom->definition() == ld::Atom::definitionRegular) @@ -581,7 +599,7 @@ void OutputFile::assignFileOffsets(ld::Internal& state) for (std::vector::iterator it = state.sections.begin(); it != state.sections.end(); ++it) { ld::Internal::FinalSection* sect = *it; if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) { - _encryptedTEXTendOffset = pageAlign(sect->fileOffset); + _encryptedTEXTendOffset = pageAlign(sect->fileOffset + sect->size); } } } @@ -779,10 +797,43 @@ void OutputFile::rangeCheckBranch32(int64_t displacement, ld::Internal& state, c } } + +void OutputFile::rangeCheckAbsolute32(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup) +{ + const int64_t fourGigLimit = 0xFFFFFFFF; + if ( displacement > fourGigLimit ) { + // cannot enforce 32-bit range checks on 32-bit archs because assembler loses sign information + // .long _foo - 0xC0000000 + // is encoded in mach-o the same as: + // .long _foo + 0x40000000 + // so if _foo lays out to 0xC0000100, the first is ok, but the second is not. + if ( (_options.architecture() == CPU_TYPE_ARM) || (_options.architecture() == CPU_TYPE_I386) ) { + // Unlikely userland code does funky stuff like this, so warn for them, but not warn for -preload + if ( _options.outputKind() != Options::kPreload ) { + warning("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to 0x%08llX", + displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), displacement); + } + return; + } + // show layout of final image + printSectionLayout(state); + + const ld::Atom* target; + if ( fixup->binding == ld::Fixup::bindingNone ) + throwf("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to 0x%08llX", + displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), displacement); + else + throwf("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to %s (0x%08llX)", + displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), referenceTargetAtomName(state, fixup), + addressOf(state, fixup, &target)); + } +} + + void OutputFile::rangeCheckRIP32(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup) { const int64_t twoGigLimit = 0x7FFFFFFF; - if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) { + if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) { // show layout of final image printSectionLayout(state); @@ -822,8 +873,8 @@ void OutputFile::rangeCheckARMBranch24(int64_t displacement, ld::Internal& state void OutputFile::rangeCheckThumbBranch22(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup) { - // armv7 supports a larger displacement - if ( _options.preferSubArchitecture() && (_options.subArchitecture() == CPU_SUBTYPE_ARM_V7) ) { + // thumb2 supports a larger displacement + if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) { if ( (displacement > 16777214LL) || (displacement < (-16777216LL)) ) { // show layout of final image printSectionLayout(state); @@ -967,6 +1018,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld:: set32LE(fixUpLocation, (get32LE(fixUpLocation) & 0xFF000000) | (accumulator & 0x00FFFFFF) ); break; case ld::Fixup::kindStoreLittleEndian32: + rangeCheckAbsolute32(accumulator, state, atom, fit); set32LE(fixUpLocation, accumulator); break; case ld::Fixup::kindStoreLittleEndian64: @@ -979,6 +1031,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld:: set32BE(fixUpLocation, (get32BE(fixUpLocation) & 0xFF000000) | (accumulator & 0x00FFFFFF) ); break; case ld::Fixup::kindStoreBigEndian32: + rangeCheckAbsolute32(accumulator, state, atom, fit); set32BE(fixUpLocation, accumulator); break; case ld::Fixup::kindStoreBigEndian64: @@ -1198,6 +1251,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld:: accumulator |= 1; if ( fit->contentAddendOnly ) accumulator = 0; + rangeCheckAbsolute32(accumulator, state, atom, fit); set32LE(fixUpLocation, accumulator); break; case ld::Fixup::kindStoreTargetAddressLittleEndian64: @@ -1287,6 +1341,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld:: // Make sure we are calling arm with bl, thumb with blx is_bl = ((instruction & 0xFF000000) == 0xEB000000); is_blx = ((instruction & 0xFE000000) == 0xFA000000); + is_b = !is_blx && ((instruction & 0x0F000000) == 0x0A000000); if ( is_bl && thumbTarget ) { uint32_t opcode = 0xFA000000; uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF; @@ -1298,6 +1353,13 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld:: uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF; newInstruction = opcode | disp; } + else if ( is_b && thumbTarget ) { + if ( fit->contentDetlaToAddendOnly ) + newInstruction = (instruction & 0xFF000000) | ((uint32_t)(delta >> 2) & 0x00FFFFFF); + else + throwf("no pc-rel bx arm instruction. Can't fix up branch to %s in %s", + referenceTargetAtomName(state, fit), atom->name()); + } else if ( !is_bl && !is_blx && thumbTarget ) { throwf("don't know how to convert instruction %x referencing %s to thumb", instruction, referenceTargetAtomName(state, fit)); @@ -1324,14 +1386,14 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld:: // Since blx cannot have the low bit set, set bit[1] of the target to // bit[1] of the base address, so that the difference is a multiple of // 4 bytes. - if ( !thumbTarget ) { + if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) { accumulator &= -3ULL; accumulator |= ((atom->finalAddress() + fit->offsetInAtom ) & 2LL); } // The pc added will be +4 from the pc delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4); rangeCheckThumbBranch22(delta, state, atom, fit); - if ( _options.preferSubArchitecture() && _options.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) { + if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) { // The instruction is really two instructions: // The lower 16 bits are the first instruction, which contains the high // 11 bits of the displacement. @@ -1357,12 +1419,13 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld:: instruction = 0xC000F000; // keep blx } else if ( is_b ) { - if ( !thumbTarget ) - throwf("don't know how to convert instruction %x referencing %s to arm", - instruction, referenceTargetAtomName(state, fit)); instruction = 0x9000F000; // keep b + if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) { + throwf("armv7 has no pc-rel bx thumb instruction. Can't fix up branch to %s in %s", + referenceTargetAtomName(state, fit), atom->name()); + } } - else if ( is_b ) { + else { if ( !thumbTarget ) throwf("don't know how to convert branch instruction %x referencing %s to bx", instruction, referenceTargetAtomName(state, fit)); @@ -1389,10 +1452,13 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld:: else if ( is_blx && thumbTarget ) { instruction = 0xF800F000; } - else if ( !is_bl && !is_blx && !thumbTarget ) { - throwf("don't know how to convert instruction %x referencing %s to arm", - instruction, referenceTargetAtomName(state, fit)); - } + else if ( is_b ) { + instruction = 0x9000F000; // keep b + if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) { + throwf("armv6 has no pc-rel bx thumb instruction. Can't fix up branch to %s in %s", + referenceTargetAtomName(state, fit), atom->name()); + } + } else { instruction = instruction & 0xF800F800; } @@ -1456,7 +1522,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld:: } } -void OutputFile::copyNoOps(uint8_t* from, uint8_t* to) +void OutputFile::copyNoOps(uint8_t* from, uint8_t* to, bool thumb) { switch ( _options.architecture() ) { case CPU_TYPE_POWERPC: @@ -1469,9 +1535,14 @@ void OutputFile::copyNoOps(uint8_t* from, uint8_t* to) *p = 0x90; break; case CPU_TYPE_ARM: - // fixme: need thumb nop? - for (uint8_t* p=from; p < to; p += 4) - OSWriteBigInt32((uint32_t*)p, 0, 0xe1a00000); + if ( thumb ) { + for (uint8_t* p=from; p < to; p += 2) + OSWriteLittleInt16((uint16_t*)p, 0, 0x46c0); + } + else { + for (uint8_t* p=from; p < to; p += 4) + OSWriteLittleInt32((uint32_t*)p, 0, 0xe1a00000); + } break; default: for (uint8_t* p=from; p < to; ++p) @@ -1555,6 +1626,7 @@ void OutputFile::writeOutputFile(ld::Internal& state) const bool sectionUsesNops = (sect->type() == ld::Section::typeCode); //fprintf(stderr, "file offset=0x%08llX, section %s\n", sect->fileOffset, sect->sectionName()); std::vector& atoms = sect->atoms; + bool lastAtomWasThumb = false; for (std::vector::iterator ait = atoms.begin(); ait != atoms.end(); ++ait) { const ld::Atom* atom = *ait; if ( atom->definition() == ld::Atom::definitionProxy ) @@ -1563,7 +1635,7 @@ void OutputFile::writeOutputFile(ld::Internal& state) uint64_t fileOffset = atom->finalAddress() - sect->address + sect->fileOffset; // check for alignment padding between atoms if ( (fileOffset != fileOffsetOfEndOfLastAtom) && lastAtomUsesNoOps ) { - this->copyNoOps(&wholeBuffer[fileOffsetOfEndOfLastAtom], &wholeBuffer[fileOffset]); + this->copyNoOps(&wholeBuffer[fileOffsetOfEndOfLastAtom], &wholeBuffer[fileOffset], lastAtomWasThumb); } // copy atom content atom->copyRawContent(&wholeBuffer[fileOffset]); @@ -1571,6 +1643,7 @@ void OutputFile::writeOutputFile(ld::Internal& state) this->applyFixUps(state, mhAddress, atom, &wholeBuffer[fileOffset]); fileOffsetOfEndOfLastAtom = fileOffset+atom->size(); lastAtomUsesNoOps = sectionUsesNops; + lastAtomWasThumb = atom->isThumb(); } catch (const char* msg) { if ( atom->file() != NULL ) @@ -1658,6 +1731,19 @@ struct AtomByNameSorter } }; +class NotInSet +{ +public: + NotInSet(const std::set& theSet) : _set(theSet) {} + + bool operator()(const ld::Atom* atom) const { + return ( _set.count(atom) == 0 ); + } +private: + const std::set& _set; +}; + + void OutputFile::buildSymbolTable(ld::Internal& state) { unsigned int machoSectionIndex = 0; @@ -1800,7 +1886,11 @@ void OutputFile::buildSymbolTable(ld::Internal& state) } } else { - if ( _options.keepLocalSymbol(atom->name()) ) + if ( _options.keepLocalSymbol(atom->name()) ) + _localAtoms.push_back(atom); + // ld should never have a symbol in the non-lazy indirect symbol table with index 0 + // this works by making __mh_execute_header be a local symbol which takes symbol index 0 + else if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip) && !_options.makeCompressedDyldInfo() ) _localAtoms.push_back(atom); else (const_cast(atom))->setSymbolTableInclusion(ld::Atom::symbolTableNotIn); @@ -1810,10 +1900,35 @@ void OutputFile::buildSymbolTable(ld::Internal& state) } } + // ld adds undefined symbol from .exp file to binary + if ( (_options.outputKind() == Options::kKextBundle) && _options.hasExportRestrictList() ) { + // search for referenced undefines + std::set referencedProxyAtoms; + for (std::vector::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) { + ld::Internal::FinalSection* sect = *sit; + for (std::vector::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { + const ld::Atom* atom = *ait; + for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) { + switch ( fit->binding ) { + case ld::Fixup::bindingsIndirectlyBound: + referencedProxyAtoms.insert(state.indirectBindingTable[fit->u.bindingIndex]); + break; + case ld::Fixup::bindingDirectlyBound: + referencedProxyAtoms.insert(fit->u.target); + break; + default: + break; + } + } + } + } + // remove any unreferenced _importedAtoms + _importedAtoms.erase(std::remove_if(_importedAtoms.begin(), _importedAtoms.end(), NotInSet(referencedProxyAtoms)), _importedAtoms.end()); + } + // sort by name std::sort(_exportedAtoms.begin(), _exportedAtoms.end(), AtomByNameSorter()); std::sort(_importedAtoms.begin(), _importedAtoms.end(), AtomByNameSorter()); - } void OutputFile::addPreloadLinkEdit(ld::Internal& state) @@ -2583,7 +2698,7 @@ void OutputFile::noteTextReloc(const ld::Atom* atom, const ld::Atom* target) if ( _options.warnAboutTextRelocs() ) warning("text reloc in %s to %s", atom->name(), target->name()); } - else if ( _options.positionIndependentExecutable() && (_options.iphoneOSVersionMin() >= ld::iPhone4_3) ) { + else if ( _options.positionIndependentExecutable() && ((_options.iOSVersionMin() >= ld::iOS_4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) { if ( ! this->pieDisabled ) { warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, " "but used in %s from %s. " @@ -2592,8 +2707,11 @@ void OutputFile::noteTextReloc(const ld::Atom* atom, const ld::Atom* target) } this->pieDisabled = true; } + else if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) ) { + throwf("illegal text-relocoation (direct reference) to (global,weak) %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path()); + } else { - throwf("illegal text reloc to %s from %s in %s", target->name(), target->file()->path(), atom->name()); + throwf("illegal text-relocation to %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path()); } } @@ -2608,8 +2726,22 @@ void OutputFile::addDyldInfo(ld::Internal& state, ld::Internal::FinalSection* s // no need to rebase or bind PCRel stores if ( this->isPcRelStore(fixupWithStore->kind) ) { // as long as target is in same linkage unit - if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) ) + if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) ) { + // make sure target is not global and weak + if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular)) { + if ( (atom->section().type() == ld::Section::typeCFI) + || (atom->section().type() == ld::Section::typeDtraceDOF) + || (atom->section().type() == ld::Section::typeUnwindInfo) ) { + // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols + return; + } + // Have direct reference to weak-global. This should be an indrect reference + warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. " + "This was likely caused by different translation units being compiled with different visibility settings.", + atom->name(), target->name()); + } return; + } } // no need to rebase or bind PIC internal pointer diff @@ -2623,13 +2755,18 @@ void OutputFile::addDyldInfo(ld::Internal& state, ld::Internal::FinalSection* s return; } - // make sure target is not global and weak - if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) - && (atom->section().type() != ld::Section::typeCFI) - && (atom->section().type() != ld::Section::typeDtraceDOF) - && (atom->section().type() != ld::Section::typeUnwindInfo) ) { - // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols - throwf("bad codegen, pointer diff in %s to global weak symbol %s", atom->name(), target->name()); + // check if target of pointer-diff is global and weak + if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular) ) { + if ( (atom->section().type() == ld::Section::typeCFI) + || (atom->section().type() == ld::Section::typeDtraceDOF) + || (atom->section().type() == ld::Section::typeUnwindInfo) ) { + // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols + return; + } + // Have direct reference to weak-global. This should be an indrect reference + warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. " + "This was likely caused by different translation units being compiled with different visibility settings.", + atom->name(), target->name()); } return; } @@ -2651,7 +2788,7 @@ void OutputFile::addDyldInfo(ld::Internal& state, ld::Internal::FinalSection* s uint8_t rebaseType = REBASE_TYPE_POINTER; uint8_t type = BIND_TYPE_POINTER; const ld::dylib::File* dylib = dynamic_cast(target->file()); - bool weak_import = ((dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked())); + bool weak_import = ((dylib != NULL) && (fixupWithTarget->weakImport || dylib->forcedWeakLinked())); uint64_t address = atom->finalAddress() + fixupWithTarget->offsetInAtom; uint64_t addend = targetAddend - minusTargetAddend; @@ -2764,10 +2901,6 @@ void OutputFile::addDyldInfo(ld::Internal& state, ld::Internal::FinalSection* s } if ( needsWeakBinding ) _weakBindingInfo.push_back(BindingInfo(type, 0, target->name(), false, address, addend)); - - // record if weak imported - if ( weak_import && (target->definition() == ld::Atom::definitionProxy) ) - (const_cast(target))->setWeakImported(); } @@ -2783,10 +2916,6 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio if ( (sect->type() == ld::Section::typeNonLazyPointer) && (_options.outputKind() != Options::kKextBundle) ) { assert(target != NULL); assert(fixupWithTarget != NULL); - // record if weak imported - const ld::dylib::File* dylib = dynamic_cast(target->file()); - if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) ) - (const_cast(target))->setWeakImported(); return; } @@ -2828,12 +2957,7 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio switch ( fixupWithStore->kind ) { case ld::Fixup::kindLazyTarget: - { - // lazy pointers don't need relocs, but might need weak_import bit set - const ld::dylib::File* dylib = dynamic_cast(target->file()); - if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) ) - (const_cast(target))->setWeakImported(); - } + // lazy pointers don't need relocs break; case ld::Fixup::kindStoreLittleEndian32: case ld::Fixup::kindStoreLittleEndian64: @@ -2893,9 +3017,6 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio _externalRelocsAtom->addExternalPointerReloc(relocAddress, target); sect->hasExternalRelocs = true; fixupWithTarget->contentAddendOnly = true; - // record if weak imported - if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) ) - (const_cast(target))->setWeakImported(); } else if ( needsLocalReloc ) { assert(target != NULL); @@ -2933,6 +3054,21 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio } } break; + + case ld::Fixup::kindStoreARMLow16: + case ld::Fixup::kindStoreThumbLow16: + // no way to encode rebasing of binding for these instructions + if ( _options.outputSlidable() || (target->definition() == ld::Atom::definitionProxy) ) + throwf("no supported runtime lo16 relocation in %s from %s to %s", atom->name(), atom->file()->path(), target->name()); + break; + + case ld::Fixup::kindStoreARMHigh16: + case ld::Fixup::kindStoreThumbHigh16: + // no way to encode rebasing of binding for these instructions + if ( _options.outputSlidable() || (target->definition() == ld::Atom::definitionProxy) ) + throwf("no supported runtime hi16 relocation in %s from %s to %s", atom->name(), atom->file()->path(), target->name()); + break; + default: break; } @@ -2945,6 +3081,22 @@ bool OutputFile::useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* t // x86_64 uses external relocations for everthing that has a symbol return ( target->symbolTableInclusion() != ld::Atom::symbolTableNotIn ); } + + // support arm branch interworking in -r mode + if ( (_options.architecture() == CPU_TYPE_ARM) && (_options.outputKind() == Options::kObjectFile) ) { + if ( atom->isThumb() != target->isThumb() ) { + switch ( fixupWithTarget->kind ) { + // have branch that switches mode, then might be 'b' not 'bl' + // Force external relocation, since no way to do local reloc for 'b' + case ld::Fixup::kindStoreTargetAddressThumbBranch22 : + case ld::Fixup::kindStoreTargetAddressARMBranch24: + return true; + default: + break; + } + } + } + // most architectures use external relocations only for references // to a symbol in another translation unit or for references to "weak symbols" or tentative definitions assert(target != NULL); @@ -3035,27 +3187,30 @@ void OutputFile::makeSplitSegInfo(ld::Internal& state) for (std::vector::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { const ld::Atom* atom = *ait; const ld::Atom* target = NULL; + const ld::Atom* fromTarget = NULL; + uint64_t accumulator = 0; + bool thumbTarget; bool hadSubtract = false; for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) { if ( fit->firstInCluster() ) target = NULL; - if ( fit->kind == ld::Fixup::kindSubtractTargetAddress ) { - hadSubtract = true; - continue; + if ( this->setsTarget(fit->kind) ) { + accumulator = addressOf(state, fit, &target); + thumbTarget = targetIsThumb(state, fit); + if ( thumbTarget ) + accumulator |= 1; } - switch ( fit->binding ) { - case ld::Fixup::bindingNone: - case ld::Fixup::bindingByNameUnbound: + switch ( fit->kind ) { + case ld::Fixup::kindSubtractTargetAddress: + accumulator -= addressOf(state, fit, &fromTarget); + hadSubtract = true; break; - case ld::Fixup::bindingByContentBound: - case ld::Fixup::bindingDirectlyBound: - target = fit->u.target; + case ld::Fixup::kindAddAddend: + accumulator += fit->u.addend; break; - case ld::Fixup::bindingsIndirectlyBound: - target = state.indirectBindingTable[fit->u.bindingIndex]; + case ld::Fixup::kindSubtractAddend: + accumulator -= fit->u.addend; break; - } - switch ( fit->kind ) { case ld::Fixup::kindStoreBigEndian32: case ld::Fixup::kindStoreLittleEndian32: case ld::Fixup::kindStoreLittleEndian64: @@ -3065,6 +3220,7 @@ void OutputFile::makeSplitSegInfo(ld::Internal& state) // there is also a text reloc which update_dyld_shared_cache will use. if ( ! hadSubtract ) break; + // fall through case ld::Fixup::kindStoreX86PCRel32: case ld::Fixup::kindStoreX86PCRel32_1: case ld::Fixup::kindStoreX86PCRel32_2: @@ -3076,11 +3232,27 @@ void OutputFile::makeSplitSegInfo(ld::Internal& state) case ld::Fixup::kindStoreTargetAddressX86PCRel32: case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad: case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA: + case ld::Fixup::kindStoreARMLow16: + case ld::Fixup::kindStoreThumbLow16: assert(target != NULL); if ( strcmp(sect->segmentName(), target->section().segmentName()) != 0 ) { _splitSegInfos.push_back(SplitSegInfoEntry(atom->finalAddress()+fit->offsetInAtom,fit->kind)); } break; + case ld::Fixup::kindStoreARMHigh16: + case ld::Fixup::kindStoreThumbHigh16: + assert(target != NULL); + if ( strcmp(sect->segmentName(), target->section().segmentName()) != 0 ) { + // hi16 needs to know upper 4-bits of low16 to compute carry + uint32_t extra = (accumulator >> 12) & 0xF; + _splitSegInfos.push_back(SplitSegInfoEntry(atom->finalAddress()+fit->offsetInAtom,fit->kind, extra)); + } + break; + case ld::Fixup::kindSetTargetImageOffset: + accumulator = addressOf(state, fit, &target); + assert(target != NULL); + hadSubtract = true; + break; default: break; } @@ -3218,8 +3390,8 @@ public: return (leftFileOrdinal < rightFileOrdinal); // then sort by atom objectAddress - uint64_t leftAddr = left->objectAddress(); - uint64_t rightAddr = right->objectAddress(); + uint64_t leftAddr = left->finalAddress(); + uint64_t rightAddr = right->finalAddress(); return leftAddr < rightAddr; } }; @@ -3315,7 +3487,7 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state) const ld::relocatable::File* atomObjFile = dynamic_cast(atomFile); const char* newDirPath; const char* newFilename; - //fprintf(stderr, "debug note for %s\n", atom->getDisplayName()); + //fprintf(stderr, "debug note for %s\n", atom->name()); if ( atom->translationUnitSource(&newDirPath, &newFilename) ) { // need SO's whenever the translation unit source file changes if ( newFilename != filename ) { @@ -3370,7 +3542,7 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state) // add the source file path to seenFiles so it does not show up in SOLs seenFiles.insert(newFilename); char* fullFilePath; - asprintf(&fullFilePath, "%s/%s", newDirPath, newFilename); + asprintf(&fullFilePath, "%s%s", newDirPath, newFilename); // add both leaf path and full path seenFiles.insert(fullFilePath); }