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 0x10000
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 bool rootless
= true;
81 static std::vector
<const char*> warnings
;
84 static void warn(const char *arch
, const char *format
, ...)
89 va_start(args
, format
);
90 ::vasprintf(&msg
, format
, args
);
93 warnings
.push_back(msg
);
96 ::fprintf(::stderr
, "update_dyld_shared_cache: warning: %s%s%s%s\n",
97 arch
? "for arch " : "",
107 size_t operator()(const char* __s
) const {
110 __h
= 5 * __h
+ *__s
;
117 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
125 typedef std::unordered_map
<const char*, const char*, CStringHash
, CStringEquals
> StringToString
;
127 static void addArchPair(ArchPair ap
);
128 static void addRoot(const char* vpath
, const std::set
<ArchPair
>& archs
);
129 static uint64_t maxCacheSizeForArchPair(ArchPair ap
);
130 static void findSharedDylibs(ArchPair ap
);
131 static ArchGraph
* graphForArchPair(ArchPair ap
) { return fgPerArchGraph
[ap
]; }
132 static void setFileSystemRoot(const char* root
) { fgFileSystemRoot
= root
; }
133 static void setFileSystemOverlay(const std::vector
<const char*>& overlays
);
134 static const char* archName(ArchPair ap
);
136 ArchPair
getArchPair() { return fArchPair
; }
137 std::set
<const class MachOLayoutAbstraction
*>& getSharedDylibs() { return fSharedDylibs
; }
138 StringToString
& getDylibAliases() { return fAliasesMap
; }
139 const char* archName() { return archName(fArchPair
); }
146 DependencyNode(ArchGraph
*, const char* path
, const MachOLayoutAbstraction
* layout
);
147 void loadDependencies(const MachOLayoutAbstraction
*);
148 void markNeededByRoot(DependencyNode
*);
149 const char* getPath() const { return fPath
; }
150 const MachOLayoutAbstraction
* getLayout() const { return fLayout
; }
151 size_t useCount() const { return fRootsDependentOnThis
.size(); }
152 bool allDependentsFound() const { return !fDependentMissing
; }
153 bool dependsOnDylibList() const { return fRootsDependentOnThis
.count(const_cast<DependencyNode
*>(this)); }
158 const MachOLayoutAbstraction
* fLayout
;
159 bool fDependenciesLoaded
;
160 bool fDependentMissing
;
161 std::set
<DependencyNode
*> fDependsOn
;
162 std::set
<DependencyNode
*> fRootsDependentOnThis
;
165 typedef std::unordered_map
<const char*, class DependencyNode
*, CStringHash
, CStringEquals
> PathToNode
;
168 ArchGraph(ArchPair ap
) : fArchPair(ap
) {}
169 void addRoot(const char* path
, const MachOLayoutAbstraction
*);
170 DependencyNode
* getNode(const char* path
);
171 DependencyNode
* getNodeForVirtualPath(const char* vpath
);
172 static bool canBeShared(const MachOLayoutAbstraction
* layout
, ArchPair ap
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
);
173 static bool sharable(const MachOLayoutAbstraction
* layout
, ArchPair ap
, char** msg
);
175 static std::map
<ArchPair
, ArchGraph
*> fgPerArchGraph
;
176 static const char* fgFileSystemRoot
;
177 static std::vector
<const char*> fgFileSystemOverlays
;
180 std::set
<DependencyNode
*> fRoots
;
182 std::set
<const MachOLayoutAbstraction
*> fSharedDylibs
; // use set to avoid duplicates when installname!=realpath
183 StringToString fAliasesMap
;
185 std::map
<ArchPair
, ArchGraph
*> ArchGraph::fgPerArchGraph
;
186 const char* ArchGraph::fgFileSystemRoot
= "";
187 std::vector
<const char*> ArchGraph::fgFileSystemOverlays
;
189 void ArchGraph::addArchPair(ArchPair ap
)
191 //fprintf(stderr, "adding ArchPair 0x%08X,0x%08X\n", ap.arch, ap.subtype);
192 fgPerArchGraph
[ap
] = new ArchGraph(ap
);
195 void ArchGraph::setFileSystemOverlay(const std::vector
<const char*>& overlays
)
197 for (std::vector
<const char*>::const_iterator it
=overlays
.begin(); it
!= overlays
.end(); ++it
)
198 fgFileSystemOverlays
.push_back(*it
);
201 void ArchGraph::addRoot(const char* vpath
, const std::set
<ArchPair
>& onlyArchs
)
203 //fprintf(stderr, "addRoot(%s)\n", vpath);
204 char completePath
[MAXPATHLEN
];
205 const char* path
= NULL
;
206 // check -overlay path first
207 for (std::vector
<const char*>::const_iterator it
=fgFileSystemOverlays
.begin(); it
!= fgFileSystemOverlays
.end(); ++it
) {
208 strcpy(completePath
, *it
);
209 strcat(completePath
, vpath
); // assumes vpath starts with '/'
210 struct stat stat_buf
;
211 if ( stat(completePath
, &stat_buf
) == 0 ) {
216 // if not found in overlay, check for -root
217 if ( (path
== NULL
) && (fgFileSystemRoot
[0] != '\0') ) {
218 strcpy(completePath
, fgFileSystemRoot
);
219 strcat(completePath
, vpath
); // assumes vpath starts with '/'
220 struct stat stat_buf
;
221 if ( stat(completePath
, &stat_buf
) == 0 )
228 //fprintf(stderr, " UniversalMachOLayout::find(%s)\n", path);
229 const UniversalMachOLayout
& uni
= UniversalMachOLayout::find(path
, &onlyArchs
);
230 for(std::set
<ArchPair
>::iterator ait
= onlyArchs
.begin(); ait
!= onlyArchs
.end(); ++ait
) {
232 const MachOLayoutAbstraction
* layout
= uni
.getSlice(*ait
);
233 if ( layout
!= NULL
)
234 fgPerArchGraph
[*ait
]->addRoot(path
, layout
);
236 catch (const char* msg
) {
238 fprintf(stderr
, "update_dyld_shared_cache: warning for %s can't use root '%s': %s\n", fgPerArchGraph
[*ait
]->archName(), path
, msg
);
243 catch (const char* msg
) {
244 fprintf(stderr
, "update_dyld_shared_cache: warning can't use root '%s': %s\n", path
, msg
);
250 void ArchGraph::addRoot(const char* path
, const MachOLayoutAbstraction
* layout
)
253 fprintf(stderr
, "update_dyld_shared_cache: adding root: %s\n", path
);
254 DependencyNode
* node
= this->getNode(path
);
256 const MachOLayoutAbstraction
* mainExecutableLayout
= NULL
;
257 if ( layout
->getFileType() == MH_EXECUTE
)
258 mainExecutableLayout
= layout
;
259 node
->loadDependencies(mainExecutableLayout
);
260 node
->markNeededByRoot(node
);
261 if ( layout
->getFileType() == MH_DYLIB
)
262 node
->markNeededByRoot(NULL
);
265 // a virtual path does not have the fgFileSystemRoot prefix
266 ArchGraph::DependencyNode
* ArchGraph::getNodeForVirtualPath(const char* vpath
)
268 //fprintf(stderr, "getNodeForVirtualPath(%s)\n", vpath);
269 char completePath
[MAXPATHLEN
];
270 for (std::vector
<const char*>::const_iterator it
=fgFileSystemOverlays
.begin(); it
!= fgFileSystemOverlays
.end(); ++it
) {
271 const char* overlayPath
= *it
;
272 // using -overlay means if /overlay/path/dylib exists use it, otherwise use /path/dylib
273 strcpy(completePath
, overlayPath
);
274 strcat(completePath
, vpath
); // assumes vpath starts with '/'
275 struct stat stat_buf
;
276 if ( stat(completePath
, &stat_buf
) == 0 ) {
277 return this->getNode(completePath
);
279 // <rdar://problem/9279770> support when install name is a symlink
280 const char* pathToSymlink
= vpath
;
281 if ( fgFileSystemRoot
[0] != '\0' ) {
282 strcpy(completePath
, fgFileSystemRoot
);
283 strcat(completePath
, vpath
);
284 pathToSymlink
= completePath
;
286 if ( (lstat(pathToSymlink
, &stat_buf
) == 0) && S_ISLNK(stat_buf
.st_mode
) ) {
287 // requested path did not exist in /overlay, but leaf of path is a symlink in /
288 char pathInSymLink
[MAXPATHLEN
];
289 size_t res
= readlink(pathToSymlink
, pathInSymLink
, sizeof(pathInSymLink
));
291 pathInSymLink
[res
] = '\0';
292 if ( pathInSymLink
[0] != '/' ) {
293 char symFullPath
[MAXPATHLEN
];
294 strcpy(symFullPath
, vpath
);
295 char* lastSlash
= strrchr(symFullPath
, '/');
296 if ( lastSlash
!= NULL
) {
297 strcpy(lastSlash
+1, pathInSymLink
);
298 // (re)try looking for what symlink points to, but in /overlay
299 return this->getNodeForVirtualPath(symFullPath
);
306 if ( fgFileSystemRoot
[0] != '\0' ) {
307 // using -root means always use /rootpath/usr/lib
308 strcpy(completePath
, fgFileSystemRoot
);
309 strcat(completePath
, vpath
); // assumes vpath starts with '/'
310 return this->getNode(completePath
);
312 // not found in -overlay or -root not used
313 return this->getNode(vpath
);
316 ArchGraph::DependencyNode
* ArchGraph::getNode(const char* path
)
318 //fprintf(stderr, "getNode(%s)\n", path);
319 // look up supplied path to see if node already exists
320 PathToNode::iterator pos
= fNodes
.find(path
);
321 if ( pos
!= fNodes
.end() )
325 char realPath
[MAXPATHLEN
];
326 if ( realpath(path
, realPath
) == NULL
)
327 throwf("realpath() failed on %s\n", path
);
329 // look up real path to see if node already exists
330 pos
= fNodes
.find(realPath
);
331 if ( pos
!= fNodes
.end() ) {
332 // update fAliasesMap with symlinks found
333 const char* aliasPath
= path
;
334 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(path
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
335 aliasPath
= &path
[strlen(fgFileSystemRoot
)];
337 if ( fAliasesMap
.find(aliasPath
) == fAliasesMap
.end() ) {
338 if ( strcmp(aliasPath
, pos
->second
->getLayout()->getID().name
) != 0 ) {
339 fAliasesMap
[strdup(aliasPath
)] = pos
->second
->getLayout()->getID().name
;
340 //fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
346 // still does not exist, so create a new node
347 const UniversalMachOLayout
& uni
= UniversalMachOLayout::find(realPath
);
348 DependencyNode
* node
= new DependencyNode(this, realPath
, uni
.getSlice(fArchPair
));
349 if ( node
->getLayout() == NULL
) {
350 throwf("%s is missing arch %s", realPath
, archName(fArchPair
));
352 // add realpath to node map
353 fNodes
[node
->getPath()] = node
;
354 // if install name is not real path, add install name to node map
355 if ( (node
->getLayout()->getFileType() == MH_DYLIB
) && (strcmp(realPath
, node
->getLayout()->getID().name
) != 0) ) {
356 //fprintf(stderr, "adding %s node alias %s for %s\n", archName(fArchPair), node->getLayout()->getID().name, realPath);
357 pos
= fNodes
.find(node
->getLayout()->getID().name
);
358 if ( pos
!= fNodes
.end() ) {
359 // get uuids of two dylibs to see if this is accidental copy of a dylib or two differnent dylibs with same -install_name
362 node
->getLayout()->uuid(uuid1
);
363 pos
->second
->getLayout()->uuid(uuid2
);
364 if ( memcmp(&uuid1
, &uuid2
, 16) == 0 ) {
365 // <rdar://problem/8305479> warn if two dylib in cache have same install_name
367 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",
368 node
->getLayout()->getID().name
, pos
->second
->getPath(), node
->getPath());
369 fprintf(stderr
, "%s", msg
);
370 warnings
.push_back(msg
);
373 // <rdar://problem/12763450> update_dyld_shared_cache should fail if two images have same install name
374 fprintf(stderr
, "update_dyld_shared_cache: found two different dylibs with same install path: %s\n\t%s\n\t%s\n",
375 node
->getLayout()->getID().name
, pos
->second
->getPath(), node
->getPath());
380 fNodes
[node
->getLayout()->getID().name
] = node
;
381 // update fAliasesMap with symlinks found
382 const char* aliasPath
= realPath
;
383 if ( (fgFileSystemRoot
!= NULL
) && (fgFileSystemRoot
[0] != '\0') && (strncmp(realPath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
384 aliasPath
= &realPath
[strlen(fgFileSystemRoot
)];
386 // <rdar://problem/11192810> Too many aliases in -overlay mode
387 for (std::vector
<const char*>::const_iterator it
=fgFileSystemOverlays
.begin(); it
!= fgFileSystemOverlays
.end(); ++it
) {
388 const char* overlayPath
= *it
;
389 if ( strncmp(realPath
, overlayPath
, strlen(overlayPath
)) == 0 ) {
390 aliasPath
= &realPath
[strlen(overlayPath
)];
394 if ( fAliasesMap
.find(aliasPath
) == fAliasesMap
.end() ) {
395 if ( strcmp(aliasPath
, node
->getLayout()->getID().name
) != 0 ) {
396 fAliasesMap
[strdup(aliasPath
)] = node
->getLayout()->getID().name
;
397 //fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
405 void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction
* mainExecutableLayout
)
407 if ( !fDependenciesLoaded
) {
408 fDependenciesLoaded
= true;
410 const std::vector
<MachOLayoutAbstraction::Library
>& dependsOn
= fLayout
->getLibraries();
411 for(std::vector
<MachOLayoutAbstraction::Library
>::const_iterator it
= dependsOn
.begin(); it
!= dependsOn
.end(); ++it
) {
413 const char* dependentPath
= it
->name
;
414 if ( strncmp(dependentPath
, "@executable_path/", 17) == 0 ) {
415 if ( mainExecutableLayout
== NULL
)
416 throw "@executable_path without main executable";
417 // expand @executable_path path prefix
418 const char* executablePath
= mainExecutableLayout
->getFilePath();
419 char newPath
[strlen(executablePath
) + strlen(dependentPath
)+2];
420 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(executablePath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
421 // executablePath already has rootPath prefix, need to remove that to get to base virtual path
422 strcpy(newPath
, &executablePath
[strlen(fgFileSystemRoot
)]);
425 strcpy(newPath
, executablePath
);
427 char* addPoint
= strrchr(newPath
,'/');
428 if ( addPoint
!= NULL
)
429 strcpy(&addPoint
[1], &dependentPath
[17]);
431 strcpy(newPath
, &dependentPath
[17]);
432 dependentPath
= strdup(newPath
);
434 else if ( strncmp(dependentPath
, "@loader_path/", 13) == 0 ) {
435 // expand @loader_path path prefix
436 char newPath
[strlen(fPath
) + strlen(dependentPath
)+2];
437 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(fPath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
438 // fPath already has rootPath prefix, need to remove that to get to base virtual path
439 strcpy(newPath
, &fPath
[strlen(fgFileSystemRoot
)]);
442 strcpy(newPath
, fPath
);
444 char* addPoint
= strrchr(newPath
,'/');
445 if ( addPoint
!= NULL
)
446 strcpy(&addPoint
[1], &dependentPath
[13]);
448 strcpy(newPath
, &dependentPath
[13]);
449 dependentPath
= strdup(newPath
);
451 else if ( strncmp(dependentPath
, "@rpath/", 7) == 0 ) {
452 throw "@rpath not supported in dyld shared cache";
454 // <rdar://problem/9161945> silently ignore dependents from main executables that can't be in shared cache
455 bool addDependent
= true;
456 if ( fLayout
->getFileType() == MH_EXECUTE
) {
457 if ( (strncmp(dependentPath
, "/usr/lib/", 9) != 0) && (strncmp(dependentPath
, "/System/Library/", 16) != 0) ) {
458 addDependent
= false;
462 fDependsOn
.insert(fGraph
->getNodeForVirtualPath(dependentPath
));
464 catch (const char* msg
) {
465 if ( it
->weakImport
|| ! fLayout
->hasSplitSegInfo() ) {
466 // ok to ignore missing weak imported dylibs from things that are
467 // not going to be in the dyld shared cache
470 fprintf(stderr
, "warning, could not bind %s because %s\n", fPath
, msg
);
471 fDependentMissing
= true;
476 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
477 (*it
)->loadDependencies(mainExecutableLayout
);
482 void ArchGraph::DependencyNode::markNeededByRoot(ArchGraph::DependencyNode
* rootNode
)
484 if ( fRootsDependentOnThis
.count(rootNode
) == 0 ) {
485 fRootsDependentOnThis
.insert(rootNode
);
486 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
487 (*it
)->markNeededByRoot(rootNode
);
494 ArchGraph::DependencyNode::DependencyNode(ArchGraph
* graph
, const char* path
, const MachOLayoutAbstraction
* layout
)
495 : fGraph(graph
), fPath(strdup(path
)), fLayout(layout
), fDependenciesLoaded(false), fDependentMissing(false)
497 //fprintf(stderr, "new DependencyNode(0x%08X, %s)\n", graph->fArch, path);
500 uint64_t ArchGraph::maxCacheSizeForArchPair(ArchPair ap
) {
504 case CPU_TYPE_X86_64
:
507 return ARM_SHARED_REGION_SIZE
;
509 return ARM64_SHARED_REGION_SIZE
;
510 default: return UINT64_MAX
;
514 void ArchGraph::findSharedDylibs(ArchPair ap
)
516 const PathToNode
& nodes
= fgPerArchGraph
[ap
]->fNodes
;
517 std::set
<const MachOLayoutAbstraction
*> possibleLibs
;
518 std::map
<const MachOLayoutAbstraction
*, const DependencyNode
*> layoutToNode
;
519 //fprintf(stderr, "shared for arch %s\n", archName(ap));
520 for(PathToNode::const_iterator it
= nodes
.begin(); it
!= nodes
.end(); ++it
) {
521 DependencyNode
* node
= it
->second
;
522 // <rdar://problem/6127437> put all dylibs in shared cache - not just ones used by more than one app
523 if ( node
->allDependentsFound() /*&& (node->useCount() > 1)*/ ) {
524 const MachOLayoutAbstraction
* layout
= node
->getLayout();
525 if ( layout
->isDylib() ) {
527 if ( sharable(layout
, ap
, &msg
) ) {
528 possibleLibs
.insert(layout
);
529 layoutToNode
[layout
] = node
;
532 if ( !iPhoneOS
&& (layout
->getID().name
[0] == '@') ) {
533 // <rdar://problem/7770139> update_dyld_shared_cache should suppress warnings for embedded frameworks
536 warnings
.push_back(msg
);
537 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
544 // prune so that all shareable libs depend only on other shareable libs
545 std::set
<const MachOLayoutAbstraction
*>& sharedLibs
= fgPerArchGraph
[ap
]->fSharedDylibs
;
546 std::map
<const MachOLayoutAbstraction
*,bool> shareableMap
;
547 uint64_t totalLibSize
= 0;
548 for (std::set
<const MachOLayoutAbstraction
*>::iterator lit
= possibleLibs
.begin(); lit
!= possibleLibs
.end(); ++lit
) {
549 if ( canBeShared(*lit
, ap
, possibleLibs
, shareableMap
) ) {
550 totalLibSize
+= (*lit
)->getVMSize();
551 sharedLibs
.insert(*lit
);
555 #if 0 // disable auto-eviction because it happens before linkedit optimization which means it is overly conservative.
557 // Check to see if the unoptimized cache size is too large, if so trim out some libraries
558 uint64_t maxCacheSize
= maxCacheSizeForArchPair(ap
);
559 if (totalLibSize
> maxCacheSize
) {
560 fprintf(stderr
, "update_dyld_shared_cache: unoptimized %s shared cache overflow, total VM space: %lldMB (max=%lldMB)\n", archName(ap
), totalLibSize
/(1024*1024), maxCacheSize
/(1024*1024));
561 std::vector
<const MachOLayoutAbstraction
*> removableLibs
;
563 for (const MachOLayoutAbstraction
* layout
: sharedLibs
) {
564 // Every library uses itself, and every MH_DYLIB has an extra useCount, so we know useCount of 2 implies nothing else in the shared cache uses it
565 if (layoutToNode
[layout
]->useCount() == 2) {
566 if ( layoutToNode
[layout
]->dependsOnDylibList() ) {
567 removableLibs
.push_back(layout
);
568 //fprintf(stderr, " possible to evict: %s\n", layout->getID().name);
573 std::sort(removableLibs
.begin(), removableLibs
.end(), [](const MachOLayoutAbstraction
* a
, const MachOLayoutAbstraction
* b
){
574 return a
->getVMSize() < b
->getVMSize();
577 while ( (totalLibSize
> maxCacheSize
) && !removableLibs
.empty() ) {
578 const MachOLayoutAbstraction
* largestRemovableLib
= removableLibs
.back();
579 removableLibs
.pop_back();
580 if ( largestRemovableLib
->getVMSize() > 1024*1024 )
581 fprintf(stderr
, "update_dyld_shared_cache: evicting % 3lldMB leaf dylib %s\n", largestRemovableLib
->getVMSize()/(1024*1024), largestRemovableLib
->getID().name
);
583 fprintf(stderr
, "update_dyld_shared_cache: evicting % 3lldKB leaf dylib %s\n", largestRemovableLib
->getVMSize()/1024, largestRemovableLib
->getID().name
);
584 sharedLibs
.erase(largestRemovableLib
);
585 totalLibSize
-= largestRemovableLib
->getVMSize();
587 fprintf(stderr
, "update_dyld_shared_cache: unoptimized %s shared cache reduced to total VM space: %lldMB\n", archName(ap
), totalLibSize
/1024/1024);
592 const char* ArchGraph::archName(ArchPair ap
)
597 case CPU_TYPE_X86_64
:
598 switch ( ap
.subtype
) {
599 case CPU_SUBTYPE_X86_64_H
:
605 switch ( ap
.subtype
) {
606 case CPU_SUBTYPE_ARM_V4T
:
608 case CPU_SUBTYPE_ARM_V6
:
610 case CPU_SUBTYPE_ARM_V5TEJ
:
612 case CPU_SUBTYPE_ARM_XSCALE
:
614 case CPU_SUBTYPE_ARM_V7
:
616 case CPU_SUBTYPE_ARM_V7F
:
618 case CPU_SUBTYPE_ARM_V7K
:
620 case CPU_SUBTYPE_ARM_V7S
:
632 bool ArchGraph::sharable(const MachOLayoutAbstraction
* layout
, ArchPair ap
, char** msg
)
634 int trustErr
= layout
->notTrusted();
635 if ( ! layout
->isTwoLevelNamespace() )
636 asprintf(msg
, "can't put %s in shared cache because it was built -flat_namespace", layout
->getID().name
);
637 else if ( ! layout
->inSharableLocation() )
638 asprintf(msg
, "can't put %s in shared cache because its -install_name is not in /usr/lib or /System/Library", layout
->getID().name
);
639 else if ( ! layout
->hasSplitSegInfo() )
640 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"));
641 else if ( rootless
== true && trustErr
!= 0 )
642 asprintf(msg
, "can't put %s in shared cache because it is not trusted: %s", layout
->getFilePath(), strerror(trustErr
));
643 else if ( layout
->hasDynamicLookupLinkage() )
644 asprintf(msg
, "can't put %s in shared cache because it was built with '-undefined dynamic_lookup'", layout
->getID().name
);
645 else if ( layout
->hasMainExecutableLookupLinkage() )
646 asprintf(msg
, "can't put %s in shared cache because it was built with '-bundle_loader'", layout
->getID().name
);
652 bool ArchGraph::canBeShared(const MachOLayoutAbstraction
* layout
, ArchPair ap
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
)
654 // check map which is a cache of results
655 std::map
<const MachOLayoutAbstraction
*, bool>::iterator mapPos
= shareableMap
.find(layout
);
656 if ( mapPos
!= shareableMap
.end() ) {
657 return mapPos
->second
;
660 if ( possibleLibs
.count(layout
) == 0 ) {
661 shareableMap
[layout
] = false;
663 if ( sharable(layout
, ap
, &msg
) )
664 asprintf(&msg
, "can't put %s in shared cache, unknown reason", layout
->getID().name
);
665 warnings
.push_back(msg
);
667 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
671 shareableMap
[layout
] = true; // mark this shareable early in case of circular references
672 const PathToNode
& nodes
= fgPerArchGraph
[ap
]->fNodes
;
673 const std::vector
<MachOLayoutAbstraction::Library
>& dependents
= layout
->getLibraries();
674 for (std::vector
<MachOLayoutAbstraction::Library
>::const_iterator dit
= dependents
.begin(); dit
!= dependents
.end(); ++dit
) {
675 PathToNode::const_iterator pos
= nodes
.find(dit
->name
);
676 if ( pos
== nodes
.end() ) {
677 // path from load command does not match any loaded dylibs, maybe there is a temp symlink
678 char realPath
[MAXPATHLEN
];
679 if ( realpath(dit
->name
, realPath
) != NULL
) {
680 if ( nodes
.find(realPath
) != nodes
.end() )
683 // handle weak imported dylibs not found
684 if ( dit
->weakImport
)
686 shareableMap
[layout
] = false;
688 asprintf(&msg
, "can't put %s in shared cache because it depends on %s which can't be found", layout
->getID().name
, dit
->name
);
689 warnings
.push_back(msg
);
691 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
695 if ( ! canBeShared(pos
->second
->getLayout(), ap
, possibleLibs
, shareableMap
) ) {
696 shareableMap
[layout
] = false;
698 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
);
699 warnings
.push_back(msg
);
701 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
715 const char* getBuffer();
717 uint32_t add(const char* str
);
718 uint32_t addUnique(const char* str
);
719 const char* stringAtIndex(uint32_t) const;
722 typedef std::unordered_map
<const char*, uint32_t, CStringHash
, CStringEquals
> StringToOffset
;
725 uint32_t fBufferAllocated
;
726 uint32_t fBufferUsed
;
727 StringToOffset fUniqueStrings
;
731 StringPool::StringPool()
732 : fBufferUsed(0), fBufferAllocated(128*1024*1024)
734 fBuffer
= (char*)malloc(fBufferAllocated
);
737 uint32_t StringPool::add(const char* str
)
739 uint32_t len
= strlen(str
);
740 if ( (fBufferUsed
+ len
+ 1) > fBufferAllocated
) {
742 throw "string buffer exhausted";
744 strcpy(&fBuffer
[fBufferUsed
], str
);
745 uint32_t result
= fBufferUsed
;
746 fUniqueStrings
[&fBuffer
[fBufferUsed
]] = result
;
747 fBufferUsed
+= len
+1;
751 uint32_t StringPool::addUnique(const char* str
)
753 StringToOffset::iterator pos
= fUniqueStrings
.find(str
);
754 if ( pos
!= fUniqueStrings
.end() )
757 //fprintf(stderr, "StringPool::addUnique() new string: %s\n", str);
758 return this->add(str
);
762 uint32_t StringPool::size()
767 const char* StringPool::getBuffer()
772 const char* StringPool::stringAtIndex(uint32_t index
) const
774 return &fBuffer
[index
];
779 struct LocalSymbolInfo
781 uint32_t dylibOffset
;
782 uint32_t nlistStartIndex
;
787 template <typename A
>
791 SharedCache(ArchGraph
* graph
, const char* rootPath
, const std::vector
<const char*>& overlayPaths
, const char* cacheDir
, bool explicitCacheDir
,
792 bool alphaSort
, bool verify
, bool optimize
, uint64_t dyldBaseAddress
);
793 bool update(bool force
, bool optimize
, bool deleteExistingFirst
, int archIndex
,
794 int archCount
, bool keepSignatures
, bool dontMapLocalSymbols
);
795 void writeCacheFile(const char *cacheFilePath
, uint8_t *cacheFileBuffer
, uint32_t cacheFileSize
, bool deleteOldCache
);
796 static const char* cacheFileSuffix(bool optimized
, const char* archName
);
798 // vm address = address AS WRITTEN into the cache
799 // mapped address = address AS MAPPED into the update process only
800 // file offset = offset relative to start of cache file
801 void * mappedAddressForVMAddress(uint64_t vmaddr
);
802 uint64_t VMAddressForMappedAddress(const void *mapaddr
);
803 uint64_t cacheFileOffsetForVMAddress(uint64_t addr
) const;
804 uint64_t VMAddressForCacheFileOffset(uint64_t addr
) const;
806 static const char* archName();
809 typedef typename
A::P P
;
810 typedef typename
A::P::E E
;
811 typedef typename
A::P::uint_t pint_t
;
813 bool notUpToDate(const char* path
, unsigned int aliasCount
);
814 bool notUpToDate(const void* cache
, unsigned int aliasCount
);
815 uint8_t* optimizeLINKEDIT(bool keepSignatures
, bool dontMapLocalSymbols
);
816 void optimizeObjC(std::vector
<void*>& pointersInData
);
818 static void getSharedCacheBasAddresses(cpu_type_t arch
, uint64_t* baseReadOnly
, uint64_t* baseWritable
);
819 static cpu_type_t
arch();
820 static uint64_t sharedRegionStartAddress();
821 static uint64_t sharedRegionSize();
822 static uint64_t sharedRegionStartWritableAddress(uint64_t);
823 static uint64_t sharedRegionStartReadOnlyAddress(uint64_t, uint64_t);
824 static uint64_t getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
);
825 static bool addCacheSlideInfo();
826 static uint64_t pathHash(const char*);
828 static uint64_t pageAlign(uint64_t addr
);
829 static uint64_t regionAlign(uint64_t addr
);
830 static uint64_t pageAlign4KB(uint64_t addr
);
831 void assignNewBaseAddresses(bool verify
);
834 const MachOLayoutAbstraction
* layout
;
835 std::vector
<const char*> aliases
;
836 dyld_cache_image_info info
;
839 struct ByNameSorter
{
840 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
)
841 { return (strcmp(left
.layout
->getID().name
, right
.layout
->getID().name
) < 0); }
844 struct ByAddressSorter
{
845 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
846 return (left
.layout
->getSegments()[0].newAddress() < right
.layout
->getSegments()[0].newAddress());
850 struct ByCStringSectionSizeSorter
{
851 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
852 const std::vector
<MachOLayoutAbstraction::Segment
>& segs_l
=
853 left
.layout
->getSegments();
854 const std::vector
<MachOLayoutAbstraction::Segment
>& segs_r
=
855 right
.layout
->getSegments();
856 if (segs_l
.size() == 0 || segs_r
.size() == 0) {
857 // one image has no segments
858 return segs_l
.size() > segs_r
.size();
860 const macho_header
<P
> *mh_l
= (macho_header
<P
>*)segs_l
[0].mappedAddress();
861 const macho_header
<P
> *mh_r
= (macho_header
<P
>*)segs_r
[0].mappedAddress();
862 const macho_section
<P
> *cstring_l
= mh_l
->getSection("__TEXT", "__cstring");
863 const macho_section
<P
> *cstring_r
= mh_r
->getSection("__TEXT", "__cstring");
864 if (!cstring_l
|| !cstring_r
) {
865 // one image has no cstrings
866 return cstring_l
&& !cstring_r
;
869 return cstring_l
->size() > cstring_r
->size();
874 Sorter(std::map
<const MachOLayoutAbstraction
*, uint32_t>& map
): fMap(map
) {}
875 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
876 return (fMap
[left
.layout
] < fMap
[right
.layout
]);
879 std::map
<const MachOLayoutAbstraction
*, uint32_t>& fMap
;
883 ArchGraph
* fArchGraph
;
885 bool fExistingIsNotUpToDate
;
886 bool fCacheFileInFinalLocation
;
887 const char* fCacheFilePath
;
888 uint8_t* fExistingCacheForVerification
;
889 std::vector
<LayoutInfo
> fDylibs
;
890 std::vector
<LayoutInfo
> fDylibAliases
;
891 std::vector
<shared_file_mapping_np
> fMappings
;
892 std::vector
<macho_nlist
<P
> > fUnmappedLocalSymbols
;
893 StringPool fUnmappedLocalsStringPool
;
894 std::vector
<LocalSymbolInfo
> fLocalSymbolInfos
;
895 uint32_t fHeaderSize
;
896 uint8_t* fInMemoryCache
;
897 uint64_t fDyldBaseAddress
;
898 uint64_t fLinkEditsTotalUnoptimizedSize
;
899 uint64_t fLinkEditsStartAddress
;
900 MachOLayoutAbstraction::Segment
* fFirstLinkEditSegment
;
901 uint32_t fOffsetOfBindInfoInCombinedLinkedit
;
902 uint32_t fOffsetOfWeakBindInfoInCombinedLinkedit
;
903 uint32_t fOffsetOfLazyBindInfoInCombinedLinkedit
;
904 uint32_t fOffsetOfExportInfoInCombinedLinkedit
;
905 uint32_t fOffsetOfOldSymbolTableInfoInCombinedLinkedit
;
906 uint32_t fSizeOfOldSymbolTableInfoInCombinedLinkedit
;
907 uint32_t fOffsetOfOldExternalRelocationsInCombinedLinkedit
;
908 uint32_t fSizeOfOldExternalRelocationsInCombinedLinkedit
;
909 uint32_t fOffsetOfOldIndirectSymbolsInCombinedLinkedit
;
910 uint32_t fSizeOfOldIndirectSymbolsInCombinedLinkedit
;
911 uint32_t fOffsetOfOldStringPoolInCombinedLinkedit
;
912 uint32_t fSizeOfOldStringPoolInCombinedLinkedit
;
913 uint32_t fOffsetOfFunctionStartsInCombinedLinkedit
;
914 uint32_t fSizeOfFunctionStartsInCombinedLinkedit
;
915 uint32_t fOffsetOfDataInCodeInCombinedLinkedit
;
916 uint32_t fSizeOfDataInCodeInCombinedLinkedit
;
917 uint32_t fLinkEditsTotalOptimizedSize
;
918 uint32_t fUnmappedLocalSymbolsSize
;
922 // Access a section containing a list of pointers
923 template <typename A
, typename T
>
926 typedef typename
A::P P
;
927 typedef typename
A::P::uint_t pint_t
;
929 SharedCache
<A
>* const fCache
;
930 const macho_section
<P
>* const fSection
;
931 pint_t
* const fBase
;
935 PointerSection(SharedCache
<A
>* cache
, const macho_header
<P
>* header
,
936 const char *segname
, const char *sectname
)
938 , fSection(header
->getSection(segname
, sectname
))
939 , fBase(fSection
? (pint_t
*)cache
->mappedAddressForVMAddress(fSection
->addr()) : 0)
940 , fCount(fSection
? fSection
->size() / sizeof(pint_t
) : 0)
944 pint_t
count() const { return fCount
; }
946 pint_t
getVMAddress(pint_t index
) const {
947 if (index
>= fCount
) throwf("index out of range");
948 return P::getP(fBase
[index
]);
951 T
get(pint_t index
) const {
952 return (T
)fCache
->mappedAddressForVMAddress(getVMAddress(index
));
955 void setVMAddress(pint_t index
, pint_t value
) {
956 if (index
>= fCount
) throwf("index out of range");
957 P::setP(fBase
[index
], value
);
962 for (pint_t i
= 0; i
< fCount
; i
++) {
963 pint_t value
= fBase
[i
];
965 fBase
[i
-shift
] = value
;
971 const_cast<macho_section
<P
>*>(fSection
)->set_size(fCount
* sizeof(pint_t
));
975 // Access a section containing an array of structures
976 template <typename A
, typename T
>
979 typedef typename
A::P P
;
981 SharedCache
<A
>* const fCache
;
982 const macho_section
<P
>* const fSection
;
984 uint64_t const fCount
;
987 ArraySection(SharedCache
<A
>* cache
, const macho_header
<P
>* header
,
988 const char *segname
, const char *sectname
)
990 , fSection(header
->getSection(segname
, sectname
))
991 , fBase(fSection
? (T
*)cache
->mappedAddressForVMAddress(fSection
->addr()) : 0)
992 , fCount(fSection
? fSection
->size() / sizeof(T
) : 0)
996 uint64_t count() const { return fCount
; }
998 T
& get(uint64_t index
) const {
999 if (index
>= fCount
) throwf("index out of range");
1000 return fBase
[index
];
1006 #include "ObjCLegacyAbstraction.hpp"
1007 #include "ObjCModernAbstraction.hpp"
1011 template <> cpu_type_t SharedCache
<x86
>::arch() { return CPU_TYPE_I386
; }
1012 template <> cpu_type_t SharedCache
<x86_64
>::arch() { return CPU_TYPE_X86_64
; }
1013 template <> cpu_type_t SharedCache
<arm
>::arch() { return CPU_TYPE_ARM
; }
1014 template <> cpu_type_t SharedCache
<arm64
>::arch() { return CPU_TYPE_ARM64
; }
1016 template <> uint64_t SharedCache
<x86
>::sharedRegionStartAddress() { return 0x90000000; }
1017 template <> uint64_t SharedCache
<x86_64
>::sharedRegionStartAddress() { return 0x7FFF80000000LL
; }
1018 template <> uint64_t SharedCache
<arm
>::sharedRegionStartAddress() { return ARM_SHARED_REGION_START
; }
1019 template <> uint64_t SharedCache
<arm64
>::sharedRegionStartAddress() { return ARM64_SHARED_REGION_START
; }
1021 template <> uint64_t SharedCache
<x86
>::sharedRegionSize() { return 0x20000000; }
1022 template <> uint64_t SharedCache
<x86_64
>::sharedRegionSize() { return 0x40000000; }
1023 template <> uint64_t SharedCache
<arm
>::sharedRegionSize() { return ARM_SHARED_REGION_SIZE
; }
1024 template <> uint64_t SharedCache
<arm64
>::sharedRegionSize() { return ARM64_SHARED_REGION_SIZE
; }
1026 template <> uint64_t SharedCache
<x86
>::sharedRegionStartWritableAddress(uint64_t exEnd
) { return exEnd
+ 0x04000000; }
1027 template <> uint64_t SharedCache
<x86_64
>::sharedRegionStartWritableAddress(uint64_t exEnd
) { return 0x7FFF70000000LL
; }
1028 template <> uint64_t SharedCache
<arm
>::sharedRegionStartWritableAddress(uint64_t exEnd
) { return (exEnd
+ 16383) & (-16384); }
1029 template <> uint64_t SharedCache
<arm64
>::sharedRegionStartWritableAddress(uint64_t exEnd
) { return exEnd
; }
1031 template <> uint64_t SharedCache
<x86
>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd
, uint64_t exEnd
) { return wrEnd
+ 0x04000000; }
1032 template <> uint64_t SharedCache
<x86_64
>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd
, uint64_t exEnd
){ return exEnd
; }
1033 template <> uint64_t SharedCache
<arm
>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd
, uint64_t exEnd
) { return (wrEnd
+ 16383) & (-16384); }
1034 template <> uint64_t SharedCache
<arm64
>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd
, uint64_t exEnd
) { return (wrEnd
+ 16383) & (-16384); }
1036 template <> const char* SharedCache
<x86
>::archName() { return "i386"; }
1037 template <> const char* SharedCache
<x86_64
>::archName() { return "x86_64"; }
1038 template <> const char* SharedCache
<arm
>::archName() { return "arm"; }
1039 template <> const char* SharedCache
<arm64
>::archName() { return "arm64"; }
1041 template <> const char* SharedCache
<x86
>::cacheFileSuffix(bool, const char* archName
) { return archName
; }
1042 template <> const char* SharedCache
<x86_64
>::cacheFileSuffix(bool, const char* archName
){ return archName
; }
1043 template <> const char* SharedCache
<arm
>::cacheFileSuffix(bool, const char* archName
) { return archName
; }
1044 template <> const char* SharedCache
<arm64
>::cacheFileSuffix(bool, const char* archName
) { return archName
; }
1046 template <> uint64_t SharedCache
<x86
>::pageAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
1047 template <> uint64_t SharedCache
<x86_64
>::pageAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
1048 template <> uint64_t SharedCache
<arm
>::pageAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
1049 template <> uint64_t SharedCache
<arm64
>::pageAlign(uint64_t addr
) { return ( (addr
+ 16383) & (-16384) ); }
1051 template <> uint64_t SharedCache
<x86
>::regionAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
1052 template <> uint64_t SharedCache
<x86_64
>::regionAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
1053 template <> uint64_t SharedCache
<arm
>::regionAlign(uint64_t addr
) { return ( (addr
+ 16383) & (-16384) ); }
1054 template <> uint64_t SharedCache
<arm64
>::regionAlign(uint64_t addr
) { return ( (addr
+ 16383) & (-16384) ); }
1057 template <typename A
>
1058 uint64_t SharedCache
<A
>::pageAlign4KB(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
1060 template <typename A
>
1061 SharedCache
<A
>::SharedCache(ArchGraph
* graph
, const char* rootPath
, const std::vector
<const char*>& overlayPaths
, const char* cacheDir
, bool explicitCacheDir
, bool alphaSort
, bool verify
, bool optimize
, uint64_t dyldBaseAddress
)
1062 : fArchGraph(graph
), fVerify(verify
), fExistingIsNotUpToDate(true),
1063 fCacheFileInFinalLocation(rootPath
[0] == '\0'), fCacheFilePath(NULL
),
1064 fExistingCacheForVerification(NULL
), fDyldBaseAddress(dyldBaseAddress
),
1065 fOffsetOfBindInfoInCombinedLinkedit(0), fOffsetOfWeakBindInfoInCombinedLinkedit(0),
1066 fOffsetOfLazyBindInfoInCombinedLinkedit(0), fOffsetOfExportInfoInCombinedLinkedit(0),
1067 fOffsetOfOldSymbolTableInfoInCombinedLinkedit(0), fSizeOfOldSymbolTableInfoInCombinedLinkedit(0),
1068 fOffsetOfOldExternalRelocationsInCombinedLinkedit(0), fSizeOfOldExternalRelocationsInCombinedLinkedit(0),
1069 fOffsetOfOldIndirectSymbolsInCombinedLinkedit(0), fSizeOfOldIndirectSymbolsInCombinedLinkedit(0),
1070 fOffsetOfOldStringPoolInCombinedLinkedit(0), fSizeOfOldStringPoolInCombinedLinkedit(0),
1071 fOffsetOfFunctionStartsInCombinedLinkedit(0), fSizeOfFunctionStartsInCombinedLinkedit(0),
1072 fOffsetOfDataInCodeInCombinedLinkedit(0), fSizeOfDataInCodeInCombinedLinkedit(0),
1073 fUnmappedLocalSymbolsSize(0)
1075 if ( fArchGraph
->getArchPair().arch
!= arch() )
1076 throwf("SharedCache object is wrong architecture: 0x%08X vs 0x%08X", fArchGraph
->getArchPair().arch
, arch());
1078 // build vector of all shared dylibs
1079 unsigned int aliasCount
= 0;
1080 std::set
<const MachOLayoutAbstraction
*>& dylibs
= fArchGraph
->getSharedDylibs();
1081 ArchGraph::StringToString
& aliases
= fArchGraph
->getDylibAliases();
1082 for(std::set
<const MachOLayoutAbstraction
*>::iterator it
= dylibs
.begin(); it
!= dylibs
.end(); ++it
) {
1083 const MachOLayoutAbstraction
* lib
= *it
;
1086 temp
.info
.address
= 0;
1087 temp
.info
.inode
= lib
->getInode();
1088 temp
.info
.modTime
= lib
->getLastModTime();
1090 temp
.info
.inode
= pathHash(lib
->getID().name
);
1091 temp
.info
.modTime
= 0;
1093 temp
.info
.pathFileOffset
= lib
->getNameFileOffset(); // for now this is the offset within the dylib
1094 for(ArchGraph::StringToString::iterator ait
= aliases
.begin(); ait
!= aliases
.end(); ++ait
) {
1095 if ( strcmp(ait
->second
, lib
->getID().name
) == 0 ) {
1096 temp
.aliases
.push_back(ait
->first
);
1100 fDylibs
.push_back(temp
);
1103 // create path to cache file
1104 char cachePathCanonical
[MAXPATHLEN
];
1105 strcpy(cachePathCanonical
, cacheDir
);
1106 if ( cachePathCanonical
[strlen(cachePathCanonical
)-1] != '/' )
1107 strcat(cachePathCanonical
, "/");
1108 strcat(cachePathCanonical
, DYLD_SHARED_CACHE_BASE_NAME
);
1109 strcat(cachePathCanonical
, cacheFileSuffix(optimize
, fArchGraph
->archName()));
1110 char cachePath
[MAXPATHLEN
];
1111 if ( explicitCacheDir
) {
1112 fCacheFilePath
= strdup(cachePathCanonical
);
1114 else if ( overlayPaths
.size() == 1 ) {
1115 // if no -cache_dir and exactly on -overlay, write cache file into that overlay dir
1116 strcpy(cachePath
, overlayPaths
[0]);
1117 strcat(cachePath
, "/");
1118 strcat(cachePath
, cachePathCanonical
);
1119 fCacheFilePath
= strdup(cachePath
);
1121 else if ( rootPath
[0] != '\0' ) {
1122 strcpy(cachePath
, rootPath
);
1123 strcat(cachePath
, "/");
1124 strcat(cachePath
, cachePathCanonical
);
1125 fCacheFilePath
= strdup(cachePath
);
1128 fCacheFilePath
= strdup(cachePathCanonical
);
1131 // If the path we are writing to is trusted then our sources need to be trusted
1132 // <rdar://problem/21166835> Can't update the update_dyld_shared_cache on a non-boot volume
1133 rootless
= rootless_check_trusted(fCacheFilePath
);
1135 if ( overlayPaths
.size() == 1 ) {
1136 // in overlay mode if there already is a cache file in the overlay,
1137 // check if it is up to date.
1138 struct stat stat_buf
;
1139 if ( stat(fCacheFilePath
, &stat_buf
) == 0 ) {
1140 fExistingIsNotUpToDate
= this->notUpToDate(fCacheFilePath
, aliasCount
);
1142 else if ( rootPath
[0] != '\0' ) {
1143 // using -root and -overlay, but no cache file in overlay, check one in -root
1144 char cachePathRoot
[MAXPATHLEN
];
1145 strcpy(cachePathRoot
, rootPath
);
1146 strcat(cachePathRoot
, "/");
1147 strcat(cachePathRoot
, cachePathCanonical
);
1148 fExistingIsNotUpToDate
= this->notUpToDate(cachePathRoot
, aliasCount
);
1151 // uisng -overlay, but no cache file in overlay, check one in boot volume
1152 fExistingIsNotUpToDate
= this->notUpToDate(cachePathCanonical
, aliasCount
);
1156 fExistingIsNotUpToDate
= this->notUpToDate(fCacheFilePath
, aliasCount
);
1159 // sort shared dylibs
1161 // already sorted by notUpToDate()
1163 else if ( alphaSort
) {
1164 std::sort(fDylibs
.begin(), fDylibs
.end(), ByNameSorter());
1167 // random sort for Address Space Randomization
1168 std::map
<const MachOLayoutAbstraction
*, uint32_t> map
;
1169 for(typename
std::vector
<struct LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
)
1170 map
[it
->layout
] = arc4random();
1171 std::sort(fDylibs
.begin(), fDylibs
.end(), Sorter(map
));
1174 // assign segments in each dylib a new address
1175 this->assignNewBaseAddresses(verify
);
1177 // calculate where string pool offset will start
1178 // calculate cache file header size
1179 fHeaderSize
= sizeof(dyld_cache_header
)
1180 + fMappings
.size()*sizeof(shared_file_mapping_np
)
1181 + (fDylibs
.size()+aliasCount
)*sizeof(dyld_cache_image_info
);
1182 const uint64_t baseHeaderSize
= fHeaderSize
;
1183 //fprintf(stderr, "aliasCount=%d, fHeaderSize=0x%08X\n", aliasCount, fHeaderSize);
1184 // build list of aliases and compute where each ones path string will go
1185 for(typename
std::vector
<struct LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1186 for(std::vector
<const char*>::const_iterator ait
= it
->aliases
.begin(); ait
!= it
->aliases
.end(); ++ait
) {
1187 LayoutInfo temp
= *it
;
1188 // alias looks just like real dylib, but has a different name string
1189 const char* aliasPath
= *ait
;
1190 temp
.aliases
.clear();
1191 temp
.aliases
.push_back(aliasPath
);
1192 temp
.info
.pathFileOffset
= fHeaderSize
;
1194 temp
.info
.inode
= pathHash(aliasPath
);
1195 temp
.info
.modTime
= 0;
1197 fDylibAliases
.push_back(temp
);
1198 fHeaderSize
+= strlen(aliasPath
)+1;
1201 std::sort(fDylibAliases
.begin(), fDylibAliases
.end(), ByNameSorter());
1202 //fprintf(stderr, "fHeaderSize=0x%08X, fDylibAliases.size()=%lu\n", fHeaderSize, fDylibAliases.size());
1203 fHeaderSize
= pageAlign(fHeaderSize
);
1205 // check that cache we are about to create for verification purposes has same layout as existing cache
1207 // if no existing cache, say so
1208 if ( fExistingCacheForVerification
== NULL
) {
1209 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
1210 getpid(), fArchGraph
->archName());
1212 const dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)fExistingCacheForVerification
;
1213 const dyldCacheImageInfo
<E
>* cacheEntry
= (dyldCacheImageInfo
<E
>*)(fExistingCacheForVerification
+ header
->imagesOffset());
1214 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++cacheEntry
) {
1215 if ( cacheEntry
->address() != it
->layout
->getSegments()[0].newAddress() ) {
1216 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",
1217 getpid(), fArchGraph
->archName(), it
->layout
->getID().name
, cacheEntry
->address(), it
->layout
->getSegments()[0].newAddress());
1223 if ( fHeaderSize
> FIRST_DYLIB_TEXT_OFFSET
)
1224 throwf("header size overflow: allowed=0x%08X, base=0x%08llX, aliases=0x%08llX", FIRST_DYLIB_TEXT_OFFSET
, baseHeaderSize
, fHeaderSize
-baseHeaderSize
);
1228 template <typename A
>
1229 uint64_t SharedCache
<A
>::getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
)
1231 return proposedNewAddress
;
1234 template <typename A
>
1235 uint64_t SharedCache
<A
>::pathHash(const char* path
)
1238 for (const char* s
=path
; *s
!= '\0'; ++s
)
1244 template <typename A
>
1245 void SharedCache
<A
>::assignNewBaseAddresses(bool verify
)
1247 // first layout TEXT for dylibs
1248 const uint64_t startExecuteAddress
= sharedRegionStartAddress();
1249 uint64_t currentExecuteAddress
= startExecuteAddress
+ FIRST_DYLIB_TEXT_OFFSET
;
1250 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1251 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1252 for (int i
=0; i
< segs
.size(); ++i
) {
1253 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1255 if ( seg
.executable() && !seg
.writable() ) {
1256 // <rdar://problem/15947734> Some dylib require extra alignment
1257 currentExecuteAddress
= (currentExecuteAddress
+ seg
.alignment() - 1) & (-seg
.alignment());
1259 if ( it
->info
.address
== 0 )
1260 it
->info
.address
= currentExecuteAddress
;
1261 seg
.setNewAddress(currentExecuteAddress
);
1262 currentExecuteAddress
+= pageAlign(seg
.size());
1266 // align __TEXT region
1267 currentExecuteAddress
= regionAlign(currentExecuteAddress
);
1269 #define DENSE_PACK 0
1270 // layout __DATA* segments
1271 std::vector
<MachOLayoutAbstraction::Segment
*> dataSegs
;
1272 std::vector
<MachOLayoutAbstraction::Segment
*> dataConstSegs
;
1273 std::vector
<MachOLayoutAbstraction::Segment
*> dataDirtySegs
;
1274 const uint64_t startWritableAddress
= sharedRegionStartWritableAddress(currentExecuteAddress
);
1275 uint64_t currentWritableAddress
= startWritableAddress
;
1276 for (const LayoutInfo
& info
: fDylibs
) {
1277 for (MachOLayoutAbstraction::Segment
& seg
: ((MachOLayoutAbstraction
*)(info
.layout
))->getSegments()) {
1278 if ( seg
.writable() ) {
1279 if ( seg
.executable() )
1280 throw "found writable and executable segment";
1282 if ( strcmp(seg
.name(), "__DATA_CONST") == 0 )
1283 dataConstSegs
.push_back(&seg
);
1284 else if ( strcmp(seg
.name(), "__DATA_DIRTY") == 0 )
1285 dataDirtySegs
.push_back(&seg
);
1287 dataSegs
.push_back(&seg
);
1291 // coalesce all __DATA_CONST segments
1292 for (MachOLayoutAbstraction::Segment
* seg
: dataConstSegs
) {
1294 // start segment at needed alignment
1295 currentWritableAddress
= (currentWritableAddress
+ seg
->sectionsAlignment() - 1) & (-seg
->sectionsAlignment());
1296 seg
->setNewAddress(currentWritableAddress
);
1298 uint64_t justSectionsSize
= seg
->sectionsSize();
1299 currentWritableAddress
= seg
->newAddress() + justSectionsSize
;
1300 seg
->setSize(justSectionsSize
);
1301 if ( seg
->fileSize() > justSectionsSize
)
1302 seg
->setFileSize(justSectionsSize
);
1304 seg
->setNewAddress(currentWritableAddress
);
1305 // pack to 4KB pages
1306 currentWritableAddress
= pageAlign4KB(seg
->newAddress() + seg
->size());
1310 currentWritableAddress
= pageAlign4KB(currentWritableAddress
);
1312 // coalesce all __DATA segments
1313 for (MachOLayoutAbstraction::Segment
* seg
: dataSegs
) {
1315 // start segment at needed alignment
1316 currentWritableAddress
= (currentWritableAddress
+ seg
->sectionsAlignment() - 1) & (-seg
->sectionsAlignment());
1317 seg
->setNewAddress(currentWritableAddress
);
1319 uint64_t justSectionsSize
= seg
->sectionsSize();
1320 currentWritableAddress
= seg
->newAddress() + justSectionsSize
;
1321 seg
->setSize(justSectionsSize
);
1322 if ( seg
->fileSize() > justSectionsSize
)
1323 seg
->setFileSize(justSectionsSize
);
1325 seg
->setNewAddress(currentWritableAddress
);
1326 // pack to 4KB pages
1327 currentWritableAddress
= pageAlign4KB(seg
->newAddress() + seg
->size());
1331 currentWritableAddress
= pageAlign4KB(currentWritableAddress
);
1333 // coalesce all __DATA_DIRTY segments
1334 for (MachOLayoutAbstraction::Segment
* seg
: dataDirtySegs
) {
1335 // start segment at needed alignment
1336 currentWritableAddress
= (currentWritableAddress
+ seg
->sectionsAlignment() - 1) & (-seg
->sectionsAlignment());
1337 seg
->setNewAddress(currentWritableAddress
);
1339 uint64_t justSectionsSize
= seg
->sectionsSize();
1340 currentWritableAddress
= seg
->newAddress() + justSectionsSize
;
1341 seg
->setSize(justSectionsSize
);
1342 if ( seg
->fileSize() > justSectionsSize
)
1343 seg
->setFileSize(justSectionsSize
);
1345 // align __DATA region
1346 currentWritableAddress
= regionAlign(currentWritableAddress
);
1348 // layout all read-only (but not LINKEDIT) segments
1349 const uint64_t startReadOnlyAddress
= sharedRegionStartReadOnlyAddress(currentWritableAddress
, currentExecuteAddress
);
1350 uint64_t currentReadOnlyAddress
= startReadOnlyAddress
;
1351 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1352 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1353 for(int i
=0; i
< segs
.size(); ++i
) {
1354 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1355 if ( seg
.readable() && !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") != 0) ) {
1356 // __UNICODE segment
1357 seg
.setNewAddress(currentReadOnlyAddress
);
1358 currentReadOnlyAddress
+= pageAlign(seg
.size());
1363 // layout all LINKEDIT segments at end of all read-only segments
1364 currentReadOnlyAddress
= regionAlign(currentReadOnlyAddress
); // <rdar://problem/16491435>
1365 fLinkEditsStartAddress
= currentReadOnlyAddress
;
1366 fFirstLinkEditSegment
= NULL
;
1367 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1368 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1369 for(int i
=0; i
< segs
.size(); ++i
) {
1370 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1371 if ( seg
.readable() && !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
1372 if ( fFirstLinkEditSegment
== NULL
)
1373 fFirstLinkEditSegment
= &seg
;
1374 seg
.setNewAddress(currentReadOnlyAddress
);
1375 currentReadOnlyAddress
+= pageAlign(seg
.size());
1379 fLinkEditsTotalUnoptimizedSize
= pageAlign(currentReadOnlyAddress
- fLinkEditsStartAddress
);
1381 // populate large mappings
1382 uint64_t cacheFileOffset
= 0;
1383 if ( currentExecuteAddress
> startExecuteAddress
) {
1384 shared_file_mapping_np executeMapping
;
1385 executeMapping
.sfm_address
= startExecuteAddress
;
1386 executeMapping
.sfm_size
= currentExecuteAddress
- startExecuteAddress
;
1387 executeMapping
.sfm_file_offset
= cacheFileOffset
;
1388 executeMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
1389 executeMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
1390 fMappings
.push_back(executeMapping
);
1391 cacheFileOffset
+= executeMapping
.sfm_size
;
1393 shared_file_mapping_np writableMapping
;
1394 writableMapping
.sfm_address
= startWritableAddress
;
1395 writableMapping
.sfm_size
= currentWritableAddress
- startWritableAddress
;
1396 writableMapping
.sfm_file_offset
= cacheFileOffset
;
1397 writableMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
1398 writableMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
1399 fMappings
.push_back(writableMapping
);
1400 cacheFileOffset
+= writableMapping
.sfm_size
;
1402 // make read-only (contains LINKEDIT segments) last, so it can be cut back when optimized
1403 shared_file_mapping_np readOnlyMapping
;
1404 readOnlyMapping
.sfm_address
= startReadOnlyAddress
;
1405 readOnlyMapping
.sfm_size
= currentReadOnlyAddress
- startReadOnlyAddress
;
1406 readOnlyMapping
.sfm_file_offset
= cacheFileOffset
;
1407 readOnlyMapping
.sfm_max_prot
= VM_PROT_READ
;
1408 readOnlyMapping
.sfm_init_prot
= VM_PROT_READ
;
1409 fMappings
.push_back(readOnlyMapping
);
1410 cacheFileOffset
+= readOnlyMapping
.sfm_size
;
1414 shared_file_mapping_np cacheHeaderMapping
;
1415 cacheHeaderMapping
.sfm_address
= startExecuteAddress
;
1416 cacheHeaderMapping
.sfm_size
= FIRST_DYLIB_TEXT_OFFSET
;
1417 cacheHeaderMapping
.sfm_file_offset
= cacheFileOffset
;
1418 cacheHeaderMapping
.sfm_max_prot
= VM_PROT_READ
;
1419 cacheHeaderMapping
.sfm_init_prot
= VM_PROT_READ
;
1420 fMappings
.push_back(cacheHeaderMapping
);
1421 cacheFileOffset
+= cacheHeaderMapping
.sfm_size
;
1426 template <typename A
>
1427 uint64_t SharedCache
<A
>::cacheFileOffsetForVMAddress(uint64_t vmaddr
) const
1429 for(std::vector
<shared_file_mapping_np
>::const_iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1430 if ( (it
->sfm_address
<= vmaddr
) && (vmaddr
< it
->sfm_address
+it
->sfm_size
) )
1431 return it
->sfm_file_offset
+ vmaddr
- it
->sfm_address
;
1433 throwf("address 0x%0llX is not in cache", vmaddr
);
1436 template <typename A
>
1437 uint64_t SharedCache
<A
>::VMAddressForCacheFileOffset(uint64_t offset
) const
1439 for(std::vector
<shared_file_mapping_np
>::const_iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1440 if ( (it
->sfm_file_offset
<= offset
) && (offset
< it
->sfm_file_offset
+it
->sfm_size
) )
1441 return it
->sfm_address
+ offset
- it
->sfm_file_offset
;
1443 throwf("offset 0x%0llX is not in cache", offset
);
1446 template <typename A
>
1447 void *SharedCache
<A
>::mappedAddressForVMAddress(uint64_t vmaddr
)
1449 if (!vmaddr
) return NULL
;
1450 else return fInMemoryCache
+ cacheFileOffsetForVMAddress(vmaddr
);
1453 template <typename A
>
1454 uint64_t SharedCache
<A
>::VMAddressForMappedAddress(const void *mapaddr
)
1456 if (!mapaddr
) return 0;
1457 uint64_t offset
= (uint8_t *)mapaddr
- (uint8_t *)fInMemoryCache
;
1458 return VMAddressForCacheFileOffset(offset
);
1462 template <typename A
>
1463 bool SharedCache
<A
>::notUpToDate(const void* cache
, unsigned int aliasCount
)
1465 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)cache
;
1466 // not valid if header signature is wrong
1467 const char* archPairName
= fArchGraph
->archName();
1469 strcpy(temp
, "dyld_v1 ");
1470 strcpy(&temp
[15-strlen(archPairName
)], archPairName
);
1471 if ( strcmp(header
->magic(), temp
) != 0 ) {
1473 fprintf(stderr
, "update_dyld_shared_cache[%u] cannot verify %s because current cache file has invalid header\n", getpid(), archPairName
);
1477 fprintf(stderr
, "update_dyld_shared_cache[%u] updating cache because current cache file has invalid header\n", getpid());
1481 // not valid if count of images does not match current images needed
1482 if ( header
->imagesCount() != (fDylibs
.size()+aliasCount
) ) {
1484 fprintf(stderr
, "update_dyld_shared_cache[%u] cannot verify %s because current cache file contains a different set of dylibs\n", getpid(), archPairName
);
1488 fprintf(stderr
, "update_dyld_shared_cache[%u] updating %s cache because current cache file contains a different set of dylibs\n", getpid(), archPairName
);
1492 // get end of TEXT region
1493 const dyldCacheFileMapping
<E
>* textMapping
= (dyldCacheFileMapping
<E
>*)((uint8_t*)cache
+sizeof(dyldCacheHeader
<E
>));
1494 const uint32_t textSize
= textMapping
->size();
1496 // verify every dylib in constructed graph is in existing cache with same inode and modTime
1497 std::map
<const MachOLayoutAbstraction
*, uint32_t> sortingMap
;
1498 const dyldCacheImageInfo
<E
>* imagesStart
= (dyldCacheImageInfo
<E
>*)((uint8_t*)cache
+ header
->imagesOffset());
1499 const dyldCacheImageInfo
<E
>* imagesEnd
= &imagesStart
[header
->imagesCount()];
1500 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1502 //fprintf(stderr, "inode=0x%llX, mTime=0x%llX, path=%s\n", it->info.inode, it->info.modTime, it->layout->getID().name);
1503 for(const dyldCacheImageInfo
<E
>* cacheEntry
= imagesStart
; cacheEntry
< imagesEnd
; ++cacheEntry
) {
1505 if ( cacheEntry
->pathFileOffset() > textSize
) {
1506 throwf("update_dyld_shared_cache[%u]: for arch=%s, image entries corrupt, bad path offset in %s\n",
1507 getpid(), archPairName
, it
->layout
->getID().name
);
1509 // in -verify mode, just match by path and warn if file looks different
1510 if ( strcmp((char*)cache
+cacheEntry
->pathFileOffset(), it
->layout
->getID().name
) == 0 ) {
1512 sortingMap
[it
->layout
] = cacheEntry
-imagesStart
;
1513 if ( (cacheEntry
->inode() != it
->info
.inode
) || (cacheEntry
->modTime() != it
->info
.modTime
) ) {
1514 fprintf(stderr
, "update_dyld_shared_cache[%u] warning: for arch=%s, %s has changed since cache was built\n",
1515 getpid(), archPairName
, it
->layout
->getID().name
);
1521 if ( cacheEntry
->pathFileOffset() > textSize
) {
1522 // cache corrupt, needs to be regenerated
1525 // in normal update mode, everything has to match for cache to be up-to-date
1526 if ( (cacheEntry
->inode() == it
->info
.inode
)
1527 && (cacheEntry
->modTime() == it
->info
.modTime
)
1528 && (strcmp((char*)cache
+cacheEntry
->pathFileOffset(), it
->layout
->getID().name
) == 0) ) {
1536 throwf("update_dyld_shared_cache[%u] can't verify %s cache because %s is not in existing cache\n", getpid(), archPairName
, it
->layout
->getID().name
);
1539 fprintf(stderr
, "update_dyld_shared_cache[%u] updating %s cache because dylib at %s has changed\n", getpid(), archPairName
, it
->layout
->getID().name
);
1544 // all dylibs in existing cache file match those determined need to be in shared cache
1546 // sort fDylibs to match existing cache file so we can compare content
1547 std::sort(fDylibs
.begin(), fDylibs
.end(), Sorter(sortingMap
));
1548 //fprintf(stderr, "dylibs sorted like existing cache:\n");
1549 //for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1550 // fprintf(stderr," %s\n", it->layout->getID().name);
1552 // do regenerate a new cache so we can compare content with existing
1556 // existing cache file is up-to-date, don't need to regenerate
1562 template <typename A
>
1563 bool SharedCache
<A
>::notUpToDate(const char* path
, unsigned int aliasCount
)
1565 // mmap existing cache file
1566 int fd
= ::open(path
, O_RDONLY
);
1569 struct stat stat_buf
;
1570 ::fstat(fd
, &stat_buf
);
1571 uint32_t cacheFileSize
= stat_buf
.st_size
;
1572 uint32_t cacheAllocatedSize
= pageAlign(cacheFileSize
);
1573 uint8_t* mappingAddr
= NULL
;
1574 if ( vm_allocate(mach_task_self(), (vm_address_t
*)(&mappingAddr
), cacheAllocatedSize
, VM_FLAGS_ANYWHERE
) != KERN_SUCCESS
)
1575 throwf("can't vm_allocate cache of size %u", cacheFileSize
);
1576 // <rdar://problem/8960832> update_dyld_shared_cache -verify finds differences
1577 (void)fcntl(fd
, F_NOCACHE
, 1);
1578 ssize_t readResult
= pread(fd
, mappingAddr
, cacheFileSize
, 0);
1579 if ( readResult
!= cacheFileSize
)
1580 throwf("can't read all of existing cache file (%lu of %u): %s", readResult
, cacheFileSize
, path
);
1584 bool result
= this->notUpToDate(mappingAddr
, aliasCount
);
1586 // don't unmap yet, leave so it can be verified later
1587 fExistingCacheForVerification
= mappingAddr
;
1591 vm_deallocate(mach_task_self(), (vm_address_t
)mappingAddr
, cacheAllocatedSize
);
1592 if ( verbose
&& !result
)
1593 fprintf(stderr
, "update_dyld_shared_cache: %s is up-to-date\n", path
);
1600 template <typename A
>
1601 class LinkEditOptimizer
1604 LinkEditOptimizer(const MachOLayoutAbstraction
&, const SharedCache
<A
>&, uint8_t*, StringPool
&);
1605 virtual ~LinkEditOptimizer() {}
1607 void copyBindInfo(uint32_t&);
1608 void copyWeakBindInfo(uint32_t&);
1609 void copyLazyBindInfo(uint32_t&);
1610 void copyExportInfo(uint32_t&);
1611 void copyLocalSymbols(uint32_t symbolTableOffset
, uint32_t&, bool dontMapLocalSymbols
,
1612 uint8_t* cacheStart
, StringPool
& unmappedLocalsStringPool
,
1613 std::vector
<macho_nlist
<typename
A::P
> >& unmappedSymbols
,
1614 std::vector
<LocalSymbolInfo
>& info
);
1615 void copyExportedSymbols(uint32_t symbolTableOffset
, uint32_t&);
1616 void copyImportedSymbols(uint32_t symbolTableOffset
, uint32_t&);
1617 void copyExternalRelocations(uint32_t& offset
);
1618 void copyIndirectSymbolTable(uint32_t& offset
);
1619 void copyFunctionStarts(uint32_t& offset
);
1620 void copyDataInCode(uint32_t& offset
);
1621 void updateLoadCommands(uint64_t newVMAddress
, uint64_t size
, uint32_t stringPoolOffset
,
1622 uint32_t linkEditsFileOffset
, bool keepSignatures
);
1626 typedef typename
A::P P
;
1627 typedef typename
A::P::E E
;
1628 typedef typename
A::P::uint_t pint_t
;
1632 const SharedCache
<A
>& fSharedCache
;
1633 const macho_header
<P
>* fHeader
;
1634 uint8_t* fNewLinkEditStart
;
1635 uint8_t* fLinkEditBase
;
1636 const MachOLayoutAbstraction
& fLayout
;
1637 macho_dyld_info_command
<P
>* fDyldInfo
;
1638 macho_dysymtab_command
<P
>* fDynamicSymbolTable
;
1639 macho_linkedit_data_command
<P
>* fFunctionStarts
;
1640 macho_linkedit_data_command
<P
>* fDataInCode
;
1641 macho_symtab_command
<P
>* fSymbolTableLoadCommand
;
1642 const macho_nlist
<P
>* fSymbolTable
;
1643 const char* fStrings
;
1644 StringPool
& fNewStringPool
;
1645 std::map
<uint32_t,uint32_t> fOldToNewSymbolIndexes
;
1646 uint32_t fBindInfoOffsetIntoNewLinkEdit
;
1647 uint32_t fBindInfoSizeInNewLinkEdit
;
1648 uint32_t fWeakBindInfoOffsetIntoNewLinkEdit
;
1649 uint32_t fWeakBindInfoSizeInNewLinkEdit
;
1650 uint32_t fLazyBindInfoOffsetIntoNewLinkEdit
;
1651 uint32_t fLazyBindInfoSizeInNewLinkEdit
;
1652 uint32_t fExportInfoOffsetIntoNewLinkEdit
;
1653 uint32_t fExportInfoSizeInNewLinkEdit
;
1654 uint32_t fSymbolTableStartOffsetInNewLinkEdit
;
1655 uint32_t fLocalSymbolsStartIndexInNewLinkEdit
;
1656 uint32_t fLocalSymbolsCountInNewLinkEdit
;
1657 uint32_t fExportedSymbolsStartIndexInNewLinkEdit
;
1658 uint32_t fExportedSymbolsCountInNewLinkEdit
;
1659 uint32_t fImportSymbolsStartIndexInNewLinkEdit
;
1660 uint32_t fImportedSymbolsCountInNewLinkEdit
;
1661 uint32_t fExternalRelocationsOffsetIntoNewLinkEdit
;
1662 uint32_t fIndirectSymbolTableOffsetInfoNewLinkEdit
;
1663 uint32_t fFunctionStartsOffsetInNewLinkEdit
;
1664 uint32_t fDataInCodeOffsetInNewLinkEdit
;
1665 uint32_t fUnmappedLocalSymbolsStartIndexInNewLinkEdit
;
1666 uint32_t fUnmappedLocalSymbolsCountInNewLinkEdit
;
1671 template <typename A
>
1672 LinkEditOptimizer
<A
>::LinkEditOptimizer(const MachOLayoutAbstraction
& layout
, const SharedCache
<A
>& sharedCache
, uint8_t* newLinkEdit
, StringPool
& stringPool
)
1673 : fSharedCache(sharedCache
), fLayout(layout
), fLinkEditBase(NULL
), fNewLinkEditStart(newLinkEdit
), fDyldInfo(NULL
),
1674 fDynamicSymbolTable(NULL
), fFunctionStarts(NULL
), fDataInCode(NULL
),
1675 fSymbolTableLoadCommand(NULL
), fSymbolTable(NULL
), fStrings(NULL
), fNewStringPool(stringPool
),
1676 fBindInfoOffsetIntoNewLinkEdit(0), fBindInfoSizeInNewLinkEdit(0),
1677 fWeakBindInfoOffsetIntoNewLinkEdit(0), fWeakBindInfoSizeInNewLinkEdit(0),
1678 fLazyBindInfoOffsetIntoNewLinkEdit(0), fLazyBindInfoSizeInNewLinkEdit(0),
1679 fExportInfoOffsetIntoNewLinkEdit(0), fExportInfoSizeInNewLinkEdit(0),
1680 fSymbolTableStartOffsetInNewLinkEdit(0),
1681 fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
1682 fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
1683 fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
1684 fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0),
1685 fFunctionStartsOffsetInNewLinkEdit(0), fDataInCodeOffsetInNewLinkEdit(0),
1686 fUnmappedLocalSymbolsStartIndexInNewLinkEdit(0), fUnmappedLocalSymbolsCountInNewLinkEdit(0)
1689 fHeader
= (const macho_header
<P
>*)fLayout
.getSegments()[0].mappedAddress();
1691 const std::vector
<MachOLayoutAbstraction::Segment
>& segments
= fLayout
.getSegments();
1692 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator it
= segments
.begin(); it
!= segments
.end(); ++it
) {
1693 const MachOLayoutAbstraction::Segment
& seg
= *it
;
1694 if ( strcmp(seg
.name(), "__LINKEDIT") == 0 )
1695 fLinkEditBase
= (uint8_t*)seg
.mappedAddress() - seg
.fileOffset();
1697 if ( fLinkEditBase
== NULL
)
1698 throw "no __LINKEDIT segment";
1700 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
1701 const uint32_t cmd_count
= fHeader
->ncmds();
1702 const macho_load_command
<P
>* cmd
= cmds
;
1703 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1704 switch (cmd
->cmd()) {
1707 fSymbolTableLoadCommand
= (macho_symtab_command
<P
>*)cmd
;
1708 fSymbolTable
= (macho_nlist
<P
>*)(&fLinkEditBase
[fSymbolTableLoadCommand
->symoff()]);
1709 fStrings
= (char*)&fLinkEditBase
[fSymbolTableLoadCommand
->stroff()];
1713 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
1716 case LC_DYLD_INFO_ONLY
:
1717 fDyldInfo
= (macho_dyld_info_command
<P
>*)cmd
;
1719 case LC_FUNCTION_STARTS
:
1720 fFunctionStarts
= (macho_linkedit_data_command
<P
>*)cmd
;
1721 case LC_DATA_IN_CODE
:
1722 fDataInCode
= (macho_linkedit_data_command
<P
>*)cmd
;
1725 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1727 if ( fSymbolTable
== NULL
)
1728 throw "no LC_SYMTAB";
1729 if ( fDynamicSymbolTable
== NULL
)
1730 throw "no LC_DYSYMTAB";
1735 template <typename A
>
1739 typedef typename
A::P P
;
1740 SymbolSorter(const StringPool
& pool
) : fStringPool(pool
) {}
1741 bool operator()(const macho_nlist
<P
>& left
, const macho_nlist
<P
>& right
) {
1742 return (strcmp(fStringPool
.stringAtIndex(left
.n_strx()) , fStringPool
.stringAtIndex(right
.n_strx())) < 0);
1746 const StringPool
& fStringPool
;
1750 template <typename A
>
1751 void LinkEditOptimizer
<A
>::copyBindInfo(uint32_t& offset
)
1753 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->bind_off() != 0) ) {
1754 fBindInfoOffsetIntoNewLinkEdit
= offset
;
1755 fBindInfoSizeInNewLinkEdit
= fDyldInfo
->bind_size();
1756 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->bind_off()], fDyldInfo
->bind_size());
1757 offset
+= fDyldInfo
->bind_size();
1761 template <typename A
>
1762 void LinkEditOptimizer
<A
>::copyWeakBindInfo(uint32_t& offset
)
1764 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->weak_bind_off() != 0) ) {
1765 fWeakBindInfoOffsetIntoNewLinkEdit
= offset
;
1766 fWeakBindInfoSizeInNewLinkEdit
= fDyldInfo
->weak_bind_size();
1767 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->weak_bind_off()], fDyldInfo
->weak_bind_size());
1768 offset
+= fDyldInfo
->weak_bind_size();
1772 template <typename A
>
1773 void LinkEditOptimizer
<A
>::copyLazyBindInfo(uint32_t& offset
)
1775 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->lazy_bind_off() != 0) ) {
1776 fLazyBindInfoOffsetIntoNewLinkEdit
= offset
;
1777 fLazyBindInfoSizeInNewLinkEdit
= fDyldInfo
->lazy_bind_size();
1778 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->lazy_bind_off()], fDyldInfo
->lazy_bind_size());
1779 offset
+= fDyldInfo
->lazy_bind_size();
1783 template <typename A
>
1784 void LinkEditOptimizer
<A
>::copyExportInfo(uint32_t& offset
)
1786 if ( (fDyldInfo
!= NULL
) && (fLayout
.getDyldInfoExports() != NULL
) ) {
1787 fExportInfoOffsetIntoNewLinkEdit
= offset
;
1788 fExportInfoSizeInNewLinkEdit
= fDyldInfo
->export_size();
1789 memcpy(fNewLinkEditStart
+offset
, fLayout
.getDyldInfoExports(), fDyldInfo
->export_size());
1790 offset
+= fDyldInfo
->export_size();
1795 template <typename A
>
1796 void LinkEditOptimizer
<A
>::copyLocalSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
, bool dontMapLocalSymbols
, uint8_t* cacheStart
,
1797 StringPool
& unmappedLocalsStringPool
, std::vector
<macho_nlist
<P
> >& unmappedSymbols
,
1798 std::vector
<LocalSymbolInfo
>& dylibInfos
)
1800 fLocalSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1801 LocalSymbolInfo localInfo
;
1802 localInfo
.dylibOffset
= ((uint8_t*)fHeader
) - cacheStart
;
1803 localInfo
.nlistStartIndex
= unmappedSymbols
.size();
1804 localInfo
.nlistCount
= 0;
1805 fSymbolTableStartOffsetInNewLinkEdit
= symbolTableOffset
+ symbolIndex
*sizeof(macho_nlist
<P
>);
1806 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1807 const macho_nlist
<P
>* const firstLocal
= &fSymbolTable
[fDynamicSymbolTable
->ilocalsym()];
1808 const macho_nlist
<P
>* const lastLocal
= &fSymbolTable
[fDynamicSymbolTable
->ilocalsym()+fDynamicSymbolTable
->nlocalsym()];
1809 uint32_t oldIndex
= fDynamicSymbolTable
->ilocalsym();
1810 for (const macho_nlist
<P
>* entry
= firstLocal
; entry
< lastLocal
; ++entry
, ++oldIndex
) {
1811 // <rdar://problem/12237639> don't copy stab symbols
1812 if ( (entry
->n_sect() != NO_SECT
) && ((entry
->n_type() & N_STAB
) == 0) ) {
1813 const char* name
= &fStrings
[entry
->n_strx()];
1814 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1815 *newSymbolEntry
= *entry
;
1816 if ( dontMapLocalSymbols
) {
1817 // if local in __text, add <redacted> symbol name to shared cache so backtraces don't have bogus names
1818 if ( entry
->n_sect() == 1 ) {
1819 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique("<redacted>"));
1822 // copy local symbol to unmmapped locals area
1823 unmappedSymbols
.push_back(*entry
);
1824 unmappedSymbols
.back().set_n_strx(unmappedLocalsStringPool
.addUnique(name
));
1827 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(name
));
1832 fLocalSymbolsCountInNewLinkEdit
= symbolIndex
- fLocalSymbolsStartIndexInNewLinkEdit
;
1833 localInfo
.nlistCount
= unmappedSymbols
.size() - localInfo
.nlistStartIndex
;
1834 dylibInfos
.push_back(localInfo
);
1835 //fprintf(stderr, "%u locals starting at %u for %s\n", fLocalSymbolsCountInNewLinkEdit, fLocalSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1839 template <typename A
>
1840 void LinkEditOptimizer
<A
>::copyExportedSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1842 fExportedSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1843 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1844 const macho_nlist
<P
>* const firstExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()];
1845 const macho_nlist
<P
>* const lastExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1846 uint32_t oldIndex
= fDynamicSymbolTable
->iextdefsym();
1847 for (const macho_nlist
<P
>* entry
= firstExport
; entry
< lastExport
; ++entry
, ++oldIndex
) {
1848 if ( ((entry
->n_type() & N_TYPE
) == N_SECT
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0)
1849 && (strncmp(&fStrings
[entry
->n_strx()], "$ld$", 4) != 0) ) {
1850 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1851 *newSymbolEntry
= *entry
;
1852 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1853 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
-fLocalSymbolsStartIndexInNewLinkEdit
;
1857 fExportedSymbolsCountInNewLinkEdit
= symbolIndex
- fExportedSymbolsStartIndexInNewLinkEdit
;
1858 //fprintf(stderr, "%u exports starting at %u for %s\n", fExportedSymbolsCountInNewLinkEdit, fExportedSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1859 // sort by name, so that dyld does not need a toc
1860 macho_nlist
<P
>* newSymbolsStart
= &newSymbolTableStart
[fExportedSymbolsStartIndexInNewLinkEdit
];
1861 macho_nlist
<P
>* newSymbolsEnd
= &newSymbolTableStart
[fExportedSymbolsStartIndexInNewLinkEdit
+fExportedSymbolsCountInNewLinkEdit
];
1862 std::sort(newSymbolsStart
, newSymbolsEnd
, SymbolSorter
<A
>(fNewStringPool
));
1863 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1864 // fprintf(stderr, "\t%u\t %s\n", (entry-newSymbolsStart)+fExportedSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1868 template <typename A
>
1869 void LinkEditOptimizer
<A
>::copyImportedSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1871 fImportSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1872 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1873 const macho_nlist
<P
>* const firstImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()];
1874 const macho_nlist
<P
>* const lastImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()+fDynamicSymbolTable
->nundefsym()];
1875 uint32_t oldIndex
= fDynamicSymbolTable
->iundefsym();
1876 for (const macho_nlist
<P
>* entry
= firstImport
; entry
< lastImport
; ++entry
, ++oldIndex
) {
1877 if ( ((entry
->n_type() & N_TYPE
) == N_UNDF
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0) ) {
1878 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1879 *newSymbolEntry
= *entry
;
1880 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1881 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
-fLocalSymbolsStartIndexInNewLinkEdit
;
1885 fImportedSymbolsCountInNewLinkEdit
= symbolIndex
- fImportSymbolsStartIndexInNewLinkEdit
;
1886 //fprintf(stderr, "%u imports starting at %u for %s\n", fImportedSymbolsCountInNewLinkEdit, fImportSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1887 //macho_nlist<P>* newSymbolsStart = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit];
1888 //macho_nlist<P>* newSymbolsEnd = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit];
1889 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1890 // fprintf(stderr, "\t%u\t%s\n", (entry-newSymbolsStart)+fImportSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1894 template <typename A
>
1895 void LinkEditOptimizer
<A
>::copyExternalRelocations(uint32_t& offset
)
1897 fExternalRelocationsOffsetIntoNewLinkEdit
= offset
;
1898 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(&fLinkEditBase
[fDynamicSymbolTable
->extreloff()]);
1899 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
1900 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1901 macho_relocation_info
<P
>* newReloc
= (macho_relocation_info
<P
>*)(&fNewLinkEditStart
[offset
]);
1903 uint32_t newSymbolIndex
= fOldToNewSymbolIndexes
[reloc
->r_symbolnum()];
1904 //fprintf(stderr, "copyExternalRelocations() old=%d, new=%u name=%s in %s\n", reloc->r_symbolnum(), newSymbolIndex,
1905 // &fStrings[fSymbolTable[reloc->r_symbolnum()].n_strx()], fLayout.getFilePath());
1906 newReloc
->set_r_symbolnum(newSymbolIndex
);
1907 offset
+= sizeof(macho_relocation_info
<P
>);
1911 template <typename A
>
1912 void LinkEditOptimizer
<A
>::copyFunctionStarts(uint32_t& offset
)
1914 if ( fFunctionStarts
!= NULL
) {
1915 fFunctionStartsOffsetInNewLinkEdit
= offset
;
1916 memcpy(&fNewLinkEditStart
[offset
], &fLinkEditBase
[fFunctionStarts
->dataoff()], fFunctionStarts
->datasize());
1917 offset
+= fFunctionStarts
->datasize();
1921 template <typename A
>
1922 void LinkEditOptimizer
<A
>::copyDataInCode(uint32_t& offset
)
1924 if ( fDataInCode
!= NULL
) {
1925 fDataInCodeOffsetInNewLinkEdit
= offset
;
1926 memcpy(&fNewLinkEditStart
[offset
], &fLinkEditBase
[fDataInCode
->dataoff()], fDataInCode
->datasize());
1927 offset
+= fDataInCode
->datasize();
1932 template <typename A
>
1933 void LinkEditOptimizer
<A
>::copyIndirectSymbolTable(uint32_t& offset
)
1935 fIndirectSymbolTableOffsetInfoNewLinkEdit
= offset
;
1936 const uint32_t* const indirectTable
= (uint32_t*)&this->fLinkEditBase
[fDynamicSymbolTable
->indirectsymoff()];
1937 uint32_t* newIndirectTable
= (uint32_t*)&fNewLinkEditStart
[offset
];
1938 for (int i
=0; i
< fDynamicSymbolTable
->nindirectsyms(); ++i
) {
1939 uint32_t oldSymbolIndex
= E::get32(indirectTable
[i
]);
1940 uint32_t newSymbolIndex
= oldSymbolIndex
;
1941 if ( (oldSymbolIndex
!= INDIRECT_SYMBOL_ABS
) && (oldSymbolIndex
!= INDIRECT_SYMBOL_LOCAL
) ) {
1942 newSymbolIndex
= fOldToNewSymbolIndexes
[oldSymbolIndex
];
1943 //fprintf(stderr, "copyIndirectSymbolTable() old=%d, new=%u name=%s in %s\n", oldSymbolIndex, newSymbolIndex,
1944 // &fStrings[fSymbolTable[oldSymbolIndex].n_strx()], fLayout.getFilePath());
1946 E::set32(newIndirectTable
[i
], newSymbolIndex
);
1948 offset
+= (fDynamicSymbolTable
->nindirectsyms() * 4);
1951 template <typename A
>
1952 void LinkEditOptimizer
<A
>::updateLoadCommands(uint64_t newVMAddress
, uint64_t leSize
, uint32_t stringPoolOffset
,
1953 uint32_t linkEditsFileOffset
, bool keepSignatures
)
1955 // set LINKEDIT segment commmand to new merged LINKEDIT
1956 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
1957 const uint32_t cmd_count
= fHeader
->ncmds();
1958 const macho_load_command
<P
>* cmd
= cmds
;
1959 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1960 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
1961 macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
1962 if ( strcmp(seg
->segname(), "__LINKEDIT") == 0 ) {
1963 seg
->set_vmaddr(newVMAddress
);
1964 seg
->set_vmsize(leSize
);
1965 seg
->set_filesize(leSize
);
1966 seg
->set_fileoff(linkEditsFileOffset
);
1969 pint_t oldFileOff
= seg
->fileoff();
1970 // don't alter __TEXT until <rdar://problem/7022345> is fixed
1971 if ( strcmp(seg
->segname(), "__TEXT") != 0 ) {
1972 // update all other segments fileoff to be offset from start of cache file
1973 seg
->set_fileoff(fSharedCache
.cacheFileOffsetForVMAddress(seg
->vmaddr()));
1975 pint_t fileOffsetDelta
= seg
->fileoff() - oldFileOff
;
1976 const MachOLayoutAbstraction::Segment
* layoutSeg
= fLayout
.getSegment(seg
->segname());
1977 if ( layoutSeg
!= NULL
) {
1978 //if ( seg->filesize() != layoutSeg->fileSize() ) {
1979 // fprintf(stderr, "LC filesize=0x%08llX, trimmed seg file size=0x%08llX, seg=%s, path=%s\n",
1980 // seg->filesize(), layoutSeg->fileSize(), seg->segname(), fLayout.getFilePath());
1982 //if ( seg->vmsize() != layoutSeg->size() ) {
1983 // fprintf(stderr, "LC vmsize=0x%08llX, trimmed seg size=0x%08llX, seg=%s, path=%s\n",
1984 // seg->vmsize(), layoutSeg->size(), seg->segname(), fLayout.getFilePath());
1986 seg
->set_vmsize(layoutSeg
->size());
1987 seg
->set_filesize(layoutSeg
->fileSize());
1989 // update all sections in this segment
1990 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)seg
+ sizeof(macho_segment_command
<P
>));
1991 macho_section
<P
>* const sectionsEnd
= §ionsStart
[seg
->nsects()];
1992 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1993 if ( sect
->offset() != 0 )
1994 sect
->set_offset(sect
->offset()+fileOffsetDelta
);
1995 //if ( (sect->flags() & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS )
1996 // fprintf(stderr, "found initializer(s) in %s\n", fLayout.getFilePath());
2000 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
2003 // update dyld_info with new offsets
2004 if ( fDyldInfo
!= NULL
) {
2005 fDyldInfo
->set_rebase_off(0);
2006 fDyldInfo
->set_rebase_size(0);
2007 fDyldInfo
->set_bind_off(linkEditsFileOffset
+fBindInfoOffsetIntoNewLinkEdit
);
2008 fDyldInfo
->set_bind_size(fBindInfoSizeInNewLinkEdit
);
2009 fDyldInfo
->set_weak_bind_off(linkEditsFileOffset
+fWeakBindInfoOffsetIntoNewLinkEdit
);
2010 fDyldInfo
->set_weak_bind_size(fWeakBindInfoSizeInNewLinkEdit
);
2011 fDyldInfo
->set_lazy_bind_off(linkEditsFileOffset
+fLazyBindInfoOffsetIntoNewLinkEdit
);
2012 fDyldInfo
->set_lazy_bind_size(fLazyBindInfoSizeInNewLinkEdit
);
2013 fDyldInfo
->set_export_off(linkEditsFileOffset
+fExportInfoOffsetIntoNewLinkEdit
);
2014 fDyldInfo
->set_export_size(fExportInfoSizeInNewLinkEdit
);
2016 // fprintf(stderr, "dylib %s\n", fLayout.getFilePath());
2017 // fprintf(stderr, " bind_off=0x%08X\n", fDyldInfo->bind_off());
2018 // fprintf(stderr, " export_off=0x%08X\n", fDyldInfo->export_off());
2019 // fprintf(stderr, " export_size=%d\n", fDyldInfo->export_size());
2023 // update symbol table and dynamic symbol table with new offsets
2024 fSymbolTableLoadCommand
->set_symoff(linkEditsFileOffset
+fSymbolTableStartOffsetInNewLinkEdit
);
2025 fSymbolTableLoadCommand
->set_nsyms(fLocalSymbolsCountInNewLinkEdit
+fExportedSymbolsCountInNewLinkEdit
+fImportedSymbolsCountInNewLinkEdit
);
2026 fSymbolTableLoadCommand
->set_stroff(linkEditsFileOffset
+stringPoolOffset
);
2027 fSymbolTableLoadCommand
->set_strsize(fNewStringPool
.size());
2028 fDynamicSymbolTable
->set_ilocalsym(0);
2029 fDynamicSymbolTable
->set_nlocalsym(fLocalSymbolsCountInNewLinkEdit
);
2030 fDynamicSymbolTable
->set_iextdefsym(fExportedSymbolsStartIndexInNewLinkEdit
-fLocalSymbolsStartIndexInNewLinkEdit
);
2031 fDynamicSymbolTable
->set_nextdefsym(fExportedSymbolsCountInNewLinkEdit
);
2032 fDynamicSymbolTable
->set_iundefsym(fImportSymbolsStartIndexInNewLinkEdit
-fLocalSymbolsStartIndexInNewLinkEdit
);
2033 fDynamicSymbolTable
->set_nundefsym(fImportedSymbolsCountInNewLinkEdit
);
2034 fDynamicSymbolTable
->set_tocoff(0);
2035 fDynamicSymbolTable
->set_ntoc(0);
2036 fDynamicSymbolTable
->set_modtaboff(0);
2037 fDynamicSymbolTable
->set_nmodtab(0);
2038 fDynamicSymbolTable
->set_indirectsymoff(linkEditsFileOffset
+fIndirectSymbolTableOffsetInfoNewLinkEdit
);
2039 fDynamicSymbolTable
->set_extreloff(linkEditsFileOffset
+fExternalRelocationsOffsetIntoNewLinkEdit
);
2040 fDynamicSymbolTable
->set_locreloff(0);
2041 fDynamicSymbolTable
->set_nlocrel(0);
2043 // update function starts
2044 if ( fFunctionStarts
!= NULL
) {
2045 fFunctionStarts
->set_dataoff(linkEditsFileOffset
+fFunctionStartsOffsetInNewLinkEdit
);
2047 // update data-in-code info
2048 if ( fDataInCode
!= NULL
) {
2049 fDataInCode
->set_dataoff(linkEditsFileOffset
+fDataInCodeOffsetInNewLinkEdit
);
2052 // now remove load commands no longer needed
2053 const macho_load_command
<P
>* srcCmd
= cmds
;
2054 macho_load_command
<P
>* dstCmd
= (macho_load_command
<P
>*)cmds
;
2055 int32_t newCount
= 0;
2056 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2057 uint32_t cmdSize
= srcCmd
->cmdsize();
2058 switch ( srcCmd
->cmd() ) {
2059 case LC_SEGMENT_SPLIT_INFO
:
2060 case LC_DYLIB_CODE_SIGN_DRS
:
2064 case LC_CODE_SIGNATURE
:
2065 if ( !keepSignatures
)
2067 // otherwise fall into copy case
2069 memmove(dstCmd
, srcCmd
, cmdSize
);
2070 dstCmd
= (macho_load_command
<P
>*)(((uint8_t*)dstCmd
)+cmdSize
);
2074 srcCmd
= (const macho_load_command
<P
>*)(((uint8_t*)srcCmd
)+cmdSize
);
2076 // zero out stuff removed
2077 bzero(dstCmd
, (uint8_t*)srcCmd
- (uint8_t*)dstCmd
);
2079 // update mach_header
2080 macho_header
<P
>* writableHeader
= (macho_header
<P
>*)fHeader
;
2081 writableHeader
->set_ncmds(newCount
);
2082 writableHeader
->set_sizeofcmds((uint8_t*)dstCmd
- ((uint8_t*)fHeader
+ sizeof(macho_header
<P
>)));
2084 // this invalidates some ivars
2085 fDynamicSymbolTable
= NULL
;
2086 fSymbolTableLoadCommand
= NULL
;
2088 fSymbolTable
= NULL
;
2094 template <typename A
>
2095 uint8_t* SharedCache
<A
>::optimizeLINKEDIT(bool keepSignatures
, bool dontMapLocalSymbols
)
2097 // allocate space for optimized LINKEDIT area
2098 uint8_t* newLinkEdit
= new uint8_t[fLinkEditsTotalUnoptimizedSize
];
2099 bzero(newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
2101 // make a string pool
2102 StringPool stringPool
;
2104 // create optimizer object for each LINKEDIT segment
2105 std::vector
<LinkEditOptimizer
<A
>*> optimizers
;
2106 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2107 optimizers
.push_back(new LinkEditOptimizer
<A
>(*it
->layout
, *this, newLinkEdit
, stringPool
));
2110 // rebase info is not copied because images in shared cache are never rebased
2112 // copy weak bind info
2113 uint32_t offset
= 0;
2114 fOffsetOfWeakBindInfoInCombinedLinkedit
= offset
;
2115 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2116 (*it
)->copyWeakBindInfo(offset
);
2120 fOffsetOfExportInfoInCombinedLinkedit
= offset
;
2121 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2122 (*it
)->copyExportInfo(offset
);
2126 fOffsetOfBindInfoInCombinedLinkedit
= offset
;
2127 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2128 (*it
)->copyBindInfo(offset
);
2131 // copy lazy bind info
2132 fOffsetOfLazyBindInfoInCombinedLinkedit
= offset
;
2133 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2134 (*it
)->copyLazyBindInfo(offset
);
2137 // copy symbol table entries
2138 fOffsetOfOldSymbolTableInfoInCombinedLinkedit
= offset
;
2139 uint32_t symbolTableOffset
= offset
;
2140 uint32_t symbolTableIndex
= 0;
2141 if ( dontMapLocalSymbols
)
2142 fUnmappedLocalSymbols
.reserve(16384);
2143 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2144 (*it
)->copyLocalSymbols(symbolTableOffset
, symbolTableIndex
, dontMapLocalSymbols
, fInMemoryCache
,
2145 fUnmappedLocalsStringPool
, fUnmappedLocalSymbols
, fLocalSymbolInfos
);
2146 (*it
)->copyExportedSymbols(symbolTableOffset
, symbolTableIndex
);
2147 (*it
)->copyImportedSymbols(symbolTableOffset
, symbolTableIndex
);
2149 fSizeOfOldSymbolTableInfoInCombinedLinkedit
= symbolTableIndex
* sizeof(macho_nlist
<typename
A::P
>);
2150 offset
= symbolTableOffset
+ fSizeOfOldSymbolTableInfoInCombinedLinkedit
& (-8);
2152 // copy external relocations, 8-byte aligned after end of symbol table
2153 fOffsetOfOldExternalRelocationsInCombinedLinkedit
= offset
;
2154 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2155 (*it
)->copyExternalRelocations(offset
);
2157 fSizeOfOldExternalRelocationsInCombinedLinkedit
= offset
- fOffsetOfOldExternalRelocationsInCombinedLinkedit
;
2159 // copy function starts
2160 fOffsetOfFunctionStartsInCombinedLinkedit
= offset
;
2161 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2162 (*it
)->copyFunctionStarts(offset
);
2164 fSizeOfFunctionStartsInCombinedLinkedit
= offset
- fOffsetOfFunctionStartsInCombinedLinkedit
;
2166 // copy data-in-code info
2167 fOffsetOfDataInCodeInCombinedLinkedit
= offset
;
2168 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2169 (*it
)->copyDataInCode(offset
);
2171 fSizeOfDataInCodeInCombinedLinkedit
= offset
- fOffsetOfDataInCodeInCombinedLinkedit
;
2173 // copy indirect symbol tables
2174 fOffsetOfOldIndirectSymbolsInCombinedLinkedit
= offset
;
2175 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2176 (*it
)->copyIndirectSymbolTable(offset
);
2178 fSizeOfOldIndirectSymbolsInCombinedLinkedit
= offset
- fOffsetOfOldIndirectSymbolsInCombinedLinkedit
;
2181 fOffsetOfOldStringPoolInCombinedLinkedit
= offset
;
2182 memcpy(&newLinkEdit
[offset
], stringPool
.getBuffer(), stringPool
.size());
2183 fSizeOfOldStringPoolInCombinedLinkedit
= stringPool
.size();
2185 // total new size round up to page size
2186 fLinkEditsTotalOptimizedSize
= pageAlign(fOffsetOfOldStringPoolInCombinedLinkedit
+ fSizeOfOldStringPoolInCombinedLinkedit
);
2188 // choose new linkedit file offset
2189 uint32_t linkEditsFileOffset
= cacheFileOffsetForVMAddress(fLinkEditsStartAddress
);
2190 // uint32_t linkEditsFileOffset = fLinkEditsStartAddress - sharedRegionStartAddress();
2192 // update load commands so that all dylibs shared different areas of the same LINKEDIT segment
2193 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2194 (*it
)->updateLoadCommands(fLinkEditsStartAddress
, fLinkEditsTotalOptimizedSize
, fOffsetOfOldStringPoolInCombinedLinkedit
, linkEditsFileOffset
, keepSignatures
);
2197 //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, fLinkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, fLinkEditsTotalOptimizedSize);
2198 //printf(stderr, "mega link edit mapped starting at: %p\n", fFirstLinkEditSegment->mappedAddress());
2200 // overwrite mapped LINKEDIT area with new optimized LINKEDIT segment
2201 memcpy(fFirstLinkEditSegment
->mappedAddress(), newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
2203 // update all LINKEDIT Segment objects to point to same merged LINKEDIT area
2204 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2205 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
2206 for(int i
=0; i
< segs
.size(); ++i
) {
2207 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
2208 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
2209 seg
.setNewAddress(fLinkEditsStartAddress
);
2210 seg
.setMappedAddress(fFirstLinkEditSegment
->mappedAddress());
2211 seg
.setSize(fLinkEditsTotalOptimizedSize
);
2212 seg
.setFileSize(fLinkEditsTotalOptimizedSize
);
2213 seg
.setFileOffset(linkEditsFileOffset
);
2218 // return new end of cache
2219 return (uint8_t*)fFirstLinkEditSegment
->mappedAddress() + regionAlign(fLinkEditsTotalOptimizedSize
);
2223 template <typename A
>
2224 class ObjCSelectorUniquer
2227 objc_opt::string_map fSelectorStrings
;
2228 SharedCache
<A
> *fCache
;
2233 ObjCSelectorUniquer(SharedCache
<A
> *newCache
)
2234 : fSelectorStrings()
2239 typename
A::P::uint_t
visit(typename
A::P::uint_t oldValue
)
2242 const char *s
= (const char *)
2243 fCache
->mappedAddressForVMAddress(oldValue
);
2244 objc_opt::string_map::iterator element
=
2245 fSelectorStrings
.insert(objc_opt::string_map::value_type(s
, oldValue
)).first
;
2246 return (typename
A::P::uint_t
)element
->second
;
2249 objc_opt::string_map
& strings() {
2250 return fSelectorStrings
;
2253 size_t count() const { return fCount
; }
2257 template <typename A
>
2258 class ClassListBuilder
2261 typedef typename
A::P P
;
2263 objc_opt::string_map fClassNames
;
2264 objc_opt::class_map fClasses
;
2266 HeaderInfoOptimizer
<A
>& fHinfos
;
2270 ClassListBuilder(HeaderInfoOptimizer
<A
>& hinfos
)
2277 void visitClass(SharedCache
<A
>* cache
,
2278 const macho_header
<P
>* header
,
2279 objc_class_t
<A
>* cls
)
2281 if (cls
->isMetaClass(cache
)) return;
2283 const char *name
= cls
->getName(cache
);
2284 uint64_t name_vmaddr
= cache
->VMAddressForMappedAddress(name
);
2285 uint64_t cls_vmaddr
= cache
->VMAddressForMappedAddress(cls
);
2286 uint64_t hinfo_vmaddr
= cache
->VMAddressForMappedAddress(fHinfos
.hinfoForHeader(cache
, header
));
2287 fClassNames
.insert(objc_opt::string_map::value_type(name
, name_vmaddr
));
2288 fClasses
.insert(objc_opt::class_map::value_type(name
, std::pair
<uint64_t, uint64_t>(cls_vmaddr
, hinfo_vmaddr
)));
2292 objc_opt::string_map
& classNames() {
2296 objc_opt::class_map
& classes() {
2300 size_t count() const { return fCount
; }
2304 template <typename A
>
2305 class ProtocolOptimizer
2308 typedef typename
A::P P
;
2309 typedef typename
A::P::uint_t pint_t
;
2311 objc_opt::string_map fProtocolNames
;
2312 objc_opt::protocol_map fProtocols
;
2313 size_t fProtocolCount
;
2314 size_t fProtocolReferenceCount
;
2316 friend class ProtocolReferenceWalker
<A
, ProtocolOptimizer
<A
>>;
2317 pint_t
visitProtocolReference(SharedCache
<A
>* cache
, pint_t oldValue
)
2319 objc_protocol_t
<A
>* proto
= (objc_protocol_t
<A
>*)
2320 cache
->mappedAddressForVMAddress(oldValue
);
2321 pint_t newValue
= fProtocols
[proto
->getName(cache
)];
2322 if (oldValue
!= newValue
) fProtocolReferenceCount
++;
2332 , fProtocolReferenceCount(0)
2335 void addProtocols(SharedCache
<A
>* cache
,
2336 const macho_header
<P
>* header
)
2338 PointerSection
<A
, objc_protocol_t
<A
> *>
2339 protocols(cache
, header
, "__DATA", "__objc_protolist");
2341 for (pint_t i
= 0; i
< protocols
.count(); i
++) {
2342 objc_protocol_t
<A
> *proto
= protocols
.get(i
);
2344 const char *name
= proto
->getName(cache
);
2345 if (fProtocolNames
.count(name
) == 0) {
2346 // Need a Swift demangler API in OS before we can handle this
2347 if (0 == strncmp(name
, "_TtP", 4)) {
2348 throw "objc protocol has Swift name";
2350 if (proto
->getSize() > sizeof(objc_protocol_t
<A
>)) {
2351 throw "objc protocol is too big";
2354 uint64_t name_vmaddr
= cache
->VMAddressForMappedAddress(name
);
2355 uint64_t proto_vmaddr
= cache
->VMAddressForMappedAddress(proto
);
2356 fProtocolNames
.insert(objc_opt::string_map::value_type(name
, name_vmaddr
));
2357 fProtocols
.insert(objc_opt::protocol_map::value_type(name
, proto_vmaddr
));
2363 const char *writeProtocols(SharedCache
<A
>* cache
,
2364 uint8_t *& dest
, size_t& remaining
,
2365 std::vector
<void*>& pointersInData
,
2366 pint_t protocolClassVMAddr
)
2368 if (fProtocolCount
== 0) return NULL
;
2370 if (protocolClassVMAddr
== 0) {
2371 return "libobjc's Protocol class symbol not found (metadata not optimized)";
2374 size_t required
= fProtocolCount
* sizeof(objc_protocol_t
<A
>);
2375 if (remaining
< required
) {
2376 return "libobjc's read-write section is too small (metadata not optimized)";
2379 for (objc_opt::protocol_map::iterator iter
= fProtocols
.begin();
2380 iter
!= fProtocols
.end();
2383 objc_protocol_t
<A
>* oldProto
= (objc_protocol_t
<A
>*)
2384 cache
->mappedAddressForVMAddress(iter
->second
);
2386 // Create a new protocol object.
2387 objc_protocol_t
<A
>* proto
= (objc_protocol_t
<A
>*)dest
;
2388 dest
+= sizeof(*proto
);
2389 remaining
-= sizeof(*proto
);
2392 uint32_t oldSize
= oldProto
->getSize();
2393 memcpy(proto
, oldProto
, oldSize
);
2394 if (!proto
->getIsaVMAddr()) {
2395 proto
->setIsaVMAddr(protocolClassVMAddr
);
2397 if (oldSize
< sizeof(*proto
)) {
2398 // Protocol object is old. Populate new fields.
2399 proto
->setSize(sizeof(objc_protocol_t
<A
>));
2400 // missing extendedMethodTypes is already nil
2402 // Some protocol objects are big enough to have the
2403 // demangledName field but don't initialize it.
2404 if (! proto
->getDemangledName(cache
)) {
2405 proto
->setDemangledName(cache
, proto
->getName(cache
));
2407 proto
->setFixedUp();
2409 // Redirect the protocol table at our new object.
2410 iter
->second
= cache
->VMAddressForMappedAddress(proto
);
2412 // Add new rebase entries.
2413 proto
->addPointers(pointersInData
);
2419 void updateReferences(SharedCache
<A
>* cache
, const macho_header
<P
>* header
)
2421 ProtocolReferenceWalker
<A
, ProtocolOptimizer
<A
>> refs(*this);
2422 refs
.walk(cache
, header
);
2425 objc_opt::string_map
& protocolNames() {
2426 return fProtocolNames
;
2429 objc_opt::protocol_map
& protocols() {
2433 size_t protocolCount() const { return fProtocolCount
; }
2434 size_t protocolReferenceCount() const { return fProtocolReferenceCount
; }
2438 static int percent(size_t num
, size_t denom
) {
2439 if (denom
) return (int)(num
/ (double)denom
* 100);
2443 template <typename A
>
2444 void SharedCache
<A
>::optimizeObjC(std::vector
<void*>& pointersInData
)
2449 fprintf(stderr
, "update_dyld_shared_cache: for %s, optimizing objc metadata\n", archName());
2452 size_t headerSize
= P::round_up(sizeof(objc_opt::objc_opt_t
));
2453 if (headerSize
!= sizeof(objc_opt::objc_opt_t
)) {
2454 warn(archName(), "libobjc's optimization structure size is wrong (metadata not optimized)");
2457 // Find libobjc's empty sections to fill in.
2458 // Find libobjc's list of pointers for us to use.
2459 const macho_section
<P
> *optROSection
= NULL
;
2460 const macho_section
<P
> *optRWSection
= NULL
;
2461 const macho_section
<P
> *optPointerListSection
= NULL
;
2462 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2463 if ( strstr(it
->layout
->getFilePath(), "/libobjc.") != NULL
) {
2464 const macho_header
<P
>* mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2465 optROSection
= mh
->getSection("__TEXT", "__objc_opt_ro");
2466 optRWSection
= mh
->getSection("__DATA", "__objc_opt_rw");
2467 optPointerListSection
= mh
->getSection("__DATA", "__objc_opt_ptrs");
2472 if ( optROSection
== NULL
) {
2473 warn(archName(), "libobjc's read-only section missing (metadata not optimized)");
2477 if ( optRWSection
== NULL
) {
2478 warn(archName(), "libobjc's read/write section missing (metadata not optimized)");
2482 if ( optPointerListSection
== NULL
) {
2483 warn(archName(), "libobjc's pointer list section missing (metadata not optimized)");
2487 uint8_t* optROData
= (uint8_t*)mappedAddressForVMAddress(optROSection
->addr());
2488 size_t optRORemaining
= optROSection
->size();
2490 uint8_t* optRWData
= (uint8_t*)mappedAddressForVMAddress(optRWSection
->addr());
2491 size_t optRWRemaining
= optRWSection
->size();
2493 if (optRORemaining
< headerSize
) {
2494 warn(archName(), "libobjc's read-only section is too small (metadata not optimized)");
2497 objc_opt::objc_opt_t
* optROHeader
= (objc_opt::objc_opt_t
*)optROData
;
2498 optROData
+= headerSize
;
2499 optRORemaining
-= headerSize
;
2501 if (E::get32(optROHeader
->version
) != objc_opt::VERSION
) {
2502 warn(archName(), "libobjc's read-only section version is unrecognized (metadata not optimized)");
2506 if (optPointerListSection
->size() < sizeof(objc_opt::objc_opt_pointerlist_tt
<pint_t
>)) {
2507 warn(archName(), "libobjc's pointer list section is too small (metadata not optimized)");
2510 const objc_opt::objc_opt_pointerlist_tt
<pint_t
> *optPointerList
= (const objc_opt::objc_opt_pointerlist_tt
<pint_t
> *)mappedAddressForVMAddress(optPointerListSection
->addr());
2512 // Write nothing to optROHeader until everything else is written.
2513 // If something fails below, libobjc will not use the section.
2515 // Find objc-containing dylibs
2516 std::vector
<LayoutInfo
> objcDylibs
;
2517 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2518 macho_header
<P
> *mh
= (macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2519 if (mh
->getSection("__DATA", "__objc_imageinfo") || mh
->getSegment("__OBJC")) {
2520 objcDylibs
.push_back(*it
);
2526 // This is SAFE: the binaries themselves are unmodified.
2528 std::vector
<LayoutInfo
> addressSortedDylibs
= objcDylibs
;
2529 std::sort(addressSortedDylibs
.begin(), addressSortedDylibs
.end(), ByAddressSorter());
2531 uint64_t hinfoVMAddr
= optRWSection
->addr() + optRWSection
->size() - optRWRemaining
;
2532 HeaderInfoOptimizer
<A
> hinfoOptimizer
;
2533 err
= hinfoOptimizer
.init(objcDylibs
.size(), optRWData
, optRWRemaining
);
2535 warn(archName(), err
);
2538 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= addressSortedDylibs
.begin(); it
!= addressSortedDylibs
.end(); ++it
) {
2539 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2540 hinfoOptimizer
.update(this, mh
, pointersInData
);
2544 // Update selector references and build selector list
2546 // This is SAFE: if we run out of room for the selector table,
2547 // the modified binaries are still usable.
2549 // Heuristic: choose selectors from libraries with more cstring data first.
2550 // This tries to localize selector cstring memory.
2551 ObjCSelectorUniquer
<A
> uniq(this);
2552 std::vector
<LayoutInfo
> sizeSortedDylibs
= objcDylibs
;
2553 std::sort(sizeSortedDylibs
.begin(), sizeSortedDylibs
.end(), ByCStringSectionSizeSorter());
2555 SelectorOptimizer
<A
, ObjCSelectorUniquer
<A
> > selOptimizer(uniq
);
2556 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2557 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2558 LegacySelectorUpdater
<A
, ObjCSelectorUniquer
<A
> >::update(this, mh
, uniq
);
2559 selOptimizer
.optimize(this, mh
);
2562 uint64_t seloptVMAddr
= optROSection
->addr() + optROSection
->size() - optRORemaining
;
2563 objc_opt::objc_selopt_t
*selopt
= new(optROData
) objc_opt::objc_selopt_t
;
2564 err
= selopt
->write(seloptVMAddr
, optRORemaining
, uniq
.strings());
2566 warn(archName(), err
);
2569 optROData
+= selopt
->size();
2570 optRORemaining
-= selopt
->size();
2571 selopt
->byteswap(E::little_endian
), selopt
= NULL
;
2574 // Build class table.
2576 // This is SAFE: the binaries themselves are unmodified.
2578 ClassListBuilder
<A
> classes(hinfoOptimizer
);
2579 ClassWalker
< A
, ClassListBuilder
<A
> > classWalker(classes
);
2580 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2581 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2582 classWalker
.walk(this, mh
);
2585 uint64_t clsoptVMAddr
= optROSection
->addr() + optROSection
->size() - optRORemaining
;
2586 objc_opt::objc_clsopt_t
*clsopt
= new(optROData
) objc_opt::objc_clsopt_t
;
2587 err
= clsopt
->write(clsoptVMAddr
, optRORemaining
,
2588 classes
.classNames(), classes
.classes(), verbose
);
2590 warn(archName(), err
);
2593 optROData
+= clsopt
->size();
2594 optRORemaining
-= clsopt
->size();
2595 size_t duplicateCount
= clsopt
->duplicateCount();
2596 clsopt
->byteswap(E::little_endian
), clsopt
= NULL
;
2599 // Sort method lists.
2601 // This is SAFE: modified binaries are still usable as unsorted lists.
2602 // This must be done AFTER uniquing selectors.
2604 MethodListSorter
<A
> methodSorter
;
2605 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2606 macho_header
<P
> *mh
= (macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2607 methodSorter
.optimize(this, mh
);
2611 // Unique protocols and build protocol table.
2613 // This is SAFE: no protocol references are updated yet
2614 // This must be done AFTER updating method lists.
2616 ProtocolOptimizer
<A
> protocolOptimizer
;
2617 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2618 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2619 protocolOptimizer
.addProtocols(this, mh
);
2622 pint_t protocolClassVMAddr
= P::getP(optPointerList
->protocolClass
);
2623 err
= protocolOptimizer
.writeProtocols(this, optRWData
, optRWRemaining
,
2624 pointersInData
, protocolClassVMAddr
);
2626 warn(archName(), err
);
2630 uint64_t protocoloptVMAddr
= optROSection
->addr() + optROSection
->size() - optRORemaining
;
2631 objc_opt::objc_protocolopt_t
*protocolopt
= new(optROData
) objc_opt::objc_protocolopt_t
;
2632 err
= protocolopt
->write(protocoloptVMAddr
, optRORemaining
,
2633 protocolOptimizer
.protocolNames(),
2634 protocolOptimizer
.protocols(), verbose
);
2636 warn(archName(), err
);
2639 optROData
+= protocolopt
->size();
2640 optRORemaining
-= protocolopt
->size();
2641 protocolopt
->byteswap(E::little_endian
), protocolopt
= NULL
;
2644 // Redirect protocol references to the uniqued protocols.
2646 // This is SAFE: the new protocol objects are still usable as-is.
2647 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2648 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2649 protocolOptimizer
.updateReferences(this, mh
);
2653 // Repair ivar offsets.
2655 // This is SAFE: the runtime always validates ivar offsets at runtime.
2657 IvarOffsetOptimizer
<A
> ivarOffsetOptimizer
;
2658 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2659 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2660 ivarOffsetOptimizer
.findGCClasses(this, mh
);
2662 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2663 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2664 ivarOffsetOptimizer
.optimize(this, mh
);
2668 // Success. Mark dylibs as optimized.
2669 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2670 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2671 const macho_section
<P
> *imageInfoSection
;
2672 imageInfoSection
= mh
->getSection("__DATA", "__objc_imageinfo");
2673 if (!imageInfoSection
) {
2674 imageInfoSection
= mh
->getSection("__OBJC", "__image_info");
2676 if (imageInfoSection
) {
2677 objc_image_info
<A
> *info
= (objc_image_info
<A
> *)
2678 mappedAddressForVMAddress(imageInfoSection
->addr());
2679 info
->setOptimizedByDyld();
2684 // Success. Update RO header last.
2685 E::set32(optROHeader
->selopt_offset
, seloptVMAddr
- optROSection
->addr());
2686 E::set32(optROHeader
->clsopt_offset
, clsoptVMAddr
- optROSection
->addr());
2687 E::set32(optROHeader
->protocolopt_offset
, protocoloptVMAddr
- optROSection
->addr());
2688 E::set32(optROHeader
->headeropt_offset
, hinfoVMAddr
- optROSection
->addr());
2691 size_t roSize
= optROSection
->size() - optRORemaining
;
2692 size_t rwSize
= optRWSection
->size() - optRWRemaining
;
2693 fprintf(stderr
, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
2694 "(%d%%) used in libobjc read-only optimization section\n",
2695 archName(), roSize
, optROSection
->size(),
2696 percent(roSize
, optROSection
->size()));
2697 fprintf(stderr
, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
2698 "(%d%%) used in libobjc read/write optimization section\n",
2699 archName(), rwSize
, optRWSection
->size(),
2700 percent(rwSize
, optRWSection
->size()));
2701 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2702 "uniqued %zu selectors\n",
2703 archName(), uniq
.strings().size());
2704 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2705 "updated %zu selector references\n",
2706 archName(), uniq
.count());
2707 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2708 "uniqued %zu protocols\n",
2709 archName(), protocolOptimizer
.protocolCount());
2710 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2711 "updated %zu protocol references\n",
2712 archName(), protocolOptimizer
.protocolReferenceCount());
2713 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2714 "updated %zu ivar offsets\n",
2715 archName(), ivarOffsetOptimizer
.optimized());
2716 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2717 "sorted %zu method lists\n",
2718 archName(), methodSorter
.optimized());
2719 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2720 "recorded %zu classes (%zu duplicates)\n",
2721 archName(), classes
.classNames().size(), duplicateCount
);
2722 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2723 "wrote objc metadata optimization version %d\n",
2724 archName(), objc_opt::VERSION
);
2731 static const char* sCleanupFile
= NULL
;
2732 static void cleanup(int sig
)
2734 ::signal(sig
, SIG_DFL
);
2735 if ( sCleanupFile
!= NULL
)
2736 ::unlink(sCleanupFile
);
2738 // fprintf(stderr, "update_dyld_shared_cache: deleting temp file in response to a signal\n");
2739 if ( sig
== SIGINT
)
2744 // <rdar://problem/10730767> update_dyld_shared_cache should use sync_volume_np() instead of sync()
2745 static void sync_volume(const char* volumePath
)
2747 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
2748 int error
= sync_volume_np(volumePath
, SYNC_VOLUME_FULLSYNC
|SYNC_VOLUME_FULLSYNC
);
2750 int full_sync
= 3; // SYNC_VOLUME_FULLSYNC | SYNC_VOLUME_FULLSYNC
2752 if ( fsctl(volumePath
, 0x80004101 /*FSCTL_SYNC_VOLUME*/, &full_sync
, 0) == -1)
2760 // <rdar://problem/12552226> update shared cache should sign the shared cache
2761 static bool adhoc_codesign_share_cache(const char* path
)
2763 CFURLRef target
= ::CFURLCreateFromFileSystemRepresentation(NULL
, (const UInt8
*)path
, strlen(path
), FALSE
);
2764 if ( target
== NULL
)
2767 SecStaticCodeRef code
;
2768 OSStatus status
= ::SecStaticCodeCreateWithPath(target
, kSecCSDefaultFlags
, &code
);
2771 ::fprintf(stderr
, "codesign: failed to create url to signed object\n");
2775 const void * keys
[1] = { (void *)kSecCodeSignerIdentity
} ;
2776 const void * values
[1] = { (void *)kCFNull
};
2777 CFDictionaryRef params
= ::CFDictionaryCreate(NULL
, keys
, values
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2778 if ( params
== NULL
) {
2783 SecCodeSignerRef signer
;
2784 status
= ::SecCodeSignerCreate(params
, kSecCSDefaultFlags
, &signer
);
2788 ::fprintf(stderr
, "codesign: failed to create signer object\n");
2792 status
= ::SecCodeSignerAddSignatureWithErrors(signer
, code
, kSecCSDefaultFlags
, NULL
);
2796 ::fprintf(stderr
, "codesign: failed to sign object: %s\n", path
);
2801 ::fprintf(stderr
, "codesigning complete of %s\n", path
);
2806 template <typename A
>
2807 void SharedCache
<A
>::writeCacheFile(const char *cacheFilePath
, uint8_t *cacheFileBuffer
, uint32_t cacheFileSize
, bool deleteOldCache
) {
2808 char tempCachePath
[strlen(cacheFilePath
)+16];
2809 sprintf(tempCachePath
, "%s.tmp%u", cacheFilePath
, getpid());
2812 // install signal handlers to delete temp file if program is killed
2813 sCleanupFile
= tempCachePath
;
2814 ::signal(SIGINT
, cleanup
);
2815 ::signal(SIGBUS
, cleanup
);
2816 ::signal(SIGSEGV
, cleanup
);
2818 // compute UUID of whole cache
2820 CC_MD5(cacheFileBuffer
, cacheFileSize
, digest
);
2821 // <rdar://problem/6723729> uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
2822 digest
[6] = ( digest
[6] & 0x0F ) | ( 3 << 4 );
2823 digest
[8] = ( digest
[8] & 0x3F ) | 0x80;
2824 ((dyldCacheHeader
<E
>*)cacheFileBuffer
)->set_uuid(digest
);
2826 // create var/db/dyld dirs if needed
2827 char dyldDirs
[1024];
2828 strcpy(dyldDirs
, cacheFilePath
);
2829 char* lastSlash
= strrchr(dyldDirs
, '/');
2830 if ( lastSlash
!= NULL
)
2831 lastSlash
[1] = '\0';
2832 struct stat stat_buf
;
2833 if ( stat(dyldDirs
, &stat_buf
) != 0 ) {
2834 const char* afterSlash
= &dyldDirs
[1];
2836 while ( (slash
= strchr(afterSlash
, '/')) != NULL
) {
2838 ::mkdir(dyldDirs
, S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
);
2840 afterSlash
= slash
+1;
2844 // create temp file for cache
2845 int fd
= ::open(tempCachePath
, O_CREAT
| O_RDWR
| O_TRUNC
, 0644);
2847 throwf("can't create temp file %s, errno=%d", tempCachePath
, errno
);
2849 // try to allocate whole cache file contiguously
2850 fstore_t fcntlSpec
= { F_ALLOCATECONTIG
|F_ALLOCATEALL
, F_PEOFPOSMODE
, 0, cacheFileSize
, 0 };
2851 ::fcntl(fd
, F_PREALLOCATE
, &fcntlSpec
);
2853 // write out cache file
2855 fprintf(stderr
, "update_dyld_shared_cache: writing cache to disk: %s\n", tempCachePath
);
2856 if ( ::pwrite(fd
, cacheFileBuffer
, cacheFileSize
, 0) != cacheFileSize
)
2857 throwf("write() failure creating cache file, errno=%d", errno
);
2859 // flush to disk and close
2860 int result
= ::fcntl(fd
, F_FULLFSYNC
, NULL
);
2862 fprintf(stderr
, "update_dyld_shared_cache: warning, fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno
, tempCachePath
);
2863 result
= ::close(fd
);
2865 fprintf(stderr
, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno
, tempCachePath
);
2868 adhoc_codesign_share_cache(tempCachePath
);
2870 if ( deleteOldCache
) {
2871 const char* pathLastSlash
= strrchr(cacheFilePath
, '/');
2872 if ( pathLastSlash
!= NULL
) {
2873 result
= ::unlink(cacheFilePath
);
2874 if ( result
!= 0 ) {
2875 if ( errno
!= ENOENT
)
2876 fprintf(stderr
, "update_dyld_shared_cache: warning, unable to remove existing cache %s because errno=%d\n", cacheFilePath
, errno
);
2881 // move new cache file to correct location for use after reboot
2883 fprintf(stderr
, "update_dyld_shared_cache: atomically moving cache file into place: %s\n", cacheFilePath
);
2884 result
= ::rename(tempCachePath
, cacheFilePath
);
2886 throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath
, cacheFilePath
, errno
);
2888 // flush everything to disk to assure rename() gets recorded
2889 sync_volume(cacheFilePath
);
2891 // restore default signal handlers
2892 ::signal(SIGINT
, SIG_DFL
);
2893 ::signal(SIGBUS
, SIG_DFL
);
2894 ::signal(SIGSEGV
, SIG_DFL
);
2897 // remove temp cache file
2898 ::unlink(tempCachePath
);
2904 template <> bool SharedCache
<x86_64
>::addCacheSlideInfo(){ return true; }
2905 template <> bool SharedCache
<arm
>::addCacheSlideInfo() { return true; }
2906 template <> bool SharedCache
<x86
>::addCacheSlideInfo() { return false; }
2907 template <> bool SharedCache
<arm64
>::addCacheSlideInfo() { return true; }
2910 template <typename A
>
2911 bool SharedCache
<A
>::update(bool force
, bool optimize
, bool deleteExistingFirst
, int archIndex
,
2912 int archCount
, bool keepSignatures
, bool dontMapLocalSymbols
)
2914 bool didUpdate
= false;
2915 bool canEmitDevelopmentCache
= true;
2916 char devCacheFilePath
[strlen(fCacheFilePath
)+strlen(".development")];
2917 char fileListFilePath
[strlen(fCacheFilePath
)+strlen(".list")];
2918 sprintf(devCacheFilePath
, "%s.development", fCacheFilePath
);
2919 sprintf(fileListFilePath
, "%s.list", fCacheFilePath
);
2920 std::vector
<const char *> paths
;
2922 // already up to date?
2923 if ( force
|| fExistingIsNotUpToDate
) {
2925 fprintf(stderr
, "update_dyld_shared_cache: regenerating %s\n", fCacheFilePath
);
2926 if ( fDylibs
.size() == 0 ) {
2927 fprintf(stderr
, "update_dyld_shared_cache: warning, empty cache not generated for arch %s\n", archName());
2930 // delete existing cache while building the new one
2931 // this is a flag to dyld to stop pinging update_dyld_shared_cache
2932 if ( deleteExistingFirst
)
2933 ::unlink(fCacheFilePath
);
2934 uint8_t* inMemoryCache
= NULL
;
2935 uint32_t allocatedCacheSize
= 0;
2937 // allocate a memory block to hold cache
2938 uint32_t cacheFileSize
= 0;
2939 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
2940 uint32_t end
= it
->sfm_file_offset
+ it
->sfm_size
;
2941 if ( end
> cacheFileSize
)
2942 cacheFileSize
= end
;
2944 if ( vm_allocate(mach_task_self(), (vm_address_t
*)(&inMemoryCache
), cacheFileSize
, VM_FLAGS_ANYWHERE
) != KERN_SUCCESS
)
2945 throwf("can't vm_allocate cache of size %u", cacheFileSize
);
2946 allocatedCacheSize
= cacheFileSize
;
2947 fInMemoryCache
= inMemoryCache
;
2950 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2951 const char* archPairName
= fArchGraph
->archName();
2953 strcpy(temp
, "dyld_v1 ");
2954 strcpy(&temp
[15-strlen(archPairName
)], archPairName
);
2955 header
->set_magic(temp
);
2956 //header->set_architecture(arch());
2957 header
->set_mappingOffset(sizeof(dyldCacheHeader
<E
>));
2958 header
->set_mappingCount(fMappings
.size());
2959 header
->set_imagesOffset(header
->mappingOffset() + fMappings
.size()*sizeof(dyldCacheFileMapping
<E
>));
2960 header
->set_imagesCount(fDylibs
.size()+fDylibAliases
.size());
2961 header
->set_dyldBaseAddress(fDyldBaseAddress
);
2962 header
->set_codeSignatureOffset(cacheFileSize
);
2963 header
->set_codeSignatureSize(0);
2964 header
->set_slideInfoOffset(0);
2965 header
->set_slideInfoSize(0);
2966 header
->set_localSymbolsOffset(0);
2967 header
->set_localSymbolsSize(0);
2970 dyldCacheFileMapping
<E
>* mapping
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
2971 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
2973 fprintf(stderr
, "update_dyld_shared_cache: cache mappings: address=0x%0llX, size=0x%0llX, fileOffset=0x%0llX, prot=0x%X\n",
2974 it
->sfm_address
, it
->sfm_size
, it
->sfm_file_offset
, it
->sfm_init_prot
);
2975 mapping
->set_address(it
->sfm_address
);
2976 mapping
->set_size(it
->sfm_size
);
2977 mapping
->set_file_offset(it
->sfm_file_offset
);
2978 mapping
->set_max_prot(it
->sfm_max_prot
);
2979 mapping
->set_init_prot(it
->sfm_init_prot
);
2983 // fill in image table
2984 dyldCacheImageInfo
<E
>* image
= (dyldCacheImageInfo
<E
>*)mapping
;
2985 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2986 image
->set_address(it
->info
.address
);
2987 image
->set_modTime(it
->info
.modTime
);
2988 image
->set_inode(it
->info
.inode
);
2989 image
->set_pathFileOffset(cacheFileOffsetForVMAddress(it
->info
.address
+it
->info
.pathFileOffset
));
2993 // add aliases to end of image table
2994 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibAliases
.begin(); it
!= fDylibAliases
.end(); ++it
) {
2995 image
->set_address(it
->info
.address
);
2996 image
->set_modTime(it
->info
.modTime
);
2997 image
->set_inode(it
->info
.inode
);
2998 image
->set_pathFileOffset(it
->info
.pathFileOffset
);
2999 strcpy((char*)inMemoryCache
+it
->info
.pathFileOffset
, it
->aliases
[0]);
3000 //fprintf(stderr, "adding alias to offset 0x%08X %s\n", it->info.pathFileOffset, it->aliases[0]);
3004 // copy each segment to cache buffer
3005 const int dylibCount
= fDylibs
.size();
3007 int progressIndex
= 0;
3008 bool foundLibSystem
= false;
3009 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++dylibIndex
) {
3010 const char* path
= it
->layout
->getFilePath();
3011 int src
= ::open(path
, O_RDONLY
, 0);
3013 throwf("can't open file %s, errno=%d", it
->layout
->getID().name
, errno
);
3014 // mark source as "don't cache"
3015 (void)fcntl(src
, F_NOCACHE
, 1);
3016 // verify file has not changed since dependency analysis
3017 struct stat stat_buf
;
3018 if ( fstat(src
, &stat_buf
) == -1)
3019 throwf("can't stat open file %s, errno=%d", path
, errno
);
3020 if ( (it
->layout
->getInode() != stat_buf
.st_ino
) )
3021 throwf("file inode changed from %llu to %llu during cache creation: %s", it
->layout
->getInode(), stat_buf
.st_ino
, path
);
3022 else if ( it
->layout
->getLastModTime() != stat_buf
.st_mtime
)
3023 throwf("file mtime changed from 0x%lX to 0x%lX during cache creation: %s", it
->layout
->getLastModTime(), stat_buf
.st_mtime
, path
);
3024 if ( strcmp(it
->layout
->getID().name
, "/usr/lib/libSystem.B.dylib") == 0 )
3025 foundLibSystem
= true;
3027 fprintf(stderr
, "update_dyld_shared_cache: copying %s to cache\n", it
->layout
->getFilePath());
3029 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
3030 for (int i
=0; i
< segs
.size(); ++i
) {
3031 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
3033 fprintf(stderr
, "\t\tsegment %s, size=0x%0llX, cache address=0x%0llX, buffer address=%p\n",
3034 seg
.name(), seg
.size(), seg
.newAddress(), &inMemoryCache
[cacheFileOffsetForVMAddress(seg
.newAddress())]);
3036 if ( seg
.size() > 0 ) {
3037 const uint64_t segmentSrcStartOffset
= it
->layout
->getOffsetInUniversalFile()+seg
.fileOffset();
3038 const uint64_t segmentSize
= seg
.fileSize();
3039 const uint64_t segmentDstStartOffset
= cacheFileOffsetForVMAddress(seg
.newAddress());
3040 ssize_t readResult
= ::pread(src
, &inMemoryCache
[segmentDstStartOffset
], segmentSize
, segmentSrcStartOffset
);
3041 if ( readResult
!= segmentSize
) {
3042 if ( readResult
== -1 )
3043 throwf("read failure copying dylib errno=%d for %s", errno
, it
->layout
->getID().name
);
3045 throwf("read failure copying dylib. Read of %lld bytes at file offset %lld returned %ld for %s",
3046 segmentSize
, segmentSrcStartOffset
, readResult
, it
->layout
->getID().name
);
3051 catch (const char* msg
) {
3052 throwf("%s while copying %s to shared cache", msg
, it
->layout
->getID().name
);
3055 paths
.push_back(it
->layout
->getID().name
);
3057 // assuming read takes 40% of time
3058 int nextProgressIndex
= archIndex
*100+(40*dylibIndex
)/dylibCount
;
3059 if ( nextProgressIndex
!= progressIndex
)
3060 fprintf(stdout
, "%3u/%u\n", nextProgressIndex
, archCount
*100);
3061 progressIndex
= nextProgressIndex
;
3064 if ( !foundLibSystem
)
3065 throw "cache would be missing required dylib /usr/lib/libSystem.B.dylib";
3067 // set mapped address for each segment
3068 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
3069 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
3070 for (int i
=0; i
< segs
.size(); ++i
) {
3071 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
3072 if ( seg
.size() > 0 )
3073 seg
.setMappedAddress(inMemoryCache
+ cacheFileOffsetForVMAddress(seg
.newAddress()));
3074 //fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
3078 // also construct list of all pointers in cache to other things in cache
3079 std::vector
<void*> pointersInData
;
3080 pointersInData
.reserve(1024);
3082 // rebase each dylib in shared cache
3083 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
3085 Rebaser
<A
> r(*it
->layout
);
3086 if (!r
.rebase(pointersInData
)) {
3087 canEmitDevelopmentCache
= false;
3088 fprintf(stderr
, "update_dyld_shared_cache: Omitting development cache for %s, cannot rebase dylib into place for %s\n", archName(), it
->layout
->getID().name
);
3091 // fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
3093 catch (const char* msg
) {
3094 throwf("%s in %s", msg
, it
->layout
->getID().name
);
3099 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs
.size());
3100 // instantiate a Binder for each image and add to map
3101 typename Binder
<A
>::Map map
;
3102 std::vector
<Binder
<A
>*> binders
;
3103 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
3104 //fprintf(stderr, "binding %s\n", it->layout->getID().name);
3105 Binder
<A
>* binder
= new Binder
<A
>(*it
->layout
);
3106 binders
.push_back(binder
);
3107 // only add dylibs to map
3108 if ( it
->layout
->getID().name
!= NULL
)
3109 map
[it
->layout
->getID().name
] = binder
;
3111 // tell each Binder about the others
3112 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
3113 (*it
)->setDependentBinders(map
);
3116 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
3118 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it
)->getDylibID());
3120 (*it
)->bind(pointersInData
);
3122 catch (const char* msg
) {
3123 throwf("%s in %s", msg
, (*it
)->getDylibID());
3127 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
3128 const macho_header
<P
>* fHeader
= (const macho_header
<P
>*)it
->layout
->getSegments()[0].mappedAddress();
3129 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
3130 const uint32_t cmd_count
= fHeader
->ncmds();
3131 const macho_load_command
<P
>* cmd
= cmds
;
3132 macho_dyld_info_command
<P
>* fDyldInfo
;
3133 uint64_t originalLinkEditVMAddr
= 0;
3134 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
3135 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
3136 macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
3137 if ( strcmp(seg
->segname(), "__LINKEDIT") != 0 ) {
3138 pint_t oldFileOff
= seg
->fileoff();
3139 originalLinkEditVMAddr
+= seg
->vmsize();
3140 // don't alter __TEXT until <rdar://problem/7022345> is fixed
3141 if ( strcmp(seg
->segname(), "__TEXT") != 0 ) {
3142 // update all other segments fileoff to be offset from start of cache file
3143 seg
->set_fileoff(cacheFileOffsetForVMAddress(seg
->vmaddr()));
3145 pint_t fileOffsetDelta
= seg
->fileoff() - oldFileOff
;
3146 const MachOLayoutAbstraction::Segment
* layoutSeg
= it
->layout
->getSegment(seg
->segname());
3147 if ( layoutSeg
!= NULL
) {
3148 seg
->set_vmsize(layoutSeg
->size());
3149 seg
->set_filesize(layoutSeg
->fileSize());
3151 // update all sections in this segment
3152 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)seg
+ sizeof(macho_segment_command
<P
>));
3153 macho_section
<P
>* const sectionsEnd
= §ionsStart
[seg
->nsects()];
3154 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
3155 if ( sect
->offset() != 0 )
3156 sect
->set_offset(sect
->offset()+fileOffsetDelta
);
3159 } else if (cmd
->cmd() == LC_DYLD_INFO
|| cmd
->cmd() == LC_DYLD_INFO_ONLY
) {
3160 fDyldInfo
= (macho_dyld_info_command
<P
>*)cmd
;
3162 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
3167 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
3171 catch (const char* msg
) {
3172 throwf("%s in %s", msg
, (*it
)->getDylibID());
3177 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
3181 // merge/optimize all LINKEDIT segments
3184 fprintf(stderr
, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize
/(1024*1024));
3185 cacheFileSize
= (this->optimizeLINKEDIT(keepSignatures
, dontMapLocalSymbols
) - inMemoryCache
);
3187 fprintf(stderr
, "update_dyld_shared_cache: optimized cache file size %uMB\n", cacheFileSize
/(1024*1024));
3188 // update header to reduce mapping size
3189 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
3190 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
3191 dyldCacheFileMapping
<E
>* lastMapping
= &mappings
[cacheHeader
->mappingCount()-1];
3192 lastMapping
->set_size(cacheFileSize
-lastMapping
->file_offset());
3193 // update fMappings so .map file will print correctly
3194 fMappings
.back().sfm_size
= cacheFileSize
-fMappings
.back().sfm_file_offset
;
3196 //fprintf(stderr, "update_dyld_shared_cache: changing end of cache address from 0x%08llX to 0x%08llX\n",
3197 // header->codeSignatureOffset(), fMappings.back().sfm_address + fMappings.back().sfm_size);
3198 header
->set_codeSignatureOffset(fMappings
.back().sfm_file_offset
+ fMappings
.back().sfm_size
);
3201 // dump dev cache with optimized linkedit, but not ObjC optimizations
3202 if (iPhoneOS
&& canEmitDevelopmentCache
) {
3203 int fileListFD
= ::open(fileListFilePath
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0644);
3204 if ( fileListFD
!= -1 ) {
3205 for (const char* path
: paths
) {
3206 write(fileListFD
, path
, strlen(path
)+1);
3207 write(fileListFD
, "\n", 1);
3212 ((dyldCacheHeader
<E
>*)inMemoryCache
)->set_cacheType(1);
3213 writeCacheFile(devCacheFilePath
, inMemoryCache
, cacheFileSize
, fCacheFileInFinalLocation
);
3216 // unique objc selectors and update other objc metadata
3218 optimizeObjC(pointersInData
);
3220 // assuming objc optimizations takes 15% of time
3221 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*55, archCount
*100);
3225 if ( addCacheSlideInfo() ) {
3226 // build bitmap of which pointers need sliding
3227 uint8_t* const dataStart
= &inMemoryCache
[fMappings
[1].sfm_file_offset
]; // R/W mapping is always second
3228 uint8_t* const dataEnd
= &inMemoryCache
[fMappings
[1].sfm_file_offset
+fMappings
[1].sfm_size
];
3229 const int bitmapSize
= (dataEnd
- dataStart
)/(4*8);
3230 uint8_t* bitmap
= (uint8_t*)calloc(bitmapSize
, 1);
3231 void* lastPointer
= inMemoryCache
;
3232 for(std::vector
<void*>::iterator pit
=pointersInData
.begin(); pit
!= pointersInData
.end(); ++pit
) {
3233 if ( *pit
!= lastPointer
) {
3235 if ( (p
< dataStart
) || ( p
> dataEnd
) )
3236 throwf("DATA pointer for sliding, out of range 0x%08lX\n", (long)((uint8_t*)p
-inMemoryCache
));
3237 long offset
= (long)((uint8_t*)p
- dataStart
);
3238 if ( (offset
% 4) != 0 )
3239 throwf("pointer not 4-byte aligned in DATA offset 0x%08lX\n", offset
);
3240 long byteIndex
= offset
/ (4*8);
3241 long bitInByte
= (offset
% 32) >> 2;
3242 bitmap
[byteIndex
] |= (1 << bitInByte
);
3247 // allocate worst case size block of all slide info
3248 const int entry_size
= 4096/(8*4); // 8 bits per byte, possible pointer every 4 bytes.
3249 const int toc_count
= bitmapSize
/entry_size
;
3250 int slideInfoSize
= sizeof(dyldCacheSlideInfo
<E
>) + 2*toc_count
+ entry_size
*(toc_count
+1);
3251 dyldCacheSlideInfo
<E
>* slideInfo
= (dyldCacheSlideInfo
<E
>*)calloc(slideInfoSize
, 1);
3252 slideInfo
->set_version(1);
3253 slideInfo
->set_toc_offset(sizeof(dyldCacheSlideInfo
<E
>));
3254 slideInfo
->set_toc_count(toc_count
);
3255 slideInfo
->set_entries_offset((slideInfo
->toc_offset()+2*toc_count
+127)&(-128));
3256 slideInfo
->set_entries_count(0);
3257 slideInfo
->set_entries_size(entry_size
);
3258 // append each unique entry
3259 const dyldCacheSlideInfoEntry
* bitmapAsEntries
= (dyldCacheSlideInfoEntry
*)bitmap
;
3260 dyldCacheSlideInfoEntry
* const entriesInSlidInfo
= (dyldCacheSlideInfoEntry
*)((char*)slideInfo
+slideInfo
->entries_offset());
3261 int entry_count
= 0;
3262 for (int i
=0; i
< toc_count
; ++i
) {
3263 const dyldCacheSlideInfoEntry
* thisEntry
= &bitmapAsEntries
[i
];
3264 // see if it is same as one already added
3266 for (int j
=0; j
< entry_count
; ++j
) {
3267 if ( memcmp(thisEntry
, &entriesInSlidInfo
[j
], entry_size
) == 0 ) {
3268 //fprintf(stderr, "toc[%d] optimized to %d\n", i, j);
3269 slideInfo
->set_toc(i
, j
);
3276 memcpy(&entriesInSlidInfo
[entry_count
], thisEntry
, entry_size
);
3277 slideInfo
->set_toc(i
, entry_count
++);
3280 slideInfo
->set_entries_count(entry_count
);
3282 int slideInfoPageSize
= regionAlign(slideInfo
->entries_offset() + entry_count
*entry_size
);
3283 cacheFileSize
+= slideInfoPageSize
;
3285 // update mappings to increase RO size
3286 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
3287 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
3288 dyldCacheFileMapping
<E
>* lastMapping
= &mappings
[cacheHeader
->mappingCount()-1];
3289 lastMapping
->set_size(lastMapping
->size()+slideInfoPageSize
);
3291 // update header to show location of slidePointers
3292 cacheHeader
->set_slideInfoOffset(cacheHeader
->codeSignatureOffset());
3293 cacheHeader
->set_slideInfoSize(slideInfoPageSize
);
3294 cacheHeader
->set_codeSignatureOffset(cacheHeader
->codeSignatureOffset()+slideInfoPageSize
);
3296 // update fMappings so .map file will print correctly
3297 fMappings
.back().sfm_size
= cacheFileSize
-fMappings
.back().sfm_file_offset
;
3299 // copy compressed into into buffer
3300 memcpy(&inMemoryCache
[cacheHeader
->slideInfoOffset()], slideInfo
, slideInfoPageSize
);
3303 // append local symbol info in an unmapped region
3304 if ( dontMapLocalSymbols
) {
3305 uint32_t spaceAtEnd
= allocatedCacheSize
- cacheFileSize
;
3306 uint32_t localSymbolsOffset
= pageAlign(cacheFileSize
);
3307 dyldCacheLocalSymbolsInfo
<E
>* infoHeader
= (dyldCacheLocalSymbolsInfo
<E
>*)(&inMemoryCache
[localSymbolsOffset
]);
3308 const uint32_t entriesOffset
= sizeof(dyldCacheLocalSymbolsInfo
<E
>);
3309 const uint32_t entriesCount
= fLocalSymbolInfos
.size();
3310 const uint32_t nlistOffset
= entriesOffset
+ entriesCount
* sizeof(dyldCacheLocalSymbolEntry
<E
>);
3311 const uint32_t nlistCount
= fUnmappedLocalSymbols
.size();
3312 const uint32_t stringsOffset
= nlistOffset
+ nlistCount
* sizeof(macho_nlist
<P
>);
3313 const uint32_t stringsSize
= fUnmappedLocalsStringPool
.size();
3314 if ( stringsOffset
+stringsSize
> spaceAtEnd
)
3315 throwf("update_dyld_shared_cache[%u] for arch=%s, out of space for local symbols. Have 0x%X, Need 0x%X\n",
3316 getpid(), fArchGraph
->archName(), spaceAtEnd
, stringsOffset
+stringsSize
);
3317 // fill in local symbols info
3318 infoHeader
->set_nlistOffset(nlistOffset
);
3319 infoHeader
->set_nlistCount(nlistCount
);
3320 infoHeader
->set_stringsOffset(stringsOffset
);
3321 infoHeader
->set_stringsSize(stringsSize
);
3322 infoHeader
->set_entriesOffset(entriesOffset
);
3323 infoHeader
->set_entriesCount(entriesCount
);
3324 // copy info for each dylib
3325 dyldCacheLocalSymbolEntry
<E
>* entries
= (dyldCacheLocalSymbolEntry
<E
>*)(&inMemoryCache
[localSymbolsOffset
+entriesOffset
]);
3326 for (int i
=0; i
< entriesCount
; ++i
) {
3327 entries
[i
].set_dylibOffset(fLocalSymbolInfos
[i
].dylibOffset
);
3328 entries
[i
].set_nlistStartIndex(fLocalSymbolInfos
[i
].nlistStartIndex
);
3329 entries
[i
].set_nlistCount(fLocalSymbolInfos
[i
].nlistCount
);
3332 memcpy(&inMemoryCache
[localSymbolsOffset
+nlistOffset
], &fUnmappedLocalSymbols
[0], nlistCount
*sizeof(macho_nlist
<P
>));
3334 memcpy(&inMemoryCache
[localSymbolsOffset
+stringsOffset
], fUnmappedLocalsStringPool
.getBuffer(), stringsSize
);
3337 fUnmappedLocalSymbolsSize
= pageAlign(stringsOffset
+ stringsSize
);
3338 cacheFileSize
= regionAlign(localSymbolsOffset
+ fUnmappedLocalSymbolsSize
);
3340 // update header to show location of slidePointers
3341 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
3342 cacheHeader
->set_localSymbolsOffset(localSymbolsOffset
);
3343 cacheHeader
->set_localSymbolsSize(stringsOffset
+stringsSize
);
3344 cacheHeader
->set_codeSignatureOffset(cacheFileSize
);
3347 // make sure after all optimizations, that whole cache file fits into shared region address range
3349 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
3350 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[cacheHeader
->mappingOffset()];
3351 // <rdar://problem/16128830> incorporate code signature size into overflow check
3352 uint32_t estCodeSigSize
= regionAlign(cacheFileSize
/200); // guess 0.5% for code signature
3353 for (int i
=0; i
< cacheHeader
->mappingCount(); ++i
) {
3354 uint64_t endAddr
= mappings
[i
].address() + mappings
[i
].size() + estCodeSigSize
;
3355 if ( endAddr
> (sharedRegionStartAddress() + sharedRegionSize()) ) {
3356 throwf("update_dyld_shared_cache[%u] for arch=%s, shared cache will not fit in shared regions address space. Overflow amount: %lluKB\n",
3357 getpid(), fArchGraph
->archName(), (endAddr
-(sharedRegionStartAddress() + sharedRegionSize()))/1024);
3363 // if no existing cache, say so
3364 if ( fExistingCacheForVerification
== NULL
) {
3365 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
3366 getpid(), archName());
3368 // new cache is built, compare header entries
3369 const dyldCacheHeader
<E
>* newHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
3370 const dyldCacheHeader
<E
>* oldHeader
= (dyldCacheHeader
<E
>*)fExistingCacheForVerification
;
3371 if ( newHeader
->mappingCount() != oldHeader
->mappingCount() ) {
3372 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because caches have a different number of mappings\n",
3373 getpid(), archName());
3375 const dyldCacheFileMapping
<E
>* newMappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[newHeader
->mappingOffset()];
3376 const dyldCacheFileMapping
<E
>* oldMappings
= (dyldCacheFileMapping
<E
>*)&fExistingCacheForVerification
[oldHeader
->mappingOffset()];
3377 for (int i
=0; i
< newHeader
->mappingCount(); ++i
) {
3378 if ( newMappings
[i
].address() != oldMappings
[i
].address() ) {
3379 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",
3380 getpid(), archName(), i
, newMappings
[i
].address(), oldMappings
[i
].address() );
3382 if ( newMappings
[i
].size() != oldMappings
[i
].size() ) {
3383 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because mapping %d has a different size\n",
3384 getpid(), archName(), i
);
3388 //fprintf(stderr, "%s existing cache = %p\n", archName(), fExistingCacheForVerification);
3389 //fprintf(stderr, "%s new cache = %p\n", archName(), inMemoryCache);
3390 // compare content to existing cache page by page
3391 for (int offset
=0; offset
< cacheFileSize
; offset
+= 4096) {
3392 if ( memcmp(&inMemoryCache
[offset
], &fExistingCacheForVerification
[offset
], 4096) != 0 ) {
3393 fprintf(stderr
, "verifier found differences on page offset 0x%08X for %s:\n", offset
, archName());
3394 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++dylibIndex
) {
3395 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
3396 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator sit
= segs
.begin(); sit
!= segs
.end(); ++sit
) {
3397 const MachOLayoutAbstraction::Segment
& seg
= *sit
;
3398 if ( (seg
.mappedAddress() <= &inMemoryCache
[offset
]) && (&inMemoryCache
[offset
] < ((uint8_t*)seg
.mappedAddress() + seg
.fileSize())) ) {
3399 // all LINKEDITs point to the same region, so just print one
3400 if ( strcmp(seg
.name(), "__LINKEDIT") == 0 )
3401 fprintf(stderr
, " in merged LINKEDIT segment\n");
3403 fprintf(stderr
, " in segment %s of dylib %s\n", seg
.name(), it
->layout
->getID().name
);
3408 for (int po
=0; po
< 4096; po
+= 16) {
3409 if ( memcmp(&inMemoryCache
[offset
+po
], &fExistingCacheForVerification
[offset
+po
], 16) != 0 ) {
3410 fprintf(stderr
, " existing: 0x%08X: ", offset
+po
);
3411 for ( int j
=0; j
< 16; ++j
)
3412 fprintf(stderr
, " 0x%02X", fExistingCacheForVerification
[offset
+po
+j
]);
3413 fprintf(stderr
, "\n");
3414 fprintf(stderr
, " should be: 0x%08X: ", offset
+po
);
3415 for ( int j
=0; j
< 16; ++j
)
3416 fprintf(stderr
, " 0x%02X", inMemoryCache
[offset
+po
+j
]);
3417 fprintf(stderr
, "\n");
3424 ((dyldCacheHeader
<E
>*)inMemoryCache
)->set_cacheType(0);
3425 writeCacheFile(fCacheFilePath
, inMemoryCache
, cacheFileSize
, fCacheFileInFinalLocation
);
3427 // generate human readable "map" file that shows the layout of the cache file
3429 fprintf(stderr
, "update_dyld_shared_cache: writing .map file to disk\n");
3430 char mapFilePath
[strlen(fCacheFilePath
)+16];
3431 sprintf(mapFilePath
, "%s.map", fCacheFilePath
);
3432 char tempMapFilePath
[strlen(fCacheFilePath
)+32];
3433 sprintf(tempMapFilePath
, "%s.map%u", fCacheFilePath
, getpid());
3434 FILE* fmap
= ::fopen(tempMapFilePath
, "w");
3435 if ( fmap
== NULL
) {
3436 fprintf(stderr
, "can't create map file %s, errno=%d", tempMapFilePath
, errno
);
3439 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
3440 const char* prot
= "RW";
3441 if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_READ
) )
3443 else if ( it
->sfm_init_prot
== VM_PROT_READ
)
3445 else if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_WRITE
|VM_PROT_READ
) )
3447 if ( it
->sfm_size
> 1024*1024 )
3448 fprintf(fmap
, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/(1024*1024),
3449 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
3451 fprintf(fmap
, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/1024,
3452 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
3455 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX weak binding info\n",
3456 (fOffsetOfExportInfoInCombinedLinkedit
-fOffsetOfWeakBindInfoInCombinedLinkedit
)/1024,
3457 fLinkEditsStartAddress
+fOffsetOfWeakBindInfoInCombinedLinkedit
,
3458 fLinkEditsStartAddress
+fOffsetOfExportInfoInCombinedLinkedit
);
3459 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX export info\n",
3460 (fOffsetOfBindInfoInCombinedLinkedit
-fOffsetOfExportInfoInCombinedLinkedit
)/1024,
3461 fLinkEditsStartAddress
+fOffsetOfExportInfoInCombinedLinkedit
,
3462 fLinkEditsStartAddress
+fOffsetOfBindInfoInCombinedLinkedit
);
3463 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX binding info\n",
3464 (fOffsetOfLazyBindInfoInCombinedLinkedit
-fOffsetOfBindInfoInCombinedLinkedit
)/1024,
3465 fLinkEditsStartAddress
+fOffsetOfBindInfoInCombinedLinkedit
,
3466 fLinkEditsStartAddress
+fOffsetOfLazyBindInfoInCombinedLinkedit
);
3467 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX lazy binding info\n",
3468 (fOffsetOfOldSymbolTableInfoInCombinedLinkedit
-fOffsetOfLazyBindInfoInCombinedLinkedit
)/1024,
3469 fLinkEditsStartAddress
+fOffsetOfLazyBindInfoInCombinedLinkedit
,
3470 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
);
3471 fprintf(fmap
, " linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld symbol table size\n",
3472 (fSizeOfOldSymbolTableInfoInCombinedLinkedit
)/(1024*1024),
3473 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
,
3474 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
+fSizeOfOldSymbolTableInfoInCombinedLinkedit
);
3475 if ( fSizeOfFunctionStartsInCombinedLinkedit
!= 0 )
3476 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld functions starts size\n",
3477 fSizeOfFunctionStartsInCombinedLinkedit
/1024,
3478 fLinkEditsStartAddress
+fOffsetOfFunctionStartsInCombinedLinkedit
,
3479 fLinkEditsStartAddress
+fOffsetOfFunctionStartsInCombinedLinkedit
+fSizeOfFunctionStartsInCombinedLinkedit
);
3480 if ( fSizeOfDataInCodeInCombinedLinkedit
!= 0 )
3481 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld data-in-code info size\n",
3482 fSizeOfDataInCodeInCombinedLinkedit
/1024,
3483 fLinkEditsStartAddress
+fOffsetOfDataInCodeInCombinedLinkedit
,
3484 fLinkEditsStartAddress
+fOffsetOfDataInCodeInCombinedLinkedit
+fSizeOfDataInCodeInCombinedLinkedit
);
3485 if ( fSizeOfOldExternalRelocationsInCombinedLinkedit
!= 0 )
3486 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld external relocs size\n",
3487 fSizeOfOldExternalRelocationsInCombinedLinkedit
/1024,
3488 fLinkEditsStartAddress
+fOffsetOfOldExternalRelocationsInCombinedLinkedit
,
3489 fLinkEditsStartAddress
+fOffsetOfOldExternalRelocationsInCombinedLinkedit
+fSizeOfOldExternalRelocationsInCombinedLinkedit
);
3490 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld indirect symbol table size\n",
3491 fSizeOfOldIndirectSymbolsInCombinedLinkedit
/1024,
3492 fLinkEditsStartAddress
+fOffsetOfOldIndirectSymbolsInCombinedLinkedit
,
3493 fLinkEditsStartAddress
+fOffsetOfOldIndirectSymbolsInCombinedLinkedit
+fSizeOfOldIndirectSymbolsInCombinedLinkedit
);
3494 fprintf(fmap
, " linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld string pool\n",
3495 (fSizeOfOldStringPoolInCombinedLinkedit
)/(1024*1024),
3496 fLinkEditsStartAddress
+fOffsetOfOldStringPoolInCombinedLinkedit
,
3497 fLinkEditsStartAddress
+fOffsetOfOldStringPoolInCombinedLinkedit
+fSizeOfOldStringPoolInCombinedLinkedit
);
3499 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
3500 if ( cacheHeader
->slideInfoSize() != 0 ) {
3501 fprintf(fmap
, " linkedit %4lluKB kernel slide info\n", (cacheHeader
->slideInfoSize())/1024);
3504 fprintf(fmap
, "unmapped -- %4uMB local symbol info\n", fUnmappedLocalSymbolsSize
/(1024*1024));
3506 uint64_t endMappingAddr
= fMappings
[2].sfm_address
+ fMappings
[2].sfm_size
;
3507 fprintf(fmap
, "total map %4lluMB\n", (endMappingAddr
- sharedRegionStartAddress())/(1024*1024));
3508 if ( sharedRegionStartWritableAddress(0) == 0x7FFF70000000LL
) {
3509 // x86_64 has different slide constraints
3510 uint64_t freeSpace
= 256*1024*1024 - fMappings
[1].sfm_size
;
3511 fprintf(fmap
, "r/w space %4lluMB -> %d bits of entropy for ASLR\n\n", freeSpace
/(1024*1024), (int)log2(freeSpace
/4096));
3514 uint64_t freeSpace
= sharedRegionStartAddress() + sharedRegionSize() - endMappingAddr
;
3515 fprintf(fmap
, "free space %4lluMB -> %d bits of entropy for ASLR\n\n", freeSpace
/(1024*1024), (int)log2(freeSpace
/4096));
3518 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
3519 fprintf(fmap
, "%s\n", it
->layout
->getID().name
);
3520 for (std::vector
<const char*>::const_iterator ait
= it
->aliases
.begin(); ait
!= it
->aliases
.end(); ++ait
)
3521 fprintf(fmap
, "%s\n", *ait
);
3522 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
3523 for (int i
=0; i
< segs
.size(); ++i
) {
3524 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
3525 fprintf(fmap
, "\t%16s 0x%0llX -> 0x%0llX\n", seg
.name(), seg
.newAddress(), seg
.newAddress()+seg
.size());
3528 if ( warnings
.size() > 0 ) {
3529 fprintf(fmap
, "# Warnings:\n");
3530 for (std::vector
<const char*>::iterator it
=warnings
.begin(); it
!= warnings
.end(); ++it
) {
3531 fprintf(fmap
, "# %s\n", *it
);
3535 ::rename(tempMapFilePath
, mapFilePath
);
3539 // free in memory cache
3540 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
3541 inMemoryCache
= NULL
;
3544 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*100, archCount
*100);
3548 // remove in memory cache
3549 if ( inMemoryCache
!= NULL
)
3550 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
3560 // The shared cache is driven by /var/db/dyld/shared_region_roots which contains
3561 // the paths used to search for dylibs that should go in the shared cache
3563 // Leading and trailing white space is ignored
3564 // Blank lines are ignored
3565 // Lines starting with # are ignored
3567 static void parsePathsFile(const char* filePath
, std::vector
<const char*>& paths
)
3569 // read in whole file
3570 int fd
= open(filePath
, O_RDONLY
, 0);
3572 fprintf(stderr
, "update_dyld_shared_cache: can't open file: %s\n", filePath
);
3575 struct stat stat_buf
;
3576 fstat(fd
, &stat_buf
);
3577 char* p
= (char*)malloc(stat_buf
.st_size
);
3579 fprintf(stderr
, "update_dyld_shared_cache: malloc failure\n");
3582 if ( read(fd
, p
, stat_buf
.st_size
) != stat_buf
.st_size
) {
3583 fprintf(stderr
, "update_dyld_shared_cache: can't read file: %s\n", filePath
);
3588 // parse into paths and add to vector
3589 char * const end
= &p
[stat_buf
.st_size
];
3590 enum { lineStart
, inSymbol
, inComment
} state
= lineStart
;
3591 char* symbolStart
= NULL
;
3592 for (char* s
= p
; s
< end
; ++s
) {
3598 else if ( !isspace(*s
) ) {
3606 // removing any trailing spaces
3608 while ( isspace(*last
) ) {
3612 paths
.push_back(symbolStart
);
3623 // Note: we do not free() the malloc buffer, because the strings in it are used by exec()
3628 static void setSharedDylibs(const char* rootPath
, const std::vector
<const char*>& overlayPaths
, const std::set
<ArchPair
>& onlyArchs
, std::vector
<const char*> rootsPaths
)
3630 // set file system root
3631 ArchGraph::setFileSystemRoot(rootPath
);
3632 ArchGraph::setFileSystemOverlay(overlayPaths
);
3634 // initialize all architectures requested
3635 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
3636 ArchGraph::addArchPair(*a
);
3638 // add roots to graph
3639 for(std::vector
<const char*>::const_iterator it
= rootsPaths
.begin(); it
!= rootsPaths
.end(); ++it
)
3640 ArchGraph::addRoot(*it
, onlyArchs
);
3642 // determine shared dylibs
3643 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
3644 ArchGraph::findSharedDylibs(*a
);
3648 static void scanForSharedDylibs(const char* rootPath
, const std::vector
<const char*>& overlayPaths
, const char* dirOfPathFiles
, const std::set
<ArchPair
>& onlyArchs
)
3650 char rootDirOfPathFiles
[strlen(rootPath
)+strlen(dirOfPathFiles
)+2];
3651 // in -root mode, look for roots in /rootpath/var/db/dyld
3652 if ( rootPath
[0] != '\0' ) {
3653 strcpy(rootDirOfPathFiles
, rootPath
);
3654 strcat(rootDirOfPathFiles
, dirOfPathFiles
);
3655 dirOfPathFiles
= rootDirOfPathFiles
;
3658 // extract all root paths from files in "/var/db/dyld/shared_region_roots/"
3660 fprintf(stderr
, "update_dyld_shared_cache: finding roots in: %s\n", dirOfPathFiles
);
3661 std::vector
<const char*> rootsPaths
;
3662 DIR* dir
= ::opendir(dirOfPathFiles
);
3664 throwf("%s does not exist, errno=%d\n", dirOfPathFiles
, errno
);
3665 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
3666 if ( entry
->d_type
== DT_REG
|| entry
->d_type
== DT_UNKNOWN
) {
3667 // only look at regular files ending in .paths
3668 if ( strcmp(&entry
->d_name
[entry
->d_namlen
-6], ".paths") == 0 ) {
3669 struct stat tmpStatPathsFile
;
3670 char fullPath
[strlen(dirOfPathFiles
)+entry
->d_namlen
+2];
3671 strcpy(fullPath
, dirOfPathFiles
);
3672 strcat(fullPath
, "/");
3673 strcat(fullPath
, entry
->d_name
);
3674 if ( lstat(fullPath
, &tmpStatPathsFile
) == -1 ) {
3675 fprintf(stderr
, "update_dyld_shared_cache: can't access %s\n", fullPath
);
3677 else if ( S_ISREG(tmpStatPathsFile
.st_mode
) ) {
3678 parsePathsFile(fullPath
, rootsPaths
);
3681 fprintf(stderr
, "update_dyld_shared_cache: wrong file type for %s\n", fullPath
);
3685 fprintf(stderr
, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry
->d_name
);
3691 if ( rootsPaths
.size() == 0 )
3692 fprintf(stderr
, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
3693 setSharedDylibs(rootPath
, overlayPaths
, onlyArchs
, rootsPaths
);
3696 static void setSharedDylibs(const char* rootPath
, const std::vector
<const char*>& overlayPaths
, const char* pathsFile
, const std::set
<ArchPair
>& onlyArchs
)
3698 std::vector
<const char*> rootsPaths
;
3699 parsePathsFile(pathsFile
, rootsPaths
);
3700 setSharedDylibs(rootPath
, overlayPaths
, onlyArchs
, rootsPaths
);
3704 // If the 10.5.0 version of update_dyld_shared_cache was killed or crashed, it
3705 // could leave large half written cache files laying around. The function deletes
3706 // those files. To prevent the deletion of tmp files being created by another
3707 // copy of update_dyld_shared_cache, it only deletes the temp cache file if its
3708 // creation time was before the last restart of this machine.
3709 static void deleteOrphanTempCacheFiles()
3711 DIR* dir
= ::opendir(MACOSX_DYLD_SHARED_CACHE_DIR
);
3712 if ( dir
!= NULL
) {
3713 std::vector
<const char*> filesToDelete
;
3714 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
3715 if ( entry
->d_type
== DT_REG
) {
3716 // only look at files with .tmp in name
3717 if ( strstr(entry
->d_name
, ".tmp") != NULL
) {
3718 char fullPath
[strlen(MACOSX_DYLD_SHARED_CACHE_DIR
)+entry
->d_namlen
+2];
3719 strcpy(fullPath
, MACOSX_DYLD_SHARED_CACHE_DIR
);
3720 strcat(fullPath
, "/");
3721 strcat(fullPath
, entry
->d_name
);
3722 struct stat tmpFileStatInfo
;
3723 if ( stat(fullPath
, &tmpFileStatInfo
) != -1 ) {
3724 int mib
[2] = {CTL_KERN
, KERN_BOOTTIME
};
3725 struct timeval boottime
;
3726 size_t size
= sizeof(boottime
);
3727 if ( (sysctl(mib
, 2, &boottime
, &size
, NULL
, 0) != -1) && (boottime
.tv_sec
!= 0) ) {
3728 // make sure this file is older than the boot time of this machine
3729 if ( tmpFileStatInfo
.st_mtime
< boottime
.tv_sec
) {
3730 filesToDelete
.push_back(strdup(fullPath
));
3738 for(std::vector
<const char*>::iterator it
= filesToDelete
.begin(); it
!= filesToDelete
.end(); ++it
) {
3739 fprintf(stderr
, "update_dyld_shared_cache: deleting old temp cache file: %s\n", *it
);
3747 static bool updateSharedeCacheFile(const char* rootPath
, const std::vector
<const char*>& overlayPaths
, const char* cacheDir
, bool explicitCacheDir
, const std::set
<ArchPair
>& onlyArchs
,
3748 bool force
, bool alphaSort
, bool optimize
, bool deleteExistingFirst
, bool verify
, bool keepSignatures
, bool dontMapLocalSymbols
)
3750 bool didUpdate
= false;
3751 // get dyld load address info
3752 UniversalMachOLayout
* dyldLayout
= NULL
;
3753 char dyldPath
[1024];
3754 strlcpy(dyldPath
, rootPath
, 1024);
3755 strlcat(dyldPath
, "/usr/lib/dyld", 1024);
3756 struct stat stat_buf
;
3757 if ( stat(dyldPath
, &stat_buf
) == 0 ) {
3758 dyldLayout
= new UniversalMachOLayout(dyldPath
, &onlyArchs
);
3761 dyldLayout
= new UniversalMachOLayout("/usr/lib/dyld", &onlyArchs
);
3763 const int archCount
= onlyArchs
.size();
3765 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
, ++index
) {
3766 const MachOLayoutAbstraction
* dyldLayoutForArch
= dyldLayout
->getSlice(*a
);
3767 uint64_t dyldBaseAddress
= 0;
3768 if ( dyldLayoutForArch
!= NULL
)
3769 dyldBaseAddress
= dyldLayoutForArch
->getBaseAddress();
3771 fprintf(stderr
, "update_dyld_shared_cache: warning, dyld not available for specified architectures\n");
3772 switch ( a
->arch
) {
3775 SharedCache
<x86
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, overlayPaths
, cacheDir
, explicitCacheDir
, alphaSort
, verify
, optimize
, dyldBaseAddress
);
3776 didUpdate
|= cache
.update(force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
, dontMapLocalSymbols
);
3779 case CPU_TYPE_X86_64
:
3781 SharedCache
<x86_64
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, overlayPaths
, cacheDir
, explicitCacheDir
, alphaSort
, verify
, optimize
, dyldBaseAddress
);
3782 didUpdate
|= cache
.update(force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
, dontMapLocalSymbols
);
3787 SharedCache
<arm
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, overlayPaths
, cacheDir
, explicitCacheDir
, alphaSort
, verify
, optimize
, dyldBaseAddress
);
3788 didUpdate
|= cache
.update(force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
, dontMapLocalSymbols
);
3791 case CPU_TYPE_ARM64
:
3793 SharedCache
<arm64
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, overlayPaths
, cacheDir
, explicitCacheDir
, alphaSort
, verify
, optimize
, dyldBaseAddress
);
3794 didUpdate
|= cache
.update(force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
, dontMapLocalSymbols
);
3801 deleteOrphanTempCacheFiles();
3809 fprintf(stderr
, "update_dyld_shared_cache [-force] [-root dir] [-overlay dir] [-arch arch] [-debug]\n");
3813 int main(int argc
, const char* argv
[])
3815 std::set
<ArchPair
> onlyArchs
;
3816 const char* rootPath
= "";
3817 std::vector
<const char*> overlayPaths
;
3818 const char* dylibListFile
= NULL
;
3820 bool alphaSort
= false;
3821 bool optimize
= true;
3822 bool verify
= false;
3823 bool keepSignatures
= false;
3824 bool explicitCacheDir
= false;
3825 bool dontMapLocalSymbols
= false;
3826 bool relaunchForHaswell
= false;
3827 const char* cacheDir
= NULL
;
3830 // parse command line options
3831 for(int i
=1; i
< argc
; ++i
) {
3832 const char* arg
= argv
[i
];
3833 if ( arg
[0] == '-' ) {
3834 if ( strcmp(arg
, "-debug") == 0 ) {
3837 else if ( strcmp(arg
, "-force") == 0 ) {
3840 else if ( strcmp(arg
, "-verify") == 0 ) {
3843 else if ( strcmp(arg
, "-sort_by_name") == 0 ) {
3846 else if ( strcmp(arg
, "-progress") == 0 ) {
3849 else if ( strcmp(arg
, "-opt") == 0 ) {
3852 else if ( strcmp(arg
, "-no_opt") == 0 ) {
3855 else if ( strcmp(arg
, "-dont_map_local_symbols") == 0 ) {
3856 dontMapLocalSymbols
= true;
3858 else if ( strcmp(arg
, "-iPhone") == 0 ) {
3862 else if ( strcmp(arg
, "-dylib_list") == 0 ) {
3863 dylibListFile
= argv
[++i
];
3864 if ( dylibListFile
== NULL
)
3865 throw "-dylib_list missing path argument";
3867 else if ( (strcmp(arg
, "-root") == 0) || (strcmp(arg
, "--root") == 0) ) {
3868 rootPath
= argv
[++i
];
3869 if ( rootPath
== NULL
)
3870 throw "-root missing path argument";
3872 else if ( strcmp(arg
, "-overlay") == 0 ) {
3873 const char* path
= argv
[++i
];
3875 throw "-overlay missing path argument";
3876 overlayPaths
.push_back(path
);
3878 else if ( strcmp(arg
, "-cache_dir") == 0 ) {
3879 cacheDir
= argv
[++i
];
3880 if ( cacheDir
== NULL
)
3881 throw "-cache_dir missing path argument";
3882 explicitCacheDir
= true;
3884 else if ( strcmp(arg
, "-arch") == 0 ) {
3885 const char* arch
= argv
[++i
];
3886 if ( strcmp(arch
, "i386") == 0 )
3887 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3888 else if ( strcmp(arch
, "x86_64") == 0 )
3889 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
3890 else if ( strcmp(arch
, "x86_64h") == 0 )
3891 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_H
));
3892 else if ( strcmp(arch
, "armv4t") == 0 )
3893 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V4T
));
3894 else if ( strcmp(arch
, "armv5") == 0 )
3895 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V5TEJ
));
3896 else if ( strcmp(arch
, "armv6") == 0 )
3897 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V6
));
3898 else if ( strcmp(arch
, "armv7") == 0 )
3899 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7
));
3900 else if ( strcmp(arch
, "armv7f") == 0 )
3901 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7F
));
3902 else if ( strcmp(arch
, "armv7k") == 0 )
3903 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7K
));
3904 else if ( strcmp(arch
, "armv7s") == 0 )
3905 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7S
));
3906 else if ( strcmp(arch
, "arm64") == 0 )
3907 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM64
, CPU_SUBTYPE_ARM64_ALL
));
3909 throwf("unknown architecture %s", arch
);
3911 else if ( strcmp(arg
, "-universal_boot") == 0 ) {
3912 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
3913 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3914 relaunchForHaswell
= true;
3918 throwf("unknown option: %s\n", arg
);
3923 throwf("unknown option: %s\n", arg
);
3927 // strip tailing slashes on -root
3928 // make it a real path so as to not make all dylibs look like symlink aliases
3929 if ( rootPath
[0] != '\0' ) {
3930 char realRootPath
[MAXPATHLEN
];
3931 if ( realpath(rootPath
, realRootPath
) == NULL
)
3932 throwf("realpath() failed on %s\n", rootPath
);
3933 rootPath
= strdup(realRootPath
);
3936 // strip tailing slashes on -overlay
3937 for (std::vector
<const char*>::iterator it
=overlayPaths
.begin(); it
!= overlayPaths
.end(); ++it
) {
3938 char realOverlayPath
[MAXPATHLEN
];
3939 if ( realpath(*it
, realOverlayPath
) == NULL
)
3940 throwf("realpath() failed on %s\n", *it
);
3941 *it
= strdup(realOverlayPath
);
3944 // set default location to write cache dir
3945 if ( cacheDir
== NULL
)
3946 cacheDir
= (iPhoneOS
? IPHONE_DYLD_SHARED_CACHE_DIR
: MACOSX_DYLD_SHARED_CACHE_DIR
);
3948 // if no restrictions specified, use architectures that work on this machine
3949 if ( onlyArchs
.size() == 0 ) {
3951 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V6
));
3952 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7
));
3956 size_t len
= sizeof(int);
3957 #if __i386__ || __x86_64__
3958 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3959 // check system is capable of running 64-bit programs
3960 if ( (sysctlbyname("hw.optional.x86_64", &available
, &len
, NULL
, 0) == 0) && available
) {
3961 // check system is capable of running x86_64h code
3962 struct host_basic_info info
;
3963 mach_msg_type_number_t count
= HOST_BASIC_INFO_COUNT
;
3964 mach_port_t hostPort
= mach_host_self();
3965 kern_return_t result
= host_info(hostPort
, HOST_BASIC_INFO
, (host_info_t
)&info
, &count
);
3966 mach_port_deallocate(mach_task_self(), hostPort
);
3967 if ( result
!= KERN_SUCCESS
)
3968 throw "host_info() failed";
3969 if ( info
.cpu_subtype
== CPU_SUBTYPE_X86_64_H
)
3970 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_H
));
3972 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_ALL
));
3975 #error unsupported architecture
3980 if ( !verify
&& (geteuid() != 0) )
3981 throw "you must be root to run this tool";
3983 // build list of shared dylibs
3984 if ( dylibListFile
!= NULL
)
3985 setSharedDylibs(rootPath
, overlayPaths
, dylibListFile
, onlyArchs
);
3987 scanForSharedDylibs(rootPath
, overlayPaths
, "/var/db/dyld/shared_region_roots/", onlyArchs
);
3988 bool didUpdate
= updateSharedeCacheFile(rootPath
, overlayPaths
, cacheDir
, explicitCacheDir
, onlyArchs
, force
, alphaSort
, optimize
,
3989 false, verify
, keepSignatures
, dontMapLocalSymbols
);
3991 if ( didUpdate
&& !iPhoneOS
) {
3992 void* handle
= dlopen("/usr/lib/libspindump.dylib", RTLD_LAZY
);
3993 if ( handle
!= NULL
) {
3994 typedef bool (*dscsym_proc_t
)(const char *root
);
3995 dscsym_proc_t proc
= (dscsym_proc_t
)dlsym(handle
, "dscsym_save_nuggets_for_current_caches");
3996 const char* nuggetRootPath
= "/";
3997 if ( !overlayPaths
.empty() )
3998 nuggetRootPath
= overlayPaths
[0];
3999 else if ( rootPath
[0] != '\0' )
4000 nuggetRootPath
= rootPath
;
4001 (*proc
)(nuggetRootPath
);
4006 if ( relaunchForHaswell
) {
4008 strlcpy(cmd
, argv
[0], 2048);
4009 strlcat(cmd
, " -arch x86_64h", 2048);
4011 strlcat(cmd
, " -force", 2048);
4013 strlcat(cmd
, " -verify", 2048);
4015 strlcat(cmd
, " -sort_by_name", 2048);
4016 if ( (rootPath
!= NULL
) && (rootPath
[0] != '\0') ) {
4017 strlcat(cmd
, " -root ", 2048);
4018 strlcat(cmd
, rootPath
, 2048);
4024 catch (const char* msg
) {
4025 fprintf(stderr
, "update_dyld_shared_cache failed: %s\n", msg
);