1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.h>
28 #include <mach/mach.h>
29 #include <mach/mach_time.h>
40 #include <sys/param.h>
41 #include <sys/sysctl.h>
42 #include <sys/resource.h>
44 #include <servers/bootstrap.h>
45 #include <mach-o/loader.h>
46 #include <mach-o/fat.h>
48 #include "dyld_cache_format.h"
53 #include <ext/hash_map>
55 #include "Architectures.hpp"
56 #include "MachOLayout.hpp"
57 #include "MachORebaser.hpp"
58 #include "MachOBinder.hpp"
59 #include "CacheFileAbstraction.hpp"
62 #include <objc/objc-selopt.h>
64 #define FIRST_DYLIB_TEXT_OFFSET 0x5000
65 #define FIRST_DYLIB_DATA_OFFSET 0x1000
67 #ifndef LC_FUNCTION_STARTS
68 #define LC_FUNCTION_STARTS 0x26
71 static bool verbose
= false;
72 static bool progress
= false;
73 static bool iPhoneOS
= false;
74 static std::vector
<const char*> warnings
;
77 static void warn(const char *arch
, const char *format
, ...)
82 va_start(args
, format
);
83 ::vasprintf(&msg
, format
, args
);
86 warnings
.push_back(msg
);
89 ::fprintf(::stderr
, "update_dyld_shared_cache: warning: %s%s%s%s\n",
90 arch
? "for arch " : "",
98 static uint64_t pageAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
103 struct CStringEquals
{
104 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
106 typedef __gnu_cxx::hash_map
<const char*, const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> StringToString
;
108 static void addArchPair(ArchPair ap
);
109 static void addRoot(const char* vpath
, const std::set
<ArchPair
>& archs
);
110 static void findSharedDylibs(ArchPair ap
);
111 static ArchGraph
* graphForArchPair(ArchPair ap
) { return fgPerArchGraph
[ap
]; }
112 static void setFileSystemRoot(const char* root
, bool usesOverlay
) { fgFileSystemRoot
= root
; fgUsesOverlay
= usesOverlay
; }
113 static const char* archName(ArchPair ap
);
115 ArchPair
getArchPair() { return fArchPair
; }
116 std::set
<const class MachOLayoutAbstraction
*>& getSharedDylibs() { return fSharedDylibs
; }
117 StringToString
& getDylibAliases() { return fAliasesMap
; }
118 const char* archName() { return archName(fArchPair
); }
125 DependencyNode(ArchGraph
*, const char* path
, const MachOLayoutAbstraction
* layout
);
126 void loadDependencies(const MachOLayoutAbstraction
*);
127 void markNeededByRoot(DependencyNode
*);
128 const char* getPath() const { return fPath
; }
129 const MachOLayoutAbstraction
* getLayout() const { return fLayout
; }
130 size_t useCount() const { return fRootsDependentOnThis
.size(); }
131 bool allDependentsFound() const { return !fDependentMissing
; }
135 const MachOLayoutAbstraction
* fLayout
;
136 bool fDependenciesLoaded
;
137 bool fDependentMissing
;
138 std::set
<DependencyNode
*> fDependsOn
;
139 std::set
<DependencyNode
*> fRootsDependentOnThis
;
142 typedef __gnu_cxx::hash_map
<const char*, class DependencyNode
*, __gnu_cxx::hash
<const char*>, CStringEquals
> PathToNode
;
145 ArchGraph(ArchPair ap
) : fArchPair(ap
) {}
146 void addRoot(const char* path
, const MachOLayoutAbstraction
*);
147 DependencyNode
* getNode(const char* path
);
148 DependencyNode
* getNodeForVirtualPath(const char* vpath
);
149 static bool canBeShared(const MachOLayoutAbstraction
* layout
, ArchPair ap
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
);
150 static bool sharable(const MachOLayoutAbstraction
* layout
, ArchPair ap
, char** msg
);
152 static std::map
<ArchPair
, ArchGraph
*> fgPerArchGraph
;
153 static const char* fgFileSystemRoot
;
154 static bool fgUsesOverlay
;
157 std::set
<DependencyNode
*> fRoots
;
159 std::set
<const MachOLayoutAbstraction
*> fSharedDylibs
; // use set to avoid duplicates when installname!=realpath
160 StringToString fAliasesMap
;
162 std::map
<ArchPair
, ArchGraph
*> ArchGraph::fgPerArchGraph
;
163 const char* ArchGraph::fgFileSystemRoot
= "";
164 bool ArchGraph::fgUsesOverlay
= false;
166 void ArchGraph::addArchPair(ArchPair ap
)
168 //fprintf(stderr, "adding ArchPair 0x%08X,0x%08X\n", ap.arch, ap.subtype);
169 fgPerArchGraph
[ap
] = new ArchGraph(ap
);
172 void ArchGraph::addRoot(const char* vpath
, const std::set
<ArchPair
>& onlyArchs
)
174 char completePath
[strlen(fgFileSystemRoot
)+strlen(vpath
)+2];
175 const char* path
= NULL
;
176 if ( strlen(fgFileSystemRoot
) == 0 ) {
180 strcpy(completePath
, fgFileSystemRoot
);
181 strcat(completePath
, vpath
); // assumes vpath starts with '/'
182 if ( fgUsesOverlay
) {
183 // using -overlay means if /overlay/usr/lib exists use it, otherwise use original path
184 struct stat stat_buf
;
185 if ( stat(completePath
, &stat_buf
) == 0 )
191 // using -root means alway redirect /usr/lib to /rootpath/usr/lib
196 const UniversalMachOLayout
& uni
= UniversalMachOLayout::find(path
, &onlyArchs
);
197 for(std::set
<ArchPair
>::iterator ait
= onlyArchs
.begin(); ait
!= onlyArchs
.end(); ++ait
) {
199 const MachOLayoutAbstraction
* layout
= uni
.getSlice(*ait
);
200 if ( layout
!= NULL
)
201 fgPerArchGraph
[*ait
]->addRoot(path
, layout
);
203 catch (const char* msg
) {
205 fprintf(stderr
, "update_dyld_shared_cache: warning for %s can't use root '%s': %s\n", fgPerArchGraph
[*ait
]->archName(), path
, msg
);
210 catch (const char* msg
) {
211 fprintf(stderr
, "update_dyld_shared_cache: warning can't use root '%s': %s\n", path
, msg
);
217 void ArchGraph::addRoot(const char* path
, const MachOLayoutAbstraction
* layout
)
220 fprintf(stderr
, "update_dyld_shared_cache: adding root: %s\n", path
);
221 DependencyNode
* node
= this->getNode(path
);
223 const MachOLayoutAbstraction
* mainExecutableLayout
= NULL
;
224 if ( layout
->getFileType() == MH_EXECUTE
)
225 mainExecutableLayout
= layout
;
226 node
->loadDependencies(mainExecutableLayout
);
227 node
->markNeededByRoot(node
);
228 if ( layout
->getFileType() == MH_DYLIB
)
229 node
->markNeededByRoot(NULL
);
232 // a virtual path does not have the fgFileSystemRoot prefix
233 // a virtual path does not have the fgFileSystemRoot prefix
234 ArchGraph::DependencyNode
* ArchGraph::getNodeForVirtualPath(const char* vpath
)
236 if ( fgFileSystemRoot
== NULL
) {
237 return this->getNode(vpath
);
240 char completePath
[strlen(fgFileSystemRoot
)+strlen(vpath
)+2];
241 strcpy(completePath
, fgFileSystemRoot
);
242 strcat(completePath
, vpath
); // assumes vpath starts with '/'
243 if ( fgUsesOverlay
) {
244 // using -overlay means if /overlay/path/dylib exists use it, otherwise use /path/dylib
245 struct stat stat_buf
;
246 if ( stat(completePath
, &stat_buf
) == 0 )
247 return this->getNode(completePath
);
249 // <rdar://problem/9279770> support when install name is a symlink
250 if ( (lstat(vpath
, &stat_buf
) == 0) && S_ISLNK(stat_buf
.st_mode
) ) {
251 // requested path did not exist in /overlay, but leaf of path is a symlink in /
252 char pathInSymLink
[MAXPATHLEN
];
253 size_t res
= readlink(vpath
, pathInSymLink
, sizeof(pathInSymLink
));
255 pathInSymLink
[res
] = '\0';
256 if ( pathInSymLink
[0] != '/' ) {
257 char symFullPath
[MAXPATHLEN
];
258 strcpy(symFullPath
, vpath
);
259 char* lastSlash
= strrchr(symFullPath
, '/');
260 if ( lastSlash
!= NULL
) {
261 strcpy(lastSlash
+1, pathInSymLink
);
262 // (re)try looking for what symlink points to, but in /overlay
263 return this->getNodeForVirtualPath(symFullPath
);
268 return this->getNode(vpath
);
272 // using -root means always use /rootpath/usr/lib
273 return this->getNode(completePath
);
278 ArchGraph::DependencyNode
* ArchGraph::getNode(const char* path
)
280 // look up supplied path to see if node already exists
281 PathToNode::iterator pos
= fNodes
.find(path
);
282 if ( pos
!= fNodes
.end() )
286 char realPath
[MAXPATHLEN
];
287 if ( realpath(path
, realPath
) == NULL
)
288 throwf("realpath() failed on %s\n", path
);
290 // look up real path to see if node already exists
291 pos
= fNodes
.find(realPath
);
292 if ( pos
!= fNodes
.end() ) {
293 // update fAliasesMap with symlinks found
294 const char* aliasPath
= path
;
295 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(path
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
296 aliasPath
= &path
[strlen(fgFileSystemRoot
)];
298 if ( fAliasesMap
.find(aliasPath
) == fAliasesMap
.end() ) {
299 if ( strcmp(aliasPath
, pos
->second
->getLayout()->getID().name
) != 0 ) {
300 fAliasesMap
[strdup(aliasPath
)] = pos
->second
->getLayout()->getID().name
;
301 //fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
307 // still does not exist, so create a new node
308 const UniversalMachOLayout
& uni
= UniversalMachOLayout::find(realPath
);
309 DependencyNode
* node
= new DependencyNode(this, realPath
, uni
.getSlice(fArchPair
));
310 if ( node
->getLayout() == NULL
) {
311 throwf("%s is missing arch %s", realPath
, archName(fArchPair
));
313 // add realpath to node map
314 fNodes
[node
->getPath()] = node
;
315 // if install name is not real path, add install name to node map
316 if ( (node
->getLayout()->getFileType() == MH_DYLIB
) && (strcmp(realPath
, node
->getLayout()->getID().name
) != 0) ) {
317 //fprintf(stderr, "adding %s node alias %s for %s\n", archName(fArchPair), node->getLayout()->getID().name, realPath);
318 pos
= fNodes
.find(node
->getLayout()->getID().name
);
319 if ( pos
!= fNodes
.end() ) {
320 // <rdar://problem/8305479> warn if two dylib in cache have same install_name
322 asprintf(&msg
, "update_dyld_shared_cache: warning, found two dylibs with same install path: %s\n\t%s\n\t%s\n",
323 node
->getLayout()->getID().name
, pos
->second
->getPath(), node
->getPath());
324 fprintf(stderr
, "%s", msg
);
325 warnings
.push_back(msg
);
328 fNodes
[node
->getLayout()->getID().name
] = node
;
329 // update fAliasesMap with symlinks found
330 const char* aliasPath
= realPath
;
331 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(realPath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
332 aliasPath
= &realPath
[strlen(fgFileSystemRoot
)];
334 if ( fAliasesMap
.find(aliasPath
) == fAliasesMap
.end() ) {
335 if ( strcmp(aliasPath
, node
->getLayout()->getID().name
) != 0 ) {
336 fAliasesMap
[strdup(aliasPath
)] = node
->getLayout()->getID().name
;
337 //fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
345 void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction
* mainExecutableLayout
)
347 if ( !fDependenciesLoaded
) {
348 fDependenciesLoaded
= true;
350 const std::vector
<MachOLayoutAbstraction::Library
>& dependsOn
= fLayout
->getLibraries();
351 for(std::vector
<MachOLayoutAbstraction::Library
>::const_iterator it
= dependsOn
.begin(); it
!= dependsOn
.end(); ++it
) {
353 const char* dependentPath
= it
->name
;
354 if ( strncmp(dependentPath
, "@executable_path/", 17) == 0 ) {
355 if ( mainExecutableLayout
== NULL
)
356 throw "@executable_path without main executable";
357 // expand @executable_path path prefix
358 const char* executablePath
= mainExecutableLayout
->getFilePath();
359 char newPath
[strlen(executablePath
) + strlen(dependentPath
)+2];
360 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(executablePath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
361 // executablePath already has rootPath prefix, need to remove that to get to base virtual path
362 strcpy(newPath
, &executablePath
[strlen(fgFileSystemRoot
)]);
365 strcpy(newPath
, executablePath
);
367 char* addPoint
= strrchr(newPath
,'/');
368 if ( addPoint
!= NULL
)
369 strcpy(&addPoint
[1], &dependentPath
[17]);
371 strcpy(newPath
, &dependentPath
[17]);
372 dependentPath
= strdup(newPath
);
374 else if ( strncmp(dependentPath
, "@loader_path/", 13) == 0 ) {
375 // expand @loader_path path prefix
376 char newPath
[strlen(fPath
) + strlen(dependentPath
)+2];
377 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(fPath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
378 // fPath already has rootPath prefix, need to remove that to get to base virtual path
379 strcpy(newPath
, &fPath
[strlen(fgFileSystemRoot
)]);
382 strcpy(newPath
, fPath
);
384 char* addPoint
= strrchr(newPath
,'/');
385 if ( addPoint
!= NULL
)
386 strcpy(&addPoint
[1], &dependentPath
[13]);
388 strcpy(newPath
, &dependentPath
[13]);
389 dependentPath
= strdup(newPath
);
391 else if ( strncmp(dependentPath
, "@rpath/", 7) == 0 ) {
392 throw "@rpath not supported in dyld shared cache";
394 // <rdar://problem/9161945> silently ignore dependents from main executables that can't be in shared cache
395 bool addDependent
= true;
396 if ( fLayout
->getFileType() == MH_EXECUTE
) {
397 if ( (strncmp(dependentPath
, "/usr/lib/", 9) != 0) && (strncmp(dependentPath
, "/System/Library/", 16) != 0) ) {
398 addDependent
= false;
402 fDependsOn
.insert(fGraph
->getNodeForVirtualPath(dependentPath
));
404 catch (const char* msg
) {
405 if ( it
->weakImport
&& ! fLayout
->hasSplitSegInfo() ) {
406 // ok to ignore missing weak imported dylibs from things that are
407 // not going to be in the dyld shared cache
410 fprintf(stderr
, "warning, could not bind %s because %s\n", fPath
, msg
);
411 fDependentMissing
= true;
416 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
417 (*it
)->loadDependencies(mainExecutableLayout
);
422 void ArchGraph::DependencyNode::markNeededByRoot(ArchGraph::DependencyNode
* rootNode
)
424 if ( fRootsDependentOnThis
.count(rootNode
) == 0 ) {
425 fRootsDependentOnThis
.insert(rootNode
);
426 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
427 (*it
)->markNeededByRoot(rootNode
);
433 ArchGraph::DependencyNode::DependencyNode(ArchGraph
* graph
, const char* path
, const MachOLayoutAbstraction
* layout
)
434 : fGraph(graph
), fPath(strdup(path
)), fLayout(layout
), fDependenciesLoaded(false), fDependentMissing(false)
436 //fprintf(stderr, "new DependencyNode(0x%08X, %s)\n", graph->fArch, path);
439 void ArchGraph::findSharedDylibs(ArchPair ap
)
441 const PathToNode
& nodes
= fgPerArchGraph
[ap
]->fNodes
;
442 std::set
<const MachOLayoutAbstraction
*> possibleLibs
;
443 //fprintf(stderr, "shared for arch %s\n", archName(ap));
444 for(PathToNode::const_iterator it
= nodes
.begin(); it
!= nodes
.end(); ++it
) {
445 DependencyNode
* node
= it
->second
;
446 // <rdar://problem/6127437> put all dylibs in shared cache - not just ones used by more than one app
447 if ( node
->allDependentsFound() /*&& (node->useCount() > 1)*/ ) {
448 const MachOLayoutAbstraction
* layout
= node
->getLayout();
449 if ( layout
->isDylib() ) {
451 if ( sharable(layout
, ap
, &msg
) ) {
452 possibleLibs
.insert(layout
);
455 if ( layout
->getID().name
[0] == '@' ) {
456 // <rdar://problem/7770139> update_dyld_shared_cache should suppress warnings for embedded frameworks
459 warnings
.push_back(msg
);
460 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
467 // prune so that all shareable libs depend only on other shareable libs
468 std::set
<const MachOLayoutAbstraction
*>& sharedLibs
= fgPerArchGraph
[ap
]->fSharedDylibs
;
469 std::map
<const MachOLayoutAbstraction
*,bool> shareableMap
;
470 for (std::set
<const MachOLayoutAbstraction
*>::iterator lit
= possibleLibs
.begin(); lit
!= possibleLibs
.end(); ++lit
) {
471 if ( canBeShared(*lit
, ap
, possibleLibs
, shareableMap
) )
472 sharedLibs
.insert(*lit
);
476 const char* ArchGraph::archName(ArchPair ap
)
479 case CPU_TYPE_POWERPC
:
483 case CPU_TYPE_X86_64
:
486 switch ( ap
.subtype
) {
487 case CPU_SUBTYPE_ARM_V4T
:
489 case CPU_SUBTYPE_ARM_V6
:
491 case CPU_SUBTYPE_ARM_V5TEJ
:
493 case CPU_SUBTYPE_ARM_XSCALE
:
495 case CPU_SUBTYPE_ARM_V7
:
505 bool ArchGraph::sharable(const MachOLayoutAbstraction
* layout
, ArchPair ap
, char** msg
)
507 if ( ! layout
->isTwoLevelNamespace() )
508 asprintf(msg
, "can't put %s in shared cache because it was built -flat_namespace", layout
->getID().name
);
509 else if ( ! layout
->hasSplitSegInfo() )
510 asprintf(msg
, "can't put %s in shared cache because it was not built for %s or later", layout
->getID().name
, (iPhoneOS
? "iPhoneOS 3.1" : "MacOSX 10.5"));
511 else if ( ! layout
->isRootOwned() )
512 asprintf(msg
, "can't put %s in shared cache because it is not owned by root", layout
->getID().name
);
513 else if ( ! layout
->inSharableLocation() )
514 asprintf(msg
, "can't put %s in shared cache because it is not in /usr/lib or /System/Library", layout
->getID().name
);
515 else if ( layout
->hasDynamicLookupLinkage() )
516 asprintf(msg
, "can't put %s in shared cache because it was built with '-undefined dynamic_lookup'", layout
->getID().name
);
517 else if ( layout
->hasMainExecutableLookupLinkage() )
518 asprintf(msg
, "can't put %s in shared cache because it was built with '-bundle_loader'", layout
->getID().name
);
519 //else if ( ! layout->hasDyldInfo() )
520 // asprintf(msg, "can't put %s in shared cache because it was built for older OS", layout->getID().name);
526 bool ArchGraph::canBeShared(const MachOLayoutAbstraction
* layout
, ArchPair ap
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
)
528 // check map which is a cache of results
529 std::map
<const MachOLayoutAbstraction
*, bool>::iterator mapPos
= shareableMap
.find(layout
);
530 if ( mapPos
!= shareableMap
.end() ) {
531 return mapPos
->second
;
534 if ( possibleLibs
.count(layout
) == 0 ) {
535 shareableMap
[layout
] = false;
537 if ( sharable(layout
, ap
, &msg
) )
538 asprintf(&msg
, "can't put %s in shared cache, unknown reason", layout
->getID().name
);
539 warnings
.push_back(msg
);
541 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
545 shareableMap
[layout
] = true; // mark this shareable early in case of circular references
546 const PathToNode
& nodes
= fgPerArchGraph
[ap
]->fNodes
;
547 const std::vector
<MachOLayoutAbstraction::Library
>& dependents
= layout
->getLibraries();
548 for (std::vector
<MachOLayoutAbstraction::Library
>::const_iterator dit
= dependents
.begin(); dit
!= dependents
.end(); ++dit
) {
549 PathToNode::const_iterator pos
= nodes
.find(dit
->name
);
550 if ( pos
== nodes
.end() ) {
551 // path from load command does not match any loaded dylibs, maybe there is a temp symlink
552 char realPath
[MAXPATHLEN
];
553 if ( realpath(dit
->name
, realPath
) != NULL
) {
554 if ( nodes
.find(realPath
) != nodes
.end() )
557 shareableMap
[layout
] = false;
559 asprintf(&msg
, "can't put %s in shared cache because it depends on %s which can't be found", layout
->getID().name
, dit
->name
);
560 warnings
.push_back(msg
);
562 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
566 if ( ! canBeShared(pos
->second
->getLayout(), ap
, possibleLibs
, shareableMap
) ) {
567 shareableMap
[layout
] = false;
569 asprintf(&msg
, "can't put %s in shared cache because it depends on %s which can't be in shared cache", layout
->getID().name
, dit
->name
);
570 warnings
.push_back(msg
);
572 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
581 template <typename A
>
585 SharedCache(ArchGraph
* graph
, const char* rootPath
, const char* cacheDir
, bool alphaSort
, bool verify
, bool optimize
, bool overlay
, uint64_t dyldBaseAddress
);
586 bool update(bool usesOverlay
, bool force
, bool optimize
, bool deleteExistingFirst
, int archIndex
,
587 int archCount
, bool keepSignatures
);
588 static const char* cacheFileSuffix(bool optimized
, const char* archName
);
590 // vm address = address AS WRITTEN into the cache
591 // mapped address = address AS MAPPED into the update process only
592 // file offset = offset relative to start of cache file
593 void * mappedAddressForVMAddress(uint64_t vmaddr
);
594 uint64_t VMAddressForMappedAddress(const void *mapaddr
);
595 uint64_t cacheFileOffsetForVMAddress(uint64_t addr
) const;
596 uint64_t VMAddressForCacheFileOffset(uint64_t addr
) const;
599 typedef typename
A::P P
;
600 typedef typename
A::P::E E
;
601 typedef typename
A::P::uint_t pint_t
;
603 bool notUpToDate(const char* path
, unsigned int aliasCount
);
604 bool notUpToDate(const void* cache
, unsigned int aliasCount
);
605 uint8_t* optimizeLINKEDIT(bool keepSignatures
);
606 void optimizeObjC(std::vector
<void*>& pointersInData
);
608 static void getSharedCacheBasAddresses(cpu_type_t arch
, uint64_t* baseReadOnly
, uint64_t* baseWritable
);
609 static cpu_type_t
arch();
610 static const char* archName();
611 static uint64_t sharedRegionReadOnlyStartAddress();
612 static uint64_t sharedRegionWritableStartAddress();
613 static uint64_t sharedRegionReadOnlySize();
614 static uint64_t sharedRegionWritableSize();
615 static uint64_t getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
);
616 static bool addCacheSlideInfo();
618 void assignNewBaseAddresses(bool verify
);
621 const MachOLayoutAbstraction
* layout
;
622 std::vector
<const char*> aliases
;
623 dyld_cache_image_info info
;
626 struct ByNameSorter
{
627 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
)
628 { return (strcmp(left
.layout
->getID().name
, right
.layout
->getID().name
) < 0); }
631 struct ByCStringSectionSizeSorter
{
632 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
633 const std::vector
<MachOLayoutAbstraction::Segment
>& segs_l
=
634 left
.layout
->getSegments();
635 const std::vector
<MachOLayoutAbstraction::Segment
>& segs_r
=
636 right
.layout
->getSegments();
637 if (segs_l
.size() == 0 || segs_r
.size() == 0) {
638 // one image has no segments
639 return segs_l
.size() > segs_r
.size();
641 const macho_header
<P
> *mh_l
= (macho_header
<P
>*)segs_l
[0].mappedAddress();
642 const macho_header
<P
> *mh_r
= (macho_header
<P
>*)segs_r
[0].mappedAddress();
643 const macho_section
<P
> *cstring_l
= mh_l
->getSection("__TEXT", "__cstring");
644 const macho_section
<P
> *cstring_r
= mh_r
->getSection("__TEXT", "__cstring");
645 if (!cstring_l
|| !cstring_r
) {
646 // one image has no cstrings
647 return cstring_l
&& !cstring_r
;
650 return cstring_l
->size() > cstring_r
->size();
655 Sorter(std::map
<const MachOLayoutAbstraction
*, uint32_t>& map
): fMap(map
) {}
656 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
657 return (fMap
[left
.layout
] < fMap
[right
.layout
]);
660 std::map
<const MachOLayoutAbstraction
*, uint32_t>& fMap
;
664 ArchGraph
* fArchGraph
;
666 bool fExistingIsNotUpToDate
;
667 bool fCacheFileInFinalLocation
;
668 const char* fCacheFilePath
;
669 uint8_t* fExistingCacheForVerification
;
670 std::vector
<LayoutInfo
> fDylibs
;
671 std::vector
<LayoutInfo
> fDylibAliases
;
672 std::vector
<shared_file_mapping_np
> fMappings
;
673 uint32_t fHeaderSize
;
674 uint8_t* fInMemoryCache
;
675 uint64_t fDyldBaseAddress
;
676 uint64_t fLinkEditsTotalUnoptimizedSize
;
677 uint64_t fLinkEditsStartAddress
;
678 MachOLayoutAbstraction::Segment
* fFirstLinkEditSegment
;
679 uint32_t fOffsetOfBindInfoInCombinedLinkedit
;
680 uint32_t fOffsetOfWeakBindInfoInCombinedLinkedit
;
681 uint32_t fOffsetOfLazyBindInfoInCombinedLinkedit
;
682 uint32_t fOffsetOfExportInfoInCombinedLinkedit
;
683 uint32_t fOffsetOfOldSymbolTableInfoInCombinedLinkedit
;
684 uint32_t fSizeOfOldSymbolTableInfoInCombinedLinkedit
;
685 uint32_t fOffsetOfOldExternalRelocationsInCombinedLinkedit
;
686 uint32_t fSizeOfOldExternalRelocationsInCombinedLinkedit
;
687 uint32_t fOffsetOfOldIndirectSymbolsInCombinedLinkedit
;
688 uint32_t fSizeOfOldIndirectSymbolsInCombinedLinkedit
;
689 uint32_t fOffsetOfOldStringPoolInCombinedLinkedit
;
690 uint32_t fSizeOfOldStringPoolInCombinedLinkedit
;
691 uint32_t fOffsetOfFunctionStartsInCombinedLinkedit
;
692 uint32_t fSizeOfFunctionStartsInCombinedLinkedit
;
693 uint32_t fLinkEditsTotalOptimizedSize
;
697 // Access a section containing a list of pointers
698 template <typename A
, typename T
>
701 typedef typename
A::P P
;
702 typedef typename
A::P::uint_t pint_t
;
704 SharedCache
<A
>* const fCache
;
705 const macho_section
<P
>* const fSection
;
706 pint_t
* const fBase
;
710 PointerSection(SharedCache
<A
>* cache
, const macho_header
<P
>* header
,
711 const char *segname
, const char *sectname
)
713 , fSection(header
->getSection(segname
, sectname
))
714 , fBase(fSection
? (pint_t
*)cache
->mappedAddressForVMAddress(fSection
->addr()) : 0)
715 , fCount(fSection
? fSection
->size() / sizeof(pint_t
) : 0)
719 uint64_t count() const { return fCount
; }
721 uint64_t getUnmapped(uint64_t index
) const {
722 if (index
>= fCount
) throwf("index out of range");
723 return P::getP(fBase
[index
]);
726 T
get(uint64_t index
) const {
727 return (T
)fCache
->mappedAddressForVMAddress(getUnmapped(index
));
730 void set(uint64_t index
, uint64_t value
) {
731 if (index
>= fCount
) throwf("index out of range");
732 P::setP(fBase
[index
], value
);
737 for (uint64_t i
= 0; i
< fCount
; i
++) {
738 pint_t value
= fBase
[i
];
740 fBase
[i
-shift
] = value
;
746 const_cast<macho_section
<P
>*>(fSection
)->set_size(fCount
* sizeof(pint_t
));
750 // Access a section containing an array of structures
751 template <typename A
, typename T
>
754 typedef typename
A::P P
;
756 SharedCache
<A
>* const fCache
;
757 const macho_section
<P
>* const fSection
;
759 uint64_t const fCount
;
762 ArraySection(SharedCache
<A
>* cache
, const macho_header
<P
>* header
,
763 const char *segname
, const char *sectname
)
765 , fSection(header
->getSection(segname
, sectname
))
766 , fBase(fSection
? (T
*)cache
->mappedAddressForVMAddress(fSection
->addr()) : 0)
767 , fCount(fSection
? fSection
->size() / sizeof(T
) : 0)
771 uint64_t count() const { return fCount
; }
773 T
& get(uint64_t index
) const {
774 if (index
>= fCount
) throwf("index out of range");
781 #include "ObjCLegacyAbstraction.hpp"
782 #include "ObjCModernAbstraction.hpp"
786 template <> cpu_type_t SharedCache
<ppc
>::arch() { return CPU_TYPE_POWERPC
; }
787 template <> cpu_type_t SharedCache
<x86
>::arch() { return CPU_TYPE_I386
; }
788 template <> cpu_type_t SharedCache
<x86_64
>::arch() { return CPU_TYPE_X86_64
; }
789 template <> cpu_type_t SharedCache
<arm
>::arch() { return CPU_TYPE_ARM
; }
791 template <> uint64_t SharedCache
<ppc
>::sharedRegionReadOnlyStartAddress() { return 0x90000000; }
792 template <> uint64_t SharedCache
<x86
>::sharedRegionReadOnlyStartAddress() { return 0x90000000; }
793 template <> uint64_t SharedCache
<x86_64
>::sharedRegionReadOnlyStartAddress() { return 0x7FFF80000000LL
; }
794 template <> uint64_t SharedCache
<arm
>::sharedRegionReadOnlyStartAddress() { return 0x30000000; }
796 template <> uint64_t SharedCache
<ppc
>::sharedRegionWritableStartAddress() { return 0xA0000000; }
797 template <> uint64_t SharedCache
<x86
>::sharedRegionWritableStartAddress() { return 0xAC000000; }
798 template <> uint64_t SharedCache
<x86_64
>::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL
; }
799 template <> uint64_t SharedCache
<arm
>::sharedRegionWritableStartAddress() { return 0x3E000000; }
801 template <> uint64_t SharedCache
<ppc
>::sharedRegionReadOnlySize() { return 0x10000000; }
802 template <> uint64_t SharedCache
<x86
>::sharedRegionReadOnlySize() { return 0x1C000000; }
803 template <> uint64_t SharedCache
<x86_64
>::sharedRegionReadOnlySize() { return 0x40000000; }
804 template <> uint64_t SharedCache
<arm
>::sharedRegionReadOnlySize() { return 0x0E000000; }
806 template <> uint64_t SharedCache
<ppc
>::sharedRegionWritableSize() { return 0x10000000; }
807 template <> uint64_t SharedCache
<x86
>::sharedRegionWritableSize() { return 0x04000000; }
808 template <> uint64_t SharedCache
<x86_64
>::sharedRegionWritableSize() { return 0x10000000; }
809 template <> uint64_t SharedCache
<arm
>::sharedRegionWritableSize() { return 0x02000000; }
812 template <> const char* SharedCache
<ppc
>::archName() { return "ppc"; }
813 template <> const char* SharedCache
<x86
>::archName() { return "i386"; }
814 template <> const char* SharedCache
<x86_64
>::archName() { return "x86_64"; }
815 template <> const char* SharedCache
<arm
>::archName() { return "arm"; }
817 template <> const char* SharedCache
<ppc
>::cacheFileSuffix(bool optimized
, const char*) { return optimized
? "ppc" : "rosetta"; }
818 template <> const char* SharedCache
<x86
>::cacheFileSuffix(bool, const char* archName
) { return archName
; }
819 template <> const char* SharedCache
<x86_64
>::cacheFileSuffix(bool, const char* archName
){ return archName
; }
820 template <> const char* SharedCache
<arm
>::cacheFileSuffix(bool, const char* archName
) { return archName
; }
822 template <typename A
>
823 SharedCache
<A
>::SharedCache(ArchGraph
* graph
, const char* rootPath
, const char* cacheDir
, bool alphaSort
, bool verify
, bool optimize
, bool overlay
, uint64_t dyldBaseAddress
)
824 : fArchGraph(graph
), fVerify(verify
), fExistingIsNotUpToDate(true),
825 fCacheFileInFinalLocation(rootPath
[0] == '\0'), fCacheFilePath(NULL
),
826 fExistingCacheForVerification(NULL
), fDyldBaseAddress(dyldBaseAddress
),
827 fOffsetOfBindInfoInCombinedLinkedit(0), fOffsetOfWeakBindInfoInCombinedLinkedit(0),
828 fOffsetOfLazyBindInfoInCombinedLinkedit(0), fOffsetOfExportInfoInCombinedLinkedit(0),
829 fOffsetOfOldSymbolTableInfoInCombinedLinkedit(0), fSizeOfOldSymbolTableInfoInCombinedLinkedit(0),
830 fOffsetOfOldExternalRelocationsInCombinedLinkedit(0), fSizeOfOldExternalRelocationsInCombinedLinkedit(0),
831 fOffsetOfOldIndirectSymbolsInCombinedLinkedit(0), fSizeOfOldIndirectSymbolsInCombinedLinkedit(0),
832 fOffsetOfOldStringPoolInCombinedLinkedit(0), fSizeOfOldStringPoolInCombinedLinkedit(0),
833 fOffsetOfFunctionStartsInCombinedLinkedit(0), fSizeOfFunctionStartsInCombinedLinkedit(0)
835 if ( fArchGraph
->getArchPair().arch
!= arch() )
836 throwf("SharedCache object is wrong architecture: 0x%08X vs 0x%08X", fArchGraph
->getArchPair().arch
, arch());
838 // build vector of all shared dylibs
839 unsigned int aliasCount
= 0;
840 std::set
<const MachOLayoutAbstraction
*>& dylibs
= fArchGraph
->getSharedDylibs();
841 ArchGraph::StringToString
& aliases
= fArchGraph
->getDylibAliases();
842 for(std::set
<const MachOLayoutAbstraction
*>::iterator it
= dylibs
.begin(); it
!= dylibs
.end(); ++it
) {
843 const MachOLayoutAbstraction
* lib
= *it
;
846 temp
.info
.address
= 0;
847 temp
.info
.modTime
= lib
->getLastModTime();
848 temp
.info
.inode
= lib
->getInode();
849 temp
.info
.pathFileOffset
= lib
->getNameFileOffset(); // for now this is the offset within the dylib
850 for(ArchGraph::StringToString::iterator ait
= aliases
.begin(); ait
!= aliases
.end(); ++ait
) {
851 if ( strcmp(ait
->second
, lib
->getID().name
) == 0 ) {
852 temp
.aliases
.push_back(ait
->first
);
856 fDylibs
.push_back(temp
);
859 // create path to cache file
860 char cachePathNonOverlay
[1024];
861 strcpy(cachePathNonOverlay
, cacheDir
);
862 if ( cachePathNonOverlay
[strlen(cachePathNonOverlay
)-1] != '/' )
863 strcat(cachePathNonOverlay
, "/");
864 strcat(cachePathNonOverlay
, DYLD_SHARED_CACHE_BASE_NAME
);
865 strcat(cachePathNonOverlay
, cacheFileSuffix(optimize
, fArchGraph
->archName()));
866 char cachePath
[1024];
867 strcpy(cachePath
, rootPath
);
868 strcat(cachePath
, "/");
869 strcat(cachePath
, cachePathNonOverlay
);
870 if ( !overlay
&& (rootPath
[0] != '\0') )
871 fCacheFilePath
= strdup(cachePathNonOverlay
);
873 fCacheFilePath
= strdup(cachePath
);
875 // in overlay mode if there already is a cache file in the overlay
876 // check if it is up to date. If there is no file, check if
877 // the one in the boot volume is up to date.
878 struct stat stat_buf
;
879 if ( stat(fCacheFilePath
, &stat_buf
) == 0 )
880 fExistingIsNotUpToDate
= this->notUpToDate(fCacheFilePath
, aliasCount
);
882 fExistingIsNotUpToDate
= this->notUpToDate(cachePathNonOverlay
, aliasCount
);
885 fExistingIsNotUpToDate
= this->notUpToDate(fCacheFilePath
, aliasCount
);
888 // sort shared dylibs
890 // already sorted by notUpToDate()
892 else if ( alphaSort
) {
893 std::sort(fDylibs
.begin(), fDylibs
.end(), ByNameSorter());
896 // random sort for Address Space Randomization
897 std::map
<const MachOLayoutAbstraction
*, uint32_t> map
;
898 for(typename
std::vector
<struct LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
)
899 map
[it
->layout
] = arc4random();
900 std::sort(fDylibs
.begin(), fDylibs
.end(), Sorter(map
));
903 // assign segments in each dylib a new address
904 this->assignNewBaseAddresses(verify
);
906 // calculate where string pool offset will start
907 // calculate cache file header size
908 fHeaderSize
= sizeof(dyld_cache_header
)
909 + fMappings
.size()*sizeof(shared_file_mapping_np
)
910 + (fDylibs
.size()+aliasCount
)*sizeof(dyld_cache_image_info
);
911 //fprintf(stderr, "aliasCount=%d, fHeaderSize=0x%08X\n", aliasCount, fHeaderSize);
912 // build list of aliases and compute where each ones path string will go
913 for(typename
std::vector
<struct LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
914 for(std::vector
<const char*>::const_iterator ait
= it
->aliases
.begin(); ait
!= it
->aliases
.end(); ++ait
) {
915 LayoutInfo temp
= *it
;
916 // alias looks just like real dylib, but has a different name string
917 const char* aliasPath
= *ait
;
918 temp
.aliases
.clear();
919 temp
.aliases
.push_back(aliasPath
);
920 temp
.info
.pathFileOffset
= fHeaderSize
;
921 fDylibAliases
.push_back(temp
);
922 fHeaderSize
+= strlen(aliasPath
)+1;
925 std::sort(fDylibAliases
.begin(), fDylibAliases
.end(), ByNameSorter());
926 //fprintf(stderr, "fHeaderSize=0x%08X, fDylibAliases.size()=%lu\n", fHeaderSize, fDylibAliases.size());
927 fHeaderSize
= pageAlign(fHeaderSize
);
929 // check that cache we are about to create for verification purposes has same layout as existing cache
931 // if no existing cache, say so
932 if ( fExistingCacheForVerification
== NULL
) {
933 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
934 getpid(), archName());
936 const dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)fExistingCacheForVerification
;
937 const dyldCacheImageInfo
<E
>* cacheEntry
= (dyldCacheImageInfo
<E
>*)(fExistingCacheForVerification
+ header
->imagesOffset());
938 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++cacheEntry
) {
939 if ( cacheEntry
->address() != it
->layout
->getSegments()[0].newAddress() ) {
940 throwf("update_dyld_shared_cache[%u] warning: for arch=%s, could not verify cache because start address of %s is 0x%llX in cache, but should be 0x%llX\n",
941 getpid(), archName(), it
->layout
->getID().name
, cacheEntry
->address(), it
->layout
->getSegments()[0].newAddress());
947 if ( fHeaderSize
> FIRST_DYLIB_TEXT_OFFSET
)
948 throwf("header size miscalculation 0x%08X", fHeaderSize
);
952 template <typename A
>
953 uint64_t SharedCache
<A
>::getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
)
955 return proposedNewAddress
;
959 uint64_t SharedCache
<ppc
>::getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
)
961 // for ppc writable segments can only move in increments of 64K (so only hi16 instruction needs to be modified)
962 return (((executableSlide
& 0x000000000000F000ULL
) - ((proposedNewAddress
- originalAddress
) & 0x000000000000F000ULL
)) & 0x000000000000F000ULL
) + proposedNewAddress
;
966 template <typename A
>
967 void SharedCache
<A
>::assignNewBaseAddresses(bool verify
)
969 uint64_t sharedCacheStartAddress
= sharedRegionReadOnlyStartAddress();
971 if ( arch() == CPU_TYPE_X86_64
) {
973 if ( fExistingCacheForVerification
== NULL
) {
974 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
975 getpid(), archName());
977 const dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)fExistingCacheForVerification
;
978 const dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)(fExistingCacheForVerification
+ header
->mappingOffset());
979 sharedCacheStartAddress
= mappings
[0].address();
982 // <rdar://problem/5274722> dyld shared cache can be more random
983 uint64_t readOnlySize
= 0;
984 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
985 if ( ! it
->layout
->hasSplitSegInfo() )
987 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
988 for (int i
=0; i
< segs
.size(); ++i
) {
989 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
990 if ( ! seg
.writable() )
991 readOnlySize
+= pageAlign(seg
.size());
994 uint64_t maxSlide
= sharedRegionReadOnlySize() - (readOnlySize
+ FIRST_DYLIB_TEXT_OFFSET
);
995 sharedCacheStartAddress
= sharedRegionReadOnlyStartAddress() + pageAlign(arc4random() % maxSlide
);
999 uint64_t currentExecuteAddress
= sharedCacheStartAddress
+ FIRST_DYLIB_TEXT_OFFSET
;
1000 uint64_t currentWritableAddress
= sharedRegionWritableStartAddress() + FIRST_DYLIB_DATA_OFFSET
;
1002 // first layout TEXT and DATA for dylibs
1003 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1004 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1005 MachOLayoutAbstraction::Segment
* executableSegment
= NULL
;
1006 for (int i
=0; i
< segs
.size(); ++i
) {
1007 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1009 if ( seg
.writable() ) {
1010 if ( seg
.executable() && it
->layout
->hasSplitSegInfo() ) {
1011 // skip __IMPORT segments in this pass
1015 // for ppc, writable segments have to move in 64K increments
1016 if ( it
->layout
->hasSplitSegInfo() ) {
1017 if ( executableSegment
== NULL
)
1018 throwf("first segment in dylib is not executable for %s", it
->layout
->getID().name
);
1019 seg
.setNewAddress(getWritableSegmentNewAddress(currentWritableAddress
, seg
.address(), executableSegment
->newAddress() - executableSegment
->address()));
1022 seg
.setNewAddress(currentWritableAddress
);
1023 currentWritableAddress
= pageAlign(seg
.newAddress() + seg
.size());
1027 if ( seg
.executable() ) {
1029 if ( it
->info
.address
== 0 )
1030 it
->info
.address
= currentExecuteAddress
;
1031 executableSegment
= &seg
;
1032 seg
.setNewAddress(currentExecuteAddress
);
1033 currentExecuteAddress
+= pageAlign(seg
.size());
1036 // skip read-only segments in this pass
1042 // append all read-only (but not LINKEDIT) segments at end of all TEXT segments
1043 // append all IMPORT segments at end of all DATA segments rounded to next 2MB
1044 uint64_t currentReadOnlyAddress
= currentExecuteAddress
;
1045 uint64_t startWritableExecutableAddress
= (currentWritableAddress
+ 0x200000 - 1) & (-0x200000);
1046 uint64_t currentWritableExecutableAddress
= startWritableExecutableAddress
;
1047 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1048 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1049 for(int i
=0; i
< segs
.size(); ++i
) {
1050 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1051 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") != 0) ) {
1052 // allocate non-executable,read-only segments from end of read only shared region
1053 seg
.setNewAddress(currentReadOnlyAddress
);
1054 currentReadOnlyAddress
+= pageAlign(seg
.size());
1056 else if ( seg
.writable() && seg
.executable() && it
->layout
->hasSplitSegInfo() ) {
1057 // allocate IMPORT segments to end of writable shared region
1058 seg
.setNewAddress(currentWritableExecutableAddress
);
1059 currentWritableExecutableAddress
+= pageAlign(seg
.size());
1064 // append all LINKEDIT segments at end of all read-only segments
1065 fLinkEditsStartAddress
= currentReadOnlyAddress
;
1066 fFirstLinkEditSegment
= NULL
;
1067 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1068 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1069 for(int i
=0; i
< segs
.size(); ++i
) {
1070 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1071 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
1072 if ( fFirstLinkEditSegment
== NULL
)
1073 fFirstLinkEditSegment
= &seg
;
1074 // allocate non-executable,read-only segments from end of read only shared region
1075 seg
.setNewAddress(currentReadOnlyAddress
);
1076 currentReadOnlyAddress
+= pageAlign(seg
.size());
1080 fLinkEditsTotalUnoptimizedSize
= (currentReadOnlyAddress
- fLinkEditsStartAddress
+ 4095) & (-4096);
1082 // <rdar://problem/9361288> i386 dyld shared cache overflows after adding libclh.dylib
1083 if ( (currentReadOnlyAddress
- sharedRegionReadOnlyStartAddress()) > sharedRegionReadOnlySize() )
1084 throwf("read-only slice of cache too big: %lluMB (max %lluMB)",
1085 (currentReadOnlyAddress
- sharedRegionReadOnlyStartAddress())/(1024*1024),
1086 sharedRegionReadOnlySize()/(1024*1024));
1089 // populate large mappings
1090 uint64_t cacheFileOffset
= 0;
1091 if ( currentExecuteAddress
> sharedCacheStartAddress
+ FIRST_DYLIB_TEXT_OFFSET
) {
1092 shared_file_mapping_np executeMapping
;
1093 executeMapping
.sfm_address
= sharedCacheStartAddress
;
1094 executeMapping
.sfm_size
= currentExecuteAddress
- sharedCacheStartAddress
;
1095 executeMapping
.sfm_file_offset
= cacheFileOffset
;
1096 executeMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
1097 executeMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
1098 fMappings
.push_back(executeMapping
);
1099 cacheFileOffset
+= executeMapping
.sfm_size
;
1101 shared_file_mapping_np writableMapping
;
1102 writableMapping
.sfm_address
= sharedRegionWritableStartAddress();
1103 writableMapping
.sfm_size
= currentWritableAddress
- sharedRegionWritableStartAddress();
1104 writableMapping
.sfm_file_offset
= cacheFileOffset
;
1105 writableMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
1106 writableMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
1107 fMappings
.push_back(writableMapping
);
1108 cacheFileOffset
+= writableMapping
.sfm_size
;
1110 if ( currentWritableExecutableAddress
> startWritableExecutableAddress
) {
1111 shared_file_mapping_np writableExecutableMapping
;
1112 writableExecutableMapping
.sfm_address
= startWritableExecutableAddress
;
1113 writableExecutableMapping
.sfm_size
= currentWritableExecutableAddress
- startWritableExecutableAddress
;
1114 writableExecutableMapping
.sfm_file_offset
= cacheFileOffset
;
1115 writableExecutableMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_WRITE
| VM_PROT_EXECUTE
;
1116 writableExecutableMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_WRITE
| VM_PROT_EXECUTE
;
1117 fMappings
.push_back(writableExecutableMapping
);
1118 cacheFileOffset
+= writableExecutableMapping
.sfm_size
;
1121 // make read-only (contains LINKEDIT segments) last, so it can be cut back when optimized
1122 shared_file_mapping_np readOnlyMapping
;
1123 readOnlyMapping
.sfm_address
= currentExecuteAddress
;
1124 readOnlyMapping
.sfm_size
= currentReadOnlyAddress
- currentExecuteAddress
;
1125 readOnlyMapping
.sfm_file_offset
= cacheFileOffset
;
1126 readOnlyMapping
.sfm_max_prot
= VM_PROT_READ
;
1127 readOnlyMapping
.sfm_init_prot
= VM_PROT_READ
;
1128 fMappings
.push_back(readOnlyMapping
);
1129 cacheFileOffset
+= readOnlyMapping
.sfm_size
;
1133 shared_file_mapping_np cacheHeaderMapping
;
1134 cacheHeaderMapping
.sfm_address
= sharedRegionWritableStartAddress();
1135 cacheHeaderMapping
.sfm_size
= FIRST_DYLIB_TEXT_OFFSET
;
1136 cacheHeaderMapping
.sfm_file_offset
= cacheFileOffset
;
1137 cacheHeaderMapping
.sfm_max_prot
= VM_PROT_READ
;
1138 cacheHeaderMapping
.sfm_init_prot
= VM_PROT_READ
;
1139 fMappings
.push_back(cacheHeaderMapping
);
1140 cacheFileOffset
+= cacheHeaderMapping
.sfm_size
;
1145 template <typename A
>
1146 uint64_t SharedCache
<A
>::cacheFileOffsetForVMAddress(uint64_t vmaddr
) const
1148 for(std::vector
<shared_file_mapping_np
>::const_iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1149 if ( (it
->sfm_address
<= vmaddr
) && (vmaddr
< it
->sfm_address
+it
->sfm_size
) )
1150 return it
->sfm_file_offset
+ vmaddr
- it
->sfm_address
;
1152 throwf("address 0x%0llX is not in cache", vmaddr
);
1155 template <typename A
>
1156 uint64_t SharedCache
<A
>::VMAddressForCacheFileOffset(uint64_t offset
) const
1158 for(std::vector
<shared_file_mapping_np
>::const_iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1159 if ( (it
->sfm_file_offset
<= offset
) && (offset
< it
->sfm_file_offset
+it
->sfm_size
) )
1160 return it
->sfm_address
+ offset
- it
->sfm_file_offset
;
1162 throwf("offset 0x%0llX is not in cache", offset
);
1165 template <typename A
>
1166 void *SharedCache
<A
>::mappedAddressForVMAddress(uint64_t vmaddr
)
1168 if (!vmaddr
) return NULL
;
1169 else return fInMemoryCache
+ cacheFileOffsetForVMAddress(vmaddr
);
1172 template <typename A
>
1173 uint64_t SharedCache
<A
>::VMAddressForMappedAddress(const void *mapaddr
)
1175 if (!mapaddr
) return 0;
1176 uint64_t offset
= (uint8_t *)mapaddr
- (uint8_t *)fInMemoryCache
;
1177 return VMAddressForCacheFileOffset(offset
);
1181 template <typename A
>
1182 bool SharedCache
<A
>::notUpToDate(const void* cache
, unsigned int aliasCount
)
1184 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)cache
;
1185 // not valid if header signature is wrong
1186 const char* archPairName
= fArchGraph
->archName();
1188 strcpy(temp
, "dyld_v1 ");
1189 strcpy(&temp
[15-strlen(archPairName
)], archPairName
);
1190 if ( strcmp(header
->magic(), temp
) != 0 ) {
1192 fprintf(stderr
, "update_dyld_shared_cache[%u] cannot verify %s because current cache file has invalid header\n", getpid(), archName());
1196 fprintf(stderr
, "update_dyld_shared_cache[%u] updating cache because current cache file has invalid header\n", getpid());
1200 // not valid if count of images does not match current images needed
1201 if ( header
->imagesCount() != (fDylibs
.size()+aliasCount
) ) {
1203 fprintf(stderr
, "update_dyld_shared_cache[%u] cannot verify %s because current cache file contains a different set of dylibs\n", getpid(), archName());
1207 fprintf(stderr
, "update_dyld_shared_cache[%u] updating %s cache because current cache file contains a different set of dylibs\n", getpid(), archName());
1211 // get end of TEXT region
1212 const dyldCacheFileMapping
<E
>* textMapping
= (dyldCacheFileMapping
<E
>*)((uint8_t*)cache
+sizeof(dyldCacheHeader
<E
>));
1213 const uint32_t textSize
= textMapping
->size();
1215 // verify every dylib in constructed graph is in existing cache with same inode and modTime
1216 std::map
<const MachOLayoutAbstraction
*, uint32_t> sortingMap
;
1217 const dyldCacheImageInfo
<E
>* imagesStart
= (dyldCacheImageInfo
<E
>*)((uint8_t*)cache
+ header
->imagesOffset());
1218 const dyldCacheImageInfo
<E
>* imagesEnd
= &imagesStart
[header
->imagesCount()];
1219 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1221 //fprintf(stderr, "inode=0x%llX, mTime=0x%llX, path=%s\n", it->info.inode, it->info.modTime, it->layout->getID().name);
1222 for(const dyldCacheImageInfo
<E
>* cacheEntry
= imagesStart
; cacheEntry
< imagesEnd
; ++cacheEntry
) {
1224 if ( cacheEntry
->pathFileOffset() > textSize
) {
1225 throwf("update_dyld_shared_cache[%u]: for arch=%s, image entries corrupt, bad path offset in %s\n",
1226 getpid(), archName(), it
->layout
->getID().name
);
1228 // in -verify mode, just match by path and warn if file looks different
1229 if ( strcmp((char*)cache
+cacheEntry
->pathFileOffset(), it
->layout
->getID().name
) == 0 ) {
1231 sortingMap
[it
->layout
] = cacheEntry
-imagesStart
;
1232 if ( (cacheEntry
->inode() != it
->info
.inode
) || (cacheEntry
->modTime() != it
->info
.modTime
) ) {
1233 fprintf(stderr
, "update_dyld_shared_cache[%u] warning: for arch=%s, %s has changed since cache was built\n",
1234 getpid(), archName(), it
->layout
->getID().name
);
1240 if ( cacheEntry
->pathFileOffset() > textSize
) {
1241 // cache corrupt, needs to be regenerated
1244 // in normal update mode, everything has to match for cache to be up-to-date
1245 if ( (cacheEntry
->inode() == it
->info
.inode
)
1246 && (cacheEntry
->modTime() == it
->info
.modTime
)
1247 && (strcmp((char*)cache
+cacheEntry
->pathFileOffset(), it
->layout
->getID().name
) == 0) ) {
1255 throwf("update_dyld_shared_cache[%u] can't verify %s cache because %s is not in existing cache\n", getpid(), archName(), it
->layout
->getID().name
);
1258 fprintf(stderr
, "update_dyld_shared_cache[%u] updating %s cache because dylib at %s has changed\n", getpid(), archName(), it
->layout
->getID().name
);
1263 // all dylibs in existing cache file match those determined need to be in shared cache
1265 // sort fDylibs to match existing cache file so we can compare content
1266 std::sort(fDylibs
.begin(), fDylibs
.end(), Sorter(sortingMap
));
1267 //fprintf(stderr, "dylibs sorted like existing cache:\n");
1268 //for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1269 // fprintf(stderr," %s\n", it->layout->getID().name);
1271 // do regenerate a new cache so we can compare content with existing
1275 // existing cache file is up-to-date, don't need to regenerate
1281 template <typename A
>
1282 bool SharedCache
<A
>::notUpToDate(const char* path
, unsigned int aliasCount
)
1284 // mmap existing cache file
1285 int fd
= ::open(path
, O_RDONLY
);
1288 struct stat stat_buf
;
1289 ::fstat(fd
, &stat_buf
);
1290 uint32_t cacheFileSize
= stat_buf
.st_size
;
1291 uint32_t cacheAllocatedSize
= (cacheFileSize
+ 4095) & (-4096);
1292 uint8_t* mappingAddr
= NULL
;
1293 if ( vm_allocate(mach_task_self(), (vm_address_t
*)(&mappingAddr
), cacheAllocatedSize
, VM_FLAGS_ANYWHERE
) != KERN_SUCCESS
)
1294 throwf("can't vm_allocate cache of size %u", cacheFileSize
);
1295 // <rdar://problem/8960832> update_dyld_shared_cache -verify finds differences
1296 (void)fcntl(fd
, F_NOCACHE
, 1);
1297 ssize_t readResult
= pread(fd
, mappingAddr
, cacheFileSize
, 0);
1298 if ( readResult
!= cacheFileSize
)
1299 throw "can't read existing cache file";
1303 bool result
= this->notUpToDate(mappingAddr
, aliasCount
);
1305 // don't unmap yet, leave so it can be verified later
1306 fExistingCacheForVerification
= mappingAddr
;
1310 vm_deallocate(mach_task_self(), (vm_address_t
)mappingAddr
, cacheAllocatedSize
);
1311 if ( verbose
&& !result
)
1312 fprintf(stderr
, "update_dyld_shared_cache: %s is up-to-date\n", path
);
1320 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
1327 const char* getBuffer();
1329 uint32_t add(const char* str
);
1330 uint32_t addUnique(const char* str
);
1331 const char* stringAtIndex(uint32_t) const;
1333 typedef __gnu_cxx::hash_map
<const char*, uint32_t, __gnu_cxx::hash
<const char*>, CStringEquals
> StringToOffset
;
1336 uint32_t fBufferAllocated
;
1337 uint32_t fBufferUsed
;
1338 StringToOffset fUniqueStrings
;
1342 StringPool::StringPool()
1343 : fBufferUsed(0), fBufferAllocated(32*1024*1024)
1345 fBuffer
= (char*)malloc(fBufferAllocated
);
1348 uint32_t StringPool::add(const char* str
)
1350 uint32_t len
= strlen(str
);
1351 if ( (fBufferUsed
+ len
+ 1) > fBufferAllocated
) {
1353 throw "string buffer exhausted";
1355 strcpy(&fBuffer
[fBufferUsed
], str
);
1356 uint32_t result
= fBufferUsed
;
1357 fUniqueStrings
[&fBuffer
[fBufferUsed
]] = result
;
1358 fBufferUsed
+= len
+1;
1362 uint32_t StringPool::addUnique(const char* str
)
1364 StringToOffset::iterator pos
= fUniqueStrings
.find(str
);
1365 if ( pos
!= fUniqueStrings
.end() )
1368 //fprintf(stderr, "StringPool::addUnique() new string: %s\n", str);
1369 return this->add(str
);
1373 uint32_t StringPool::size()
1378 const char* StringPool::getBuffer()
1383 const char* StringPool::stringAtIndex(uint32_t index
) const
1385 return &fBuffer
[index
];
1389 template <typename A
>
1390 class LinkEditOptimizer
1393 LinkEditOptimizer(const MachOLayoutAbstraction
&, const SharedCache
<A
>&, uint8_t*, StringPool
&);
1394 virtual ~LinkEditOptimizer() {}
1396 void copyBindInfo(uint32_t&);
1397 void copyWeakBindInfo(uint32_t&);
1398 void copyLazyBindInfo(uint32_t&);
1399 void copyExportInfo(uint32_t&);
1400 void copyLocalSymbols(uint32_t symbolTableOffset
, uint32_t&);
1401 void copyExportedSymbols(uint32_t symbolTableOffset
, uint32_t&);
1402 void copyImportedSymbols(uint32_t symbolTableOffset
, uint32_t&);
1403 void copyExternalRelocations(uint32_t& offset
);
1404 void copyIndirectSymbolTable(uint32_t& offset
);
1405 void copyFunctionStarts(uint32_t& offset
);
1406 void updateLoadCommands(uint64_t newVMAddress
, uint64_t size
, uint32_t stringPoolOffset
,
1407 uint32_t linkEditsFileOffset
, bool keepSignatures
);
1411 typedef typename
A::P P
;
1412 typedef typename
A::P::E E
;
1413 typedef typename
A::P::uint_t pint_t
;
1417 const SharedCache
<A
>& fSharedCache
;
1418 const macho_header
<P
>* fHeader
;
1419 uint8_t* fNewLinkEditStart
;
1420 uint8_t* fLinkEditBase
;
1421 const MachOLayoutAbstraction
& fLayout
;
1422 macho_dyld_info_command
<P
>* fDyldInfo
;
1423 macho_dysymtab_command
<P
>* fDynamicSymbolTable
;
1424 macho_linkedit_data_command
<P
>* fFunctionStarts
;
1425 macho_symtab_command
<P
>* fSymbolTableLoadCommand
;
1426 const macho_nlist
<P
>* fSymbolTable
;
1427 const char* fStrings
;
1428 StringPool
& fNewStringPool
;
1429 std::map
<uint32_t,uint32_t> fOldToNewSymbolIndexes
;
1430 uint32_t fBindInfoOffsetIntoNewLinkEdit
;
1431 uint32_t fBindInfoSizeInNewLinkEdit
;
1432 uint32_t fWeakBindInfoOffsetIntoNewLinkEdit
;
1433 uint32_t fWeakBindInfoSizeInNewLinkEdit
;
1434 uint32_t fLazyBindInfoOffsetIntoNewLinkEdit
;
1435 uint32_t fLazyBindInfoSizeInNewLinkEdit
;
1436 uint32_t fExportInfoOffsetIntoNewLinkEdit
;
1437 uint32_t fExportInfoSizeInNewLinkEdit
;
1438 uint32_t fSymbolTableStartOffsetInNewLinkEdit
;
1439 uint32_t fLocalSymbolsStartIndexInNewLinkEdit
;
1440 uint32_t fLocalSymbolsCountInNewLinkEdit
;
1441 uint32_t fExportedSymbolsStartIndexInNewLinkEdit
;
1442 uint32_t fExportedSymbolsCountInNewLinkEdit
;
1443 uint32_t fImportSymbolsStartIndexInNewLinkEdit
;
1444 uint32_t fImportedSymbolsCountInNewLinkEdit
;
1445 uint32_t fExternalRelocationsOffsetIntoNewLinkEdit
;
1446 uint32_t fIndirectSymbolTableOffsetInfoNewLinkEdit
;
1447 uint32_t fFunctionStartsOffsetInNewLinkEdit
;
1452 template <typename A
>
1453 LinkEditOptimizer
<A
>::LinkEditOptimizer(const MachOLayoutAbstraction
& layout
, const SharedCache
<A
>& sharedCache
, uint8_t* newLinkEdit
, StringPool
& stringPool
)
1454 : fSharedCache(sharedCache
), fLayout(layout
), fLinkEditBase(NULL
), fNewLinkEditStart(newLinkEdit
), fDyldInfo(NULL
),
1455 fDynamicSymbolTable(NULL
), fFunctionStarts(NULL
), fSymbolTableLoadCommand(NULL
), fSymbolTable(NULL
), fStrings(NULL
), fNewStringPool(stringPool
),
1456 fBindInfoOffsetIntoNewLinkEdit(0), fBindInfoSizeInNewLinkEdit(0),
1457 fWeakBindInfoOffsetIntoNewLinkEdit(0), fWeakBindInfoSizeInNewLinkEdit(0),
1458 fLazyBindInfoOffsetIntoNewLinkEdit(0), fLazyBindInfoSizeInNewLinkEdit(0),
1459 fExportInfoOffsetIntoNewLinkEdit(0), fExportInfoSizeInNewLinkEdit(0),
1460 fSymbolTableStartOffsetInNewLinkEdit(0),
1461 fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
1462 fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
1463 fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
1464 fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0),
1465 fFunctionStartsOffsetInNewLinkEdit(0)
1468 fHeader
= (const macho_header
<P
>*)fLayout
.getSegments()[0].mappedAddress();
1470 const std::vector
<MachOLayoutAbstraction::Segment
>& segments
= fLayout
.getSegments();
1471 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator it
= segments
.begin(); it
!= segments
.end(); ++it
) {
1472 const MachOLayoutAbstraction::Segment
& seg
= *it
;
1473 if ( strcmp(seg
.name(), "__LINKEDIT") == 0 )
1474 fLinkEditBase
= (uint8_t*)seg
.mappedAddress() - seg
.fileOffset();
1476 if ( fLinkEditBase
== NULL
)
1477 throw "no __LINKEDIT segment";
1479 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
1480 const uint32_t cmd_count
= fHeader
->ncmds();
1481 const macho_load_command
<P
>* cmd
= cmds
;
1482 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1483 switch (cmd
->cmd()) {
1486 fSymbolTableLoadCommand
= (macho_symtab_command
<P
>*)cmd
;
1487 fSymbolTable
= (macho_nlist
<P
>*)(&fLinkEditBase
[fSymbolTableLoadCommand
->symoff()]);
1488 fStrings
= (char*)&fLinkEditBase
[fSymbolTableLoadCommand
->stroff()];
1492 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
1495 case LC_DYLD_INFO_ONLY
:
1496 fDyldInfo
= (macho_dyld_info_command
<P
>*)cmd
;
1498 case LC_FUNCTION_STARTS
:
1499 fFunctionStarts
= (macho_linkedit_data_command
<P
>*)cmd
;
1502 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1504 if ( fSymbolTable
== NULL
)
1505 throw "no LC_SYMTAB";
1506 if ( fDynamicSymbolTable
== NULL
)
1507 throw "no LC_DYSYMTAB";
1512 template <typename A
>
1516 typedef typename
A::P P
;
1517 SymbolSorter(const StringPool
& pool
) : fStringPool(pool
) {}
1518 bool operator()(const macho_nlist
<P
>& left
, const macho_nlist
<P
>& right
) {
1519 return (strcmp(fStringPool
.stringAtIndex(left
.n_strx()) , fStringPool
.stringAtIndex(right
.n_strx())) < 0);
1523 const StringPool
& fStringPool
;
1527 template <typename A
>
1528 void LinkEditOptimizer
<A
>::copyBindInfo(uint32_t& offset
)
1530 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->bind_off() != 0) ) {
1531 fBindInfoOffsetIntoNewLinkEdit
= offset
;
1532 fBindInfoSizeInNewLinkEdit
= fDyldInfo
->bind_size();
1533 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->bind_off()], fDyldInfo
->bind_size());
1534 offset
+= fDyldInfo
->bind_size();
1538 template <typename A
>
1539 void LinkEditOptimizer
<A
>::copyWeakBindInfo(uint32_t& offset
)
1541 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->weak_bind_off() != 0) ) {
1542 fWeakBindInfoOffsetIntoNewLinkEdit
= offset
;
1543 fWeakBindInfoSizeInNewLinkEdit
= fDyldInfo
->weak_bind_size();
1544 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->weak_bind_off()], fDyldInfo
->weak_bind_size());
1545 offset
+= fDyldInfo
->weak_bind_size();
1549 template <typename A
>
1550 void LinkEditOptimizer
<A
>::copyLazyBindInfo(uint32_t& offset
)
1552 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->lazy_bind_off() != 0) ) {
1553 fLazyBindInfoOffsetIntoNewLinkEdit
= offset
;
1554 fLazyBindInfoSizeInNewLinkEdit
= fDyldInfo
->lazy_bind_size();
1555 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->lazy_bind_off()], fDyldInfo
->lazy_bind_size());
1556 offset
+= fDyldInfo
->lazy_bind_size();
1560 template <typename A
>
1561 void LinkEditOptimizer
<A
>::copyExportInfo(uint32_t& offset
)
1563 if ( (fDyldInfo
!= NULL
) && (fLayout
.getDyldInfoExports() != NULL
) ) {
1564 fExportInfoOffsetIntoNewLinkEdit
= offset
;
1565 fExportInfoSizeInNewLinkEdit
= fDyldInfo
->export_size();
1566 memcpy(fNewLinkEditStart
+offset
, fLayout
.getDyldInfoExports(), fDyldInfo
->export_size());
1567 offset
+= fDyldInfo
->export_size();
1573 template <typename A
>
1574 void LinkEditOptimizer
<A
>::copyLocalSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1576 fLocalSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1577 fSymbolTableStartOffsetInNewLinkEdit
= symbolTableOffset
+ symbolIndex
*sizeof(macho_nlist
<P
>);
1578 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1579 const macho_nlist
<P
>* const firstLocal
= &fSymbolTable
[fDynamicSymbolTable
->ilocalsym()];
1580 const macho_nlist
<P
>* const lastLocal
= &fSymbolTable
[fDynamicSymbolTable
->ilocalsym()+fDynamicSymbolTable
->nlocalsym()];
1581 uint32_t oldIndex
= fDynamicSymbolTable
->ilocalsym();
1582 for (const macho_nlist
<P
>* entry
= firstLocal
; entry
< lastLocal
; ++entry
, ++oldIndex
) {
1583 if ( (entry
->n_type() & N_TYPE
) == N_SECT
) {
1584 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1585 *newSymbolEntry
= *entry
;
1586 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1590 fLocalSymbolsCountInNewLinkEdit
= symbolIndex
- fLocalSymbolsStartIndexInNewLinkEdit
;
1591 //fprintf(stderr, "%u locals starting at %u for %s\n", fLocalSymbolsCountInNewLinkEdit, fLocalSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1595 template <typename A
>
1596 void LinkEditOptimizer
<A
>::copyExportedSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1598 fExportedSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1599 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1600 const macho_nlist
<P
>* const firstExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()];
1601 const macho_nlist
<P
>* const lastExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1602 uint32_t oldIndex
= fDynamicSymbolTable
->iextdefsym();
1603 for (const macho_nlist
<P
>* entry
= firstExport
; entry
< lastExport
; ++entry
, ++oldIndex
) {
1604 if ( ((entry
->n_type() & N_TYPE
) == N_SECT
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0)
1605 && (strncmp(&fStrings
[entry
->n_strx()], "$ld$", 4) != 0) ) {
1606 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1607 *newSymbolEntry
= *entry
;
1608 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1609 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
-fLocalSymbolsStartIndexInNewLinkEdit
;
1613 fExportedSymbolsCountInNewLinkEdit
= symbolIndex
- fExportedSymbolsStartIndexInNewLinkEdit
;
1614 //fprintf(stderr, "%u exports starting at %u for %s\n", fExportedSymbolsCountInNewLinkEdit, fExportedSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1615 // sort by name, so that dyld does not need a toc
1616 macho_nlist
<P
>* newSymbolsStart
= &newSymbolTableStart
[fExportedSymbolsStartIndexInNewLinkEdit
];
1617 macho_nlist
<P
>* newSymbolsEnd
= &newSymbolTableStart
[fExportedSymbolsStartIndexInNewLinkEdit
+fExportedSymbolsCountInNewLinkEdit
];
1618 std::sort(newSymbolsStart
, newSymbolsEnd
, SymbolSorter
<A
>(fNewStringPool
));
1619 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1620 // fprintf(stderr, "\t%u\t %s\n", (entry-newSymbolsStart)+fExportedSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1624 template <typename A
>
1625 void LinkEditOptimizer
<A
>::copyImportedSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1627 fImportSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1628 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1629 const macho_nlist
<P
>* const firstImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()];
1630 const macho_nlist
<P
>* const lastImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()+fDynamicSymbolTable
->nundefsym()];
1631 uint32_t oldIndex
= fDynamicSymbolTable
->iundefsym();
1632 for (const macho_nlist
<P
>* entry
= firstImport
; entry
< lastImport
; ++entry
, ++oldIndex
) {
1633 if ( ((entry
->n_type() & N_TYPE
) == N_UNDF
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0) ) {
1634 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1635 *newSymbolEntry
= *entry
;
1636 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1637 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
-fLocalSymbolsStartIndexInNewLinkEdit
;
1641 fImportedSymbolsCountInNewLinkEdit
= symbolIndex
- fImportSymbolsStartIndexInNewLinkEdit
;
1642 //fprintf(stderr, "%u imports starting at %u for %s\n", fImportedSymbolsCountInNewLinkEdit, fImportSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1643 //macho_nlist<P>* newSymbolsStart = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit];
1644 //macho_nlist<P>* newSymbolsEnd = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit];
1645 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1646 // fprintf(stderr, "\t%u\t%s\n", (entry-newSymbolsStart)+fImportSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1650 template <typename A
>
1651 void LinkEditOptimizer
<A
>::copyExternalRelocations(uint32_t& offset
)
1653 fExternalRelocationsOffsetIntoNewLinkEdit
= offset
;
1654 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(&fLinkEditBase
[fDynamicSymbolTable
->extreloff()]);
1655 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
1656 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1657 macho_relocation_info
<P
>* newReloc
= (macho_relocation_info
<P
>*)(&fNewLinkEditStart
[offset
]);
1659 uint32_t newSymbolIndex
= fOldToNewSymbolIndexes
[reloc
->r_symbolnum()];
1660 //fprintf(stderr, "copyExternalRelocations() old=%d, new=%u name=%s in %s\n", reloc->r_symbolnum(), newSymbolIndex,
1661 // &fStrings[fSymbolTable[reloc->r_symbolnum()].n_strx()], fLayout.getFilePath());
1662 newReloc
->set_r_symbolnum(newSymbolIndex
);
1663 offset
+= sizeof(macho_relocation_info
<P
>);
1667 template <typename A
>
1668 void LinkEditOptimizer
<A
>::copyFunctionStarts(uint32_t& offset
)
1670 if ( fFunctionStarts
!= NULL
) {
1671 fFunctionStartsOffsetInNewLinkEdit
= offset
;
1672 memcpy(&fNewLinkEditStart
[offset
], &fLinkEditBase
[fFunctionStarts
->dataoff()], fFunctionStarts
->datasize());
1673 offset
+= fFunctionStarts
->datasize();
1677 template <typename A
>
1678 void LinkEditOptimizer
<A
>::copyIndirectSymbolTable(uint32_t& offset
)
1680 fIndirectSymbolTableOffsetInfoNewLinkEdit
= offset
;
1681 const uint32_t* const indirectTable
= (uint32_t*)&this->fLinkEditBase
[fDynamicSymbolTable
->indirectsymoff()];
1682 uint32_t* newIndirectTable
= (uint32_t*)&fNewLinkEditStart
[offset
];
1683 for (int i
=0; i
< fDynamicSymbolTable
->nindirectsyms(); ++i
) {
1684 uint32_t oldSymbolIndex
= E::get32(indirectTable
[i
]);
1685 uint32_t newSymbolIndex
= oldSymbolIndex
;
1686 if ( (oldSymbolIndex
!= INDIRECT_SYMBOL_ABS
) && (oldSymbolIndex
!= INDIRECT_SYMBOL_LOCAL
) ) {
1687 newSymbolIndex
= fOldToNewSymbolIndexes
[oldSymbolIndex
];
1688 //fprintf(stderr, "copyIndirectSymbolTable() old=%d, new=%u name=%s in %s\n", oldSymbolIndex, newSymbolIndex,
1689 // &fStrings[fSymbolTable[oldSymbolIndex].n_strx()], fLayout.getFilePath());
1691 E::set32(newIndirectTable
[i
], newSymbolIndex
);
1693 offset
+= (fDynamicSymbolTable
->nindirectsyms() * 4);
1696 template <typename A
>
1697 void LinkEditOptimizer
<A
>::updateLoadCommands(uint64_t newVMAddress
, uint64_t size
, uint32_t stringPoolOffset
,
1698 uint32_t linkEditsFileOffset
, bool keepSignatures
)
1700 // set LINKEDIT segment commmand to new merged LINKEDIT
1701 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
1702 const uint32_t cmd_count
= fHeader
->ncmds();
1703 const macho_load_command
<P
>* cmd
= cmds
;
1704 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1705 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
1706 macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
1707 if ( strcmp(seg
->segname(), "__LINKEDIT") == 0 ) {
1708 seg
->set_vmaddr(newVMAddress
);
1709 seg
->set_vmsize(size
);
1710 seg
->set_filesize(size
);
1711 seg
->set_fileoff(linkEditsFileOffset
);
1713 // don't alter __TEXT until <rdar://problem/7022345> is fixed
1714 else if ( strcmp(seg
->segname(), "__TEXT") != 0 ) {
1715 // update all other segments fileoff to be offset from start of cache file
1716 pint_t oldFileOff
= seg
->fileoff();
1717 seg
->set_fileoff(fSharedCache
.cacheFileOffsetForVMAddress(seg
->vmaddr()));
1718 pint_t fileOffsetDelta
= seg
->fileoff() - oldFileOff
;
1719 // update all sections in this segment
1720 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)seg
+ sizeof(macho_segment_command
<P
>));
1721 macho_section
<P
>* const sectionsEnd
= §ionsStart
[seg
->nsects()];
1722 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1723 if ( sect
->offset() != 0 )
1724 sect
->set_offset(sect
->offset()+fileOffsetDelta
);
1728 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1731 // update dyld_info with new offsets
1732 if ( fDyldInfo
!= NULL
) {
1733 fDyldInfo
->set_rebase_off(0);
1734 fDyldInfo
->set_rebase_size(0);
1735 fDyldInfo
->set_bind_off(linkEditsFileOffset
+fBindInfoOffsetIntoNewLinkEdit
);
1736 fDyldInfo
->set_bind_size(fBindInfoSizeInNewLinkEdit
);
1737 fDyldInfo
->set_weak_bind_off(linkEditsFileOffset
+fWeakBindInfoOffsetIntoNewLinkEdit
);
1738 fDyldInfo
->set_weak_bind_size(fWeakBindInfoSizeInNewLinkEdit
);
1739 fDyldInfo
->set_lazy_bind_off(linkEditsFileOffset
+fLazyBindInfoOffsetIntoNewLinkEdit
);
1740 fDyldInfo
->set_lazy_bind_size(fLazyBindInfoSizeInNewLinkEdit
);
1741 fDyldInfo
->set_export_off(linkEditsFileOffset
+fExportInfoOffsetIntoNewLinkEdit
);
1742 fDyldInfo
->set_export_size(fExportInfoSizeInNewLinkEdit
);
1744 // fprintf(stderr, "dylib %s\n", fLayout.getFilePath());
1745 // fprintf(stderr, " bind_off=0x%08X\n", fDyldInfo->bind_off());
1746 // fprintf(stderr, " export_off=0x%08X\n", fDyldInfo->export_off());
1747 // fprintf(stderr, " export_size=%d\n", fDyldInfo->export_size());
1751 // update symbol table and dynamic symbol table with new offsets
1752 fSymbolTableLoadCommand
->set_symoff(linkEditsFileOffset
+fSymbolTableStartOffsetInNewLinkEdit
);
1753 fSymbolTableLoadCommand
->set_nsyms(fLocalSymbolsCountInNewLinkEdit
+fExportedSymbolsCountInNewLinkEdit
+fImportedSymbolsCountInNewLinkEdit
);
1754 fSymbolTableLoadCommand
->set_stroff(linkEditsFileOffset
+stringPoolOffset
);
1755 fSymbolTableLoadCommand
->set_strsize(fNewStringPool
.size());
1756 fDynamicSymbolTable
->set_ilocalsym(0);
1757 fDynamicSymbolTable
->set_nlocalsym(fLocalSymbolsCountInNewLinkEdit
);
1758 fDynamicSymbolTable
->set_iextdefsym(fExportedSymbolsStartIndexInNewLinkEdit
-fLocalSymbolsStartIndexInNewLinkEdit
);
1759 fDynamicSymbolTable
->set_nextdefsym(fExportedSymbolsCountInNewLinkEdit
);
1760 fDynamicSymbolTable
->set_iundefsym(fImportSymbolsStartIndexInNewLinkEdit
-fLocalSymbolsStartIndexInNewLinkEdit
);
1761 fDynamicSymbolTable
->set_nundefsym(fImportedSymbolsCountInNewLinkEdit
);
1762 fDynamicSymbolTable
->set_tocoff(0);
1763 fDynamicSymbolTable
->set_ntoc(0);
1764 fDynamicSymbolTable
->set_modtaboff(0);
1765 fDynamicSymbolTable
->set_nmodtab(0);
1766 fDynamicSymbolTable
->set_indirectsymoff(linkEditsFileOffset
+fIndirectSymbolTableOffsetInfoNewLinkEdit
);
1767 fDynamicSymbolTable
->set_extreloff(linkEditsFileOffset
+fExternalRelocationsOffsetIntoNewLinkEdit
);
1768 fDynamicSymbolTable
->set_locreloff(0);
1769 fDynamicSymbolTable
->set_nlocrel(0);
1771 // update function starts
1772 if ( fFunctionStarts
!= NULL
) {
1773 fFunctionStarts
->set_dataoff(linkEditsFileOffset
+fFunctionStartsOffsetInNewLinkEdit
);
1776 // now remove load commands no longer needed
1777 const macho_load_command
<P
>* srcCmd
= cmds
;
1778 macho_load_command
<P
>* dstCmd
= (macho_load_command
<P
>*)cmds
;
1779 int32_t newCount
= 0;
1780 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1781 uint32_t cmdSize
= srcCmd
->cmdsize();
1782 switch ( srcCmd
->cmd() ) {
1783 case LC_SEGMENT_SPLIT_INFO
:
1786 case LC_CODE_SIGNATURE
:
1787 if ( !keepSignatures
)
1789 // otherwise fall into copy case
1791 memmove(dstCmd
, srcCmd
, cmdSize
);
1792 dstCmd
= (macho_load_command
<P
>*)(((uint8_t*)dstCmd
)+cmdSize
);
1796 srcCmd
= (const macho_load_command
<P
>*)(((uint8_t*)srcCmd
)+cmdSize
);
1798 // zero out stuff removed
1799 bzero(dstCmd
, (uint8_t*)srcCmd
- (uint8_t*)dstCmd
);
1801 // update mach_header
1802 macho_header
<P
>* writableHeader
= (macho_header
<P
>*)fHeader
;
1803 writableHeader
->set_ncmds(newCount
);
1804 writableHeader
->set_sizeofcmds((uint8_t*)dstCmd
- ((uint8_t*)fHeader
+ sizeof(macho_header
<P
>)));
1806 // this invalidates some ivars
1807 fDynamicSymbolTable
= NULL
;
1808 fSymbolTableLoadCommand
= NULL
;
1810 fSymbolTable
= NULL
;
1816 template <typename A
>
1817 uint8_t* SharedCache
<A
>::optimizeLINKEDIT(bool keepSignatures
)
1819 // allocate space for optimized LINKEDIT area
1820 uint8_t* newLinkEdit
= new uint8_t[fLinkEditsTotalUnoptimizedSize
];
1821 bzero(newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
1823 // make a string pool
1824 StringPool stringPool
;
1826 // create optimizer object for each LINKEDIT segment
1827 std::vector
<LinkEditOptimizer
<A
>*> optimizers
;
1828 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1829 optimizers
.push_back(new LinkEditOptimizer
<A
>(*it
->layout
, *this, newLinkEdit
, stringPool
));
1832 // rebase info is not copied because images in shared cache are never rebased
1834 // copy weak bind info
1835 uint32_t offset
= 0;
1836 fOffsetOfWeakBindInfoInCombinedLinkedit
= offset
;
1837 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1838 (*it
)->copyWeakBindInfo(offset
);
1842 fOffsetOfExportInfoInCombinedLinkedit
= offset
;
1843 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1844 (*it
)->copyExportInfo(offset
);
1848 fOffsetOfBindInfoInCombinedLinkedit
= offset
;
1849 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1850 (*it
)->copyBindInfo(offset
);
1853 // copy lazy bind info
1854 fOffsetOfLazyBindInfoInCombinedLinkedit
= offset
;
1855 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1856 (*it
)->copyLazyBindInfo(offset
);
1859 // copy symbol table entries
1860 fOffsetOfOldSymbolTableInfoInCombinedLinkedit
= offset
;
1861 uint32_t symbolTableOffset
= offset
;
1862 uint32_t symbolTableIndex
= 0;
1863 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1864 (*it
)->copyLocalSymbols(symbolTableOffset
, symbolTableIndex
);
1865 (*it
)->copyExportedSymbols(symbolTableOffset
, symbolTableIndex
);
1866 (*it
)->copyImportedSymbols(symbolTableOffset
, symbolTableIndex
);
1868 fSizeOfOldSymbolTableInfoInCombinedLinkedit
= symbolTableIndex
* sizeof(macho_nlist
<typename
A::P
>);
1869 offset
= symbolTableOffset
+ fSizeOfOldSymbolTableInfoInCombinedLinkedit
& (-8);
1871 // copy external relocations, 8-byte aligned after end of symbol table
1872 fOffsetOfOldExternalRelocationsInCombinedLinkedit
= offset
;
1873 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1874 (*it
)->copyExternalRelocations(offset
);
1876 fSizeOfOldExternalRelocationsInCombinedLinkedit
= offset
- fOffsetOfOldExternalRelocationsInCombinedLinkedit
;
1878 // copy function starts
1879 fOffsetOfFunctionStartsInCombinedLinkedit
= offset
;
1880 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1881 (*it
)->copyFunctionStarts(offset
);
1883 fSizeOfFunctionStartsInCombinedLinkedit
= offset
- fOffsetOfFunctionStartsInCombinedLinkedit
;
1885 // copy indirect symbol tables
1886 fOffsetOfOldIndirectSymbolsInCombinedLinkedit
= offset
;
1887 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1888 (*it
)->copyIndirectSymbolTable(offset
);
1890 fSizeOfOldIndirectSymbolsInCombinedLinkedit
= offset
- fOffsetOfOldIndirectSymbolsInCombinedLinkedit
;
1893 fOffsetOfOldStringPoolInCombinedLinkedit
= offset
;
1894 memcpy(&newLinkEdit
[offset
], stringPool
.getBuffer(), stringPool
.size());
1895 fSizeOfOldStringPoolInCombinedLinkedit
= stringPool
.size();
1897 // total new size round up to page size
1898 fLinkEditsTotalOptimizedSize
= (fOffsetOfOldStringPoolInCombinedLinkedit
+ fSizeOfOldStringPoolInCombinedLinkedit
+ 4095) & (-4096);
1900 // choose new linkedit file offset
1901 uint32_t linkEditsFileOffset
= cacheFileOffsetForVMAddress(fLinkEditsStartAddress
);
1902 // uint32_t linkEditsFileOffset = fLinkEditsStartAddress - sharedRegionReadOnlyStartAddress();
1904 // update load commands so that all dylibs shared different areas of the same LINKEDIT segment
1905 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1906 (*it
)->updateLoadCommands(fLinkEditsStartAddress
, fLinkEditsTotalUnoptimizedSize
, fOffsetOfOldStringPoolInCombinedLinkedit
, linkEditsFileOffset
, keepSignatures
);
1909 //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, fLinkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, fLinkEditsTotalOptimizedSize);
1910 //printf(stderr, "mega link edit mapped starting at: %p\n", fFirstLinkEditSegment->mappedAddress());
1912 // overwrite mapped LINKEDIT area with new optimized LINKEDIT segment
1913 memcpy(fFirstLinkEditSegment
->mappedAddress(), newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
1915 // update all LINKEDIT Segment objects to point to same merged LINKEDIT area
1916 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1917 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1918 for(int i
=0; i
< segs
.size(); ++i
) {
1919 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1920 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
1921 seg
.setNewAddress(fLinkEditsStartAddress
);
1922 seg
.setMappedAddress(fFirstLinkEditSegment
->mappedAddress());
1923 seg
.setSize(fLinkEditsTotalOptimizedSize
);
1924 seg
.setFileSize(fLinkEditsTotalOptimizedSize
);
1925 seg
.setFileOffset(linkEditsFileOffset
);
1930 // return new end of cache
1931 return (uint8_t*)fFirstLinkEditSegment
->mappedAddress() + fLinkEditsTotalOptimizedSize
;
1936 template <typename A
>
1937 class ObjCSelectorUniquer
1940 objc_opt::string_map fSelectorStrings
;
1941 SharedCache
<A
> *fCache
;
1946 ObjCSelectorUniquer(SharedCache
<A
> *newCache
)
1947 : fSelectorStrings()
1952 typename
A::P::uint_t
visit(typename
A::P::uint_t oldValue
)
1955 const char *s
= (const char *)
1956 fCache
->mappedAddressForVMAddress(oldValue
);
1957 objc_opt::string_map::iterator element
=
1958 fSelectorStrings
.insert(objc_opt::string_map::value_type(s
, oldValue
)).first
;
1959 return (typename
A::P::uint_t
)element
->second
;
1962 objc_opt::string_map
& strings() {
1963 return fSelectorStrings
;
1966 size_t count() const { return fCount
; }
1969 template <typename A
>
1970 void SharedCache
<A
>::optimizeObjC(std::vector
<void*>& pointersInData
)
1973 size_t headerSize
= sizeof(objc_opt::objc_opt_t
);
1976 fprintf(stderr
, "update_dyld_shared_cache: for %s, optimizing objc metadata\n", archName());
1979 // Find libobjc's empty sections to fill in
1980 const macho_section
<P
> *optROSection
= NULL
;
1981 const macho_section
<P
> *optRWSection
= NULL
;
1982 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1983 if ( strstr(it
->layout
->getFilePath(), "libobjc") != NULL
) {
1984 const macho_header
<P
>* mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
1985 optROSection
= mh
->getSection("__TEXT", "__objc_opt_ro");
1986 // __objc_selopt is old name for __objc_opt_ro
1987 if ( optROSection
== NULL
)
1988 optROSection
= mh
->getSection("__TEXT", "__objc_selopt");
1989 optRWSection
= mh
->getSection("__DATA", "__objc_opt_rw");
1994 if ( optROSection
== NULL
) {
1995 warn(archName(), "libobjc's read-only section missing (metadata not optimized)");
1999 objc_opt::objc_opt_t
* optROHeader
= (objc_opt::objc_opt_t
*)mappedAddressForVMAddress(optROSection
->addr());
2000 if (optROSection
->size() < headerSize
) {
2001 warn(archName(), "libobjc's read-only section is too small (metadata not optimized)");
2005 if (E::get32(optROHeader
->version
) != objc_opt::VERSION
) {
2006 warn(archName(), "libobjc's read-only section version is unrecognized (metadata not optimized)");
2010 // Update selector references and build selector list
2012 // This is SAFE: if we run out of room for the selector table,
2013 // the modified binaries are still usable.
2015 // Heuristic: choose selectors from libraries with more cstring data first.
2016 // This tries to localize selector cstring memory.
2017 ObjCSelectorUniquer
<A
> uniq(this);
2018 std::vector
<LayoutInfo
> sortedDylibs
= fDylibs
;
2019 std::sort(sortedDylibs
.begin(), sortedDylibs
.end(), ByCStringSectionSizeSorter());
2021 SelectorOptimizer
<A
, ObjCSelectorUniquer
<A
> > selOptimizer(uniq
);
2022 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sortedDylibs
.begin(); it
!= sortedDylibs
.end(); ++it
) {
2023 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2024 LegacySelectorUpdater
<A
, ObjCSelectorUniquer
<A
> >::update(this, mh
, uniq
);
2025 selOptimizer
.optimize(this, mh
);
2029 fprintf(stderr
, "update_dyld_shared_cache: for %s, found %zu unique objc selectors\n", archName(), uniq
.strings().size());
2032 // Write selector table in read-only data.
2033 size_t selTableOffset
= P::round_up(headerSize
);
2034 size_t selTableSize
;
2035 objc_opt::objc_selopt_t
*seloptData
= (objc_opt::objc_selopt_t
*)
2036 mappedAddressForVMAddress(optROSection
->addr() + selTableOffset
);
2037 err
= objc_opt::write_selopt(seloptData
,
2038 optROSection
->addr() + selTableOffset
,
2039 optROSection
->size() - selTableOffset
,
2041 E::little_endian
, &selTableSize
);
2043 warn(archName(), err
);
2048 size_t totalSize
= headerSize
+ selTableSize
;
2049 fprintf(stderr
, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
2050 "(%d%%) used in libobjc read-only optimization section\n",
2051 archName(), totalSize
, optROSection
->size(),
2052 (int)(totalSize
/ (double)optROSection
->size() * 100));
2053 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2054 "updated %zu selector references\n",
2055 archName(), uniq
.count());
2056 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2057 "wrote objc metadata optimization version %d\n",
2058 archName(), objc_opt::VERSION
);
2061 // if r/w section exists in libojc attempt to optimize categories into classes
2062 if ( optRWSection
!= NULL
) {
2063 // Attach categories to classes in the same framework.
2064 // Build aggregated (but unsorted) method lists in read-write data.
2066 // This is SAFE: if we run out of room while attaching categories in
2067 // a binary then previously-edited binaries are still valid. (This assumes
2068 // each binary is processed all-or-nothing, which CategoryAttacher does.)
2069 // This must be done AFTER uniquing selectors.
2070 // This must be done BEFORE sorting method lists.
2072 size_t categoryOffset
= 0;
2073 uint8_t *categoryData
= (uint8_t*)mappedAddressForVMAddress(optRWSection
->addr() + categoryOffset
);
2074 CategoryAttacher
<A
> categoryAttacher(categoryData
, optRWSection
->size() - categoryOffset
);
2075 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sortedDylibs
.begin(); it
!= sortedDylibs
.end(); ++it
) {
2076 macho_header
<P
> *mh
= (macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2077 err
= categoryAttacher
.optimize(this, mh
, pointersInData
);
2079 warn(archName(), err
);
2083 size_t categorySize
= categoryAttacher
.bytesUsed();
2086 // Sort method lists.
2088 // This is SAFE: modified binaries are still usable as unsorted lists.
2089 // This must be done AFTER uniquing selectors.
2090 // This must be done AFTER attaching categories.
2092 MethodListSorter
<A
> methodSorter
;
2093 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sortedDylibs
.begin(); it
!= sortedDylibs
.end(); ++it
) {
2094 macho_header
<P
> *mh
= (macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2095 methodSorter
.optimize(this, mh
);
2099 size_t totalRWSize
= categorySize
;
2100 fprintf(stderr
, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
2101 "(%d%%) used in libobjc read-write optimization section\n",
2102 archName(), totalRWSize
, optRWSection
->size(),
2103 (int)(totalRWSize
/ (double)optRWSection
->size() * 100));
2104 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2105 "attached %zu categories (%zd bytes used)\n",
2106 archName(), categoryAttacher
.count(),
2107 categoryAttacher
.bytesUsed());
2111 // Success. Update RO header last
2112 E::set32(optROHeader
->selopt_offset
, headerSize
);
2118 static const char* sCleanupFile
= NULL
;
2119 static void cleanup(int sig
)
2121 ::signal(sig
, SIG_DFL
);
2122 if ( sCleanupFile
!= NULL
)
2123 ::unlink(sCleanupFile
);
2125 // fprintf(stderr, "update_dyld_shared_cache: deleting temp file in response to a signal\n");
2126 if ( sig
== SIGINT
)
2132 template <> bool SharedCache
<x86_64
>::addCacheSlideInfo(){ return true; }
2133 template <> bool SharedCache
<arm
>::addCacheSlideInfo() { return true; }
2134 template <> bool SharedCache
<x86
>::addCacheSlideInfo() { return false; }
2135 template <> bool SharedCache
<ppc
>::addCacheSlideInfo() { return false; }
2139 template <typename A
>
2140 bool SharedCache
<A
>::update(bool usesOverlay
, bool force
, bool optimize
, bool deleteExistingFirst
, int archIndex
,
2141 int archCount
, bool keepSignatures
)
2143 bool didUpdate
= false;
2145 // already up to date?
2146 if ( force
|| fExistingIsNotUpToDate
) {
2148 fprintf(stderr
, "update_dyld_shared_cache: regenerating %s\n", fCacheFilePath
);
2149 if ( fDylibs
.size() == 0 ) {
2150 fprintf(stderr
, "update_dyld_shared_cache: warning, empty cache not generated for arch %s\n", archName());
2153 // delete existing cache while building the new one
2154 // this is a flag to dyld to stop pinging update_dyld_shared_cache
2155 if ( deleteExistingFirst
)
2156 ::unlink(fCacheFilePath
);
2157 uint8_t* inMemoryCache
= NULL
;
2158 uint32_t allocatedCacheSize
= 0;
2159 char tempCachePath
[strlen(fCacheFilePath
)+16];
2160 sprintf(tempCachePath
, "%s.tmp%u", fCacheFilePath
, getpid());
2162 // allocate a memory block to hold cache
2163 uint32_t cacheFileSize
= 0;
2164 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
2165 uint32_t end
= it
->sfm_file_offset
+ it
->sfm_size
;
2166 if ( end
> cacheFileSize
)
2167 cacheFileSize
= end
;
2169 if ( vm_allocate(mach_task_self(), (vm_address_t
*)(&inMemoryCache
), cacheFileSize
, VM_FLAGS_ANYWHERE
) != KERN_SUCCESS
)
2170 throwf("can't vm_allocate cache of size %u", cacheFileSize
);
2171 allocatedCacheSize
= cacheFileSize
;
2172 fInMemoryCache
= inMemoryCache
;
2175 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2176 const char* archPairName
= fArchGraph
->archName();
2178 strcpy(temp
, "dyld_v1 ");
2179 strcpy(&temp
[15-strlen(archPairName
)], archPairName
);
2180 header
->set_magic(temp
);
2181 //header->set_architecture(arch());
2182 header
->set_mappingOffset(sizeof(dyldCacheHeader
<E
>));
2183 header
->set_mappingCount(fMappings
.size());
2184 header
->set_imagesOffset(header
->mappingOffset() + fMappings
.size()*sizeof(dyldCacheFileMapping
<E
>));
2185 header
->set_imagesCount(fDylibs
.size()+fDylibAliases
.size());
2186 header
->set_dyldBaseAddress(fDyldBaseAddress
);
2187 header
->set_codeSignatureOffset(cacheFileSize
);
2188 header
->set_codeSignatureSize(0);
2189 header
->set_slideInfoOffset(0);
2190 header
->set_slideInfoSize(0);
2193 dyldCacheFileMapping
<E
>* mapping
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
2194 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
2196 fprintf(stderr
, "update_dyld_shared_cache: cache mappings: address=0x%0llX, size=0x%0llX, fileOffset=0x%0llX, prot=0x%X\n",
2197 it
->sfm_address
, it
->sfm_size
, it
->sfm_file_offset
, it
->sfm_init_prot
);
2198 mapping
->set_address(it
->sfm_address
);
2199 mapping
->set_size(it
->sfm_size
);
2200 mapping
->set_file_offset(it
->sfm_file_offset
);
2201 mapping
->set_max_prot(it
->sfm_max_prot
);
2202 mapping
->set_init_prot(it
->sfm_init_prot
);
2206 // fill in image table
2207 dyldCacheImageInfo
<E
>* image
= (dyldCacheImageInfo
<E
>*)mapping
;
2208 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2209 image
->set_address(it
->info
.address
);
2210 image
->set_modTime(it
->info
.modTime
);
2211 image
->set_inode(it
->info
.inode
);
2212 image
->set_pathFileOffset(cacheFileOffsetForVMAddress(it
->info
.address
+it
->info
.pathFileOffset
));
2216 // add aliases to end of image table
2217 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibAliases
.begin(); it
!= fDylibAliases
.end(); ++it
) {
2218 image
->set_address(it
->info
.address
);
2219 image
->set_modTime(it
->info
.modTime
);
2220 image
->set_inode(it
->info
.inode
);
2221 image
->set_pathFileOffset(it
->info
.pathFileOffset
);
2222 strcpy((char*)inMemoryCache
+it
->info
.pathFileOffset
, it
->aliases
[0]);
2223 //fprintf(stderr, "adding alias to offset 0x%08X %s\n", it->info.pathFileOffset, it->aliases[0]);
2227 // copy each segment to cache buffer
2228 const int dylibCount
= fDylibs
.size();
2230 int progressIndex
= 0;
2231 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++dylibIndex
) {
2232 const char* path
= it
->layout
->getFilePath();
2233 int src
= ::open(path
, O_RDONLY
, 0);
2235 throwf("can't open file %s, errnor=%d", it
->layout
->getID().name
, errno
);
2236 // mark source as "don't cache"
2237 (void)fcntl(src
, F_NOCACHE
, 1);
2238 // verify file has not changed since dependency analysis
2239 struct stat stat_buf
;
2240 if ( fstat(src
, &stat_buf
) == -1)
2241 throwf("can't stat open file %s, errno=%d", path
, errno
);
2242 if ( (it
->layout
->getInode() != stat_buf
.st_ino
) || (it
->layout
->getLastModTime() != stat_buf
.st_mtime
) )
2243 throwf("file modified during cache creation: %s", path
);
2246 fprintf(stderr
, "update_dyld_shared_cache: copying %s to cache\n", it
->layout
->getID().name
);
2248 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
2249 for (int i
=0; i
< segs
.size(); ++i
) {
2250 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
2252 fprintf(stderr
, "\t\tsegment %s, size=0x%0llX, cache address=0x%0llX\n", seg
.name(), seg
.fileSize(), seg
.newAddress());
2253 if ( seg
.size() > 0 ) {
2254 const uint64_t segmentSrcStartOffset
= it
->layout
->getOffsetInUniversalFile()+seg
.fileOffset();
2255 const uint64_t segmentSize
= seg
.fileSize();
2256 const uint64_t segmentDstStartOffset
= cacheFileOffsetForVMAddress(seg
.newAddress());
2257 ssize_t readResult
= ::pread(src
, &inMemoryCache
[segmentDstStartOffset
], segmentSize
, segmentSrcStartOffset
);
2258 if ( readResult
!= segmentSize
) {
2259 if ( readResult
== -1 )
2260 throwf("read failure copying dylib errno=%d for %s", errno
, it
->layout
->getID().name
);
2262 throwf("read failure copying dylib. Read of %lld bytes at file offset %lld returned %ld for %s",
2263 segmentSize
, segmentSrcStartOffset
, readResult
, it
->layout
->getID().name
);
2268 catch (const char* msg
) {
2269 throwf("%s while copying %s to shared cache", msg
, it
->layout
->getID().name
);
2273 // assuming read takes 40% of time
2274 int nextProgressIndex
= archIndex
*100+(40*dylibIndex
)/dylibCount
;
2275 if ( nextProgressIndex
!= progressIndex
)
2276 fprintf(stdout
, "%3u/%u\n", nextProgressIndex
, archCount
*100);
2277 progressIndex
= nextProgressIndex
;
2281 // set mapped address for each segment
2282 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2283 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
2284 for (int i
=0; i
< segs
.size(); ++i
) {
2285 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
2286 if ( seg
.size() > 0 )
2287 seg
.setMappedAddress(inMemoryCache
+ cacheFileOffsetForVMAddress(seg
.newAddress()));
2288 //fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
2292 // also construct list of all pointers in cache to other things in cache
2293 std::vector
<void*> pointersInData
;
2294 pointersInData
.reserve(1024);
2296 // add pointer in start of __DATA to start of __TEXT to remain compatible with previous dylds
2297 pint_t
* dataStartPtr
= (pint_t
*)(&inMemoryCache
[fMappings
[1].sfm_file_offset
]);
2298 P::setP(*dataStartPtr
, fMappings
[0].sfm_address
);
2300 // rebase each dylib in shared cache
2301 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2303 Rebaser
<A
> r(*it
->layout
);
2304 r
.rebase(pointersInData
);
2306 // fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
2308 catch (const char* msg
) {
2309 throwf("%s in %s", msg
, it
->layout
->getID().name
);
2314 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs
.size());
2315 // instantiate a Binder for each image and add to map
2316 typename Binder
<A
>::Map map
;
2317 std::vector
<Binder
<A
>*> binders
;
2318 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2319 //fprintf(stderr, "binding %s\n", it->layout->getID().name);
2320 Binder
<A
>* binder
= new Binder
<A
>(*it
->layout
, fDyldBaseAddress
);
2321 binders
.push_back(binder
);
2322 // only add dylibs to map
2323 if ( it
->layout
->getID().name
!= NULL
)
2324 map
[it
->layout
->getID().name
] = binder
;
2327 // tell each Binder about the others
2328 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2329 (*it
)->setDependentBinders(map
);
2332 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2334 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it
)->getDylibID());
2336 (*it
)->bind(pointersInData
);
2338 catch (const char* msg
) {
2339 throwf("%s in %s", msg
, (*it
)->getDylibID());
2343 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2347 catch (const char* msg
) {
2348 throwf("%s in %s", msg
, (*it
)->getDylibID());
2352 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2356 // merge/optimize all LINKEDIT segments
2358 //fprintf(stderr, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize/(1024*1024));
2359 cacheFileSize
= (this->optimizeLINKEDIT(keepSignatures
) - inMemoryCache
);
2360 //fprintf(stderr, "update_dyld_shared_cache: optimized cache file size %uMB\n", cacheFileSize/(1024*1024));
2361 // update header to reduce mapping size
2362 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2363 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
2364 dyldCacheFileMapping
<E
>* lastMapping
= &mappings
[cacheHeader
->mappingCount()-1];
2365 lastMapping
->set_size(cacheFileSize
-lastMapping
->file_offset());
2366 // update fMappings so .map file will print correctly
2367 fMappings
.back().sfm_size
= cacheFileSize
-fMappings
.back().sfm_file_offset
;
2369 //fprintf(stderr, "update_dyld_shared_cache: changing end of cache address from 0x%08llX to 0x%08llX\n",
2370 // header->codeSignatureOffset(), fMappings.back().sfm_address + fMappings.back().sfm_size);
2371 header
->set_codeSignatureOffset(fMappings
.back().sfm_file_offset
+ fMappings
.back().sfm_size
);
2374 // unique objc selectors and update other objc metadata
2376 optimizeObjC(pointersInData
);
2378 // assuming objc optimizations takes 15% of time
2379 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*55, archCount
*100);
2383 if ( addCacheSlideInfo() ) {
2384 // build bitmap of which pointers need sliding
2385 uint8_t* const dataStart
= &inMemoryCache
[fMappings
[1].sfm_file_offset
]; // R/W mapping is always second
2386 uint8_t* const dataEnd
= &inMemoryCache
[fMappings
[1].sfm_file_offset
+fMappings
[1].sfm_size
];
2387 const int bitmapSize
= (dataEnd
- dataStart
)/(4*8);
2388 uint8_t* bitmap
= (uint8_t*)calloc(bitmapSize
, 1);
2389 void* lastPointer
= inMemoryCache
;
2390 for(std::vector
<void*>::iterator pit
=pointersInData
.begin(); pit
!= pointersInData
.end(); ++pit
) {
2391 if ( *pit
!= lastPointer
) {
2393 if ( (p
< dataStart
) || ( p
> dataEnd
) )
2394 throwf("DATA pointer for sliding, out of range 0x%08lX\n", (long)((uint8_t*)p
-inMemoryCache
));
2395 long offset
= (long)((uint8_t*)p
- dataStart
);
2396 if ( (offset
% 4) != 0 )
2397 throwf("pointer not 4-byte aligned in DATA offset 0x%08lX\n", offset
);
2398 long byteIndex
= offset
/ (4*8);
2399 long bitInByte
= (offset
% 32) >> 2;
2400 bitmap
[byteIndex
] |= (1 << bitInByte
);
2405 // allocate worst case size block of all slide info
2406 const int entry_size
= 4096/(8*4); // 8 bits per byte, possible pointer every 4 bytes.
2407 const int toc_count
= bitmapSize
/entry_size
;
2408 int slideInfoSize
= sizeof(dyldCacheSlideInfo
<E
>) + 2*toc_count
+ entry_size
*(toc_count
+1);
2409 dyldCacheSlideInfo
<E
>* slideInfo
= (dyldCacheSlideInfo
<E
>*)calloc(slideInfoSize
, 1);
2410 slideInfo
->set_version(1);
2411 slideInfo
->set_toc_offset(sizeof(dyldCacheSlideInfo
<E
>));
2412 slideInfo
->set_toc_count(toc_count
);
2413 slideInfo
->set_entries_offset((slideInfo
->toc_offset()+2*toc_count
+127)&(-128));
2414 slideInfo
->set_entries_count(0);
2415 slideInfo
->set_entries_size(entry_size
);
2416 // append each unique entry
2417 const dyldCacheSlideInfoEntry
* bitmapAsEntries
= (dyldCacheSlideInfoEntry
*)bitmap
;
2418 dyldCacheSlideInfoEntry
* const entriesInSlidInfo
= (dyldCacheSlideInfoEntry
*)((char*)slideInfo
+slideInfo
->entries_offset());
2419 int entry_count
= 0;
2420 for (int i
=0; i
< toc_count
; ++i
) {
2421 const dyldCacheSlideInfoEntry
* thisEntry
= &bitmapAsEntries
[i
];
2422 // see if it is same as one already added
2424 for (int j
=0; j
< entry_count
; ++j
) {
2425 if ( memcmp(thisEntry
, &entriesInSlidInfo
[j
], entry_size
) == 0 ) {
2426 //fprintf(stderr, "toc[%d] optimized to %d\n", i, j);
2427 slideInfo
->set_toc(i
, j
);
2434 memcpy(&entriesInSlidInfo
[entry_count
], thisEntry
, entry_size
);
2435 slideInfo
->set_toc(i
, entry_count
++);
2438 slideInfo
->set_entries_count(entry_count
);
2440 int slideInfoPageSize
= (slideInfo
->entries_offset() + entry_count
*entry_size
+ 4095) & (-4096);
2441 cacheFileSize
+= slideInfoPageSize
;
2443 // update mappings to increase RO size
2444 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2445 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
2446 dyldCacheFileMapping
<E
>* lastMapping
= &mappings
[cacheHeader
->mappingCount()-1];
2447 lastMapping
->set_size(lastMapping
->size()+slideInfoPageSize
);
2449 // update header to show location of slidePointers
2450 cacheHeader
->set_slideInfoOffset(cacheHeader
->codeSignatureOffset());
2451 cacheHeader
->set_slideInfoSize(slideInfoPageSize
);
2452 cacheHeader
->set_codeSignatureOffset(cacheHeader
->codeSignatureOffset()+slideInfoPageSize
);
2454 // update fMappings so .map file will print correctly
2455 fMappings
.back().sfm_size
= cacheFileSize
-fMappings
.back().sfm_file_offset
;
2457 // copy compressed into into buffer
2458 memcpy(&inMemoryCache
[cacheHeader
->slideInfoOffset()], slideInfo
, slideInfoPageSize
);
2463 // if no existing cache, say so
2464 if ( fExistingCacheForVerification
== NULL
) {
2465 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
2466 getpid(), archName());
2468 // new cache is built, compare header entries
2469 const dyldCacheHeader
<E
>* newHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2470 const dyldCacheHeader
<E
>* oldHeader
= (dyldCacheHeader
<E
>*)fExistingCacheForVerification
;
2471 if ( newHeader
->mappingCount() != oldHeader
->mappingCount() ) {
2472 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because caches have a different number of mappings\n",
2473 getpid(), archName());
2475 const dyldCacheFileMapping
<E
>* newMappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[newHeader
->mappingOffset()];
2476 const dyldCacheFileMapping
<E
>* oldMappings
= (dyldCacheFileMapping
<E
>*)&fExistingCacheForVerification
[oldHeader
->mappingOffset()];
2477 for (int i
=0; i
< newHeader
->mappingCount(); ++i
) {
2478 if ( newMappings
[i
].address() != oldMappings
[i
].address() ) {
2479 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because mapping %d starts at a different address 0x%0llX vs 0x%0llX\n",
2480 getpid(), archName(), i
, newMappings
[i
].address(), oldMappings
[i
].address() );
2482 if ( newMappings
[i
].size() != oldMappings
[i
].size() ) {
2483 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because mapping %d has a different size\n",
2484 getpid(), archName(), i
);
2488 //fprintf(stderr, "%s existing cache = %p\n", archName(), fExistingCacheForVerification);
2489 //fprintf(stderr, "%s new cache = %p\n", archName(), inMemoryCache);
2490 // compare content to existing cache page by page
2491 for (int offset
=0; offset
< cacheFileSize
; offset
+= 4096) {
2492 if ( memcmp(&inMemoryCache
[offset
], &fExistingCacheForVerification
[offset
], 4096) != 0 ) {
2493 fprintf(stderr
, "verifier found differences on page offset 0x%08X for %s:\n", offset
, archName());
2494 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++dylibIndex
) {
2495 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
2496 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator sit
= segs
.begin(); sit
!= segs
.end(); ++sit
) {
2497 const MachOLayoutAbstraction::Segment
& seg
= *sit
;
2498 if ( (seg
.mappedAddress() <= &inMemoryCache
[offset
]) && (&inMemoryCache
[offset
] < ((uint8_t*)seg
.mappedAddress() + seg
.fileSize())) ) {
2499 // all LINKEDITs point to the same region, so just print one
2500 if ( strcmp(seg
.name(), "__LINKEDIT") == 0 )
2501 fprintf(stderr
, " in merged LINKEDIT segment\n");
2503 fprintf(stderr
, " in segment %s of dylib %s\n", seg
.name(), it
->layout
->getID().name
);
2508 for (int po
=0; po
< 4096; po
+= 16) {
2509 if ( memcmp(&inMemoryCache
[offset
+po
], &fExistingCacheForVerification
[offset
+po
], 16) != 0 ) {
2510 fprintf(stderr
, " existing: 0x%08X: ", offset
+po
);
2511 for ( int j
=0; j
< 16; ++j
)
2512 fprintf(stderr
, " 0x%02X", fExistingCacheForVerification
[offset
+po
+j
]);
2513 fprintf(stderr
, "\n");
2514 fprintf(stderr
, " should be: 0x%08X: ", offset
+po
);
2515 for ( int j
=0; j
< 16; ++j
)
2516 fprintf(stderr
, " 0x%02X", inMemoryCache
[offset
+po
+j
]);
2517 fprintf(stderr
, "\n");
2524 // install signal handlers to delete temp file if program is killed
2525 sCleanupFile
= tempCachePath
;
2526 ::signal(SIGINT
, cleanup
);
2527 ::signal(SIGBUS
, cleanup
);
2528 ::signal(SIGSEGV
, cleanup
);
2530 // create var/db/dyld dirs if needed
2531 char dyldDirs
[1024];
2532 strcpy(dyldDirs
, fCacheFilePath
);
2533 char* lastSlash
= strrchr(dyldDirs
, '/');
2534 if ( lastSlash
!= NULL
)
2535 lastSlash
[1] = '\0';
2536 struct stat stat_buf
;
2537 if ( stat(dyldDirs
, &stat_buf
) != 0 ) {
2538 const char* afterSlash
= &dyldDirs
[1];
2540 while ( (slash
= strchr(afterSlash
, '/')) != NULL
) {
2542 ::mkdir(dyldDirs
, S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
);
2544 afterSlash
= slash
+1;
2548 // create temp file for cache
2549 int fd
= ::open(tempCachePath
, O_CREAT
| O_RDWR
| O_TRUNC
, 0644);
2551 throwf("can't create temp file %s, errnor=%d", tempCachePath
, errno
);
2553 // try to allocate whole cache file contiguously
2554 fstore_t fcntlSpec
= { F_ALLOCATECONTIG
|F_ALLOCATEALL
, F_PEOFPOSMODE
, 0, cacheFileSize
, 0 };
2555 ::fcntl(fd
, F_PREALLOCATE
, &fcntlSpec
);
2557 // write out cache file
2559 fprintf(stderr
, "update_dyld_shared_cache: writing cache to disk\n");
2560 if ( ::pwrite(fd
, inMemoryCache
, cacheFileSize
, 0) != cacheFileSize
)
2561 throwf("write() failure creating cache file, errno=%d", errno
);
2563 // assuming write takes 35% of time
2564 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*90, archCount
*100);
2567 // flush to disk and close
2568 int result
= ::fcntl(fd
, F_FULLFSYNC
, NULL
);
2570 fprintf(stderr
, "update_dyld_shared_cache: warning, fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno
, tempCachePath
);
2571 result
= ::close(fd
);
2573 fprintf(stderr
, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno
, tempCachePath
);
2575 // <rdar://problem/7901042> Make life easier for the kernel at shutdown.
2576 // If we just move the new cache file over the old, the old file
2577 // may need to exist in the open-unlink state. But because it
2578 // may be mapped into the shared region, it cannot be deleted
2579 // until all user processes are terminated. That leaves are
2580 // small to non-existent window for the kernel to delete the
2582 if ( fCacheFileInFinalLocation
) {
2583 char tmpDirPath
[64];
2584 const char* pathLastSlash
= strrchr(fCacheFilePath
, '/');
2585 if ( pathLastSlash
!= NULL
) {
2586 sprintf(tmpDirPath
, "/var/run%s.old.%u", pathLastSlash
, getpid());
2587 // move existing cache file to /var/run to be clean up next boot
2588 result
= ::rename(fCacheFilePath
, tmpDirPath
);
2589 if ( result
!= 0 ) {
2590 if ( errno
!= ENOENT
)
2591 fprintf(stderr
, "update_dyld_shared_cache: warning, unable to move existing cache to %s errno=%d for %s\n", tmpDirPath
, errno
, fCacheFilePath
);
2596 // move new cache file to correct location for use after reboot
2597 result
= ::rename(tempCachePath
, fCacheFilePath
);
2599 throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath
, fCacheFilePath
, errno
);
2602 // flush everything to disk to assure rename() gets recorded
2606 // restore default signal handlers
2607 ::signal(SIGINT
, SIG_DFL
);
2608 ::signal(SIGBUS
, SIG_DFL
);
2609 ::signal(SIGSEGV
, SIG_DFL
);
2611 // generate human readable "map" file that shows the layout of the cache file
2613 fprintf(stderr
, "update_dyld_shared_cache: writing .map file to disk\n");
2614 char mapFilePath
[strlen(fCacheFilePath
)+16];
2615 sprintf(mapFilePath
, "%s.map", fCacheFilePath
);
2616 char tempMapFilePath
[strlen(fCacheFilePath
)+32];
2617 sprintf(tempMapFilePath
, "%s.map%u", fCacheFilePath
, getpid());
2618 FILE* fmap
= ::fopen(tempMapFilePath
, "w");
2619 if ( fmap
== NULL
) {
2620 fprintf(stderr
, "can't create map file %s, errnor=%d", tempCachePath
, errno
);
2623 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
2624 const char* prot
= "RW";
2625 if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_READ
) )
2627 else if ( it
->sfm_init_prot
== VM_PROT_READ
)
2629 else if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_WRITE
|VM_PROT_READ
) )
2631 if ( it
->sfm_size
> 1024*1024 )
2632 fprintf(fmap
, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/(1024*1024),
2633 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
2635 fprintf(fmap
, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/1024,
2636 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
2639 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX weak binding info\n",
2640 (fOffsetOfExportInfoInCombinedLinkedit
-fOffsetOfWeakBindInfoInCombinedLinkedit
)/1024,
2641 fLinkEditsStartAddress
+fOffsetOfWeakBindInfoInCombinedLinkedit
,
2642 fLinkEditsStartAddress
+fOffsetOfExportInfoInCombinedLinkedit
);
2643 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX export info\n",
2644 (fOffsetOfBindInfoInCombinedLinkedit
-fOffsetOfExportInfoInCombinedLinkedit
)/1024,
2645 fLinkEditsStartAddress
+fOffsetOfExportInfoInCombinedLinkedit
,
2646 fLinkEditsStartAddress
+fOffsetOfBindInfoInCombinedLinkedit
);
2647 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX binding info\n",
2648 (fOffsetOfLazyBindInfoInCombinedLinkedit
-fOffsetOfBindInfoInCombinedLinkedit
)/1024,
2649 fLinkEditsStartAddress
+fOffsetOfBindInfoInCombinedLinkedit
,
2650 fLinkEditsStartAddress
+fOffsetOfLazyBindInfoInCombinedLinkedit
);
2651 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX lazy binding info\n",
2652 (fOffsetOfOldSymbolTableInfoInCombinedLinkedit
-fOffsetOfLazyBindInfoInCombinedLinkedit
)/1024,
2653 fLinkEditsStartAddress
+fOffsetOfLazyBindInfoInCombinedLinkedit
,
2654 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
);
2655 fprintf(fmap
, "linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld symbol table size\n",
2656 (fSizeOfOldSymbolTableInfoInCombinedLinkedit
)/(1024*1024),
2657 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
,
2658 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
+fSizeOfOldSymbolTableInfoInCombinedLinkedit
);
2659 if ( fSizeOfFunctionStartsInCombinedLinkedit
!= 0 )
2660 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld functions starts size\n",
2661 fSizeOfFunctionStartsInCombinedLinkedit
/1024,
2662 fLinkEditsStartAddress
+fOffsetOfFunctionStartsInCombinedLinkedit
,
2663 fLinkEditsStartAddress
+fOffsetOfFunctionStartsInCombinedLinkedit
+fSizeOfFunctionStartsInCombinedLinkedit
);
2664 if ( fSizeOfOldExternalRelocationsInCombinedLinkedit
!= 0 )
2665 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld external relocs size\n",
2666 fSizeOfOldExternalRelocationsInCombinedLinkedit
/1024,
2667 fLinkEditsStartAddress
+fOffsetOfOldExternalRelocationsInCombinedLinkedit
,
2668 fLinkEditsStartAddress
+fOffsetOfOldExternalRelocationsInCombinedLinkedit
+fSizeOfOldExternalRelocationsInCombinedLinkedit
);
2669 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld indirect symbol table size\n",
2670 fSizeOfOldIndirectSymbolsInCombinedLinkedit
/1024,
2671 fLinkEditsStartAddress
+fOffsetOfOldIndirectSymbolsInCombinedLinkedit
,
2672 fLinkEditsStartAddress
+fOffsetOfOldIndirectSymbolsInCombinedLinkedit
+fSizeOfOldIndirectSymbolsInCombinedLinkedit
);
2673 fprintf(fmap
, "linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld string pool\n",
2674 (fSizeOfOldStringPoolInCombinedLinkedit
)/(1024*1024),
2675 fLinkEditsStartAddress
+fOffsetOfOldStringPoolInCombinedLinkedit
,
2676 fLinkEditsStartAddress
+fOffsetOfOldStringPoolInCombinedLinkedit
+fSizeOfOldStringPoolInCombinedLinkedit
);
2678 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2679 fprintf(fmap
, "%s\n", it
->layout
->getID().name
);
2680 for (std::vector
<const char*>::const_iterator ait
= it
->aliases
.begin(); ait
!= it
->aliases
.end(); ++ait
)
2681 fprintf(fmap
, "%s\n", *ait
);
2682 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
2683 for (int i
=0; i
< segs
.size(); ++i
) {
2684 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
2685 fprintf(fmap
, "\t%16s 0x%0llX -> 0x%0llX\n", seg
.name(), seg
.newAddress(), seg
.newAddress()+seg
.size());
2688 if ( warnings
.size() > 0 ) {
2689 fprintf(fmap
, "# Warnings:\n");
2690 for (std::vector
<const char*>::iterator it
=warnings
.begin(); it
!= warnings
.end(); ++it
) {
2691 fprintf(fmap
, "# %s\n", *it
);
2695 result
= ::rename(tempMapFilePath
, mapFilePath
);
2699 // free in memory cache
2700 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
2701 inMemoryCache
= NULL
;
2704 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*100, archCount
*100);
2708 // remove temp cache file
2709 ::unlink(tempCachePath
);
2710 // remove in memory cache
2711 if ( inMemoryCache
!= NULL
)
2712 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
2722 // The shared cache is driven by /var/db/dyld/shared_region_roots which contains
2723 // the paths used to search for dylibs that should go in the shared cache
2725 // Leading and trailing white space is ignored
2726 // Blank lines are ignored
2727 // Lines starting with # are ignored
2729 static void parsePathsFile(const char* filePath
, std::vector
<const char*>& paths
)
2731 // read in whole file
2732 int fd
= open(filePath
, O_RDONLY
, 0);
2734 fprintf(stderr
, "update_dyld_shared_cache: can't open file: %s\n", filePath
);
2737 struct stat stat_buf
;
2738 fstat(fd
, &stat_buf
);
2739 char* p
= (char*)malloc(stat_buf
.st_size
);
2741 fprintf(stderr
, "update_dyld_shared_cache: malloc failure\n");
2744 if ( read(fd
, p
, stat_buf
.st_size
) != stat_buf
.st_size
) {
2745 fprintf(stderr
, "update_dyld_shared_cache: can't read file: %s\n", filePath
);
2750 // parse into paths and add to vector
2751 char * const end
= &p
[stat_buf
.st_size
];
2752 enum { lineStart
, inSymbol
, inComment
} state
= lineStart
;
2753 char* symbolStart
= NULL
;
2754 for (char* s
= p
; s
< end
; ++s
) {
2760 else if ( !isspace(*s
) ) {
2768 // removing any trailing spaces
2770 while ( isspace(*last
) ) {
2774 // <rdar://problem/8305479> images in shared cache are bound against different IOKit than found at runtime
2775 // HACK: Just ignore the known bad IOKit
2776 if ( strcmp(symbolStart
, "/System/Library/Frameworks/IOKit.framework/IOKit") == 0 ) {
2777 fprintf(stderr
, "update_dyld_shared_cache: warning, ignoring /System/Library/Frameworks/IOKit.framework/IOKit\n");
2778 warnings
.push_back("update_dyld_shared_cache: warning, ignoring /System/Library/Frameworks/IOKit.framework/IOKit\n");
2781 paths
.push_back(symbolStart
);
2793 // Note: we do not free() the malloc buffer, because the strings in it are used by exec()
2798 static void setSharedDylibs(const char* rootPath
, bool usesOverlay
, const std::set
<ArchPair
>& onlyArchs
, std::vector
<const char*> rootsPaths
)
2800 // set file system root
2801 ArchGraph::setFileSystemRoot(rootPath
, usesOverlay
);
2803 // initialize all architectures requested
2804 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
2805 ArchGraph::addArchPair(*a
);
2807 // add roots to graph
2808 for(std::vector
<const char*>::const_iterator it
= rootsPaths
.begin(); it
!= rootsPaths
.end(); ++it
)
2809 ArchGraph::addRoot(*it
, onlyArchs
);
2811 // determine shared dylibs
2812 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
2813 ArchGraph::findSharedDylibs(*a
);
2817 static void scanForSharedDylibs(const char* rootPath
, bool usesOverlay
, const char* dirOfPathFiles
, const std::set
<ArchPair
>& onlyArchs
)
2819 char rootDirOfPathFiles
[strlen(rootPath
)+strlen(dirOfPathFiles
)+2];
2820 // in -overlay mode, still look for roots in /var/db/dyld
2821 // in -root mode, look for roots in /rootpath/var/db/dyld
2822 if ( !usesOverlay
&& (strlen(rootPath
) != 0) ) {
2823 strcpy(rootDirOfPathFiles
, rootPath
);
2824 strcat(rootDirOfPathFiles
, dirOfPathFiles
);
2825 dirOfPathFiles
= rootDirOfPathFiles
;
2828 // extract all root paths from files in "/var/db/dyld/shared_region_roots/"
2830 fprintf(stderr
, "update_dyld_shared_cache: finding roots in: %s\n", dirOfPathFiles
);
2831 std::vector
<const char*> rootsPaths
;
2832 DIR* dir
= ::opendir(dirOfPathFiles
);
2834 throwf("%s does not exist, errno=%d\n", dirOfPathFiles
, errno
);
2835 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
2836 if ( entry
->d_type
== DT_REG
|| entry
->d_type
== DT_UNKNOWN
) {
2837 // only look at regular files ending in .paths
2838 if ( strcmp(&entry
->d_name
[entry
->d_namlen
-6], ".paths") == 0 ) {
2839 struct stat tmpStatPathsFile
;
2840 char fullPath
[strlen(dirOfPathFiles
)+entry
->d_namlen
+2];
2841 strcpy(fullPath
, dirOfPathFiles
);
2842 strcat(fullPath
, "/");
2843 strcat(fullPath
, entry
->d_name
);
2844 if ( lstat(fullPath
, &tmpStatPathsFile
) == -1 ) {
2845 fprintf(stderr
, "update_dyld_shared_cache: can't access %s\n", fullPath
);
2847 else if ( S_ISREG(tmpStatPathsFile
.st_mode
) ) {
2848 parsePathsFile(fullPath
, rootsPaths
);
2851 fprintf(stderr
, "update_dyld_shared_cache: wrong file type for %s\n", fullPath
);
2855 fprintf(stderr
, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry
->d_name
);
2861 if ( rootsPaths
.size() == 0 )
2862 fprintf(stderr
, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
2863 setSharedDylibs(rootPath
, usesOverlay
, onlyArchs
, rootsPaths
);
2866 static void setSharedDylibs(const char* rootPath
, bool usesOverlay
, const char* pathsFile
, const std::set
<ArchPair
>& onlyArchs
)
2868 std::vector
<const char*> rootsPaths
;
2869 parsePathsFile(pathsFile
, rootsPaths
);
2870 setSharedDylibs(rootPath
, usesOverlay
, onlyArchs
, rootsPaths
);
2874 // If the 10.5.0 version of update_dyld_shared_cache was killed or crashed, it
2875 // could leave large half written cache files laying around. The function deletes
2876 // those files. To prevent the deletion of tmp files being created by another
2877 // copy of update_dyld_shared_cache, it only deletes the temp cache file if its
2878 // creation time was before the last restart of this machine.
2879 static void deleteOrphanTempCacheFiles()
2881 DIR* dir
= ::opendir(MACOSX_DYLD_SHARED_CACHE_DIR
);
2882 if ( dir
!= NULL
) {
2883 std::vector
<const char*> filesToDelete
;
2884 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
2885 if ( entry
->d_type
== DT_REG
) {
2886 // only look at files with .tmp in name
2887 if ( strstr(entry
->d_name
, ".tmp") != NULL
) {
2888 char fullPath
[strlen(MACOSX_DYLD_SHARED_CACHE_DIR
)+entry
->d_namlen
+2];
2889 strcpy(fullPath
, MACOSX_DYLD_SHARED_CACHE_DIR
);
2890 strcat(fullPath
, "/");
2891 strcat(fullPath
, entry
->d_name
);
2892 struct stat tmpFileStatInfo
;
2893 if ( stat(fullPath
, &tmpFileStatInfo
) != -1 ) {
2894 int mib
[2] = {CTL_KERN
, KERN_BOOTTIME
};
2895 struct timeval boottime
;
2896 size_t size
= sizeof(boottime
);
2897 if ( (sysctl(mib
, 2, &boottime
, &size
, NULL
, 0) != -1) && (boottime
.tv_sec
!= 0) ) {
2898 // make sure this file is older than the boot time of this machine
2899 if ( tmpFileStatInfo
.st_mtime
< boottime
.tv_sec
) {
2900 filesToDelete
.push_back(strdup(fullPath
));
2908 for(std::vector
<const char*>::iterator it
= filesToDelete
.begin(); it
!= filesToDelete
.end(); ++it
) {
2909 fprintf(stderr
, "update_dyld_shared_cache: deleting old temp cache file: %s\n", *it
);
2917 static bool updateSharedeCacheFile(const char* rootPath
, bool usesOverlay
, const char* cacheDir
, const std::set
<ArchPair
>& onlyArchs
,
2918 bool force
, bool alphaSort
, bool optimize
, bool deleteExistingFirst
, bool verify
, bool keepSignatures
)
2920 bool didUpdate
= false;
2921 // get dyld load address info
2922 UniversalMachOLayout
* dyldLayout
= NULL
;
2923 char dyldPath
[1024];
2924 strlcpy(dyldPath
, rootPath
, 1024);
2925 strlcat(dyldPath
, "/usr/lib/dyld", 1024);
2926 struct stat stat_buf
;
2927 if ( stat(dyldPath
, &stat_buf
) == 0 ) {
2928 dyldLayout
= new UniversalMachOLayout(dyldPath
, &onlyArchs
);
2931 dyldLayout
= new UniversalMachOLayout("/usr/lib/dyld", &onlyArchs
);
2933 const int archCount
= onlyArchs
.size();
2935 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
, ++index
) {
2936 const MachOLayoutAbstraction
* dyldLayoutForArch
= dyldLayout
->getSlice(*a
);
2937 uint64_t dyldBaseAddress
= 0;
2938 if ( dyldLayoutForArch
!= NULL
)
2939 dyldBaseAddress
= dyldLayoutForArch
->getBaseAddress();
2941 fprintf(stderr
, "update_dyld_shared_cache: warning, dyld not available for specified architectures\n");
2942 switch ( a
->arch
) {
2943 case CPU_TYPE_POWERPC
:
2945 #if __i386__ || __x86_64__
2946 // <rdar://problem/5217377> Rosetta does not work with optimized dyld shared cache
2947 SharedCache
<ppc
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, cacheDir
, alphaSort
, verify
, false, usesOverlay
, dyldBaseAddress
);
2948 didUpdate
|= cache
.update(usesOverlay
, force
, false, deleteExistingFirst
, index
, archCount
, keepSignatures
);
2950 SharedCache
<ppc
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, cacheDir
, alphaSort
, verify
, optimize
, usesOverlay
, dyldBaseAddress
);
2951 didUpdate
|= cache
.update(usesOverlay
, force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
);
2957 SharedCache
<x86
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, cacheDir
, alphaSort
, verify
, optimize
, usesOverlay
, dyldBaseAddress
);
2958 didUpdate
|= cache
.update(usesOverlay
, force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
);
2961 case CPU_TYPE_X86_64
:
2963 SharedCache
<x86_64
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, cacheDir
, alphaSort
, verify
, optimize
, usesOverlay
, dyldBaseAddress
);
2964 didUpdate
|= cache
.update(usesOverlay
, force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
);
2969 SharedCache
<arm
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, cacheDir
, alphaSort
, verify
, optimize
, usesOverlay
, dyldBaseAddress
);
2970 didUpdate
|= cache
.update(usesOverlay
, force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
);
2977 deleteOrphanTempCacheFiles();
2985 fprintf(stderr
, "update_dyld_shared_cache [-force] [-root dir] [-overlay dir] [-arch arch] [-debug]\n");
2989 int main(int argc
, const char* argv
[])
2991 std::set
<ArchPair
> onlyArchs
;
2992 const char* rootPath
= "";
2993 const char* dylibListFile
= NULL
;
2995 bool alphaSort
= false;
2996 bool optimize
= true;
2997 bool hasRoot
= false;
2998 bool hasOverlay
= false;
2999 bool verify
= false;
3000 bool keepSignatures
= false;
3001 const char* cacheDir
= NULL
;
3004 // parse command line options
3005 for(int i
=1; i
< argc
; ++i
) {
3006 const char* arg
= argv
[i
];
3007 if ( arg
[0] == '-' ) {
3008 if ( strcmp(arg
, "-debug") == 0 ) {
3011 else if ( strcmp(arg
, "-force") == 0 ) {
3014 else if ( strcmp(arg
, "-verify") == 0 ) {
3017 else if ( strcmp(arg
, "-sort_by_name") == 0 ) {
3020 else if ( strcmp(arg
, "-progress") == 0 ) {
3023 else if ( strcmp(arg
, "-opt") == 0 ) {
3026 else if ( strcmp(arg
, "-no_opt") == 0 ) {
3029 else if ( strcmp(arg
, "-iPhone") == 0 ) {
3032 else if ( strcmp(arg
, "-dylib_list") == 0 ) {
3033 dylibListFile
= argv
[++i
];
3034 if ( dylibListFile
== NULL
)
3035 throw "-dylib_list missing path argument";
3037 else if ( (strcmp(arg
, "-root") == 0) || (strcmp(arg
, "--root") == 0) ) {
3039 throw "cannot use both -root and -overlay";
3040 rootPath
= argv
[++i
];
3041 if ( rootPath
== NULL
)
3042 throw "-root missing path argument";
3045 else if ( strcmp(arg
, "-overlay") == 0 ) {
3047 throw "cannot use both -root and -overlay";
3048 rootPath
= argv
[++i
];
3049 if ( rootPath
== NULL
)
3050 throw "-root missing path argument";
3053 else if ( strcmp(arg
, "-cache_dir") == 0 ) {
3054 cacheDir
= argv
[++i
];
3055 if ( cacheDir
== NULL
)
3056 throw "-cache_dir missing path argument";
3058 else if ( strcmp(arg
, "-arch") == 0 ) {
3059 const char* arch
= argv
[++i
];
3060 if ( strcmp(arch
, "ppc") == 0 )
3061 onlyArchs
.insert(ArchPair(CPU_TYPE_POWERPC
, CPU_SUBTYPE_POWERPC_ALL
));
3062 else if ( strcmp(arch
, "i386") == 0 )
3063 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3064 else if ( strcmp(arch
, "x86_64") == 0 )
3065 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
3066 else if ( strcmp(arch
, "armv4t") == 0 )
3067 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V4T
));
3068 else if ( strcmp(arch
, "armv5") == 0 )
3069 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V5TEJ
));
3070 else if ( strcmp(arch
, "armv6") == 0 )
3071 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V6
));
3072 else if ( strcmp(arch
, "armv7") == 0 )
3073 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7
));
3075 throwf("unknown architecture %s", arch
);
3077 else if ( strcmp(arg
, "-universal_boot") == 0 ) {
3079 throwf("universal_boot option can only be used on Intel machines");
3081 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
3082 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3086 throwf("unknown option: %s\n", arg
);
3091 throwf("unknown option: %s\n", arg
);
3095 // strip tailing slashes on -root or -overlay
3096 // make it a real path so as to not make all dylibs look like symlink aliases
3097 if ( rootPath
[0] != '\0' ) {
3098 char realRootPath
[MAXPATHLEN
];
3099 if ( realpath(rootPath
, realRootPath
) == NULL
)
3100 throwf("realpath() failed on %s\n", rootPath
);
3101 rootPath
= strdup(realRootPath
);
3104 // set location to write cache dir
3105 if ( cacheDir
== NULL
) {
3106 if ( (rootPath
[0] == '\0') || hasOverlay
) {
3107 cacheDir
= (iPhoneOS
? IPHONE_DYLD_SHARED_CACHE_DIR
: MACOSX_DYLD_SHARED_CACHE_DIR
);
3110 asprintf((char**)&cacheDir
, "%s/%s", rootPath
, (iPhoneOS
? IPHONE_DYLD_SHARED_CACHE_DIR
: MACOSX_DYLD_SHARED_CACHE_DIR
));
3114 // if no restrictions specified, use architectures that work on this machine
3115 if ( onlyArchs
.size() == 0 ) {
3117 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V6
));
3118 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7
));
3122 size_t len
= sizeof(int);
3123 #if __i386__ || __x86_64__
3124 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3125 // check rosetta is installed
3126 char rosettaPath
[1024];
3127 strlcpy(rosettaPath
, rootPath
, 1024);
3128 strlcat(rosettaPath
, "/usr/libexec/oah/translate", 1024);
3129 struct stat stat_buf
;
3130 if ( stat(rosettaPath
, &stat_buf
) == 0 ) {
3131 onlyArchs
.insert(ArchPair(CPU_TYPE_POWERPC
, CPU_SUBTYPE_POWERPC_ALL
));
3133 else if ( hasOverlay
) {
3134 // in overlay mode, rosetta may be installed on base system, but is not in update root
3135 if ( stat("/usr/libexec/oah/translate", &stat_buf
) == 0 )
3136 onlyArchs
.insert(ArchPair(CPU_TYPE_POWERPC
, CPU_SUBTYPE_POWERPC_ALL
));
3138 // check system is capable of running 64-bit programs
3139 if ( (sysctlbyname("hw.optional.x86_64", &available
, &len
, NULL
, 0) == 0) && available
)
3140 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
3142 #error unsupported architecture
3147 if ( !verify
&& (geteuid() != 0) )
3148 throw "you must be root to run this tool";
3150 // build list of shared dylibs
3151 if ( dylibListFile
!= NULL
)
3152 setSharedDylibs(rootPath
, hasOverlay
, dylibListFile
, onlyArchs
);
3154 scanForSharedDylibs(rootPath
, hasOverlay
, "/var/db/dyld/shared_region_roots/", onlyArchs
);
3155 updateSharedeCacheFile(rootPath
, hasOverlay
, cacheDir
, onlyArchs
, force
, alphaSort
, optimize
,
3156 false, verify
, keepSignatures
);
3158 catch (const char* msg
) {
3159 fprintf(stderr
, "update_dyld_shared_cache failed: %s\n", msg
);