Loading...
dyld3/shared-cache/OptimizerObjC.cpp dyld-655.1.1 dyld-551.3
--- dyld/dyld-655.1.1/dyld3/shared-cache/OptimizerObjC.cpp
+++ dyld/dyld-551.3/dyld3/shared-cache/OptimizerObjC.cpp
@@ -35,7 +35,7 @@
 #include "CacheBuilder.h"
 #include "FileAbstraction.hpp"
 #include "MachOFileAbstraction.hpp"
-#include "MachOLoaded.h"
+
 
 // Scan a C++ or Swift length-mangled field.
 static bool scanMangledField(const char *&string, const char *end, 
@@ -109,57 +109,37 @@
     ContentAccessor(const DyldSharedCache* cache, Diagnostics& diag)
         : _diagnostics(diag)
     {
-        _cacheStart         = (uint8_t*)cache;
-        _cacheUnslideAddr   = cache->unslidLoadAddress();
-        _slide              = (uint64_t)cache - _cacheUnslideAddr;
-#if SUPPORT_ARCH_arm64e
-        _chainedFixups      = (strcmp(cache->archName(), "arm64e") == 0);
-#else
-        _chainedFixups      = false;
-#endif
-     }
-
-    // Converts from an on disk vmAddr to the real vmAddr
-    // That is, for a chained fixup, decodes the chain, for a non-chained fixup, does nothing.
-    uint64_t vmAddrForOnDiskVMAddr(uint64_t vmaddr) {
-        if ( _chainedFixups ) {
-            dyld3::MachOLoaded::ChainedFixupPointerOnDisk ptr;
-            ptr.raw = vmaddr;
-            assert(ptr.authRebase.bind == 0);
-            if ( ptr.authRebase.auth ) {
-                vmaddr = _cacheUnslideAddr + ptr.authRebase.target;
-            }
-            else {
-                vmaddr = ptr.plainRebase.signExtendedTarget();
-            }
-        }
-        return vmaddr;
+        __block int index = 0;
+        cache->forEachRegion(^(const void* content, uint64_t vmAddr, uint64_t size, uint32_t permissions) {
+            _regions[index++] = { (uint8_t*)content, (uint8_t*)content+size, vmAddr, vmAddr+size };
+        });
     }
 
     void* contentForVMAddr(uint64_t vmaddr) {
-        vmaddr = vmAddrForOnDiskVMAddr(vmaddr);
-        if ( vmaddr != 0 ) {
-            uint64_t offset = vmaddr - _cacheUnslideAddr;
-            return _cacheStart + offset;
-        } else
-            return nullptr;
+        for (const Info& info : _regions) {
+            if ( (info.startAddr <= vmaddr) && (vmaddr < info.endAddr) )
+                return (void*)(info.contentStart + vmaddr - info.startAddr);
+        }
+        if ( vmaddr != 0 )
+            _diagnostics.error("invalid vmaddr 0x%0llX in ObjC data", vmaddr);
+        return nullptr;
     }
 
     uint64_t vmAddrForContent(const void* content) {
-        if ( content != nullptr )
-            return _cacheUnslideAddr + ((uint8_t*)content - _cacheStart);
-        else
-            return 0;
+        for (const Info& info : _regions) {
+            if ( (info.contentStart <= content) && (content < info.contentEnd) )
+                return info.startAddr + ((uint8_t*)content - (uint8_t*)info.contentStart);
+        }
+        _diagnostics.error("invalid content pointer %p in ObjC data", content);
+        return 0;
     }
 
     Diagnostics& diagnostics() { return _diagnostics; }
 
 private:
-    Diagnostics&                    _diagnostics;
-    uint64_t                        _slide;
-    uint64_t                        _cacheUnslideAddr;
-    uint8_t*                        _cacheStart;
-    bool                            _chainedFixups;
+    struct Info { uint8_t* contentStart; uint8_t* contentEnd; uint64_t startAddr; uint64_t endAddr; };
+    Diagnostics&    _diagnostics;
+    Info            _regions[3];
 };
 
 
@@ -187,10 +167,6 @@
         return (pint_t)P::getP(_base[index]);
     }
 
-    pint_t getSectionVMAddress() const {
-        return (pint_t)_section->addr();
-    }
-
     T get(pint_t index) const {
         return (T)_cache->contentForVMAddr(getVMAddress(index));
     }
