]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/passes/branch_island.cpp
ld64-224.1.tar.gz
[apple/ld64.git] / src / ld / passes / branch_island.cpp
index 99b3eb8f4b70eacb8b6d263f3ceba6219e2d57fe..96b6d35c59c218f1eec991ca13b37b2eca3ac80b 100644 (file)
@@ -59,42 +59,6 @@ public:
 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 {
@@ -108,8 +72,6 @@ public:
                                _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; }
@@ -158,8 +120,6 @@ public:
                                _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; }
@@ -198,8 +158,6 @@ public:
                                _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; }
@@ -263,8 +221,6 @@ public:
                                _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; }
@@ -303,10 +259,6 @@ static ld::Atom* makeBranchIsland(const Options& opts, ld::Fixup::Kind kind, int
        }
 
        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:
@@ -337,10 +289,6 @@ static ld::Atom* makeBranchIsland(const Options& opts, ld::Fixup::Kind kind, int
 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
@@ -358,10 +306,6 @@ static uint64_t textSizeWhenMightNeedBranchIslands(const Options& opts, bool see
 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
@@ -405,10 +349,8 @@ void doPass(const Options& opts, ld::Internal& state)
        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:
@@ -462,9 +404,45 @@ void doPass(const Options& opts, ld::Internal& state)
                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];
@@ -473,7 +451,6 @@ void doPass(const Options& opts, ld::Internal& state)
                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) {
@@ -506,8 +483,6 @@ void doPass(const Options& opts, ld::Internal& state)
                                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:
@@ -585,30 +560,25 @@ void doPass(const Options& opts, ld::Internal& state)
                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();