static bool _s_log = false;
static ld::Section _s_text_section("__TEXT", "__text", ld::Section::typeCode);
-class PPCBranchIslandAtom : public ld::Atom {
-public:
- PPCBranchIslandAtom(const char* nm, const ld::Atom* target, TargetAndOffset finalTarget)
- : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
- ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland,
- ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)),
- _name(nm),
- _target(target),
- _finalTarget(finalTarget) { }
-
- virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
- virtual const char* name() const { return _name; }
- virtual uint64_t size() const { return 4; }
- virtual uint64_t objectAddress() const { return 0; }
- virtual void copyRawContent(uint8_t buffer[]) const {
- int64_t displacement = _target->finalAddress() - this->finalAddress();
- const int64_t bl_sixteenMegLimit = 0x00FFFFFF;
- if ( _target->contentType() == ld::Atom::typeBranchIsland ) {
- // try optimizing away intermediate islands
- int64_t skipToFinalDisplacement = _finalTarget.atom->finalAddress() + _finalTarget.offset - this->finalAddress();
- if ( (skipToFinalDisplacement > bl_sixteenMegLimit) && (skipToFinalDisplacement < (-bl_sixteenMegLimit)) ) {
- displacement = skipToFinalDisplacement;
- }
- }
- int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
- OSWriteBigInt32(buffer, 0, branchInstruction);
- }
- virtual void setScope(Scope) { }
-
-private:
- const char* _name;
- const ld::Atom* _target;
- TargetAndOffset _finalTarget;
-};
class ARMtoARMBranchIslandAtom : public ld::Atom {
_finalTarget(finalTarget) { }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 4; }
virtual uint64_t objectAddress() const { return 0; }
_finalTarget(finalTarget) { }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 16; }
virtual uint64_t objectAddress() const { return 0; }
_finalTarget(finalTarget) { }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 4; }
virtual uint64_t objectAddress() const { return 0; }
_finalTarget(finalTarget) { }
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char**) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 8; }
virtual uint64_t objectAddress() const { return 0; }
}
switch ( kind ) {
- case ld::Fixup::kindStorePPCBranch24:
- case ld::Fixup::kindStoreTargetAddressPPCBranch24:
- return new PPCBranchIslandAtom(name, nextTarget, finalTarget);
- break;
case ld::Fixup::kindStoreARMBranch24:
case ld::Fixup::kindStoreThumbBranch22:
case ld::Fixup::kindStoreTargetAddressARMBranch24:
static uint64_t textSizeWhenMightNeedBranchIslands(const Options& opts, bool seenThumbBranch)
{
switch ( opts.architecture() ) {
- case CPU_TYPE_POWERPC:
- case CPU_TYPE_POWERPC64:
- return 16000000;
- break;
case CPU_TYPE_ARM:
if ( ! seenThumbBranch )
return 32000000; // ARM can branch +/- 32MB
static uint64_t maxDistanceBetweenIslands(const Options& opts, bool seenThumbBranch)
{
switch ( opts.architecture() ) {
- case CPU_TYPE_POWERPC:
- case CPU_TYPE_POWERPC64:
- return 14*1024*1024;
- break;
case CPU_TYPE_ARM:
if ( ! seenThumbBranch )
return 30*1024*1024; // 2MB of branch islands per 32MB
if ( opts.outputKind() == Options::kObjectFile )
return;
- // only PowerPC and ARM need branch islands
+ // only ARM needs branch islands
switch ( opts.architecture() ) {
- case CPU_TYPE_POWERPC:
- case CPU_TYPE_POWERPC64:
case CPU_TYPE_ARM:
break;
default:
return;
if (_s_log) fprintf(stderr, "ld: __text section size=%llu, might need branch islands\n", totalTextSize);
- // figure out how many regions of branch islands will be needed
- const uint32_t kBetweenRegions = maxDistanceBetweenIslands(opts, hasThumbBranches); // place regions of islands every 14MB in __text section
- const int kIslandRegionsCount = totalTextSize / kBetweenRegions;
+ // Figure out how many regions of branch islands will be needed, and their locations.
+ // Construct a vector containing the atoms after which branch islands will be inserted,
+ // taking into account follow on fixups. No atom run without an island can exceed kBetweenRegions.
+ const uint64_t kBetweenRegions = maxDistanceBetweenIslands(opts, hasThumbBranches); // place regions of islands every 14MB in __text section
+ std::vector<const ld::Atom*> branchIslandInsertionPoints; // atoms in the atom list after which branch islands will be inserted
+ uint64_t previousIslandEndAddr = 0;
+ const ld::Atom *insertionPoint;
+ branchIslandInsertionPoints.reserve(totalTextSize/kBetweenRegions*2);
+ for (std::vector<const ld::Atom*>::iterator it=textSection->atoms.begin(); it != textSection->atoms.end(); it++) {
+ const ld::Atom* atom = *it;
+ // if we move past the next atom, will the run length exceed kBetweenRegions?
+ if ( atom->sectionOffset() + atom->size() - previousIslandEndAddr > kBetweenRegions ) {
+ // yes. Add the last known good location (atom) for inserting a branch island.
+ if ( insertionPoint == NULL )
+ throwf("Unable to insert branch island. No insertion point available.");
+ branchIslandInsertionPoints.push_back(insertionPoint);
+ previousIslandEndAddr = insertionPoint->sectionOffset()+insertionPoint->size();
+ insertionPoint = NULL;
+ }
+ // Can we insert an island after this atom? If so then keep track of it.
+ if ( !atom->hasFixupsOfKind(ld::Fixup::kindNoneFollowOn) )
+ insertionPoint = atom;
+ }
+ // add one more island after the last atom
+ if (insertionPoint != NULL)
+ branchIslandInsertionPoints.push_back(insertionPoint);
+ const int kIslandRegionsCount = branchIslandInsertionPoints.size();
+ if (_s_log) {
+ fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
+ for (std::vector<const ld::Atom*>::iterator it = branchIslandInsertionPoints.begin(); it != branchIslandInsertionPoints.end(); ++it) {
+ const ld::Atom* atom = *it;
+ const ld::File *file = atom->file();
+ fprintf(stderr, "ld: branch island will be inserted at 0x%llx after %s", atom->sectionOffset()+atom->size(), atom->name());
+ if (file) fprintf(stderr, " (%s)", atom->file()->path());
+ fprintf(stderr, "\n");
+ }
+ }
+
+
typedef std::map<TargetAndOffset,const ld::Atom*, TargetAndOffsetComparor> AtomToIsland;
AtomToIsland* regionsMap[kIslandRegionsCount];
std::vector<const ld::Atom*>* regionsIslands[kIslandRegionsCount];
regionsIslands[i] = new std::vector<const ld::Atom*>();
}
unsigned int islandCount = 0;
- if (_s_log) fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
// create islands for branches in __text that are out of range
for (std::vector<const ld::Atom*>::iterator ait=textSection->atoms.begin(); ait != textSection->atoms.end(); ++ait) {
case ld::Fixup::kindAddAddend:
addend = fit->u.addend;
break;
- case ld::Fixup::kindStorePPCBranch24:
- case ld::Fixup::kindStoreTargetAddressPPCBranch24:
case ld::Fixup::kindStoreARMBranch24:
case ld::Fixup::kindStoreThumbBranch22:
case ld::Fixup::kindStoreTargetAddressARMBranch24:
if ( _s_log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount);
std::vector<const ld::Atom*> newAtomList;
newAtomList.reserve(textSection->atoms.size()+islandCount);
- uint64_t islandRegionAddr = kBetweenRegions;;
- int regionIndex = 0;
- for (std::vector<const ld::Atom*>::iterator it=textSection->atoms.begin(); it != textSection->atoms.end(); it++) {
- const ld::Atom* atom = *it;
- if ( (atom->sectionOffset()+atom->size()) > islandRegionAddr ) {
- std::vector<const ld::Atom*>* regionIslands = regionsIslands[regionIndex];
- for (std::vector<const ld::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
- const ld::Atom* islandAtom = *rit;
- newAtomList.push_back(islandAtom);
- if ( _s_log ) fprintf(stderr, "inserting island %s into __text section\n", islandAtom->name());
- }
- ++regionIndex;
- islandRegionAddr += kBetweenRegions;
+
+ uint64_t regionIndex = 0;
+ for (std::vector<const ld::Atom*>::iterator ait=textSection->atoms.begin(); ait != textSection->atoms.end(); ait++) {
+ newAtomList.push_back(*ait);
+ // copy over atoms until we find an island insertion point
+ // Note that the last insertion point is the last atom, so this loop never moves the iterator to atoms.end().
+ while (*ait != branchIslandInsertionPoints[regionIndex]) {
+ ait++;
+ newAtomList.push_back(*ait);
}
- newAtomList.push_back(atom);
- }
- // put any remaining islands at end of __text section
- if ( regionIndex < kIslandRegionsCount ) {
+
+ // insert the branch island atoms after the insertion point atom
std::vector<const ld::Atom*>* regionIslands = regionsIslands[regionIndex];
for (std::vector<const ld::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
const ld::Atom* islandAtom = *rit;
newAtomList.push_back(islandAtom);
if ( _s_log ) fprintf(stderr, "inserting island %s into __text section\n", islandAtom->name());
}
+ regionIndex++;
}
// swap in new list of atoms for __text section
textSection->atoms.clear();