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>
42 #include <sys/param.h>
43 #include <sys/sysctl.h>
44 #include <sys/resource.h>
46 #include <servers/bootstrap.h>
47 #include <mach-o/loader.h>
48 #include <mach-o/fat.h>
49 #include <CoreFoundation/CoreFoundation.h>
50 #include <Security/Security.h>
51 #include <Security/SecCodeSigner.h>
52 #include <CommonCrypto/CommonDigest.h>
54 #include "dyld_cache_format.h"
59 #include <unordered_map>
61 #include "Architectures.hpp"
62 #include "MachOLayout.hpp"
63 #include "MachORebaser.hpp"
64 #include "MachOBinder.hpp"
65 #include "CacheFileAbstraction.hpp"
66 #include "dyld_cache_config.h"
69 #include "objc-shared-cache.h"
71 #define FIRST_DYLIB_TEXT_OFFSET 0x8000
73 #ifndef LC_FUNCTION_STARTS
74 #define LC_FUNCTION_STARTS 0x26
77 static bool verbose
= false;
78 static bool progress
= false;
79 static bool iPhoneOS
= false;
80 static std::vector
<const char*> warnings
;
83 static void warn(const char *arch
, const char *format
, ...)
88 va_start(args
, format
);
89 ::vasprintf(&msg
, format
, args
);
92 warnings
.push_back(msg
);
95 ::fprintf(::stderr
, "update_dyld_shared_cache: warning: %s%s%s%s\n",
96 arch
? "for arch " : "",
106 size_t operator()(const char* __s
) const {
109 __h
= 5 * __h
+ *__s
;
116 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
124 typedef std::unordered_map
<const char*, const char*, CStringHash
, CStringEquals
> StringToString
;
126 static void addArchPair(ArchPair ap
);
127 static void addRoot(const char* vpath
, const std::set
<ArchPair
>& archs
);
128 static void findSharedDylibs(ArchPair ap
);
129 static ArchGraph
* graphForArchPair(ArchPair ap
) { return fgPerArchGraph
[ap
]; }
130 static void setFileSystemRoot(const char* root
) { fgFileSystemRoot
= root
; }
131 static void setFileSystemOverlay(const char* overlay
) { fgFileSystemOverlay
= overlay
; }
132 static const char* archName(ArchPair ap
);
134 ArchPair
getArchPair() { return fArchPair
; }
135 std::set
<const class MachOLayoutAbstraction
*>& getSharedDylibs() { return fSharedDylibs
; }
136 StringToString
& getDylibAliases() { return fAliasesMap
; }
137 const char* archName() { return archName(fArchPair
); }
144 DependencyNode(ArchGraph
*, const char* path
, const MachOLayoutAbstraction
* layout
);
145 void loadDependencies(const MachOLayoutAbstraction
*);
146 void markNeededByRoot(DependencyNode
*);
147 const char* getPath() const { return fPath
; }
148 const MachOLayoutAbstraction
* getLayout() const { return fLayout
; }
149 size_t useCount() const { return fRootsDependentOnThis
.size(); }
150 bool allDependentsFound() const { return !fDependentMissing
; }
154 const MachOLayoutAbstraction
* fLayout
;
155 bool fDependenciesLoaded
;
156 bool fDependentMissing
;
157 std::set
<DependencyNode
*> fDependsOn
;
158 std::set
<DependencyNode
*> fRootsDependentOnThis
;
161 typedef std::unordered_map
<const char*, class DependencyNode
*, CStringHash
, CStringEquals
> PathToNode
;
164 ArchGraph(ArchPair ap
) : fArchPair(ap
) {}
165 void addRoot(const char* path
, const MachOLayoutAbstraction
*);
166 DependencyNode
* getNode(const char* path
);
167 DependencyNode
* getNodeForVirtualPath(const char* vpath
);
168 static bool canBeShared(const MachOLayoutAbstraction
* layout
, ArchPair ap
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
);
169 static bool sharable(const MachOLayoutAbstraction
* layout
, ArchPair ap
, char** msg
);
171 static std::map
<ArchPair
, ArchGraph
*> fgPerArchGraph
;
172 static const char* fgFileSystemRoot
;
173 static const char* fgFileSystemOverlay
;
176 std::set
<DependencyNode
*> fRoots
;
178 std::set
<const MachOLayoutAbstraction
*> fSharedDylibs
; // use set to avoid duplicates when installname!=realpath
179 StringToString fAliasesMap
;
181 std::map
<ArchPair
, ArchGraph
*> ArchGraph::fgPerArchGraph
;
182 const char* ArchGraph::fgFileSystemRoot
= "";
183 const char* ArchGraph::fgFileSystemOverlay
= "";
185 void ArchGraph::addArchPair(ArchPair ap
)
187 //fprintf(stderr, "adding ArchPair 0x%08X,0x%08X\n", ap.arch, ap.subtype);
188 fgPerArchGraph
[ap
] = new ArchGraph(ap
);
191 void ArchGraph::addRoot(const char* vpath
, const std::set
<ArchPair
>& onlyArchs
)
193 //fprintf(stderr, "addRoot(%s)\n", vpath);
194 char completePath
[MAXPATHLEN
];
195 const char* path
= NULL
;
196 // check -overlay path first
197 if ( fgFileSystemOverlay
[0] != '\0' ) {
198 strcpy(completePath
, fgFileSystemOverlay
);
199 strcat(completePath
, vpath
); // assumes vpath starts with '/'
200 struct stat stat_buf
;
201 if ( stat(completePath
, &stat_buf
) == 0 )
204 // if not found in overlay, check for -root
205 if ( (path
== NULL
) && (fgFileSystemRoot
[0] != '\0') ) {
206 strcpy(completePath
, fgFileSystemRoot
);
207 strcat(completePath
, vpath
); // assumes vpath starts with '/'
208 struct stat stat_buf
;
209 if ( stat(completePath
, &stat_buf
) == 0 )
216 //fprintf(stderr, " UniversalMachOLayout::find(%s)\n", path);
217 const UniversalMachOLayout
& uni
= UniversalMachOLayout::find(path
, &onlyArchs
);
218 for(std::set
<ArchPair
>::iterator ait
= onlyArchs
.begin(); ait
!= onlyArchs
.end(); ++ait
) {
220 const MachOLayoutAbstraction
* layout
= uni
.getSlice(*ait
);
221 if ( layout
!= NULL
)
222 fgPerArchGraph
[*ait
]->addRoot(path
, layout
);
224 catch (const char* msg
) {
226 fprintf(stderr
, "update_dyld_shared_cache: warning for %s can't use root '%s': %s\n", fgPerArchGraph
[*ait
]->archName(), path
, msg
);
231 catch (const char* msg
) {
232 fprintf(stderr
, "update_dyld_shared_cache: warning can't use root '%s': %s\n", path
, msg
);
238 void ArchGraph::addRoot(const char* path
, const MachOLayoutAbstraction
* layout
)
241 fprintf(stderr
, "update_dyld_shared_cache: adding root: %s\n", path
);
242 DependencyNode
* node
= this->getNode(path
);
244 const MachOLayoutAbstraction
* mainExecutableLayout
= NULL
;
245 if ( layout
->getFileType() == MH_EXECUTE
)
246 mainExecutableLayout
= layout
;
247 node
->loadDependencies(mainExecutableLayout
);
248 node
->markNeededByRoot(node
);
249 if ( layout
->getFileType() == MH_DYLIB
)
250 node
->markNeededByRoot(NULL
);
253 // a virtual path does not have the fgFileSystemRoot prefix
254 ArchGraph::DependencyNode
* ArchGraph::getNodeForVirtualPath(const char* vpath
)
256 //fprintf(stderr, "getNodeForVirtualPath(%s)\n", vpath);
257 char completePath
[MAXPATHLEN
];
258 if ( fgFileSystemOverlay
[0] != '\0' ) {
259 // using -overlay means if /overlay/path/dylib exists use it, otherwise use /path/dylib
260 strcpy(completePath
, fgFileSystemOverlay
);
261 strcat(completePath
, vpath
); // assumes vpath starts with '/'
262 struct stat stat_buf
;
263 if ( stat(completePath
, &stat_buf
) == 0 )
264 return this->getNode(completePath
);
266 // <rdar://problem/9279770> support when install name is a symlink
267 const char* pathToSymlink
= vpath
;
268 if ( fgFileSystemRoot
[0] != '\0' ) {
269 strcpy(completePath
, fgFileSystemRoot
);
270 strcat(completePath
, vpath
);
271 pathToSymlink
= completePath
;
273 if ( (lstat(pathToSymlink
, &stat_buf
) == 0) && S_ISLNK(stat_buf
.st_mode
) ) {
274 // requested path did not exist in /overlay, but leaf of path is a symlink in /
275 char pathInSymLink
[MAXPATHLEN
];
276 size_t res
= readlink(pathToSymlink
, pathInSymLink
, sizeof(pathInSymLink
));
278 pathInSymLink
[res
] = '\0';
279 if ( pathInSymLink
[0] != '/' ) {
280 char symFullPath
[MAXPATHLEN
];
281 strcpy(symFullPath
, vpath
);
282 char* lastSlash
= strrchr(symFullPath
, '/');
283 if ( lastSlash
!= NULL
) {
284 strcpy(lastSlash
+1, pathInSymLink
);
285 // (re)try looking for what symlink points to, but in /overlay
286 return this->getNodeForVirtualPath(symFullPath
);
293 if ( fgFileSystemRoot
[0] != '\0' ) {
294 // using -root means always use /rootpath/usr/lib
295 strcpy(completePath
, fgFileSystemRoot
);
296 strcat(completePath
, vpath
); // assumes vpath starts with '/'
297 return this->getNode(completePath
);
299 // not found in -overlay or -root not used
300 return this->getNode(vpath
);
303 ArchGraph::DependencyNode
* ArchGraph::getNode(const char* path
)
305 //fprintf(stderr, "getNode(%s)\n", path);
306 // look up supplied path to see if node already exists
307 PathToNode::iterator pos
= fNodes
.find(path
);
308 if ( pos
!= fNodes
.end() )
312 char realPath
[MAXPATHLEN
];
313 if ( realpath(path
, realPath
) == NULL
)
314 throwf("realpath() failed on %s\n", path
);
316 // look up real path to see if node already exists
317 pos
= fNodes
.find(realPath
);
318 if ( pos
!= fNodes
.end() ) {
319 // update fAliasesMap with symlinks found
320 const char* aliasPath
= path
;
321 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(path
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
322 aliasPath
= &path
[strlen(fgFileSystemRoot
)];
324 if ( fAliasesMap
.find(aliasPath
) == fAliasesMap
.end() ) {
325 if ( strcmp(aliasPath
, pos
->second
->getLayout()->getID().name
) != 0 ) {
326 fAliasesMap
[strdup(aliasPath
)] = pos
->second
->getLayout()->getID().name
;
327 //fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
333 // still does not exist, so create a new node
334 const UniversalMachOLayout
& uni
= UniversalMachOLayout::find(realPath
);
335 DependencyNode
* node
= new DependencyNode(this, realPath
, uni
.getSlice(fArchPair
));
336 if ( node
->getLayout() == NULL
) {
337 throwf("%s is missing arch %s", realPath
, archName(fArchPair
));
339 // add realpath to node map
340 fNodes
[node
->getPath()] = node
;
341 // if install name is not real path, add install name to node map
342 if ( (node
->getLayout()->getFileType() == MH_DYLIB
) && (strcmp(realPath
, node
->getLayout()->getID().name
) != 0) ) {
343 //fprintf(stderr, "adding %s node alias %s for %s\n", archName(fArchPair), node->getLayout()->getID().name, realPath);
344 pos
= fNodes
.find(node
->getLayout()->getID().name
);
345 if ( pos
!= fNodes
.end() ) {
346 // get uuids of two dylibs to see if this is accidental copy of a dylib or two differnent dylibs with same -install_name
349 node
->getLayout()->uuid(uuid1
);
350 pos
->second
->getLayout()->uuid(uuid2
);
351 if ( memcmp(&uuid1
, &uuid2
, 16) == 0 ) {
352 // <rdar://problem/8305479> warn if two dylib in cache have same install_name
354 asprintf(&msg
, "update_dyld_shared_cache: warning, found two copies of the same dylib with same install path: %s\n\t%s\n\t%s\n",
355 node
->getLayout()->getID().name
, pos
->second
->getPath(), node
->getPath());
356 fprintf(stderr
, "%s", msg
);
357 warnings
.push_back(msg
);
360 // <rdar://problem/12763450> update_dyld_shared_cache should fail if two images have same install name
361 fprintf(stderr
, "update_dyld_shared_cache: found two different dylibs with same install path: %s\n\t%s\n\t%s\n",
362 node
->getLayout()->getID().name
, pos
->second
->getPath(), node
->getPath());
367 fNodes
[node
->getLayout()->getID().name
] = node
;
368 // update fAliasesMap with symlinks found
369 const char* aliasPath
= realPath
;
370 if ( (fgFileSystemRoot
!= NULL
) && (fgFileSystemRoot
[0] != '\0') && (strncmp(realPath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
371 aliasPath
= &realPath
[strlen(fgFileSystemRoot
)];
373 // <rdar://problem/11192810> Too many aliases in -overlay mode
374 if ( (fgFileSystemOverlay
!= NULL
) && (fgFileSystemOverlay
[0] != '\0') && (strncmp(realPath
, fgFileSystemOverlay
, strlen(fgFileSystemOverlay
)) == 0) ) {
375 aliasPath
= &realPath
[strlen(fgFileSystemOverlay
)];
377 if ( fAliasesMap
.find(aliasPath
) == fAliasesMap
.end() ) {
378 if ( strcmp(aliasPath
, node
->getLayout()->getID().name
) != 0 ) {
379 fAliasesMap
[strdup(aliasPath
)] = node
->getLayout()->getID().name
;
380 //fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
388 void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction
* mainExecutableLayout
)
390 if ( !fDependenciesLoaded
) {
391 fDependenciesLoaded
= true;
393 const std::vector
<MachOLayoutAbstraction::Library
>& dependsOn
= fLayout
->getLibraries();
394 for(std::vector
<MachOLayoutAbstraction::Library
>::const_iterator it
= dependsOn
.begin(); it
!= dependsOn
.end(); ++it
) {
396 const char* dependentPath
= it
->name
;
397 if ( strncmp(dependentPath
, "@executable_path/", 17) == 0 ) {
398 if ( mainExecutableLayout
== NULL
)
399 throw "@executable_path without main executable";
400 // expand @executable_path path prefix
401 const char* executablePath
= mainExecutableLayout
->getFilePath();
402 char newPath
[strlen(executablePath
) + strlen(dependentPath
)+2];
403 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(executablePath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
404 // executablePath already has rootPath prefix, need to remove that to get to base virtual path
405 strcpy(newPath
, &executablePath
[strlen(fgFileSystemRoot
)]);
408 strcpy(newPath
, executablePath
);
410 char* addPoint
= strrchr(newPath
,'/');
411 if ( addPoint
!= NULL
)
412 strcpy(&addPoint
[1], &dependentPath
[17]);
414 strcpy(newPath
, &dependentPath
[17]);
415 dependentPath
= strdup(newPath
);
417 else if ( strncmp(dependentPath
, "@loader_path/", 13) == 0 ) {
418 // expand @loader_path path prefix
419 char newPath
[strlen(fPath
) + strlen(dependentPath
)+2];
420 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(fPath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
421 // fPath already has rootPath prefix, need to remove that to get to base virtual path
422 strcpy(newPath
, &fPath
[strlen(fgFileSystemRoot
)]);
425 strcpy(newPath
, fPath
);
427 char* addPoint
= strrchr(newPath
,'/');
428 if ( addPoint
!= NULL
)
429 strcpy(&addPoint
[1], &dependentPath
[13]);
431 strcpy(newPath
, &dependentPath
[13]);
432 dependentPath
= strdup(newPath
);
434 else if ( strncmp(dependentPath
, "@rpath/", 7) == 0 ) {
435 throw "@rpath not supported in dyld shared cache";
437 // <rdar://problem/9161945> silently ignore dependents from main executables that can't be in shared cache
438 bool addDependent
= true;
439 if ( fLayout
->getFileType() == MH_EXECUTE
) {
440 if ( (strncmp(dependentPath
, "/usr/lib/", 9) != 0) && (strncmp(dependentPath
, "/System/Library/", 16) != 0) ) {
441 addDependent
= false;
445 fDependsOn
.insert(fGraph
->getNodeForVirtualPath(dependentPath
));
447 catch (const char* msg
) {
448 if ( it
->weakImport
|| ! fLayout
->hasSplitSegInfo() ) {
449 // ok to ignore missing weak imported dylibs from things that are
450 // not going to be in the dyld shared cache
453 fprintf(stderr
, "warning, could not bind %s because %s\n", fPath
, msg
);
454 fDependentMissing
= true;
459 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
460 (*it
)->loadDependencies(mainExecutableLayout
);
465 void ArchGraph::DependencyNode::markNeededByRoot(ArchGraph::DependencyNode
* rootNode
)
467 if ( fRootsDependentOnThis
.count(rootNode
) == 0 ) {
468 fRootsDependentOnThis
.insert(rootNode
);
469 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
470 (*it
)->markNeededByRoot(rootNode
);
476 ArchGraph::DependencyNode::DependencyNode(ArchGraph
* graph
, const char* path
, const MachOLayoutAbstraction
* layout
)
477 : fGraph(graph
), fPath(strdup(path
)), fLayout(layout
), fDependenciesLoaded(false), fDependentMissing(false)
479 //fprintf(stderr, "new DependencyNode(0x%08X, %s)\n", graph->fArch, path);
482 void ArchGraph::findSharedDylibs(ArchPair ap
)
484 const PathToNode
& nodes
= fgPerArchGraph
[ap
]->fNodes
;
485 std::set
<const MachOLayoutAbstraction
*> possibleLibs
;
486 //fprintf(stderr, "shared for arch %s\n", archName(ap));
487 for(PathToNode::const_iterator it
= nodes
.begin(); it
!= nodes
.end(); ++it
) {
488 DependencyNode
* node
= it
->second
;
489 // <rdar://problem/6127437> put all dylibs in shared cache - not just ones used by more than one app
490 if ( node
->allDependentsFound() /*&& (node->useCount() > 1)*/ ) {
491 const MachOLayoutAbstraction
* layout
= node
->getLayout();
492 if ( layout
->isDylib() ) {
494 if ( sharable(layout
, ap
, &msg
) ) {
495 possibleLibs
.insert(layout
);
498 if ( layout
->getID().name
[0] == '@' ) {
499 // <rdar://problem/7770139> update_dyld_shared_cache should suppress warnings for embedded frameworks
502 warnings
.push_back(msg
);
503 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
510 // prune so that all shareable libs depend only on other shareable libs
511 std::set
<const MachOLayoutAbstraction
*>& sharedLibs
= fgPerArchGraph
[ap
]->fSharedDylibs
;
512 std::map
<const MachOLayoutAbstraction
*,bool> shareableMap
;
513 for (std::set
<const MachOLayoutAbstraction
*>::iterator lit
= possibleLibs
.begin(); lit
!= possibleLibs
.end(); ++lit
) {
514 if ( canBeShared(*lit
, ap
, possibleLibs
, shareableMap
) )
515 sharedLibs
.insert(*lit
);
519 const char* ArchGraph::archName(ArchPair ap
)
524 case CPU_TYPE_X86_64
:
527 switch ( ap
.subtype
) {
528 case CPU_SUBTYPE_ARM_V4T
:
530 case CPU_SUBTYPE_ARM_V6
:
532 case CPU_SUBTYPE_ARM_V5TEJ
:
534 case CPU_SUBTYPE_ARM_XSCALE
:
536 case CPU_SUBTYPE_ARM_V7
:
538 case CPU_SUBTYPE_ARM_V7F
:
540 case CPU_SUBTYPE_ARM_V7K
:
542 case CPU_SUBTYPE_ARM_V7S
:
552 bool ArchGraph::sharable(const MachOLayoutAbstraction
* layout
, ArchPair ap
, char** msg
)
554 if ( ! layout
->isTwoLevelNamespace() )
555 asprintf(msg
, "can't put %s in shared cache because it was built -flat_namespace", layout
->getID().name
);
556 else if ( ! layout
->hasSplitSegInfo() )
557 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"));
558 else if ( ! layout
->isRootOwned() )
559 asprintf(msg
, "can't put %s in shared cache because it is not owned by root", layout
->getID().name
);
560 else if ( ! layout
->inSharableLocation() )
561 asprintf(msg
, "can't put %s in shared cache because it is not in /usr/lib or /System/Library", layout
->getID().name
);
562 else if ( layout
->hasDynamicLookupLinkage() )
563 asprintf(msg
, "can't put %s in shared cache because it was built with '-undefined dynamic_lookup'", layout
->getID().name
);
564 else if ( layout
->hasMainExecutableLookupLinkage() )
565 asprintf(msg
, "can't put %s in shared cache because it was built with '-bundle_loader'", layout
->getID().name
);
566 //else if ( ! layout->hasDyldInfo() )
567 // asprintf(msg, "can't put %s in shared cache because it was built for older OS", layout->getID().name);
573 bool ArchGraph::canBeShared(const MachOLayoutAbstraction
* layout
, ArchPair ap
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
)
575 // check map which is a cache of results
576 std::map
<const MachOLayoutAbstraction
*, bool>::iterator mapPos
= shareableMap
.find(layout
);
577 if ( mapPos
!= shareableMap
.end() ) {
578 return mapPos
->second
;
581 if ( possibleLibs
.count(layout
) == 0 ) {
582 shareableMap
[layout
] = false;
584 if ( sharable(layout
, ap
, &msg
) )
585 asprintf(&msg
, "can't put %s in shared cache, unknown reason", layout
->getID().name
);
586 warnings
.push_back(msg
);
588 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
592 shareableMap
[layout
] = true; // mark this shareable early in case of circular references
593 const PathToNode
& nodes
= fgPerArchGraph
[ap
]->fNodes
;
594 const std::vector
<MachOLayoutAbstraction::Library
>& dependents
= layout
->getLibraries();
595 for (std::vector
<MachOLayoutAbstraction::Library
>::const_iterator dit
= dependents
.begin(); dit
!= dependents
.end(); ++dit
) {
596 PathToNode::const_iterator pos
= nodes
.find(dit
->name
);
597 if ( pos
== nodes
.end() ) {
598 // path from load command does not match any loaded dylibs, maybe there is a temp symlink
599 char realPath
[MAXPATHLEN
];
600 if ( realpath(dit
->name
, realPath
) != NULL
) {
601 if ( nodes
.find(realPath
) != nodes
.end() )
604 // handle weak imported dylibs not found
605 if ( dit
->weakImport
)
607 shareableMap
[layout
] = false;
609 asprintf(&msg
, "can't put %s in shared cache because it depends on %s which can't be found", layout
->getID().name
, dit
->name
);
610 warnings
.push_back(msg
);
612 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
616 if ( ! canBeShared(pos
->second
->getLayout(), ap
, possibleLibs
, shareableMap
) ) {
617 shareableMap
[layout
] = false;
619 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
);
620 warnings
.push_back(msg
);
622 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
636 const char* getBuffer();
638 uint32_t add(const char* str
);
639 uint32_t addUnique(const char* str
);
640 const char* stringAtIndex(uint32_t) const;
642 typedef std::unordered_map
<const char*, uint32_t, CStringHash
, CStringEquals
> StringToOffset
;
645 uint32_t fBufferAllocated
;
646 uint32_t fBufferUsed
;
647 StringToOffset fUniqueStrings
;
651 StringPool::StringPool()
652 : fBufferUsed(0), fBufferAllocated(48*1024*1024)
654 fBuffer
= (char*)malloc(fBufferAllocated
);
657 uint32_t StringPool::add(const char* str
)
659 uint32_t len
= strlen(str
);
660 if ( (fBufferUsed
+ len
+ 1) > fBufferAllocated
) {
662 throw "string buffer exhausted";
664 strcpy(&fBuffer
[fBufferUsed
], str
);
665 uint32_t result
= fBufferUsed
;
666 fUniqueStrings
[&fBuffer
[fBufferUsed
]] = result
;
667 fBufferUsed
+= len
+1;
671 uint32_t StringPool::addUnique(const char* str
)
673 StringToOffset::iterator pos
= fUniqueStrings
.find(str
);
674 if ( pos
!= fUniqueStrings
.end() )
677 //fprintf(stderr, "StringPool::addUnique() new string: %s\n", str);
678 return this->add(str
);
682 uint32_t StringPool::size()
687 const char* StringPool::getBuffer()
692 const char* StringPool::stringAtIndex(uint32_t index
) const
694 return &fBuffer
[index
];
699 struct LocalSymbolInfo
701 uint32_t dylibOffset
;
702 uint32_t nlistStartIndex
;
707 template <typename A
>
711 SharedCache(ArchGraph
* graph
, const char* rootPath
, const char* overlayPath
, const char* cacheDir
, bool explicitCacheDir
,
712 bool alphaSort
, bool verify
, bool optimize
, uint64_t dyldBaseAddress
);
713 bool update(bool force
, bool optimize
, bool deleteExistingFirst
, int archIndex
,
714 int archCount
, bool keepSignatures
, bool dontMapLocalSymbols
);
715 static const char* cacheFileSuffix(bool optimized
, const char* archName
);
717 // vm address = address AS WRITTEN into the cache
718 // mapped address = address AS MAPPED into the update process only
719 // file offset = offset relative to start of cache file
720 void * mappedAddressForVMAddress(uint64_t vmaddr
);
721 uint64_t VMAddressForMappedAddress(const void *mapaddr
);
722 uint64_t cacheFileOffsetForVMAddress(uint64_t addr
) const;
723 uint64_t VMAddressForCacheFileOffset(uint64_t addr
) const;
725 static const char* archName();
728 typedef typename
A::P P
;
729 typedef typename
A::P::E E
;
730 typedef typename
A::P::uint_t pint_t
;
732 bool notUpToDate(const char* path
, unsigned int aliasCount
);
733 bool notUpToDate(const void* cache
, unsigned int aliasCount
);
734 uint8_t* optimizeLINKEDIT(bool keepSignatures
, bool dontMapLocalSymbols
);
735 void optimizeObjC(std::vector
<void*>& pointersInData
);
737 static void getSharedCacheBasAddresses(cpu_type_t arch
, uint64_t* baseReadOnly
, uint64_t* baseWritable
);
738 static cpu_type_t
arch();
739 static uint64_t sharedRegionStartAddress();
740 static uint64_t sharedRegionSize();
741 static uint64_t sharedRegionStartWritableAddress(uint64_t);
742 static uint64_t sharedRegionStartReadOnlyAddress(uint64_t, uint64_t);
743 static uint64_t getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
);
744 static bool addCacheSlideInfo();
746 static uint64_t pageAlign(uint64_t addr
);
747 void assignNewBaseAddresses(bool verify
);
750 const MachOLayoutAbstraction
* layout
;
751 std::vector
<const char*> aliases
;
752 dyld_cache_image_info info
;
755 struct ByNameSorter
{
756 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
)
757 { return (strcmp(left
.layout
->getID().name
, right
.layout
->getID().name
) < 0); }
760 struct ByAddressSorter
{
761 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
762 return (left
.layout
->getSegments()[0].newAddress() < right
.layout
->getSegments()[0].newAddress());
766 struct ByCStringSectionSizeSorter
{
767 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
768 const std::vector
<MachOLayoutAbstraction::Segment
>& segs_l
=
769 left
.layout
->getSegments();
770 const std::vector
<MachOLayoutAbstraction::Segment
>& segs_r
=
771 right
.layout
->getSegments();
772 if (segs_l
.size() == 0 || segs_r
.size() == 0) {
773 // one image has no segments
774 return segs_l
.size() > segs_r
.size();
776 const macho_header
<P
> *mh_l
= (macho_header
<P
>*)segs_l
[0].mappedAddress();
777 const macho_header
<P
> *mh_r
= (macho_header
<P
>*)segs_r
[0].mappedAddress();
778 const macho_section
<P
> *cstring_l
= mh_l
->getSection("__TEXT", "__cstring");
779 const macho_section
<P
> *cstring_r
= mh_r
->getSection("__TEXT", "__cstring");
780 if (!cstring_l
|| !cstring_r
) {
781 // one image has no cstrings
782 return cstring_l
&& !cstring_r
;
785 return cstring_l
->size() > cstring_r
->size();
790 Sorter(std::map
<const MachOLayoutAbstraction
*, uint32_t>& map
): fMap(map
) {}
791 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
792 return (fMap
[left
.layout
] < fMap
[right
.layout
]);
795 std::map
<const MachOLayoutAbstraction
*, uint32_t>& fMap
;
799 ArchGraph
* fArchGraph
;
801 bool fExistingIsNotUpToDate
;
802 bool fCacheFileInFinalLocation
;
803 const char* fCacheFilePath
;
804 uint8_t* fExistingCacheForVerification
;
805 std::vector
<LayoutInfo
> fDylibs
;
806 std::vector
<LayoutInfo
> fDylibAliases
;
807 std::vector
<shared_file_mapping_np
> fMappings
;
808 std::vector
<macho_nlist
<P
> > fUnmappedLocalSymbols
;
809 StringPool fUnmappedLocalsStringPool
;
810 std::vector
<LocalSymbolInfo
> fLocalSymbolInfos
;
811 uint32_t fHeaderSize
;
812 uint8_t* fInMemoryCache
;
813 uint64_t fDyldBaseAddress
;
814 uint64_t fLinkEditsTotalUnoptimizedSize
;
815 uint64_t fLinkEditsStartAddress
;
816 MachOLayoutAbstraction::Segment
* fFirstLinkEditSegment
;
817 uint32_t fOffsetOfBindInfoInCombinedLinkedit
;
818 uint32_t fOffsetOfWeakBindInfoInCombinedLinkedit
;
819 uint32_t fOffsetOfLazyBindInfoInCombinedLinkedit
;
820 uint32_t fOffsetOfExportInfoInCombinedLinkedit
;
821 uint32_t fOffsetOfOldSymbolTableInfoInCombinedLinkedit
;
822 uint32_t fSizeOfOldSymbolTableInfoInCombinedLinkedit
;
823 uint32_t fOffsetOfOldExternalRelocationsInCombinedLinkedit
;
824 uint32_t fSizeOfOldExternalRelocationsInCombinedLinkedit
;
825 uint32_t fOffsetOfOldIndirectSymbolsInCombinedLinkedit
;
826 uint32_t fSizeOfOldIndirectSymbolsInCombinedLinkedit
;
827 uint32_t fOffsetOfOldStringPoolInCombinedLinkedit
;
828 uint32_t fSizeOfOldStringPoolInCombinedLinkedit
;
829 uint32_t fOffsetOfFunctionStartsInCombinedLinkedit
;
830 uint32_t fSizeOfFunctionStartsInCombinedLinkedit
;
831 uint32_t fOffsetOfDataInCodeInCombinedLinkedit
;
832 uint32_t fSizeOfDataInCodeInCombinedLinkedit
;
833 uint32_t fLinkEditsTotalOptimizedSize
;
834 uint32_t fUnmappedLocalSymbolsSize
;
838 // Access a section containing a list of pointers
839 template <typename A
, typename T
>
842 typedef typename
A::P P
;
843 typedef typename
A::P::uint_t pint_t
;
845 SharedCache
<A
>* const fCache
;
846 const macho_section
<P
>* const fSection
;
847 pint_t
* const fBase
;
851 PointerSection(SharedCache
<A
>* cache
, const macho_header
<P
>* header
,
852 const char *segname
, const char *sectname
)
854 , fSection(header
->getSection(segname
, sectname
))
855 , fBase(fSection
? (pint_t
*)cache
->mappedAddressForVMAddress(fSection
->addr()) : 0)
856 , fCount(fSection
? fSection
->size() / sizeof(pint_t
) : 0)
860 uint64_t count() const { return fCount
; }
862 uint64_t getUnmapped(uint64_t index
) const {
863 if (index
>= fCount
) throwf("index out of range");
864 return P::getP(fBase
[index
]);
867 T
get(uint64_t index
) const {
868 return (T
)fCache
->mappedAddressForVMAddress(getUnmapped(index
));
871 void set(uint64_t index
, uint64_t value
) {
872 if (index
>= fCount
) throwf("index out of range");
873 P::setP(fBase
[index
], value
);
878 for (uint64_t i
= 0; i
< fCount
; i
++) {
879 pint_t value
= fBase
[i
];
881 fBase
[i
-shift
] = value
;
887 const_cast<macho_section
<P
>*>(fSection
)->set_size(fCount
* sizeof(pint_t
));
891 // Access a section containing an array of structures
892 template <typename A
, typename T
>
895 typedef typename
A::P P
;
897 SharedCache
<A
>* const fCache
;
898 const macho_section
<P
>* const fSection
;
900 uint64_t const fCount
;
903 ArraySection(SharedCache
<A
>* cache
, const macho_header
<P
>* header
,
904 const char *segname
, const char *sectname
)
906 , fSection(header
->getSection(segname
, sectname
))
907 , fBase(fSection
? (T
*)cache
->mappedAddressForVMAddress(fSection
->addr()) : 0)
908 , fCount(fSection
? fSection
->size() / sizeof(T
) : 0)
912 uint64_t count() const { return fCount
; }
914 T
& get(uint64_t index
) const {
915 if (index
>= fCount
) throwf("index out of range");
922 #include "ObjCLegacyAbstraction.hpp"
923 #include "ObjCModernAbstraction.hpp"
927 template <> cpu_type_t SharedCache
<x86
>::arch() { return CPU_TYPE_I386
; }
928 template <> cpu_type_t SharedCache
<x86_64
>::arch() { return CPU_TYPE_X86_64
; }
929 template <> cpu_type_t SharedCache
<arm
>::arch() { return CPU_TYPE_ARM
; }
931 template <> uint64_t SharedCache
<x86
>::sharedRegionStartAddress() { return 0x90000000; }
932 template <> uint64_t SharedCache
<x86_64
>::sharedRegionStartAddress() { return 0x7FFF80000000LL
; }
933 template <> uint64_t SharedCache
<arm
>::sharedRegionStartAddress() { return ARM_SHARED_REGION_START
; }
935 template <> uint64_t SharedCache
<x86
>::sharedRegionSize() { return 0x20000000; }
936 template <> uint64_t SharedCache
<x86_64
>::sharedRegionSize() { return 0x40000000; }
937 template <> uint64_t SharedCache
<arm
>::sharedRegionSize() { return ARM_SHARED_REGION_SIZE
; }
939 template <> uint64_t SharedCache
<x86
>::sharedRegionStartWritableAddress(uint64_t exEnd
) { return exEnd
+ 0x04000000; }
940 template <> uint64_t SharedCache
<x86_64
>::sharedRegionStartWritableAddress(uint64_t exEnd
) { return 0x7FFF70000000LL
; }
941 template <> uint64_t SharedCache
<arm
>::sharedRegionStartWritableAddress(uint64_t exEnd
) { return (exEnd
+ 16383) & (-16384); }
943 template <> uint64_t SharedCache
<x86
>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd
, uint64_t exEnd
) { return wrEnd
+ 0x04000000; }
944 template <> uint64_t SharedCache
<x86_64
>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd
, uint64_t exEnd
){ return exEnd
; }
945 template <> uint64_t SharedCache
<arm
>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd
, uint64_t exEnd
) { return (wrEnd
+ 16383) & (-16384); }
948 template <> const char* SharedCache
<x86
>::archName() { return "i386"; }
949 template <> const char* SharedCache
<x86_64
>::archName() { return "x86_64"; }
950 template <> const char* SharedCache
<arm
>::archName() { return "arm"; }
952 template <> const char* SharedCache
<x86
>::cacheFileSuffix(bool, const char* archName
) { return archName
; }
953 template <> const char* SharedCache
<x86_64
>::cacheFileSuffix(bool, const char* archName
){ return archName
; }
954 template <> const char* SharedCache
<arm
>::cacheFileSuffix(bool, const char* archName
) { return archName
; }
957 template <> uint64_t SharedCache
<x86
>::pageAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
958 template <> uint64_t SharedCache
<x86_64
>::pageAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
959 template <> uint64_t SharedCache
<arm
>::pageAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
962 template <typename A
>
963 SharedCache
<A
>::SharedCache(ArchGraph
* graph
, const char* rootPath
, const char* overlayPath
, const char* cacheDir
, bool explicitCacheDir
, bool alphaSort
, bool verify
, bool optimize
, uint64_t dyldBaseAddress
)
964 : fArchGraph(graph
), fVerify(verify
), fExistingIsNotUpToDate(true),
965 fCacheFileInFinalLocation(rootPath
[0] == '\0'), fCacheFilePath(NULL
),
966 fExistingCacheForVerification(NULL
), fDyldBaseAddress(dyldBaseAddress
),
967 fOffsetOfBindInfoInCombinedLinkedit(0), fOffsetOfWeakBindInfoInCombinedLinkedit(0),
968 fOffsetOfLazyBindInfoInCombinedLinkedit(0), fOffsetOfExportInfoInCombinedLinkedit(0),
969 fOffsetOfOldSymbolTableInfoInCombinedLinkedit(0), fSizeOfOldSymbolTableInfoInCombinedLinkedit(0),
970 fOffsetOfOldExternalRelocationsInCombinedLinkedit(0), fSizeOfOldExternalRelocationsInCombinedLinkedit(0),
971 fOffsetOfOldIndirectSymbolsInCombinedLinkedit(0), fSizeOfOldIndirectSymbolsInCombinedLinkedit(0),
972 fOffsetOfOldStringPoolInCombinedLinkedit(0), fSizeOfOldStringPoolInCombinedLinkedit(0),
973 fOffsetOfFunctionStartsInCombinedLinkedit(0), fSizeOfFunctionStartsInCombinedLinkedit(0),
974 fOffsetOfDataInCodeInCombinedLinkedit(0), fSizeOfDataInCodeInCombinedLinkedit(0),
975 fUnmappedLocalSymbolsSize(0)
977 if ( fArchGraph
->getArchPair().arch
!= arch() )
978 throwf("SharedCache object is wrong architecture: 0x%08X vs 0x%08X", fArchGraph
->getArchPair().arch
, arch());
980 // build vector of all shared dylibs
981 unsigned int aliasCount
= 0;
982 std::set
<const MachOLayoutAbstraction
*>& dylibs
= fArchGraph
->getSharedDylibs();
983 ArchGraph::StringToString
& aliases
= fArchGraph
->getDylibAliases();
984 for(std::set
<const MachOLayoutAbstraction
*>::iterator it
= dylibs
.begin(); it
!= dylibs
.end(); ++it
) {
985 const MachOLayoutAbstraction
* lib
= *it
;
988 temp
.info
.address
= 0;
989 temp
.info
.modTime
= lib
->getLastModTime();
990 temp
.info
.inode
= lib
->getInode();
991 temp
.info
.pathFileOffset
= lib
->getNameFileOffset(); // for now this is the offset within the dylib
992 for(ArchGraph::StringToString::iterator ait
= aliases
.begin(); ait
!= aliases
.end(); ++ait
) {
993 if ( strcmp(ait
->second
, lib
->getID().name
) == 0 ) {
994 temp
.aliases
.push_back(ait
->first
);
998 fDylibs
.push_back(temp
);
1001 // create path to cache file
1002 char cachePathCanonical
[MAXPATHLEN
];
1003 strcpy(cachePathCanonical
, cacheDir
);
1004 if ( cachePathCanonical
[strlen(cachePathCanonical
)-1] != '/' )
1005 strcat(cachePathCanonical
, "/");
1006 strcat(cachePathCanonical
, DYLD_SHARED_CACHE_BASE_NAME
);
1007 strcat(cachePathCanonical
, cacheFileSuffix(optimize
, fArchGraph
->archName()));
1008 char cachePath
[MAXPATHLEN
];
1009 if ( explicitCacheDir
) {
1010 fCacheFilePath
= strdup(cachePathCanonical
);
1012 else if ( overlayPath
[0] != '\0' ) {
1013 strcpy(cachePath
, overlayPath
);
1014 strcat(cachePath
, "/");
1015 strcat(cachePath
, cachePathCanonical
);
1016 fCacheFilePath
= strdup(cachePath
);
1018 else if ( rootPath
[0] != '\0' ) {
1019 strcpy(cachePath
, rootPath
);
1020 strcat(cachePath
, "/");
1021 strcat(cachePath
, cachePathCanonical
);
1022 fCacheFilePath
= strdup(cachePath
);
1025 fCacheFilePath
= strdup(cachePathCanonical
);
1027 if ( overlayPath
[0] != '\0' ) {
1028 // in overlay mode if there already is a cache file in the overlay
1029 // check if it is up to date.
1030 struct stat stat_buf
;
1031 if ( stat(fCacheFilePath
, &stat_buf
) == 0 ) {
1032 fExistingIsNotUpToDate
= this->notUpToDate(fCacheFilePath
, aliasCount
);
1034 else if ( rootPath
[0] != '\0' ) {
1035 // using -root and -overlay, but no cache file in overlay, check one in -root
1036 char cachePathRoot
[MAXPATHLEN
];
1037 strcpy(cachePathRoot
, rootPath
);
1038 strcat(cachePathRoot
, "/");
1039 strcat(cachePathRoot
, cachePathCanonical
);
1040 fExistingIsNotUpToDate
= this->notUpToDate(cachePathRoot
, aliasCount
);
1043 // uisng -overlay, but no cache file in overlay, check one in boot volume
1044 fExistingIsNotUpToDate
= this->notUpToDate(cachePathCanonical
, aliasCount
);
1048 fExistingIsNotUpToDate
= this->notUpToDate(fCacheFilePath
, aliasCount
);
1051 // sort shared dylibs
1053 // already sorted by notUpToDate()
1055 else if ( alphaSort
) {
1056 std::sort(fDylibs
.begin(), fDylibs
.end(), ByNameSorter());
1059 // random sort for Address Space Randomization
1060 std::map
<const MachOLayoutAbstraction
*, uint32_t> map
;
1061 for(typename
std::vector
<struct LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
)
1062 map
[it
->layout
] = arc4random();
1063 std::sort(fDylibs
.begin(), fDylibs
.end(), Sorter(map
));
1066 // assign segments in each dylib a new address
1067 this->assignNewBaseAddresses(verify
);
1069 // calculate where string pool offset will start
1070 // calculate cache file header size
1071 fHeaderSize
= sizeof(dyld_cache_header
)
1072 + fMappings
.size()*sizeof(shared_file_mapping_np
)
1073 + (fDylibs
.size()+aliasCount
)*sizeof(dyld_cache_image_info
);
1074 const uint64_t baseHeaderSize
= fHeaderSize
;
1075 //fprintf(stderr, "aliasCount=%d, fHeaderSize=0x%08X\n", aliasCount, fHeaderSize);
1076 // build list of aliases and compute where each ones path string will go
1077 for(typename
std::vector
<struct LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1078 for(std::vector
<const char*>::const_iterator ait
= it
->aliases
.begin(); ait
!= it
->aliases
.end(); ++ait
) {
1079 LayoutInfo temp
= *it
;
1080 // alias looks just like real dylib, but has a different name string
1081 const char* aliasPath
= *ait
;
1082 temp
.aliases
.clear();
1083 temp
.aliases
.push_back(aliasPath
);
1084 temp
.info
.pathFileOffset
= fHeaderSize
;
1085 fDylibAliases
.push_back(temp
);
1086 fHeaderSize
+= strlen(aliasPath
)+1;
1089 std::sort(fDylibAliases
.begin(), fDylibAliases
.end(), ByNameSorter());
1090 //fprintf(stderr, "fHeaderSize=0x%08X, fDylibAliases.size()=%lu\n", fHeaderSize, fDylibAliases.size());
1091 fHeaderSize
= pageAlign(fHeaderSize
);
1093 // check that cache we are about to create for verification purposes has same layout as existing cache
1095 // if no existing cache, say so
1096 if ( fExistingCacheForVerification
== NULL
) {
1097 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
1098 getpid(), fArchGraph
->archName());
1100 const dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)fExistingCacheForVerification
;
1101 const dyldCacheImageInfo
<E
>* cacheEntry
= (dyldCacheImageInfo
<E
>*)(fExistingCacheForVerification
+ header
->imagesOffset());
1102 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++cacheEntry
) {
1103 if ( cacheEntry
->address() != it
->layout
->getSegments()[0].newAddress() ) {
1104 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",
1105 getpid(), fArchGraph
->archName(), it
->layout
->getID().name
, cacheEntry
->address(), it
->layout
->getSegments()[0].newAddress());
1111 if ( fHeaderSize
> FIRST_DYLIB_TEXT_OFFSET
)
1112 throwf("header size overflow: allowed=0x%08X, base=0x%08llX, aliases=0x%08llX", FIRST_DYLIB_TEXT_OFFSET
, baseHeaderSize
, fHeaderSize
-baseHeaderSize
);
1116 template <typename A
>
1117 uint64_t SharedCache
<A
>::getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
)
1119 return proposedNewAddress
;
1123 template <typename A
>
1124 void SharedCache
<A
>::assignNewBaseAddresses(bool verify
)
1126 // first layout TEXT for dylibs
1127 const uint64_t startExecuteAddress
= sharedRegionStartAddress();
1128 uint64_t currentExecuteAddress
= startExecuteAddress
+ FIRST_DYLIB_TEXT_OFFSET
;
1129 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1130 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1131 for (int i
=0; i
< segs
.size(); ++i
) {
1132 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1134 if ( seg
.executable() && !seg
.writable() ) {
1136 if ( it
->info
.address
== 0 )
1137 it
->info
.address
= currentExecuteAddress
;
1138 seg
.setNewAddress(currentExecuteAddress
);
1139 currentExecuteAddress
+= pageAlign(seg
.size());
1144 // layout DATA for dylibs
1145 const uint64_t startWritableAddress
= sharedRegionStartWritableAddress(currentExecuteAddress
);
1146 uint64_t currentWritableAddress
= startWritableAddress
;
1147 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1148 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1149 for (int i
=0; i
< segs
.size(); ++i
) {
1150 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1152 if ( seg
.writable() ) {
1153 if ( seg
.executable() )
1154 throw "found writable and executable segment";
1156 seg
.setNewAddress(currentWritableAddress
);
1157 currentWritableAddress
= pageAlign(seg
.newAddress() + seg
.size());
1162 // layout all read-only (but not LINKEDIT) segments
1163 const uint64_t startReadOnlyAddress
= sharedRegionStartReadOnlyAddress(currentWritableAddress
, currentExecuteAddress
);
1164 uint64_t currentReadOnlyAddress
= startReadOnlyAddress
;
1165 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1166 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1167 for(int i
=0; i
< segs
.size(); ++i
) {
1168 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1169 if ( seg
.readable() && !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") != 0) ) {
1170 // __UNICODE segment
1171 seg
.setNewAddress(currentReadOnlyAddress
);
1172 currentReadOnlyAddress
+= pageAlign(seg
.size());
1177 // layout all LINKEDIT segments at end of all read-only segments
1178 fLinkEditsStartAddress
= currentReadOnlyAddress
;
1179 fFirstLinkEditSegment
= NULL
;
1180 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1181 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1182 for(int i
=0; i
< segs
.size(); ++i
) {
1183 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1184 if ( seg
.readable() && !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
1185 if ( fFirstLinkEditSegment
== NULL
)
1186 fFirstLinkEditSegment
= &seg
;
1187 seg
.setNewAddress(currentReadOnlyAddress
);
1188 currentReadOnlyAddress
+= pageAlign(seg
.size());
1192 fLinkEditsTotalUnoptimizedSize
= pageAlign(currentReadOnlyAddress
- fLinkEditsStartAddress
);
1194 // populate large mappings
1195 uint64_t cacheFileOffset
= 0;
1196 if ( currentExecuteAddress
> startExecuteAddress
) {
1197 shared_file_mapping_np executeMapping
;
1198 executeMapping
.sfm_address
= startExecuteAddress
;
1199 executeMapping
.sfm_size
= currentExecuteAddress
- startExecuteAddress
;
1200 executeMapping
.sfm_file_offset
= cacheFileOffset
;
1201 executeMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
1202 executeMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
1203 fMappings
.push_back(executeMapping
);
1204 cacheFileOffset
+= executeMapping
.sfm_size
;
1206 shared_file_mapping_np writableMapping
;
1207 writableMapping
.sfm_address
= startWritableAddress
;
1208 writableMapping
.sfm_size
= currentWritableAddress
- startWritableAddress
;
1209 writableMapping
.sfm_file_offset
= cacheFileOffset
;
1210 writableMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
1211 writableMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
1212 fMappings
.push_back(writableMapping
);
1213 cacheFileOffset
+= writableMapping
.sfm_size
;
1215 // make read-only (contains LINKEDIT segments) last, so it can be cut back when optimized
1216 shared_file_mapping_np readOnlyMapping
;
1217 readOnlyMapping
.sfm_address
= startReadOnlyAddress
;
1218 readOnlyMapping
.sfm_size
= currentReadOnlyAddress
- startReadOnlyAddress
;
1219 readOnlyMapping
.sfm_file_offset
= cacheFileOffset
;
1220 readOnlyMapping
.sfm_max_prot
= VM_PROT_READ
;
1221 readOnlyMapping
.sfm_init_prot
= VM_PROT_READ
;
1222 fMappings
.push_back(readOnlyMapping
);
1223 cacheFileOffset
+= readOnlyMapping
.sfm_size
;
1227 shared_file_mapping_np cacheHeaderMapping
;
1228 cacheHeaderMapping
.sfm_address
= startExecuteAddress
;
1229 cacheHeaderMapping
.sfm_size
= FIRST_DYLIB_TEXT_OFFSET
;
1230 cacheHeaderMapping
.sfm_file_offset
= cacheFileOffset
;
1231 cacheHeaderMapping
.sfm_max_prot
= VM_PROT_READ
;
1232 cacheHeaderMapping
.sfm_init_prot
= VM_PROT_READ
;
1233 fMappings
.push_back(cacheHeaderMapping
);
1234 cacheFileOffset
+= cacheHeaderMapping
.sfm_size
;
1239 template <typename A
>
1240 uint64_t SharedCache
<A
>::cacheFileOffsetForVMAddress(uint64_t vmaddr
) const
1242 for(std::vector
<shared_file_mapping_np
>::const_iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1243 if ( (it
->sfm_address
<= vmaddr
) && (vmaddr
< it
->sfm_address
+it
->sfm_size
) )
1244 return it
->sfm_file_offset
+ vmaddr
- it
->sfm_address
;
1246 throwf("address 0x%0llX is not in cache", vmaddr
);
1249 template <typename A
>
1250 uint64_t SharedCache
<A
>::VMAddressForCacheFileOffset(uint64_t offset
) const
1252 for(std::vector
<shared_file_mapping_np
>::const_iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1253 if ( (it
->sfm_file_offset
<= offset
) && (offset
< it
->sfm_file_offset
+it
->sfm_size
) )
1254 return it
->sfm_address
+ offset
- it
->sfm_file_offset
;
1256 throwf("offset 0x%0llX is not in cache", offset
);
1259 template <typename A
>
1260 void *SharedCache
<A
>::mappedAddressForVMAddress(uint64_t vmaddr
)
1262 if (!vmaddr
) return NULL
;
1263 else return fInMemoryCache
+ cacheFileOffsetForVMAddress(vmaddr
);
1266 template <typename A
>
1267 uint64_t SharedCache
<A
>::VMAddressForMappedAddress(const void *mapaddr
)
1269 if (!mapaddr
) return 0;
1270 uint64_t offset
= (uint8_t *)mapaddr
- (uint8_t *)fInMemoryCache
;
1271 return VMAddressForCacheFileOffset(offset
);
1275 template <typename A
>
1276 bool SharedCache
<A
>::notUpToDate(const void* cache
, unsigned int aliasCount
)
1278 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)cache
;
1279 // not valid if header signature is wrong
1280 const char* archPairName
= fArchGraph
->archName();
1282 strcpy(temp
, "dyld_v1 ");
1283 strcpy(&temp
[15-strlen(archPairName
)], archPairName
);
1284 if ( strcmp(header
->magic(), temp
) != 0 ) {
1286 fprintf(stderr
, "update_dyld_shared_cache[%u] cannot verify %s because current cache file has invalid header\n", getpid(), archName());
1290 fprintf(stderr
, "update_dyld_shared_cache[%u] updating cache because current cache file has invalid header\n", getpid());
1294 // not valid if count of images does not match current images needed
1295 if ( header
->imagesCount() != (fDylibs
.size()+aliasCount
) ) {
1297 fprintf(stderr
, "update_dyld_shared_cache[%u] cannot verify %s because current cache file contains a different set of dylibs\n", getpid(), archName());
1301 fprintf(stderr
, "update_dyld_shared_cache[%u] updating %s cache because current cache file contains a different set of dylibs\n", getpid(), archName());
1305 // get end of TEXT region
1306 const dyldCacheFileMapping
<E
>* textMapping
= (dyldCacheFileMapping
<E
>*)((uint8_t*)cache
+sizeof(dyldCacheHeader
<E
>));
1307 const uint32_t textSize
= textMapping
->size();
1309 // verify every dylib in constructed graph is in existing cache with same inode and modTime
1310 std::map
<const MachOLayoutAbstraction
*, uint32_t> sortingMap
;
1311 const dyldCacheImageInfo
<E
>* imagesStart
= (dyldCacheImageInfo
<E
>*)((uint8_t*)cache
+ header
->imagesOffset());
1312 const dyldCacheImageInfo
<E
>* imagesEnd
= &imagesStart
[header
->imagesCount()];
1313 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1315 //fprintf(stderr, "inode=0x%llX, mTime=0x%llX, path=%s\n", it->info.inode, it->info.modTime, it->layout->getID().name);
1316 for(const dyldCacheImageInfo
<E
>* cacheEntry
= imagesStart
; cacheEntry
< imagesEnd
; ++cacheEntry
) {
1318 if ( cacheEntry
->pathFileOffset() > textSize
) {
1319 throwf("update_dyld_shared_cache[%u]: for arch=%s, image entries corrupt, bad path offset in %s\n",
1320 getpid(), archName(), it
->layout
->getID().name
);
1322 // in -verify mode, just match by path and warn if file looks different
1323 if ( strcmp((char*)cache
+cacheEntry
->pathFileOffset(), it
->layout
->getID().name
) == 0 ) {
1325 sortingMap
[it
->layout
] = cacheEntry
-imagesStart
;
1326 if ( (cacheEntry
->inode() != it
->info
.inode
) || (cacheEntry
->modTime() != it
->info
.modTime
) ) {
1327 fprintf(stderr
, "update_dyld_shared_cache[%u] warning: for arch=%s, %s has changed since cache was built\n",
1328 getpid(), archName(), it
->layout
->getID().name
);
1334 if ( cacheEntry
->pathFileOffset() > textSize
) {
1335 // cache corrupt, needs to be regenerated
1338 // in normal update mode, everything has to match for cache to be up-to-date
1339 if ( (cacheEntry
->inode() == it
->info
.inode
)
1340 && (cacheEntry
->modTime() == it
->info
.modTime
)
1341 && (strcmp((char*)cache
+cacheEntry
->pathFileOffset(), it
->layout
->getID().name
) == 0) ) {
1349 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
);
1352 fprintf(stderr
, "update_dyld_shared_cache[%u] updating %s cache because dylib at %s has changed\n", getpid(), archName(), it
->layout
->getID().name
);
1357 // all dylibs in existing cache file match those determined need to be in shared cache
1359 // sort fDylibs to match existing cache file so we can compare content
1360 std::sort(fDylibs
.begin(), fDylibs
.end(), Sorter(sortingMap
));
1361 //fprintf(stderr, "dylibs sorted like existing cache:\n");
1362 //for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1363 // fprintf(stderr," %s\n", it->layout->getID().name);
1365 // do regenerate a new cache so we can compare content with existing
1369 // existing cache file is up-to-date, don't need to regenerate
1375 template <typename A
>
1376 bool SharedCache
<A
>::notUpToDate(const char* path
, unsigned int aliasCount
)
1378 // mmap existing cache file
1379 int fd
= ::open(path
, O_RDONLY
);
1382 struct stat stat_buf
;
1383 ::fstat(fd
, &stat_buf
);
1384 uint32_t cacheFileSize
= stat_buf
.st_size
;
1385 uint32_t cacheAllocatedSize
= pageAlign(cacheFileSize
);
1386 uint8_t* mappingAddr
= NULL
;
1387 if ( vm_allocate(mach_task_self(), (vm_address_t
*)(&mappingAddr
), cacheAllocatedSize
, VM_FLAGS_ANYWHERE
) != KERN_SUCCESS
)
1388 throwf("can't vm_allocate cache of size %u", cacheFileSize
);
1389 // <rdar://problem/8960832> update_dyld_shared_cache -verify finds differences
1390 (void)fcntl(fd
, F_NOCACHE
, 1);
1391 ssize_t readResult
= pread(fd
, mappingAddr
, cacheFileSize
, 0);
1392 if ( readResult
!= cacheFileSize
)
1393 throwf("can't read all of existing cache file (%lu of %u): %s", readResult
, cacheFileSize
, path
);
1397 bool result
= this->notUpToDate(mappingAddr
, aliasCount
);
1399 // don't unmap yet, leave so it can be verified later
1400 fExistingCacheForVerification
= mappingAddr
;
1404 vm_deallocate(mach_task_self(), (vm_address_t
)mappingAddr
, cacheAllocatedSize
);
1405 if ( verbose
&& !result
)
1406 fprintf(stderr
, "update_dyld_shared_cache: %s is up-to-date\n", path
);
1413 template <typename A
>
1414 class LinkEditOptimizer
1417 LinkEditOptimizer(const MachOLayoutAbstraction
&, const SharedCache
<A
>&, uint8_t*, StringPool
&);
1418 virtual ~LinkEditOptimizer() {}
1420 void copyBindInfo(uint32_t&);
1421 void copyWeakBindInfo(uint32_t&);
1422 void copyLazyBindInfo(uint32_t&);
1423 void copyExportInfo(uint32_t&);
1424 void copyLocalSymbols(uint32_t symbolTableOffset
, uint32_t&, bool dontMapLocalSymbols
,
1425 uint8_t* cacheStart
, StringPool
& unmappedLocalsStringPool
,
1426 std::vector
<macho_nlist
<typename
A::P
> >& unmappedSymbols
,
1427 std::vector
<LocalSymbolInfo
>& info
);
1428 void copyExportedSymbols(uint32_t symbolTableOffset
, uint32_t&);
1429 void copyImportedSymbols(uint32_t symbolTableOffset
, uint32_t&);
1430 void copyExternalRelocations(uint32_t& offset
);
1431 void copyIndirectSymbolTable(uint32_t& offset
);
1432 void copyFunctionStarts(uint32_t& offset
);
1433 void copyDataInCode(uint32_t& offset
);
1434 void updateLoadCommands(uint64_t newVMAddress
, uint64_t size
, uint32_t stringPoolOffset
,
1435 uint32_t linkEditsFileOffset
, bool keepSignatures
);
1439 typedef typename
A::P P
;
1440 typedef typename
A::P::E E
;
1441 typedef typename
A::P::uint_t pint_t
;
1445 const SharedCache
<A
>& fSharedCache
;
1446 const macho_header
<P
>* fHeader
;
1447 uint8_t* fNewLinkEditStart
;
1448 uint8_t* fLinkEditBase
;
1449 const MachOLayoutAbstraction
& fLayout
;
1450 macho_dyld_info_command
<P
>* fDyldInfo
;
1451 macho_dysymtab_command
<P
>* fDynamicSymbolTable
;
1452 macho_linkedit_data_command
<P
>* fFunctionStarts
;
1453 macho_linkedit_data_command
<P
>* fDataInCode
;
1454 macho_symtab_command
<P
>* fSymbolTableLoadCommand
;
1455 const macho_nlist
<P
>* fSymbolTable
;
1456 const char* fStrings
;
1457 StringPool
& fNewStringPool
;
1458 std::map
<uint32_t,uint32_t> fOldToNewSymbolIndexes
;
1459 uint32_t fBindInfoOffsetIntoNewLinkEdit
;
1460 uint32_t fBindInfoSizeInNewLinkEdit
;
1461 uint32_t fWeakBindInfoOffsetIntoNewLinkEdit
;
1462 uint32_t fWeakBindInfoSizeInNewLinkEdit
;
1463 uint32_t fLazyBindInfoOffsetIntoNewLinkEdit
;
1464 uint32_t fLazyBindInfoSizeInNewLinkEdit
;
1465 uint32_t fExportInfoOffsetIntoNewLinkEdit
;
1466 uint32_t fExportInfoSizeInNewLinkEdit
;
1467 uint32_t fSymbolTableStartOffsetInNewLinkEdit
;
1468 uint32_t fLocalSymbolsStartIndexInNewLinkEdit
;
1469 uint32_t fLocalSymbolsCountInNewLinkEdit
;
1470 uint32_t fExportedSymbolsStartIndexInNewLinkEdit
;
1471 uint32_t fExportedSymbolsCountInNewLinkEdit
;
1472 uint32_t fImportSymbolsStartIndexInNewLinkEdit
;
1473 uint32_t fImportedSymbolsCountInNewLinkEdit
;
1474 uint32_t fExternalRelocationsOffsetIntoNewLinkEdit
;
1475 uint32_t fIndirectSymbolTableOffsetInfoNewLinkEdit
;
1476 uint32_t fFunctionStartsOffsetInNewLinkEdit
;
1477 uint32_t fDataInCodeOffsetInNewLinkEdit
;
1478 uint32_t fUnmappedLocalSymbolsStartIndexInNewLinkEdit
;
1479 uint32_t fUnmappedLocalSymbolsCountInNewLinkEdit
;
1484 template <typename A
>
1485 LinkEditOptimizer
<A
>::LinkEditOptimizer(const MachOLayoutAbstraction
& layout
, const SharedCache
<A
>& sharedCache
, uint8_t* newLinkEdit
, StringPool
& stringPool
)
1486 : fSharedCache(sharedCache
), fLayout(layout
), fLinkEditBase(NULL
), fNewLinkEditStart(newLinkEdit
), fDyldInfo(NULL
),
1487 fDynamicSymbolTable(NULL
), fFunctionStarts(NULL
), fDataInCode(NULL
),
1488 fSymbolTableLoadCommand(NULL
), fSymbolTable(NULL
), fStrings(NULL
), fNewStringPool(stringPool
),
1489 fBindInfoOffsetIntoNewLinkEdit(0), fBindInfoSizeInNewLinkEdit(0),
1490 fWeakBindInfoOffsetIntoNewLinkEdit(0), fWeakBindInfoSizeInNewLinkEdit(0),
1491 fLazyBindInfoOffsetIntoNewLinkEdit(0), fLazyBindInfoSizeInNewLinkEdit(0),
1492 fExportInfoOffsetIntoNewLinkEdit(0), fExportInfoSizeInNewLinkEdit(0),
1493 fSymbolTableStartOffsetInNewLinkEdit(0),
1494 fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
1495 fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
1496 fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
1497 fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0),
1498 fFunctionStartsOffsetInNewLinkEdit(0), fDataInCodeOffsetInNewLinkEdit(0),
1499 fUnmappedLocalSymbolsStartIndexInNewLinkEdit(0), fUnmappedLocalSymbolsCountInNewLinkEdit(0)
1502 fHeader
= (const macho_header
<P
>*)fLayout
.getSegments()[0].mappedAddress();
1504 const std::vector
<MachOLayoutAbstraction::Segment
>& segments
= fLayout
.getSegments();
1505 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator it
= segments
.begin(); it
!= segments
.end(); ++it
) {
1506 const MachOLayoutAbstraction::Segment
& seg
= *it
;
1507 if ( strcmp(seg
.name(), "__LINKEDIT") == 0 )
1508 fLinkEditBase
= (uint8_t*)seg
.mappedAddress() - seg
.fileOffset();
1510 if ( fLinkEditBase
== NULL
)
1511 throw "no __LINKEDIT segment";
1513 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
1514 const uint32_t cmd_count
= fHeader
->ncmds();
1515 const macho_load_command
<P
>* cmd
= cmds
;
1516 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1517 switch (cmd
->cmd()) {
1520 fSymbolTableLoadCommand
= (macho_symtab_command
<P
>*)cmd
;
1521 fSymbolTable
= (macho_nlist
<P
>*)(&fLinkEditBase
[fSymbolTableLoadCommand
->symoff()]);
1522 fStrings
= (char*)&fLinkEditBase
[fSymbolTableLoadCommand
->stroff()];
1526 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
1529 case LC_DYLD_INFO_ONLY
:
1530 fDyldInfo
= (macho_dyld_info_command
<P
>*)cmd
;
1532 case LC_FUNCTION_STARTS
:
1533 fFunctionStarts
= (macho_linkedit_data_command
<P
>*)cmd
;
1534 case LC_DATA_IN_CODE
:
1535 fDataInCode
= (macho_linkedit_data_command
<P
>*)cmd
;
1538 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1540 if ( fSymbolTable
== NULL
)
1541 throw "no LC_SYMTAB";
1542 if ( fDynamicSymbolTable
== NULL
)
1543 throw "no LC_DYSYMTAB";
1548 template <typename A
>
1552 typedef typename
A::P P
;
1553 SymbolSorter(const StringPool
& pool
) : fStringPool(pool
) {}
1554 bool operator()(const macho_nlist
<P
>& left
, const macho_nlist
<P
>& right
) {
1555 return (strcmp(fStringPool
.stringAtIndex(left
.n_strx()) , fStringPool
.stringAtIndex(right
.n_strx())) < 0);
1559 const StringPool
& fStringPool
;
1563 template <typename A
>
1564 void LinkEditOptimizer
<A
>::copyBindInfo(uint32_t& offset
)
1566 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->bind_off() != 0) ) {
1567 fBindInfoOffsetIntoNewLinkEdit
= offset
;
1568 fBindInfoSizeInNewLinkEdit
= fDyldInfo
->bind_size();
1569 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->bind_off()], fDyldInfo
->bind_size());
1570 offset
+= fDyldInfo
->bind_size();
1574 template <typename A
>
1575 void LinkEditOptimizer
<A
>::copyWeakBindInfo(uint32_t& offset
)
1577 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->weak_bind_off() != 0) ) {
1578 fWeakBindInfoOffsetIntoNewLinkEdit
= offset
;
1579 fWeakBindInfoSizeInNewLinkEdit
= fDyldInfo
->weak_bind_size();
1580 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->weak_bind_off()], fDyldInfo
->weak_bind_size());
1581 offset
+= fDyldInfo
->weak_bind_size();
1585 template <typename A
>
1586 void LinkEditOptimizer
<A
>::copyLazyBindInfo(uint32_t& offset
)
1588 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->lazy_bind_off() != 0) ) {
1589 fLazyBindInfoOffsetIntoNewLinkEdit
= offset
;
1590 fLazyBindInfoSizeInNewLinkEdit
= fDyldInfo
->lazy_bind_size();
1591 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->lazy_bind_off()], fDyldInfo
->lazy_bind_size());
1592 offset
+= fDyldInfo
->lazy_bind_size();
1596 template <typename A
>
1597 void LinkEditOptimizer
<A
>::copyExportInfo(uint32_t& offset
)
1599 if ( (fDyldInfo
!= NULL
) && (fLayout
.getDyldInfoExports() != NULL
) ) {
1600 fExportInfoOffsetIntoNewLinkEdit
= offset
;
1601 fExportInfoSizeInNewLinkEdit
= fDyldInfo
->export_size();
1602 memcpy(fNewLinkEditStart
+offset
, fLayout
.getDyldInfoExports(), fDyldInfo
->export_size());
1603 offset
+= fDyldInfo
->export_size();
1608 template <typename A
>
1609 void LinkEditOptimizer
<A
>::copyLocalSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
, bool dontMapLocalSymbols
, uint8_t* cacheStart
,
1610 StringPool
& unmappedLocalsStringPool
, std::vector
<macho_nlist
<P
> >& unmappedSymbols
,
1611 std::vector
<LocalSymbolInfo
>& dylibInfos
)
1613 fLocalSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1614 LocalSymbolInfo localInfo
;
1615 localInfo
.dylibOffset
= ((uint8_t*)fHeader
) - cacheStart
;
1616 localInfo
.nlistStartIndex
= unmappedSymbols
.size();
1617 localInfo
.nlistCount
= 0;
1618 fSymbolTableStartOffsetInNewLinkEdit
= symbolTableOffset
+ symbolIndex
*sizeof(macho_nlist
<P
>);
1619 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1620 const macho_nlist
<P
>* const firstLocal
= &fSymbolTable
[fDynamicSymbolTable
->ilocalsym()];
1621 const macho_nlist
<P
>* const lastLocal
= &fSymbolTable
[fDynamicSymbolTable
->ilocalsym()+fDynamicSymbolTable
->nlocalsym()];
1622 uint32_t oldIndex
= fDynamicSymbolTable
->ilocalsym();
1623 for (const macho_nlist
<P
>* entry
= firstLocal
; entry
< lastLocal
; ++entry
, ++oldIndex
) {
1624 // <rdar://problem/12237639> don't copy stab symbols
1625 if ( (entry
->n_sect() != NO_SECT
) && ((entry
->n_type() & N_STAB
) == 0) ) {
1626 const char* name
= &fStrings
[entry
->n_strx()];
1627 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1628 *newSymbolEntry
= *entry
;
1629 if ( dontMapLocalSymbols
) {
1630 // if local in __text, add <redacted> symbol name to shared cache so backtraces don't have bogus names
1631 if ( entry
->n_sect() == 1 ) {
1632 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique("<redacted>"));
1635 // copy local symbol to unmmapped locals area
1636 unmappedSymbols
.push_back(*entry
);
1637 unmappedSymbols
.back().set_n_strx(unmappedLocalsStringPool
.addUnique(name
));
1640 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(name
));
1645 fLocalSymbolsCountInNewLinkEdit
= symbolIndex
- fLocalSymbolsStartIndexInNewLinkEdit
;
1646 localInfo
.nlistCount
= unmappedSymbols
.size() - localInfo
.nlistStartIndex
;
1647 dylibInfos
.push_back(localInfo
);
1648 //fprintf(stderr, "%u locals starting at %u for %s\n", fLocalSymbolsCountInNewLinkEdit, fLocalSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1652 template <typename A
>
1653 void LinkEditOptimizer
<A
>::copyExportedSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1655 fExportedSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1656 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1657 const macho_nlist
<P
>* const firstExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()];
1658 const macho_nlist
<P
>* const lastExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1659 uint32_t oldIndex
= fDynamicSymbolTable
->iextdefsym();
1660 for (const macho_nlist
<P
>* entry
= firstExport
; entry
< lastExport
; ++entry
, ++oldIndex
) {
1661 if ( ((entry
->n_type() & N_TYPE
) == N_SECT
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0)
1662 && (strncmp(&fStrings
[entry
->n_strx()], "$ld$", 4) != 0) ) {
1663 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1664 *newSymbolEntry
= *entry
;
1665 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1666 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
-fLocalSymbolsStartIndexInNewLinkEdit
;
1670 fExportedSymbolsCountInNewLinkEdit
= symbolIndex
- fExportedSymbolsStartIndexInNewLinkEdit
;
1671 //fprintf(stderr, "%u exports starting at %u for %s\n", fExportedSymbolsCountInNewLinkEdit, fExportedSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1672 // sort by name, so that dyld does not need a toc
1673 macho_nlist
<P
>* newSymbolsStart
= &newSymbolTableStart
[fExportedSymbolsStartIndexInNewLinkEdit
];
1674 macho_nlist
<P
>* newSymbolsEnd
= &newSymbolTableStart
[fExportedSymbolsStartIndexInNewLinkEdit
+fExportedSymbolsCountInNewLinkEdit
];
1675 std::sort(newSymbolsStart
, newSymbolsEnd
, SymbolSorter
<A
>(fNewStringPool
));
1676 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1677 // fprintf(stderr, "\t%u\t %s\n", (entry-newSymbolsStart)+fExportedSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1681 template <typename A
>
1682 void LinkEditOptimizer
<A
>::copyImportedSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1684 fImportSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1685 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1686 const macho_nlist
<P
>* const firstImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()];
1687 const macho_nlist
<P
>* const lastImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()+fDynamicSymbolTable
->nundefsym()];
1688 uint32_t oldIndex
= fDynamicSymbolTable
->iundefsym();
1689 for (const macho_nlist
<P
>* entry
= firstImport
; entry
< lastImport
; ++entry
, ++oldIndex
) {
1690 if ( ((entry
->n_type() & N_TYPE
) == N_UNDF
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0) ) {
1691 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1692 *newSymbolEntry
= *entry
;
1693 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1694 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
-fLocalSymbolsStartIndexInNewLinkEdit
;
1698 fImportedSymbolsCountInNewLinkEdit
= symbolIndex
- fImportSymbolsStartIndexInNewLinkEdit
;
1699 //fprintf(stderr, "%u imports starting at %u for %s\n", fImportedSymbolsCountInNewLinkEdit, fImportSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1700 //macho_nlist<P>* newSymbolsStart = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit];
1701 //macho_nlist<P>* newSymbolsEnd = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit];
1702 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1703 // fprintf(stderr, "\t%u\t%s\n", (entry-newSymbolsStart)+fImportSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1707 template <typename A
>
1708 void LinkEditOptimizer
<A
>::copyExternalRelocations(uint32_t& offset
)
1710 fExternalRelocationsOffsetIntoNewLinkEdit
= offset
;
1711 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(&fLinkEditBase
[fDynamicSymbolTable
->extreloff()]);
1712 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
1713 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1714 macho_relocation_info
<P
>* newReloc
= (macho_relocation_info
<P
>*)(&fNewLinkEditStart
[offset
]);
1716 uint32_t newSymbolIndex
= fOldToNewSymbolIndexes
[reloc
->r_symbolnum()];
1717 //fprintf(stderr, "copyExternalRelocations() old=%d, new=%u name=%s in %s\n", reloc->r_symbolnum(), newSymbolIndex,
1718 // &fStrings[fSymbolTable[reloc->r_symbolnum()].n_strx()], fLayout.getFilePath());
1719 newReloc
->set_r_symbolnum(newSymbolIndex
);
1720 offset
+= sizeof(macho_relocation_info
<P
>);
1724 template <typename A
>
1725 void LinkEditOptimizer
<A
>::copyFunctionStarts(uint32_t& offset
)
1727 if ( fFunctionStarts
!= NULL
) {
1728 fFunctionStartsOffsetInNewLinkEdit
= offset
;
1729 memcpy(&fNewLinkEditStart
[offset
], &fLinkEditBase
[fFunctionStarts
->dataoff()], fFunctionStarts
->datasize());
1730 offset
+= fFunctionStarts
->datasize();
1734 template <typename A
>
1735 void LinkEditOptimizer
<A
>::copyDataInCode(uint32_t& offset
)
1737 if ( fDataInCode
!= NULL
) {
1738 fDataInCodeOffsetInNewLinkEdit
= offset
;
1739 memcpy(&fNewLinkEditStart
[offset
], &fLinkEditBase
[fDataInCode
->dataoff()], fDataInCode
->datasize());
1740 offset
+= fDataInCode
->datasize();
1745 template <typename A
>
1746 void LinkEditOptimizer
<A
>::copyIndirectSymbolTable(uint32_t& offset
)
1748 fIndirectSymbolTableOffsetInfoNewLinkEdit
= offset
;
1749 const uint32_t* const indirectTable
= (uint32_t*)&this->fLinkEditBase
[fDynamicSymbolTable
->indirectsymoff()];
1750 uint32_t* newIndirectTable
= (uint32_t*)&fNewLinkEditStart
[offset
];
1751 for (int i
=0; i
< fDynamicSymbolTable
->nindirectsyms(); ++i
) {
1752 uint32_t oldSymbolIndex
= E::get32(indirectTable
[i
]);
1753 uint32_t newSymbolIndex
= oldSymbolIndex
;
1754 if ( (oldSymbolIndex
!= INDIRECT_SYMBOL_ABS
) && (oldSymbolIndex
!= INDIRECT_SYMBOL_LOCAL
) ) {
1755 newSymbolIndex
= fOldToNewSymbolIndexes
[oldSymbolIndex
];
1756 //fprintf(stderr, "copyIndirectSymbolTable() old=%d, new=%u name=%s in %s\n", oldSymbolIndex, newSymbolIndex,
1757 // &fStrings[fSymbolTable[oldSymbolIndex].n_strx()], fLayout.getFilePath());
1759 E::set32(newIndirectTable
[i
], newSymbolIndex
);
1761 offset
+= (fDynamicSymbolTable
->nindirectsyms() * 4);
1764 template <typename A
>
1765 void LinkEditOptimizer
<A
>::updateLoadCommands(uint64_t newVMAddress
, uint64_t size
, uint32_t stringPoolOffset
,
1766 uint32_t linkEditsFileOffset
, bool keepSignatures
)
1768 // set LINKEDIT segment commmand to new merged LINKEDIT
1769 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
1770 const uint32_t cmd_count
= fHeader
->ncmds();
1771 const macho_load_command
<P
>* cmd
= cmds
;
1772 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1773 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
1774 macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
1775 if ( strcmp(seg
->segname(), "__LINKEDIT") == 0 ) {
1776 seg
->set_vmaddr(newVMAddress
);
1777 seg
->set_vmsize(size
);
1778 seg
->set_filesize(size
);
1779 seg
->set_fileoff(linkEditsFileOffset
);
1781 // don't alter __TEXT until <rdar://problem/7022345> is fixed
1782 else if ( strcmp(seg
->segname(), "__TEXT") != 0 ) {
1783 // update all other segments fileoff to be offset from start of cache file
1784 pint_t oldFileOff
= seg
->fileoff();
1785 seg
->set_fileoff(fSharedCache
.cacheFileOffsetForVMAddress(seg
->vmaddr()));
1786 pint_t fileOffsetDelta
= seg
->fileoff() - oldFileOff
;
1787 // update all sections in this segment
1788 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)seg
+ sizeof(macho_segment_command
<P
>));
1789 macho_section
<P
>* const sectionsEnd
= §ionsStart
[seg
->nsects()];
1790 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1791 if ( sect
->offset() != 0 )
1792 sect
->set_offset(sect
->offset()+fileOffsetDelta
);
1796 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1799 // update dyld_info with new offsets
1800 if ( fDyldInfo
!= NULL
) {
1801 fDyldInfo
->set_rebase_off(0);
1802 fDyldInfo
->set_rebase_size(0);
1803 fDyldInfo
->set_bind_off(linkEditsFileOffset
+fBindInfoOffsetIntoNewLinkEdit
);
1804 fDyldInfo
->set_bind_size(fBindInfoSizeInNewLinkEdit
);
1805 fDyldInfo
->set_weak_bind_off(linkEditsFileOffset
+fWeakBindInfoOffsetIntoNewLinkEdit
);
1806 fDyldInfo
->set_weak_bind_size(fWeakBindInfoSizeInNewLinkEdit
);
1807 fDyldInfo
->set_lazy_bind_off(linkEditsFileOffset
+fLazyBindInfoOffsetIntoNewLinkEdit
);
1808 fDyldInfo
->set_lazy_bind_size(fLazyBindInfoSizeInNewLinkEdit
);
1809 fDyldInfo
->set_export_off(linkEditsFileOffset
+fExportInfoOffsetIntoNewLinkEdit
);
1810 fDyldInfo
->set_export_size(fExportInfoSizeInNewLinkEdit
);
1812 // fprintf(stderr, "dylib %s\n", fLayout.getFilePath());
1813 // fprintf(stderr, " bind_off=0x%08X\n", fDyldInfo->bind_off());
1814 // fprintf(stderr, " export_off=0x%08X\n", fDyldInfo->export_off());
1815 // fprintf(stderr, " export_size=%d\n", fDyldInfo->export_size());
1819 // update symbol table and dynamic symbol table with new offsets
1820 fSymbolTableLoadCommand
->set_symoff(linkEditsFileOffset
+fSymbolTableStartOffsetInNewLinkEdit
);
1821 fSymbolTableLoadCommand
->set_nsyms(fLocalSymbolsCountInNewLinkEdit
+fExportedSymbolsCountInNewLinkEdit
+fImportedSymbolsCountInNewLinkEdit
);
1822 fSymbolTableLoadCommand
->set_stroff(linkEditsFileOffset
+stringPoolOffset
);
1823 fSymbolTableLoadCommand
->set_strsize(fNewStringPool
.size());
1824 fDynamicSymbolTable
->set_ilocalsym(0);
1825 fDynamicSymbolTable
->set_nlocalsym(fLocalSymbolsCountInNewLinkEdit
);
1826 fDynamicSymbolTable
->set_iextdefsym(fExportedSymbolsStartIndexInNewLinkEdit
-fLocalSymbolsStartIndexInNewLinkEdit
);
1827 fDynamicSymbolTable
->set_nextdefsym(fExportedSymbolsCountInNewLinkEdit
);
1828 fDynamicSymbolTable
->set_iundefsym(fImportSymbolsStartIndexInNewLinkEdit
-fLocalSymbolsStartIndexInNewLinkEdit
);
1829 fDynamicSymbolTable
->set_nundefsym(fImportedSymbolsCountInNewLinkEdit
);
1830 fDynamicSymbolTable
->set_tocoff(0);
1831 fDynamicSymbolTable
->set_ntoc(0);
1832 fDynamicSymbolTable
->set_modtaboff(0);
1833 fDynamicSymbolTable
->set_nmodtab(0);
1834 fDynamicSymbolTable
->set_indirectsymoff(linkEditsFileOffset
+fIndirectSymbolTableOffsetInfoNewLinkEdit
);
1835 fDynamicSymbolTable
->set_extreloff(linkEditsFileOffset
+fExternalRelocationsOffsetIntoNewLinkEdit
);
1836 fDynamicSymbolTable
->set_locreloff(0);
1837 fDynamicSymbolTable
->set_nlocrel(0);
1839 // update function starts
1840 if ( fFunctionStarts
!= NULL
) {
1841 fFunctionStarts
->set_dataoff(linkEditsFileOffset
+fFunctionStartsOffsetInNewLinkEdit
);
1843 // update data-in-code info
1844 if ( fDataInCode
!= NULL
) {
1845 fDataInCode
->set_dataoff(linkEditsFileOffset
+fDataInCodeOffsetInNewLinkEdit
);
1848 // now remove load commands no longer needed
1849 const macho_load_command
<P
>* srcCmd
= cmds
;
1850 macho_load_command
<P
>* dstCmd
= (macho_load_command
<P
>*)cmds
;
1851 int32_t newCount
= 0;
1852 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1853 uint32_t cmdSize
= srcCmd
->cmdsize();
1854 switch ( srcCmd
->cmd() ) {
1855 case LC_SEGMENT_SPLIT_INFO
:
1856 case LC_DYLIB_CODE_SIGN_DRS
:
1859 case LC_CODE_SIGNATURE
:
1860 if ( !keepSignatures
)
1862 // otherwise fall into copy case
1864 memmove(dstCmd
, srcCmd
, cmdSize
);
1865 dstCmd
= (macho_load_command
<P
>*)(((uint8_t*)dstCmd
)+cmdSize
);
1869 srcCmd
= (const macho_load_command
<P
>*)(((uint8_t*)srcCmd
)+cmdSize
);
1871 // zero out stuff removed
1872 bzero(dstCmd
, (uint8_t*)srcCmd
- (uint8_t*)dstCmd
);
1874 // update mach_header
1875 macho_header
<P
>* writableHeader
= (macho_header
<P
>*)fHeader
;
1876 writableHeader
->set_ncmds(newCount
);
1877 writableHeader
->set_sizeofcmds((uint8_t*)dstCmd
- ((uint8_t*)fHeader
+ sizeof(macho_header
<P
>)));
1879 // this invalidates some ivars
1880 fDynamicSymbolTable
= NULL
;
1881 fSymbolTableLoadCommand
= NULL
;
1883 fSymbolTable
= NULL
;
1889 template <typename A
>
1890 uint8_t* SharedCache
<A
>::optimizeLINKEDIT(bool keepSignatures
, bool dontMapLocalSymbols
)
1892 // allocate space for optimized LINKEDIT area
1893 uint8_t* newLinkEdit
= new uint8_t[fLinkEditsTotalUnoptimizedSize
];
1894 bzero(newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
1896 // make a string pool
1897 StringPool stringPool
;
1899 // create optimizer object for each LINKEDIT segment
1900 std::vector
<LinkEditOptimizer
<A
>*> optimizers
;
1901 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1902 optimizers
.push_back(new LinkEditOptimizer
<A
>(*it
->layout
, *this, newLinkEdit
, stringPool
));
1905 // rebase info is not copied because images in shared cache are never rebased
1907 // copy weak bind info
1908 uint32_t offset
= 0;
1909 fOffsetOfWeakBindInfoInCombinedLinkedit
= offset
;
1910 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1911 (*it
)->copyWeakBindInfo(offset
);
1915 fOffsetOfExportInfoInCombinedLinkedit
= offset
;
1916 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1917 (*it
)->copyExportInfo(offset
);
1921 fOffsetOfBindInfoInCombinedLinkedit
= offset
;
1922 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1923 (*it
)->copyBindInfo(offset
);
1926 // copy lazy bind info
1927 fOffsetOfLazyBindInfoInCombinedLinkedit
= offset
;
1928 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1929 (*it
)->copyLazyBindInfo(offset
);
1932 // copy symbol table entries
1933 fOffsetOfOldSymbolTableInfoInCombinedLinkedit
= offset
;
1934 uint32_t symbolTableOffset
= offset
;
1935 uint32_t symbolTableIndex
= 0;
1936 if ( dontMapLocalSymbols
)
1937 fUnmappedLocalSymbols
.reserve(16384);
1938 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1939 (*it
)->copyLocalSymbols(symbolTableOffset
, symbolTableIndex
, dontMapLocalSymbols
, fInMemoryCache
,
1940 fUnmappedLocalsStringPool
, fUnmappedLocalSymbols
, fLocalSymbolInfos
);
1941 (*it
)->copyExportedSymbols(symbolTableOffset
, symbolTableIndex
);
1942 (*it
)->copyImportedSymbols(symbolTableOffset
, symbolTableIndex
);
1944 fSizeOfOldSymbolTableInfoInCombinedLinkedit
= symbolTableIndex
* sizeof(macho_nlist
<typename
A::P
>);
1945 offset
= symbolTableOffset
+ fSizeOfOldSymbolTableInfoInCombinedLinkedit
& (-8);
1947 // copy external relocations, 8-byte aligned after end of symbol table
1948 fOffsetOfOldExternalRelocationsInCombinedLinkedit
= offset
;
1949 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1950 (*it
)->copyExternalRelocations(offset
);
1952 fSizeOfOldExternalRelocationsInCombinedLinkedit
= offset
- fOffsetOfOldExternalRelocationsInCombinedLinkedit
;
1954 // copy function starts
1955 fOffsetOfFunctionStartsInCombinedLinkedit
= offset
;
1956 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1957 (*it
)->copyFunctionStarts(offset
);
1959 fSizeOfFunctionStartsInCombinedLinkedit
= offset
- fOffsetOfFunctionStartsInCombinedLinkedit
;
1961 // copy data-in-code info
1962 fOffsetOfDataInCodeInCombinedLinkedit
= offset
;
1963 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1964 (*it
)->copyDataInCode(offset
);
1966 fSizeOfDataInCodeInCombinedLinkedit
= offset
- fOffsetOfDataInCodeInCombinedLinkedit
;
1968 // copy indirect symbol tables
1969 fOffsetOfOldIndirectSymbolsInCombinedLinkedit
= offset
;
1970 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1971 (*it
)->copyIndirectSymbolTable(offset
);
1973 fSizeOfOldIndirectSymbolsInCombinedLinkedit
= offset
- fOffsetOfOldIndirectSymbolsInCombinedLinkedit
;
1976 fOffsetOfOldStringPoolInCombinedLinkedit
= offset
;
1977 memcpy(&newLinkEdit
[offset
], stringPool
.getBuffer(), stringPool
.size());
1978 fSizeOfOldStringPoolInCombinedLinkedit
= stringPool
.size();
1980 // total new size round up to page size
1981 fLinkEditsTotalOptimizedSize
= pageAlign(fOffsetOfOldStringPoolInCombinedLinkedit
+ fSizeOfOldStringPoolInCombinedLinkedit
);
1983 // choose new linkedit file offset
1984 uint32_t linkEditsFileOffset
= cacheFileOffsetForVMAddress(fLinkEditsStartAddress
);
1985 // uint32_t linkEditsFileOffset = fLinkEditsStartAddress - sharedRegionStartAddress();
1987 // update load commands so that all dylibs shared different areas of the same LINKEDIT segment
1988 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1989 (*it
)->updateLoadCommands(fLinkEditsStartAddress
, fLinkEditsTotalUnoptimizedSize
, fOffsetOfOldStringPoolInCombinedLinkedit
, linkEditsFileOffset
, keepSignatures
);
1992 //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, fLinkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, fLinkEditsTotalOptimizedSize);
1993 //printf(stderr, "mega link edit mapped starting at: %p\n", fFirstLinkEditSegment->mappedAddress());
1995 // overwrite mapped LINKEDIT area with new optimized LINKEDIT segment
1996 memcpy(fFirstLinkEditSegment
->mappedAddress(), newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
1998 // update all LINKEDIT Segment objects to point to same merged LINKEDIT area
1999 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2000 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
2001 for(int i
=0; i
< segs
.size(); ++i
) {
2002 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
2003 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
2004 seg
.setNewAddress(fLinkEditsStartAddress
);
2005 seg
.setMappedAddress(fFirstLinkEditSegment
->mappedAddress());
2006 seg
.setSize(fLinkEditsTotalOptimizedSize
);
2007 seg
.setFileSize(fLinkEditsTotalOptimizedSize
);
2008 seg
.setFileOffset(linkEditsFileOffset
);
2013 // return new end of cache
2014 return (uint8_t*)fFirstLinkEditSegment
->mappedAddress() + fLinkEditsTotalOptimizedSize
;
2018 template <typename A
>
2019 class ObjCSelectorUniquer
2022 objc_opt::string_map fSelectorStrings
;
2023 SharedCache
<A
> *fCache
;
2028 ObjCSelectorUniquer(SharedCache
<A
> *newCache
)
2029 : fSelectorStrings()
2034 typename
A::P::uint_t
visit(typename
A::P::uint_t oldValue
)
2037 const char *s
= (const char *)
2038 fCache
->mappedAddressForVMAddress(oldValue
);
2039 objc_opt::string_map::iterator element
=
2040 fSelectorStrings
.insert(objc_opt::string_map::value_type(s
, oldValue
)).first
;
2041 return (typename
A::P::uint_t
)element
->second
;
2044 objc_opt::string_map
& strings() {
2045 return fSelectorStrings
;
2048 size_t count() const { return fCount
; }
2052 template <typename A
>
2053 class ClassListBuilder
2056 typedef typename
A::P P
;
2058 objc_opt::string_map fClassNames
;
2059 objc_opt::class_map fClasses
;
2061 HeaderInfoOptimizer
<A
>& fHinfos
;
2065 ClassListBuilder(HeaderInfoOptimizer
<A
>& hinfos
)
2072 void visitClass(SharedCache
<A
>* cache
,
2073 const macho_header
<P
>* header
,
2074 objc_class_t
<A
>* cls
)
2076 if (cls
->isMetaClass(cache
)) return;
2078 const char *name
= cls
->getName(cache
);
2079 uint64_t name_vmaddr
= cache
->VMAddressForMappedAddress(name
);
2080 uint64_t cls_vmaddr
= cache
->VMAddressForMappedAddress(cls
);
2081 uint64_t hinfo_vmaddr
= cache
->VMAddressForMappedAddress(fHinfos
.hinfoForHeader(cache
, header
));
2082 fClassNames
.insert(objc_opt::string_map::value_type(name
, name_vmaddr
));
2083 fClasses
.insert(objc_opt::class_map::value_type(name
, std::pair
<uint64_t, uint64_t>(cls_vmaddr
, hinfo_vmaddr
)));
2087 objc_opt::string_map
& classNames() {
2091 objc_opt::class_map
& classes() {
2095 size_t count() const { return fCount
; }
2099 static int percent(size_t num
, size_t denom
) {
2100 if (denom
) return (int)(num
/ (double)denom
* 100);
2104 template <typename A
>
2105 void SharedCache
<A
>::optimizeObjC(std::vector
<void*>& pointersInData
)
2110 fprintf(stderr
, "update_dyld_shared_cache: for %s, optimizing objc metadata\n", archName());
2113 size_t headerSize
= P::round_up(sizeof(objc_opt::objc_opt_t
));
2114 if (headerSize
!= sizeof(objc_opt::objc_opt_t
)) {
2115 warn(archName(), "libobjc's optimization structure size is wrong (metadata not optimized)");
2118 // Find libobjc's empty sections to fill in
2119 const macho_section
<P
> *optROSection
= NULL
;
2120 const macho_section
<P
> *optRWSection
= NULL
;
2121 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2122 if ( strstr(it
->layout
->getFilePath(), "libobjc") != NULL
) {
2123 const macho_header
<P
>* mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2124 optROSection
= mh
->getSection("__TEXT", "__objc_opt_ro");
2125 optRWSection
= mh
->getSection("__DATA", "__objc_opt_rw");
2130 if ( optROSection
== NULL
) {
2131 warn(archName(), "libobjc's read-only section missing (metadata not optimized)");
2135 if ( optRWSection
== NULL
) {
2136 warn(archName(), "libobjc's read/write section missing (metadata not optimized)");
2140 uint8_t* optROData
= (uint8_t*)mappedAddressForVMAddress(optROSection
->addr());
2141 size_t optRORemaining
= optROSection
->size();
2143 uint8_t* optRWData
= (uint8_t*)mappedAddressForVMAddress(optRWSection
->addr());
2144 size_t optRWRemaining
= optRWSection
->size();
2146 if (optRORemaining
< headerSize
) {
2147 warn(archName(), "libobjc's read-only section is too small (metadata not optimized)");
2150 objc_opt::objc_opt_t
* optROHeader
= (objc_opt::objc_opt_t
*)optROData
;
2151 optROData
+= headerSize
;
2152 optRORemaining
-= headerSize
;
2154 if (E::get32(optROHeader
->version
) != objc_opt::VERSION
) {
2155 warn(archName(), "libobjc's read-only section version is unrecognized (metadata not optimized)");
2159 // Write nothing to optROHeader until everything else is written.
2160 // If something fails below, libobjc will not use the section.
2162 // Find objc-containing dylibs
2163 std::vector
<LayoutInfo
> objcDylibs
;
2164 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2165 macho_header
<P
> *mh
= (macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2166 if (mh
->getSection("__DATA", "__objc_imageinfo") || mh
->getSegment("__OBJC")) {
2167 objcDylibs
.push_back(*it
);
2173 // This is SAFE: the binaries themselves are unmodified.
2175 std::vector
<LayoutInfo
> addressSortedDylibs
= objcDylibs
;
2176 std::sort(addressSortedDylibs
.begin(), addressSortedDylibs
.end(), ByAddressSorter());
2178 uint64_t hinfoVMAddr
= optRWSection
->addr() + optRWSection
->size() - optRWRemaining
;
2179 HeaderInfoOptimizer
<A
> hinfoOptimizer
;
2180 err
= hinfoOptimizer
.init(objcDylibs
.size(), optRWData
, optRWRemaining
);
2182 warn(archName(), err
);
2185 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= addressSortedDylibs
.begin(); it
!= addressSortedDylibs
.end(); ++it
) {
2186 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2187 hinfoOptimizer
.update(this, mh
, pointersInData
);
2191 // Update selector references and build selector list
2193 // This is SAFE: if we run out of room for the selector table,
2194 // the modified binaries are still usable.
2196 // Heuristic: choose selectors from libraries with more cstring data first.
2197 // This tries to localize selector cstring memory.
2198 ObjCSelectorUniquer
<A
> uniq(this);
2199 std::vector
<LayoutInfo
> sizeSortedDylibs
= objcDylibs
;
2200 std::sort(sizeSortedDylibs
.begin(), sizeSortedDylibs
.end(), ByCStringSectionSizeSorter());
2202 SelectorOptimizer
<A
, ObjCSelectorUniquer
<A
> > selOptimizer(uniq
);
2203 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2204 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2205 LegacySelectorUpdater
<A
, ObjCSelectorUniquer
<A
> >::update(this, mh
, uniq
);
2206 selOptimizer
.optimize(this, mh
);
2209 uint64_t seloptVMAddr
= optROSection
->addr() + optROSection
->size() - optRORemaining
;
2210 objc_opt::objc_selopt_t
*selopt
= new(optROData
) objc_opt::objc_selopt_t
;
2211 err
= selopt
->write(seloptVMAddr
, optRORemaining
, uniq
.strings());
2213 warn(archName(), err
);
2216 optROData
+= selopt
->size();
2217 optRORemaining
-= selopt
->size();
2218 selopt
->byteswap(E::little_endian
), selopt
= NULL
;
2221 // Build class table.
2223 // This is SAFE: the binaries themselves are unmodified.
2225 ClassListBuilder
<A
> classes(hinfoOptimizer
);
2226 ClassWalker
< A
, ClassListBuilder
<A
> > classWalker(classes
);
2227 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2228 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2229 classWalker
.walk(this, mh
);
2232 uint64_t clsoptVMAddr
= optROSection
->addr() + optROSection
->size() - optRORemaining
;
2233 objc_opt::objc_clsopt_t
*clsopt
= new(optROData
) objc_opt::objc_clsopt_t
;
2234 err
= clsopt
->write(clsoptVMAddr
, optRORemaining
,
2235 classes
.classNames(), classes
.classes(), verbose
);
2237 warn(archName(), err
);
2240 optROData
+= clsopt
->size();
2241 optRORemaining
-= clsopt
->size();
2242 size_t duplicateCount
= clsopt
->duplicateCount();
2243 clsopt
->byteswap(E::little_endian
), clsopt
= NULL
;
2246 // Sort method lists.
2248 // This is SAFE: modified binaries are still usable as unsorted lists.
2249 // This must be done AFTER uniquing selectors.
2251 MethodListSorter
<A
> methodSorter
;
2252 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2253 macho_header
<P
> *mh
= (macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2254 methodSorter
.optimize(this, mh
);
2258 // Repair ivar offsets.
2260 // This is SAFE: the runtime always validates ivar offsets at runtime.
2262 IvarOffsetOptimizer
<A
> ivarOffsetOptimizer
;
2263 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2264 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2265 ivarOffsetOptimizer
.optimize(this, mh
);
2269 // Success. Mark dylibs as optimized.
2270 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2271 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2272 const macho_section
<P
> *imageInfoSection
;
2273 imageInfoSection
= mh
->getSection("__DATA", "__objc_imageinfo");
2274 if (!imageInfoSection
) {
2275 imageInfoSection
= mh
->getSection("__OBJC", "__image_info");
2277 if (imageInfoSection
) {
2278 objc_image_info
<A
> *info
= (objc_image_info
<A
> *)
2279 mappedAddressForVMAddress(imageInfoSection
->addr());
2280 info
->setOptimizedByDyld();
2285 // Success. Update RO header last.
2286 E::set32(optROHeader
->selopt_offset
, seloptVMAddr
- optROSection
->addr());
2287 E::set32(optROHeader
->clsopt_offset
, clsoptVMAddr
- optROSection
->addr());
2288 E::set32(optROHeader
->headeropt_offset
, hinfoVMAddr
- optROSection
->addr());
2291 size_t roSize
= optROSection
->size() - optRORemaining
;
2292 size_t rwSize
= optRWSection
->size() - optRWRemaining
;
2293 fprintf(stderr
, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
2294 "(%d%%) used in libobjc read-only optimization section\n",
2295 archName(), roSize
, optROSection
->size(),
2296 percent(roSize
, optROSection
->size()));
2297 fprintf(stderr
, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
2298 "(%d%%) used in libobjc read/write optimization section\n",
2299 archName(), rwSize
, optRWSection
->size(),
2300 percent(rwSize
, optRWSection
->size()));
2301 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2302 "uniqued %zu selectors\n",
2303 archName(), uniq
.strings().size());
2304 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2305 "updated %zu selector references\n",
2306 archName(), uniq
.count());
2307 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2308 "updated %zu ivar offsets\n",
2309 archName(), ivarOffsetOptimizer
.optimized());
2310 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2311 "sorted %zu method lists\n",
2312 archName(), methodSorter
.optimized());
2313 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2314 "recorded %zu classes (%zu duplicates)\n",
2315 archName(), classes
.classNames().size(), duplicateCount
);
2316 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2317 "wrote objc metadata optimization version %d\n",
2318 archName(), objc_opt::VERSION
);
2325 static const char* sCleanupFile
= NULL
;
2326 static void cleanup(int sig
)
2328 ::signal(sig
, SIG_DFL
);
2329 if ( sCleanupFile
!= NULL
)
2330 ::unlink(sCleanupFile
);
2332 // fprintf(stderr, "update_dyld_shared_cache: deleting temp file in response to a signal\n");
2333 if ( sig
== SIGINT
)
2338 // <rdar://problem/10730767> update_dyld_shared_cache should use sync_volume_np() instead of sync()
2339 static void sync_volume(const char* volumePath
)
2341 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
2342 int error
= sync_volume_np(volumePath
, SYNC_VOLUME_FULLSYNC
|SYNC_VOLUME_FULLSYNC
);
2344 int full_sync
= 3; // SYNC_VOLUME_FULLSYNC | SYNC_VOLUME_FULLSYNC
2346 if ( fsctl(volumePath
, 0x80004101 /*FSCTL_SYNC_VOLUME*/, &full_sync
, 0) == -1)
2354 // <rdar://problem/12552226> update shared cache should sign the shared cache
2355 static bool adhoc_codesign_share_cache(const char* path
)
2357 CFURLRef target
= ::CFURLCreateFromFileSystemRepresentation(NULL
, (const UInt8
*)path
, strlen(path
), FALSE
);
2358 if ( target
== NULL
)
2361 SecStaticCodeRef code
;
2362 OSStatus status
= ::SecStaticCodeCreateWithPath(target
, kSecCSDefaultFlags
, &code
);
2365 ::fprintf(stderr
, "codesign: failed to create url to signed object\n");
2369 const void * keys
[1] = { (void *)kSecCodeSignerIdentity
} ;
2370 const void * values
[1] = { (void *)kCFNull
};
2371 CFDictionaryRef params
= ::CFDictionaryCreate(NULL
, keys
, values
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2372 if ( params
== NULL
) {
2377 SecCodeSignerRef signer
;
2378 status
= ::SecCodeSignerCreate(params
, kSecCSDefaultFlags
, &signer
);
2382 ::fprintf(stderr
, "codesign: failed to create signer object\n");
2386 status
= ::SecCodeSignerAddSignatureWithErrors(signer
, code
, kSecCSDefaultFlags
, NULL
);
2390 ::fprintf(stderr
, "codesign: failed to sign object: %s\n", path
);
2395 ::fprintf(stderr
, "codesigning complete of %s\n", path
);
2402 template <> bool SharedCache
<x86_64
>::addCacheSlideInfo(){ return true; }
2403 template <> bool SharedCache
<arm
>::addCacheSlideInfo() { return true; }
2404 template <> bool SharedCache
<x86
>::addCacheSlideInfo() { return false; }
2408 template <typename A
>
2409 bool SharedCache
<A
>::update(bool force
, bool optimize
, bool deleteExistingFirst
, int archIndex
,
2410 int archCount
, bool keepSignatures
, bool dontMapLocalSymbols
)
2412 bool didUpdate
= false;
2414 // already up to date?
2415 if ( force
|| fExistingIsNotUpToDate
) {
2417 fprintf(stderr
, "update_dyld_shared_cache: regenerating %s\n", fCacheFilePath
);
2418 if ( fDylibs
.size() == 0 ) {
2419 fprintf(stderr
, "update_dyld_shared_cache: warning, empty cache not generated for arch %s\n", archName());
2422 // delete existing cache while building the new one
2423 // this is a flag to dyld to stop pinging update_dyld_shared_cache
2424 if ( deleteExistingFirst
)
2425 ::unlink(fCacheFilePath
);
2426 uint8_t* inMemoryCache
= NULL
;
2427 uint32_t allocatedCacheSize
= 0;
2428 char tempCachePath
[strlen(fCacheFilePath
)+16];
2429 sprintf(tempCachePath
, "%s.tmp%u", fCacheFilePath
, getpid());
2431 // allocate a memory block to hold cache
2432 uint32_t cacheFileSize
= 0;
2433 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
2434 uint32_t end
= it
->sfm_file_offset
+ it
->sfm_size
;
2435 if ( end
> cacheFileSize
)
2436 cacheFileSize
= end
;
2438 if ( vm_allocate(mach_task_self(), (vm_address_t
*)(&inMemoryCache
), cacheFileSize
, VM_FLAGS_ANYWHERE
) != KERN_SUCCESS
)
2439 throwf("can't vm_allocate cache of size %u", cacheFileSize
);
2440 allocatedCacheSize
= cacheFileSize
;
2441 fInMemoryCache
= inMemoryCache
;
2444 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2445 const char* archPairName
= fArchGraph
->archName();
2447 strcpy(temp
, "dyld_v1 ");
2448 strcpy(&temp
[15-strlen(archPairName
)], archPairName
);
2449 header
->set_magic(temp
);
2450 //header->set_architecture(arch());
2451 header
->set_mappingOffset(sizeof(dyldCacheHeader
<E
>));
2452 header
->set_mappingCount(fMappings
.size());
2453 header
->set_imagesOffset(header
->mappingOffset() + fMappings
.size()*sizeof(dyldCacheFileMapping
<E
>));
2454 header
->set_imagesCount(fDylibs
.size()+fDylibAliases
.size());
2455 header
->set_dyldBaseAddress(fDyldBaseAddress
);
2456 header
->set_codeSignatureOffset(cacheFileSize
);
2457 header
->set_codeSignatureSize(0);
2458 header
->set_slideInfoOffset(0);
2459 header
->set_slideInfoSize(0);
2460 header
->set_localSymbolsOffset(0);
2461 header
->set_localSymbolsSize(0);
2464 dyldCacheFileMapping
<E
>* mapping
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
2465 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
2467 fprintf(stderr
, "update_dyld_shared_cache: cache mappings: address=0x%0llX, size=0x%0llX, fileOffset=0x%0llX, prot=0x%X\n",
2468 it
->sfm_address
, it
->sfm_size
, it
->sfm_file_offset
, it
->sfm_init_prot
);
2469 mapping
->set_address(it
->sfm_address
);
2470 mapping
->set_size(it
->sfm_size
);
2471 mapping
->set_file_offset(it
->sfm_file_offset
);
2472 mapping
->set_max_prot(it
->sfm_max_prot
);
2473 mapping
->set_init_prot(it
->sfm_init_prot
);
2477 // fill in image table
2478 dyldCacheImageInfo
<E
>* image
= (dyldCacheImageInfo
<E
>*)mapping
;
2479 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2480 image
->set_address(it
->info
.address
);
2481 image
->set_modTime(it
->info
.modTime
);
2482 image
->set_inode(it
->info
.inode
);
2483 image
->set_pathFileOffset(cacheFileOffsetForVMAddress(it
->info
.address
+it
->info
.pathFileOffset
));
2487 // add aliases to end of image table
2488 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibAliases
.begin(); it
!= fDylibAliases
.end(); ++it
) {
2489 image
->set_address(it
->info
.address
);
2490 image
->set_modTime(it
->info
.modTime
);
2491 image
->set_inode(it
->info
.inode
);
2492 image
->set_pathFileOffset(it
->info
.pathFileOffset
);
2493 strcpy((char*)inMemoryCache
+it
->info
.pathFileOffset
, it
->aliases
[0]);
2494 //fprintf(stderr, "adding alias to offset 0x%08X %s\n", it->info.pathFileOffset, it->aliases[0]);
2498 // copy each segment to cache buffer
2499 const int dylibCount
= fDylibs
.size();
2501 int progressIndex
= 0;
2502 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++dylibIndex
) {
2503 const char* path
= it
->layout
->getFilePath();
2504 int src
= ::open(path
, O_RDONLY
, 0);
2506 throwf("can't open file %s, errnor=%d", it
->layout
->getID().name
, errno
);
2507 // mark source as "don't cache"
2508 (void)fcntl(src
, F_NOCACHE
, 1);
2509 // verify file has not changed since dependency analysis
2510 struct stat stat_buf
;
2511 if ( fstat(src
, &stat_buf
) == -1)
2512 throwf("can't stat open file %s, errno=%d", path
, errno
);
2513 if ( (it
->layout
->getInode() != stat_buf
.st_ino
) || (it
->layout
->getLastModTime() != stat_buf
.st_mtime
) )
2514 throwf("file modified during cache creation: %s", path
);
2517 fprintf(stderr
, "update_dyld_shared_cache: copying %s to cache\n", it
->layout
->getFilePath());
2519 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
2520 for (int i
=0; i
< segs
.size(); ++i
) {
2521 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
2523 fprintf(stderr
, "\t\tsegment %s, size=0x%0llX, cache address=0x%0llX\n", seg
.name(), seg
.fileSize(), seg
.newAddress());
2524 if ( seg
.size() > 0 ) {
2525 const uint64_t segmentSrcStartOffset
= it
->layout
->getOffsetInUniversalFile()+seg
.fileOffset();
2526 const uint64_t segmentSize
= seg
.fileSize();
2527 const uint64_t segmentDstStartOffset
= cacheFileOffsetForVMAddress(seg
.newAddress());
2528 ssize_t readResult
= ::pread(src
, &inMemoryCache
[segmentDstStartOffset
], segmentSize
, segmentSrcStartOffset
);
2529 if ( readResult
!= segmentSize
) {
2530 if ( readResult
== -1 )
2531 throwf("read failure copying dylib errno=%d for %s", errno
, it
->layout
->getID().name
);
2533 throwf("read failure copying dylib. Read of %lld bytes at file offset %lld returned %ld for %s",
2534 segmentSize
, segmentSrcStartOffset
, readResult
, it
->layout
->getID().name
);
2539 catch (const char* msg
) {
2540 throwf("%s while copying %s to shared cache", msg
, it
->layout
->getID().name
);
2544 // assuming read takes 40% of time
2545 int nextProgressIndex
= archIndex
*100+(40*dylibIndex
)/dylibCount
;
2546 if ( nextProgressIndex
!= progressIndex
)
2547 fprintf(stdout
, "%3u/%u\n", nextProgressIndex
, archCount
*100);
2548 progressIndex
= nextProgressIndex
;
2552 // set mapped address for each segment
2553 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2554 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
2555 for (int i
=0; i
< segs
.size(); ++i
) {
2556 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
2557 if ( seg
.size() > 0 )
2558 seg
.setMappedAddress(inMemoryCache
+ cacheFileOffsetForVMAddress(seg
.newAddress()));
2559 //fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
2563 // also construct list of all pointers in cache to other things in cache
2564 std::vector
<void*> pointersInData
;
2565 pointersInData
.reserve(1024);
2567 // rebase each dylib in shared cache
2568 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2570 Rebaser
<A
> r(*it
->layout
);
2571 r
.rebase(pointersInData
);
2573 // fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
2575 catch (const char* msg
) {
2576 throwf("%s in %s", msg
, it
->layout
->getID().name
);
2581 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs
.size());
2582 // instantiate a Binder for each image and add to map
2583 typename Binder
<A
>::Map map
;
2584 std::vector
<Binder
<A
>*> binders
;
2585 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2586 //fprintf(stderr, "binding %s\n", it->layout->getID().name);
2587 Binder
<A
>* binder
= new Binder
<A
>(*it
->layout
, fDyldBaseAddress
);
2588 binders
.push_back(binder
);
2589 // only add dylibs to map
2590 if ( it
->layout
->getID().name
!= NULL
)
2591 map
[it
->layout
->getID().name
] = binder
;
2594 // tell each Binder about the others
2595 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2596 (*it
)->setDependentBinders(map
);
2599 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2601 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it
)->getDylibID());
2603 (*it
)->bind(pointersInData
);
2605 catch (const char* msg
) {
2606 throwf("%s in %s", msg
, (*it
)->getDylibID());
2610 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2614 catch (const char* msg
) {
2615 throwf("%s in %s", msg
, (*it
)->getDylibID());
2619 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2623 // merge/optimize all LINKEDIT segments
2625 //fprintf(stderr, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize/(1024*1024));
2626 cacheFileSize
= (this->optimizeLINKEDIT(keepSignatures
, dontMapLocalSymbols
) - inMemoryCache
);
2627 //fprintf(stderr, "update_dyld_shared_cache: optimized cache file size %uMB\n", cacheFileSize/(1024*1024));
2628 // update header to reduce mapping size
2629 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2630 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
2631 dyldCacheFileMapping
<E
>* lastMapping
= &mappings
[cacheHeader
->mappingCount()-1];
2632 lastMapping
->set_size(cacheFileSize
-lastMapping
->file_offset());
2633 // update fMappings so .map file will print correctly
2634 fMappings
.back().sfm_size
= cacheFileSize
-fMappings
.back().sfm_file_offset
;
2636 //fprintf(stderr, "update_dyld_shared_cache: changing end of cache address from 0x%08llX to 0x%08llX\n",
2637 // header->codeSignatureOffset(), fMappings.back().sfm_address + fMappings.back().sfm_size);
2638 header
->set_codeSignatureOffset(fMappings
.back().sfm_file_offset
+ fMappings
.back().sfm_size
);
2641 // unique objc selectors and update other objc metadata
2643 optimizeObjC(pointersInData
);
2645 // assuming objc optimizations takes 15% of time
2646 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*55, archCount
*100);
2650 if ( addCacheSlideInfo() ) {
2651 // build bitmap of which pointers need sliding
2652 uint8_t* const dataStart
= &inMemoryCache
[fMappings
[1].sfm_file_offset
]; // R/W mapping is always second
2653 uint8_t* const dataEnd
= &inMemoryCache
[fMappings
[1].sfm_file_offset
+fMappings
[1].sfm_size
];
2654 const int bitmapSize
= (dataEnd
- dataStart
)/(4*8);
2655 uint8_t* bitmap
= (uint8_t*)calloc(bitmapSize
, 1);
2656 void* lastPointer
= inMemoryCache
;
2657 for(std::vector
<void*>::iterator pit
=pointersInData
.begin(); pit
!= pointersInData
.end(); ++pit
) {
2658 if ( *pit
!= lastPointer
) {
2660 if ( (p
< dataStart
) || ( p
> dataEnd
) )
2661 throwf("DATA pointer for sliding, out of range 0x%08lX\n", (long)((uint8_t*)p
-inMemoryCache
));
2662 long offset
= (long)((uint8_t*)p
- dataStart
);
2663 if ( (offset
% 4) != 0 )
2664 throwf("pointer not 4-byte aligned in DATA offset 0x%08lX\n", offset
);
2665 long byteIndex
= offset
/ (4*8);
2666 long bitInByte
= (offset
% 32) >> 2;
2667 bitmap
[byteIndex
] |= (1 << bitInByte
);
2672 // allocate worst case size block of all slide info
2673 const int entry_size
= 4096/(8*4); // 8 bits per byte, possible pointer every 4 bytes.
2674 const int toc_count
= bitmapSize
/entry_size
;
2675 int slideInfoSize
= sizeof(dyldCacheSlideInfo
<E
>) + 2*toc_count
+ entry_size
*(toc_count
+1);
2676 dyldCacheSlideInfo
<E
>* slideInfo
= (dyldCacheSlideInfo
<E
>*)calloc(slideInfoSize
, 1);
2677 slideInfo
->set_version(1);
2678 slideInfo
->set_toc_offset(sizeof(dyldCacheSlideInfo
<E
>));
2679 slideInfo
->set_toc_count(toc_count
);
2680 slideInfo
->set_entries_offset((slideInfo
->toc_offset()+2*toc_count
+127)&(-128));
2681 slideInfo
->set_entries_count(0);
2682 slideInfo
->set_entries_size(entry_size
);
2683 // append each unique entry
2684 const dyldCacheSlideInfoEntry
* bitmapAsEntries
= (dyldCacheSlideInfoEntry
*)bitmap
;
2685 dyldCacheSlideInfoEntry
* const entriesInSlidInfo
= (dyldCacheSlideInfoEntry
*)((char*)slideInfo
+slideInfo
->entries_offset());
2686 int entry_count
= 0;
2687 for (int i
=0; i
< toc_count
; ++i
) {
2688 const dyldCacheSlideInfoEntry
* thisEntry
= &bitmapAsEntries
[i
];
2689 // see if it is same as one already added
2691 for (int j
=0; j
< entry_count
; ++j
) {
2692 if ( memcmp(thisEntry
, &entriesInSlidInfo
[j
], entry_size
) == 0 ) {
2693 //fprintf(stderr, "toc[%d] optimized to %d\n", i, j);
2694 slideInfo
->set_toc(i
, j
);
2701 memcpy(&entriesInSlidInfo
[entry_count
], thisEntry
, entry_size
);
2702 slideInfo
->set_toc(i
, entry_count
++);
2705 slideInfo
->set_entries_count(entry_count
);
2707 int slideInfoPageSize
= pageAlign(slideInfo
->entries_offset() + entry_count
*entry_size
);
2708 cacheFileSize
+= slideInfoPageSize
;
2710 // update mappings to increase RO size
2711 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2712 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
2713 dyldCacheFileMapping
<E
>* lastMapping
= &mappings
[cacheHeader
->mappingCount()-1];
2714 lastMapping
->set_size(lastMapping
->size()+slideInfoPageSize
);
2716 // update header to show location of slidePointers
2717 cacheHeader
->set_slideInfoOffset(cacheHeader
->codeSignatureOffset());
2718 cacheHeader
->set_slideInfoSize(slideInfoPageSize
);
2719 cacheHeader
->set_codeSignatureOffset(cacheHeader
->codeSignatureOffset()+slideInfoPageSize
);
2721 // update fMappings so .map file will print correctly
2722 fMappings
.back().sfm_size
= cacheFileSize
-fMappings
.back().sfm_file_offset
;
2724 // copy compressed into into buffer
2725 memcpy(&inMemoryCache
[cacheHeader
->slideInfoOffset()], slideInfo
, slideInfoPageSize
);
2728 // make sure after all optimizations, that whole cache file fits into shared region address range
2730 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2731 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[cacheHeader
->mappingOffset()];
2732 for (int i
=0; i
< cacheHeader
->mappingCount(); ++i
) {
2733 uint64_t endAddr
= mappings
[i
].address() + mappings
[i
].size();
2734 if ( endAddr
> (sharedRegionStartAddress() + sharedRegionSize()) ) {
2735 throwf("update_dyld_shared_cache[%u] for arch=%s, shared cache will not fit in address space: 0x%llX\n",
2736 getpid(), fArchGraph
->archName(), endAddr
);
2741 // append local symbol info in an unmapped region
2742 if ( dontMapLocalSymbols
) {
2743 uint32_t spaceAtEnd
= allocatedCacheSize
- cacheFileSize
;
2744 uint32_t localSymbolsOffset
= pageAlign(cacheFileSize
);
2745 dyldCacheLocalSymbolsInfo
<E
>* infoHeader
= (dyldCacheLocalSymbolsInfo
<E
>*)(&inMemoryCache
[localSymbolsOffset
]);
2746 const uint32_t entriesOffset
= sizeof(dyldCacheLocalSymbolsInfo
<E
>);
2747 const uint32_t entriesCount
= fLocalSymbolInfos
.size();
2748 const uint32_t nlistOffset
= entriesOffset
+ entriesCount
* sizeof(dyldCacheLocalSymbolEntry
<E
>);
2749 const uint32_t nlistCount
= fUnmappedLocalSymbols
.size();
2750 const uint32_t stringsOffset
= nlistOffset
+ nlistCount
* sizeof(macho_nlist
<P
>);
2751 const uint32_t stringsSize
= fUnmappedLocalsStringPool
.size();
2752 if ( stringsOffset
+stringsSize
> spaceAtEnd
)
2753 throwf("update_dyld_shared_cache[%u] for arch=%s, out of space for local symbols. Have 0x%X, Need 0x%X\n",
2754 getpid(), fArchGraph
->archName(), spaceAtEnd
, stringsOffset
+stringsSize
);
2755 // fill in local symbols info
2756 infoHeader
->set_nlistOffset(nlistOffset
);
2757 infoHeader
->set_nlistCount(nlistCount
);
2758 infoHeader
->set_stringsOffset(stringsOffset
);
2759 infoHeader
->set_stringsSize(stringsSize
);
2760 infoHeader
->set_entriesOffset(entriesOffset
);
2761 infoHeader
->set_entriesCount(entriesCount
);
2762 // copy info for each dylib
2763 dyldCacheLocalSymbolEntry
<E
>* entries
= (dyldCacheLocalSymbolEntry
<E
>*)(&inMemoryCache
[localSymbolsOffset
+entriesOffset
]);
2764 for (int i
=0; i
< entriesCount
; ++i
) {
2765 entries
[i
].set_dylibOffset(fLocalSymbolInfos
[i
].dylibOffset
);
2766 entries
[i
].set_nlistStartIndex(fLocalSymbolInfos
[i
].nlistStartIndex
);
2767 entries
[i
].set_nlistCount(fLocalSymbolInfos
[i
].nlistCount
);
2770 memcpy(&inMemoryCache
[localSymbolsOffset
+nlistOffset
], &fUnmappedLocalSymbols
[0], nlistCount
*sizeof(macho_nlist
<P
>));
2772 memcpy(&inMemoryCache
[localSymbolsOffset
+stringsOffset
], fUnmappedLocalsStringPool
.getBuffer(), stringsSize
);
2775 fUnmappedLocalSymbolsSize
= pageAlign(stringsOffset
+ stringsSize
);
2776 cacheFileSize
= localSymbolsOffset
+ fUnmappedLocalSymbolsSize
;
2778 // update header to show location of slidePointers
2779 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2780 cacheHeader
->set_localSymbolsOffset(localSymbolsOffset
);
2781 cacheHeader
->set_localSymbolsSize(stringsOffset
+stringsSize
);
2782 cacheHeader
->set_codeSignatureOffset(cacheFileSize
);
2785 // compute UUID of whole cache
2787 CC_MD5(inMemoryCache
, cacheFileSize
, digest
);
2788 // <rdar://problem/6723729> uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
2789 digest
[6] = ( digest
[6] & 0x0F ) | ( 3 << 4 );
2790 digest
[8] = ( digest
[8] & 0x3F ) | 0x80;
2791 ((dyldCacheHeader
<E
>*)inMemoryCache
)->set_uuid(digest
);
2794 // if no existing cache, say so
2795 if ( fExistingCacheForVerification
== NULL
) {
2796 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
2797 getpid(), archName());
2799 // new cache is built, compare header entries
2800 const dyldCacheHeader
<E
>* newHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2801 const dyldCacheHeader
<E
>* oldHeader
= (dyldCacheHeader
<E
>*)fExistingCacheForVerification
;
2802 if ( newHeader
->mappingCount() != oldHeader
->mappingCount() ) {
2803 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because caches have a different number of mappings\n",
2804 getpid(), archName());
2806 const dyldCacheFileMapping
<E
>* newMappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[newHeader
->mappingOffset()];
2807 const dyldCacheFileMapping
<E
>* oldMappings
= (dyldCacheFileMapping
<E
>*)&fExistingCacheForVerification
[oldHeader
->mappingOffset()];
2808 for (int i
=0; i
< newHeader
->mappingCount(); ++i
) {
2809 if ( newMappings
[i
].address() != oldMappings
[i
].address() ) {
2810 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",
2811 getpid(), archName(), i
, newMappings
[i
].address(), oldMappings
[i
].address() );
2813 if ( newMappings
[i
].size() != oldMappings
[i
].size() ) {
2814 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because mapping %d has a different size\n",
2815 getpid(), archName(), i
);
2819 //fprintf(stderr, "%s existing cache = %p\n", archName(), fExistingCacheForVerification);
2820 //fprintf(stderr, "%s new cache = %p\n", archName(), inMemoryCache);
2821 // compare content to existing cache page by page
2822 for (int offset
=0; offset
< cacheFileSize
; offset
+= 4096) {
2823 if ( memcmp(&inMemoryCache
[offset
], &fExistingCacheForVerification
[offset
], 4096) != 0 ) {
2824 fprintf(stderr
, "verifier found differences on page offset 0x%08X for %s:\n", offset
, archName());
2825 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++dylibIndex
) {
2826 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
2827 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator sit
= segs
.begin(); sit
!= segs
.end(); ++sit
) {
2828 const MachOLayoutAbstraction::Segment
& seg
= *sit
;
2829 if ( (seg
.mappedAddress() <= &inMemoryCache
[offset
]) && (&inMemoryCache
[offset
] < ((uint8_t*)seg
.mappedAddress() + seg
.fileSize())) ) {
2830 // all LINKEDITs point to the same region, so just print one
2831 if ( strcmp(seg
.name(), "__LINKEDIT") == 0 )
2832 fprintf(stderr
, " in merged LINKEDIT segment\n");
2834 fprintf(stderr
, " in segment %s of dylib %s\n", seg
.name(), it
->layout
->getID().name
);
2839 for (int po
=0; po
< 4096; po
+= 16) {
2840 if ( memcmp(&inMemoryCache
[offset
+po
], &fExistingCacheForVerification
[offset
+po
], 16) != 0 ) {
2841 fprintf(stderr
, " existing: 0x%08X: ", offset
+po
);
2842 for ( int j
=0; j
< 16; ++j
)
2843 fprintf(stderr
, " 0x%02X", fExistingCacheForVerification
[offset
+po
+j
]);
2844 fprintf(stderr
, "\n");
2845 fprintf(stderr
, " should be: 0x%08X: ", offset
+po
);
2846 for ( int j
=0; j
< 16; ++j
)
2847 fprintf(stderr
, " 0x%02X", inMemoryCache
[offset
+po
+j
]);
2848 fprintf(stderr
, "\n");
2855 // install signal handlers to delete temp file if program is killed
2856 sCleanupFile
= tempCachePath
;
2857 ::signal(SIGINT
, cleanup
);
2858 ::signal(SIGBUS
, cleanup
);
2859 ::signal(SIGSEGV
, cleanup
);
2861 // create var/db/dyld dirs if needed
2862 char dyldDirs
[1024];
2863 strcpy(dyldDirs
, fCacheFilePath
);
2864 char* lastSlash
= strrchr(dyldDirs
, '/');
2865 if ( lastSlash
!= NULL
)
2866 lastSlash
[1] = '\0';
2867 struct stat stat_buf
;
2868 if ( stat(dyldDirs
, &stat_buf
) != 0 ) {
2869 const char* afterSlash
= &dyldDirs
[1];
2871 while ( (slash
= strchr(afterSlash
, '/')) != NULL
) {
2873 ::mkdir(dyldDirs
, S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
);
2875 afterSlash
= slash
+1;
2879 // create temp file for cache
2880 int fd
= ::open(tempCachePath
, O_CREAT
| O_RDWR
| O_TRUNC
, 0644);
2882 throwf("can't create temp file %s, errnor=%d", tempCachePath
, errno
);
2884 // try to allocate whole cache file contiguously
2885 fstore_t fcntlSpec
= { F_ALLOCATECONTIG
|F_ALLOCATEALL
, F_PEOFPOSMODE
, 0, cacheFileSize
, 0 };
2886 ::fcntl(fd
, F_PREALLOCATE
, &fcntlSpec
);
2888 // write out cache file
2890 fprintf(stderr
, "update_dyld_shared_cache: writing cache to disk: %s\n", tempCachePath
);
2891 if ( ::pwrite(fd
, inMemoryCache
, cacheFileSize
, 0) != cacheFileSize
)
2892 throwf("write() failure creating cache file, errno=%d", errno
);
2894 // assuming write takes 35% of time
2895 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*90, archCount
*100);
2898 // flush to disk and close
2899 int result
= ::fcntl(fd
, F_FULLFSYNC
, NULL
);
2901 fprintf(stderr
, "update_dyld_shared_cache: warning, fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno
, tempCachePath
);
2902 result
= ::close(fd
);
2904 fprintf(stderr
, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno
, tempCachePath
);
2907 adhoc_codesign_share_cache(tempCachePath
);
2909 // <rdar://problem/7901042> Make life easier for the kernel at shutdown.
2910 // If we just move the new cache file over the old, the old file
2911 // may need to exist in the open-unlink state. But because it
2912 // may be mapped into the shared region, it cannot be deleted
2913 // until all user processes are terminated. That leaves are
2914 // small to non-existent window for the kernel to delete the
2916 if ( fCacheFileInFinalLocation
) {
2917 char tmpDirPath
[64];
2918 const char* pathLastSlash
= strrchr(fCacheFilePath
, '/');
2919 if ( pathLastSlash
!= NULL
) {
2920 sprintf(tmpDirPath
, "/var/run%s.old.%u", pathLastSlash
, getpid());
2921 // move existing cache file to /var/run to be clean up next boot
2922 result
= ::rename(fCacheFilePath
, tmpDirPath
);
2923 if ( result
!= 0 ) {
2924 if ( errno
!= ENOENT
)
2925 fprintf(stderr
, "update_dyld_shared_cache: warning, unable to move existing cache to %s errno=%d for %s\n", tmpDirPath
, errno
, fCacheFilePath
);
2930 // move new cache file to correct location for use after reboot
2932 fprintf(stderr
, "update_dyld_shared_cache: atomically moving cache file into place: %s\n", fCacheFilePath
);
2933 result
= ::rename(tempCachePath
, fCacheFilePath
);
2935 throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath
, fCacheFilePath
, errno
);
2938 // flush everything to disk to assure rename() gets recorded
2939 sync_volume(fCacheFilePath
);
2942 // restore default signal handlers
2943 ::signal(SIGINT
, SIG_DFL
);
2944 ::signal(SIGBUS
, SIG_DFL
);
2945 ::signal(SIGSEGV
, SIG_DFL
);
2947 // generate human readable "map" file that shows the layout of the cache file
2949 fprintf(stderr
, "update_dyld_shared_cache: writing .map file to disk\n");
2950 char mapFilePath
[strlen(fCacheFilePath
)+16];
2951 sprintf(mapFilePath
, "%s.map", fCacheFilePath
);
2952 char tempMapFilePath
[strlen(fCacheFilePath
)+32];
2953 sprintf(tempMapFilePath
, "%s.map%u", fCacheFilePath
, getpid());
2954 FILE* fmap
= ::fopen(tempMapFilePath
, "w");
2955 if ( fmap
== NULL
) {
2956 fprintf(stderr
, "can't create map file %s, errnor=%d", tempCachePath
, errno
);
2959 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
2960 const char* prot
= "RW";
2961 if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_READ
) )
2963 else if ( it
->sfm_init_prot
== VM_PROT_READ
)
2965 else if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_WRITE
|VM_PROT_READ
) )
2967 if ( it
->sfm_size
> 1024*1024 )
2968 fprintf(fmap
, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/(1024*1024),
2969 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
2971 fprintf(fmap
, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/1024,
2972 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
2975 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX weak binding info\n",
2976 (fOffsetOfExportInfoInCombinedLinkedit
-fOffsetOfWeakBindInfoInCombinedLinkedit
)/1024,
2977 fLinkEditsStartAddress
+fOffsetOfWeakBindInfoInCombinedLinkedit
,
2978 fLinkEditsStartAddress
+fOffsetOfExportInfoInCombinedLinkedit
);
2979 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX export info\n",
2980 (fOffsetOfBindInfoInCombinedLinkedit
-fOffsetOfExportInfoInCombinedLinkedit
)/1024,
2981 fLinkEditsStartAddress
+fOffsetOfExportInfoInCombinedLinkedit
,
2982 fLinkEditsStartAddress
+fOffsetOfBindInfoInCombinedLinkedit
);
2983 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX binding info\n",
2984 (fOffsetOfLazyBindInfoInCombinedLinkedit
-fOffsetOfBindInfoInCombinedLinkedit
)/1024,
2985 fLinkEditsStartAddress
+fOffsetOfBindInfoInCombinedLinkedit
,
2986 fLinkEditsStartAddress
+fOffsetOfLazyBindInfoInCombinedLinkedit
);
2987 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX lazy binding info\n",
2988 (fOffsetOfOldSymbolTableInfoInCombinedLinkedit
-fOffsetOfLazyBindInfoInCombinedLinkedit
)/1024,
2989 fLinkEditsStartAddress
+fOffsetOfLazyBindInfoInCombinedLinkedit
,
2990 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
);
2991 fprintf(fmap
, " linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld symbol table size\n",
2992 (fSizeOfOldSymbolTableInfoInCombinedLinkedit
)/(1024*1024),
2993 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
,
2994 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
+fSizeOfOldSymbolTableInfoInCombinedLinkedit
);
2995 if ( fSizeOfFunctionStartsInCombinedLinkedit
!= 0 )
2996 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld functions starts size\n",
2997 fSizeOfFunctionStartsInCombinedLinkedit
/1024,
2998 fLinkEditsStartAddress
+fOffsetOfFunctionStartsInCombinedLinkedit
,
2999 fLinkEditsStartAddress
+fOffsetOfFunctionStartsInCombinedLinkedit
+fSizeOfFunctionStartsInCombinedLinkedit
);
3000 if ( fSizeOfDataInCodeInCombinedLinkedit
!= 0 )
3001 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld data-in-code info size\n",
3002 fSizeOfDataInCodeInCombinedLinkedit
/1024,
3003 fLinkEditsStartAddress
+fOffsetOfDataInCodeInCombinedLinkedit
,
3004 fLinkEditsStartAddress
+fOffsetOfDataInCodeInCombinedLinkedit
+fSizeOfDataInCodeInCombinedLinkedit
);
3005 if ( fSizeOfOldExternalRelocationsInCombinedLinkedit
!= 0 )
3006 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld external relocs size\n",
3007 fSizeOfOldExternalRelocationsInCombinedLinkedit
/1024,
3008 fLinkEditsStartAddress
+fOffsetOfOldExternalRelocationsInCombinedLinkedit
,
3009 fLinkEditsStartAddress
+fOffsetOfOldExternalRelocationsInCombinedLinkedit
+fSizeOfOldExternalRelocationsInCombinedLinkedit
);
3010 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld indirect symbol table size\n",
3011 fSizeOfOldIndirectSymbolsInCombinedLinkedit
/1024,
3012 fLinkEditsStartAddress
+fOffsetOfOldIndirectSymbolsInCombinedLinkedit
,
3013 fLinkEditsStartAddress
+fOffsetOfOldIndirectSymbolsInCombinedLinkedit
+fSizeOfOldIndirectSymbolsInCombinedLinkedit
);
3014 fprintf(fmap
, " linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld string pool\n",
3015 (fSizeOfOldStringPoolInCombinedLinkedit
)/(1024*1024),
3016 fLinkEditsStartAddress
+fOffsetOfOldStringPoolInCombinedLinkedit
,
3017 fLinkEditsStartAddress
+fOffsetOfOldStringPoolInCombinedLinkedit
+fSizeOfOldStringPoolInCombinedLinkedit
);
3019 fprintf(fmap
, "unmapped -- %4uMB local symbol info\n", fUnmappedLocalSymbolsSize
/(1024*1024));
3021 uint64_t endMappingAddr
= fMappings
[2].sfm_address
+ fMappings
[2].sfm_size
;
3022 fprintf(fmap
, "total map %4lluMB\n", (endMappingAddr
- sharedRegionStartAddress())/(1024*1024));
3023 if ( sharedRegionStartWritableAddress(0) == 0x7FFF70000000LL
) {
3024 // x86_64 has different slide constraints
3025 uint64_t freeSpace
= 256*1024*1024 - fMappings
[1].sfm_size
;
3026 fprintf(fmap
, "r/w space %4lluMB -> %d bits of entropy for ASLR\n\n", freeSpace
/(1024*1024), (int)log2(freeSpace
/4096));
3029 uint64_t freeSpace
= sharedRegionStartAddress() + sharedRegionSize() - endMappingAddr
;
3030 fprintf(fmap
, "free space %4lluMB -> %d bits of entropy for ASLR\n\n", freeSpace
/(1024*1024), (int)log2(freeSpace
/4096));
3033 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
3034 fprintf(fmap
, "%s\n", it
->layout
->getID().name
);
3035 for (std::vector
<const char*>::const_iterator ait
= it
->aliases
.begin(); ait
!= it
->aliases
.end(); ++ait
)
3036 fprintf(fmap
, "%s\n", *ait
);
3037 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
3038 for (int i
=0; i
< segs
.size(); ++i
) {
3039 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
3040 fprintf(fmap
, "\t%16s 0x%0llX -> 0x%0llX\n", seg
.name(), seg
.newAddress(), seg
.newAddress()+seg
.size());
3043 if ( warnings
.size() > 0 ) {
3044 fprintf(fmap
, "# Warnings:\n");
3045 for (std::vector
<const char*>::iterator it
=warnings
.begin(); it
!= warnings
.end(); ++it
) {
3046 fprintf(fmap
, "# %s\n", *it
);
3050 result
= ::rename(tempMapFilePath
, mapFilePath
);
3054 // free in memory cache
3055 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
3056 inMemoryCache
= NULL
;
3059 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*100, archCount
*100);
3063 // remove temp cache file
3064 ::unlink(tempCachePath
);
3065 // remove in memory cache
3066 if ( inMemoryCache
!= NULL
)
3067 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
3077 // The shared cache is driven by /var/db/dyld/shared_region_roots which contains
3078 // the paths used to search for dylibs that should go in the shared cache
3080 // Leading and trailing white space is ignored
3081 // Blank lines are ignored
3082 // Lines starting with # are ignored
3084 static void parsePathsFile(const char* filePath
, std::vector
<const char*>& paths
)
3086 // read in whole file
3087 int fd
= open(filePath
, O_RDONLY
, 0);
3089 fprintf(stderr
, "update_dyld_shared_cache: can't open file: %s\n", filePath
);
3092 struct stat stat_buf
;
3093 fstat(fd
, &stat_buf
);
3094 char* p
= (char*)malloc(stat_buf
.st_size
);
3096 fprintf(stderr
, "update_dyld_shared_cache: malloc failure\n");
3099 if ( read(fd
, p
, stat_buf
.st_size
) != stat_buf
.st_size
) {
3100 fprintf(stderr
, "update_dyld_shared_cache: can't read file: %s\n", filePath
);
3105 // parse into paths and add to vector
3106 char * const end
= &p
[stat_buf
.st_size
];
3107 enum { lineStart
, inSymbol
, inComment
} state
= lineStart
;
3108 char* symbolStart
= NULL
;
3109 for (char* s
= p
; s
< end
; ++s
) {
3115 else if ( !isspace(*s
) ) {
3123 // removing any trailing spaces
3125 while ( isspace(*last
) ) {
3129 // <rdar://problem/8305479> images in shared cache are bound against different IOKit than found at runtime
3130 // HACK: Just ignore the known bad IOKit
3131 if ( strcmp(symbolStart
, "/System/Library/Frameworks/IOKit.framework/IOKit") == 0 ) {
3132 // Disable warning because after three years <rdar://problem/7089957> has still not been fixed...
3133 //fprintf(stderr, "update_dyld_shared_cache: warning, ignoring /System/Library/Frameworks/IOKit.framework/IOKit\n");
3134 //warnings.push_back("update_dyld_shared_cache: warning, ignoring /System/Library/Frameworks/IOKit.framework/IOKit\n");
3137 paths
.push_back(symbolStart
);
3149 // Note: we do not free() the malloc buffer, because the strings in it are used by exec()
3154 static void setSharedDylibs(const char* rootPath
, const char* overlayPath
, const std::set
<ArchPair
>& onlyArchs
, std::vector
<const char*> rootsPaths
)
3156 // set file system root
3157 ArchGraph::setFileSystemRoot(rootPath
);
3158 ArchGraph::setFileSystemOverlay(overlayPath
);
3160 // initialize all architectures requested
3161 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
3162 ArchGraph::addArchPair(*a
);
3164 // add roots to graph
3165 for(std::vector
<const char*>::const_iterator it
= rootsPaths
.begin(); it
!= rootsPaths
.end(); ++it
)
3166 ArchGraph::addRoot(*it
, onlyArchs
);
3168 // determine shared dylibs
3169 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
3170 ArchGraph::findSharedDylibs(*a
);
3174 static void scanForSharedDylibs(const char* rootPath
, const char* overlayPath
, const char* dirOfPathFiles
, const std::set
<ArchPair
>& onlyArchs
)
3176 char rootDirOfPathFiles
[strlen(rootPath
)+strlen(dirOfPathFiles
)+2];
3177 // in -root mode, look for roots in /rootpath/var/db/dyld
3178 if ( rootPath
[0] != '\0' ) {
3179 strcpy(rootDirOfPathFiles
, rootPath
);
3180 strcat(rootDirOfPathFiles
, dirOfPathFiles
);
3181 dirOfPathFiles
= rootDirOfPathFiles
;
3184 // extract all root paths from files in "/var/db/dyld/shared_region_roots/"
3186 fprintf(stderr
, "update_dyld_shared_cache: finding roots in: %s\n", dirOfPathFiles
);
3187 std::vector
<const char*> rootsPaths
;
3188 DIR* dir
= ::opendir(dirOfPathFiles
);
3190 throwf("%s does not exist, errno=%d\n", dirOfPathFiles
, errno
);
3191 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
3192 if ( entry
->d_type
== DT_REG
|| entry
->d_type
== DT_UNKNOWN
) {
3193 // only look at regular files ending in .paths
3194 if ( strcmp(&entry
->d_name
[entry
->d_namlen
-6], ".paths") == 0 ) {
3195 struct stat tmpStatPathsFile
;
3196 char fullPath
[strlen(dirOfPathFiles
)+entry
->d_namlen
+2];
3197 strcpy(fullPath
, dirOfPathFiles
);
3198 strcat(fullPath
, "/");
3199 strcat(fullPath
, entry
->d_name
);
3200 if ( lstat(fullPath
, &tmpStatPathsFile
) == -1 ) {
3201 fprintf(stderr
, "update_dyld_shared_cache: can't access %s\n", fullPath
);
3203 else if ( S_ISREG(tmpStatPathsFile
.st_mode
) ) {
3204 parsePathsFile(fullPath
, rootsPaths
);
3207 fprintf(stderr
, "update_dyld_shared_cache: wrong file type for %s\n", fullPath
);
3211 fprintf(stderr
, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry
->d_name
);
3217 if ( rootsPaths
.size() == 0 )
3218 fprintf(stderr
, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
3219 setSharedDylibs(rootPath
, overlayPath
, onlyArchs
, rootsPaths
);
3222 static void setSharedDylibs(const char* rootPath
, const char* overlayPath
, const char* pathsFile
, const std::set
<ArchPair
>& onlyArchs
)
3224 std::vector
<const char*> rootsPaths
;
3225 parsePathsFile(pathsFile
, rootsPaths
);
3226 setSharedDylibs(rootPath
, overlayPath
, onlyArchs
, rootsPaths
);
3230 // If the 10.5.0 version of update_dyld_shared_cache was killed or crashed, it
3231 // could leave large half written cache files laying around. The function deletes
3232 // those files. To prevent the deletion of tmp files being created by another
3233 // copy of update_dyld_shared_cache, it only deletes the temp cache file if its
3234 // creation time was before the last restart of this machine.
3235 static void deleteOrphanTempCacheFiles()
3237 DIR* dir
= ::opendir(MACOSX_DYLD_SHARED_CACHE_DIR
);
3238 if ( dir
!= NULL
) {
3239 std::vector
<const char*> filesToDelete
;
3240 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
3241 if ( entry
->d_type
== DT_REG
) {
3242 // only look at files with .tmp in name
3243 if ( strstr(entry
->d_name
, ".tmp") != NULL
) {
3244 char fullPath
[strlen(MACOSX_DYLD_SHARED_CACHE_DIR
)+entry
->d_namlen
+2];
3245 strcpy(fullPath
, MACOSX_DYLD_SHARED_CACHE_DIR
);
3246 strcat(fullPath
, "/");
3247 strcat(fullPath
, entry
->d_name
);
3248 struct stat tmpFileStatInfo
;
3249 if ( stat(fullPath
, &tmpFileStatInfo
) != -1 ) {
3250 int mib
[2] = {CTL_KERN
, KERN_BOOTTIME
};
3251 struct timeval boottime
;
3252 size_t size
= sizeof(boottime
);
3253 if ( (sysctl(mib
, 2, &boottime
, &size
, NULL
, 0) != -1) && (boottime
.tv_sec
!= 0) ) {
3254 // make sure this file is older than the boot time of this machine
3255 if ( tmpFileStatInfo
.st_mtime
< boottime
.tv_sec
) {
3256 filesToDelete
.push_back(strdup(fullPath
));
3264 for(std::vector
<const char*>::iterator it
= filesToDelete
.begin(); it
!= filesToDelete
.end(); ++it
) {
3265 fprintf(stderr
, "update_dyld_shared_cache: deleting old temp cache file: %s\n", *it
);
3273 static bool updateSharedeCacheFile(const char* rootPath
, const char* overlayPath
, const char* cacheDir
, bool explicitCacheDir
, const std::set
<ArchPair
>& onlyArchs
,
3274 bool force
, bool alphaSort
, bool optimize
, bool deleteExistingFirst
, bool verify
, bool keepSignatures
, bool dontMapLocalSymbols
)
3276 bool didUpdate
= false;
3277 // get dyld load address info
3278 UniversalMachOLayout
* dyldLayout
= NULL
;
3279 char dyldPath
[1024];
3280 strlcpy(dyldPath
, rootPath
, 1024);
3281 strlcat(dyldPath
, "/usr/lib/dyld", 1024);
3282 struct stat stat_buf
;
3283 if ( stat(dyldPath
, &stat_buf
) == 0 ) {
3284 dyldLayout
= new UniversalMachOLayout(dyldPath
, &onlyArchs
);
3287 dyldLayout
= new UniversalMachOLayout("/usr/lib/dyld", &onlyArchs
);
3289 const int archCount
= onlyArchs
.size();
3291 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
, ++index
) {
3292 const MachOLayoutAbstraction
* dyldLayoutForArch
= dyldLayout
->getSlice(*a
);
3293 uint64_t dyldBaseAddress
= 0;
3294 if ( dyldLayoutForArch
!= NULL
)
3295 dyldBaseAddress
= dyldLayoutForArch
->getBaseAddress();
3297 fprintf(stderr
, "update_dyld_shared_cache: warning, dyld not available for specified architectures\n");
3298 switch ( a
->arch
) {
3301 SharedCache
<x86
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, overlayPath
, cacheDir
, explicitCacheDir
, alphaSort
, verify
, optimize
, dyldBaseAddress
);
3302 didUpdate
|= cache
.update(force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
, dontMapLocalSymbols
);
3305 case CPU_TYPE_X86_64
:
3307 SharedCache
<x86_64
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, overlayPath
, cacheDir
, explicitCacheDir
, alphaSort
, verify
, optimize
, dyldBaseAddress
);
3308 didUpdate
|= cache
.update(force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
, dontMapLocalSymbols
);
3313 SharedCache
<arm
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, overlayPath
, cacheDir
, explicitCacheDir
, alphaSort
, verify
, optimize
, dyldBaseAddress
);
3314 didUpdate
|= cache
.update(force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
, dontMapLocalSymbols
);
3321 deleteOrphanTempCacheFiles();
3329 fprintf(stderr
, "update_dyld_shared_cache [-force] [-root dir] [-overlay dir] [-arch arch] [-debug]\n");
3333 int main(int argc
, const char* argv
[])
3335 std::set
<ArchPair
> onlyArchs
;
3336 const char* rootPath
= "";
3337 const char* overlayPath
= "";
3338 const char* dylibListFile
= NULL
;
3340 bool alphaSort
= false;
3341 bool optimize
= true;
3342 bool verify
= false;
3343 bool keepSignatures
= false;
3344 bool explicitCacheDir
= false;
3345 bool dontMapLocalSymbols
= false;
3346 const char* cacheDir
= NULL
;
3349 // parse command line options
3350 for(int i
=1; i
< argc
; ++i
) {
3351 const char* arg
= argv
[i
];
3352 if ( arg
[0] == '-' ) {
3353 if ( strcmp(arg
, "-debug") == 0 ) {
3356 else if ( strcmp(arg
, "-force") == 0 ) {
3359 else if ( strcmp(arg
, "-verify") == 0 ) {
3362 else if ( strcmp(arg
, "-sort_by_name") == 0 ) {
3365 else if ( strcmp(arg
, "-progress") == 0 ) {
3368 else if ( strcmp(arg
, "-opt") == 0 ) {
3371 else if ( strcmp(arg
, "-no_opt") == 0 ) {
3374 else if ( strcmp(arg
, "-dont_map_local_symbols") == 0 ) {
3375 dontMapLocalSymbols
= true;
3377 else if ( strcmp(arg
, "-iPhone") == 0 ) {
3381 else if ( strcmp(arg
, "-dylib_list") == 0 ) {
3382 dylibListFile
= argv
[++i
];
3383 if ( dylibListFile
== NULL
)
3384 throw "-dylib_list missing path argument";
3386 else if ( (strcmp(arg
, "-root") == 0) || (strcmp(arg
, "--root") == 0) ) {
3387 rootPath
= argv
[++i
];
3388 if ( rootPath
== NULL
)
3389 throw "-root missing path argument";
3391 else if ( strcmp(arg
, "-overlay") == 0 ) {
3392 overlayPath
= argv
[++i
];
3393 if ( overlayPath
== NULL
)
3394 throw "-overlay missing path argument";
3396 else if ( strcmp(arg
, "-cache_dir") == 0 ) {
3397 cacheDir
= argv
[++i
];
3398 if ( cacheDir
== NULL
)
3399 throw "-cache_dir missing path argument";
3400 explicitCacheDir
= true;
3402 else if ( strcmp(arg
, "-arch") == 0 ) {
3403 const char* arch
= argv
[++i
];
3404 if ( strcmp(arch
, "i386") == 0 )
3405 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3406 else if ( strcmp(arch
, "x86_64") == 0 )
3407 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
3408 else if ( strcmp(arch
, "armv4t") == 0 )
3409 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V4T
));
3410 else if ( strcmp(arch
, "armv5") == 0 )
3411 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V5TEJ
));
3412 else if ( strcmp(arch
, "armv6") == 0 )
3413 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V6
));
3414 else if ( strcmp(arch
, "armv7") == 0 )
3415 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7
));
3416 else if ( strcmp(arch
, "armv7f") == 0 )
3417 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7F
));
3418 else if ( strcmp(arch
, "armv7k") == 0 )
3419 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7K
));
3420 else if ( strcmp(arch
, "armv7s") == 0 )
3421 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7S
));
3423 throwf("unknown architecture %s", arch
);
3425 else if ( strcmp(arg
, "-universal_boot") == 0 ) {
3426 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
3427 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3431 throwf("unknown option: %s\n", arg
);
3436 throwf("unknown option: %s\n", arg
);
3440 // strip tailing slashes on -root
3441 // make it a real path so as to not make all dylibs look like symlink aliases
3442 if ( rootPath
[0] != '\0' ) {
3443 char realRootPath
[MAXPATHLEN
];
3444 if ( realpath(rootPath
, realRootPath
) == NULL
)
3445 throwf("realpath() failed on %s\n", rootPath
);
3446 rootPath
= strdup(realRootPath
);
3449 // strip tailing slashes on -overlay
3450 if ( overlayPath
[0] != '\0' ) {
3451 char realOverlayPath
[MAXPATHLEN
];
3452 if ( realpath(overlayPath
, realOverlayPath
) == NULL
)
3453 throwf("realpath() failed on %s\n", overlayPath
);
3454 overlayPath
= strdup(realOverlayPath
);
3457 // set default location to write cache dir
3458 if ( cacheDir
== NULL
)
3459 cacheDir
= (iPhoneOS
? IPHONE_DYLD_SHARED_CACHE_DIR
: MACOSX_DYLD_SHARED_CACHE_DIR
);
3461 // if no restrictions specified, use architectures that work on this machine
3462 if ( onlyArchs
.size() == 0 ) {
3464 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V6
));
3465 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7
));
3469 size_t len
= sizeof(int);
3470 #if __i386__ || __x86_64__
3471 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3472 // check system is capable of running 64-bit programs
3473 if ( (sysctlbyname("hw.optional.x86_64", &available
, &len
, NULL
, 0) == 0) && available
)
3474 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
3476 #error unsupported architecture
3481 if ( !verify
&& (geteuid() != 0) )
3482 throw "you must be root to run this tool";
3484 // build list of shared dylibs
3485 if ( dylibListFile
!= NULL
)
3486 setSharedDylibs(rootPath
, overlayPath
, dylibListFile
, onlyArchs
);
3488 scanForSharedDylibs(rootPath
, overlayPath
, "/var/db/dyld/shared_region_roots/", onlyArchs
);
3489 bool didUpdate
= updateSharedeCacheFile(rootPath
, overlayPath
, cacheDir
, explicitCacheDir
, onlyArchs
, force
, alphaSort
, optimize
,
3490 false, verify
, keepSignatures
, dontMapLocalSymbols
);
3492 if ( didUpdate
&& !iPhoneOS
) {
3493 void* handle
= dlopen("/usr/lib/libspindump.dylib", RTLD_LAZY
);
3494 if ( handle
!= NULL
) {
3495 typedef bool (*dscsym_proc_t
)(const char *root
);
3496 dscsym_proc_t proc
= (dscsym_proc_t
)dlsym(handle
, "dscsym_save_nuggets_for_current_caches");
3497 const char* nuggetRootPath
= "/";
3498 if ( overlayPath
[0] != '\0' )
3499 nuggetRootPath
= overlayPath
;
3500 else if ( rootPath
[0] != '\0' )
3501 nuggetRootPath
= rootPath
;
3502 (*proc
)(nuggetRootPath
);
3507 catch (const char* msg
) {
3508 fprintf(stderr
, "update_dyld_shared_cache failed: %s\n", msg
);