Loading...
--- dyld/dyld-832.7.3/dyld3/shared-cache/OptimizerLinkedit.cpp
+++ dyld/dyld-551.3/dyld3/shared-cache/OptimizerLinkedit.cpp
@@ -40,7 +40,7 @@
#include "Trie.hpp"
#include "DyldSharedCache.h"
#include "CacheBuilder.h"
-#include "MachOLoaded.h"
+
#define ALIGN_AS_TYPE(value, type) \
((value + alignof(type) - 1) & (-alignof(type)))
@@ -53,31 +53,27 @@
public:
// add a string and symbol table entry index to be updated later
void add(uint32_t symbolIndex, const char* symbolName) {
- _map[symbolName].push_back({ symbolIndex, false });
- }
-
- // add a string and symbol table entry index to be updated later
- void addIndirect(uint32_t symbolIndex, const char* symbolName) {
- _map[symbolName].push_back({ symbolIndex, true });
+ _map[symbolName].push_back(symbolIndex);
}
// copy sorted strings to buffer and update all symbol's string offsets
uint32_t copyPoolAndUpdateOffsets(char* dstStringPool, macho_nlist<P>* symbolTable) {
+ // make sorted list of strings
+ std::vector<std::string> allStrings;
+ allStrings.reserve(_map.size());
+ for (auto& entry : _map) {
+ allStrings.push_back(entry.first);
+ }
+ std::sort(allStrings.begin(), allStrings.end());
// walk sorted list of strings
dstStringPool[0] = '\0'; // tradition for start of pool to be empty string
uint32_t poolOffset = 1;
- for (auto& entry : _map) {
- const std::string& symName = entry.first;
+ for (const std::string& symName : allStrings) {
// append string to pool
strcpy(&dstStringPool[poolOffset], symName.c_str());
// set each string offset of each symbol using it
- for (std::pair<uint32_t, bool> symbolIndexAndIndirect : entry.second) {
- if ( symbolIndexAndIndirect.second ) {
- // Indirect
- symbolTable[symbolIndexAndIndirect.first].set_n_value(poolOffset);
- } else {
- symbolTable[symbolIndexAndIndirect.first].set_n_strx(poolOffset);
- }
+ for (uint32_t symbolIndex : _map[symName]) {
+ symbolTable[symbolIndex].set_n_strx(poolOffset);
}
poolOffset += symName.size() + 1;
}
@@ -95,11 +91,10 @@
private:
- std::map<std::string, std::vector<std::pair<uint32_t, bool>>> _map;
+ std::unordered_map<std::string, std::vector<uint32_t>> _map;
};
-} // anonymous namespace
struct LocalSymbolInfo
@@ -113,12 +108,12 @@
template <typename P>
class LinkeditOptimizer {
public:
- LinkeditOptimizer(const void* containerBuffer, macho_header<P>* mh, const char* dylibID,
- Diagnostics& diag);
+ LinkeditOptimizer(void* cacheBuffer, macho_header<P>* mh, Diagnostics& diag);
uint32_t linkeditSize() { return _linkeditSize; }
+ uint32_t linkeditOffset() { return _linkeditCacheOffset; }
uint64_t linkeditAddr() { return _linkeditAddr; }
- const char* dylibID() { return _dylibID; }
+ const char* installName() { return _installName; }
void copyWeakBindingInfo(uint8_t* newLinkEditContent, uint32_t& offset);
void copyLazyBindingInfo(uint8_t* newLinkEditContent, uint32_t& offset);
void copyBindingInfo(uint8_t* newLinkEditContent, uint32_t& offset);
@@ -135,9 +130,6 @@
uint32_t sharedSymbolTableStartOffset, uint32_t sharedSymbolTableCount,
uint32_t sharedSymbolStringsOffset, uint32_t sharedSymbolStringsSize);
- typedef CacheBuilder::DylibStripMode DylibStripMode;
- void setStripMode(DylibStripMode stripMode);
-
macho_header<P>* machHeader() { return _mh; }
const std::vector<const char*> getDownwardDependents() { return _downDependentPaths; }
const std::vector<const char*> getAllDependents() { return _allDependentPaths; }
@@ -152,28 +144,22 @@
const std::vector<macho_segment_command<P>*>& segCmds() { return _segCmds; }
- static void optimizeLinkedit(CacheBuilder& builder, const void* containerBuffer,
- CacheBuilder::UnmappedRegion* localSymbolsRegion,
- const std::vector<std::tuple<const mach_header*, const char*, DylibStripMode>>& images);
- static void mergeLinkedits(CacheBuilder& builder, CacheBuilder::UnmappedRegion* localSymbolsRegion,
- std::vector<LinkeditOptimizer<P>*>& optimizers);
-
private:
typedef typename P::uint_t pint_t;
typedef typename P::E E;
macho_header<P>* _mh;
- const void* _containerBuffer;
+ void* _cacheBuffer;
Diagnostics& _diagnostics;
uint32_t _linkeditSize = 0;
+ uint32_t _linkeditCacheOffset = 0;
uint64_t _linkeditAddr = 0;
const uint8_t* _linkeditBias = nullptr;
- const char* _dylibID = nullptr;
+ const char* _installName = nullptr;
macho_symtab_command<P>* _symTabCmd = nullptr;
macho_dysymtab_command<P>* _dynSymTabCmd = nullptr;
macho_dyld_info_command<P>* _dyldInfo = nullptr;
- macho_linkedit_data_command<P>* _exportTrieCmd = nullptr;
macho_linkedit_data_command<P>* _functionStartsCmd = nullptr;
macho_linkedit_data_command<P>* _dataInCodeCmd = nullptr;
std::vector<macho_segment_command<P>*> _segCmds;
@@ -199,20 +185,352 @@
uint32_t _newDataInCodeOffset = 0;
uint32_t _newIndirectSymbolTableOffset = 0;
uint64_t _dyldSectionAddr = 0;
- DylibStripMode _stripMode = DylibStripMode::stripAll;
};
-template <typename P>
-LinkeditOptimizer<P>::LinkeditOptimizer(const void* containerBuffer, macho_header<P>* mh,
- const char* dylibID, Diagnostics& diag)
-: _mh(mh), _dylibID(dylibID), _containerBuffer(containerBuffer), _diagnostics(diag)
-{
+
+template <typename P>
+class AcceleratorTables {
+public:
+ AcceleratorTables(DyldSharedCache* cache, uint64_t linkeditStartAddr, Diagnostics& diag, const std::vector<LinkeditOptimizer<P>*>& optimizers);
+
+ uint32_t totalSize() const;
+ void copyTo(uint8_t* buffer);
+
+private:
+ typedef typename P::E E;
+
+ struct NodeChain;
+
+ struct DepNode {
+ std::vector<DepNode*> _dependents;
+ unsigned _depth;
+ const char* _installName;
+
+ DepNode() : _depth(0), _installName(nullptr) { }
+ void computeDepth();
+ static void verifyUnreachable(DepNode* target, NodeChain& chain, Diagnostics& diag, std::unordered_set<DepNode*>& visitedNodes, const std::vector<DepNode*>& from);
+ };
+
+ struct NodeChain {
+ NodeChain* prev;
+ DepNode* node;
+ };
+
+ std::unordered_map<macho_header<P>*, DepNode> _depDAG;
+ std::vector<dyld_cache_image_info_extra> _extraInfo;
+ std::vector<uint8_t> _trieBytes;
+ std::vector<uint16_t> _reExportArray;
+ std::vector<uint16_t> _dependencyArray;
+ std::vector<uint16_t> _bottomUpArray;
+ std::vector<dyld_cache_accelerator_initializer> _initializers;
+ std::vector<dyld_cache_accelerator_dof> _dofSections;
+ std::vector<dyld_cache_range_entry> _rangeTable;
+ std::unordered_map<macho_header<P>*, uint32_t> _machHeaderToImageIndex;
+ std::unordered_map<std::string, macho_header<P>*> _dylibPathToMachHeader;
+ std::unordered_map<macho_header<P>*, LinkeditOptimizer<P>*> _machHeaderToOptimizer;
+ dyld_cache_accelerator_info _acceleratorInfoHeader;
+};
+
+
+template <typename P>
+void AcceleratorTables<P>::AcceleratorTables::DepNode::verifyUnreachable(AcceleratorTables<P>::DepNode* target, struct AcceleratorTables<P>::NodeChain& chain, Diagnostics& diag,
+ std::unordered_set<DepNode*>& visitedNodes, const std::vector<AcceleratorTables<P>::DepNode*>& from) {
+ for (DepNode* node : from) {
+ bool foundCycle = (node == target);
+ for (NodeChain* c = &chain; c->prev != nullptr; c = c->prev) {
+ if ( c->node == target ) {
+ foundCycle = true;
+ break;
+ }
+ }
+ if ( foundCycle ) {
+ NodeChain* chp = &chain;
+ std::string msg = std::string("found cycle for ") + target->_installName;
+ while (chp != nullptr) {
+ msg = msg + "\n " + chp->node->_installName;
+ chp = chp->prev;
+ }
+ diag.warning("%s", msg.c_str());
+ return;
+ }
+
+ if ( visitedNodes.count(node) )
+ continue;
+ visitedNodes.insert(node);
+ NodeChain nextChain;
+ nextChain.prev = &chain;
+ nextChain.node = node;
+ verifyUnreachable(target, nextChain, diag, visitedNodes, node->_dependents);
+ }
+}
+
+const uint16_t kBranchIslandDylibIndex = 0x7FFF;
+
+template <typename P>
+AcceleratorTables<P>::AcceleratorTables(DyldSharedCache* cache, uint64_t linkeditStartAddr, Diagnostics& diag, const std::vector<LinkeditOptimizer<P>*>& optimizers)
+{
+ // build table mapping tables to map between mach_header, index, and optimizer
+ for ( LinkeditOptimizer<P>* op : optimizers ) {
+ _machHeaderToOptimizer[op->machHeader()] = op;
+ }
+ const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)((uint8_t*)cache + cache->header.mappingOffset);
+ uint64_t cacheStartAddress = mappings[0].address;
+ const dyld_cache_image_info* images = (dyld_cache_image_info*)((uint8_t*)cache + cache->header.imagesOffset);
+ for (unsigned i=0; i < cache->header.imagesCount; ++i) {
+ uint64_t segCacheFileOffset = images[i].address - cacheStartAddress;
+ macho_header<P>* mhMapped = (macho_header<P>*)((uint8_t*)cache+segCacheFileOffset);
+ const char* path = (char*)cache + images[i].pathFileOffset;
+ _dylibPathToMachHeader[path] = mhMapped;
+ // don't add alias entries (path offset in pool near start of cache) to header->index map
+ if ( images[i].pathFileOffset > segCacheFileOffset )
+ _machHeaderToImageIndex[mhMapped] = i;
+ }
+
+
+ // build DAG of image dependencies
+ for (LinkeditOptimizer<P>* op : optimizers) {
+ _depDAG[op->machHeader()]._installName = op->installName();
+ }
+ for (LinkeditOptimizer<P>* op : optimizers) {
+ DepNode& node = _depDAG[op->machHeader()];
+ for (const char* depPath : op->getDownwardDependents()) {
+ macho_header<P>* depMH = _dylibPathToMachHeader[depPath];
+ if ( depMH != nullptr ) {
+ DepNode* depNode = &_depDAG[depMH];
+ node._dependents.push_back(depNode);
+ }
+ }
+ }
+
+ // check for cycles in DAG
+ for (auto& entry : _depDAG) {
+ DepNode* node = &entry.second;
+ NodeChain chain;
+ chain.prev = nullptr;
+ chain.node = node;
+ std::unordered_set<DepNode*> visitedNodes;
+ DepNode::verifyUnreachable(node, chain, diag, visitedNodes, node->_dependents);
+ }
+
+ // compute depth for each DAG node
+ for (auto& entry : _depDAG) {
+ entry.second.computeDepth();
+ }
+
+ // build sorted (bottom up) list of images
+ std::vector<macho_header<P>*> sortedMachHeaders;
+ sortedMachHeaders.reserve(optimizers.size());
+ for (LinkeditOptimizer<P>* op : optimizers) {
+ if ( strcmp(op->installName(), "dyld_shared_cache_branch_islands") != 0 )
+ sortedMachHeaders.push_back(op->machHeader());
+ else
+ _machHeaderToImageIndex[op->machHeader()] = kBranchIslandDylibIndex;
+ }
+ std::sort(sortedMachHeaders.begin(), sortedMachHeaders.end(),
+ [&](macho_header<P>* lmh, macho_header<P>* rmh) -> bool {
+ if ( _depDAG[lmh]._depth != _depDAG[rmh]._depth )
+ return (_depDAG[lmh]._depth < _depDAG[rmh]._depth);
+ else
+ return (lmh < rmh);
+ });
+
+ // build zeroed array of extra infos
+ dyld_cache_image_info_extra emptyExtra;
+ emptyExtra.exportsTrieAddr = 0;
+ emptyExtra.weakBindingsAddr = 0;
+ emptyExtra.exportsTrieSize = 0;
+ emptyExtra.weakBindingsSize = 0;
+ emptyExtra.dependentsStartArrayIndex = 0;
+ emptyExtra.reExportsStartArrayIndex = 0;
+ _extraInfo.insert(_extraInfo.begin(), sortedMachHeaders.size(), emptyExtra);
+
+ //for ( macho_header<P>* mh : sortedMachHeaders ) {
+ // fprintf(stderr, "depth: %3d mh: %p path: %s\n", _depDAG[mh]._depth, mh, _machHeaderToOptimizer[mh]->installName());
+ //}
+
+ // build dependency table
+ _dependencyArray.push_back(0xFFFF); // reserve 0 slot to be "no-dependencies"
+ for (macho_header<P>* mh : sortedMachHeaders) {
+ LinkeditOptimizer<P>* op = _machHeaderToOptimizer[mh];
+ unsigned index = _machHeaderToImageIndex[mh];
+ auto depPaths = op->getAllDependents();
+ if ( depPaths.empty() ) {
+ _extraInfo[index].dependentsStartArrayIndex = 0;
+ }
+ else {
+ _extraInfo[index].dependentsStartArrayIndex = (uint32_t)_dependencyArray.size();
+ auto downPaths = op->getDownwardDependents();
+ for (const char* depPath : depPaths) {
+ macho_header<P>* depMH = _dylibPathToMachHeader[depPath];
+ uint16_t depIndex = _machHeaderToImageIndex[depMH];
+ if ( std::find(downPaths.begin(), downPaths.end(), depPath) == downPaths.end())
+ depIndex |= 0x8000;
+ _dependencyArray.push_back(depIndex);
+ }
+ _dependencyArray.push_back(0xFFFF); // mark end of list
+ }
+ }
+
+ // build re-exports table
+ _reExportArray.push_back(0xFFFF); // reserve 0 slot to be "no-re-exports"
+ for (macho_header<P>* mh : sortedMachHeaders) {
+ LinkeditOptimizer<P>* op = _machHeaderToOptimizer[mh];
+ unsigned index = _machHeaderToImageIndex[mh];
+ auto reExPaths = op->getReExportPaths();
+ if ( reExPaths.empty() ) {
+ _extraInfo[index].reExportsStartArrayIndex = 0;
+ }
+ else {
+ _extraInfo[index].reExportsStartArrayIndex = (uint32_t)_reExportArray.size();
+ for (const char* reExPath : reExPaths) {
+ macho_header<P>* reExMH = _dylibPathToMachHeader[reExPath];
+ uint32_t reExIndex = _machHeaderToImageIndex[reExMH];
+ _reExportArray.push_back(reExIndex);
+ }
+ _reExportArray.push_back(0xFFFF); // mark end of list
+ }
+ }
+
+ // build ordered list of initializers
+ for (macho_header<P>* mh : sortedMachHeaders) {
+ LinkeditOptimizer<P>* op = _machHeaderToOptimizer[mh];
+ unsigned index = _machHeaderToImageIndex[mh];
+ _bottomUpArray.push_back(index);
+ for (uint64_t initializer : op->initializerAddresses()) {
+ //fprintf(stderr, "0x%08llX %s\n", initializer, op->installName());
+ dyld_cache_accelerator_initializer entry;
+ entry.functionOffset = (uint32_t)(initializer-cacheStartAddress);
+ entry.imageIndex = _machHeaderToImageIndex[mh];
+ _initializers.push_back(entry);
+ }
+ }
+
+ // build ordered list of DOF sections
+ for (macho_header<P>* mh : sortedMachHeaders) {
+ LinkeditOptimizer<P>* op = _machHeaderToOptimizer[mh];
+ assert(op != NULL);
+ unsigned imageIndex = _machHeaderToImageIndex[mh];
+ for (auto& sect : op->dofSections()) {
+ //fprintf(stderr, "0x%08llX %s\n", initializer, op->installName());
+ dyld_cache_accelerator_dof entry;
+ entry.sectionAddress = sect->addr();
+ entry.sectionSize = (uint32_t)sect->size();
+ entry.imageIndex = imageIndex;
+ _dofSections.push_back(entry);
+ }
+ }
+
+ // register exports trie and weak binding info in each dylib with image extra info
+ for (macho_header<P>* mh : sortedMachHeaders) {
+ LinkeditOptimizer<P>* op = _machHeaderToOptimizer[mh];
+ unsigned index = _machHeaderToImageIndex[mh];
+ _extraInfo[index].exportsTrieAddr = op->exportsTrieLinkEditOffset() + linkeditStartAddr;
+ _extraInfo[index].exportsTrieSize = op->exportsTrieLinkEditSize();
+ _extraInfo[index].weakBindingsAddr = op->weakBindingLinkEditOffset() + linkeditStartAddr;
+ _extraInfo[index].weakBindingsSize = op->weakBindingLinkEditSize();
+ }
+
+ // record location of __DATA/__dyld section in libdyld.dylib
+ macho_header<P>* libdyldMH = _dylibPathToMachHeader["/usr/lib/system/libdyld.dylib"];
+ LinkeditOptimizer<P>* libdyldOp = _machHeaderToOptimizer[libdyldMH];
+ uint64_t dyldSectionAddr = libdyldOp->dyldSectionAddress();
+
+ // build range table for fast address->image lookups
+ for (macho_header<P>* mh : sortedMachHeaders) {
+ LinkeditOptimizer<P>* op = _machHeaderToOptimizer[mh];
+ unsigned imageIndex = _machHeaderToImageIndex[mh];
+ for (const macho_segment_command<P>* segCmd : op->segCmds()) {
+ if ( strcmp(segCmd->segname(), "__LINKEDIT") == 0 )
+ continue;
+ dyld_cache_range_entry entry;
+ entry.startAddress = segCmd->vmaddr();
+ entry.size = (uint32_t)segCmd->vmsize();
+ entry.imageIndex = imageIndex;
+ _rangeTable.push_back(entry);
+ }
+ }
+ std::sort(_rangeTable.begin(), _rangeTable.end(),
+ [&](const dyld_cache_range_entry& lRange, const dyld_cache_range_entry& rRange) -> bool {
+ return (lRange.startAddress < rRange.startAddress);
+ });
+
+ // build trie that maps install names to image index
+ std::vector<DylibIndexTrie::Entry> dylibEntrys;
+ for (auto &x : _dylibPathToMachHeader) {
+ const std::string& path = x.first;
+ unsigned index = _machHeaderToImageIndex[x.second];
+ dylibEntrys.push_back(DylibIndexTrie::Entry(path, DylibIndex(index)));
+ }
+ DylibIndexTrie dylibsTrie(dylibEntrys);
+ dylibsTrie.emit(_trieBytes);
+ while ( (_trieBytes.size() % 4) != 0 )
+ _trieBytes.push_back(0);
+
+ // fill out header
+ _acceleratorInfoHeader.version = 1;
+ _acceleratorInfoHeader.imageExtrasCount = (uint32_t)_extraInfo.size();
+ _acceleratorInfoHeader.imagesExtrasOffset = ALIGN_AS_TYPE(sizeof(dyld_cache_accelerator_info), dyld_cache_image_info_extra);
+ _acceleratorInfoHeader.bottomUpListOffset = _acceleratorInfoHeader.imagesExtrasOffset + _acceleratorInfoHeader.imageExtrasCount*sizeof(dyld_cache_image_info_extra);
+ _acceleratorInfoHeader.dylibTrieOffset = _acceleratorInfoHeader.bottomUpListOffset + _acceleratorInfoHeader.imageExtrasCount*sizeof(uint16_t);
+ _acceleratorInfoHeader.dylibTrieSize = (uint32_t)_trieBytes.size();
+ _acceleratorInfoHeader.initializersOffset = ALIGN_AS_TYPE(_acceleratorInfoHeader.dylibTrieOffset + _acceleratorInfoHeader.dylibTrieSize, dyld_cache_accelerator_initializer);
+ _acceleratorInfoHeader.initializersCount = (uint32_t)_initializers.size();
+ _acceleratorInfoHeader.dofSectionsOffset = ALIGN_AS_TYPE(_acceleratorInfoHeader.initializersOffset + _acceleratorInfoHeader.initializersCount*sizeof(dyld_cache_accelerator_initializer), dyld_cache_accelerator_initializer);
+ _acceleratorInfoHeader.dofSectionsCount = (uint32_t)_dofSections.size();
+ _acceleratorInfoHeader.reExportListOffset = ALIGN_AS_TYPE(_acceleratorInfoHeader.dofSectionsOffset + _acceleratorInfoHeader.dofSectionsCount*sizeof(dyld_cache_accelerator_dof), dyld_cache_accelerator_dof);
+ _acceleratorInfoHeader.reExportCount = (uint32_t)_reExportArray.size();
+ _acceleratorInfoHeader.depListOffset = ALIGN_AS_TYPE(_acceleratorInfoHeader.reExportListOffset + _acceleratorInfoHeader.reExportCount*sizeof(uint16_t), uint16_t);
+ _acceleratorInfoHeader.depListCount = (uint32_t)_dependencyArray.size();
+ _acceleratorInfoHeader.rangeTableOffset = ALIGN_AS_TYPE(_acceleratorInfoHeader.depListOffset + _acceleratorInfoHeader.depListCount*sizeof(uint16_t), dyld_cache_range_entry);
+ _acceleratorInfoHeader.rangeTableCount = (uint32_t)_rangeTable.size();
+ _acceleratorInfoHeader.dyldSectionAddr = dyldSectionAddr;
+}
+
+
+template <typename P>
+void AcceleratorTables<P>::DepNode::computeDepth()
+{
+ if ( _depth != 0 )
+ return;
+ _depth = 1;
+ for (DepNode* node : _dependents) {
+ node->computeDepth();
+ if ( node->_depth >= _depth )
+ _depth = node->_depth + 1;
+ }
+}
+
+template <typename P>
+uint32_t AcceleratorTables<P>::totalSize() const
+{
+ return (uint32_t)align(_acceleratorInfoHeader.rangeTableOffset + _acceleratorInfoHeader.rangeTableCount*sizeof(dyld_cache_range_entry), 14);
+}
+
+template <typename P>
+void AcceleratorTables<P>::copyTo(uint8_t* buffer)
+{
+ memcpy(buffer, &_acceleratorInfoHeader, sizeof(dyld_cache_accelerator_info));
+ memcpy(&buffer[_acceleratorInfoHeader.imagesExtrasOffset], &_extraInfo[0], _extraInfo.size()*sizeof(dyld_cache_image_info_extra));
+ memcpy(&buffer[_acceleratorInfoHeader.bottomUpListOffset], &_bottomUpArray[0], _bottomUpArray.size()*sizeof(uint16_t));
+ memcpy(&buffer[_acceleratorInfoHeader.initializersOffset], &_initializers[0], _initializers.size()*sizeof(dyld_cache_accelerator_initializer));
+ memcpy(&buffer[_acceleratorInfoHeader.reExportListOffset], &_reExportArray[0], _reExportArray.size()*sizeof(uint16_t));
+ memcpy(&buffer[_acceleratorInfoHeader.dofSectionsOffset], &_dofSections[0], _dofSections.size()*sizeof(dyld_cache_accelerator_dof));
+ memcpy(&buffer[_acceleratorInfoHeader.depListOffset], &_dependencyArray[0], _dependencyArray.size()*sizeof(uint16_t));
+ memcpy(&buffer[_acceleratorInfoHeader.rangeTableOffset], &_rangeTable[0], _rangeTable.size()*sizeof(dyld_cache_range_entry));
+ memcpy(&buffer[_acceleratorInfoHeader.dylibTrieOffset], &_trieBytes[0], _trieBytes.size());
+}
+
+
+
+template <typename P>
+LinkeditOptimizer<P>::LinkeditOptimizer(void* cacheBuffer, macho_header<P>* mh, Diagnostics& diag)
+: _mh(mh), _cacheBuffer(cacheBuffer), _diagnostics(diag)
+{
+ _linkeditBias = (uint8_t*)cacheBuffer;
const unsigned origLoadCommandsSize = mh->sizeofcmds();
unsigned bytesRemaining = origLoadCommandsSize;
unsigned removedCount = 0;
- uint64_t textSegAddr = 0;
- int64_t slide = 0;
const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)mh + sizeof(macho_header<P>));
const uint32_t cmdCount = mh->ncmds();
const macho_load_command<P>* cmd = cmds;
@@ -222,6 +540,9 @@
for (uint32_t i = 0; i < cmdCount; ++i) {
bool remove = false;
switch (cmd->cmd()) {
+ case LC_ID_DYLIB:
+ _installName = ((macho_dylib_command<P>*)cmd)->name();
+ break;
case LC_SYMTAB:
_symTabCmd = (macho_symtab_command<P>*)cmd;
break;
@@ -238,10 +559,6 @@
break;
case LC_DATA_IN_CODE:
_dataInCodeCmd = (macho_linkedit_data_command<P>*)cmd;
- break;
- case LC_DYLD_EXPORTS_TRIE:
- _exportTrieCmd = (macho_linkedit_data_command<P>*)cmd;
- _exportInfoSize = _exportTrieCmd->datasize();
break;
case LC_ROUTINES:
case LC_ROUTINES_64:
@@ -262,14 +579,10 @@
case macho_segment_command<P>::CMD:
segCmd = (macho_segment_command<P>*)cmd;
_segCmds.push_back(segCmd);
- if ( strcmp(segCmd->segname(), "__TEXT") == 0 ) {
- textSegAddr = segCmd->vmaddr();
- slide = (uint64_t)mh - textSegAddr;
- }
- else if ( strcmp(segCmd->segname(), "__LINKEDIT") == 0 ) {
+ if ( strcmp(segCmd->segname(), "__LINKEDIT") == 0 ) {
+ _linkeditSize = (uint32_t)segCmd->vmsize();
+ _linkeditCacheOffset = (uint32_t)segCmd->fileoff();
_linkeditAddr = segCmd->vmaddr();
- _linkeditBias = (uint8_t*)mh + (_linkeditAddr - textSegAddr) - segCmd->fileoff();
- _linkeditSize = (uint32_t)segCmd->vmsize();
}
else if ( segCmd->nsects() > 0 ) {
macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)segCmd + sizeof(macho_segment_command<P>));
@@ -277,22 +590,14 @@
for (macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
const uint8_t type = sect->flags() & SECTION_TYPE;
if ( type == S_MOD_INIT_FUNC_POINTERS ) {
- const pint_t* inits = (pint_t*)(sect->addr()+slide);
+ const pint_t* inits = (pint_t*)((char*)cacheBuffer + sect->offset());
const size_t count = sect->size() / sizeof(pint_t);
for (size_t j=0; j < count; ++j) {
uint64_t func = P::getP(inits[j]);
_initializerAddresses.push_back(func);
}
}
- else if ( type == S_INIT_FUNC_OFFSETS ) {
- const uint32_t* inits = (uint32_t*)(sect->addr()+slide);
- const size_t count = sect->size() / sizeof(uint32_t);
- for (size_t j=0; j < count; ++j) {
- uint32_t funcOffset = E::get32(inits[j]);
- _initializerAddresses.push_back(textSegAddr + funcOffset);
- }
- }
- else if ( type == S_DTRACE_DOF ) {
+ else if ( type == S_DTRACE_DOF ) {
_dofSections.push_back(sect);
}
else if ( (strcmp(sect->sectname(), "__dyld") == 0) && (strncmp(sect->segname(), "__DATA", 6) == 0) ) {
@@ -301,7 +606,6 @@
}
}
break;
- case LC_DYLD_CHAINED_FIXUPS:
case LC_SEGMENT_SPLIT_INFO:
remove = true;
break;
@@ -322,11 +626,6 @@
// update header
mh->set_ncmds(cmdCount - removedCount);
mh->set_sizeofcmds(origLoadCommandsSize - bytesRemaining);
-}
-
-template <typename P>
-void LinkeditOptimizer<P>::setStripMode(DylibStripMode stripMode) {
- _stripMode = stripMode;
}
/*
@@ -432,22 +731,20 @@
_symTabCmd->set_strsize(sharedSymbolStringsSize);
// update dynamic symbol table to have proper offsets into shared symbol table
- if ( _dynSymTabCmd != nullptr ) {
- _dynSymTabCmd->set_ilocalsym(0);
- _dynSymTabCmd->set_nlocalsym(_newLocalSymbolCount);
- _dynSymTabCmd->set_iextdefsym(_newExportedSymbolsStartIndex-_newLocalSymbolsStartIndex);
- _dynSymTabCmd->set_nextdefsym(_newExportedSymbolCount);
- _dynSymTabCmd->set_iundefsym(_newImportedSymbolsStartIndex-_newLocalSymbolsStartIndex);
- _dynSymTabCmd->set_nundefsym(_newImportedSymbolCount);
- _dynSymTabCmd->set_tocoff(0);
- _dynSymTabCmd->set_ntoc(0);
- _dynSymTabCmd->set_modtaboff(0);
- _dynSymTabCmd->set_nmodtab(0);
- _dynSymTabCmd->set_indirectsymoff(mergedLinkeditStartOffset + _newIndirectSymbolTableOffset);
- _dynSymTabCmd->set_extreloff(0);
- _dynSymTabCmd->set_locreloff(0);
- _dynSymTabCmd->set_nlocrel(0);
- }
+ _dynSymTabCmd->set_ilocalsym(0);
+ _dynSymTabCmd->set_nlocalsym(_newLocalSymbolCount);
+ _dynSymTabCmd->set_iextdefsym(_newExportedSymbolsStartIndex-_newLocalSymbolsStartIndex);
+ _dynSymTabCmd->set_nextdefsym(_newExportedSymbolCount);
+ _dynSymTabCmd->set_iundefsym(_newImportedSymbolsStartIndex-_newLocalSymbolsStartIndex);
+ _dynSymTabCmd->set_nundefsym(_newImportedSymbolCount);
+ _dynSymTabCmd->set_tocoff(0);
+ _dynSymTabCmd->set_ntoc(0);
+ _dynSymTabCmd->set_modtaboff(0);
+ _dynSymTabCmd->set_nmodtab(0);
+ _dynSymTabCmd->set_indirectsymoff(mergedLinkeditStartOffset + _newIndirectSymbolTableOffset);
+ _dynSymTabCmd->set_extreloff(0);
+ _dynSymTabCmd->set_locreloff(0);
+ _dynSymTabCmd->set_nlocrel(0);
// update dyld info
if ( _dyldInfo != nullptr ) {
@@ -457,8 +754,6 @@
_dyldInfo->set_weak_bind_off(_dyldInfo->weak_bind_size() ? mergedLinkeditStartOffset + _newWeakBindingInfoOffset : 0 );
_dyldInfo->set_lazy_bind_off(_dyldInfo->lazy_bind_size() ? mergedLinkeditStartOffset + _newLazyBindingInfoOffset : 0 );
_dyldInfo->set_export_off(mergedLinkeditStartOffset + _newExportInfoOffset);
- } else if ( _exportTrieCmd != nullptr ) {
- _exportTrieCmd->set_dataoff(mergedLinkeditStartOffset + _newExportInfoOffset);
}
// update function-starts
@@ -514,15 +809,13 @@
template <typename P>
void LinkeditOptimizer<P>::copyExportInfo(uint8_t* newLinkEditContent, uint32_t& offset)
{
- if ( (_dyldInfo == nullptr) && (_exportTrieCmd == nullptr) )
+ if ( _dyldInfo == nullptr )
return;
-
- uint32_t exportOffset = _exportTrieCmd ? _exportTrieCmd->dataoff() : _dyldInfo->export_off();
- uint32_t exportSize = _exportTrieCmd ? _exportTrieCmd->datasize() : _dyldInfo->export_size();
- if ( exportSize != 0 ) {
- ::memcpy(&newLinkEditContent[offset], &_linkeditBias[exportOffset], exportSize);
+ unsigned size = _dyldInfo->export_size();
+ if ( size != 0 ) {
+ ::memcpy(&newLinkEditContent[offset], &_linkeditBias[_dyldInfo->export_off()], size);
_newExportInfoOffset = offset;
- offset += exportSize;
+ offset += size;
}
}
@@ -555,27 +848,11 @@
bool redact, std::vector<LocalSymbolInfo>& localSymbolInfos,
std::vector<macho_nlist<P>>& unmappedLocalSymbols, SortedStringPool<P>& localSymbolsStringPool)
{
- localSymbolInfos.push_back(LocalSymbolInfo());
-
- LocalSymbolInfo& localInfo = localSymbolInfos.back();
- localInfo.dylibOffset = (uint32_t)(((uint8_t*)_mh) - (uint8_t*)_containerBuffer);
+ LocalSymbolInfo localInfo;
+ localInfo.dylibOffset = (uint32_t)(((uint8_t*)_mh) - (uint8_t*)_cacheBuffer);
localInfo.nlistStartIndex = (uint32_t)unmappedLocalSymbols.size();
localInfo.nlistCount = 0;
_newLocalSymbolsStartIndex = symbolIndex;
- _newLocalSymbolCount = 0;
-
- switch (_stripMode) {
- case CacheBuilder::DylibStripMode::stripNone:
- case CacheBuilder::DylibStripMode::stripExports:
- break;
- case CacheBuilder::DylibStripMode::stripLocals:
- case CacheBuilder::DylibStripMode::stripAll:
- return;
- }
-
- if ( _dynSymTabCmd == nullptr )
- return;
-
const char* strings = (char*)&_linkeditBias[_symTabCmd->stroff()];
const macho_nlist<P>* const symbolTable = (macho_nlist<P>*)(&_linkeditBias[_symTabCmd->symoff()]);
const macho_nlist<P>* const firstExport = &symbolTable[_dynSymTabCmd->ilocalsym()];
@@ -608,6 +885,7 @@
}
_newLocalSymbolCount = symbolIndex - _newLocalSymbolsStartIndex;
localInfo.nlistCount = (uint32_t)unmappedLocalSymbols.size() - localInfo.nlistStartIndex;
+ localSymbolInfos.push_back(localInfo);
}
@@ -615,20 +893,6 @@
void LinkeditOptimizer<P>::copyExportedSymbols(uint8_t* newLinkEditContent, SortedStringPool<P>& stringPool, uint32_t& offset, uint32_t& symbolIndex)
{
_newExportedSymbolsStartIndex = symbolIndex;
- _newExportedSymbolCount = 0;
-
- switch (_stripMode) {
- case CacheBuilder::DylibStripMode::stripNone:
- case CacheBuilder::DylibStripMode::stripLocals:
- break;
- case CacheBuilder::DylibStripMode::stripExports:
- case CacheBuilder::DylibStripMode::stripAll:
- return;
- }
-
- if ( _dynSymTabCmd == nullptr )
- return;
-
const char* strings = (char*)&_linkeditBias[_symTabCmd->stroff()];
const macho_nlist<P>* const symbolTable = (macho_nlist<P>*)(&_linkeditBias[_symTabCmd->symoff()]);
const macho_nlist<P>* const firstExport = &symbolTable[_dynSymTabCmd->iextdefsym()];
@@ -657,20 +921,6 @@
void LinkeditOptimizer<P>::copyImportedSymbols(uint8_t* newLinkEditContent, SortedStringPool<P>& stringPool, uint32_t& offset, uint32_t& symbolIndex)
{
_newImportedSymbolsStartIndex = symbolIndex;
- _newImportedSymbolCount = 0;
-
- if ( _dynSymTabCmd == nullptr )
- return;
-
- switch (_stripMode) {
- case CacheBuilder::DylibStripMode::stripNone:
- break;
- case CacheBuilder::DylibStripMode::stripLocals:
- case CacheBuilder::DylibStripMode::stripExports:
- case CacheBuilder::DylibStripMode::stripAll:
- return;
- }
-
const char* strings = (char*)&_linkeditBias[_symTabCmd->stroff()];
const macho_nlist<P>* const symbolTable = (macho_nlist<P>*)(&_linkeditBias[_symTabCmd->symoff()]);
const macho_nlist<P>* const firstImport = &symbolTable[_dynSymTabCmd->iundefsym()];
@@ -695,13 +945,9 @@
void LinkeditOptimizer<P>::copyIndirectSymbolTable(uint8_t* newLinkEditContent, uint32_t& offset)
{
_newIndirectSymbolTableOffset = offset;
-
- if ( _dynSymTabCmd == nullptr )
- return;
-
const uint32_t* const indirectTable = (uint32_t*)&_linkeditBias[_dynSymTabCmd->indirectsymoff()];
uint32_t* newIndirectTable = (uint32_t*)&newLinkEditContent[offset];
- for (uint32_t i=0; i < _dynSymTabCmd->nindirectsyms(); ++i) {
+ for (int i=0; i < _dynSymTabCmd->nindirectsyms(); ++i) {
uint32_t symbolIndex = E::get32(indirectTable[i]);
if ( (symbolIndex == INDIRECT_SYMBOL_ABS) || (symbolIndex == INDIRECT_SYMBOL_LOCAL) )
E::set32(newIndirectTable[i], symbolIndex);
@@ -712,63 +958,63 @@
}
template <typename P>
-void LinkeditOptimizer<P>::mergeLinkedits(CacheBuilder& builder,
- CacheBuilder::UnmappedRegion* localSymbolsRegion,
- std::vector<LinkeditOptimizer<P>*>& optimizers)
+uint64_t mergeLinkedits(DyldSharedCache* cache, bool dontMapLocalSymbols, bool addAcceleratorTables, std::vector<LinkeditOptimizer<P>*>& optimizers, Diagnostics& diagnostics, dyld_cache_local_symbols_info** localsInfo)
{
// allocate space for new linkedit data
- uint64_t totalUnoptLinkeditsSize = builder._readOnlyRegion.sizeInUse - builder._nonLinkEditReadOnlySize;
+ uint32_t linkeditStartOffset = 0xFFFFFFFF;
+ uint32_t linkeditEndOffset = 0;
+ uint64_t linkeditStartAddr = 0;
+ for (LinkeditOptimizer<P>* op : optimizers) {
+ uint32_t leOffset = op->linkeditOffset();
+ if ( leOffset < linkeditStartOffset ) {
+ linkeditStartOffset = leOffset;
+ linkeditStartAddr = op->linkeditAddr();
+ }
+ uint32_t leEndOffset = op->linkeditOffset() + op->linkeditSize();
+ if ( leEndOffset > linkeditEndOffset )
+ linkeditEndOffset = leEndOffset;
+ }
+ uint64_t totalUnoptLinkeditsSize = linkeditEndOffset - linkeditStartOffset;
uint8_t* newLinkEdit = (uint8_t*)calloc(totalUnoptLinkeditsSize, 1);
SortedStringPool<P> stringPool;
uint32_t offset = 0;
- builder._diagnostics.verbose("Merged LINKEDIT:\n");
+ diagnostics.verbose("Merged LINKEDIT:\n");
// copy weak binding info
uint32_t startWeakBindInfosOffset = offset;
for (LinkeditOptimizer<P>* op : optimizers) {
- // Skip chained fixups as the in-place linked list isn't valid any more
- const dyld3::MachOFile* mf = (dyld3::MachOFile*)op->machHeader();
- if (!mf->hasChainedFixups())
- op->copyWeakBindingInfo(newLinkEdit, offset);
- }
- builder._diagnostics.verbose(" weak bindings size: %5uKB\n", (uint32_t)(offset-startWeakBindInfosOffset)/1024);
+ op->copyWeakBindingInfo(newLinkEdit, offset);
+ }
+ diagnostics.verbose(" weak bindings size: %5uKB\n", (uint32_t)(offset-startWeakBindInfosOffset)/1024);
// copy export info
uint32_t startExportInfosOffset = offset;
for (LinkeditOptimizer<P>* op : optimizers) {
op->copyExportInfo(newLinkEdit, offset);
}
- builder._diagnostics.verbose(" exports info size: %5uKB\n", (uint32_t)(offset-startExportInfosOffset)/1024);
+ diagnostics.verbose(" exports info size: %5uKB\n", (uint32_t)(offset-startExportInfosOffset)/1024);
// in theory, an optimized cache can drop the binding info
if ( true ) {
// copy binding info
uint32_t startBindingsInfosOffset = offset;
for (LinkeditOptimizer<P>* op : optimizers) {
- // Skip chained fixups as the in-place linked list isn't valid any more
- const dyld3::MachOFile* mf = (dyld3::MachOFile*)op->machHeader();
- if (!mf->hasChainedFixups())
- op->copyBindingInfo(newLinkEdit, offset);
- }
- builder._diagnostics.verbose(" bindings size: %5uKB\n", (uint32_t)(offset-startBindingsInfosOffset)/1024);
+ op->copyBindingInfo(newLinkEdit, offset);
+ }
+ diagnostics.verbose(" bindings size: %5uKB\n", (uint32_t)(offset-startBindingsInfosOffset)/1024);
// copy lazy binding info
uint32_t startLazyBindingsInfosOffset = offset;
for (LinkeditOptimizer<P>* op : optimizers) {
- // Skip chained fixups as the in-place linked list isn't valid any more
- const dyld3::MachOFile* mf = (dyld3::MachOFile*)op->machHeader();
- if (!mf->hasChainedFixups())
- op->copyLazyBindingInfo(newLinkEdit, offset);
- }
- builder._diagnostics.verbose(" lazy bindings size: %5uKB\n", (offset-startLazyBindingsInfosOffset)/1024);
- }
-
- bool unmapLocals = ( builder._options.localSymbolMode == DyldSharedCache::LocalSymbolsMode::unmap );
+ op->copyLazyBindingInfo(newLinkEdit, offset);
+ }
+ diagnostics.verbose(" lazy bindings size: %5uKB\n", (offset-startLazyBindingsInfosOffset)/1024);
+ }
// copy symbol table entries
std::vector<macho_nlist<P>> unmappedLocalSymbols;
- if ( unmapLocals )
+ if ( dontMapLocalSymbols )
unmappedLocalSymbols.reserve(0x01000000);
std::vector<LocalSymbolInfo> localSymbolInfos;
localSymbolInfos.reserve(optimizers.size());
@@ -778,7 +1024,7 @@
uint32_t sharedSymbolTableExportsCount = 0;
uint32_t sharedSymbolTableImportsCount = 0;
for (LinkeditOptimizer<P>* op : optimizers) {
- op->copyLocalSymbols(newLinkEdit, stringPool, offset, symbolIndex, unmapLocals,
+ op->copyLocalSymbols(newLinkEdit, stringPool, offset, symbolIndex, dontMapLocalSymbols,
localSymbolInfos, unmappedLocalSymbols, localSymbolsStringPool);
uint32_t x = symbolIndex;
op->copyExportedSymbols(newLinkEdit, stringPool, offset, symbolIndex);
@@ -795,14 +1041,14 @@
for (LinkeditOptimizer<P>* op : optimizers) {
op->copyFunctionStarts(newLinkEdit, offset);
}
- builder._diagnostics.verbose(" function starts size: %5uKB\n", (offset-startFunctionStartsOffset)/1024);
+ diagnostics.verbose(" function starts size: %5uKB\n", (offset-startFunctionStartsOffset)/1024);
// copy data-in-code info
uint32_t startDataInCodeOffset = offset;
for (LinkeditOptimizer<P>* op : optimizers) {
op->copyDataInCode(newLinkEdit, offset);
}
- builder._diagnostics.verbose(" data in code size: %5uKB\n", (offset-startDataInCodeOffset)/1024);
+ diagnostics.verbose(" data in code size: %5uKB\n", (offset-startDataInCodeOffset)/1024);
// copy indirect symbol tables
for (LinkeditOptimizer<P>* op : optimizers) {
@@ -817,18 +1063,41 @@
uint32_t sharedSymbolStringsSize = stringPool.copyPoolAndUpdateOffsets((char*)&newLinkEdit[sharedSymbolStringsOffset], (macho_nlist<P>*)&newLinkEdit[sharedSymbolTableStartOffset]);
offset += sharedSymbolStringsSize;
uint32_t newLinkeditUnalignedSize = offset;
- uint64_t newLinkeditAlignedSize = align(offset, 14);
- builder._diagnostics.verbose(" symbol table size: %5uKB (%d exports, %d imports)\n", (sharedSymbolTableEndOffset-sharedSymbolTableStartOffset)/1024, sharedSymbolTableExportsCount, sharedSymbolTableImportsCount);
- builder._diagnostics.verbose(" symbol string pool size: %5uKB\n", sharedSymbolStringsSize/1024);
+ uint64_t newLinkeditEnd = align(linkeditStartOffset+newLinkeditUnalignedSize, 14);
+ diagnostics.verbose(" symbol table size: %5uKB (%d exports, %d imports)\n", (sharedSymbolTableEndOffset-sharedSymbolTableStartOffset)/1024, sharedSymbolTableExportsCount, sharedSymbolTableImportsCount);
+ diagnostics.verbose(" symbol string pool size: %5uKB\n", sharedSymbolStringsSize/1024);
// overwrite mapped LINKEDIT area in cache with new merged LINKEDIT content
- builder._diagnostics.verbose("LINKEDITS optimized from %uMB to %uMB\n", (uint32_t)totalUnoptLinkeditsSize/(1024*1024), (uint32_t)newLinkeditUnalignedSize/(1024*1024));
- ::memcpy(builder._readOnlyRegion.buffer+builder._nonLinkEditReadOnlySize, newLinkEdit, newLinkeditAlignedSize);
+ diagnostics.verbose("LINKEDITS optimized from %uMB to %uMB\n", (uint32_t)totalUnoptLinkeditsSize/(1024*1024), (uint32_t)newLinkeditUnalignedSize/(1024*1024));
+ ::memcpy((char*)cache + linkeditStartOffset, newLinkEdit, newLinkeditUnalignedSize);
+ ::bzero((char*)cache + linkeditStartOffset+newLinkeditUnalignedSize, totalUnoptLinkeditsSize-newLinkeditUnalignedSize);
::free(newLinkEdit);
- builder._readOnlyRegion.sizeInUse = builder._nonLinkEditReadOnlySize + newLinkeditAlignedSize;
+
+ // If making cache for customers, add extra accelerator tables for dyld
+ if ( addAcceleratorTables ) {
+ AcceleratorTables<P> tables(cache, linkeditStartAddr, diagnostics, optimizers);
+ uint32_t tablesSize = tables.totalSize();
+ if ( tablesSize < (totalUnoptLinkeditsSize-newLinkeditUnalignedSize) ) {
+ tables.copyTo((uint8_t*)cache+newLinkeditEnd);
+ newLinkeditEnd += tablesSize;
+ uint64_t accelInfoAddr = align(linkeditStartAddr + newLinkeditUnalignedSize, 14);
+ cache->header.accelerateInfoAddr = accelInfoAddr;
+ cache->header.accelerateInfoSize = tablesSize;
+ diagnostics.verbose("Accelerator tables %uMB\n", (uint32_t)tablesSize/(1024*1024));
+ }
+ else {
+ diagnostics.warning("not enough room to add dyld accelerator tables");
+ }
+ }
+
+ // update mapping to reduce linkedit size
+ dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)((char*)cache + cache->header.mappingOffset);
+ mappings[2].size = newLinkeditEnd - mappings[2].fileOffset;
// overwrite end of un-opt linkedits to create a new unmapped region for local symbols
- if ( unmapLocals ) {
+ uint64_t newFileSize = newLinkeditEnd;
+ if ( dontMapLocalSymbols ) {
+ typedef typename P::E E;
const uint32_t entriesOffset = sizeof(dyld_cache_local_symbols_info);
const uint32_t entriesCount = (uint32_t)localSymbolInfos.size();
const uint32_t nlistOffset = (uint32_t)align(entriesOffset + entriesCount * sizeof(dyld_cache_local_symbols_info), 4); // 16-byte align start
@@ -837,60 +1106,50 @@
const uint32_t stringsOffset = nlistOffset + nlistCount * sizeof(macho_nlist<P>);
// allocate buffer for local symbols
const size_t localsBufferSize = align(stringsOffset + stringsSize, 14);
- vm_address_t localsBuffer;
- if ( ::vm_allocate(mach_task_self(), &localsBuffer, localsBufferSize, VM_FLAGS_ANYWHERE) == 0 ) {
- dyld_cache_local_symbols_info* infoHeader = (dyld_cache_local_symbols_info*)localsBuffer;
- // fill in header info
- infoHeader->nlistOffset = nlistOffset;
- infoHeader->nlistCount = nlistCount;
- infoHeader->stringsOffset = stringsOffset;
- infoHeader->stringsSize = stringsSize;
- infoHeader->entriesOffset = entriesOffset;
- infoHeader->entriesCount = entriesCount;
- // copy info for each dylib
- dyld_cache_local_symbols_entry* entries = (dyld_cache_local_symbols_entry*)(((uint8_t*)infoHeader)+entriesOffset);
- for (uint32_t i=0; i < entriesCount; ++i) {
- entries[i].dylibOffset = localSymbolInfos[i].dylibOffset;
- entries[i].nlistStartIndex = localSymbolInfos[i].nlistStartIndex;
- entries[i].nlistCount = localSymbolInfos[i].nlistCount;
- }
- // copy nlists
- macho_nlist<P>* newLocalsSymbolTable = (macho_nlist<P>*)(localsBuffer+nlistOffset);
- ::memcpy(newLocalsSymbolTable, &unmappedLocalSymbols[0], nlistCount*sizeof(macho_nlist<P>));
- // copy string pool
- localSymbolsStringPool.copyPoolAndUpdateOffsets(((char*)infoHeader)+stringsOffset, newLocalsSymbolTable);
- // return buffer of local symbols, caller to free() it
- localSymbolsRegion->buffer = (uint8_t*)localsBuffer;
- localSymbolsRegion->bufferSize = localsBufferSize;
- localSymbolsRegion->sizeInUse = localsBufferSize;
- }
- else {
- builder._diagnostics.warning("could not allocate local symbols");
- }
+ dyld_cache_local_symbols_info* infoHeader = (dyld_cache_local_symbols_info*)malloc(localsBufferSize);
+ // fill in header info
+ infoHeader->nlistOffset = nlistOffset;
+ infoHeader->nlistCount = nlistCount;
+ infoHeader->stringsOffset = stringsOffset;
+ infoHeader->stringsSize = stringsSize;
+ infoHeader->entriesOffset = entriesOffset;
+ infoHeader->entriesCount = entriesCount;
+ // copy info for each dylib
+ dyld_cache_local_symbols_entry* entries = (dyld_cache_local_symbols_entry*)(((uint8_t*)infoHeader)+entriesOffset);
+ for (int i=0; i < entriesCount; ++i) {
+ entries[i].dylibOffset = localSymbolInfos[i].dylibOffset;
+ entries[i].nlistStartIndex = localSymbolInfos[i].nlistStartIndex;
+ entries[i].nlistCount = localSymbolInfos[i].nlistCount;
+ }
+ // copy nlists
+ macho_nlist<P>* newLocalsSymbolTable = (macho_nlist<P>*)(((uint8_t*)infoHeader)+nlistOffset);
+ ::memcpy(newLocalsSymbolTable, &unmappedLocalSymbols[0], nlistCount*sizeof(macho_nlist<P>));
+ // copy string pool
+ localSymbolsStringPool.copyPoolAndUpdateOffsets(((char*)infoHeader)+stringsOffset, newLocalsSymbolTable);
+ // return buffer of local symbols, caller to free() it
+ *localsInfo = infoHeader;
}
// update all load commands to new merged layout
- uint64_t linkeditsUnslidStartAddr = builder._readOnlyRegion.unslidLoadAddress + builder._nonLinkEditReadOnlySize;
- uint32_t linkeditsCacheFileOffset = (uint32_t)(builder._readOnlyRegion.cacheFileOffset + builder._nonLinkEditReadOnlySize);
for (LinkeditOptimizer<P>* op : optimizers) {
- op->updateLoadCommands(linkeditsCacheFileOffset, linkeditsUnslidStartAddr, newLinkeditUnalignedSize,
+ op->updateLoadCommands(linkeditStartOffset, linkeditStartAddr, newLinkeditEnd-linkeditStartOffset,
sharedSymbolTableStartOffset, sharedSymbolTableCount,
sharedSymbolStringsOffset, sharedSymbolStringsSize);
}
-}
-
-
-template <typename P>
-void LinkeditOptimizer<P>::optimizeLinkedit(CacheBuilder& builder, const void* containerBuffer,
- CacheBuilder::UnmappedRegion* localSymbolsRegion,
- const std::vector<std::tuple<const mach_header*, const char*, DylibStripMode>>& images)
+
+ return newFileSize;
+}
+
+} // anonymous namespace
+
+template <typename P>
+uint64_t optimizeLinkedit(DyldSharedCache* cache, bool dontMapLocalSymbols, bool addAcceleratorTables, const std::vector<uint64_t>& branchPoolOffsets, Diagnostics& diag, dyld_cache_local_symbols_info** localsInfo)
{
// construct a LinkeditOptimizer for each image
__block std::vector<LinkeditOptimizer<P>*> optimizers;
- for (std::tuple<const mach_header*, const char*, DylibStripMode> image : images) {
- optimizers.push_back(new LinkeditOptimizer<P>(containerBuffer, (macho_header<P>*)std::get<0>(image), std::get<1>(image), builder._diagnostics));
- optimizers.back()->setStripMode(std::get<2>(image));
- }
+ cache->forEachImage(^(const mach_header* mh, const char*) {
+ optimizers.push_back(new LinkeditOptimizer<P>(cache, (macho_header<P>*)mh, diag));
+ });
#if 0
// add optimizer for each branch pool
for (uint64_t poolOffset : branchPoolOffsets) {
@@ -899,26 +1158,24 @@
}
#endif
// merge linkedit info
- mergeLinkedits(builder, localSymbolsRegion, optimizers);
+ uint64_t newFileSize = mergeLinkedits(cache, dontMapLocalSymbols, addAcceleratorTables, optimizers, diag, localsInfo);
// delete optimizers
for (LinkeditOptimizer<P>* op : optimizers)
delete op;
-}
-
-void CacheBuilder::optimizeLinkedit(UnmappedRegion* localSymbolsRegion,
- const std::vector<std::tuple<const mach_header*, const char*, DylibStripMode>>& images)
-{
- const void* buffer = (const void*)_fullAllocatedBuffer;
- if ( _is64 ) {
- return LinkeditOptimizer<Pointer64<LittleEndian>>::optimizeLinkedit(*this, buffer,
- localSymbolsRegion, images);
+
+ return newFileSize;
+}
+
+uint64_t optimizeLinkedit(DyldSharedCache* cache, bool is64, bool dontMapLocalSymbols, bool addAcceleratorTables, const std::vector<uint64_t>& branchPoolOffsets, Diagnostics& diag, dyld_cache_local_symbols_info** localsInfo)
+{
+ if ( is64) {
+ return optimizeLinkedit<Pointer64<LittleEndian>>(cache, dontMapLocalSymbols, addAcceleratorTables, branchPoolOffsets, diag, localsInfo);
}
else {
- return LinkeditOptimizer<Pointer32<LittleEndian>>::optimizeLinkedit(*this, buffer,
- localSymbolsRegion, images);
- }
-}
-
-
-
+ return optimizeLinkedit<Pointer32<LittleEndian>>(cache, dontMapLocalSymbols, addAcceleratorTables, branchPoolOffsets, diag, localsInfo);
+ }
+}
+
+
+