@@ -277,7 +253,6 @@
     {
         _count++;
         const char *s = (const char *)_cache->contentForVMAddr(oldValue);
-        oldValue = (pint_t)_cache->vmAddrForOnDiskVMAddr(oldValue);
         objc_opt::string_map::iterator element = 
             _selectorStrings.insert(objc_opt::string_map::value_type(s, oldValue)).first;
         return (pint_t)element->second;
@@ -391,7 +366,7 @@
     const char *writeProtocols(ContentAccessor* cache,
                                uint8_t *& rwdest, size_t& rwremaining,
                                uint8_t *& rodest, size_t& roremaining, 
-                               CacheBuilder::ASLR_Tracker& aslrTracker,
+                               std::vector<void*>& pointersInData, 
                                pint_t protocolClassVMAddr)
     {
         if (_protocolCount == 0) return NULL;
@@ -455,7 +430,7 @@
             iter->second = cache->vmAddrForContent(proto);
 
             // Add new rebase entries.
-            proto->addPointers(cache, aslrTracker);
+            proto->addPointers(pointersInData);
         }
         
         return NULL;
@@ -489,9 +464,7 @@
 
 
 template <typename P>
-void doOptimizeObjC(DyldSharedCache* cache, bool forProduction, CacheBuilder::ASLR_Tracker& aslrTracker,
-                    CacheBuilder::LOH_Tracker& lohTracker,
-                    const std::map<void*, std::string>& missingWeakImports, Diagnostics& diag)
+void optimizeObjC(DyldSharedCache* cache, bool forProduction, std::vector<void*>& pointersForASLR, Diagnostics& diag)
 {
     typedef typename P::E           E;
     typedef typename P::uint_t      pint_t;
@@ -590,7 +563,7 @@
     }
     else {
         for (const macho_header<P>* mh : addressSortedDylibs) {
-            hinfoROOptimizer.update(&cacheAccessor, mh, aslrTracker);
+            hinfoROOptimizer.update(&cacheAccessor, mh, pointersForASLR);
         }
     }
 
@@ -605,7 +578,7 @@
     }
     else {
         for (const macho_header<P>* mh : addressSortedDylibs) {
-            hinfoRWOptimizer.update(&cacheAccessor, mh, aslrTracker);
+            hinfoRWOptimizer.update(&cacheAccessor, mh, pointersForASLR);
         }
     }
 
