1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.h>
28 #include <mach/mach.h>
29 #include <mach/mach_time.h>
42 #include <sys/param.h>
43 #include <sys/sysctl.h>
44 #include <sys/resource.h>
46 #include <servers/bootstrap.h>
47 #include <mach-o/loader.h>
48 #include <mach-o/fat.h>
49 #include <CoreFoundation/CoreFoundation.h>
50 #include <Security/Security.h>
51 #include <Security/SecCodeSigner.h>
52 #include <CommonCrypto/CommonDigest.h>
54 #include "dyld_cache_format.h"
59 #include <unordered_map>
61 #include "Architectures.hpp"
62 #include "MachOLayout.hpp"
63 #include "MachORebaser.hpp"
64 #include "MachOBinder.hpp"
65 #include "CacheFileAbstraction.hpp"
66 #include "dyld_cache_config.h"
69 #include "objc-shared-cache.h"
71 #define FIRST_DYLIB_TEXT_OFFSET 0x8000
73 #ifndef LC_FUNCTION_STARTS
74 #define LC_FUNCTION_STARTS 0x26
77 static bool verbose
= false;
78 static bool progress
= false;
79 static bool iPhoneOS
= false;
80 static std::vector
<const char*> warnings
;
83 static void warn(const char *arch
, const char *format
, ...)
88 va_start(args
, format
);
89 ::vasprintf(&msg
, format
, args
);
92 warnings
.push_back(msg
);
95 ::fprintf(::stderr
, "update_dyld_shared_cache: warning: %s%s%s%s\n",
96 arch
? "for arch " : "",
106 size_t operator()(const char* __s
) const {
109 __h
= 5 * __h
+ *__s
;
116 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
124 typedef std::unordered_map
<const char*, const char*, CStringHash
, CStringEquals
> StringToString
;
126 static void addArchPair(ArchPair ap
);
127 static void addRoot(const char* vpath
, const std::set
<ArchPair
>& archs
);
128 static void findSharedDylibs(ArchPair ap
);
129 static ArchGraph
* graphForArchPair(ArchPair ap
) { return fgPerArchGraph
[ap
]; }
130 static void setFileSystemRoot(const char* root
) { fgFileSystemRoot
= root
; }
131 static void setFileSystemOverlay(const std::vector
<const char*>& overlays
);
132 static const char* archName(ArchPair ap
);
134 ArchPair
getArchPair() { return fArchPair
; }
135 std::set
<const class MachOLayoutAbstraction
*>& getSharedDylibs() { return fSharedDylibs
; }
136 StringToString
& getDylibAliases() { return fAliasesMap
; }
137 const char* archName() { return archName(fArchPair
); }
144 DependencyNode(ArchGraph
*, const char* path
, const MachOLayoutAbstraction
* layout
);
145 void loadDependencies(const MachOLayoutAbstraction
*);
146 void markNeededByRoot(DependencyNode
*);
147 const char* getPath() const { return fPath
; }
148 const MachOLayoutAbstraction
* getLayout() const { return fLayout
; }
149 size_t useCount() const { return fRootsDependentOnThis
.size(); }
150 bool allDependentsFound() const { return !fDependentMissing
; }
154 const MachOLayoutAbstraction
* fLayout
;
155 bool fDependenciesLoaded
;
156 bool fDependentMissing
;
157 std::set
<DependencyNode
*> fDependsOn
;
158 std::set
<DependencyNode
*> fRootsDependentOnThis
;
161 typedef std::unordered_map
<const char*, class DependencyNode
*, CStringHash
, CStringEquals
> PathToNode
;
164 ArchGraph(ArchPair ap
) : fArchPair(ap
) {}
165 void addRoot(const char* path
, const MachOLayoutAbstraction
*);
166 DependencyNode
* getNode(const char* path
);
167 DependencyNode
* getNodeForVirtualPath(const char* vpath
);
168 static bool canBeShared(const MachOLayoutAbstraction
* layout
, ArchPair ap
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
);
169 static bool sharable(const MachOLayoutAbstraction
* layout
, ArchPair ap
, char** msg
);
171 static std::map
<ArchPair
, ArchGraph
*> fgPerArchGraph
;
172 static const char* fgFileSystemRoot
;
173 static std::vector
<const char*> fgFileSystemOverlays
;
176 std::set
<DependencyNode
*> fRoots
;
178 std::set
<const MachOLayoutAbstraction
*> fSharedDylibs
; // use set to avoid duplicates when installname!=realpath
179 StringToString fAliasesMap
;
181 std::map
<ArchPair
, ArchGraph
*> ArchGraph::fgPerArchGraph
;
182 const char* ArchGraph::fgFileSystemRoot
= "";
183 std::vector
<const char*> ArchGraph::fgFileSystemOverlays
;
185 void ArchGraph::addArchPair(ArchPair ap
)
187 //fprintf(stderr, "adding ArchPair 0x%08X,0x%08X\n", ap.arch, ap.subtype);
188 fgPerArchGraph
[ap
] = new ArchGraph(ap
);
191 void ArchGraph::setFileSystemOverlay(const std::vector
<const char*>& overlays
)
193 for (std::vector
<const char*>::const_iterator it
=overlays
.begin(); it
!= overlays
.end(); ++it
)
194 fgFileSystemOverlays
.push_back(*it
);
197 void ArchGraph::addRoot(const char* vpath
, const std::set
<ArchPair
>& onlyArchs
)
199 //fprintf(stderr, "addRoot(%s)\n", vpath);
200 char completePath
[MAXPATHLEN
];
201 const char* path
= NULL
;
202 // check -overlay path first
203 for (std::vector
<const char*>::const_iterator it
=fgFileSystemOverlays
.begin(); it
!= fgFileSystemOverlays
.end(); ++it
) {
204 strcpy(completePath
, *it
);
205 strcat(completePath
, vpath
); // assumes vpath starts with '/'
206 struct stat stat_buf
;
207 if ( stat(completePath
, &stat_buf
) == 0 ) {
212 // if not found in overlay, check for -root
213 if ( (path
== NULL
) && (fgFileSystemRoot
[0] != '\0') ) {
214 strcpy(completePath
, fgFileSystemRoot
);
215 strcat(completePath
, vpath
); // assumes vpath starts with '/'
216 struct stat stat_buf
;
217 if ( stat(completePath
, &stat_buf
) == 0 )
224 //fprintf(stderr, " UniversalMachOLayout::find(%s)\n", path);
225 const UniversalMachOLayout
& uni
= UniversalMachOLayout::find(path
, &onlyArchs
);
226 for(std::set
<ArchPair
>::iterator ait
= onlyArchs
.begin(); ait
!= onlyArchs
.end(); ++ait
) {
228 const MachOLayoutAbstraction
* layout
= uni
.getSlice(*ait
);
229 if ( layout
!= NULL
)
230 fgPerArchGraph
[*ait
]->addRoot(path
, layout
);
232 catch (const char* msg
) {
234 fprintf(stderr
, "update_dyld_shared_cache: warning for %s can't use root '%s': %s\n", fgPerArchGraph
[*ait
]->archName(), path
, msg
);
239 catch (const char* msg
) {
240 fprintf(stderr
, "update_dyld_shared_cache: warning can't use root '%s': %s\n", path
, msg
);
246 void ArchGraph::addRoot(const char* path
, const MachOLayoutAbstraction
* layout
)
249 fprintf(stderr
, "update_dyld_shared_cache: adding root: %s\n", path
);
250 DependencyNode
* node
= this->getNode(path
);
252 const MachOLayoutAbstraction
* mainExecutableLayout
= NULL
;
253 if ( layout
->getFileType() == MH_EXECUTE
)
254 mainExecutableLayout
= layout
;
255 node
->loadDependencies(mainExecutableLayout
);
256 node
->markNeededByRoot(node
);
257 if ( layout
->getFileType() == MH_DYLIB
)
258 node
->markNeededByRoot(NULL
);
261 // a virtual path does not have the fgFileSystemRoot prefix
262 ArchGraph::DependencyNode
* ArchGraph::getNodeForVirtualPath(const char* vpath
)
264 //fprintf(stderr, "getNodeForVirtualPath(%s)\n", vpath);
265 char completePath
[MAXPATHLEN
];
266 for (std::vector
<const char*>::const_iterator it
=fgFileSystemOverlays
.begin(); it
!= fgFileSystemOverlays
.end(); ++it
) {
267 const char* overlayPath
= *it
;
268 // using -overlay means if /overlay/path/dylib exists use it, otherwise use /path/dylib
269 strcpy(completePath
, overlayPath
);
270 strcat(completePath
, vpath
); // assumes vpath starts with '/'
271 struct stat stat_buf
;
272 if ( stat(completePath
, &stat_buf
) == 0 ) {
273 return this->getNode(completePath
);
275 // <rdar://problem/9279770> support when install name is a symlink
276 const char* pathToSymlink
= vpath
;
277 if ( fgFileSystemRoot
[0] != '\0' ) {
278 strcpy(completePath
, fgFileSystemRoot
);
279 strcat(completePath
, vpath
);
280 pathToSymlink
= completePath
;
282 if ( (lstat(pathToSymlink
, &stat_buf
) == 0) && S_ISLNK(stat_buf
.st_mode
) ) {
283 // requested path did not exist in /overlay, but leaf of path is a symlink in /
284 char pathInSymLink
[MAXPATHLEN
];
285 size_t res
= readlink(pathToSymlink
, pathInSymLink
, sizeof(pathInSymLink
));
287 pathInSymLink
[res
] = '\0';
288 if ( pathInSymLink
[0] != '/' ) {
289 char symFullPath
[MAXPATHLEN
];
290 strcpy(symFullPath
, vpath
);
291 char* lastSlash
= strrchr(symFullPath
, '/');
292 if ( lastSlash
!= NULL
) {
293 strcpy(lastSlash
+1, pathInSymLink
);
294 // (re)try looking for what symlink points to, but in /overlay
295 return this->getNodeForVirtualPath(symFullPath
);
302 if ( fgFileSystemRoot
[0] != '\0' ) {
303 // using -root means always use /rootpath/usr/lib
304 strcpy(completePath
, fgFileSystemRoot
);
305 strcat(completePath
, vpath
); // assumes vpath starts with '/'
306 return this->getNode(completePath
);
308 // not found in -overlay or -root not used
309 return this->getNode(vpath
);
312 ArchGraph::DependencyNode
* ArchGraph::getNode(const char* path
)
314 //fprintf(stderr, "getNode(%s)\n", path);
315 // look up supplied path to see if node already exists
316 PathToNode::iterator pos
= fNodes
.find(path
);
317 if ( pos
!= fNodes
.end() )
321 char realPath
[MAXPATHLEN
];
322 if ( realpath(path
, realPath
) == NULL
)
323 throwf("realpath() failed on %s\n", path
);
325 // look up real path to see if node already exists
326 pos
= fNodes
.find(realPath
);
327 if ( pos
!= fNodes
.end() ) {
328 // update fAliasesMap with symlinks found
329 const char* aliasPath
= path
;
330 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(path
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
331 aliasPath
= &path
[strlen(fgFileSystemRoot
)];
333 if ( fAliasesMap
.find(aliasPath
) == fAliasesMap
.end() ) {
334 if ( strcmp(aliasPath
, pos
->second
->getLayout()->getID().name
) != 0 ) {
335 fAliasesMap
[strdup(aliasPath
)] = pos
->second
->getLayout()->getID().name
;
336 //fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
342 // still does not exist, so create a new node
343 const UniversalMachOLayout
& uni
= UniversalMachOLayout::find(realPath
);
344 DependencyNode
* node
= new DependencyNode(this, realPath
, uni
.getSlice(fArchPair
));
345 if ( node
->getLayout() == NULL
) {
346 throwf("%s is missing arch %s", realPath
, archName(fArchPair
));
348 // add realpath to node map
349 fNodes
[node
->getPath()] = node
;
350 // if install name is not real path, add install name to node map
351 if ( (node
->getLayout()->getFileType() == MH_DYLIB
) && (strcmp(realPath
, node
->getLayout()->getID().name
) != 0) ) {
352 //fprintf(stderr, "adding %s node alias %s for %s\n", archName(fArchPair), node->getLayout()->getID().name, realPath);
353 pos
= fNodes
.find(node
->getLayout()->getID().name
);
354 if ( pos
!= fNodes
.end() ) {
355 // get uuids of two dylibs to see if this is accidental copy of a dylib or two differnent dylibs with same -install_name
358 node
->getLayout()->uuid(uuid1
);
359 pos
->second
->getLayout()->uuid(uuid2
);
360 if ( memcmp(&uuid1
, &uuid2
, 16) == 0 ) {
361 // <rdar://problem/8305479> warn if two dylib in cache have same install_name
363 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",
364 node
->getLayout()->getID().name
, pos
->second
->getPath(), node
->getPath());
365 fprintf(stderr
, "%s", msg
);
366 warnings
.push_back(msg
);
369 // <rdar://problem/12763450> update_dyld_shared_cache should fail if two images have same install name
370 fprintf(stderr
, "update_dyld_shared_cache: found two different dylibs with same install path: %s\n\t%s\n\t%s\n",
371 node
->getLayout()->getID().name
, pos
->second
->getPath(), node
->getPath());
376 fNodes
[node
->getLayout()->getID().name
] = node
;
377 // update fAliasesMap with symlinks found
378 const char* aliasPath
= realPath
;
379 if ( (fgFileSystemRoot
!= NULL
) && (fgFileSystemRoot
[0] != '\0') && (strncmp(realPath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
380 aliasPath
= &realPath
[strlen(fgFileSystemRoot
)];
382 // <rdar://problem/11192810> Too many aliases in -overlay mode
383 for (std::vector
<const char*>::const_iterator it
=fgFileSystemOverlays
.begin(); it
!= fgFileSystemOverlays
.end(); ++it
) {
384 const char* overlayPath
= *it
;
385 if ( strncmp(realPath
, overlayPath
, strlen(overlayPath
)) == 0 ) {
386 aliasPath
= &realPath
[strlen(overlayPath
)];
390 if ( fAliasesMap
.find(aliasPath
) == fAliasesMap
.end() ) {
391 if ( strcmp(aliasPath
, node
->getLayout()->getID().name
) != 0 ) {
392 fAliasesMap
[strdup(aliasPath
)] = node
->getLayout()->getID().name
;
393 //fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
401 void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction
* mainExecutableLayout
)
403 if ( !fDependenciesLoaded
) {
404 fDependenciesLoaded
= true;
406 const std::vector
<MachOLayoutAbstraction::Library
>& dependsOn
= fLayout
->getLibraries();
407 for(std::vector
<MachOLayoutAbstraction::Library
>::const_iterator it
= dependsOn
.begin(); it
!= dependsOn
.end(); ++it
) {
409 const char* dependentPath
= it
->name
;
410 if ( strncmp(dependentPath
, "@executable_path/", 17) == 0 ) {
411 if ( mainExecutableLayout
== NULL
)
412 throw "@executable_path without main executable";
413 // expand @executable_path path prefix
414 const char* executablePath
= mainExecutableLayout
->getFilePath();
415 char newPath
[strlen(executablePath
) + strlen(dependentPath
)+2];
416 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(executablePath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
417 // executablePath already has rootPath prefix, need to remove that to get to base virtual path
418 strcpy(newPath
, &executablePath
[strlen(fgFileSystemRoot
)]);
421 strcpy(newPath
, executablePath
);
423 char* addPoint
= strrchr(newPath
,'/');
424 if ( addPoint
!= NULL
)
425 strcpy(&addPoint
[1], &dependentPath
[17]);
427 strcpy(newPath
, &dependentPath
[17]);
428 dependentPath
= strdup(newPath
);
430 else if ( strncmp(dependentPath
, "@loader_path/", 13) == 0 ) {
431 // expand @loader_path path prefix
432 char newPath
[strlen(fPath
) + strlen(dependentPath
)+2];
433 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(fPath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
434 // fPath already has rootPath prefix, need to remove that to get to base virtual path
435 strcpy(newPath
, &fPath
[strlen(fgFileSystemRoot
)]);
438 strcpy(newPath
, fPath
);
440 char* addPoint
= strrchr(newPath
,'/');
441 if ( addPoint
!= NULL
)
442 strcpy(&addPoint
[1], &dependentPath
[13]);
444 strcpy(newPath
, &dependentPath
[13]);
445 dependentPath
= strdup(newPath
);
447 else if ( strncmp(dependentPath
, "@rpath/", 7) == 0 ) {
448 throw "@rpath not supported in dyld shared cache";
450 // <rdar://problem/9161945> silently ignore dependents from main executables that can't be in shared cache
451 bool addDependent
= true;
452 if ( fLayout
->getFileType() == MH_EXECUTE
) {
453 if ( (strncmp(dependentPath
, "/usr/lib/", 9) != 0) && (strncmp(dependentPath
, "/System/Library/", 16) != 0) ) {
454 addDependent
= false;
458 fDependsOn
.insert(fGraph
->getNodeForVirtualPath(dependentPath
));
460 catch (const char* msg
) {
461 if ( it
->weakImport
|| ! fLayout
->hasSplitSegInfo() ) {
462 // ok to ignore missing weak imported dylibs from things that are
463 // not going to be in the dyld shared cache
466 fprintf(stderr
, "warning, could not bind %s because %s\n", fPath
, msg
);
467 fDependentMissing
= true;
472 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
473 (*it
)->loadDependencies(mainExecutableLayout
);
478 void ArchGraph::DependencyNode::markNeededByRoot(ArchGraph::DependencyNode
* rootNode
)
480 if ( fRootsDependentOnThis
.count(rootNode
) == 0 ) {
481 fRootsDependentOnThis
.insert(rootNode
);
482 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
483 (*it
)->markNeededByRoot(rootNode
);
489 ArchGraph::DependencyNode::DependencyNode(ArchGraph
* graph
, const char* path
, const MachOLayoutAbstraction
* layout
)
490 : fGraph(graph
), fPath(strdup(path
)), fLayout(layout
), fDependenciesLoaded(false), fDependentMissing(false)
492 //fprintf(stderr, "new DependencyNode(0x%08X, %s)\n", graph->fArch, path);
495 void ArchGraph::findSharedDylibs(ArchPair ap
)
497 const PathToNode
& nodes
= fgPerArchGraph
[ap
]->fNodes
;
498 std::set
<const MachOLayoutAbstraction
*> possibleLibs
;
499 //fprintf(stderr, "shared for arch %s\n", archName(ap));
500 for(PathToNode::const_iterator it
= nodes
.begin(); it
!= nodes
.end(); ++it
) {
501 DependencyNode
* node
= it
->second
;
502 // <rdar://problem/6127437> put all dylibs in shared cache - not just ones used by more than one app
503 if ( node
->allDependentsFound() /*&& (node->useCount() > 1)*/ ) {
504 const MachOLayoutAbstraction
* layout
= node
->getLayout();
505 if ( layout
->isDylib() ) {
507 if ( sharable(layout
, ap
, &msg
) ) {
508 possibleLibs
.insert(layout
);
511 if ( layout
->getID().name
[0] == '@' ) {
512 // <rdar://problem/7770139> update_dyld_shared_cache should suppress warnings for embedded frameworks
515 warnings
.push_back(msg
);
516 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
523 // prune so that all shareable libs depend only on other shareable libs
524 std::set
<const MachOLayoutAbstraction
*>& sharedLibs
= fgPerArchGraph
[ap
]->fSharedDylibs
;
525 std::map
<const MachOLayoutAbstraction
*,bool> shareableMap
;
526 for (std::set
<const MachOLayoutAbstraction
*>::iterator lit
= possibleLibs
.begin(); lit
!= possibleLibs
.end(); ++lit
) {
527 if ( canBeShared(*lit
, ap
, possibleLibs
, shareableMap
) )
528 sharedLibs
.insert(*lit
);
532 const char* ArchGraph::archName(ArchPair ap
)
537 case CPU_TYPE_X86_64
:
538 switch ( ap
.subtype
) {
539 case CPU_SUBTYPE_X86_64_H
:
545 switch ( ap
.subtype
) {
546 case CPU_SUBTYPE_ARM_V4T
:
548 case CPU_SUBTYPE_ARM_V6
:
550 case CPU_SUBTYPE_ARM_V5TEJ
:
552 case CPU_SUBTYPE_ARM_XSCALE
:
554 case CPU_SUBTYPE_ARM_V7
:
556 case CPU_SUBTYPE_ARM_V7F
:
558 case CPU_SUBTYPE_ARM_V7K
:
560 case CPU_SUBTYPE_ARM_V7S
:
572 bool ArchGraph::sharable(const MachOLayoutAbstraction
* layout
, ArchPair ap
, char** msg
)
574 if ( ! layout
->isTwoLevelNamespace() )
575 asprintf(msg
, "can't put %s in shared cache because it was built -flat_namespace", layout
->getID().name
);
576 else if ( ! layout
->inSharableLocation() )
577 asprintf(msg
, "can't put %s in shared cache because its -install_name is not in /usr/lib or /System/Library", layout
->getID().name
);
578 else if ( ! layout
->hasSplitSegInfo() )
579 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"));
580 else if ( ! layout
->isRootOwned() )
581 asprintf(msg
, "can't put %s in shared cache because it is not owned by root", layout
->getID().name
);
582 else if ( layout
->hasDynamicLookupLinkage() )
583 asprintf(msg
, "can't put %s in shared cache because it was built with '-undefined dynamic_lookup'", layout
->getID().name
);
584 else if ( layout
->hasMainExecutableLookupLinkage() )
585 asprintf(msg
, "can't put %s in shared cache because it was built with '-bundle_loader'", layout
->getID().name
);
586 else if ( layout
->hasMultipleReadWriteSegments() )
587 asprintf(msg
, "can't put %s in shared cache because it has multiple r/w segments", layout
->getID().name
);
593 bool ArchGraph::canBeShared(const MachOLayoutAbstraction
* layout
, ArchPair ap
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
)
595 // check map which is a cache of results
596 std::map
<const MachOLayoutAbstraction
*, bool>::iterator mapPos
= shareableMap
.find(layout
);
597 if ( mapPos
!= shareableMap
.end() ) {
598 return mapPos
->second
;
601 if ( possibleLibs
.count(layout
) == 0 ) {
602 shareableMap
[layout
] = false;
604 if ( sharable(layout
, ap
, &msg
) )
605 asprintf(&msg
, "can't put %s in shared cache, unknown reason", layout
->getID().name
);
606 warnings
.push_back(msg
);
608 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
612 shareableMap
[layout
] = true; // mark this shareable early in case of circular references
613 const PathToNode
& nodes
= fgPerArchGraph
[ap
]->fNodes
;
614 const std::vector
<MachOLayoutAbstraction::Library
>& dependents
= layout
->getLibraries();
615 for (std::vector
<MachOLayoutAbstraction::Library
>::const_iterator dit
= dependents
.begin(); dit
!= dependents
.end(); ++dit
) {
616 PathToNode::const_iterator pos
= nodes
.find(dit
->name
);
617 if ( pos
== nodes
.end() ) {
618 // path from load command does not match any loaded dylibs, maybe there is a temp symlink
619 char realPath
[MAXPATHLEN
];
620 if ( realpath(dit
->name
, realPath
) != NULL
) {
621 if ( nodes
.find(realPath
) != nodes
.end() )
624 // handle weak imported dylibs not found
625 if ( dit
->weakImport
)
627 shareableMap
[layout
] = false;
629 asprintf(&msg
, "can't put %s in shared cache because it depends on %s which can't be found", layout
->getID().name
, dit
->name
);
630 warnings
.push_back(msg
);
632 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
636 if ( ! canBeShared(pos
->second
->getLayout(), ap
, possibleLibs
, shareableMap
) ) {
637 shareableMap
[layout
] = false;
639 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
);
640 warnings
.push_back(msg
);
642 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
656 const char* getBuffer();
658 uint32_t add(const char* str
);
659 uint32_t addUnique(const char* str
);
660 const char* stringAtIndex(uint32_t) const;
663 typedef std::unordered_map
<const char*, uint32_t, CStringHash
, CStringEquals
> StringToOffset
;
666 uint32_t fBufferAllocated
;
667 uint32_t fBufferUsed
;
668 StringToOffset fUniqueStrings
;
672 StringPool::StringPool()
673 : fBufferUsed(0), fBufferAllocated(64*1024*1024)
675 fBuffer
= (char*)malloc(fBufferAllocated
);
678 uint32_t StringPool::add(const char* str
)
680 uint32_t len
= strlen(str
);
681 if ( (fBufferUsed
+ len
+ 1) > fBufferAllocated
) {
683 throw "string buffer exhausted";
685 strcpy(&fBuffer
[fBufferUsed
], str
);
686 uint32_t result
= fBufferUsed
;
687 fUniqueStrings
[&fBuffer
[fBufferUsed
]] = result
;
688 fBufferUsed
+= len
+1;
692 uint32_t StringPool::addUnique(const char* str
)
694 StringToOffset::iterator pos
= fUniqueStrings
.find(str
);
695 if ( pos
!= fUniqueStrings
.end() )
698 //fprintf(stderr, "StringPool::addUnique() new string: %s\n", str);
699 return this->add(str
);
703 uint32_t StringPool::size()
708 const char* StringPool::getBuffer()
713 const char* StringPool::stringAtIndex(uint32_t index
) const
715 return &fBuffer
[index
];
720 struct LocalSymbolInfo
722 uint32_t dylibOffset
;
723 uint32_t nlistStartIndex
;
728 template <typename A
>
732 SharedCache(ArchGraph
* graph
, const char* rootPath
, const std::vector
<const char*>& overlayPaths
, const char* cacheDir
, bool explicitCacheDir
,
733 bool alphaSort
, bool verify
, bool optimize
, uint64_t dyldBaseAddress
);
734 bool update(bool force
, bool optimize
, bool deleteExistingFirst
, int archIndex
,
735 int archCount
, bool keepSignatures
, bool dontMapLocalSymbols
);
736 static const char* cacheFileSuffix(bool optimized
, const char* archName
);
738 // vm address = address AS WRITTEN into the cache
739 // mapped address = address AS MAPPED into the update process only
740 // file offset = offset relative to start of cache file
741 void * mappedAddressForVMAddress(uint64_t vmaddr
);
742 uint64_t VMAddressForMappedAddress(const void *mapaddr
);
743 uint64_t cacheFileOffsetForVMAddress(uint64_t addr
) const;
744 uint64_t VMAddressForCacheFileOffset(uint64_t addr
) const;
746 static const char* archName();
749 typedef typename
A::P P
;
750 typedef typename
A::P::E E
;
751 typedef typename
A::P::uint_t pint_t
;
753 bool notUpToDate(const char* path
, unsigned int aliasCount
);
754 bool notUpToDate(const void* cache
, unsigned int aliasCount
);
755 uint8_t* optimizeLINKEDIT(bool keepSignatures
, bool dontMapLocalSymbols
);
756 void optimizeObjC(std::vector
<void*>& pointersInData
);
758 static void getSharedCacheBasAddresses(cpu_type_t arch
, uint64_t* baseReadOnly
, uint64_t* baseWritable
);
759 static cpu_type_t
arch();
760 static uint64_t sharedRegionStartAddress();
761 static uint64_t sharedRegionSize();
762 static uint64_t sharedRegionStartWritableAddress(uint64_t);
763 static uint64_t sharedRegionStartReadOnlyAddress(uint64_t, uint64_t);
764 static uint64_t getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
);
765 static bool addCacheSlideInfo();
766 static uint64_t pathHash(const char*);
768 static uint64_t pageAlign(uint64_t addr
);
769 static uint64_t regionAlign(uint64_t addr
);
770 static uint64_t pageAlign4KB(uint64_t addr
);
771 void assignNewBaseAddresses(bool verify
);
774 const MachOLayoutAbstraction
* layout
;
775 std::vector
<const char*> aliases
;
776 dyld_cache_image_info info
;
779 struct ByNameSorter
{
780 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
)
781 { return (strcmp(left
.layout
->getID().name
, right
.layout
->getID().name
) < 0); }
784 struct ByAddressSorter
{
785 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
786 return (left
.layout
->getSegments()[0].newAddress() < right
.layout
->getSegments()[0].newAddress());
790 struct ByCStringSectionSizeSorter
{
791 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
792 const std::vector
<MachOLayoutAbstraction::Segment
>& segs_l
=
793 left
.layout
->getSegments();
794 const std::vector
<MachOLayoutAbstraction::Segment
>& segs_r
=
795 right
.layout
->getSegments();
796 if (segs_l
.size() == 0 || segs_r
.size() == 0) {
797 // one image has no segments
798 return segs_l
.size() > segs_r
.size();
800 const macho_header
<P
> *mh_l
= (macho_header
<P
>*)segs_l
[0].mappedAddress();
801 const macho_header
<P
> *mh_r
= (macho_header
<P
>*)segs_r
[0].mappedAddress();
802 const macho_section
<P
> *cstring_l
= mh_l
->getSection("__TEXT", "__cstring");
803 const macho_section
<P
> *cstring_r
= mh_r
->getSection("__TEXT", "__cstring");
804 if (!cstring_l
|| !cstring_r
) {
805 // one image has no cstrings
806 return cstring_l
&& !cstring_r
;
809 return cstring_l
->size() > cstring_r
->size();
814 Sorter(std::map
<const MachOLayoutAbstraction
*, uint32_t>& map
): fMap(map
) {}
815 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
816 return (fMap
[left
.layout
] < fMap
[right
.layout
]);
819 std::map
<const MachOLayoutAbstraction
*, uint32_t>& fMap
;
823 ArchGraph
* fArchGraph
;
825 bool fExistingIsNotUpToDate
;
826 bool fCacheFileInFinalLocation
;
827 const char* fCacheFilePath
;
828 uint8_t* fExistingCacheForVerification
;
829 std::vector
<LayoutInfo
> fDylibs
;
830 std::vector
<LayoutInfo
> fDylibAliases
;
831 std::vector
<shared_file_mapping_np
> fMappings
;
832 std::vector
<macho_nlist
<P
> > fUnmappedLocalSymbols
;
833 StringPool fUnmappedLocalsStringPool
;
834 std::vector
<LocalSymbolInfo
> fLocalSymbolInfos
;
835 uint32_t fHeaderSize
;
836 uint8_t* fInMemoryCache
;
837 uint64_t fDyldBaseAddress
;
838 uint64_t fLinkEditsTotalUnoptimizedSize
;
839 uint64_t fLinkEditsStartAddress
;
840 MachOLayoutAbstraction::Segment
* fFirstLinkEditSegment
;
841 uint32_t fOffsetOfBindInfoInCombinedLinkedit
;
842 uint32_t fOffsetOfWeakBindInfoInCombinedLinkedit
;
843 uint32_t fOffsetOfLazyBindInfoInCombinedLinkedit
;
844 uint32_t fOffsetOfExportInfoInCombinedLinkedit
;
845 uint32_t fOffsetOfOldSymbolTableInfoInCombinedLinkedit
;
846 uint32_t fSizeOfOldSymbolTableInfoInCombinedLinkedit
;
847 uint32_t fOffsetOfOldExternalRelocationsInCombinedLinkedit
;
848 uint32_t fSizeOfOldExternalRelocationsInCombinedLinkedit
;
849 uint32_t fOffsetOfOldIndirectSymbolsInCombinedLinkedit
;
850 uint32_t fSizeOfOldIndirectSymbolsInCombinedLinkedit
;
851 uint32_t fOffsetOfOldStringPoolInCombinedLinkedit
;
852 uint32_t fSizeOfOldStringPoolInCombinedLinkedit
;
853 uint32_t fOffsetOfFunctionStartsInCombinedLinkedit
;
854 uint32_t fSizeOfFunctionStartsInCombinedLinkedit
;
855 uint32_t fOffsetOfDataInCodeInCombinedLinkedit
;
856 uint32_t fSizeOfDataInCodeInCombinedLinkedit
;
857 uint32_t fLinkEditsTotalOptimizedSize
;
858 uint32_t fUnmappedLocalSymbolsSize
;
862 // Access a section containing a list of pointers
863 template <typename A
, typename T
>
866 typedef typename
A::P P
;
867 typedef typename
A::P::uint_t pint_t
;
869 SharedCache
<A
>* const fCache
;
870 const macho_section
<P
>* const fSection
;
871 pint_t
* const fBase
;
875 PointerSection(SharedCache
<A
>* cache
, const macho_header
<P
>* header
,
876 const char *segname
, const char *sectname
)
878 , fSection(header
->getSection(segname
, sectname
))
879 , fBase(fSection
? (pint_t
*)cache
->mappedAddressForVMAddress(fSection
->addr()) : 0)
880 , fCount(fSection
? fSection
->size() / sizeof(pint_t
) : 0)
884 uint64_t count() const { return fCount
; }
886 uint64_t getUnmapped(uint64_t index
) const {
887 if (index
>= fCount
) throwf("index out of range");
888 return P::getP(fBase
[index
]);
891 T
get(uint64_t index
) const {
892 return (T
)fCache
->mappedAddressForVMAddress(getUnmapped(index
));
895 void set(uint64_t index
, uint64_t value
) {
896 if (index
>= fCount
) throwf("index out of range");
897 P::setP(fBase
[index
], value
);
902 for (uint64_t i
= 0; i
< fCount
; i
++) {
903 pint_t value
= fBase
[i
];
905 fBase
[i
-shift
] = value
;
911 const_cast<macho_section
<P
>*>(fSection
)->set_size(fCount
* sizeof(pint_t
));
915 // Access a section containing an array of structures
916 template <typename A
, typename T
>
919 typedef typename
A::P P
;
921 SharedCache
<A
>* const fCache
;
922 const macho_section
<P
>* const fSection
;
924 uint64_t const fCount
;
927 ArraySection(SharedCache
<A
>* cache
, const macho_header
<P
>* header
,
928 const char *segname
, const char *sectname
)
930 , fSection(header
->getSection(segname
, sectname
))
931 , fBase(fSection
? (T
*)cache
->mappedAddressForVMAddress(fSection
->addr()) : 0)
932 , fCount(fSection
? fSection
->size() / sizeof(T
) : 0)
936 uint64_t count() const { return fCount
; }
938 T
& get(uint64_t index
) const {
939 if (index
>= fCount
) throwf("index out of range");
946 #include "ObjCLegacyAbstraction.hpp"
947 #include "ObjCModernAbstraction.hpp"
951 template <> cpu_type_t SharedCache
<x86
>::arch() { return CPU_TYPE_I386
; }
952 template <> cpu_type_t SharedCache
<x86_64
>::arch() { return CPU_TYPE_X86_64
; }
953 template <> cpu_type_t SharedCache
<arm
>::arch() { return CPU_TYPE_ARM
; }
954 template <> cpu_type_t SharedCache
<arm64
>::arch() { return CPU_TYPE_ARM64
; }
956 template <> uint64_t SharedCache
<x86
>::sharedRegionStartAddress() { return 0x90000000; }
957 template <> uint64_t SharedCache
<x86_64
>::sharedRegionStartAddress() { return 0x7FFF80000000LL
; }
958 template <> uint64_t SharedCache
<arm
>::sharedRegionStartAddress() { return ARM_SHARED_REGION_START
; }
959 template <> uint64_t SharedCache
<arm64
>::sharedRegionStartAddress() { return ARM64_SHARED_REGION_START
; }
961 template <> uint64_t SharedCache
<x86
>::sharedRegionSize() { return 0x20000000; }
962 template <> uint64_t SharedCache
<x86_64
>::sharedRegionSize() { return 0x40000000; }
963 template <> uint64_t SharedCache
<arm
>::sharedRegionSize() { return ARM_SHARED_REGION_SIZE
; }
964 template <> uint64_t SharedCache
<arm64
>::sharedRegionSize() { return ARM64_SHARED_REGION_SIZE
; }
966 template <> uint64_t SharedCache
<x86
>::sharedRegionStartWritableAddress(uint64_t exEnd
) { return exEnd
+ 0x04000000; }
967 template <> uint64_t SharedCache
<x86_64
>::sharedRegionStartWritableAddress(uint64_t exEnd
) { return 0x7FFF70000000LL
; }
968 template <> uint64_t SharedCache
<arm
>::sharedRegionStartWritableAddress(uint64_t exEnd
) { return (exEnd
+ 16383) & (-16384); }
969 template <> uint64_t SharedCache
<arm64
>::sharedRegionStartWritableAddress(uint64_t exEnd
) { return exEnd
; }
971 template <> uint64_t SharedCache
<x86
>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd
, uint64_t exEnd
) { return wrEnd
+ 0x04000000; }
972 template <> uint64_t SharedCache
<x86_64
>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd
, uint64_t exEnd
){ return exEnd
; }
973 template <> uint64_t SharedCache
<arm
>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd
, uint64_t exEnd
) { return (wrEnd
+ 16383) & (-16384); }
974 template <> uint64_t SharedCache
<arm64
>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd
, uint64_t exEnd
) { return (wrEnd
+ 16383) & (-16384); }
976 template <> const char* SharedCache
<x86
>::archName() { return "i386"; }
977 template <> const char* SharedCache
<x86_64
>::archName() { return "x86_64"; }
978 template <> const char* SharedCache
<arm
>::archName() { return "arm"; }
979 template <> const char* SharedCache
<arm64
>::archName() { return "arm64"; }
981 template <> const char* SharedCache
<x86
>::cacheFileSuffix(bool, const char* archName
) { return archName
; }
982 template <> const char* SharedCache
<x86_64
>::cacheFileSuffix(bool, const char* archName
){ return archName
; }
983 template <> const char* SharedCache
<arm
>::cacheFileSuffix(bool, const char* archName
) { return archName
; }
984 template <> const char* SharedCache
<arm64
>::cacheFileSuffix(bool, const char* archName
) { return archName
; }
986 template <> uint64_t SharedCache
<x86
>::pageAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
987 template <> uint64_t SharedCache
<x86_64
>::pageAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
988 template <> uint64_t SharedCache
<arm
>::pageAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
989 template <> uint64_t SharedCache
<arm64
>::pageAlign(uint64_t addr
) { return ( (addr
+ 16383) & (-16384) ); }
991 template <> uint64_t SharedCache
<x86
>::regionAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
992 template <> uint64_t SharedCache
<x86_64
>::regionAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
993 template <> uint64_t SharedCache
<arm
>::regionAlign(uint64_t addr
) { return ( (addr
+ 16383) & (-16384) ); }
994 template <> uint64_t SharedCache
<arm64
>::regionAlign(uint64_t addr
) { return ( (addr
+ 16383) & (-16384) ); }
997 template <typename A
>
998 uint64_t SharedCache
<A
>::pageAlign4KB(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
1000 template <typename A
>
1001 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
)
1002 : fArchGraph(graph
), fVerify(verify
), fExistingIsNotUpToDate(true),
1003 fCacheFileInFinalLocation(rootPath
[0] == '\0'), fCacheFilePath(NULL
),
1004 fExistingCacheForVerification(NULL
), fDyldBaseAddress(dyldBaseAddress
),
1005 fOffsetOfBindInfoInCombinedLinkedit(0), fOffsetOfWeakBindInfoInCombinedLinkedit(0),
1006 fOffsetOfLazyBindInfoInCombinedLinkedit(0), fOffsetOfExportInfoInCombinedLinkedit(0),
1007 fOffsetOfOldSymbolTableInfoInCombinedLinkedit(0), fSizeOfOldSymbolTableInfoInCombinedLinkedit(0),
1008 fOffsetOfOldExternalRelocationsInCombinedLinkedit(0), fSizeOfOldExternalRelocationsInCombinedLinkedit(0),
1009 fOffsetOfOldIndirectSymbolsInCombinedLinkedit(0), fSizeOfOldIndirectSymbolsInCombinedLinkedit(0),
1010 fOffsetOfOldStringPoolInCombinedLinkedit(0), fSizeOfOldStringPoolInCombinedLinkedit(0),
1011 fOffsetOfFunctionStartsInCombinedLinkedit(0), fSizeOfFunctionStartsInCombinedLinkedit(0),
1012 fOffsetOfDataInCodeInCombinedLinkedit(0), fSizeOfDataInCodeInCombinedLinkedit(0),
1013 fUnmappedLocalSymbolsSize(0)
1015 if ( fArchGraph
->getArchPair().arch
!= arch() )
1016 throwf("SharedCache object is wrong architecture: 0x%08X vs 0x%08X", fArchGraph
->getArchPair().arch
, arch());
1018 // build vector of all shared dylibs
1019 unsigned int aliasCount
= 0;
1020 std::set
<const MachOLayoutAbstraction
*>& dylibs
= fArchGraph
->getSharedDylibs();
1021 ArchGraph::StringToString
& aliases
= fArchGraph
->getDylibAliases();
1022 for(std::set
<const MachOLayoutAbstraction
*>::iterator it
= dylibs
.begin(); it
!= dylibs
.end(); ++it
) {
1023 const MachOLayoutAbstraction
* lib
= *it
;
1026 temp
.info
.address
= 0;
1027 temp
.info
.inode
= lib
->getInode();
1028 temp
.info
.modTime
= lib
->getLastModTime();
1030 temp
.info
.inode
= pathHash(lib
->getID().name
);
1031 temp
.info
.modTime
= 0;
1033 temp
.info
.pathFileOffset
= lib
->getNameFileOffset(); // for now this is the offset within the dylib
1034 for(ArchGraph::StringToString::iterator ait
= aliases
.begin(); ait
!= aliases
.end(); ++ait
) {
1035 if ( strcmp(ait
->second
, lib
->getID().name
) == 0 ) {
1036 temp
.aliases
.push_back(ait
->first
);
1040 fDylibs
.push_back(temp
);
1043 // create path to cache file
1044 char cachePathCanonical
[MAXPATHLEN
];
1045 strcpy(cachePathCanonical
, cacheDir
);
1046 if ( cachePathCanonical
[strlen(cachePathCanonical
)-1] != '/' )
1047 strcat(cachePathCanonical
, "/");
1048 strcat(cachePathCanonical
, DYLD_SHARED_CACHE_BASE_NAME
);
1049 strcat(cachePathCanonical
, cacheFileSuffix(optimize
, fArchGraph
->archName()));
1050 char cachePath
[MAXPATHLEN
];
1051 if ( explicitCacheDir
) {
1052 fCacheFilePath
= strdup(cachePathCanonical
);
1054 else if ( overlayPaths
.size() == 1 ) {
1055 // if no -cache_dir and exactly on -overlay, write cache file into that overlay dir
1056 strcpy(cachePath
, overlayPaths
[0]);
1057 strcat(cachePath
, "/");
1058 strcat(cachePath
, cachePathCanonical
);
1059 fCacheFilePath
= strdup(cachePath
);
1061 else if ( rootPath
[0] != '\0' ) {
1062 strcpy(cachePath
, rootPath
);
1063 strcat(cachePath
, "/");
1064 strcat(cachePath
, cachePathCanonical
);
1065 fCacheFilePath
= strdup(cachePath
);
1068 fCacheFilePath
= strdup(cachePathCanonical
);
1070 if ( overlayPaths
.size() == 1 ) {
1071 // in overlay mode if there already is a cache file in the overlay,
1072 // check if it is up to date.
1073 struct stat stat_buf
;
1074 if ( stat(fCacheFilePath
, &stat_buf
) == 0 ) {
1075 fExistingIsNotUpToDate
= this->notUpToDate(fCacheFilePath
, aliasCount
);
1077 else if ( rootPath
[0] != '\0' ) {
1078 // using -root and -overlay, but no cache file in overlay, check one in -root
1079 char cachePathRoot
[MAXPATHLEN
];
1080 strcpy(cachePathRoot
, rootPath
);
1081 strcat(cachePathRoot
, "/");
1082 strcat(cachePathRoot
, cachePathCanonical
);
1083 fExistingIsNotUpToDate
= this->notUpToDate(cachePathRoot
, aliasCount
);
1086 // uisng -overlay, but no cache file in overlay, check one in boot volume
1087 fExistingIsNotUpToDate
= this->notUpToDate(cachePathCanonical
, aliasCount
);
1091 fExistingIsNotUpToDate
= this->notUpToDate(fCacheFilePath
, aliasCount
);
1094 // sort shared dylibs
1096 // already sorted by notUpToDate()
1098 else if ( alphaSort
) {
1099 std::sort(fDylibs
.begin(), fDylibs
.end(), ByNameSorter());
1102 // random sort for Address Space Randomization
1103 std::map
<const MachOLayoutAbstraction
*, uint32_t> map
;
1104 for(typename
std::vector
<struct LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
)
1105 map
[it
->layout
] = arc4random();
1106 std::sort(fDylibs
.begin(), fDylibs
.end(), Sorter(map
));
1109 // assign segments in each dylib a new address
1110 this->assignNewBaseAddresses(verify
);
1112 // calculate where string pool offset will start
1113 // calculate cache file header size
1114 fHeaderSize
= sizeof(dyld_cache_header
)
1115 + fMappings
.size()*sizeof(shared_file_mapping_np
)
1116 + (fDylibs
.size()+aliasCount
)*sizeof(dyld_cache_image_info
);
1117 const uint64_t baseHeaderSize
= fHeaderSize
;
1118 //fprintf(stderr, "aliasCount=%d, fHeaderSize=0x%08X\n", aliasCount, fHeaderSize);
1119 // build list of aliases and compute where each ones path string will go
1120 for(typename
std::vector
<struct LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1121 for(std::vector
<const char*>::const_iterator ait
= it
->aliases
.begin(); ait
!= it
->aliases
.end(); ++ait
) {
1122 LayoutInfo temp
= *it
;
1123 // alias looks just like real dylib, but has a different name string
1124 const char* aliasPath
= *ait
;
1125 temp
.aliases
.clear();
1126 temp
.aliases
.push_back(aliasPath
);
1127 temp
.info
.pathFileOffset
= fHeaderSize
;
1129 temp
.info
.inode
= pathHash(aliasPath
);
1130 temp
.info
.modTime
= 0;
1132 fDylibAliases
.push_back(temp
);
1133 fHeaderSize
+= strlen(aliasPath
)+1;
1136 std::sort(fDylibAliases
.begin(), fDylibAliases
.end(), ByNameSorter());
1137 //fprintf(stderr, "fHeaderSize=0x%08X, fDylibAliases.size()=%lu\n", fHeaderSize, fDylibAliases.size());
1138 fHeaderSize
= pageAlign(fHeaderSize
);
1140 // check that cache we are about to create for verification purposes has same layout as existing cache
1142 // if no existing cache, say so
1143 if ( fExistingCacheForVerification
== NULL
) {
1144 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
1145 getpid(), fArchGraph
->archName());
1147 const dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)fExistingCacheForVerification
;
1148 const dyldCacheImageInfo
<E
>* cacheEntry
= (dyldCacheImageInfo
<E
>*)(fExistingCacheForVerification
+ header
->imagesOffset());
1149 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++cacheEntry
) {
1150 if ( cacheEntry
->address() != it
->layout
->getSegments()[0].newAddress() ) {
1151 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",
1152 getpid(), fArchGraph
->archName(), it
->layout
->getID().name
, cacheEntry
->address(), it
->layout
->getSegments()[0].newAddress());
1158 if ( fHeaderSize
> FIRST_DYLIB_TEXT_OFFSET
)
1159 throwf("header size overflow: allowed=0x%08X, base=0x%08llX, aliases=0x%08llX", FIRST_DYLIB_TEXT_OFFSET
, baseHeaderSize
, fHeaderSize
-baseHeaderSize
);
1163 template <typename A
>
1164 uint64_t SharedCache
<A
>::getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
)
1166 return proposedNewAddress
;
1169 template <typename A
>
1170 uint64_t SharedCache
<A
>::pathHash(const char* path
)
1173 for (const char* s
=path
; *s
!= '\0'; ++s
)
1179 template <typename A
>
1180 void SharedCache
<A
>::assignNewBaseAddresses(bool verify
)
1182 // first layout TEXT for dylibs
1183 const uint64_t startExecuteAddress
= sharedRegionStartAddress();
1184 uint64_t currentExecuteAddress
= startExecuteAddress
+ FIRST_DYLIB_TEXT_OFFSET
;
1185 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1186 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1187 for (int i
=0; i
< segs
.size(); ++i
) {
1188 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1190 if ( seg
.executable() && !seg
.writable() ) {
1191 // <rdar://problem/15947734> Some dylib require extra alignment
1192 currentExecuteAddress
= (currentExecuteAddress
+ seg
.alignment() - 1) & (-seg
.alignment());
1194 if ( it
->info
.address
== 0 )
1195 it
->info
.address
= currentExecuteAddress
;
1196 seg
.setNewAddress(currentExecuteAddress
);
1197 currentExecuteAddress
+= pageAlign(seg
.size());
1201 // align __TEXT region
1202 currentExecuteAddress
= regionAlign(currentExecuteAddress
);
1204 // layout DATA for dylibs
1205 const uint64_t startWritableAddress
= sharedRegionStartWritableAddress(currentExecuteAddress
);
1206 uint64_t currentWritableAddress
= startWritableAddress
;
1207 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1208 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1209 for (int i
=0; i
< segs
.size(); ++i
) {
1210 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1212 if ( seg
.writable() ) {
1213 if ( seg
.executable() )
1214 throw "found writable and executable segment";
1216 seg
.setNewAddress(currentWritableAddress
);
1217 // <rdar://problem/13089366> always 4KB align data pages to allow padding to be removed
1218 currentWritableAddress
= pageAlign4KB(seg
.newAddress() + seg
.size());
1222 // align __DATA region
1223 currentWritableAddress
= regionAlign(currentWritableAddress
);
1225 // layout all read-only (but not LINKEDIT) segments
1226 const uint64_t startReadOnlyAddress
= sharedRegionStartReadOnlyAddress(currentWritableAddress
, currentExecuteAddress
);
1227 uint64_t currentReadOnlyAddress
= startReadOnlyAddress
;
1228 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1229 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1230 for(int i
=0; i
< segs
.size(); ++i
) {
1231 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1232 if ( seg
.readable() && !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") != 0) ) {
1233 // __UNICODE segment
1234 seg
.setNewAddress(currentReadOnlyAddress
);
1235 currentReadOnlyAddress
+= pageAlign(seg
.size());
1240 // layout all LINKEDIT segments at end of all read-only segments
1241 currentReadOnlyAddress
= regionAlign(currentReadOnlyAddress
); // <rdar://problem/16491435>
1242 fLinkEditsStartAddress
= currentReadOnlyAddress
;
1243 fFirstLinkEditSegment
= NULL
;
1244 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1245 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1246 for(int i
=0; i
< segs
.size(); ++i
) {
1247 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1248 if ( seg
.readable() && !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
1249 if ( fFirstLinkEditSegment
== NULL
)
1250 fFirstLinkEditSegment
= &seg
;
1251 seg
.setNewAddress(currentReadOnlyAddress
);
1252 currentReadOnlyAddress
+= pageAlign(seg
.size());
1256 fLinkEditsTotalUnoptimizedSize
= pageAlign(currentReadOnlyAddress
- fLinkEditsStartAddress
);
1258 // populate large mappings
1259 uint64_t cacheFileOffset
= 0;
1260 if ( currentExecuteAddress
> startExecuteAddress
) {
1261 shared_file_mapping_np executeMapping
;
1262 executeMapping
.sfm_address
= startExecuteAddress
;
1263 executeMapping
.sfm_size
= currentExecuteAddress
- startExecuteAddress
;
1264 executeMapping
.sfm_file_offset
= cacheFileOffset
;
1265 executeMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
1266 executeMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
1267 fMappings
.push_back(executeMapping
);
1268 cacheFileOffset
+= executeMapping
.sfm_size
;
1270 shared_file_mapping_np writableMapping
;
1271 writableMapping
.sfm_address
= startWritableAddress
;
1272 writableMapping
.sfm_size
= currentWritableAddress
- startWritableAddress
;
1273 writableMapping
.sfm_file_offset
= cacheFileOffset
;
1274 writableMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
1275 writableMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
1276 fMappings
.push_back(writableMapping
);
1277 cacheFileOffset
+= writableMapping
.sfm_size
;
1279 // make read-only (contains LINKEDIT segments) last, so it can be cut back when optimized
1280 shared_file_mapping_np readOnlyMapping
;
1281 readOnlyMapping
.sfm_address
= startReadOnlyAddress
;
1282 readOnlyMapping
.sfm_size
= currentReadOnlyAddress
- startReadOnlyAddress
;
1283 readOnlyMapping
.sfm_file_offset
= cacheFileOffset
;
1284 readOnlyMapping
.sfm_max_prot
= VM_PROT_READ
;
1285 readOnlyMapping
.sfm_init_prot
= VM_PROT_READ
;
1286 fMappings
.push_back(readOnlyMapping
);
1287 cacheFileOffset
+= readOnlyMapping
.sfm_size
;
1291 shared_file_mapping_np cacheHeaderMapping
;
1292 cacheHeaderMapping
.sfm_address
= startExecuteAddress
;
1293 cacheHeaderMapping
.sfm_size
= FIRST_DYLIB_TEXT_OFFSET
;
1294 cacheHeaderMapping
.sfm_file_offset
= cacheFileOffset
;
1295 cacheHeaderMapping
.sfm_max_prot
= VM_PROT_READ
;
1296 cacheHeaderMapping
.sfm_init_prot
= VM_PROT_READ
;
1297 fMappings
.push_back(cacheHeaderMapping
);
1298 cacheFileOffset
+= cacheHeaderMapping
.sfm_size
;
1303 template <typename A
>
1304 uint64_t SharedCache
<A
>::cacheFileOffsetForVMAddress(uint64_t vmaddr
) const
1306 for(std::vector
<shared_file_mapping_np
>::const_iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1307 if ( (it
->sfm_address
<= vmaddr
) && (vmaddr
< it
->sfm_address
+it
->sfm_size
) )
1308 return it
->sfm_file_offset
+ vmaddr
- it
->sfm_address
;
1310 throwf("address 0x%0llX is not in cache", vmaddr
);
1313 template <typename A
>
1314 uint64_t SharedCache
<A
>::VMAddressForCacheFileOffset(uint64_t offset
) const
1316 for(std::vector
<shared_file_mapping_np
>::const_iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1317 if ( (it
->sfm_file_offset
<= offset
) && (offset
< it
->sfm_file_offset
+it
->sfm_size
) )
1318 return it
->sfm_address
+ offset
- it
->sfm_file_offset
;
1320 throwf("offset 0x%0llX is not in cache", offset
);
1323 template <typename A
>
1324 void *SharedCache
<A
>::mappedAddressForVMAddress(uint64_t vmaddr
)
1326 if (!vmaddr
) return NULL
;
1327 else return fInMemoryCache
+ cacheFileOffsetForVMAddress(vmaddr
);
1330 template <typename A
>
1331 uint64_t SharedCache
<A
>::VMAddressForMappedAddress(const void *mapaddr
)
1333 if (!mapaddr
) return 0;
1334 uint64_t offset
= (uint8_t *)mapaddr
- (uint8_t *)fInMemoryCache
;
1335 return VMAddressForCacheFileOffset(offset
);
1339 template <typename A
>
1340 bool SharedCache
<A
>::notUpToDate(const void* cache
, unsigned int aliasCount
)
1342 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)cache
;
1343 // not valid if header signature is wrong
1344 const char* archPairName
= fArchGraph
->archName();
1346 strcpy(temp
, "dyld_v1 ");
1347 strcpy(&temp
[15-strlen(archPairName
)], archPairName
);
1348 if ( strcmp(header
->magic(), temp
) != 0 ) {
1350 fprintf(stderr
, "update_dyld_shared_cache[%u] cannot verify %s because current cache file has invalid header\n", getpid(), archPairName
);
1354 fprintf(stderr
, "update_dyld_shared_cache[%u] updating cache because current cache file has invalid header\n", getpid());
1358 // not valid if count of images does not match current images needed
1359 if ( header
->imagesCount() != (fDylibs
.size()+aliasCount
) ) {
1361 fprintf(stderr
, "update_dyld_shared_cache[%u] cannot verify %s because current cache file contains a different set of dylibs\n", getpid(), archPairName
);
1365 fprintf(stderr
, "update_dyld_shared_cache[%u] updating %s cache because current cache file contains a different set of dylibs\n", getpid(), archPairName
);
1369 // get end of TEXT region
1370 const dyldCacheFileMapping
<E
>* textMapping
= (dyldCacheFileMapping
<E
>*)((uint8_t*)cache
+sizeof(dyldCacheHeader
<E
>));
1371 const uint32_t textSize
= textMapping
->size();
1373 // verify every dylib in constructed graph is in existing cache with same inode and modTime
1374 std::map
<const MachOLayoutAbstraction
*, uint32_t> sortingMap
;
1375 const dyldCacheImageInfo
<E
>* imagesStart
= (dyldCacheImageInfo
<E
>*)((uint8_t*)cache
+ header
->imagesOffset());
1376 const dyldCacheImageInfo
<E
>* imagesEnd
= &imagesStart
[header
->imagesCount()];
1377 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1379 //fprintf(stderr, "inode=0x%llX, mTime=0x%llX, path=%s\n", it->info.inode, it->info.modTime, it->layout->getID().name);
1380 for(const dyldCacheImageInfo
<E
>* cacheEntry
= imagesStart
; cacheEntry
< imagesEnd
; ++cacheEntry
) {
1382 if ( cacheEntry
->pathFileOffset() > textSize
) {
1383 throwf("update_dyld_shared_cache[%u]: for arch=%s, image entries corrupt, bad path offset in %s\n",
1384 getpid(), archPairName
, it
->layout
->getID().name
);
1386 // in -verify mode, just match by path and warn if file looks different
1387 if ( strcmp((char*)cache
+cacheEntry
->pathFileOffset(), it
->layout
->getID().name
) == 0 ) {
1389 sortingMap
[it
->layout
] = cacheEntry
-imagesStart
;
1390 if ( (cacheEntry
->inode() != it
->info
.inode
) || (cacheEntry
->modTime() != it
->info
.modTime
) ) {
1391 fprintf(stderr
, "update_dyld_shared_cache[%u] warning: for arch=%s, %s has changed since cache was built\n",
1392 getpid(), archPairName
, it
->layout
->getID().name
);
1398 if ( cacheEntry
->pathFileOffset() > textSize
) {
1399 // cache corrupt, needs to be regenerated
1402 // in normal update mode, everything has to match for cache to be up-to-date
1403 if ( (cacheEntry
->inode() == it
->info
.inode
)
1404 && (cacheEntry
->modTime() == it
->info
.modTime
)
1405 && (strcmp((char*)cache
+cacheEntry
->pathFileOffset(), it
->layout
->getID().name
) == 0) ) {
1413 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
);
1416 fprintf(stderr
, "update_dyld_shared_cache[%u] updating %s cache because dylib at %s has changed\n", getpid(), archPairName
, it
->layout
->getID().name
);
1421 // all dylibs in existing cache file match those determined need to be in shared cache
1423 // sort fDylibs to match existing cache file so we can compare content
1424 std::sort(fDylibs
.begin(), fDylibs
.end(), Sorter(sortingMap
));
1425 //fprintf(stderr, "dylibs sorted like existing cache:\n");
1426 //for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1427 // fprintf(stderr," %s\n", it->layout->getID().name);
1429 // do regenerate a new cache so we can compare content with existing
1433 // existing cache file is up-to-date, don't need to regenerate
1439 template <typename A
>
1440 bool SharedCache
<A
>::notUpToDate(const char* path
, unsigned int aliasCount
)
1442 // mmap existing cache file
1443 int fd
= ::open(path
, O_RDONLY
);
1446 struct stat stat_buf
;
1447 ::fstat(fd
, &stat_buf
);
1448 uint32_t cacheFileSize
= stat_buf
.st_size
;
1449 uint32_t cacheAllocatedSize
= pageAlign(cacheFileSize
);
1450 uint8_t* mappingAddr
= NULL
;
1451 if ( vm_allocate(mach_task_self(), (vm_address_t
*)(&mappingAddr
), cacheAllocatedSize
, VM_FLAGS_ANYWHERE
) != KERN_SUCCESS
)
1452 throwf("can't vm_allocate cache of size %u", cacheFileSize
);
1453 // <rdar://problem/8960832> update_dyld_shared_cache -verify finds differences
1454 (void)fcntl(fd
, F_NOCACHE
, 1);
1455 ssize_t readResult
= pread(fd
, mappingAddr
, cacheFileSize
, 0);
1456 if ( readResult
!= cacheFileSize
)
1457 throwf("can't read all of existing cache file (%lu of %u): %s", readResult
, cacheFileSize
, path
);
1461 bool result
= this->notUpToDate(mappingAddr
, aliasCount
);
1463 // don't unmap yet, leave so it can be verified later
1464 fExistingCacheForVerification
= mappingAddr
;
1468 vm_deallocate(mach_task_self(), (vm_address_t
)mappingAddr
, cacheAllocatedSize
);
1469 if ( verbose
&& !result
)
1470 fprintf(stderr
, "update_dyld_shared_cache: %s is up-to-date\n", path
);
1477 template <typename A
>
1478 class LinkEditOptimizer
1481 LinkEditOptimizer(const MachOLayoutAbstraction
&, const SharedCache
<A
>&, uint8_t*, StringPool
&);
1482 virtual ~LinkEditOptimizer() {}
1484 void copyBindInfo(uint32_t&);
1485 void copyWeakBindInfo(uint32_t&);
1486 void copyLazyBindInfo(uint32_t&);
1487 void copyExportInfo(uint32_t&);
1488 void copyLocalSymbols(uint32_t symbolTableOffset
, uint32_t&, bool dontMapLocalSymbols
,
1489 uint8_t* cacheStart
, StringPool
& unmappedLocalsStringPool
,
1490 std::vector
<macho_nlist
<typename
A::P
> >& unmappedSymbols
,
1491 std::vector
<LocalSymbolInfo
>& info
);
1492 void copyExportedSymbols(uint32_t symbolTableOffset
, uint32_t&);
1493 void copyImportedSymbols(uint32_t symbolTableOffset
, uint32_t&);
1494 void copyExternalRelocations(uint32_t& offset
);
1495 void copyIndirectSymbolTable(uint32_t& offset
);
1496 void copyFunctionStarts(uint32_t& offset
);
1497 void copyDataInCode(uint32_t& offset
);
1498 void updateLoadCommands(uint64_t newVMAddress
, uint64_t size
, uint32_t stringPoolOffset
,
1499 uint32_t linkEditsFileOffset
, bool keepSignatures
);
1503 typedef typename
A::P P
;
1504 typedef typename
A::P::E E
;
1505 typedef typename
A::P::uint_t pint_t
;
1509 const SharedCache
<A
>& fSharedCache
;
1510 const macho_header
<P
>* fHeader
;
1511 uint8_t* fNewLinkEditStart
;
1512 uint8_t* fLinkEditBase
;
1513 const MachOLayoutAbstraction
& fLayout
;
1514 macho_dyld_info_command
<P
>* fDyldInfo
;
1515 macho_dysymtab_command
<P
>* fDynamicSymbolTable
;
1516 macho_linkedit_data_command
<P
>* fFunctionStarts
;
1517 macho_linkedit_data_command
<P
>* fDataInCode
;
1518 macho_symtab_command
<P
>* fSymbolTableLoadCommand
;
1519 const macho_nlist
<P
>* fSymbolTable
;
1520 const char* fStrings
;
1521 StringPool
& fNewStringPool
;
1522 std::map
<uint32_t,uint32_t> fOldToNewSymbolIndexes
;
1523 uint32_t fBindInfoOffsetIntoNewLinkEdit
;
1524 uint32_t fBindInfoSizeInNewLinkEdit
;
1525 uint32_t fWeakBindInfoOffsetIntoNewLinkEdit
;
1526 uint32_t fWeakBindInfoSizeInNewLinkEdit
;
1527 uint32_t fLazyBindInfoOffsetIntoNewLinkEdit
;
1528 uint32_t fLazyBindInfoSizeInNewLinkEdit
;
1529 uint32_t fExportInfoOffsetIntoNewLinkEdit
;
1530 uint32_t fExportInfoSizeInNewLinkEdit
;
1531 uint32_t fSymbolTableStartOffsetInNewLinkEdit
;
1532 uint32_t fLocalSymbolsStartIndexInNewLinkEdit
;
1533 uint32_t fLocalSymbolsCountInNewLinkEdit
;
1534 uint32_t fExportedSymbolsStartIndexInNewLinkEdit
;
1535 uint32_t fExportedSymbolsCountInNewLinkEdit
;
1536 uint32_t fImportSymbolsStartIndexInNewLinkEdit
;
1537 uint32_t fImportedSymbolsCountInNewLinkEdit
;
1538 uint32_t fExternalRelocationsOffsetIntoNewLinkEdit
;
1539 uint32_t fIndirectSymbolTableOffsetInfoNewLinkEdit
;
1540 uint32_t fFunctionStartsOffsetInNewLinkEdit
;
1541 uint32_t fDataInCodeOffsetInNewLinkEdit
;
1542 uint32_t fUnmappedLocalSymbolsStartIndexInNewLinkEdit
;
1543 uint32_t fUnmappedLocalSymbolsCountInNewLinkEdit
;
1548 template <typename A
>
1549 LinkEditOptimizer
<A
>::LinkEditOptimizer(const MachOLayoutAbstraction
& layout
, const SharedCache
<A
>& sharedCache
, uint8_t* newLinkEdit
, StringPool
& stringPool
)
1550 : fSharedCache(sharedCache
), fLayout(layout
), fLinkEditBase(NULL
), fNewLinkEditStart(newLinkEdit
), fDyldInfo(NULL
),
1551 fDynamicSymbolTable(NULL
), fFunctionStarts(NULL
), fDataInCode(NULL
),
1552 fSymbolTableLoadCommand(NULL
), fSymbolTable(NULL
), fStrings(NULL
), fNewStringPool(stringPool
),
1553 fBindInfoOffsetIntoNewLinkEdit(0), fBindInfoSizeInNewLinkEdit(0),
1554 fWeakBindInfoOffsetIntoNewLinkEdit(0), fWeakBindInfoSizeInNewLinkEdit(0),
1555 fLazyBindInfoOffsetIntoNewLinkEdit(0), fLazyBindInfoSizeInNewLinkEdit(0),
1556 fExportInfoOffsetIntoNewLinkEdit(0), fExportInfoSizeInNewLinkEdit(0),
1557 fSymbolTableStartOffsetInNewLinkEdit(0),
1558 fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
1559 fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
1560 fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
1561 fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0),
1562 fFunctionStartsOffsetInNewLinkEdit(0), fDataInCodeOffsetInNewLinkEdit(0),
1563 fUnmappedLocalSymbolsStartIndexInNewLinkEdit(0), fUnmappedLocalSymbolsCountInNewLinkEdit(0)
1566 fHeader
= (const macho_header
<P
>*)fLayout
.getSegments()[0].mappedAddress();
1568 const std::vector
<MachOLayoutAbstraction::Segment
>& segments
= fLayout
.getSegments();
1569 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator it
= segments
.begin(); it
!= segments
.end(); ++it
) {
1570 const MachOLayoutAbstraction::Segment
& seg
= *it
;
1571 if ( strcmp(seg
.name(), "__LINKEDIT") == 0 )
1572 fLinkEditBase
= (uint8_t*)seg
.mappedAddress() - seg
.fileOffset();
1574 if ( fLinkEditBase
== NULL
)
1575 throw "no __LINKEDIT segment";
1577 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
1578 const uint32_t cmd_count
= fHeader
->ncmds();
1579 const macho_load_command
<P
>* cmd
= cmds
;
1580 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1581 switch (cmd
->cmd()) {
1584 fSymbolTableLoadCommand
= (macho_symtab_command
<P
>*)cmd
;
1585 fSymbolTable
= (macho_nlist
<P
>*)(&fLinkEditBase
[fSymbolTableLoadCommand
->symoff()]);
1586 fStrings
= (char*)&fLinkEditBase
[fSymbolTableLoadCommand
->stroff()];
1590 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
1593 case LC_DYLD_INFO_ONLY
:
1594 fDyldInfo
= (macho_dyld_info_command
<P
>*)cmd
;
1596 case LC_FUNCTION_STARTS
:
1597 fFunctionStarts
= (macho_linkedit_data_command
<P
>*)cmd
;
1598 case LC_DATA_IN_CODE
:
1599 fDataInCode
= (macho_linkedit_data_command
<P
>*)cmd
;
1602 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1604 if ( fSymbolTable
== NULL
)
1605 throw "no LC_SYMTAB";
1606 if ( fDynamicSymbolTable
== NULL
)
1607 throw "no LC_DYSYMTAB";
1612 template <typename A
>
1616 typedef typename
A::P P
;
1617 SymbolSorter(const StringPool
& pool
) : fStringPool(pool
) {}
1618 bool operator()(const macho_nlist
<P
>& left
, const macho_nlist
<P
>& right
) {
1619 return (strcmp(fStringPool
.stringAtIndex(left
.n_strx()) , fStringPool
.stringAtIndex(right
.n_strx())) < 0);
1623 const StringPool
& fStringPool
;
1627 template <typename A
>
1628 void LinkEditOptimizer
<A
>::copyBindInfo(uint32_t& offset
)
1630 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->bind_off() != 0) ) {
1631 fBindInfoOffsetIntoNewLinkEdit
= offset
;
1632 fBindInfoSizeInNewLinkEdit
= fDyldInfo
->bind_size();
1633 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->bind_off()], fDyldInfo
->bind_size());
1634 offset
+= fDyldInfo
->bind_size();
1638 template <typename A
>
1639 void LinkEditOptimizer
<A
>::copyWeakBindInfo(uint32_t& offset
)
1641 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->weak_bind_off() != 0) ) {
1642 fWeakBindInfoOffsetIntoNewLinkEdit
= offset
;
1643 fWeakBindInfoSizeInNewLinkEdit
= fDyldInfo
->weak_bind_size();
1644 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->weak_bind_off()], fDyldInfo
->weak_bind_size());
1645 offset
+= fDyldInfo
->weak_bind_size();
1649 template <typename A
>
1650 void LinkEditOptimizer
<A
>::copyLazyBindInfo(uint32_t& offset
)
1652 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->lazy_bind_off() != 0) ) {
1653 fLazyBindInfoOffsetIntoNewLinkEdit
= offset
;
1654 fLazyBindInfoSizeInNewLinkEdit
= fDyldInfo
->lazy_bind_size();
1655 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->lazy_bind_off()], fDyldInfo
->lazy_bind_size());
1656 offset
+= fDyldInfo
->lazy_bind_size();
1660 template <typename A
>
1661 void LinkEditOptimizer
<A
>::copyExportInfo(uint32_t& offset
)
1663 if ( (fDyldInfo
!= NULL
) && (fLayout
.getDyldInfoExports() != NULL
) ) {
1664 fExportInfoOffsetIntoNewLinkEdit
= offset
;
1665 fExportInfoSizeInNewLinkEdit
= fDyldInfo
->export_size();
1666 memcpy(fNewLinkEditStart
+offset
, fLayout
.getDyldInfoExports(), fDyldInfo
->export_size());
1667 offset
+= fDyldInfo
->export_size();
1672 template <typename A
>
1673 void LinkEditOptimizer
<A
>::copyLocalSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
, bool dontMapLocalSymbols
, uint8_t* cacheStart
,
1674 StringPool
& unmappedLocalsStringPool
, std::vector
<macho_nlist
<P
> >& unmappedSymbols
,
1675 std::vector
<LocalSymbolInfo
>& dylibInfos
)
1677 fLocalSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1678 LocalSymbolInfo localInfo
;
1679 localInfo
.dylibOffset
= ((uint8_t*)fHeader
) - cacheStart
;
1680 localInfo
.nlistStartIndex
= unmappedSymbols
.size();
1681 localInfo
.nlistCount
= 0;
1682 fSymbolTableStartOffsetInNewLinkEdit
= symbolTableOffset
+ symbolIndex
*sizeof(macho_nlist
<P
>);
1683 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1684 const macho_nlist
<P
>* const firstLocal
= &fSymbolTable
[fDynamicSymbolTable
->ilocalsym()];
1685 const macho_nlist
<P
>* const lastLocal
= &fSymbolTable
[fDynamicSymbolTable
->ilocalsym()+fDynamicSymbolTable
->nlocalsym()];
1686 uint32_t oldIndex
= fDynamicSymbolTable
->ilocalsym();
1687 for (const macho_nlist
<P
>* entry
= firstLocal
; entry
< lastLocal
; ++entry
, ++oldIndex
) {
1688 // <rdar://problem/12237639> don't copy stab symbols
1689 if ( (entry
->n_sect() != NO_SECT
) && ((entry
->n_type() & N_STAB
) == 0) ) {
1690 const char* name
= &fStrings
[entry
->n_strx()];
1691 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1692 *newSymbolEntry
= *entry
;
1693 if ( dontMapLocalSymbols
) {
1694 // if local in __text, add <redacted> symbol name to shared cache so backtraces don't have bogus names
1695 if ( entry
->n_sect() == 1 ) {
1696 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique("<redacted>"));
1699 // copy local symbol to unmmapped locals area
1700 unmappedSymbols
.push_back(*entry
);
1701 unmappedSymbols
.back().set_n_strx(unmappedLocalsStringPool
.addUnique(name
));
1704 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(name
));
1709 fLocalSymbolsCountInNewLinkEdit
= symbolIndex
- fLocalSymbolsStartIndexInNewLinkEdit
;
1710 localInfo
.nlistCount
= unmappedSymbols
.size() - localInfo
.nlistStartIndex
;
1711 dylibInfos
.push_back(localInfo
);
1712 //fprintf(stderr, "%u locals starting at %u for %s\n", fLocalSymbolsCountInNewLinkEdit, fLocalSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1716 template <typename A
>
1717 void LinkEditOptimizer
<A
>::copyExportedSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1719 fExportedSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1720 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1721 const macho_nlist
<P
>* const firstExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()];
1722 const macho_nlist
<P
>* const lastExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1723 uint32_t oldIndex
= fDynamicSymbolTable
->iextdefsym();
1724 for (const macho_nlist
<P
>* entry
= firstExport
; entry
< lastExport
; ++entry
, ++oldIndex
) {
1725 if ( ((entry
->n_type() & N_TYPE
) == N_SECT
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0)
1726 && (strncmp(&fStrings
[entry
->n_strx()], "$ld$", 4) != 0) ) {
1727 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1728 *newSymbolEntry
= *entry
;
1729 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1730 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
-fLocalSymbolsStartIndexInNewLinkEdit
;
1734 fExportedSymbolsCountInNewLinkEdit
= symbolIndex
- fExportedSymbolsStartIndexInNewLinkEdit
;
1735 //fprintf(stderr, "%u exports starting at %u for %s\n", fExportedSymbolsCountInNewLinkEdit, fExportedSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1736 // sort by name, so that dyld does not need a toc
1737 macho_nlist
<P
>* newSymbolsStart
= &newSymbolTableStart
[fExportedSymbolsStartIndexInNewLinkEdit
];
1738 macho_nlist
<P
>* newSymbolsEnd
= &newSymbolTableStart
[fExportedSymbolsStartIndexInNewLinkEdit
+fExportedSymbolsCountInNewLinkEdit
];
1739 std::sort(newSymbolsStart
, newSymbolsEnd
, SymbolSorter
<A
>(fNewStringPool
));
1740 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1741 // fprintf(stderr, "\t%u\t %s\n", (entry-newSymbolsStart)+fExportedSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1745 template <typename A
>
1746 void LinkEditOptimizer
<A
>::copyImportedSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1748 fImportSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1749 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1750 const macho_nlist
<P
>* const firstImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()];
1751 const macho_nlist
<P
>* const lastImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()+fDynamicSymbolTable
->nundefsym()];
1752 uint32_t oldIndex
= fDynamicSymbolTable
->iundefsym();
1753 for (const macho_nlist
<P
>* entry
= firstImport
; entry
< lastImport
; ++entry
, ++oldIndex
) {
1754 if ( ((entry
->n_type() & N_TYPE
) == N_UNDF
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0) ) {
1755 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1756 *newSymbolEntry
= *entry
;
1757 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1758 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
-fLocalSymbolsStartIndexInNewLinkEdit
;
1762 fImportedSymbolsCountInNewLinkEdit
= symbolIndex
- fImportSymbolsStartIndexInNewLinkEdit
;
1763 //fprintf(stderr, "%u imports starting at %u for %s\n", fImportedSymbolsCountInNewLinkEdit, fImportSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1764 //macho_nlist<P>* newSymbolsStart = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit];
1765 //macho_nlist<P>* newSymbolsEnd = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit];
1766 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1767 // fprintf(stderr, "\t%u\t%s\n", (entry-newSymbolsStart)+fImportSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1771 template <typename A
>
1772 void LinkEditOptimizer
<A
>::copyExternalRelocations(uint32_t& offset
)
1774 fExternalRelocationsOffsetIntoNewLinkEdit
= offset
;
1775 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(&fLinkEditBase
[fDynamicSymbolTable
->extreloff()]);
1776 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
1777 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1778 macho_relocation_info
<P
>* newReloc
= (macho_relocation_info
<P
>*)(&fNewLinkEditStart
[offset
]);
1780 uint32_t newSymbolIndex
= fOldToNewSymbolIndexes
[reloc
->r_symbolnum()];
1781 //fprintf(stderr, "copyExternalRelocations() old=%d, new=%u name=%s in %s\n", reloc->r_symbolnum(), newSymbolIndex,
1782 // &fStrings[fSymbolTable[reloc->r_symbolnum()].n_strx()], fLayout.getFilePath());
1783 newReloc
->set_r_symbolnum(newSymbolIndex
);
1784 offset
+= sizeof(macho_relocation_info
<P
>);
1788 template <typename A
>
1789 void LinkEditOptimizer
<A
>::copyFunctionStarts(uint32_t& offset
)
1791 if ( fFunctionStarts
!= NULL
) {
1792 fFunctionStartsOffsetInNewLinkEdit
= offset
;
1793 memcpy(&fNewLinkEditStart
[offset
], &fLinkEditBase
[fFunctionStarts
->dataoff()], fFunctionStarts
->datasize());
1794 offset
+= fFunctionStarts
->datasize();
1798 template <typename A
>
1799 void LinkEditOptimizer
<A
>::copyDataInCode(uint32_t& offset
)
1801 if ( fDataInCode
!= NULL
) {
1802 fDataInCodeOffsetInNewLinkEdit
= offset
;
1803 memcpy(&fNewLinkEditStart
[offset
], &fLinkEditBase
[fDataInCode
->dataoff()], fDataInCode
->datasize());
1804 offset
+= fDataInCode
->datasize();
1809 template <typename A
>
1810 void LinkEditOptimizer
<A
>::copyIndirectSymbolTable(uint32_t& offset
)
1812 fIndirectSymbolTableOffsetInfoNewLinkEdit
= offset
;
1813 const uint32_t* const indirectTable
= (uint32_t*)&this->fLinkEditBase
[fDynamicSymbolTable
->indirectsymoff()];
1814 uint32_t* newIndirectTable
= (uint32_t*)&fNewLinkEditStart
[offset
];
1815 for (int i
=0; i
< fDynamicSymbolTable
->nindirectsyms(); ++i
) {
1816 uint32_t oldSymbolIndex
= E::get32(indirectTable
[i
]);
1817 uint32_t newSymbolIndex
= oldSymbolIndex
;
1818 if ( (oldSymbolIndex
!= INDIRECT_SYMBOL_ABS
) && (oldSymbolIndex
!= INDIRECT_SYMBOL_LOCAL
) ) {
1819 newSymbolIndex
= fOldToNewSymbolIndexes
[oldSymbolIndex
];
1820 //fprintf(stderr, "copyIndirectSymbolTable() old=%d, new=%u name=%s in %s\n", oldSymbolIndex, newSymbolIndex,
1821 // &fStrings[fSymbolTable[oldSymbolIndex].n_strx()], fLayout.getFilePath());
1823 E::set32(newIndirectTable
[i
], newSymbolIndex
);
1825 offset
+= (fDynamicSymbolTable
->nindirectsyms() * 4);
1828 template <typename A
>
1829 void LinkEditOptimizer
<A
>::updateLoadCommands(uint64_t newVMAddress
, uint64_t leSize
, uint32_t stringPoolOffset
,
1830 uint32_t linkEditsFileOffset
, bool keepSignatures
)
1832 // set LINKEDIT segment commmand to new merged LINKEDIT
1833 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
1834 const uint32_t cmd_count
= fHeader
->ncmds();
1835 const macho_load_command
<P
>* cmd
= cmds
;
1836 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1837 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
1838 macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
1839 if ( strcmp(seg
->segname(), "__LINKEDIT") == 0 ) {
1840 seg
->set_vmaddr(newVMAddress
);
1841 seg
->set_vmsize(leSize
);
1842 seg
->set_filesize(leSize
);
1843 seg
->set_fileoff(linkEditsFileOffset
);
1846 pint_t oldFileOff
= seg
->fileoff();
1847 // don't alter __TEXT until <rdar://problem/7022345> is fixed
1848 if ( strcmp(seg
->segname(), "__TEXT") != 0 ) {
1849 // update all other segments fileoff to be offset from start of cache file
1850 seg
->set_fileoff(fSharedCache
.cacheFileOffsetForVMAddress(seg
->vmaddr()));
1852 pint_t fileOffsetDelta
= seg
->fileoff() - oldFileOff
;
1853 const MachOLayoutAbstraction::Segment
* layoutSeg
= fLayout
.getSegment(seg
->segname());
1854 if ( layoutSeg
!= NULL
) {
1855 //if ( seg->filesize() != layoutSeg->fileSize() ) {
1856 // fprintf(stderr, "LC filesize=0x%08llX, trimmed seg file size=0x%08llX, seg=%s, path=%s\n",
1857 // seg->filesize(), layoutSeg->fileSize(), seg->segname(), fLayout.getFilePath());
1859 //if ( seg->vmsize() != layoutSeg->size() ) {
1860 // fprintf(stderr, "LC vmsize=0x%08llX, trimmed seg size=0x%08llX, seg=%s, path=%s\n",
1861 // seg->vmsize(), layoutSeg->size(), seg->segname(), fLayout.getFilePath());
1863 seg
->set_vmsize(layoutSeg
->size());
1864 seg
->set_filesize(layoutSeg
->fileSize());
1866 // update all sections in this segment
1867 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)seg
+ sizeof(macho_segment_command
<P
>));
1868 macho_section
<P
>* const sectionsEnd
= §ionsStart
[seg
->nsects()];
1869 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1870 if ( sect
->offset() != 0 )
1871 sect
->set_offset(sect
->offset()+fileOffsetDelta
);
1875 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1878 // update dyld_info with new offsets
1879 if ( fDyldInfo
!= NULL
) {
1880 fDyldInfo
->set_rebase_off(0);
1881 fDyldInfo
->set_rebase_size(0);
1882 fDyldInfo
->set_bind_off(linkEditsFileOffset
+fBindInfoOffsetIntoNewLinkEdit
);
1883 fDyldInfo
->set_bind_size(fBindInfoSizeInNewLinkEdit
);
1884 fDyldInfo
->set_weak_bind_off(linkEditsFileOffset
+fWeakBindInfoOffsetIntoNewLinkEdit
);
1885 fDyldInfo
->set_weak_bind_size(fWeakBindInfoSizeInNewLinkEdit
);
1886 fDyldInfo
->set_lazy_bind_off(linkEditsFileOffset
+fLazyBindInfoOffsetIntoNewLinkEdit
);
1887 fDyldInfo
->set_lazy_bind_size(fLazyBindInfoSizeInNewLinkEdit
);
1888 fDyldInfo
->set_export_off(linkEditsFileOffset
+fExportInfoOffsetIntoNewLinkEdit
);
1889 fDyldInfo
->set_export_size(fExportInfoSizeInNewLinkEdit
);
1891 // fprintf(stderr, "dylib %s\n", fLayout.getFilePath());
1892 // fprintf(stderr, " bind_off=0x%08X\n", fDyldInfo->bind_off());
1893 // fprintf(stderr, " export_off=0x%08X\n", fDyldInfo->export_off());
1894 // fprintf(stderr, " export_size=%d\n", fDyldInfo->export_size());
1898 // update symbol table and dynamic symbol table with new offsets
1899 fSymbolTableLoadCommand
->set_symoff(linkEditsFileOffset
+fSymbolTableStartOffsetInNewLinkEdit
);
1900 fSymbolTableLoadCommand
->set_nsyms(fLocalSymbolsCountInNewLinkEdit
+fExportedSymbolsCountInNewLinkEdit
+fImportedSymbolsCountInNewLinkEdit
);
1901 fSymbolTableLoadCommand
->set_stroff(linkEditsFileOffset
+stringPoolOffset
);
1902 fSymbolTableLoadCommand
->set_strsize(fNewStringPool
.size());
1903 fDynamicSymbolTable
->set_ilocalsym(0);
1904 fDynamicSymbolTable
->set_nlocalsym(fLocalSymbolsCountInNewLinkEdit
);
1905 fDynamicSymbolTable
->set_iextdefsym(fExportedSymbolsStartIndexInNewLinkEdit
-fLocalSymbolsStartIndexInNewLinkEdit
);
1906 fDynamicSymbolTable
->set_nextdefsym(fExportedSymbolsCountInNewLinkEdit
);
1907 fDynamicSymbolTable
->set_iundefsym(fImportSymbolsStartIndexInNewLinkEdit
-fLocalSymbolsStartIndexInNewLinkEdit
);
1908 fDynamicSymbolTable
->set_nundefsym(fImportedSymbolsCountInNewLinkEdit
);
1909 fDynamicSymbolTable
->set_tocoff(0);
1910 fDynamicSymbolTable
->set_ntoc(0);
1911 fDynamicSymbolTable
->set_modtaboff(0);
1912 fDynamicSymbolTable
->set_nmodtab(0);
1913 fDynamicSymbolTable
->set_indirectsymoff(linkEditsFileOffset
+fIndirectSymbolTableOffsetInfoNewLinkEdit
);
1914 fDynamicSymbolTable
->set_extreloff(linkEditsFileOffset
+fExternalRelocationsOffsetIntoNewLinkEdit
);
1915 fDynamicSymbolTable
->set_locreloff(0);
1916 fDynamicSymbolTable
->set_nlocrel(0);
1918 // update function starts
1919 if ( fFunctionStarts
!= NULL
) {
1920 fFunctionStarts
->set_dataoff(linkEditsFileOffset
+fFunctionStartsOffsetInNewLinkEdit
);
1922 // update data-in-code info
1923 if ( fDataInCode
!= NULL
) {
1924 fDataInCode
->set_dataoff(linkEditsFileOffset
+fDataInCodeOffsetInNewLinkEdit
);
1927 // now remove load commands no longer needed
1928 const macho_load_command
<P
>* srcCmd
= cmds
;
1929 macho_load_command
<P
>* dstCmd
= (macho_load_command
<P
>*)cmds
;
1930 int32_t newCount
= 0;
1931 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1932 uint32_t cmdSize
= srcCmd
->cmdsize();
1933 switch ( srcCmd
->cmd() ) {
1934 case LC_SEGMENT_SPLIT_INFO
:
1935 case LC_DYLIB_CODE_SIGN_DRS
:
1938 case LC_CODE_SIGNATURE
:
1939 if ( !keepSignatures
)
1941 // otherwise fall into copy case
1943 memmove(dstCmd
, srcCmd
, cmdSize
);
1944 dstCmd
= (macho_load_command
<P
>*)(((uint8_t*)dstCmd
)+cmdSize
);
1948 srcCmd
= (const macho_load_command
<P
>*)(((uint8_t*)srcCmd
)+cmdSize
);
1950 // zero out stuff removed
1951 bzero(dstCmd
, (uint8_t*)srcCmd
- (uint8_t*)dstCmd
);
1953 // update mach_header
1954 macho_header
<P
>* writableHeader
= (macho_header
<P
>*)fHeader
;
1955 writableHeader
->set_ncmds(newCount
);
1956 writableHeader
->set_sizeofcmds((uint8_t*)dstCmd
- ((uint8_t*)fHeader
+ sizeof(macho_header
<P
>)));
1958 // this invalidates some ivars
1959 fDynamicSymbolTable
= NULL
;
1960 fSymbolTableLoadCommand
= NULL
;
1962 fSymbolTable
= NULL
;
1968 template <typename A
>
1969 uint8_t* SharedCache
<A
>::optimizeLINKEDIT(bool keepSignatures
, bool dontMapLocalSymbols
)
1971 // allocate space for optimized LINKEDIT area
1972 uint8_t* newLinkEdit
= new uint8_t[fLinkEditsTotalUnoptimizedSize
];
1973 bzero(newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
1975 // make a string pool
1976 StringPool stringPool
;
1978 // create optimizer object for each LINKEDIT segment
1979 std::vector
<LinkEditOptimizer
<A
>*> optimizers
;
1980 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1981 optimizers
.push_back(new LinkEditOptimizer
<A
>(*it
->layout
, *this, newLinkEdit
, stringPool
));
1984 // rebase info is not copied because images in shared cache are never rebased
1986 // copy weak bind info
1987 uint32_t offset
= 0;
1988 fOffsetOfWeakBindInfoInCombinedLinkedit
= offset
;
1989 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1990 (*it
)->copyWeakBindInfo(offset
);
1994 fOffsetOfExportInfoInCombinedLinkedit
= offset
;
1995 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1996 (*it
)->copyExportInfo(offset
);
2000 fOffsetOfBindInfoInCombinedLinkedit
= offset
;
2001 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2002 (*it
)->copyBindInfo(offset
);
2005 // copy lazy bind info
2006 fOffsetOfLazyBindInfoInCombinedLinkedit
= offset
;
2007 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2008 (*it
)->copyLazyBindInfo(offset
);
2011 // copy symbol table entries
2012 fOffsetOfOldSymbolTableInfoInCombinedLinkedit
= offset
;
2013 uint32_t symbolTableOffset
= offset
;
2014 uint32_t symbolTableIndex
= 0;
2015 if ( dontMapLocalSymbols
)
2016 fUnmappedLocalSymbols
.reserve(16384);
2017 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2018 (*it
)->copyLocalSymbols(symbolTableOffset
, symbolTableIndex
, dontMapLocalSymbols
, fInMemoryCache
,
2019 fUnmappedLocalsStringPool
, fUnmappedLocalSymbols
, fLocalSymbolInfos
);
2020 (*it
)->copyExportedSymbols(symbolTableOffset
, symbolTableIndex
);
2021 (*it
)->copyImportedSymbols(symbolTableOffset
, symbolTableIndex
);
2023 fSizeOfOldSymbolTableInfoInCombinedLinkedit
= symbolTableIndex
* sizeof(macho_nlist
<typename
A::P
>);
2024 offset
= symbolTableOffset
+ fSizeOfOldSymbolTableInfoInCombinedLinkedit
& (-8);
2026 // copy external relocations, 8-byte aligned after end of symbol table
2027 fOffsetOfOldExternalRelocationsInCombinedLinkedit
= offset
;
2028 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2029 (*it
)->copyExternalRelocations(offset
);
2031 fSizeOfOldExternalRelocationsInCombinedLinkedit
= offset
- fOffsetOfOldExternalRelocationsInCombinedLinkedit
;
2033 // copy function starts
2034 fOffsetOfFunctionStartsInCombinedLinkedit
= offset
;
2035 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2036 (*it
)->copyFunctionStarts(offset
);
2038 fSizeOfFunctionStartsInCombinedLinkedit
= offset
- fOffsetOfFunctionStartsInCombinedLinkedit
;
2040 // copy data-in-code info
2041 fOffsetOfDataInCodeInCombinedLinkedit
= offset
;
2042 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2043 (*it
)->copyDataInCode(offset
);
2045 fSizeOfDataInCodeInCombinedLinkedit
= offset
- fOffsetOfDataInCodeInCombinedLinkedit
;
2047 // copy indirect symbol tables
2048 fOffsetOfOldIndirectSymbolsInCombinedLinkedit
= offset
;
2049 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2050 (*it
)->copyIndirectSymbolTable(offset
);
2052 fSizeOfOldIndirectSymbolsInCombinedLinkedit
= offset
- fOffsetOfOldIndirectSymbolsInCombinedLinkedit
;
2055 fOffsetOfOldStringPoolInCombinedLinkedit
= offset
;
2056 memcpy(&newLinkEdit
[offset
], stringPool
.getBuffer(), stringPool
.size());
2057 fSizeOfOldStringPoolInCombinedLinkedit
= stringPool
.size();
2059 // total new size round up to page size
2060 fLinkEditsTotalOptimizedSize
= pageAlign(fOffsetOfOldStringPoolInCombinedLinkedit
+ fSizeOfOldStringPoolInCombinedLinkedit
);
2062 // choose new linkedit file offset
2063 uint32_t linkEditsFileOffset
= cacheFileOffsetForVMAddress(fLinkEditsStartAddress
);
2064 // uint32_t linkEditsFileOffset = fLinkEditsStartAddress - sharedRegionStartAddress();
2066 // update load commands so that all dylibs shared different areas of the same LINKEDIT segment
2067 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
2068 (*it
)->updateLoadCommands(fLinkEditsStartAddress
, fLinkEditsTotalOptimizedSize
, fOffsetOfOldStringPoolInCombinedLinkedit
, linkEditsFileOffset
, keepSignatures
);
2071 //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, fLinkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, fLinkEditsTotalOptimizedSize);
2072 //printf(stderr, "mega link edit mapped starting at: %p\n", fFirstLinkEditSegment->mappedAddress());
2074 // overwrite mapped LINKEDIT area with new optimized LINKEDIT segment
2075 memcpy(fFirstLinkEditSegment
->mappedAddress(), newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
2077 // update all LINKEDIT Segment objects to point to same merged LINKEDIT area
2078 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2079 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
2080 for(int i
=0; i
< segs
.size(); ++i
) {
2081 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
2082 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
2083 seg
.setNewAddress(fLinkEditsStartAddress
);
2084 seg
.setMappedAddress(fFirstLinkEditSegment
->mappedAddress());
2085 seg
.setSize(fLinkEditsTotalOptimizedSize
);
2086 seg
.setFileSize(fLinkEditsTotalOptimizedSize
);
2087 seg
.setFileOffset(linkEditsFileOffset
);
2092 // return new end of cache
2093 return (uint8_t*)fFirstLinkEditSegment
->mappedAddress() + regionAlign(fLinkEditsTotalOptimizedSize
);
2097 template <typename A
>
2098 class ObjCSelectorUniquer
2101 objc_opt::string_map fSelectorStrings
;
2102 SharedCache
<A
> *fCache
;
2107 ObjCSelectorUniquer(SharedCache
<A
> *newCache
)
2108 : fSelectorStrings()
2113 typename
A::P::uint_t
visit(typename
A::P::uint_t oldValue
)
2116 const char *s
= (const char *)
2117 fCache
->mappedAddressForVMAddress(oldValue
);
2118 objc_opt::string_map::iterator element
=
2119 fSelectorStrings
.insert(objc_opt::string_map::value_type(s
, oldValue
)).first
;
2120 return (typename
A::P::uint_t
)element
->second
;
2123 objc_opt::string_map
& strings() {
2124 return fSelectorStrings
;
2127 size_t count() const { return fCount
; }
2131 template <typename A
>
2132 class ClassListBuilder
2135 typedef typename
A::P P
;
2137 objc_opt::string_map fClassNames
;
2138 objc_opt::class_map fClasses
;
2140 HeaderInfoOptimizer
<A
>& fHinfos
;
2144 ClassListBuilder(HeaderInfoOptimizer
<A
>& hinfos
)
2151 void visitClass(SharedCache
<A
>* cache
,
2152 const macho_header
<P
>* header
,
2153 objc_class_t
<A
>* cls
)
2155 if (cls
->isMetaClass(cache
)) return;
2157 const char *name
= cls
->getName(cache
);
2158 uint64_t name_vmaddr
= cache
->VMAddressForMappedAddress(name
);
2159 uint64_t cls_vmaddr
= cache
->VMAddressForMappedAddress(cls
);
2160 uint64_t hinfo_vmaddr
= cache
->VMAddressForMappedAddress(fHinfos
.hinfoForHeader(cache
, header
));
2161 fClassNames
.insert(objc_opt::string_map::value_type(name
, name_vmaddr
));
2162 fClasses
.insert(objc_opt::class_map::value_type(name
, std::pair
<uint64_t, uint64_t>(cls_vmaddr
, hinfo_vmaddr
)));
2166 objc_opt::string_map
& classNames() {
2170 objc_opt::class_map
& classes() {
2174 size_t count() const { return fCount
; }
2178 static int percent(size_t num
, size_t denom
) {
2179 if (denom
) return (int)(num
/ (double)denom
* 100);
2183 template <typename A
>
2184 void SharedCache
<A
>::optimizeObjC(std::vector
<void*>& pointersInData
)
2189 fprintf(stderr
, "update_dyld_shared_cache: for %s, optimizing objc metadata\n", archName());
2192 size_t headerSize
= P::round_up(sizeof(objc_opt::objc_opt_t
));
2193 if (headerSize
!= sizeof(objc_opt::objc_opt_t
)) {
2194 warn(archName(), "libobjc's optimization structure size is wrong (metadata not optimized)");
2197 // Find libobjc's empty sections to fill in
2198 const macho_section
<P
> *optROSection
= NULL
;
2199 const macho_section
<P
> *optRWSection
= NULL
;
2200 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2201 if ( strstr(it
->layout
->getFilePath(), "libobjc") != NULL
) {
2202 const macho_header
<P
>* mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2203 optROSection
= mh
->getSection("__TEXT", "__objc_opt_ro");
2204 optRWSection
= mh
->getSection("__DATA", "__objc_opt_rw");
2209 if ( optROSection
== NULL
) {
2210 warn(archName(), "libobjc's read-only section missing (metadata not optimized)");
2214 if ( optRWSection
== NULL
) {
2215 warn(archName(), "libobjc's read/write section missing (metadata not optimized)");
2219 uint8_t* optROData
= (uint8_t*)mappedAddressForVMAddress(optROSection
->addr());
2220 size_t optRORemaining
= optROSection
->size();
2222 uint8_t* optRWData
= (uint8_t*)mappedAddressForVMAddress(optRWSection
->addr());
2223 size_t optRWRemaining
= optRWSection
->size();
2225 if (optRORemaining
< headerSize
) {
2226 warn(archName(), "libobjc's read-only section is too small (metadata not optimized)");
2229 objc_opt::objc_opt_t
* optROHeader
= (objc_opt::objc_opt_t
*)optROData
;
2230 optROData
+= headerSize
;
2231 optRORemaining
-= headerSize
;
2233 if (E::get32(optROHeader
->version
) != objc_opt::VERSION
) {
2234 warn(archName(), "libobjc's read-only section version is unrecognized (metadata not optimized)");
2238 // Write nothing to optROHeader until everything else is written.
2239 // If something fails below, libobjc will not use the section.
2241 // Find objc-containing dylibs
2242 std::vector
<LayoutInfo
> objcDylibs
;
2243 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2244 macho_header
<P
> *mh
= (macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2245 if (mh
->getSection("__DATA", "__objc_imageinfo") || mh
->getSegment("__OBJC")) {
2246 objcDylibs
.push_back(*it
);
2252 // This is SAFE: the binaries themselves are unmodified.
2254 std::vector
<LayoutInfo
> addressSortedDylibs
= objcDylibs
;
2255 std::sort(addressSortedDylibs
.begin(), addressSortedDylibs
.end(), ByAddressSorter());
2257 uint64_t hinfoVMAddr
= optRWSection
->addr() + optRWSection
->size() - optRWRemaining
;
2258 HeaderInfoOptimizer
<A
> hinfoOptimizer
;
2259 err
= hinfoOptimizer
.init(objcDylibs
.size(), optRWData
, optRWRemaining
);
2261 warn(archName(), err
);
2264 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= addressSortedDylibs
.begin(); it
!= addressSortedDylibs
.end(); ++it
) {
2265 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2266 hinfoOptimizer
.update(this, mh
, pointersInData
);
2270 // Update selector references and build selector list
2272 // This is SAFE: if we run out of room for the selector table,
2273 // the modified binaries are still usable.
2275 // Heuristic: choose selectors from libraries with more cstring data first.
2276 // This tries to localize selector cstring memory.
2277 ObjCSelectorUniquer
<A
> uniq(this);
2278 std::vector
<LayoutInfo
> sizeSortedDylibs
= objcDylibs
;
2279 std::sort(sizeSortedDylibs
.begin(), sizeSortedDylibs
.end(), ByCStringSectionSizeSorter());
2281 SelectorOptimizer
<A
, ObjCSelectorUniquer
<A
> > selOptimizer(uniq
);
2282 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2283 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2284 LegacySelectorUpdater
<A
, ObjCSelectorUniquer
<A
> >::update(this, mh
, uniq
);
2285 selOptimizer
.optimize(this, mh
);
2288 uint64_t seloptVMAddr
= optROSection
->addr() + optROSection
->size() - optRORemaining
;
2289 objc_opt::objc_selopt_t
*selopt
= new(optROData
) objc_opt::objc_selopt_t
;
2290 err
= selopt
->write(seloptVMAddr
, optRORemaining
, uniq
.strings());
2292 warn(archName(), err
);
2295 optROData
+= selopt
->size();
2296 optRORemaining
-= selopt
->size();
2297 selopt
->byteswap(E::little_endian
), selopt
= NULL
;
2300 // Build class table.
2302 // This is SAFE: the binaries themselves are unmodified.
2304 ClassListBuilder
<A
> classes(hinfoOptimizer
);
2305 ClassWalker
< A
, ClassListBuilder
<A
> > classWalker(classes
);
2306 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2307 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2308 classWalker
.walk(this, mh
);
2311 uint64_t clsoptVMAddr
= optROSection
->addr() + optROSection
->size() - optRORemaining
;
2312 objc_opt::objc_clsopt_t
*clsopt
= new(optROData
) objc_opt::objc_clsopt_t
;
2313 err
= clsopt
->write(clsoptVMAddr
, optRORemaining
,
2314 classes
.classNames(), classes
.classes(), verbose
);
2316 warn(archName(), err
);
2319 optROData
+= clsopt
->size();
2320 optRORemaining
-= clsopt
->size();
2321 size_t duplicateCount
= clsopt
->duplicateCount();
2322 clsopt
->byteswap(E::little_endian
), clsopt
= NULL
;
2325 // Sort method lists.
2327 // This is SAFE: modified binaries are still usable as unsorted lists.
2328 // This must be done AFTER uniquing selectors.
2330 MethodListSorter
<A
> methodSorter
;
2331 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2332 macho_header
<P
> *mh
= (macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2333 methodSorter
.optimize(this, mh
);
2337 // Repair ivar offsets.
2339 // This is SAFE: the runtime always validates ivar offsets at runtime.
2341 IvarOffsetOptimizer
<A
> ivarOffsetOptimizer
;
2342 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2343 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2344 ivarOffsetOptimizer
.optimize(this, mh
);
2348 // Success. Mark dylibs as optimized.
2349 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2350 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2351 const macho_section
<P
> *imageInfoSection
;
2352 imageInfoSection
= mh
->getSection("__DATA", "__objc_imageinfo");
2353 if (!imageInfoSection
) {
2354 imageInfoSection
= mh
->getSection("__OBJC", "__image_info");
2356 if (imageInfoSection
) {
2357 objc_image_info
<A
> *info
= (objc_image_info
<A
> *)
2358 mappedAddressForVMAddress(imageInfoSection
->addr());
2359 info
->setOptimizedByDyld();
2364 // Success. Update RO header last.
2365 E::set32(optROHeader
->selopt_offset
, seloptVMAddr
- optROSection
->addr());
2366 E::set32(optROHeader
->clsopt_offset
, clsoptVMAddr
- optROSection
->addr());
2367 E::set32(optROHeader
->headeropt_offset
, hinfoVMAddr
- optROSection
->addr());
2370 size_t roSize
= optROSection
->size() - optRORemaining
;
2371 size_t rwSize
= optRWSection
->size() - optRWRemaining
;
2372 fprintf(stderr
, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
2373 "(%d%%) used in libobjc read-only optimization section\n",
2374 archName(), roSize
, optROSection
->size(),
2375 percent(roSize
, optROSection
->size()));
2376 fprintf(stderr
, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
2377 "(%d%%) used in libobjc read/write optimization section\n",
2378 archName(), rwSize
, optRWSection
->size(),
2379 percent(rwSize
, optRWSection
->size()));
2380 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2381 "uniqued %zu selectors\n",
2382 archName(), uniq
.strings().size());
2383 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2384 "updated %zu selector references\n",
2385 archName(), uniq
.count());
2386 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2387 "updated %zu ivar offsets\n",
2388 archName(), ivarOffsetOptimizer
.optimized());
2389 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2390 "sorted %zu method lists\n",
2391 archName(), methodSorter
.optimized());
2392 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2393 "recorded %zu classes (%zu duplicates)\n",
2394 archName(), classes
.classNames().size(), duplicateCount
);
2395 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2396 "wrote objc metadata optimization version %d\n",
2397 archName(), objc_opt::VERSION
);
2404 static const char* sCleanupFile
= NULL
;
2405 static void cleanup(int sig
)
2407 ::signal(sig
, SIG_DFL
);
2408 if ( sCleanupFile
!= NULL
)
2409 ::unlink(sCleanupFile
);
2411 // fprintf(stderr, "update_dyld_shared_cache: deleting temp file in response to a signal\n");
2412 if ( sig
== SIGINT
)
2417 // <rdar://problem/10730767> update_dyld_shared_cache should use sync_volume_np() instead of sync()
2418 static void sync_volume(const char* volumePath
)
2420 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
2421 int error
= sync_volume_np(volumePath
, SYNC_VOLUME_FULLSYNC
|SYNC_VOLUME_FULLSYNC
);
2423 int full_sync
= 3; // SYNC_VOLUME_FULLSYNC | SYNC_VOLUME_FULLSYNC
2425 if ( fsctl(volumePath
, 0x80004101 /*FSCTL_SYNC_VOLUME*/, &full_sync
, 0) == -1)
2433 // <rdar://problem/12552226> update shared cache should sign the shared cache
2434 static bool adhoc_codesign_share_cache(const char* path
)
2436 CFURLRef target
= ::CFURLCreateFromFileSystemRepresentation(NULL
, (const UInt8
*)path
, strlen(path
), FALSE
);
2437 if ( target
== NULL
)
2440 SecStaticCodeRef code
;
2441 OSStatus status
= ::SecStaticCodeCreateWithPath(target
, kSecCSDefaultFlags
, &code
);
2444 ::fprintf(stderr
, "codesign: failed to create url to signed object\n");
2448 const void * keys
[1] = { (void *)kSecCodeSignerIdentity
} ;
2449 const void * values
[1] = { (void *)kCFNull
};
2450 CFDictionaryRef params
= ::CFDictionaryCreate(NULL
, keys
, values
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2451 if ( params
== NULL
) {
2456 SecCodeSignerRef signer
;
2457 status
= ::SecCodeSignerCreate(params
, kSecCSDefaultFlags
, &signer
);
2461 ::fprintf(stderr
, "codesign: failed to create signer object\n");
2465 status
= ::SecCodeSignerAddSignatureWithErrors(signer
, code
, kSecCSDefaultFlags
, NULL
);
2469 ::fprintf(stderr
, "codesign: failed to sign object: %s\n", path
);
2474 ::fprintf(stderr
, "codesigning complete of %s\n", path
);
2481 template <> bool SharedCache
<x86_64
>::addCacheSlideInfo(){ return true; }
2482 template <> bool SharedCache
<arm
>::addCacheSlideInfo() { return true; }
2483 template <> bool SharedCache
<x86
>::addCacheSlideInfo() { return false; }
2484 template <> bool SharedCache
<arm64
>::addCacheSlideInfo() { return true; }
2487 template <typename A
>
2488 bool SharedCache
<A
>::update(bool force
, bool optimize
, bool deleteExistingFirst
, int archIndex
,
2489 int archCount
, bool keepSignatures
, bool dontMapLocalSymbols
)
2491 bool didUpdate
= false;
2493 // already up to date?
2494 if ( force
|| fExistingIsNotUpToDate
) {
2496 fprintf(stderr
, "update_dyld_shared_cache: regenerating %s\n", fCacheFilePath
);
2497 if ( fDylibs
.size() == 0 ) {
2498 fprintf(stderr
, "update_dyld_shared_cache: warning, empty cache not generated for arch %s\n", archName());
2501 // delete existing cache while building the new one
2502 // this is a flag to dyld to stop pinging update_dyld_shared_cache
2503 if ( deleteExistingFirst
)
2504 ::unlink(fCacheFilePath
);
2505 uint8_t* inMemoryCache
= NULL
;
2506 uint32_t allocatedCacheSize
= 0;
2507 char tempCachePath
[strlen(fCacheFilePath
)+16];
2508 sprintf(tempCachePath
, "%s.tmp%u", fCacheFilePath
, getpid());
2510 // allocate a memory block to hold cache
2511 uint32_t cacheFileSize
= 0;
2512 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
2513 uint32_t end
= it
->sfm_file_offset
+ it
->sfm_size
;
2514 if ( end
> cacheFileSize
)
2515 cacheFileSize
= end
;
2517 if ( vm_allocate(mach_task_self(), (vm_address_t
*)(&inMemoryCache
), cacheFileSize
, VM_FLAGS_ANYWHERE
) != KERN_SUCCESS
)
2518 throwf("can't vm_allocate cache of size %u", cacheFileSize
);
2519 allocatedCacheSize
= cacheFileSize
;
2520 fInMemoryCache
= inMemoryCache
;
2523 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2524 const char* archPairName
= fArchGraph
->archName();
2526 strcpy(temp
, "dyld_v1 ");
2527 strcpy(&temp
[15-strlen(archPairName
)], archPairName
);
2528 header
->set_magic(temp
);
2529 //header->set_architecture(arch());
2530 header
->set_mappingOffset(sizeof(dyldCacheHeader
<E
>));
2531 header
->set_mappingCount(fMappings
.size());
2532 header
->set_imagesOffset(header
->mappingOffset() + fMappings
.size()*sizeof(dyldCacheFileMapping
<E
>));
2533 header
->set_imagesCount(fDylibs
.size()+fDylibAliases
.size());
2534 header
->set_dyldBaseAddress(fDyldBaseAddress
);
2535 header
->set_codeSignatureOffset(cacheFileSize
);
2536 header
->set_codeSignatureSize(0);
2537 header
->set_slideInfoOffset(0);
2538 header
->set_slideInfoSize(0);
2539 header
->set_localSymbolsOffset(0);
2540 header
->set_localSymbolsSize(0);
2543 dyldCacheFileMapping
<E
>* mapping
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
2544 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
2546 fprintf(stderr
, "update_dyld_shared_cache: cache mappings: address=0x%0llX, size=0x%0llX, fileOffset=0x%0llX, prot=0x%X\n",
2547 it
->sfm_address
, it
->sfm_size
, it
->sfm_file_offset
, it
->sfm_init_prot
);
2548 mapping
->set_address(it
->sfm_address
);
2549 mapping
->set_size(it
->sfm_size
);
2550 mapping
->set_file_offset(it
->sfm_file_offset
);
2551 mapping
->set_max_prot(it
->sfm_max_prot
);
2552 mapping
->set_init_prot(it
->sfm_init_prot
);
2556 // fill in image table
2557 dyldCacheImageInfo
<E
>* image
= (dyldCacheImageInfo
<E
>*)mapping
;
2558 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2559 image
->set_address(it
->info
.address
);
2560 image
->set_modTime(it
->info
.modTime
);
2561 image
->set_inode(it
->info
.inode
);
2562 image
->set_pathFileOffset(cacheFileOffsetForVMAddress(it
->info
.address
+it
->info
.pathFileOffset
));
2566 // add aliases to end of image table
2567 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibAliases
.begin(); it
!= fDylibAliases
.end(); ++it
) {
2568 image
->set_address(it
->info
.address
);
2569 image
->set_modTime(it
->info
.modTime
);
2570 image
->set_inode(it
->info
.inode
);
2571 image
->set_pathFileOffset(it
->info
.pathFileOffset
);
2572 strcpy((char*)inMemoryCache
+it
->info
.pathFileOffset
, it
->aliases
[0]);
2573 //fprintf(stderr, "adding alias to offset 0x%08X %s\n", it->info.pathFileOffset, it->aliases[0]);
2577 // copy each segment to cache buffer
2578 const int dylibCount
= fDylibs
.size();
2580 int progressIndex
= 0;
2581 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++dylibIndex
) {
2582 const char* path
= it
->layout
->getFilePath();
2583 int src
= ::open(path
, O_RDONLY
, 0);
2585 throwf("can't open file %s, errnor=%d", it
->layout
->getID().name
, errno
);
2586 // mark source as "don't cache"
2587 (void)fcntl(src
, F_NOCACHE
, 1);
2588 // verify file has not changed since dependency analysis
2589 struct stat stat_buf
;
2590 if ( fstat(src
, &stat_buf
) == -1)
2591 throwf("can't stat open file %s, errno=%d", path
, errno
);
2592 if ( (it
->layout
->getInode() != stat_buf
.st_ino
) )
2593 throwf("file inode changed from %llu to %llu during cache creation: %s", it
->layout
->getInode(), stat_buf
.st_ino
, path
);
2594 else if ( it
->layout
->getLastModTime() != stat_buf
.st_mtime
)
2595 throwf("file mtime changed from 0x%lX to 0x%lX during cache creation: %s", it
->layout
->getLastModTime(), stat_buf
.st_mtime
, path
);
2598 fprintf(stderr
, "update_dyld_shared_cache: copying %s to cache\n", it
->layout
->getFilePath());
2600 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
2601 for (int i
=0; i
< segs
.size(); ++i
) {
2602 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
2604 fprintf(stderr
, "\t\tsegment %s, size=0x%0llX, cache address=0x%0llX\n", seg
.name(), seg
.fileSize(), seg
.newAddress());
2605 if ( seg
.size() > 0 ) {
2606 const uint64_t segmentSrcStartOffset
= it
->layout
->getOffsetInUniversalFile()+seg
.fileOffset();
2607 const uint64_t segmentSize
= seg
.fileSize();
2608 const uint64_t segmentDstStartOffset
= cacheFileOffsetForVMAddress(seg
.newAddress());
2609 ssize_t readResult
= ::pread(src
, &inMemoryCache
[segmentDstStartOffset
], segmentSize
, segmentSrcStartOffset
);
2610 if ( readResult
!= segmentSize
) {
2611 if ( readResult
== -1 )
2612 throwf("read failure copying dylib errno=%d for %s", errno
, it
->layout
->getID().name
);
2614 throwf("read failure copying dylib. Read of %lld bytes at file offset %lld returned %ld for %s",
2615 segmentSize
, segmentSrcStartOffset
, readResult
, it
->layout
->getID().name
);
2620 catch (const char* msg
) {
2621 throwf("%s while copying %s to shared cache", msg
, it
->layout
->getID().name
);
2625 // assuming read takes 40% of time
2626 int nextProgressIndex
= archIndex
*100+(40*dylibIndex
)/dylibCount
;
2627 if ( nextProgressIndex
!= progressIndex
)
2628 fprintf(stdout
, "%3u/%u\n", nextProgressIndex
, archCount
*100);
2629 progressIndex
= nextProgressIndex
;
2633 // set mapped address for each segment
2634 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2635 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
2636 for (int i
=0; i
< segs
.size(); ++i
) {
2637 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
2638 if ( seg
.size() > 0 )
2639 seg
.setMappedAddress(inMemoryCache
+ cacheFileOffsetForVMAddress(seg
.newAddress()));
2640 //fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
2644 // also construct list of all pointers in cache to other things in cache
2645 std::vector
<void*> pointersInData
;
2646 pointersInData
.reserve(1024);
2648 // rebase each dylib in shared cache
2649 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2651 Rebaser
<A
> r(*it
->layout
);
2652 r
.rebase(pointersInData
);
2654 // fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
2656 catch (const char* msg
) {
2657 throwf("%s in %s", msg
, it
->layout
->getID().name
);
2662 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs
.size());
2663 // instantiate a Binder for each image and add to map
2664 typename Binder
<A
>::Map map
;
2665 std::vector
<Binder
<A
>*> binders
;
2666 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2667 //fprintf(stderr, "binding %s\n", it->layout->getID().name);
2668 Binder
<A
>* binder
= new Binder
<A
>(*it
->layout
, fDyldBaseAddress
);
2669 binders
.push_back(binder
);
2670 // only add dylibs to map
2671 if ( it
->layout
->getID().name
!= NULL
)
2672 map
[it
->layout
->getID().name
] = binder
;
2675 // tell each Binder about the others
2676 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2677 (*it
)->setDependentBinders(map
);
2680 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2682 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it
)->getDylibID());
2684 (*it
)->bind(pointersInData
);
2686 catch (const char* msg
) {
2687 throwf("%s in %s", msg
, (*it
)->getDylibID());
2691 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2695 catch (const char* msg
) {
2696 throwf("%s in %s", msg
, (*it
)->getDylibID());
2700 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2704 // merge/optimize all LINKEDIT segments
2706 //fprintf(stderr, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize/(1024*1024));
2707 cacheFileSize
= (this->optimizeLINKEDIT(keepSignatures
, dontMapLocalSymbols
) - inMemoryCache
);
2708 //fprintf(stderr, "update_dyld_shared_cache: optimized cache file size 0x%08X %uMB\n", cacheFileSize, cacheFileSize/(1024*1024));
2709 // update header to reduce mapping size
2710 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2711 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
2712 dyldCacheFileMapping
<E
>* lastMapping
= &mappings
[cacheHeader
->mappingCount()-1];
2713 lastMapping
->set_size(cacheFileSize
-lastMapping
->file_offset());
2714 // update fMappings so .map file will print correctly
2715 fMappings
.back().sfm_size
= cacheFileSize
-fMappings
.back().sfm_file_offset
;
2717 //fprintf(stderr, "update_dyld_shared_cache: changing end of cache address from 0x%08llX to 0x%08llX\n",
2718 // header->codeSignatureOffset(), fMappings.back().sfm_address + fMappings.back().sfm_size);
2719 header
->set_codeSignatureOffset(fMappings
.back().sfm_file_offset
+ fMappings
.back().sfm_size
);
2722 // unique objc selectors and update other objc metadata
2724 optimizeObjC(pointersInData
);
2726 // assuming objc optimizations takes 15% of time
2727 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*55, archCount
*100);
2731 if ( addCacheSlideInfo() ) {
2732 // build bitmap of which pointers need sliding
2733 uint8_t* const dataStart
= &inMemoryCache
[fMappings
[1].sfm_file_offset
]; // R/W mapping is always second
2734 uint8_t* const dataEnd
= &inMemoryCache
[fMappings
[1].sfm_file_offset
+fMappings
[1].sfm_size
];
2735 const int bitmapSize
= (dataEnd
- dataStart
)/(4*8);
2736 uint8_t* bitmap
= (uint8_t*)calloc(bitmapSize
, 1);
2737 void* lastPointer
= inMemoryCache
;
2738 for(std::vector
<void*>::iterator pit
=pointersInData
.begin(); pit
!= pointersInData
.end(); ++pit
) {
2739 if ( *pit
!= lastPointer
) {
2741 if ( (p
< dataStart
) || ( p
> dataEnd
) )
2742 throwf("DATA pointer for sliding, out of range 0x%08lX\n", (long)((uint8_t*)p
-inMemoryCache
));
2743 long offset
= (long)((uint8_t*)p
- dataStart
);
2744 if ( (offset
% 4) != 0 )
2745 throwf("pointer not 4-byte aligned in DATA offset 0x%08lX\n", offset
);
2746 long byteIndex
= offset
/ (4*8);
2747 long bitInByte
= (offset
% 32) >> 2;
2748 bitmap
[byteIndex
] |= (1 << bitInByte
);
2753 // allocate worst case size block of all slide info
2754 const int entry_size
= 4096/(8*4); // 8 bits per byte, possible pointer every 4 bytes.
2755 const int toc_count
= bitmapSize
/entry_size
;
2756 int slideInfoSize
= sizeof(dyldCacheSlideInfo
<E
>) + 2*toc_count
+ entry_size
*(toc_count
+1);
2757 dyldCacheSlideInfo
<E
>* slideInfo
= (dyldCacheSlideInfo
<E
>*)calloc(slideInfoSize
, 1);
2758 slideInfo
->set_version(1);
2759 slideInfo
->set_toc_offset(sizeof(dyldCacheSlideInfo
<E
>));
2760 slideInfo
->set_toc_count(toc_count
);
2761 slideInfo
->set_entries_offset((slideInfo
->toc_offset()+2*toc_count
+127)&(-128));
2762 slideInfo
->set_entries_count(0);
2763 slideInfo
->set_entries_size(entry_size
);
2764 // append each unique entry
2765 const dyldCacheSlideInfoEntry
* bitmapAsEntries
= (dyldCacheSlideInfoEntry
*)bitmap
;
2766 dyldCacheSlideInfoEntry
* const entriesInSlidInfo
= (dyldCacheSlideInfoEntry
*)((char*)slideInfo
+slideInfo
->entries_offset());
2767 int entry_count
= 0;
2768 for (int i
=0; i
< toc_count
; ++i
) {
2769 const dyldCacheSlideInfoEntry
* thisEntry
= &bitmapAsEntries
[i
];
2770 // see if it is same as one already added
2772 for (int j
=0; j
< entry_count
; ++j
) {
2773 if ( memcmp(thisEntry
, &entriesInSlidInfo
[j
], entry_size
) == 0 ) {
2774 //fprintf(stderr, "toc[%d] optimized to %d\n", i, j);
2775 slideInfo
->set_toc(i
, j
);
2782 memcpy(&entriesInSlidInfo
[entry_count
], thisEntry
, entry_size
);
2783 slideInfo
->set_toc(i
, entry_count
++);
2786 slideInfo
->set_entries_count(entry_count
);
2788 int slideInfoPageSize
= regionAlign(slideInfo
->entries_offset() + entry_count
*entry_size
);
2789 cacheFileSize
+= slideInfoPageSize
;
2791 // update mappings to increase RO size
2792 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2793 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
2794 dyldCacheFileMapping
<E
>* lastMapping
= &mappings
[cacheHeader
->mappingCount()-1];
2795 lastMapping
->set_size(lastMapping
->size()+slideInfoPageSize
);
2797 // update header to show location of slidePointers
2798 cacheHeader
->set_slideInfoOffset(cacheHeader
->codeSignatureOffset());
2799 cacheHeader
->set_slideInfoSize(slideInfoPageSize
);
2800 cacheHeader
->set_codeSignatureOffset(cacheHeader
->codeSignatureOffset()+slideInfoPageSize
);
2802 // update fMappings so .map file will print correctly
2803 fMappings
.back().sfm_size
= cacheFileSize
-fMappings
.back().sfm_file_offset
;
2805 // copy compressed into into buffer
2806 memcpy(&inMemoryCache
[cacheHeader
->slideInfoOffset()], slideInfo
, slideInfoPageSize
);
2809 // append local symbol info in an unmapped region
2810 if ( dontMapLocalSymbols
) {
2811 uint32_t spaceAtEnd
= allocatedCacheSize
- cacheFileSize
;
2812 uint32_t localSymbolsOffset
= pageAlign(cacheFileSize
);
2813 dyldCacheLocalSymbolsInfo
<E
>* infoHeader
= (dyldCacheLocalSymbolsInfo
<E
>*)(&inMemoryCache
[localSymbolsOffset
]);
2814 const uint32_t entriesOffset
= sizeof(dyldCacheLocalSymbolsInfo
<E
>);
2815 const uint32_t entriesCount
= fLocalSymbolInfos
.size();
2816 const uint32_t nlistOffset
= entriesOffset
+ entriesCount
* sizeof(dyldCacheLocalSymbolEntry
<E
>);
2817 const uint32_t nlistCount
= fUnmappedLocalSymbols
.size();
2818 const uint32_t stringsOffset
= nlistOffset
+ nlistCount
* sizeof(macho_nlist
<P
>);
2819 const uint32_t stringsSize
= fUnmappedLocalsStringPool
.size();
2820 if ( stringsOffset
+stringsSize
> spaceAtEnd
)
2821 throwf("update_dyld_shared_cache[%u] for arch=%s, out of space for local symbols. Have 0x%X, Need 0x%X\n",
2822 getpid(), fArchGraph
->archName(), spaceAtEnd
, stringsOffset
+stringsSize
);
2823 // fill in local symbols info
2824 infoHeader
->set_nlistOffset(nlistOffset
);
2825 infoHeader
->set_nlistCount(nlistCount
);
2826 infoHeader
->set_stringsOffset(stringsOffset
);
2827 infoHeader
->set_stringsSize(stringsSize
);
2828 infoHeader
->set_entriesOffset(entriesOffset
);
2829 infoHeader
->set_entriesCount(entriesCount
);
2830 // copy info for each dylib
2831 dyldCacheLocalSymbolEntry
<E
>* entries
= (dyldCacheLocalSymbolEntry
<E
>*)(&inMemoryCache
[localSymbolsOffset
+entriesOffset
]);
2832 for (int i
=0; i
< entriesCount
; ++i
) {
2833 entries
[i
].set_dylibOffset(fLocalSymbolInfos
[i
].dylibOffset
);
2834 entries
[i
].set_nlistStartIndex(fLocalSymbolInfos
[i
].nlistStartIndex
);
2835 entries
[i
].set_nlistCount(fLocalSymbolInfos
[i
].nlistCount
);
2838 memcpy(&inMemoryCache
[localSymbolsOffset
+nlistOffset
], &fUnmappedLocalSymbols
[0], nlistCount
*sizeof(macho_nlist
<P
>));
2840 memcpy(&inMemoryCache
[localSymbolsOffset
+stringsOffset
], fUnmappedLocalsStringPool
.getBuffer(), stringsSize
);
2843 fUnmappedLocalSymbolsSize
= pageAlign(stringsOffset
+ stringsSize
);
2844 cacheFileSize
= regionAlign(localSymbolsOffset
+ fUnmappedLocalSymbolsSize
);
2846 // update header to show location of slidePointers
2847 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2848 cacheHeader
->set_localSymbolsOffset(localSymbolsOffset
);
2849 cacheHeader
->set_localSymbolsSize(stringsOffset
+stringsSize
);
2850 cacheHeader
->set_codeSignatureOffset(cacheFileSize
);
2853 // make sure after all optimizations, that whole cache file fits into shared region address range
2855 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2856 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[cacheHeader
->mappingOffset()];
2857 // <rdar://problem/16128830> incorporate code signature size into overflow check
2858 uint32_t estCodeSigSize
= regionAlign(cacheFileSize
/200); // guess 0.5% for code signature
2859 for (int i
=0; i
< cacheHeader
->mappingCount(); ++i
) {
2860 uint64_t endAddr
= mappings
[i
].address() + mappings
[i
].size() + estCodeSigSize
;
2861 if ( endAddr
> (sharedRegionStartAddress() + sharedRegionSize()) ) {
2862 throwf("update_dyld_shared_cache[%u] for arch=%s, shared cache will not fit in shared regionsaddress space. Overflow amount: %lluKB\n",
2863 getpid(), fArchGraph
->archName(), (endAddr
-(sharedRegionStartAddress() + sharedRegionSize()))/1024);
2868 // compute UUID of whole cache
2870 CC_MD5(inMemoryCache
, cacheFileSize
, digest
);
2871 // <rdar://problem/6723729> uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
2872 digest
[6] = ( digest
[6] & 0x0F ) | ( 3 << 4 );
2873 digest
[8] = ( digest
[8] & 0x3F ) | 0x80;
2874 ((dyldCacheHeader
<E
>*)inMemoryCache
)->set_uuid(digest
);
2877 // if no existing cache, say so
2878 if ( fExistingCacheForVerification
== NULL
) {
2879 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
2880 getpid(), archName());
2882 // new cache is built, compare header entries
2883 const dyldCacheHeader
<E
>* newHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2884 const dyldCacheHeader
<E
>* oldHeader
= (dyldCacheHeader
<E
>*)fExistingCacheForVerification
;
2885 if ( newHeader
->mappingCount() != oldHeader
->mappingCount() ) {
2886 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because caches have a different number of mappings\n",
2887 getpid(), archName());
2889 const dyldCacheFileMapping
<E
>* newMappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[newHeader
->mappingOffset()];
2890 const dyldCacheFileMapping
<E
>* oldMappings
= (dyldCacheFileMapping
<E
>*)&fExistingCacheForVerification
[oldHeader
->mappingOffset()];
2891 for (int i
=0; i
< newHeader
->mappingCount(); ++i
) {
2892 if ( newMappings
[i
].address() != oldMappings
[i
].address() ) {
2893 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",
2894 getpid(), archName(), i
, newMappings
[i
].address(), oldMappings
[i
].address() );
2896 if ( newMappings
[i
].size() != oldMappings
[i
].size() ) {
2897 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because mapping %d has a different size\n",
2898 getpid(), archName(), i
);
2902 //fprintf(stderr, "%s existing cache = %p\n", archName(), fExistingCacheForVerification);
2903 //fprintf(stderr, "%s new cache = %p\n", archName(), inMemoryCache);
2904 // compare content to existing cache page by page
2905 for (int offset
=0; offset
< cacheFileSize
; offset
+= 4096) {
2906 if ( memcmp(&inMemoryCache
[offset
], &fExistingCacheForVerification
[offset
], 4096) != 0 ) {
2907 fprintf(stderr
, "verifier found differences on page offset 0x%08X for %s:\n", offset
, archName());
2908 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++dylibIndex
) {
2909 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
2910 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator sit
= segs
.begin(); sit
!= segs
.end(); ++sit
) {
2911 const MachOLayoutAbstraction::Segment
& seg
= *sit
;
2912 if ( (seg
.mappedAddress() <= &inMemoryCache
[offset
]) && (&inMemoryCache
[offset
] < ((uint8_t*)seg
.mappedAddress() + seg
.fileSize())) ) {
2913 // all LINKEDITs point to the same region, so just print one
2914 if ( strcmp(seg
.name(), "__LINKEDIT") == 0 )
2915 fprintf(stderr
, " in merged LINKEDIT segment\n");
2917 fprintf(stderr
, " in segment %s of dylib %s\n", seg
.name(), it
->layout
->getID().name
);
2922 for (int po
=0; po
< 4096; po
+= 16) {
2923 if ( memcmp(&inMemoryCache
[offset
+po
], &fExistingCacheForVerification
[offset
+po
], 16) != 0 ) {
2924 fprintf(stderr
, " existing: 0x%08X: ", offset
+po
);
2925 for ( int j
=0; j
< 16; ++j
)
2926 fprintf(stderr
, " 0x%02X", fExistingCacheForVerification
[offset
+po
+j
]);
2927 fprintf(stderr
, "\n");
2928 fprintf(stderr
, " should be: 0x%08X: ", offset
+po
);
2929 for ( int j
=0; j
< 16; ++j
)
2930 fprintf(stderr
, " 0x%02X", inMemoryCache
[offset
+po
+j
]);
2931 fprintf(stderr
, "\n");
2938 // install signal handlers to delete temp file if program is killed
2939 sCleanupFile
= tempCachePath
;
2940 ::signal(SIGINT
, cleanup
);
2941 ::signal(SIGBUS
, cleanup
);
2942 ::signal(SIGSEGV
, cleanup
);
2944 // create var/db/dyld dirs if needed
2945 char dyldDirs
[1024];
2946 strcpy(dyldDirs
, fCacheFilePath
);
2947 char* lastSlash
= strrchr(dyldDirs
, '/');
2948 if ( lastSlash
!= NULL
)
2949 lastSlash
[1] = '\0';
2950 struct stat stat_buf
;
2951 if ( stat(dyldDirs
, &stat_buf
) != 0 ) {
2952 const char* afterSlash
= &dyldDirs
[1];
2954 while ( (slash
= strchr(afterSlash
, '/')) != NULL
) {
2956 ::mkdir(dyldDirs
, S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
);
2958 afterSlash
= slash
+1;
2962 // create temp file for cache
2963 int fd
= ::open(tempCachePath
, O_CREAT
| O_RDWR
| O_TRUNC
, 0644);
2965 throwf("can't create temp file %s, errnor=%d", tempCachePath
, errno
);
2967 // try to allocate whole cache file contiguously
2968 fstore_t fcntlSpec
= { F_ALLOCATECONTIG
|F_ALLOCATEALL
, F_PEOFPOSMODE
, 0, cacheFileSize
, 0 };
2969 ::fcntl(fd
, F_PREALLOCATE
, &fcntlSpec
);
2971 // write out cache file
2973 fprintf(stderr
, "update_dyld_shared_cache: writing cache to disk: %s\n", tempCachePath
);
2974 if ( ::pwrite(fd
, inMemoryCache
, cacheFileSize
, 0) != cacheFileSize
)
2975 throwf("write() failure creating cache file, errno=%d", errno
);
2977 // assuming write takes 35% of time
2978 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*90, archCount
*100);
2981 // flush to disk and close
2982 int result
= ::fcntl(fd
, F_FULLFSYNC
, NULL
);
2984 fprintf(stderr
, "update_dyld_shared_cache: warning, fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno
, tempCachePath
);
2985 result
= ::close(fd
);
2987 fprintf(stderr
, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno
, tempCachePath
);
2990 adhoc_codesign_share_cache(tempCachePath
);
2992 // <rdar://problem/7901042> Make life easier for the kernel at shutdown.
2993 // If we just move the new cache file over the old, the old file
2994 // may need to exist in the open-unlink state. But because it
2995 // may be mapped into the shared region, it cannot be deleted
2996 // until all user processes are terminated. That leaves are
2997 // small to non-existent window for the kernel to delete the
2999 if ( fCacheFileInFinalLocation
) {
3000 char tmpDirPath
[64];
3001 const char* pathLastSlash
= strrchr(fCacheFilePath
, '/');
3002 if ( pathLastSlash
!= NULL
) {
3003 sprintf(tmpDirPath
, "/var/run%s.old.%u", pathLastSlash
, getpid());
3004 // move existing cache file to /var/run to be clean up next boot
3005 result
= ::rename(fCacheFilePath
, tmpDirPath
);
3006 if ( result
!= 0 ) {
3007 if ( errno
!= ENOENT
)
3008 fprintf(stderr
, "update_dyld_shared_cache: warning, unable to move existing cache to %s errno=%d for %s\n", tmpDirPath
, errno
, fCacheFilePath
);
3013 // move new cache file to correct location for use after reboot
3015 fprintf(stderr
, "update_dyld_shared_cache: atomically moving cache file into place: %s\n", fCacheFilePath
);
3016 result
= ::rename(tempCachePath
, fCacheFilePath
);
3018 throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath
, fCacheFilePath
, errno
);
3021 // flush everything to disk to assure rename() gets recorded
3022 sync_volume(fCacheFilePath
);
3025 // restore default signal handlers
3026 ::signal(SIGINT
, SIG_DFL
);
3027 ::signal(SIGBUS
, SIG_DFL
);
3028 ::signal(SIGSEGV
, SIG_DFL
);
3030 // generate human readable "map" file that shows the layout of the cache file
3032 fprintf(stderr
, "update_dyld_shared_cache: writing .map file to disk\n");
3033 char mapFilePath
[strlen(fCacheFilePath
)+16];
3034 sprintf(mapFilePath
, "%s.map", fCacheFilePath
);
3035 char tempMapFilePath
[strlen(fCacheFilePath
)+32];
3036 sprintf(tempMapFilePath
, "%s.map%u", fCacheFilePath
, getpid());
3037 FILE* fmap
= ::fopen(tempMapFilePath
, "w");
3038 if ( fmap
== NULL
) {
3039 fprintf(stderr
, "can't create map file %s, errnor=%d", tempCachePath
, errno
);
3042 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
3043 const char* prot
= "RW";
3044 if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_READ
) )
3046 else if ( it
->sfm_init_prot
== VM_PROT_READ
)
3048 else if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_WRITE
|VM_PROT_READ
) )
3050 if ( it
->sfm_size
> 1024*1024 )
3051 fprintf(fmap
, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/(1024*1024),
3052 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
3054 fprintf(fmap
, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/1024,
3055 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
3058 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX weak binding info\n",
3059 (fOffsetOfExportInfoInCombinedLinkedit
-fOffsetOfWeakBindInfoInCombinedLinkedit
)/1024,
3060 fLinkEditsStartAddress
+fOffsetOfWeakBindInfoInCombinedLinkedit
,
3061 fLinkEditsStartAddress
+fOffsetOfExportInfoInCombinedLinkedit
);
3062 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX export info\n",
3063 (fOffsetOfBindInfoInCombinedLinkedit
-fOffsetOfExportInfoInCombinedLinkedit
)/1024,
3064 fLinkEditsStartAddress
+fOffsetOfExportInfoInCombinedLinkedit
,
3065 fLinkEditsStartAddress
+fOffsetOfBindInfoInCombinedLinkedit
);
3066 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX binding info\n",
3067 (fOffsetOfLazyBindInfoInCombinedLinkedit
-fOffsetOfBindInfoInCombinedLinkedit
)/1024,
3068 fLinkEditsStartAddress
+fOffsetOfBindInfoInCombinedLinkedit
,
3069 fLinkEditsStartAddress
+fOffsetOfLazyBindInfoInCombinedLinkedit
);
3070 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX lazy binding info\n",
3071 (fOffsetOfOldSymbolTableInfoInCombinedLinkedit
-fOffsetOfLazyBindInfoInCombinedLinkedit
)/1024,
3072 fLinkEditsStartAddress
+fOffsetOfLazyBindInfoInCombinedLinkedit
,
3073 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
);
3074 fprintf(fmap
, " linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld symbol table size\n",
3075 (fSizeOfOldSymbolTableInfoInCombinedLinkedit
)/(1024*1024),
3076 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
,
3077 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
+fSizeOfOldSymbolTableInfoInCombinedLinkedit
);
3078 if ( fSizeOfFunctionStartsInCombinedLinkedit
!= 0 )
3079 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld functions starts size\n",
3080 fSizeOfFunctionStartsInCombinedLinkedit
/1024,
3081 fLinkEditsStartAddress
+fOffsetOfFunctionStartsInCombinedLinkedit
,
3082 fLinkEditsStartAddress
+fOffsetOfFunctionStartsInCombinedLinkedit
+fSizeOfFunctionStartsInCombinedLinkedit
);
3083 if ( fSizeOfDataInCodeInCombinedLinkedit
!= 0 )
3084 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld data-in-code info size\n",
3085 fSizeOfDataInCodeInCombinedLinkedit
/1024,
3086 fLinkEditsStartAddress
+fOffsetOfDataInCodeInCombinedLinkedit
,
3087 fLinkEditsStartAddress
+fOffsetOfDataInCodeInCombinedLinkedit
+fSizeOfDataInCodeInCombinedLinkedit
);
3088 if ( fSizeOfOldExternalRelocationsInCombinedLinkedit
!= 0 )
3089 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld external relocs size\n",
3090 fSizeOfOldExternalRelocationsInCombinedLinkedit
/1024,
3091 fLinkEditsStartAddress
+fOffsetOfOldExternalRelocationsInCombinedLinkedit
,
3092 fLinkEditsStartAddress
+fOffsetOfOldExternalRelocationsInCombinedLinkedit
+fSizeOfOldExternalRelocationsInCombinedLinkedit
);
3093 fprintf(fmap
, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld indirect symbol table size\n",
3094 fSizeOfOldIndirectSymbolsInCombinedLinkedit
/1024,
3095 fLinkEditsStartAddress
+fOffsetOfOldIndirectSymbolsInCombinedLinkedit
,
3096 fLinkEditsStartAddress
+fOffsetOfOldIndirectSymbolsInCombinedLinkedit
+fSizeOfOldIndirectSymbolsInCombinedLinkedit
);
3097 fprintf(fmap
, " linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld string pool\n",
3098 (fSizeOfOldStringPoolInCombinedLinkedit
)/(1024*1024),
3099 fLinkEditsStartAddress
+fOffsetOfOldStringPoolInCombinedLinkedit
,
3100 fLinkEditsStartAddress
+fOffsetOfOldStringPoolInCombinedLinkedit
+fSizeOfOldStringPoolInCombinedLinkedit
);
3102 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
3103 if ( cacheHeader
->slideInfoSize() != 0 ) {
3104 fprintf(fmap
, " linkedit %4lluKB kernel slide info\n", (cacheHeader
->slideInfoSize())/1024);
3107 fprintf(fmap
, "unmapped -- %4uMB local symbol info\n", fUnmappedLocalSymbolsSize
/(1024*1024));
3109 uint64_t endMappingAddr
= fMappings
[2].sfm_address
+ fMappings
[2].sfm_size
;
3110 fprintf(fmap
, "total map %4lluMB\n", (endMappingAddr
- sharedRegionStartAddress())/(1024*1024));
3111 if ( sharedRegionStartWritableAddress(0) == 0x7FFF70000000LL
) {
3112 // x86_64 has different slide constraints
3113 uint64_t freeSpace
= 256*1024*1024 - fMappings
[1].sfm_size
;
3114 fprintf(fmap
, "r/w space %4lluMB -> %d bits of entropy for ASLR\n\n", freeSpace
/(1024*1024), (int)log2(freeSpace
/4096));
3117 uint64_t freeSpace
= sharedRegionStartAddress() + sharedRegionSize() - endMappingAddr
;
3118 fprintf(fmap
, "free space %4lluMB -> %d bits of entropy for ASLR\n\n", freeSpace
/(1024*1024), (int)log2(freeSpace
/4096));
3121 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
3122 fprintf(fmap
, "%s\n", it
->layout
->getID().name
);
3123 for (std::vector
<const char*>::const_iterator ait
= it
->aliases
.begin(); ait
!= it
->aliases
.end(); ++ait
)
3124 fprintf(fmap
, "%s\n", *ait
);
3125 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
3126 for (int i
=0; i
< segs
.size(); ++i
) {
3127 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
3128 fprintf(fmap
, "\t%16s 0x%0llX -> 0x%0llX\n", seg
.name(), seg
.newAddress(), seg
.newAddress()+seg
.size());
3131 if ( warnings
.size() > 0 ) {
3132 fprintf(fmap
, "# Warnings:\n");
3133 for (std::vector
<const char*>::iterator it
=warnings
.begin(); it
!= warnings
.end(); ++it
) {
3134 fprintf(fmap
, "# %s\n", *it
);
3138 result
= ::rename(tempMapFilePath
, mapFilePath
);
3142 // free in memory cache
3143 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
3144 inMemoryCache
= NULL
;
3147 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*100, archCount
*100);
3151 // remove temp cache file
3152 ::unlink(tempCachePath
);
3153 // remove in memory cache
3154 if ( inMemoryCache
!= NULL
)
3155 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
3165 // The shared cache is driven by /var/db/dyld/shared_region_roots which contains
3166 // the paths used to search for dylibs that should go in the shared cache
3168 // Leading and trailing white space is ignored
3169 // Blank lines are ignored
3170 // Lines starting with # are ignored
3172 static void parsePathsFile(const char* filePath
, std::vector
<const char*>& paths
)
3174 // read in whole file
3175 int fd
= open(filePath
, O_RDONLY
, 0);
3177 fprintf(stderr
, "update_dyld_shared_cache: can't open file: %s\n", filePath
);
3180 struct stat stat_buf
;
3181 fstat(fd
, &stat_buf
);
3182 char* p
= (char*)malloc(stat_buf
.st_size
);
3184 fprintf(stderr
, "update_dyld_shared_cache: malloc failure\n");
3187 if ( read(fd
, p
, stat_buf
.st_size
) != stat_buf
.st_size
) {
3188 fprintf(stderr
, "update_dyld_shared_cache: can't read file: %s\n", filePath
);
3193 // parse into paths and add to vector
3194 char * const end
= &p
[stat_buf
.st_size
];
3195 enum { lineStart
, inSymbol
, inComment
} state
= lineStart
;
3196 char* symbolStart
= NULL
;
3197 for (char* s
= p
; s
< end
; ++s
) {
3203 else if ( !isspace(*s
) ) {
3211 // removing any trailing spaces
3213 while ( isspace(*last
) ) {
3217 paths
.push_back(symbolStart
);
3228 // Note: we do not free() the malloc buffer, because the strings in it are used by exec()
3233 static void setSharedDylibs(const char* rootPath
, const std::vector
<const char*>& overlayPaths
, const std::set
<ArchPair
>& onlyArchs
, std::vector
<const char*> rootsPaths
)
3235 // set file system root
3236 ArchGraph::setFileSystemRoot(rootPath
);
3237 ArchGraph::setFileSystemOverlay(overlayPaths
);
3239 // initialize all architectures requested
3240 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
3241 ArchGraph::addArchPair(*a
);
3243 // add roots to graph
3244 for(std::vector
<const char*>::const_iterator it
= rootsPaths
.begin(); it
!= rootsPaths
.end(); ++it
)
3245 ArchGraph::addRoot(*it
, onlyArchs
);
3247 // determine shared dylibs
3248 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
3249 ArchGraph::findSharedDylibs(*a
);
3253 static void scanForSharedDylibs(const char* rootPath
, const std::vector
<const char*>& overlayPaths
, const char* dirOfPathFiles
, const std::set
<ArchPair
>& onlyArchs
)
3255 char rootDirOfPathFiles
[strlen(rootPath
)+strlen(dirOfPathFiles
)+2];
3256 // in -root mode, look for roots in /rootpath/var/db/dyld
3257 if ( rootPath
[0] != '\0' ) {
3258 strcpy(rootDirOfPathFiles
, rootPath
);
3259 strcat(rootDirOfPathFiles
, dirOfPathFiles
);
3260 dirOfPathFiles
= rootDirOfPathFiles
;
3263 // extract all root paths from files in "/var/db/dyld/shared_region_roots/"
3265 fprintf(stderr
, "update_dyld_shared_cache: finding roots in: %s\n", dirOfPathFiles
);
3266 std::vector
<const char*> rootsPaths
;
3267 DIR* dir
= ::opendir(dirOfPathFiles
);
3269 throwf("%s does not exist, errno=%d\n", dirOfPathFiles
, errno
);
3270 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
3271 if ( entry
->d_type
== DT_REG
|| entry
->d_type
== DT_UNKNOWN
) {
3272 // only look at regular files ending in .paths
3273 if ( strcmp(&entry
->d_name
[entry
->d_namlen
-6], ".paths") == 0 ) {
3274 struct stat tmpStatPathsFile
;
3275 char fullPath
[strlen(dirOfPathFiles
)+entry
->d_namlen
+2];
3276 strcpy(fullPath
, dirOfPathFiles
);
3277 strcat(fullPath
, "/");
3278 strcat(fullPath
, entry
->d_name
);
3279 if ( lstat(fullPath
, &tmpStatPathsFile
) == -1 ) {
3280 fprintf(stderr
, "update_dyld_shared_cache: can't access %s\n", fullPath
);
3282 else if ( S_ISREG(tmpStatPathsFile
.st_mode
) ) {
3283 parsePathsFile(fullPath
, rootsPaths
);
3286 fprintf(stderr
, "update_dyld_shared_cache: wrong file type for %s\n", fullPath
);
3290 fprintf(stderr
, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry
->d_name
);
3296 if ( rootsPaths
.size() == 0 )
3297 fprintf(stderr
, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
3298 setSharedDylibs(rootPath
, overlayPaths
, onlyArchs
, rootsPaths
);
3301 static void setSharedDylibs(const char* rootPath
, const std::vector
<const char*>& overlayPaths
, const char* pathsFile
, const std::set
<ArchPair
>& onlyArchs
)
3303 std::vector
<const char*> rootsPaths
;
3304 parsePathsFile(pathsFile
, rootsPaths
);
3305 setSharedDylibs(rootPath
, overlayPaths
, onlyArchs
, rootsPaths
);
3309 // If the 10.5.0 version of update_dyld_shared_cache was killed or crashed, it
3310 // could leave large half written cache files laying around. The function deletes
3311 // those files. To prevent the deletion of tmp files being created by another
3312 // copy of update_dyld_shared_cache, it only deletes the temp cache file if its
3313 // creation time was before the last restart of this machine.
3314 static void deleteOrphanTempCacheFiles()
3316 DIR* dir
= ::opendir(MACOSX_DYLD_SHARED_CACHE_DIR
);
3317 if ( dir
!= NULL
) {
3318 std::vector
<const char*> filesToDelete
;
3319 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
3320 if ( entry
->d_type
== DT_REG
) {
3321 // only look at files with .tmp in name
3322 if ( strstr(entry
->d_name
, ".tmp") != NULL
) {
3323 char fullPath
[strlen(MACOSX_DYLD_SHARED_CACHE_DIR
)+entry
->d_namlen
+2];
3324 strcpy(fullPath
, MACOSX_DYLD_SHARED_CACHE_DIR
);
3325 strcat(fullPath
, "/");
3326 strcat(fullPath
, entry
->d_name
);
3327 struct stat tmpFileStatInfo
;
3328 if ( stat(fullPath
, &tmpFileStatInfo
) != -1 ) {
3329 int mib
[2] = {CTL_KERN
, KERN_BOOTTIME
};
3330 struct timeval boottime
;
3331 size_t size
= sizeof(boottime
);
3332 if ( (sysctl(mib
, 2, &boottime
, &size
, NULL
, 0) != -1) && (boottime
.tv_sec
!= 0) ) {
3333 // make sure this file is older than the boot time of this machine
3334 if ( tmpFileStatInfo
.st_mtime
< boottime
.tv_sec
) {
3335 filesToDelete
.push_back(strdup(fullPath
));
3343 for(std::vector
<const char*>::iterator it
= filesToDelete
.begin(); it
!= filesToDelete
.end(); ++it
) {
3344 fprintf(stderr
, "update_dyld_shared_cache: deleting old temp cache file: %s\n", *it
);
3352 static bool updateSharedeCacheFile(const char* rootPath
, const std::vector
<const char*>& overlayPaths
, const char* cacheDir
, bool explicitCacheDir
, const std::set
<ArchPair
>& onlyArchs
,
3353 bool force
, bool alphaSort
, bool optimize
, bool deleteExistingFirst
, bool verify
, bool keepSignatures
, bool dontMapLocalSymbols
)
3355 bool didUpdate
= false;
3356 // get dyld load address info
3357 UniversalMachOLayout
* dyldLayout
= NULL
;
3358 char dyldPath
[1024];
3359 strlcpy(dyldPath
, rootPath
, 1024);
3360 strlcat(dyldPath
, "/usr/lib/dyld", 1024);
3361 struct stat stat_buf
;
3362 if ( stat(dyldPath
, &stat_buf
) == 0 ) {
3363 dyldLayout
= new UniversalMachOLayout(dyldPath
, &onlyArchs
);
3366 dyldLayout
= new UniversalMachOLayout("/usr/lib/dyld", &onlyArchs
);
3368 const int archCount
= onlyArchs
.size();
3370 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
, ++index
) {
3371 const MachOLayoutAbstraction
* dyldLayoutForArch
= dyldLayout
->getSlice(*a
);
3372 uint64_t dyldBaseAddress
= 0;
3373 if ( dyldLayoutForArch
!= NULL
)
3374 dyldBaseAddress
= dyldLayoutForArch
->getBaseAddress();
3376 fprintf(stderr
, "update_dyld_shared_cache: warning, dyld not available for specified architectures\n");
3377 switch ( a
->arch
) {
3380 SharedCache
<x86
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, overlayPaths
, cacheDir
, explicitCacheDir
, alphaSort
, verify
, optimize
, dyldBaseAddress
);
3381 didUpdate
|= cache
.update(force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
, dontMapLocalSymbols
);
3384 case CPU_TYPE_X86_64
:
3386 SharedCache
<x86_64
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, overlayPaths
, cacheDir
, explicitCacheDir
, alphaSort
, verify
, optimize
, dyldBaseAddress
);
3387 didUpdate
|= cache
.update(force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
, dontMapLocalSymbols
);
3392 SharedCache
<arm
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, overlayPaths
, cacheDir
, explicitCacheDir
, alphaSort
, verify
, optimize
, dyldBaseAddress
);
3393 didUpdate
|= cache
.update(force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
, dontMapLocalSymbols
);
3396 case CPU_TYPE_ARM64
:
3398 SharedCache
<arm64
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, overlayPaths
, cacheDir
, explicitCacheDir
, alphaSort
, verify
, optimize
, dyldBaseAddress
);
3399 didUpdate
|= cache
.update(force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
, dontMapLocalSymbols
);
3406 deleteOrphanTempCacheFiles();
3414 fprintf(stderr
, "update_dyld_shared_cache [-force] [-root dir] [-overlay dir] [-arch arch] [-debug]\n");
3418 int main(int argc
, const char* argv
[])
3420 std::set
<ArchPair
> onlyArchs
;
3421 const char* rootPath
= "";
3422 std::vector
<const char*> overlayPaths
;
3423 const char* dylibListFile
= NULL
;
3425 bool alphaSort
= false;
3426 bool optimize
= true;
3427 bool verify
= false;
3428 bool keepSignatures
= false;
3429 bool explicitCacheDir
= false;
3430 bool dontMapLocalSymbols
= false;
3431 bool relaunchForHaswell
= false;
3432 const char* cacheDir
= NULL
;
3435 // parse command line options
3436 for(int i
=1; i
< argc
; ++i
) {
3437 const char* arg
= argv
[i
];
3438 if ( arg
[0] == '-' ) {
3439 if ( strcmp(arg
, "-debug") == 0 ) {
3442 else if ( strcmp(arg
, "-force") == 0 ) {
3445 else if ( strcmp(arg
, "-verify") == 0 ) {
3448 else if ( strcmp(arg
, "-sort_by_name") == 0 ) {
3451 else if ( strcmp(arg
, "-progress") == 0 ) {
3454 else if ( strcmp(arg
, "-opt") == 0 ) {
3457 else if ( strcmp(arg
, "-no_opt") == 0 ) {
3460 else if ( strcmp(arg
, "-dont_map_local_symbols") == 0 ) {
3461 dontMapLocalSymbols
= true;
3463 else if ( strcmp(arg
, "-iPhone") == 0 ) {
3467 else if ( strcmp(arg
, "-dylib_list") == 0 ) {
3468 dylibListFile
= argv
[++i
];
3469 if ( dylibListFile
== NULL
)
3470 throw "-dylib_list missing path argument";
3472 else if ( (strcmp(arg
, "-root") == 0) || (strcmp(arg
, "--root") == 0) ) {
3473 rootPath
= argv
[++i
];
3474 if ( rootPath
== NULL
)
3475 throw "-root missing path argument";
3477 else if ( strcmp(arg
, "-overlay") == 0 ) {
3478 const char* path
= argv
[++i
];
3480 throw "-overlay missing path argument";
3481 overlayPaths
.push_back(path
);
3483 else if ( strcmp(arg
, "-cache_dir") == 0 ) {
3484 cacheDir
= argv
[++i
];
3485 if ( cacheDir
== NULL
)
3486 throw "-cache_dir missing path argument";
3487 explicitCacheDir
= true;
3489 else if ( strcmp(arg
, "-arch") == 0 ) {
3490 const char* arch
= argv
[++i
];
3491 if ( strcmp(arch
, "i386") == 0 )
3492 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3493 else if ( strcmp(arch
, "x86_64") == 0 )
3494 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
3495 else if ( strcmp(arch
, "x86_64h") == 0 )
3496 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_H
));
3497 else if ( strcmp(arch
, "armv4t") == 0 )
3498 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V4T
));
3499 else if ( strcmp(arch
, "armv5") == 0 )
3500 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V5TEJ
));
3501 else if ( strcmp(arch
, "armv6") == 0 )
3502 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V6
));
3503 else if ( strcmp(arch
, "armv7") == 0 )
3504 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7
));
3505 else if ( strcmp(arch
, "armv7f") == 0 )
3506 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7F
));
3507 else if ( strcmp(arch
, "armv7k") == 0 )
3508 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7K
));
3509 else if ( strcmp(arch
, "armv7s") == 0 )
3510 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7S
));
3511 else if ( strcmp(arch
, "arm64") == 0 )
3512 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM64
, CPU_SUBTYPE_ARM64_ALL
));
3514 throwf("unknown architecture %s", arch
);
3516 else if ( strcmp(arg
, "-universal_boot") == 0 ) {
3517 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
3518 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3519 relaunchForHaswell
= true;
3523 throwf("unknown option: %s\n", arg
);
3528 throwf("unknown option: %s\n", arg
);
3532 // strip tailing slashes on -root
3533 // make it a real path so as to not make all dylibs look like symlink aliases
3534 if ( rootPath
[0] != '\0' ) {
3535 char realRootPath
[MAXPATHLEN
];
3536 if ( realpath(rootPath
, realRootPath
) == NULL
)
3537 throwf("realpath() failed on %s\n", rootPath
);
3538 rootPath
= strdup(realRootPath
);
3541 // strip tailing slashes on -overlay
3542 for (std::vector
<const char*>::iterator it
=overlayPaths
.begin(); it
!= overlayPaths
.end(); ++it
) {
3543 char realOverlayPath
[MAXPATHLEN
];
3544 if ( realpath(*it
, realOverlayPath
) == NULL
)
3545 throwf("realpath() failed on %s\n", *it
);
3546 *it
= strdup(realOverlayPath
);
3549 // set default location to write cache dir
3550 if ( cacheDir
== NULL
)
3551 cacheDir
= (iPhoneOS
? IPHONE_DYLD_SHARED_CACHE_DIR
: MACOSX_DYLD_SHARED_CACHE_DIR
);
3553 // if no restrictions specified, use architectures that work on this machine
3554 if ( onlyArchs
.size() == 0 ) {
3556 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V6
));
3557 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7
));
3561 size_t len
= sizeof(int);
3562 #if __i386__ || __x86_64__
3563 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3564 // check system is capable of running 64-bit programs
3565 if ( (sysctlbyname("hw.optional.x86_64", &available
, &len
, NULL
, 0) == 0) && available
) {
3566 // check system is capable of running x86_64h code
3567 struct host_basic_info info
;
3568 mach_msg_type_number_t count
= HOST_BASIC_INFO_COUNT
;
3569 mach_port_t hostPort
= mach_host_self();
3570 kern_return_t result
= host_info(hostPort
, HOST_BASIC_INFO
, (host_info_t
)&info
, &count
);
3571 mach_port_deallocate(mach_task_self(), hostPort
);
3572 if ( result
!= KERN_SUCCESS
)
3573 throw "host_info() failed";
3574 if ( info
.cpu_subtype
== CPU_SUBTYPE_X86_64_H
)
3575 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_H
));
3577 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_ALL
));
3580 #error unsupported architecture
3585 if ( !verify
&& (geteuid() != 0) )
3586 throw "you must be root to run this tool";
3588 // build list of shared dylibs
3589 if ( dylibListFile
!= NULL
)
3590 setSharedDylibs(rootPath
, overlayPaths
, dylibListFile
, onlyArchs
);
3592 scanForSharedDylibs(rootPath
, overlayPaths
, "/var/db/dyld/shared_region_roots/", onlyArchs
);
3593 bool didUpdate
= updateSharedeCacheFile(rootPath
, overlayPaths
, cacheDir
, explicitCacheDir
, onlyArchs
, force
, alphaSort
, optimize
,
3594 false, verify
, keepSignatures
, dontMapLocalSymbols
);
3596 if ( didUpdate
&& !iPhoneOS
) {
3597 void* handle
= dlopen("/usr/lib/libspindump.dylib", RTLD_LAZY
);
3598 if ( handle
!= NULL
) {
3599 typedef bool (*dscsym_proc_t
)(const char *root
);
3600 dscsym_proc_t proc
= (dscsym_proc_t
)dlsym(handle
, "dscsym_save_nuggets_for_current_caches");
3601 const char* nuggetRootPath
= "/";
3602 if ( !overlayPaths
.empty() )
3603 nuggetRootPath
= overlayPaths
[0];
3604 else if ( rootPath
[0] != '\0' )
3605 nuggetRootPath
= rootPath
;
3606 (*proc
)(nuggetRootPath
);
3611 if ( relaunchForHaswell
) {
3613 strlcpy(cmd
, argv
[0], 2048);
3614 strlcat(cmd
, " -arch x86_64h", 2048);
3616 strlcat(cmd
, " -force", 2048);
3618 strlcat(cmd
, " -verify", 2048);
3620 strlcat(cmd
, " -sort_by_name", 2048);
3621 if ( (rootPath
!= NULL
) && (rootPath
[0] != '\0') ) {
3622 strlcat(cmd
, " -root ", 2048);
3623 strlcat(cmd
, rootPath
, 2048);
3629 catch (const char* msg
) {
3630 fprintf(stderr
, "update_dyld_shared_cache failed: %s\n", msg
);