@@ -667,7 +640,7 @@
     if (forProduction) {
         WeakClassDetector<P> weakopt;
         noMissingWeakSuperclasses = 
-            weakopt.noMissingWeakSuperclasses(&cacheAccessor, missingWeakImports, sizeSortedDylibs);
+            weakopt.noMissingWeakSuperclasses(&cacheAccessor, sizeSortedDylibs);
 
         // Shared cache does not currently support unbound weak references. 
         // Here we assert that there are none. If support is added later then 
@@ -744,7 +717,7 @@
     err = protocolOptimizer.writeProtocols(&cacheAccessor,
                                            optRWData, optRWRemaining,
                                            optROData, optRORemaining,
-                                           aslrTracker, protocolClassVMAddr);
+                                           pointersForASLR, protocolClassVMAddr);
     if (err) {
         diag.warning("%s", err);
         return;
@@ -831,120 +804,17 @@
     diag.verbose("  %lu/%llu bytes (%d%%) used in libobjc read/write optimization section\n",
                   rwSize, optRWSection->size(), percent(rwSize, optRWSection->size()));
     diag.verbose("  wrote objc metadata optimization version %d\n", objc_opt::VERSION);
-
-    // Now that objc has uniqued the selector references, we can apply the LOHs so that ADRP/LDR -> ADRP/ADD
-    if (forProduction) {
-        uint64_t lohADRPCount = 0;
-        uint64_t lohLDRCount = 0;
-
-        for (auto& targetAndInstructions : lohTracker) {
-            uint64_t targetVMAddr = targetAndInstructions.first;
-            if (!selOptimizer.isSelectorRefAddress((pint_t)targetVMAddr))
-                continue;
-
-            std::set<void*>& instructions = targetAndInstructions.second;
-            // We do 2 passes over the instructions.  The first to validate them and the second
-            // to actually update them.
-            for (unsigned pass = 0; pass != 2; ++pass) {
-                uint32_t adrpCount = 0;
-                uint32_t ldrCount = 0;
-                for (void* instructionAddress : instructions) {
-                    uint32_t& instruction = *(uint32_t*)instructionAddress;
-                    uint64_t instructionVMAddr = cacheAccessor.vmAddrForContent(&instruction);
-                    uint64_t selRefContent = *(uint64_t*)cacheAccessor.contentForVMAddr(targetVMAddr);
-                    const char* selectorString = (const char*)cacheAccessor.contentForVMAddr(selRefContent);
-                    uint64_t selectorStringVMAddr = cacheAccessor.vmAddrForContent(selectorString);
-
-                    if ( (instruction & 0x9F000000) == 0x90000000 ) {
-                        // ADRP
-                        int64_t pageDistance = ((selectorStringVMAddr & ~0xFFF) - (instructionVMAddr & ~0xFFF));
-                        int64_t newPage21 = pageDistance >> 12;
-
-                        if (pass == 0) {
-                            if ( (newPage21 > 2097151) || (newPage21 < -2097151) ) {
-                                diag.verbose("Out of bounds ADRP selector reference target\n");
-                                instructions.clear();
-                                break;
-                            }
-                            ++adrpCount;
-                        }
-
-                        if (pass == 1) {
-                            instruction = (instruction & 0x9F00001F) | ((newPage21 << 29) & 0x60000000) | ((newPage21 << 3) & 0x00FFFFE0);
-                            ++lohADRPCount;
-                        }
-                        continue;
-                    }
-
-                    if ( (instruction & 0x3B000000) == 0x39000000 ) {
-                        // LDR/STR.  STR shouldn't be possible as this is a selref!
-                        if (pass == 0) {
-                            if ( (instruction & 0xC0C00000) != 0xC0400000 ) {
-                                // Not a load, or dest reg isn't xN, or uses sign extension
-                                diag.verbose("Bad LDR for selector reference optimisation\n");
-                                instructions.clear();
-                                break;
-                            }
-                            if ( (instruction & 0x04000000) != 0 ) {
-                                // Loading a float
-                                diag.verbose("Bad LDR for selector reference optimisation\n");
-                                instructions.clear();
-                                break;
-                            }
-                            ++ldrCount;
-                        }
-
-                        if (pass == 1) {
-                            uint32_t ldrDestReg = (instruction & 0x1F);
-                            uint32_t ldrBaseReg = ((instruction >> 5) & 0x1F);
-
-                            // Convert the LDR to an ADD
-                            instruction = 0x91000000;
-                            instruction |= ldrDestReg;
-                            instruction |= ldrBaseReg << 5;
-                            instruction |= (selectorStringVMAddr & 0xFFF) << 10;
-
-                            ++lohLDRCount;
-                        }
-                        continue;
-                    }
-
-                    if ( (instruction & 0xFFC00000) == 0x91000000 ) {
-                        // ADD imm12
-                        // We don't support ADDs.
-                        diag.verbose("Bad ADD for selector reference optimisation\n");
-                        instructions.clear();
-                        break;
-                    }
-
-                    diag.verbose("Unknown instruction for selref optimisation\n");
-                    instructions.clear();
-                    break;
-                }
-                if (pass == 0) {
-                    // If we didn't see at least one ADRP/LDR in pass one then don't optimize this location
-                    if ((adrpCount == 0) || (ldrCount == 0)) {
-                        instructions.clear();
-                        break;
-                    }
-                }
-            }
-        }
-
-        diag.verbose("  Optimized %lld ADRP LOHs\n", lohADRPCount);
-        diag.verbose("  Optimized %lld LDR LOHs\n", lohLDRCount);
-    }
 }
 
 
 } // anon namespace
 
-void CacheBuilder::optimizeObjC()
+void optimizeObjC(DyldSharedCache* cache, bool is64, bool customerCache, std::vector<void*>& pointersForASLR, Diagnostics& diag)
 {
-    if ( _archLayout->is64 )
-        doOptimizeObjC<Pointer64<LittleEndian>>((DyldSharedCache*)_readExecuteRegion.buffer, _options.optimizeStubs, _aslrTracker, _lohTracker, _missingWeakImports, _diagnostics);
+    if ( is64 )
+        optimizeObjC<Pointer64<LittleEndian>>(cache, customerCache, pointersForASLR, diag);
     else
-        doOptimizeObjC<Pointer32<LittleEndian>>((DyldSharedCache*)_readExecuteRegion.buffer, _options.optimizeStubs, _aslrTracker, _lohTracker, _missingWeakImports, _diagnostics);
+        optimizeObjC<Pointer32<LittleEndian>>(cache, customerCache, pointersForASLR, diag);
 }