1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.h>
28 #include <mach/mach.h>
29 #include <mach/mach_time.h>
40 #include <sys/param.h>
41 #include <sys/sysctl.h>
42 #include <sys/resource.h>
44 #include <servers/bootstrap.h>
45 #include <mach-o/loader.h>
46 #include <mach-o/fat.h>
48 #include "dyld_cache_format.h"
53 #include <ext/hash_map>
55 #include "Architectures.hpp"
56 #include "MachOLayout.hpp"
57 #include "MachORebaser.hpp"
58 #include "MachOBinder.hpp"
59 #include "CacheFileAbstraction.hpp"
62 #include "objc-shared-cache.h"
64 #define FIRST_DYLIB_TEXT_OFFSET 0x7000
65 #define FIRST_DYLIB_DATA_OFFSET 0x1000
67 #ifndef LC_FUNCTION_STARTS
68 #define LC_FUNCTION_STARTS 0x26
71 static bool verbose
= false;
72 static bool progress
= false;
73 static bool iPhoneOS
= false;
74 static std::vector
<const char*> warnings
;
77 static void warn(const char *arch
, const char *format
, ...)
82 va_start(args
, format
);
83 ::vasprintf(&msg
, format
, args
);
86 warnings
.push_back(msg
);
89 ::fprintf(::stderr
, "update_dyld_shared_cache: warning: %s%s%s%s\n",
90 arch
? "for arch " : "",
98 static uint64_t pageAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
103 struct CStringEquals
{
104 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
106 typedef __gnu_cxx::hash_map
<const char*, const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> StringToString
;
108 static void addArchPair(ArchPair ap
);
109 static void addRoot(const char* vpath
, const std::set
<ArchPair
>& archs
);
110 static void findSharedDylibs(ArchPair ap
);
111 static ArchGraph
* graphForArchPair(ArchPair ap
) { return fgPerArchGraph
[ap
]; }
112 static void setFileSystemRoot(const char* root
) { fgFileSystemRoot
= root
; }
113 static void setFileSystemOverlay(const char* overlay
) { fgFileSystemOverlay
= overlay
; }
114 static const char* archName(ArchPair ap
);
116 ArchPair
getArchPair() { return fArchPair
; }
117 std::set
<const class MachOLayoutAbstraction
*>& getSharedDylibs() { return fSharedDylibs
; }
118 StringToString
& getDylibAliases() { return fAliasesMap
; }
119 const char* archName() { return archName(fArchPair
); }
126 DependencyNode(ArchGraph
*, const char* path
, const MachOLayoutAbstraction
* layout
);
127 void loadDependencies(const MachOLayoutAbstraction
*);
128 void markNeededByRoot(DependencyNode
*);
129 const char* getPath() const { return fPath
; }
130 const MachOLayoutAbstraction
* getLayout() const { return fLayout
; }
131 size_t useCount() const { return fRootsDependentOnThis
.size(); }
132 bool allDependentsFound() const { return !fDependentMissing
; }
136 const MachOLayoutAbstraction
* fLayout
;
137 bool fDependenciesLoaded
;
138 bool fDependentMissing
;
139 std::set
<DependencyNode
*> fDependsOn
;
140 std::set
<DependencyNode
*> fRootsDependentOnThis
;
143 typedef __gnu_cxx::hash_map
<const char*, class DependencyNode
*, __gnu_cxx::hash
<const char*>, CStringEquals
> PathToNode
;
146 ArchGraph(ArchPair ap
) : fArchPair(ap
) {}
147 void addRoot(const char* path
, const MachOLayoutAbstraction
*);
148 DependencyNode
* getNode(const char* path
);
149 DependencyNode
* getNodeForVirtualPath(const char* vpath
);
150 static bool canBeShared(const MachOLayoutAbstraction
* layout
, ArchPair ap
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
);
151 static bool sharable(const MachOLayoutAbstraction
* layout
, ArchPair ap
, char** msg
);
153 static std::map
<ArchPair
, ArchGraph
*> fgPerArchGraph
;
154 static const char* fgFileSystemRoot
;
155 static const char* fgFileSystemOverlay
;
158 std::set
<DependencyNode
*> fRoots
;
160 std::set
<const MachOLayoutAbstraction
*> fSharedDylibs
; // use set to avoid duplicates when installname!=realpath
161 StringToString fAliasesMap
;
163 std::map
<ArchPair
, ArchGraph
*> ArchGraph::fgPerArchGraph
;
164 const char* ArchGraph::fgFileSystemRoot
= "";
165 const char* ArchGraph::fgFileSystemOverlay
= "";
167 void ArchGraph::addArchPair(ArchPair ap
)
169 //fprintf(stderr, "adding ArchPair 0x%08X,0x%08X\n", ap.arch, ap.subtype);
170 fgPerArchGraph
[ap
] = new ArchGraph(ap
);
173 void ArchGraph::addRoot(const char* vpath
, const std::set
<ArchPair
>& onlyArchs
)
175 //fprintf(stderr, "addRoot(%s)\n", vpath);
176 char completePath
[MAXPATHLEN
];
177 const char* path
= NULL
;
178 // check -overlay path first
179 if ( fgFileSystemOverlay
[0] != '\0' ) {
180 strcpy(completePath
, fgFileSystemOverlay
);
181 strcat(completePath
, vpath
); // assumes vpath starts with '/'
182 struct stat stat_buf
;
183 if ( stat(completePath
, &stat_buf
) == 0 )
186 // if not found in overlay, check for -root
187 if ( (path
== NULL
) && (fgFileSystemRoot
[0] != '\0') ) {
188 strcpy(completePath
, fgFileSystemRoot
);
189 strcat(completePath
, vpath
); // assumes vpath starts with '/'
190 struct stat stat_buf
;
191 if ( stat(completePath
, &stat_buf
) == 0 )
198 //fprintf(stderr, " UniversalMachOLayout::find(%s)\n", path);
199 const UniversalMachOLayout
& uni
= UniversalMachOLayout::find(path
, &onlyArchs
);
200 for(std::set
<ArchPair
>::iterator ait
= onlyArchs
.begin(); ait
!= onlyArchs
.end(); ++ait
) {
202 const MachOLayoutAbstraction
* layout
= uni
.getSlice(*ait
);
203 if ( layout
!= NULL
)
204 fgPerArchGraph
[*ait
]->addRoot(path
, layout
);
206 catch (const char* msg
) {
208 fprintf(stderr
, "update_dyld_shared_cache: warning for %s can't use root '%s': %s\n", fgPerArchGraph
[*ait
]->archName(), path
, msg
);
213 catch (const char* msg
) {
214 fprintf(stderr
, "update_dyld_shared_cache: warning can't use root '%s': %s\n", path
, msg
);
220 void ArchGraph::addRoot(const char* path
, const MachOLayoutAbstraction
* layout
)
223 fprintf(stderr
, "update_dyld_shared_cache: adding root: %s\n", path
);
224 DependencyNode
* node
= this->getNode(path
);
226 const MachOLayoutAbstraction
* mainExecutableLayout
= NULL
;
227 if ( layout
->getFileType() == MH_EXECUTE
)
228 mainExecutableLayout
= layout
;
229 node
->loadDependencies(mainExecutableLayout
);
230 node
->markNeededByRoot(node
);
231 if ( layout
->getFileType() == MH_DYLIB
)
232 node
->markNeededByRoot(NULL
);
235 // a virtual path does not have the fgFileSystemRoot prefix
236 ArchGraph::DependencyNode
* ArchGraph::getNodeForVirtualPath(const char* vpath
)
238 //fprintf(stderr, "getNodeForVirtualPath(%s)\n", vpath);
239 char completePath
[MAXPATHLEN
];
240 if ( fgFileSystemOverlay
[0] != '\0' ) {
241 // using -overlay means if /overlay/path/dylib exists use it, otherwise use /path/dylib
242 strcpy(completePath
, fgFileSystemOverlay
);
243 strcat(completePath
, vpath
); // assumes vpath starts with '/'
244 struct stat stat_buf
;
245 if ( stat(completePath
, &stat_buf
) == 0 )
246 return this->getNode(completePath
);
248 // <rdar://problem/9279770> support when install name is a symlink
249 const char* pathToSymlink
= vpath
;
250 if ( fgFileSystemRoot
[0] != '\0' ) {
251 strcpy(completePath
, fgFileSystemRoot
);
252 strcat(completePath
, vpath
);
253 pathToSymlink
= completePath
;
255 if ( (lstat(pathToSymlink
, &stat_buf
) == 0) && S_ISLNK(stat_buf
.st_mode
) ) {
256 // requested path did not exist in /overlay, but leaf of path is a symlink in /
257 char pathInSymLink
[MAXPATHLEN
];
258 size_t res
= readlink(pathToSymlink
, pathInSymLink
, sizeof(pathInSymLink
));
260 pathInSymLink
[res
] = '\0';
261 if ( pathInSymLink
[0] != '/' ) {
262 char symFullPath
[MAXPATHLEN
];
263 strcpy(symFullPath
, vpath
);
264 char* lastSlash
= strrchr(symFullPath
, '/');
265 if ( lastSlash
!= NULL
) {
266 strcpy(lastSlash
+1, pathInSymLink
);
267 // (re)try looking for what symlink points to, but in /overlay
268 return this->getNodeForVirtualPath(symFullPath
);
275 if ( fgFileSystemRoot
[0] != '\0' ) {
276 // using -root means always use /rootpath/usr/lib
277 strcpy(completePath
, fgFileSystemRoot
);
278 strcat(completePath
, vpath
); // assumes vpath starts with '/'
279 return this->getNode(completePath
);
281 // not found in -overlay or -root not used
282 return this->getNode(vpath
);
285 ArchGraph::DependencyNode
* ArchGraph::getNode(const char* path
)
287 //fprintf(stderr, "getNode(%s)\n", path);
288 // look up supplied path to see if node already exists
289 PathToNode::iterator pos
= fNodes
.find(path
);
290 if ( pos
!= fNodes
.end() )
294 char realPath
[MAXPATHLEN
];
295 if ( realpath(path
, realPath
) == NULL
)
296 throwf("realpath() failed on %s\n", path
);
298 // look up real path to see if node already exists
299 pos
= fNodes
.find(realPath
);
300 if ( pos
!= fNodes
.end() ) {
301 // update fAliasesMap with symlinks found
302 const char* aliasPath
= path
;
303 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(path
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
304 aliasPath
= &path
[strlen(fgFileSystemRoot
)];
306 if ( fAliasesMap
.find(aliasPath
) == fAliasesMap
.end() ) {
307 if ( strcmp(aliasPath
, pos
->second
->getLayout()->getID().name
) != 0 ) {
308 fAliasesMap
[strdup(aliasPath
)] = pos
->second
->getLayout()->getID().name
;
309 //fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
315 // still does not exist, so create a new node
316 const UniversalMachOLayout
& uni
= UniversalMachOLayout::find(realPath
);
317 DependencyNode
* node
= new DependencyNode(this, realPath
, uni
.getSlice(fArchPair
));
318 if ( node
->getLayout() == NULL
) {
319 throwf("%s is missing arch %s", realPath
, archName(fArchPair
));
321 // add realpath to node map
322 fNodes
[node
->getPath()] = node
;
323 // if install name is not real path, add install name to node map
324 if ( (node
->getLayout()->getFileType() == MH_DYLIB
) && (strcmp(realPath
, node
->getLayout()->getID().name
) != 0) ) {
325 //fprintf(stderr, "adding %s node alias %s for %s\n", archName(fArchPair), node->getLayout()->getID().name, realPath);
326 pos
= fNodes
.find(node
->getLayout()->getID().name
);
327 if ( pos
!= fNodes
.end() ) {
328 // <rdar://problem/8305479> warn if two dylib in cache have same install_name
330 asprintf(&msg
, "update_dyld_shared_cache: warning, found two dylibs with same install path: %s\n\t%s\n\t%s\n",
331 node
->getLayout()->getID().name
, pos
->second
->getPath(), node
->getPath());
332 fprintf(stderr
, "%s", msg
);
333 warnings
.push_back(msg
);
336 fNodes
[node
->getLayout()->getID().name
] = node
;
337 // update fAliasesMap with symlinks found
338 const char* aliasPath
= realPath
;
339 if ( (fgFileSystemRoot
!= NULL
) && (fgFileSystemRoot
[0] != '\0') && (strncmp(realPath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
340 aliasPath
= &realPath
[strlen(fgFileSystemRoot
)];
342 // <rdar://problem/11192810> Too many aliases in -overlay mode
343 if ( (fgFileSystemOverlay
!= NULL
) && (fgFileSystemOverlay
[0] != '\0') && (strncmp(realPath
, fgFileSystemOverlay
, strlen(fgFileSystemOverlay
)) == 0) ) {
344 aliasPath
= &realPath
[strlen(fgFileSystemOverlay
)];
346 if ( fAliasesMap
.find(aliasPath
) == fAliasesMap
.end() ) {
347 if ( strcmp(aliasPath
, node
->getLayout()->getID().name
) != 0 ) {
348 fAliasesMap
[strdup(aliasPath
)] = node
->getLayout()->getID().name
;
349 //fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
357 void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction
* mainExecutableLayout
)
359 if ( !fDependenciesLoaded
) {
360 fDependenciesLoaded
= true;
362 const std::vector
<MachOLayoutAbstraction::Library
>& dependsOn
= fLayout
->getLibraries();
363 for(std::vector
<MachOLayoutAbstraction::Library
>::const_iterator it
= dependsOn
.begin(); it
!= dependsOn
.end(); ++it
) {
365 const char* dependentPath
= it
->name
;
366 if ( strncmp(dependentPath
, "@executable_path/", 17) == 0 ) {
367 if ( mainExecutableLayout
== NULL
)
368 throw "@executable_path without main executable";
369 // expand @executable_path path prefix
370 const char* executablePath
= mainExecutableLayout
->getFilePath();
371 char newPath
[strlen(executablePath
) + strlen(dependentPath
)+2];
372 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(executablePath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
373 // executablePath already has rootPath prefix, need to remove that to get to base virtual path
374 strcpy(newPath
, &executablePath
[strlen(fgFileSystemRoot
)]);
377 strcpy(newPath
, executablePath
);
379 char* addPoint
= strrchr(newPath
,'/');
380 if ( addPoint
!= NULL
)
381 strcpy(&addPoint
[1], &dependentPath
[17]);
383 strcpy(newPath
, &dependentPath
[17]);
384 dependentPath
= strdup(newPath
);
386 else if ( strncmp(dependentPath
, "@loader_path/", 13) == 0 ) {
387 // expand @loader_path path prefix
388 char newPath
[strlen(fPath
) + strlen(dependentPath
)+2];
389 if ( (fgFileSystemRoot
!= NULL
) && (strncmp(fPath
, fgFileSystemRoot
, strlen(fgFileSystemRoot
)) == 0) ) {
390 // fPath already has rootPath prefix, need to remove that to get to base virtual path
391 strcpy(newPath
, &fPath
[strlen(fgFileSystemRoot
)]);
394 strcpy(newPath
, fPath
);
396 char* addPoint
= strrchr(newPath
,'/');
397 if ( addPoint
!= NULL
)
398 strcpy(&addPoint
[1], &dependentPath
[13]);
400 strcpy(newPath
, &dependentPath
[13]);
401 dependentPath
= strdup(newPath
);
403 else if ( strncmp(dependentPath
, "@rpath/", 7) == 0 ) {
404 throw "@rpath not supported in dyld shared cache";
406 // <rdar://problem/9161945> silently ignore dependents from main executables that can't be in shared cache
407 bool addDependent
= true;
408 if ( fLayout
->getFileType() == MH_EXECUTE
) {
409 if ( (strncmp(dependentPath
, "/usr/lib/", 9) != 0) && (strncmp(dependentPath
, "/System/Library/", 16) != 0) ) {
410 addDependent
= false;
414 fDependsOn
.insert(fGraph
->getNodeForVirtualPath(dependentPath
));
416 catch (const char* msg
) {
417 if ( it
->weakImport
|| ! fLayout
->hasSplitSegInfo() ) {
418 // ok to ignore missing weak imported dylibs from things that are
419 // not going to be in the dyld shared cache
422 fprintf(stderr
, "warning, could not bind %s because %s\n", fPath
, msg
);
423 fDependentMissing
= true;
428 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
429 (*it
)->loadDependencies(mainExecutableLayout
);
434 void ArchGraph::DependencyNode::markNeededByRoot(ArchGraph::DependencyNode
* rootNode
)
436 if ( fRootsDependentOnThis
.count(rootNode
) == 0 ) {
437 fRootsDependentOnThis
.insert(rootNode
);
438 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
439 (*it
)->markNeededByRoot(rootNode
);
445 ArchGraph::DependencyNode::DependencyNode(ArchGraph
* graph
, const char* path
, const MachOLayoutAbstraction
* layout
)
446 : fGraph(graph
), fPath(strdup(path
)), fLayout(layout
), fDependenciesLoaded(false), fDependentMissing(false)
448 //fprintf(stderr, "new DependencyNode(0x%08X, %s)\n", graph->fArch, path);
451 void ArchGraph::findSharedDylibs(ArchPair ap
)
453 const PathToNode
& nodes
= fgPerArchGraph
[ap
]->fNodes
;
454 std::set
<const MachOLayoutAbstraction
*> possibleLibs
;
455 //fprintf(stderr, "shared for arch %s\n", archName(ap));
456 for(PathToNode::const_iterator it
= nodes
.begin(); it
!= nodes
.end(); ++it
) {
457 DependencyNode
* node
= it
->second
;
458 // <rdar://problem/6127437> put all dylibs in shared cache - not just ones used by more than one app
459 if ( node
->allDependentsFound() /*&& (node->useCount() > 1)*/ ) {
460 const MachOLayoutAbstraction
* layout
= node
->getLayout();
461 if ( layout
->isDylib() ) {
463 if ( sharable(layout
, ap
, &msg
) ) {
464 possibleLibs
.insert(layout
);
467 if ( layout
->getID().name
[0] == '@' ) {
468 // <rdar://problem/7770139> update_dyld_shared_cache should suppress warnings for embedded frameworks
471 warnings
.push_back(msg
);
472 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
479 // prune so that all shareable libs depend only on other shareable libs
480 std::set
<const MachOLayoutAbstraction
*>& sharedLibs
= fgPerArchGraph
[ap
]->fSharedDylibs
;
481 std::map
<const MachOLayoutAbstraction
*,bool> shareableMap
;
482 for (std::set
<const MachOLayoutAbstraction
*>::iterator lit
= possibleLibs
.begin(); lit
!= possibleLibs
.end(); ++lit
) {
483 if ( canBeShared(*lit
, ap
, possibleLibs
, shareableMap
) )
484 sharedLibs
.insert(*lit
);
488 const char* ArchGraph::archName(ArchPair ap
)
493 case CPU_TYPE_X86_64
:
496 switch ( ap
.subtype
) {
497 case CPU_SUBTYPE_ARM_V4T
:
499 case CPU_SUBTYPE_ARM_V6
:
501 case CPU_SUBTYPE_ARM_V5TEJ
:
503 case CPU_SUBTYPE_ARM_XSCALE
:
505 case CPU_SUBTYPE_ARM_V7
:
507 case CPU_SUBTYPE_ARM_V7F
:
509 case CPU_SUBTYPE_ARM_V7K
:
519 bool ArchGraph::sharable(const MachOLayoutAbstraction
* layout
, ArchPair ap
, char** msg
)
521 if ( ! layout
->isTwoLevelNamespace() )
522 asprintf(msg
, "can't put %s in shared cache because it was built -flat_namespace", layout
->getID().name
);
523 else if ( ! layout
->hasSplitSegInfo() )
524 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"));
525 else if ( ! layout
->isRootOwned() )
526 asprintf(msg
, "can't put %s in shared cache because it is not owned by root", layout
->getID().name
);
527 else if ( ! layout
->inSharableLocation() )
528 asprintf(msg
, "can't put %s in shared cache because it is not in /usr/lib or /System/Library", layout
->getID().name
);
529 else if ( layout
->hasDynamicLookupLinkage() )
530 asprintf(msg
, "can't put %s in shared cache because it was built with '-undefined dynamic_lookup'", layout
->getID().name
);
531 else if ( layout
->hasMainExecutableLookupLinkage() )
532 asprintf(msg
, "can't put %s in shared cache because it was built with '-bundle_loader'", layout
->getID().name
);
533 //else if ( ! layout->hasDyldInfo() )
534 // asprintf(msg, "can't put %s in shared cache because it was built for older OS", layout->getID().name);
540 bool ArchGraph::canBeShared(const MachOLayoutAbstraction
* layout
, ArchPair ap
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
)
542 // check map which is a cache of results
543 std::map
<const MachOLayoutAbstraction
*, bool>::iterator mapPos
= shareableMap
.find(layout
);
544 if ( mapPos
!= shareableMap
.end() ) {
545 return mapPos
->second
;
548 if ( possibleLibs
.count(layout
) == 0 ) {
549 shareableMap
[layout
] = false;
551 if ( sharable(layout
, ap
, &msg
) )
552 asprintf(&msg
, "can't put %s in shared cache, unknown reason", layout
->getID().name
);
553 warnings
.push_back(msg
);
555 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
559 shareableMap
[layout
] = true; // mark this shareable early in case of circular references
560 const PathToNode
& nodes
= fgPerArchGraph
[ap
]->fNodes
;
561 const std::vector
<MachOLayoutAbstraction::Library
>& dependents
= layout
->getLibraries();
562 for (std::vector
<MachOLayoutAbstraction::Library
>::const_iterator dit
= dependents
.begin(); dit
!= dependents
.end(); ++dit
) {
563 PathToNode::const_iterator pos
= nodes
.find(dit
->name
);
564 if ( pos
== nodes
.end() ) {
565 // path from load command does not match any loaded dylibs, maybe there is a temp symlink
566 char realPath
[MAXPATHLEN
];
567 if ( realpath(dit
->name
, realPath
) != NULL
) {
568 if ( nodes
.find(realPath
) != nodes
.end() )
571 // handle weak imported dylibs not found
572 if ( dit
->weakImport
)
574 shareableMap
[layout
] = false;
576 asprintf(&msg
, "can't put %s in shared cache because it depends on %s which can't be found", layout
->getID().name
, dit
->name
);
577 warnings
.push_back(msg
);
579 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
583 if ( ! canBeShared(pos
->second
->getLayout(), ap
, possibleLibs
, shareableMap
) ) {
584 shareableMap
[layout
] = false;
586 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
);
587 warnings
.push_back(msg
);
589 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
598 template <typename A
>
602 SharedCache(ArchGraph
* graph
, const char* rootPath
, const char* overlayPath
, const char* cacheDir
, bool explicitCacheDir
,
603 bool alphaSort
, bool verify
, bool optimize
, uint64_t dyldBaseAddress
);
604 bool update(bool force
, bool optimize
, bool deleteExistingFirst
, int archIndex
,
605 int archCount
, bool keepSignatures
);
606 static const char* cacheFileSuffix(bool optimized
, const char* archName
);
608 // vm address = address AS WRITTEN into the cache
609 // mapped address = address AS MAPPED into the update process only
610 // file offset = offset relative to start of cache file
611 void * mappedAddressForVMAddress(uint64_t vmaddr
);
612 uint64_t VMAddressForMappedAddress(const void *mapaddr
);
613 uint64_t cacheFileOffsetForVMAddress(uint64_t addr
) const;
614 uint64_t VMAddressForCacheFileOffset(uint64_t addr
) const;
616 static const char* archName();
619 typedef typename
A::P P
;
620 typedef typename
A::P::E E
;
621 typedef typename
A::P::uint_t pint_t
;
623 bool notUpToDate(const char* path
, unsigned int aliasCount
);
624 bool notUpToDate(const void* cache
, unsigned int aliasCount
);
625 uint8_t* optimizeLINKEDIT(bool keepSignatures
);
626 void optimizeObjC(std::vector
<void*>& pointersInData
);
628 static void getSharedCacheBasAddresses(cpu_type_t arch
, uint64_t* baseReadOnly
, uint64_t* baseWritable
);
629 static cpu_type_t
arch();
630 static uint64_t sharedRegionReadOnlyStartAddress();
631 static uint64_t sharedRegionWritableStartAddress();
632 static uint64_t sharedRegionReadOnlySize();
633 static uint64_t sharedRegionWritableSize();
634 static uint64_t getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
);
635 static bool addCacheSlideInfo();
637 void assignNewBaseAddresses(bool verify
);
640 const MachOLayoutAbstraction
* layout
;
641 std::vector
<const char*> aliases
;
642 dyld_cache_image_info info
;
645 struct ByNameSorter
{
646 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
)
647 { return (strcmp(left
.layout
->getID().name
, right
.layout
->getID().name
) < 0); }
650 struct ByAddressSorter
{
651 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
652 return (left
.layout
->getSegments()[0].newAddress() < right
.layout
->getSegments()[0].newAddress());
656 struct ByCStringSectionSizeSorter
{
657 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
658 const std::vector
<MachOLayoutAbstraction::Segment
>& segs_l
=
659 left
.layout
->getSegments();
660 const std::vector
<MachOLayoutAbstraction::Segment
>& segs_r
=
661 right
.layout
->getSegments();
662 if (segs_l
.size() == 0 || segs_r
.size() == 0) {
663 // one image has no segments
664 return segs_l
.size() > segs_r
.size();
666 const macho_header
<P
> *mh_l
= (macho_header
<P
>*)segs_l
[0].mappedAddress();
667 const macho_header
<P
> *mh_r
= (macho_header
<P
>*)segs_r
[0].mappedAddress();
668 const macho_section
<P
> *cstring_l
= mh_l
->getSection("__TEXT", "__cstring");
669 const macho_section
<P
> *cstring_r
= mh_r
->getSection("__TEXT", "__cstring");
670 if (!cstring_l
|| !cstring_r
) {
671 // one image has no cstrings
672 return cstring_l
&& !cstring_r
;
675 return cstring_l
->size() > cstring_r
->size();
680 Sorter(std::map
<const MachOLayoutAbstraction
*, uint32_t>& map
): fMap(map
) {}
681 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
682 return (fMap
[left
.layout
] < fMap
[right
.layout
]);
685 std::map
<const MachOLayoutAbstraction
*, uint32_t>& fMap
;
689 ArchGraph
* fArchGraph
;
691 bool fExistingIsNotUpToDate
;
692 bool fCacheFileInFinalLocation
;
693 const char* fCacheFilePath
;
694 uint8_t* fExistingCacheForVerification
;
695 std::vector
<LayoutInfo
> fDylibs
;
696 std::vector
<LayoutInfo
> fDylibAliases
;
697 std::vector
<shared_file_mapping_np
> fMappings
;
698 uint32_t fHeaderSize
;
699 uint8_t* fInMemoryCache
;
700 uint64_t fDyldBaseAddress
;
701 uint64_t fLinkEditsTotalUnoptimizedSize
;
702 uint64_t fLinkEditsStartAddress
;
703 MachOLayoutAbstraction::Segment
* fFirstLinkEditSegment
;
704 uint32_t fOffsetOfBindInfoInCombinedLinkedit
;
705 uint32_t fOffsetOfWeakBindInfoInCombinedLinkedit
;
706 uint32_t fOffsetOfLazyBindInfoInCombinedLinkedit
;
707 uint32_t fOffsetOfExportInfoInCombinedLinkedit
;
708 uint32_t fOffsetOfOldSymbolTableInfoInCombinedLinkedit
;
709 uint32_t fSizeOfOldSymbolTableInfoInCombinedLinkedit
;
710 uint32_t fOffsetOfOldExternalRelocationsInCombinedLinkedit
;
711 uint32_t fSizeOfOldExternalRelocationsInCombinedLinkedit
;
712 uint32_t fOffsetOfOldIndirectSymbolsInCombinedLinkedit
;
713 uint32_t fSizeOfOldIndirectSymbolsInCombinedLinkedit
;
714 uint32_t fOffsetOfOldStringPoolInCombinedLinkedit
;
715 uint32_t fSizeOfOldStringPoolInCombinedLinkedit
;
716 uint32_t fOffsetOfFunctionStartsInCombinedLinkedit
;
717 uint32_t fSizeOfFunctionStartsInCombinedLinkedit
;
718 uint32_t fOffsetOfDataInCodeInCombinedLinkedit
;
719 uint32_t fSizeOfDataInCodeInCombinedLinkedit
;
720 uint32_t fLinkEditsTotalOptimizedSize
;
724 // Access a section containing a list of pointers
725 template <typename A
, typename T
>
728 typedef typename
A::P P
;
729 typedef typename
A::P::uint_t pint_t
;
731 SharedCache
<A
>* const fCache
;
732 const macho_section
<P
>* const fSection
;
733 pint_t
* const fBase
;
737 PointerSection(SharedCache
<A
>* cache
, const macho_header
<P
>* header
,
738 const char *segname
, const char *sectname
)
740 , fSection(header
->getSection(segname
, sectname
))
741 , fBase(fSection
? (pint_t
*)cache
->mappedAddressForVMAddress(fSection
->addr()) : 0)
742 , fCount(fSection
? fSection
->size() / sizeof(pint_t
) : 0)
746 uint64_t count() const { return fCount
; }
748 uint64_t getUnmapped(uint64_t index
) const {
749 if (index
>= fCount
) throwf("index out of range");
750 return P::getP(fBase
[index
]);
753 T
get(uint64_t index
) const {
754 return (T
)fCache
->mappedAddressForVMAddress(getUnmapped(index
));
757 void set(uint64_t index
, uint64_t value
) {
758 if (index
>= fCount
) throwf("index out of range");
759 P::setP(fBase
[index
], value
);
764 for (uint64_t i
= 0; i
< fCount
; i
++) {
765 pint_t value
= fBase
[i
];
767 fBase
[i
-shift
] = value
;
773 const_cast<macho_section
<P
>*>(fSection
)->set_size(fCount
* sizeof(pint_t
));
777 // Access a section containing an array of structures
778 template <typename A
, typename T
>
781 typedef typename
A::P P
;
783 SharedCache
<A
>* const fCache
;
784 const macho_section
<P
>* const fSection
;
786 uint64_t const fCount
;
789 ArraySection(SharedCache
<A
>* cache
, const macho_header
<P
>* header
,
790 const char *segname
, const char *sectname
)
792 , fSection(header
->getSection(segname
, sectname
))
793 , fBase(fSection
? (T
*)cache
->mappedAddressForVMAddress(fSection
->addr()) : 0)
794 , fCount(fSection
? fSection
->size() / sizeof(T
) : 0)
798 uint64_t count() const { return fCount
; }
800 T
& get(uint64_t index
) const {
801 if (index
>= fCount
) throwf("index out of range");
808 #include "ObjCLegacyAbstraction.hpp"
809 #include "ObjCModernAbstraction.hpp"
813 template <> cpu_type_t SharedCache
<x86
>::arch() { return CPU_TYPE_I386
; }
814 template <> cpu_type_t SharedCache
<x86_64
>::arch() { return CPU_TYPE_X86_64
; }
815 template <> cpu_type_t SharedCache
<arm
>::arch() { return CPU_TYPE_ARM
; }
817 template <> uint64_t SharedCache
<x86
>::sharedRegionReadOnlyStartAddress() { return 0x90000000; }
818 template <> uint64_t SharedCache
<x86_64
>::sharedRegionReadOnlyStartAddress() { return 0x7FFF80000000LL
; }
819 template <> uint64_t SharedCache
<arm
>::sharedRegionReadOnlyStartAddress() { return 0x30000000; }
821 template <> uint64_t SharedCache
<x86
>::sharedRegionWritableStartAddress() { return 0xAC000000; }
822 template <> uint64_t SharedCache
<x86_64
>::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL
; }
823 template <> uint64_t SharedCache
<arm
>::sharedRegionWritableStartAddress() { return 0x3E000000; }
825 template <> uint64_t SharedCache
<x86
>::sharedRegionReadOnlySize() { return 0x1C000000; }
826 template <> uint64_t SharedCache
<x86_64
>::sharedRegionReadOnlySize() { return 0x40000000; }
827 template <> uint64_t SharedCache
<arm
>::sharedRegionReadOnlySize() { return 0x0E000000; }
829 template <> uint64_t SharedCache
<x86
>::sharedRegionWritableSize() { return 0x04000000; }
830 template <> uint64_t SharedCache
<x86_64
>::sharedRegionWritableSize() { return 0x10000000; }
831 template <> uint64_t SharedCache
<arm
>::sharedRegionWritableSize() { return 0x02000000; }
834 template <> const char* SharedCache
<x86
>::archName() { return "i386"; }
835 template <> const char* SharedCache
<x86_64
>::archName() { return "x86_64"; }
836 template <> const char* SharedCache
<arm
>::archName() { return "arm"; }
838 template <> const char* SharedCache
<x86
>::cacheFileSuffix(bool, const char* archName
) { return archName
; }
839 template <> const char* SharedCache
<x86_64
>::cacheFileSuffix(bool, const char* archName
){ return archName
; }
840 template <> const char* SharedCache
<arm
>::cacheFileSuffix(bool, const char* archName
) { return archName
; }
842 template <typename A
>
843 SharedCache
<A
>::SharedCache(ArchGraph
* graph
, const char* rootPath
, const char* overlayPath
, const char* cacheDir
, bool explicitCacheDir
, bool alphaSort
, bool verify
, bool optimize
, uint64_t dyldBaseAddress
)
844 : fArchGraph(graph
), fVerify(verify
), fExistingIsNotUpToDate(true),
845 fCacheFileInFinalLocation(rootPath
[0] == '\0'), fCacheFilePath(NULL
),
846 fExistingCacheForVerification(NULL
), fDyldBaseAddress(dyldBaseAddress
),
847 fOffsetOfBindInfoInCombinedLinkedit(0), fOffsetOfWeakBindInfoInCombinedLinkedit(0),
848 fOffsetOfLazyBindInfoInCombinedLinkedit(0), fOffsetOfExportInfoInCombinedLinkedit(0),
849 fOffsetOfOldSymbolTableInfoInCombinedLinkedit(0), fSizeOfOldSymbolTableInfoInCombinedLinkedit(0),
850 fOffsetOfOldExternalRelocationsInCombinedLinkedit(0), fSizeOfOldExternalRelocationsInCombinedLinkedit(0),
851 fOffsetOfOldIndirectSymbolsInCombinedLinkedit(0), fSizeOfOldIndirectSymbolsInCombinedLinkedit(0),
852 fOffsetOfOldStringPoolInCombinedLinkedit(0), fSizeOfOldStringPoolInCombinedLinkedit(0),
853 fOffsetOfFunctionStartsInCombinedLinkedit(0), fSizeOfFunctionStartsInCombinedLinkedit(0),
854 fOffsetOfDataInCodeInCombinedLinkedit(0), fSizeOfDataInCodeInCombinedLinkedit(0)
856 if ( fArchGraph
->getArchPair().arch
!= arch() )
857 throwf("SharedCache object is wrong architecture: 0x%08X vs 0x%08X", fArchGraph
->getArchPair().arch
, arch());
859 // build vector of all shared dylibs
860 unsigned int aliasCount
= 0;
861 std::set
<const MachOLayoutAbstraction
*>& dylibs
= fArchGraph
->getSharedDylibs();
862 ArchGraph::StringToString
& aliases
= fArchGraph
->getDylibAliases();
863 for(std::set
<const MachOLayoutAbstraction
*>::iterator it
= dylibs
.begin(); it
!= dylibs
.end(); ++it
) {
864 const MachOLayoutAbstraction
* lib
= *it
;
867 temp
.info
.address
= 0;
868 temp
.info
.modTime
= lib
->getLastModTime();
869 temp
.info
.inode
= lib
->getInode();
870 temp
.info
.pathFileOffset
= lib
->getNameFileOffset(); // for now this is the offset within the dylib
871 for(ArchGraph::StringToString::iterator ait
= aliases
.begin(); ait
!= aliases
.end(); ++ait
) {
872 if ( strcmp(ait
->second
, lib
->getID().name
) == 0 ) {
873 temp
.aliases
.push_back(ait
->first
);
877 fDylibs
.push_back(temp
);
880 // create path to cache file
881 char cachePathCanonical
[MAXPATHLEN
];
882 strcpy(cachePathCanonical
, cacheDir
);
883 if ( cachePathCanonical
[strlen(cachePathCanonical
)-1] != '/' )
884 strcat(cachePathCanonical
, "/");
885 strcat(cachePathCanonical
, DYLD_SHARED_CACHE_BASE_NAME
);
886 strcat(cachePathCanonical
, cacheFileSuffix(optimize
, fArchGraph
->archName()));
887 char cachePath
[MAXPATHLEN
];
888 if ( explicitCacheDir
) {
889 fCacheFilePath
= strdup(cachePathCanonical
);
891 else if ( overlayPath
[0] != '\0' ) {
892 strcpy(cachePath
, overlayPath
);
893 strcat(cachePath
, "/");
894 strcat(cachePath
, cachePathCanonical
);
895 fCacheFilePath
= strdup(cachePath
);
897 else if ( rootPath
[0] != '\0' ) {
898 strcpy(cachePath
, rootPath
);
899 strcat(cachePath
, "/");
900 strcat(cachePath
, cachePathCanonical
);
901 fCacheFilePath
= strdup(cachePath
);
904 fCacheFilePath
= strdup(cachePathCanonical
);
906 if ( overlayPath
[0] != '\0' ) {
907 // in overlay mode if there already is a cache file in the overlay
908 // check if it is up to date.
909 struct stat stat_buf
;
910 if ( stat(fCacheFilePath
, &stat_buf
) == 0 ) {
911 fExistingIsNotUpToDate
= this->notUpToDate(fCacheFilePath
, aliasCount
);
913 else if ( rootPath
[0] != '\0' ) {
914 // using -root and -overlay, but no cache file in overlay, check one in -root
915 char cachePathRoot
[MAXPATHLEN
];
916 strcpy(cachePathRoot
, rootPath
);
917 strcat(cachePathRoot
, "/");
918 strcat(cachePathRoot
, cachePathCanonical
);
919 fExistingIsNotUpToDate
= this->notUpToDate(cachePathRoot
, aliasCount
);
922 // uisng -overlay, but no cache file in overlay, check one in boot volume
923 fExistingIsNotUpToDate
= this->notUpToDate(cachePathCanonical
, aliasCount
);
927 fExistingIsNotUpToDate
= this->notUpToDate(fCacheFilePath
, aliasCount
);
930 // sort shared dylibs
932 // already sorted by notUpToDate()
934 else if ( alphaSort
) {
935 std::sort(fDylibs
.begin(), fDylibs
.end(), ByNameSorter());
938 // random sort for Address Space Randomization
939 std::map
<const MachOLayoutAbstraction
*, uint32_t> map
;
940 for(typename
std::vector
<struct LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
)
941 map
[it
->layout
] = arc4random();
942 std::sort(fDylibs
.begin(), fDylibs
.end(), Sorter(map
));
945 // assign segments in each dylib a new address
946 this->assignNewBaseAddresses(verify
);
948 // calculate where string pool offset will start
949 // calculate cache file header size
950 fHeaderSize
= sizeof(dyld_cache_header
)
951 + fMappings
.size()*sizeof(shared_file_mapping_np
)
952 + (fDylibs
.size()+aliasCount
)*sizeof(dyld_cache_image_info
);
953 //fprintf(stderr, "aliasCount=%d, fHeaderSize=0x%08X\n", aliasCount, fHeaderSize);
954 // build list of aliases and compute where each ones path string will go
955 for(typename
std::vector
<struct LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
956 for(std::vector
<const char*>::const_iterator ait
= it
->aliases
.begin(); ait
!= it
->aliases
.end(); ++ait
) {
957 LayoutInfo temp
= *it
;
958 // alias looks just like real dylib, but has a different name string
959 const char* aliasPath
= *ait
;
960 temp
.aliases
.clear();
961 temp
.aliases
.push_back(aliasPath
);
962 temp
.info
.pathFileOffset
= fHeaderSize
;
963 fDylibAliases
.push_back(temp
);
964 fHeaderSize
+= strlen(aliasPath
)+1;
967 std::sort(fDylibAliases
.begin(), fDylibAliases
.end(), ByNameSorter());
968 //fprintf(stderr, "fHeaderSize=0x%08X, fDylibAliases.size()=%lu\n", fHeaderSize, fDylibAliases.size());
969 fHeaderSize
= pageAlign(fHeaderSize
);
971 // check that cache we are about to create for verification purposes has same layout as existing cache
973 // if no existing cache, say so
974 if ( fExistingCacheForVerification
== NULL
) {
975 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
976 getpid(), archName());
978 const dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)fExistingCacheForVerification
;
979 const dyldCacheImageInfo
<E
>* cacheEntry
= (dyldCacheImageInfo
<E
>*)(fExistingCacheForVerification
+ header
->imagesOffset());
980 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++cacheEntry
) {
981 if ( cacheEntry
->address() != it
->layout
->getSegments()[0].newAddress() ) {
982 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",
983 getpid(), archName(), it
->layout
->getID().name
, cacheEntry
->address(), it
->layout
->getSegments()[0].newAddress());
989 if ( fHeaderSize
> FIRST_DYLIB_TEXT_OFFSET
)
990 throwf("header size miscalculation 0x%08X", fHeaderSize
);
994 template <typename A
>
995 uint64_t SharedCache
<A
>::getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
)
997 return proposedNewAddress
;
1001 template <typename A
>
1002 void SharedCache
<A
>::assignNewBaseAddresses(bool verify
)
1004 uint64_t sharedCacheStartAddress
= sharedRegionReadOnlyStartAddress();
1006 if ( arch() == CPU_TYPE_X86_64
) {
1008 if ( fExistingCacheForVerification
== NULL
) {
1009 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
1010 getpid(), archName());
1012 const dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)fExistingCacheForVerification
;
1013 const dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)(fExistingCacheForVerification
+ header
->mappingOffset());
1014 sharedCacheStartAddress
= mappings
[0].address();
1017 // <rdar://problem/5274722> dyld shared cache can be more random
1018 uint64_t readOnlySize
= 0;
1019 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1020 if ( ! it
->layout
->hasSplitSegInfo() )
1022 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1023 for (int i
=0; i
< segs
.size(); ++i
) {
1024 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1025 if ( ! seg
.writable() )
1026 readOnlySize
+= pageAlign(seg
.size());
1029 uint64_t maxSlide
= sharedRegionReadOnlySize() - (readOnlySize
+ FIRST_DYLIB_TEXT_OFFSET
);
1030 sharedCacheStartAddress
= sharedRegionReadOnlyStartAddress() + pageAlign(arc4random() % maxSlide
);
1034 uint64_t currentExecuteAddress
= sharedCacheStartAddress
+ FIRST_DYLIB_TEXT_OFFSET
;
1035 uint64_t currentWritableAddress
= sharedRegionWritableStartAddress() + FIRST_DYLIB_DATA_OFFSET
;
1037 // first layout TEXT and DATA for dylibs
1038 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1039 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1040 MachOLayoutAbstraction::Segment
* executableSegment
= NULL
;
1041 for (int i
=0; i
< segs
.size(); ++i
) {
1042 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1044 if ( seg
.writable() ) {
1045 if ( seg
.executable() && it
->layout
->hasSplitSegInfo() ) {
1046 // skip __IMPORT segments in this pass
1050 if ( it
->layout
->hasSplitSegInfo() ) {
1051 if ( executableSegment
== NULL
)
1052 throwf("first segment in dylib is not executable for %s", it
->layout
->getID().name
);
1053 seg
.setNewAddress(getWritableSegmentNewAddress(currentWritableAddress
, seg
.address(), executableSegment
->newAddress() - executableSegment
->address()));
1056 seg
.setNewAddress(currentWritableAddress
);
1057 currentWritableAddress
= pageAlign(seg
.newAddress() + seg
.size());
1061 if ( seg
.executable() ) {
1063 if ( it
->info
.address
== 0 )
1064 it
->info
.address
= currentExecuteAddress
;
1065 executableSegment
= &seg
;
1066 seg
.setNewAddress(currentExecuteAddress
);
1067 currentExecuteAddress
+= pageAlign(seg
.size());
1070 // skip read-only segments in this pass
1076 // append all read-only (but not LINKEDIT) segments at end of all TEXT segments
1077 // append all IMPORT segments at end of all DATA segments rounded to next 2MB
1078 uint64_t currentReadOnlyAddress
= currentExecuteAddress
;
1079 uint64_t startWritableExecutableAddress
= (currentWritableAddress
+ 0x200000 - 1) & (-0x200000);
1080 uint64_t currentWritableExecutableAddress
= startWritableExecutableAddress
;
1081 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1082 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1083 for(int i
=0; i
< segs
.size(); ++i
) {
1084 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1085 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") != 0) ) {
1086 // allocate non-executable,read-only segments from end of read only shared region
1087 seg
.setNewAddress(currentReadOnlyAddress
);
1088 currentReadOnlyAddress
+= pageAlign(seg
.size());
1090 else if ( seg
.writable() && seg
.executable() && it
->layout
->hasSplitSegInfo() ) {
1091 // allocate IMPORT segments to end of writable shared region
1092 seg
.setNewAddress(currentWritableExecutableAddress
);
1093 currentWritableExecutableAddress
+= pageAlign(seg
.size());
1098 // append all LINKEDIT segments at end of all read-only segments
1099 fLinkEditsStartAddress
= currentReadOnlyAddress
;
1100 fFirstLinkEditSegment
= NULL
;
1101 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1102 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1103 for(int i
=0; i
< segs
.size(); ++i
) {
1104 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1105 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
1106 if ( fFirstLinkEditSegment
== NULL
)
1107 fFirstLinkEditSegment
= &seg
;
1108 // allocate non-executable,read-only segments from end of read only shared region
1109 seg
.setNewAddress(currentReadOnlyAddress
);
1110 currentReadOnlyAddress
+= pageAlign(seg
.size());
1114 fLinkEditsTotalUnoptimizedSize
= (currentReadOnlyAddress
- fLinkEditsStartAddress
+ 4095) & (-4096);
1116 // <rdar://problem/9361288> i386 dyld shared cache overflows after adding libclh.dylib
1117 if ( (currentReadOnlyAddress
- sharedRegionReadOnlyStartAddress()) > sharedRegionReadOnlySize() )
1118 throwf("read-only slice of cache too big: %lluMB (max %lluMB)",
1119 (currentReadOnlyAddress
- sharedRegionReadOnlyStartAddress())/(1024*1024),
1120 sharedRegionReadOnlySize()/(1024*1024));
1123 // populate large mappings
1124 uint64_t cacheFileOffset
= 0;
1125 if ( currentExecuteAddress
> sharedCacheStartAddress
+ FIRST_DYLIB_TEXT_OFFSET
) {
1126 shared_file_mapping_np executeMapping
;
1127 executeMapping
.sfm_address
= sharedCacheStartAddress
;
1128 executeMapping
.sfm_size
= currentExecuteAddress
- sharedCacheStartAddress
;
1129 executeMapping
.sfm_file_offset
= cacheFileOffset
;
1130 executeMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
1131 executeMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
1132 fMappings
.push_back(executeMapping
);
1133 cacheFileOffset
+= executeMapping
.sfm_size
;
1135 shared_file_mapping_np writableMapping
;
1136 writableMapping
.sfm_address
= sharedRegionWritableStartAddress();
1137 writableMapping
.sfm_size
= currentWritableAddress
- sharedRegionWritableStartAddress();
1138 writableMapping
.sfm_file_offset
= cacheFileOffset
;
1139 writableMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
1140 writableMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
1141 fMappings
.push_back(writableMapping
);
1142 cacheFileOffset
+= writableMapping
.sfm_size
;
1144 if ( currentWritableExecutableAddress
> startWritableExecutableAddress
) {
1145 shared_file_mapping_np writableExecutableMapping
;
1146 writableExecutableMapping
.sfm_address
= startWritableExecutableAddress
;
1147 writableExecutableMapping
.sfm_size
= currentWritableExecutableAddress
- startWritableExecutableAddress
;
1148 writableExecutableMapping
.sfm_file_offset
= cacheFileOffset
;
1149 writableExecutableMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_WRITE
| VM_PROT_EXECUTE
;
1150 writableExecutableMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_WRITE
| VM_PROT_EXECUTE
;
1151 fMappings
.push_back(writableExecutableMapping
);
1152 cacheFileOffset
+= writableExecutableMapping
.sfm_size
;
1155 // make read-only (contains LINKEDIT segments) last, so it can be cut back when optimized
1156 shared_file_mapping_np readOnlyMapping
;
1157 readOnlyMapping
.sfm_address
= currentExecuteAddress
;
1158 readOnlyMapping
.sfm_size
= currentReadOnlyAddress
- currentExecuteAddress
;
1159 readOnlyMapping
.sfm_file_offset
= cacheFileOffset
;
1160 readOnlyMapping
.sfm_max_prot
= VM_PROT_READ
;
1161 readOnlyMapping
.sfm_init_prot
= VM_PROT_READ
;
1162 fMappings
.push_back(readOnlyMapping
);
1163 cacheFileOffset
+= readOnlyMapping
.sfm_size
;
1167 shared_file_mapping_np cacheHeaderMapping
;
1168 cacheHeaderMapping
.sfm_address
= sharedRegionWritableStartAddress();
1169 cacheHeaderMapping
.sfm_size
= FIRST_DYLIB_TEXT_OFFSET
;
1170 cacheHeaderMapping
.sfm_file_offset
= cacheFileOffset
;
1171 cacheHeaderMapping
.sfm_max_prot
= VM_PROT_READ
;
1172 cacheHeaderMapping
.sfm_init_prot
= VM_PROT_READ
;
1173 fMappings
.push_back(cacheHeaderMapping
);
1174 cacheFileOffset
+= cacheHeaderMapping
.sfm_size
;
1179 template <typename A
>
1180 uint64_t SharedCache
<A
>::cacheFileOffsetForVMAddress(uint64_t vmaddr
) const
1182 for(std::vector
<shared_file_mapping_np
>::const_iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1183 if ( (it
->sfm_address
<= vmaddr
) && (vmaddr
< it
->sfm_address
+it
->sfm_size
) )
1184 return it
->sfm_file_offset
+ vmaddr
- it
->sfm_address
;
1186 throwf("address 0x%0llX is not in cache", vmaddr
);
1189 template <typename A
>
1190 uint64_t SharedCache
<A
>::VMAddressForCacheFileOffset(uint64_t offset
) const
1192 for(std::vector
<shared_file_mapping_np
>::const_iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1193 if ( (it
->sfm_file_offset
<= offset
) && (offset
< it
->sfm_file_offset
+it
->sfm_size
) )
1194 return it
->sfm_address
+ offset
- it
->sfm_file_offset
;
1196 throwf("offset 0x%0llX is not in cache", offset
);
1199 template <typename A
>
1200 void *SharedCache
<A
>::mappedAddressForVMAddress(uint64_t vmaddr
)
1202 if (!vmaddr
) return NULL
;
1203 else return fInMemoryCache
+ cacheFileOffsetForVMAddress(vmaddr
);
1206 template <typename A
>
1207 uint64_t SharedCache
<A
>::VMAddressForMappedAddress(const void *mapaddr
)
1209 if (!mapaddr
) return 0;
1210 uint64_t offset
= (uint8_t *)mapaddr
- (uint8_t *)fInMemoryCache
;
1211 return VMAddressForCacheFileOffset(offset
);
1215 template <typename A
>
1216 bool SharedCache
<A
>::notUpToDate(const void* cache
, unsigned int aliasCount
)
1218 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)cache
;
1219 // not valid if header signature is wrong
1220 const char* archPairName
= fArchGraph
->archName();
1222 strcpy(temp
, "dyld_v1 ");
1223 strcpy(&temp
[15-strlen(archPairName
)], archPairName
);
1224 if ( strcmp(header
->magic(), temp
) != 0 ) {
1226 fprintf(stderr
, "update_dyld_shared_cache[%u] cannot verify %s because current cache file has invalid header\n", getpid(), archName());
1230 fprintf(stderr
, "update_dyld_shared_cache[%u] updating cache because current cache file has invalid header\n", getpid());
1234 // not valid if count of images does not match current images needed
1235 if ( header
->imagesCount() != (fDylibs
.size()+aliasCount
) ) {
1237 fprintf(stderr
, "update_dyld_shared_cache[%u] cannot verify %s because current cache file contains a different set of dylibs\n", getpid(), archName());
1241 fprintf(stderr
, "update_dyld_shared_cache[%u] updating %s cache because current cache file contains a different set of dylibs\n", getpid(), archName());
1245 // get end of TEXT region
1246 const dyldCacheFileMapping
<E
>* textMapping
= (dyldCacheFileMapping
<E
>*)((uint8_t*)cache
+sizeof(dyldCacheHeader
<E
>));
1247 const uint32_t textSize
= textMapping
->size();
1249 // verify every dylib in constructed graph is in existing cache with same inode and modTime
1250 std::map
<const MachOLayoutAbstraction
*, uint32_t> sortingMap
;
1251 const dyldCacheImageInfo
<E
>* imagesStart
= (dyldCacheImageInfo
<E
>*)((uint8_t*)cache
+ header
->imagesOffset());
1252 const dyldCacheImageInfo
<E
>* imagesEnd
= &imagesStart
[header
->imagesCount()];
1253 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1255 //fprintf(stderr, "inode=0x%llX, mTime=0x%llX, path=%s\n", it->info.inode, it->info.modTime, it->layout->getID().name);
1256 for(const dyldCacheImageInfo
<E
>* cacheEntry
= imagesStart
; cacheEntry
< imagesEnd
; ++cacheEntry
) {
1258 if ( cacheEntry
->pathFileOffset() > textSize
) {
1259 throwf("update_dyld_shared_cache[%u]: for arch=%s, image entries corrupt, bad path offset in %s\n",
1260 getpid(), archName(), it
->layout
->getID().name
);
1262 // in -verify mode, just match by path and warn if file looks different
1263 if ( strcmp((char*)cache
+cacheEntry
->pathFileOffset(), it
->layout
->getID().name
) == 0 ) {
1265 sortingMap
[it
->layout
] = cacheEntry
-imagesStart
;
1266 if ( (cacheEntry
->inode() != it
->info
.inode
) || (cacheEntry
->modTime() != it
->info
.modTime
) ) {
1267 fprintf(stderr
, "update_dyld_shared_cache[%u] warning: for arch=%s, %s has changed since cache was built\n",
1268 getpid(), archName(), it
->layout
->getID().name
);
1274 if ( cacheEntry
->pathFileOffset() > textSize
) {
1275 // cache corrupt, needs to be regenerated
1278 // in normal update mode, everything has to match for cache to be up-to-date
1279 if ( (cacheEntry
->inode() == it
->info
.inode
)
1280 && (cacheEntry
->modTime() == it
->info
.modTime
)
1281 && (strcmp((char*)cache
+cacheEntry
->pathFileOffset(), it
->layout
->getID().name
) == 0) ) {
1289 throwf("update_dyld_shared_cache[%u] can't verify %s cache because %s is not in existing cache\n", getpid(), archName(), it
->layout
->getID().name
);
1292 fprintf(stderr
, "update_dyld_shared_cache[%u] updating %s cache because dylib at %s has changed\n", getpid(), archName(), it
->layout
->getID().name
);
1297 // all dylibs in existing cache file match those determined need to be in shared cache
1299 // sort fDylibs to match existing cache file so we can compare content
1300 std::sort(fDylibs
.begin(), fDylibs
.end(), Sorter(sortingMap
));
1301 //fprintf(stderr, "dylibs sorted like existing cache:\n");
1302 //for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1303 // fprintf(stderr," %s\n", it->layout->getID().name);
1305 // do regenerate a new cache so we can compare content with existing
1309 // existing cache file is up-to-date, don't need to regenerate
1315 template <typename A
>
1316 bool SharedCache
<A
>::notUpToDate(const char* path
, unsigned int aliasCount
)
1318 // mmap existing cache file
1319 int fd
= ::open(path
, O_RDONLY
);
1322 struct stat stat_buf
;
1323 ::fstat(fd
, &stat_buf
);
1324 uint32_t cacheFileSize
= stat_buf
.st_size
;
1325 uint32_t cacheAllocatedSize
= (cacheFileSize
+ 4095) & (-4096);
1326 uint8_t* mappingAddr
= NULL
;
1327 if ( vm_allocate(mach_task_self(), (vm_address_t
*)(&mappingAddr
), cacheAllocatedSize
, VM_FLAGS_ANYWHERE
) != KERN_SUCCESS
)
1328 throwf("can't vm_allocate cache of size %u", cacheFileSize
);
1329 // <rdar://problem/8960832> update_dyld_shared_cache -verify finds differences
1330 (void)fcntl(fd
, F_NOCACHE
, 1);
1331 ssize_t readResult
= pread(fd
, mappingAddr
, cacheFileSize
, 0);
1332 if ( readResult
!= cacheFileSize
)
1333 throwf("can't read all of existing cache file (%lu of %u): %s", readResult
, cacheFileSize
, path
);
1337 bool result
= this->notUpToDate(mappingAddr
, aliasCount
);
1339 // don't unmap yet, leave so it can be verified later
1340 fExistingCacheForVerification
= mappingAddr
;
1344 vm_deallocate(mach_task_self(), (vm_address_t
)mappingAddr
, cacheAllocatedSize
);
1345 if ( verbose
&& !result
)
1346 fprintf(stderr
, "update_dyld_shared_cache: %s is up-to-date\n", path
);
1354 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
1361 const char* getBuffer();
1363 uint32_t add(const char* str
);
1364 uint32_t addUnique(const char* str
);
1365 const char* stringAtIndex(uint32_t) const;
1367 typedef __gnu_cxx::hash_map
<const char*, uint32_t, __gnu_cxx::hash
<const char*>, CStringEquals
> StringToOffset
;
1370 uint32_t fBufferAllocated
;
1371 uint32_t fBufferUsed
;
1372 StringToOffset fUniqueStrings
;
1376 StringPool::StringPool()
1377 : fBufferUsed(0), fBufferAllocated(32*1024*1024)
1379 fBuffer
= (char*)malloc(fBufferAllocated
);
1382 uint32_t StringPool::add(const char* str
)
1384 uint32_t len
= strlen(str
);
1385 if ( (fBufferUsed
+ len
+ 1) > fBufferAllocated
) {
1387 throw "string buffer exhausted";
1389 strcpy(&fBuffer
[fBufferUsed
], str
);
1390 uint32_t result
= fBufferUsed
;
1391 fUniqueStrings
[&fBuffer
[fBufferUsed
]] = result
;
1392 fBufferUsed
+= len
+1;
1396 uint32_t StringPool::addUnique(const char* str
)
1398 StringToOffset::iterator pos
= fUniqueStrings
.find(str
);
1399 if ( pos
!= fUniqueStrings
.end() )
1402 //fprintf(stderr, "StringPool::addUnique() new string: %s\n", str);
1403 return this->add(str
);
1407 uint32_t StringPool::size()
1412 const char* StringPool::getBuffer()
1417 const char* StringPool::stringAtIndex(uint32_t index
) const
1419 return &fBuffer
[index
];
1423 template <typename A
>
1424 class LinkEditOptimizer
1427 LinkEditOptimizer(const MachOLayoutAbstraction
&, const SharedCache
<A
>&, uint8_t*, StringPool
&);
1428 virtual ~LinkEditOptimizer() {}
1430 void copyBindInfo(uint32_t&);
1431 void copyWeakBindInfo(uint32_t&);
1432 void copyLazyBindInfo(uint32_t&);
1433 void copyExportInfo(uint32_t&);
1434 void copyLocalSymbols(uint32_t symbolTableOffset
, uint32_t&);
1435 void copyExportedSymbols(uint32_t symbolTableOffset
, uint32_t&);
1436 void copyImportedSymbols(uint32_t symbolTableOffset
, uint32_t&);
1437 void copyExternalRelocations(uint32_t& offset
);
1438 void copyIndirectSymbolTable(uint32_t& offset
);
1439 void copyFunctionStarts(uint32_t& offset
);
1440 void copyDataInCode(uint32_t& offset
);
1441 void updateLoadCommands(uint64_t newVMAddress
, uint64_t size
, uint32_t stringPoolOffset
,
1442 uint32_t linkEditsFileOffset
, bool keepSignatures
);
1446 typedef typename
A::P P
;
1447 typedef typename
A::P::E E
;
1448 typedef typename
A::P::uint_t pint_t
;
1452 const SharedCache
<A
>& fSharedCache
;
1453 const macho_header
<P
>* fHeader
;
1454 uint8_t* fNewLinkEditStart
;
1455 uint8_t* fLinkEditBase
;
1456 const MachOLayoutAbstraction
& fLayout
;
1457 macho_dyld_info_command
<P
>* fDyldInfo
;
1458 macho_dysymtab_command
<P
>* fDynamicSymbolTable
;
1459 macho_linkedit_data_command
<P
>* fFunctionStarts
;
1460 macho_linkedit_data_command
<P
>* fDataInCode
;
1461 macho_symtab_command
<P
>* fSymbolTableLoadCommand
;
1462 const macho_nlist
<P
>* fSymbolTable
;
1463 const char* fStrings
;
1464 StringPool
& fNewStringPool
;
1465 std::map
<uint32_t,uint32_t> fOldToNewSymbolIndexes
;
1466 uint32_t fBindInfoOffsetIntoNewLinkEdit
;
1467 uint32_t fBindInfoSizeInNewLinkEdit
;
1468 uint32_t fWeakBindInfoOffsetIntoNewLinkEdit
;
1469 uint32_t fWeakBindInfoSizeInNewLinkEdit
;
1470 uint32_t fLazyBindInfoOffsetIntoNewLinkEdit
;
1471 uint32_t fLazyBindInfoSizeInNewLinkEdit
;
1472 uint32_t fExportInfoOffsetIntoNewLinkEdit
;
1473 uint32_t fExportInfoSizeInNewLinkEdit
;
1474 uint32_t fSymbolTableStartOffsetInNewLinkEdit
;
1475 uint32_t fLocalSymbolsStartIndexInNewLinkEdit
;
1476 uint32_t fLocalSymbolsCountInNewLinkEdit
;
1477 uint32_t fExportedSymbolsStartIndexInNewLinkEdit
;
1478 uint32_t fExportedSymbolsCountInNewLinkEdit
;
1479 uint32_t fImportSymbolsStartIndexInNewLinkEdit
;
1480 uint32_t fImportedSymbolsCountInNewLinkEdit
;
1481 uint32_t fExternalRelocationsOffsetIntoNewLinkEdit
;
1482 uint32_t fIndirectSymbolTableOffsetInfoNewLinkEdit
;
1483 uint32_t fFunctionStartsOffsetInNewLinkEdit
;
1484 uint32_t fDataInCodeOffsetInNewLinkEdit
;
1489 template <typename A
>
1490 LinkEditOptimizer
<A
>::LinkEditOptimizer(const MachOLayoutAbstraction
& layout
, const SharedCache
<A
>& sharedCache
, uint8_t* newLinkEdit
, StringPool
& stringPool
)
1491 : fSharedCache(sharedCache
), fLayout(layout
), fLinkEditBase(NULL
), fNewLinkEditStart(newLinkEdit
), fDyldInfo(NULL
),
1492 fDynamicSymbolTable(NULL
), fFunctionStarts(NULL
), fDataInCode(NULL
),
1493 fSymbolTableLoadCommand(NULL
), fSymbolTable(NULL
), fStrings(NULL
), fNewStringPool(stringPool
),
1494 fBindInfoOffsetIntoNewLinkEdit(0), fBindInfoSizeInNewLinkEdit(0),
1495 fWeakBindInfoOffsetIntoNewLinkEdit(0), fWeakBindInfoSizeInNewLinkEdit(0),
1496 fLazyBindInfoOffsetIntoNewLinkEdit(0), fLazyBindInfoSizeInNewLinkEdit(0),
1497 fExportInfoOffsetIntoNewLinkEdit(0), fExportInfoSizeInNewLinkEdit(0),
1498 fSymbolTableStartOffsetInNewLinkEdit(0),
1499 fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
1500 fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
1501 fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
1502 fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0),
1503 fFunctionStartsOffsetInNewLinkEdit(0), fDataInCodeOffsetInNewLinkEdit(0)
1506 fHeader
= (const macho_header
<P
>*)fLayout
.getSegments()[0].mappedAddress();
1508 const std::vector
<MachOLayoutAbstraction::Segment
>& segments
= fLayout
.getSegments();
1509 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator it
= segments
.begin(); it
!= segments
.end(); ++it
) {
1510 const MachOLayoutAbstraction::Segment
& seg
= *it
;
1511 if ( strcmp(seg
.name(), "__LINKEDIT") == 0 )
1512 fLinkEditBase
= (uint8_t*)seg
.mappedAddress() - seg
.fileOffset();
1514 if ( fLinkEditBase
== NULL
)
1515 throw "no __LINKEDIT segment";
1517 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
1518 const uint32_t cmd_count
= fHeader
->ncmds();
1519 const macho_load_command
<P
>* cmd
= cmds
;
1520 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1521 switch (cmd
->cmd()) {
1524 fSymbolTableLoadCommand
= (macho_symtab_command
<P
>*)cmd
;
1525 fSymbolTable
= (macho_nlist
<P
>*)(&fLinkEditBase
[fSymbolTableLoadCommand
->symoff()]);
1526 fStrings
= (char*)&fLinkEditBase
[fSymbolTableLoadCommand
->stroff()];
1530 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
1533 case LC_DYLD_INFO_ONLY
:
1534 fDyldInfo
= (macho_dyld_info_command
<P
>*)cmd
;
1536 case LC_FUNCTION_STARTS
:
1537 fFunctionStarts
= (macho_linkedit_data_command
<P
>*)cmd
;
1538 case LC_DATA_IN_CODE
:
1539 fDataInCode
= (macho_linkedit_data_command
<P
>*)cmd
;
1542 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1544 if ( fSymbolTable
== NULL
)
1545 throw "no LC_SYMTAB";
1546 if ( fDynamicSymbolTable
== NULL
)
1547 throw "no LC_DYSYMTAB";
1552 template <typename A
>
1556 typedef typename
A::P P
;
1557 SymbolSorter(const StringPool
& pool
) : fStringPool(pool
) {}
1558 bool operator()(const macho_nlist
<P
>& left
, const macho_nlist
<P
>& right
) {
1559 return (strcmp(fStringPool
.stringAtIndex(left
.n_strx()) , fStringPool
.stringAtIndex(right
.n_strx())) < 0);
1563 const StringPool
& fStringPool
;
1567 template <typename A
>
1568 void LinkEditOptimizer
<A
>::copyBindInfo(uint32_t& offset
)
1570 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->bind_off() != 0) ) {
1571 fBindInfoOffsetIntoNewLinkEdit
= offset
;
1572 fBindInfoSizeInNewLinkEdit
= fDyldInfo
->bind_size();
1573 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->bind_off()], fDyldInfo
->bind_size());
1574 offset
+= fDyldInfo
->bind_size();
1578 template <typename A
>
1579 void LinkEditOptimizer
<A
>::copyWeakBindInfo(uint32_t& offset
)
1581 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->weak_bind_off() != 0) ) {
1582 fWeakBindInfoOffsetIntoNewLinkEdit
= offset
;
1583 fWeakBindInfoSizeInNewLinkEdit
= fDyldInfo
->weak_bind_size();
1584 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->weak_bind_off()], fDyldInfo
->weak_bind_size());
1585 offset
+= fDyldInfo
->weak_bind_size();
1589 template <typename A
>
1590 void LinkEditOptimizer
<A
>::copyLazyBindInfo(uint32_t& offset
)
1592 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->lazy_bind_off() != 0) ) {
1593 fLazyBindInfoOffsetIntoNewLinkEdit
= offset
;
1594 fLazyBindInfoSizeInNewLinkEdit
= fDyldInfo
->lazy_bind_size();
1595 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->lazy_bind_off()], fDyldInfo
->lazy_bind_size());
1596 offset
+= fDyldInfo
->lazy_bind_size();
1600 template <typename A
>
1601 void LinkEditOptimizer
<A
>::copyExportInfo(uint32_t& offset
)
1603 if ( (fDyldInfo
!= NULL
) && (fLayout
.getDyldInfoExports() != NULL
) ) {
1604 fExportInfoOffsetIntoNewLinkEdit
= offset
;
1605 fExportInfoSizeInNewLinkEdit
= fDyldInfo
->export_size();
1606 memcpy(fNewLinkEditStart
+offset
, fLayout
.getDyldInfoExports(), fDyldInfo
->export_size());
1607 offset
+= fDyldInfo
->export_size();
1613 template <typename A
>
1614 void LinkEditOptimizer
<A
>::copyLocalSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1616 fLocalSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1617 fSymbolTableStartOffsetInNewLinkEdit
= symbolTableOffset
+ symbolIndex
*sizeof(macho_nlist
<P
>);
1618 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1619 const macho_nlist
<P
>* const firstLocal
= &fSymbolTable
[fDynamicSymbolTable
->ilocalsym()];
1620 const macho_nlist
<P
>* const lastLocal
= &fSymbolTable
[fDynamicSymbolTable
->ilocalsym()+fDynamicSymbolTable
->nlocalsym()];
1621 uint32_t oldIndex
= fDynamicSymbolTable
->ilocalsym();
1622 for (const macho_nlist
<P
>* entry
= firstLocal
; entry
< lastLocal
; ++entry
, ++oldIndex
) {
1623 if ( (entry
->n_type() & N_TYPE
) == N_SECT
) {
1624 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1625 *newSymbolEntry
= *entry
;
1626 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1630 fLocalSymbolsCountInNewLinkEdit
= symbolIndex
- fLocalSymbolsStartIndexInNewLinkEdit
;
1631 //fprintf(stderr, "%u locals starting at %u for %s\n", fLocalSymbolsCountInNewLinkEdit, fLocalSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1635 template <typename A
>
1636 void LinkEditOptimizer
<A
>::copyExportedSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1638 fExportedSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1639 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1640 const macho_nlist
<P
>* const firstExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()];
1641 const macho_nlist
<P
>* const lastExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1642 uint32_t oldIndex
= fDynamicSymbolTable
->iextdefsym();
1643 for (const macho_nlist
<P
>* entry
= firstExport
; entry
< lastExport
; ++entry
, ++oldIndex
) {
1644 if ( ((entry
->n_type() & N_TYPE
) == N_SECT
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0)
1645 && (strncmp(&fStrings
[entry
->n_strx()], "$ld$", 4) != 0) ) {
1646 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1647 *newSymbolEntry
= *entry
;
1648 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1649 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
-fLocalSymbolsStartIndexInNewLinkEdit
;
1653 fExportedSymbolsCountInNewLinkEdit
= symbolIndex
- fExportedSymbolsStartIndexInNewLinkEdit
;
1654 //fprintf(stderr, "%u exports starting at %u for %s\n", fExportedSymbolsCountInNewLinkEdit, fExportedSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1655 // sort by name, so that dyld does not need a toc
1656 macho_nlist
<P
>* newSymbolsStart
= &newSymbolTableStart
[fExportedSymbolsStartIndexInNewLinkEdit
];
1657 macho_nlist
<P
>* newSymbolsEnd
= &newSymbolTableStart
[fExportedSymbolsStartIndexInNewLinkEdit
+fExportedSymbolsCountInNewLinkEdit
];
1658 std::sort(newSymbolsStart
, newSymbolsEnd
, SymbolSorter
<A
>(fNewStringPool
));
1659 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1660 // fprintf(stderr, "\t%u\t %s\n", (entry-newSymbolsStart)+fExportedSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1664 template <typename A
>
1665 void LinkEditOptimizer
<A
>::copyImportedSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1667 fImportSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1668 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1669 const macho_nlist
<P
>* const firstImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()];
1670 const macho_nlist
<P
>* const lastImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()+fDynamicSymbolTable
->nundefsym()];
1671 uint32_t oldIndex
= fDynamicSymbolTable
->iundefsym();
1672 for (const macho_nlist
<P
>* entry
= firstImport
; entry
< lastImport
; ++entry
, ++oldIndex
) {
1673 if ( ((entry
->n_type() & N_TYPE
) == N_UNDF
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0) ) {
1674 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1675 *newSymbolEntry
= *entry
;
1676 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1677 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
-fLocalSymbolsStartIndexInNewLinkEdit
;
1681 fImportedSymbolsCountInNewLinkEdit
= symbolIndex
- fImportSymbolsStartIndexInNewLinkEdit
;
1682 //fprintf(stderr, "%u imports starting at %u for %s\n", fImportedSymbolsCountInNewLinkEdit, fImportSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1683 //macho_nlist<P>* newSymbolsStart = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit];
1684 //macho_nlist<P>* newSymbolsEnd = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit];
1685 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1686 // fprintf(stderr, "\t%u\t%s\n", (entry-newSymbolsStart)+fImportSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1690 template <typename A
>
1691 void LinkEditOptimizer
<A
>::copyExternalRelocations(uint32_t& offset
)
1693 fExternalRelocationsOffsetIntoNewLinkEdit
= offset
;
1694 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(&fLinkEditBase
[fDynamicSymbolTable
->extreloff()]);
1695 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
1696 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1697 macho_relocation_info
<P
>* newReloc
= (macho_relocation_info
<P
>*)(&fNewLinkEditStart
[offset
]);
1699 uint32_t newSymbolIndex
= fOldToNewSymbolIndexes
[reloc
->r_symbolnum()];
1700 //fprintf(stderr, "copyExternalRelocations() old=%d, new=%u name=%s in %s\n", reloc->r_symbolnum(), newSymbolIndex,
1701 // &fStrings[fSymbolTable[reloc->r_symbolnum()].n_strx()], fLayout.getFilePath());
1702 newReloc
->set_r_symbolnum(newSymbolIndex
);
1703 offset
+= sizeof(macho_relocation_info
<P
>);
1707 template <typename A
>
1708 void LinkEditOptimizer
<A
>::copyFunctionStarts(uint32_t& offset
)
1710 if ( fFunctionStarts
!= NULL
) {
1711 fFunctionStartsOffsetInNewLinkEdit
= offset
;
1712 memcpy(&fNewLinkEditStart
[offset
], &fLinkEditBase
[fFunctionStarts
->dataoff()], fFunctionStarts
->datasize());
1713 offset
+= fFunctionStarts
->datasize();
1717 template <typename A
>
1718 void LinkEditOptimizer
<A
>::copyDataInCode(uint32_t& offset
)
1720 if ( fDataInCode
!= NULL
) {
1721 fDataInCodeOffsetInNewLinkEdit
= offset
;
1722 memcpy(&fNewLinkEditStart
[offset
], &fLinkEditBase
[fDataInCode
->dataoff()], fDataInCode
->datasize());
1723 offset
+= fDataInCode
->datasize();
1728 template <typename A
>
1729 void LinkEditOptimizer
<A
>::copyIndirectSymbolTable(uint32_t& offset
)
1731 fIndirectSymbolTableOffsetInfoNewLinkEdit
= offset
;
1732 const uint32_t* const indirectTable
= (uint32_t*)&this->fLinkEditBase
[fDynamicSymbolTable
->indirectsymoff()];
1733 uint32_t* newIndirectTable
= (uint32_t*)&fNewLinkEditStart
[offset
];
1734 for (int i
=0; i
< fDynamicSymbolTable
->nindirectsyms(); ++i
) {
1735 uint32_t oldSymbolIndex
= E::get32(indirectTable
[i
]);
1736 uint32_t newSymbolIndex
= oldSymbolIndex
;
1737 if ( (oldSymbolIndex
!= INDIRECT_SYMBOL_ABS
) && (oldSymbolIndex
!= INDIRECT_SYMBOL_LOCAL
) ) {
1738 newSymbolIndex
= fOldToNewSymbolIndexes
[oldSymbolIndex
];
1739 //fprintf(stderr, "copyIndirectSymbolTable() old=%d, new=%u name=%s in %s\n", oldSymbolIndex, newSymbolIndex,
1740 // &fStrings[fSymbolTable[oldSymbolIndex].n_strx()], fLayout.getFilePath());
1742 E::set32(newIndirectTable
[i
], newSymbolIndex
);
1744 offset
+= (fDynamicSymbolTable
->nindirectsyms() * 4);
1747 template <typename A
>
1748 void LinkEditOptimizer
<A
>::updateLoadCommands(uint64_t newVMAddress
, uint64_t size
, uint32_t stringPoolOffset
,
1749 uint32_t linkEditsFileOffset
, bool keepSignatures
)
1751 // set LINKEDIT segment commmand to new merged LINKEDIT
1752 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
1753 const uint32_t cmd_count
= fHeader
->ncmds();
1754 const macho_load_command
<P
>* cmd
= cmds
;
1755 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1756 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
1757 macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
1758 if ( strcmp(seg
->segname(), "__LINKEDIT") == 0 ) {
1759 seg
->set_vmaddr(newVMAddress
);
1760 seg
->set_vmsize(size
);
1761 seg
->set_filesize(size
);
1762 seg
->set_fileoff(linkEditsFileOffset
);
1764 // don't alter __TEXT until <rdar://problem/7022345> is fixed
1765 else if ( strcmp(seg
->segname(), "__TEXT") != 0 ) {
1766 // update all other segments fileoff to be offset from start of cache file
1767 pint_t oldFileOff
= seg
->fileoff();
1768 seg
->set_fileoff(fSharedCache
.cacheFileOffsetForVMAddress(seg
->vmaddr()));
1769 pint_t fileOffsetDelta
= seg
->fileoff() - oldFileOff
;
1770 // update all sections in this segment
1771 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)seg
+ sizeof(macho_segment_command
<P
>));
1772 macho_section
<P
>* const sectionsEnd
= §ionsStart
[seg
->nsects()];
1773 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1774 if ( sect
->offset() != 0 )
1775 sect
->set_offset(sect
->offset()+fileOffsetDelta
);
1779 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1782 // update dyld_info with new offsets
1783 if ( fDyldInfo
!= NULL
) {
1784 fDyldInfo
->set_rebase_off(0);
1785 fDyldInfo
->set_rebase_size(0);
1786 fDyldInfo
->set_bind_off(linkEditsFileOffset
+fBindInfoOffsetIntoNewLinkEdit
);
1787 fDyldInfo
->set_bind_size(fBindInfoSizeInNewLinkEdit
);
1788 fDyldInfo
->set_weak_bind_off(linkEditsFileOffset
+fWeakBindInfoOffsetIntoNewLinkEdit
);
1789 fDyldInfo
->set_weak_bind_size(fWeakBindInfoSizeInNewLinkEdit
);
1790 fDyldInfo
->set_lazy_bind_off(linkEditsFileOffset
+fLazyBindInfoOffsetIntoNewLinkEdit
);
1791 fDyldInfo
->set_lazy_bind_size(fLazyBindInfoSizeInNewLinkEdit
);
1792 fDyldInfo
->set_export_off(linkEditsFileOffset
+fExportInfoOffsetIntoNewLinkEdit
);
1793 fDyldInfo
->set_export_size(fExportInfoSizeInNewLinkEdit
);
1795 // fprintf(stderr, "dylib %s\n", fLayout.getFilePath());
1796 // fprintf(stderr, " bind_off=0x%08X\n", fDyldInfo->bind_off());
1797 // fprintf(stderr, " export_off=0x%08X\n", fDyldInfo->export_off());
1798 // fprintf(stderr, " export_size=%d\n", fDyldInfo->export_size());
1802 // update symbol table and dynamic symbol table with new offsets
1803 fSymbolTableLoadCommand
->set_symoff(linkEditsFileOffset
+fSymbolTableStartOffsetInNewLinkEdit
);
1804 fSymbolTableLoadCommand
->set_nsyms(fLocalSymbolsCountInNewLinkEdit
+fExportedSymbolsCountInNewLinkEdit
+fImportedSymbolsCountInNewLinkEdit
);
1805 fSymbolTableLoadCommand
->set_stroff(linkEditsFileOffset
+stringPoolOffset
);
1806 fSymbolTableLoadCommand
->set_strsize(fNewStringPool
.size());
1807 fDynamicSymbolTable
->set_ilocalsym(0);
1808 fDynamicSymbolTable
->set_nlocalsym(fLocalSymbolsCountInNewLinkEdit
);
1809 fDynamicSymbolTable
->set_iextdefsym(fExportedSymbolsStartIndexInNewLinkEdit
-fLocalSymbolsStartIndexInNewLinkEdit
);
1810 fDynamicSymbolTable
->set_nextdefsym(fExportedSymbolsCountInNewLinkEdit
);
1811 fDynamicSymbolTable
->set_iundefsym(fImportSymbolsStartIndexInNewLinkEdit
-fLocalSymbolsStartIndexInNewLinkEdit
);
1812 fDynamicSymbolTable
->set_nundefsym(fImportedSymbolsCountInNewLinkEdit
);
1813 fDynamicSymbolTable
->set_tocoff(0);
1814 fDynamicSymbolTable
->set_ntoc(0);
1815 fDynamicSymbolTable
->set_modtaboff(0);
1816 fDynamicSymbolTable
->set_nmodtab(0);
1817 fDynamicSymbolTable
->set_indirectsymoff(linkEditsFileOffset
+fIndirectSymbolTableOffsetInfoNewLinkEdit
);
1818 fDynamicSymbolTable
->set_extreloff(linkEditsFileOffset
+fExternalRelocationsOffsetIntoNewLinkEdit
);
1819 fDynamicSymbolTable
->set_locreloff(0);
1820 fDynamicSymbolTable
->set_nlocrel(0);
1822 // update function starts
1823 if ( fFunctionStarts
!= NULL
) {
1824 fFunctionStarts
->set_dataoff(linkEditsFileOffset
+fFunctionStartsOffsetInNewLinkEdit
);
1826 // update data-in-code info
1827 if ( fDataInCode
!= NULL
) {
1828 fDataInCode
->set_dataoff(linkEditsFileOffset
+fDataInCodeOffsetInNewLinkEdit
);
1831 // now remove load commands no longer needed
1832 const macho_load_command
<P
>* srcCmd
= cmds
;
1833 macho_load_command
<P
>* dstCmd
= (macho_load_command
<P
>*)cmds
;
1834 int32_t newCount
= 0;
1835 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1836 uint32_t cmdSize
= srcCmd
->cmdsize();
1837 switch ( srcCmd
->cmd() ) {
1838 case LC_SEGMENT_SPLIT_INFO
:
1839 case LC_DYLIB_CODE_SIGN_DRS
:
1842 case LC_CODE_SIGNATURE
:
1843 if ( !keepSignatures
)
1845 // otherwise fall into copy case
1847 memmove(dstCmd
, srcCmd
, cmdSize
);
1848 dstCmd
= (macho_load_command
<P
>*)(((uint8_t*)dstCmd
)+cmdSize
);
1852 srcCmd
= (const macho_load_command
<P
>*)(((uint8_t*)srcCmd
)+cmdSize
);
1854 // zero out stuff removed
1855 bzero(dstCmd
, (uint8_t*)srcCmd
- (uint8_t*)dstCmd
);
1857 // update mach_header
1858 macho_header
<P
>* writableHeader
= (macho_header
<P
>*)fHeader
;
1859 writableHeader
->set_ncmds(newCount
);
1860 writableHeader
->set_sizeofcmds((uint8_t*)dstCmd
- ((uint8_t*)fHeader
+ sizeof(macho_header
<P
>)));
1862 // this invalidates some ivars
1863 fDynamicSymbolTable
= NULL
;
1864 fSymbolTableLoadCommand
= NULL
;
1866 fSymbolTable
= NULL
;
1872 template <typename A
>
1873 uint8_t* SharedCache
<A
>::optimizeLINKEDIT(bool keepSignatures
)
1875 // allocate space for optimized LINKEDIT area
1876 uint8_t* newLinkEdit
= new uint8_t[fLinkEditsTotalUnoptimizedSize
];
1877 bzero(newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
1879 // make a string pool
1880 StringPool stringPool
;
1882 // create optimizer object for each LINKEDIT segment
1883 std::vector
<LinkEditOptimizer
<A
>*> optimizers
;
1884 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1885 optimizers
.push_back(new LinkEditOptimizer
<A
>(*it
->layout
, *this, newLinkEdit
, stringPool
));
1888 // rebase info is not copied because images in shared cache are never rebased
1890 // copy weak bind info
1891 uint32_t offset
= 0;
1892 fOffsetOfWeakBindInfoInCombinedLinkedit
= offset
;
1893 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1894 (*it
)->copyWeakBindInfo(offset
);
1898 fOffsetOfExportInfoInCombinedLinkedit
= offset
;
1899 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1900 (*it
)->copyExportInfo(offset
);
1904 fOffsetOfBindInfoInCombinedLinkedit
= offset
;
1905 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1906 (*it
)->copyBindInfo(offset
);
1909 // copy lazy bind info
1910 fOffsetOfLazyBindInfoInCombinedLinkedit
= offset
;
1911 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1912 (*it
)->copyLazyBindInfo(offset
);
1915 // copy symbol table entries
1916 fOffsetOfOldSymbolTableInfoInCombinedLinkedit
= offset
;
1917 uint32_t symbolTableOffset
= offset
;
1918 uint32_t symbolTableIndex
= 0;
1919 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1920 (*it
)->copyLocalSymbols(symbolTableOffset
, symbolTableIndex
);
1921 (*it
)->copyExportedSymbols(symbolTableOffset
, symbolTableIndex
);
1922 (*it
)->copyImportedSymbols(symbolTableOffset
, symbolTableIndex
);
1924 fSizeOfOldSymbolTableInfoInCombinedLinkedit
= symbolTableIndex
* sizeof(macho_nlist
<typename
A::P
>);
1925 offset
= symbolTableOffset
+ fSizeOfOldSymbolTableInfoInCombinedLinkedit
& (-8);
1927 // copy external relocations, 8-byte aligned after end of symbol table
1928 fOffsetOfOldExternalRelocationsInCombinedLinkedit
= offset
;
1929 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1930 (*it
)->copyExternalRelocations(offset
);
1932 fSizeOfOldExternalRelocationsInCombinedLinkedit
= offset
- fOffsetOfOldExternalRelocationsInCombinedLinkedit
;
1934 // copy function starts
1935 fOffsetOfFunctionStartsInCombinedLinkedit
= offset
;
1936 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1937 (*it
)->copyFunctionStarts(offset
);
1939 fSizeOfFunctionStartsInCombinedLinkedit
= offset
- fOffsetOfFunctionStartsInCombinedLinkedit
;
1941 // copy data-in-code info
1942 fOffsetOfDataInCodeInCombinedLinkedit
= offset
;
1943 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1944 (*it
)->copyDataInCode(offset
);
1946 fSizeOfDataInCodeInCombinedLinkedit
= offset
- fOffsetOfDataInCodeInCombinedLinkedit
;
1948 // copy indirect symbol tables
1949 fOffsetOfOldIndirectSymbolsInCombinedLinkedit
= offset
;
1950 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1951 (*it
)->copyIndirectSymbolTable(offset
);
1953 fSizeOfOldIndirectSymbolsInCombinedLinkedit
= offset
- fOffsetOfOldIndirectSymbolsInCombinedLinkedit
;
1956 fOffsetOfOldStringPoolInCombinedLinkedit
= offset
;
1957 memcpy(&newLinkEdit
[offset
], stringPool
.getBuffer(), stringPool
.size());
1958 fSizeOfOldStringPoolInCombinedLinkedit
= stringPool
.size();
1960 // total new size round up to page size
1961 fLinkEditsTotalOptimizedSize
= (fOffsetOfOldStringPoolInCombinedLinkedit
+ fSizeOfOldStringPoolInCombinedLinkedit
+ 4095) & (-4096);
1963 // choose new linkedit file offset
1964 uint32_t linkEditsFileOffset
= cacheFileOffsetForVMAddress(fLinkEditsStartAddress
);
1965 // uint32_t linkEditsFileOffset = fLinkEditsStartAddress - sharedRegionReadOnlyStartAddress();
1967 // update load commands so that all dylibs shared different areas of the same LINKEDIT segment
1968 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1969 (*it
)->updateLoadCommands(fLinkEditsStartAddress
, fLinkEditsTotalUnoptimizedSize
, fOffsetOfOldStringPoolInCombinedLinkedit
, linkEditsFileOffset
, keepSignatures
);
1972 //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, fLinkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, fLinkEditsTotalOptimizedSize);
1973 //printf(stderr, "mega link edit mapped starting at: %p\n", fFirstLinkEditSegment->mappedAddress());
1975 // overwrite mapped LINKEDIT area with new optimized LINKEDIT segment
1976 memcpy(fFirstLinkEditSegment
->mappedAddress(), newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
1978 // update all LINKEDIT Segment objects to point to same merged LINKEDIT area
1979 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1980 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1981 for(int i
=0; i
< segs
.size(); ++i
) {
1982 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1983 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
1984 seg
.setNewAddress(fLinkEditsStartAddress
);
1985 seg
.setMappedAddress(fFirstLinkEditSegment
->mappedAddress());
1986 seg
.setSize(fLinkEditsTotalOptimizedSize
);
1987 seg
.setFileSize(fLinkEditsTotalOptimizedSize
);
1988 seg
.setFileOffset(linkEditsFileOffset
);
1993 // return new end of cache
1994 return (uint8_t*)fFirstLinkEditSegment
->mappedAddress() + fLinkEditsTotalOptimizedSize
;
1998 template <typename A
>
1999 class ObjCSelectorUniquer
2002 objc_opt::string_map fSelectorStrings
;
2003 SharedCache
<A
> *fCache
;
2008 ObjCSelectorUniquer(SharedCache
<A
> *newCache
)
2009 : fSelectorStrings()
2014 typename
A::P::uint_t
visit(typename
A::P::uint_t oldValue
)
2017 const char *s
= (const char *)
2018 fCache
->mappedAddressForVMAddress(oldValue
);
2019 objc_opt::string_map::iterator element
=
2020 fSelectorStrings
.insert(objc_opt::string_map::value_type(s
, oldValue
)).first
;
2021 return (typename
A::P::uint_t
)element
->second
;
2024 objc_opt::string_map
& strings() {
2025 return fSelectorStrings
;
2028 size_t count() const { return fCount
; }
2032 template <typename A
>
2033 class ClassListBuilder
2036 typedef typename
A::P P
;
2038 objc_opt::string_map fClassNames
;
2039 objc_opt::class_map fClasses
;
2041 HeaderInfoOptimizer
<A
>& fHinfos
;
2045 ClassListBuilder(HeaderInfoOptimizer
<A
>& hinfos
)
2052 void visitClass(SharedCache
<A
>* cache
,
2053 const macho_header
<P
>* header
,
2054 objc_class_t
<A
>* cls
)
2056 if (cls
->isMetaClass(cache
)) return;
2058 const char *name
= cls
->getName(cache
);
2059 uint64_t name_vmaddr
= cache
->VMAddressForMappedAddress(name
);
2060 uint64_t cls_vmaddr
= cache
->VMAddressForMappedAddress(cls
);
2061 uint64_t hinfo_vmaddr
= cache
->VMAddressForMappedAddress(fHinfos
.hinfoForHeader(cache
, header
));
2062 fClassNames
.insert(objc_opt::string_map::value_type(name
, name_vmaddr
));
2063 fClasses
.insert(objc_opt::class_map::value_type(name
, std::pair
<uint64_t, uint64_t>(cls_vmaddr
, hinfo_vmaddr
)));
2067 objc_opt::string_map
& classNames() {
2071 objc_opt::class_map
& classes() {
2075 size_t count() const { return fCount
; }
2079 static int percent(size_t num
, size_t denom
) {
2080 if (denom
) return (int)(num
/ (double)denom
* 100);
2084 template <typename A
>
2085 void SharedCache
<A
>::optimizeObjC(std::vector
<void*>& pointersInData
)
2090 fprintf(stderr
, "update_dyld_shared_cache: for %s, optimizing objc metadata\n", archName());
2093 size_t headerSize
= P::round_up(sizeof(objc_opt::objc_opt_t
));
2094 if (headerSize
!= sizeof(objc_opt::objc_opt_t
)) {
2095 warn(archName(), "libobjc's optimization structure size is wrong (metadata not optimized)");
2098 // Find libobjc's empty sections to fill in
2099 const macho_section
<P
> *optROSection
= NULL
;
2100 const macho_section
<P
> *optRWSection
= NULL
;
2101 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2102 if ( strstr(it
->layout
->getFilePath(), "libobjc") != NULL
) {
2103 const macho_header
<P
>* mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2104 optROSection
= mh
->getSection("__TEXT", "__objc_opt_ro");
2105 optRWSection
= mh
->getSection("__DATA", "__objc_opt_rw");
2110 if ( optROSection
== NULL
) {
2111 warn(archName(), "libobjc's read-only section missing (metadata not optimized)");
2115 if ( optRWSection
== NULL
) {
2116 warn(archName(), "libobjc's read/write section missing (metadata not optimized)");
2120 uint8_t* optROData
= (uint8_t*)mappedAddressForVMAddress(optROSection
->addr());
2121 size_t optRORemaining
= optROSection
->size();
2123 uint8_t* optRWData
= (uint8_t*)mappedAddressForVMAddress(optRWSection
->addr());
2124 size_t optRWRemaining
= optRWSection
->size();
2126 if (optRORemaining
< headerSize
) {
2127 warn(archName(), "libobjc's read-only section is too small (metadata not optimized)");
2130 objc_opt::objc_opt_t
* optROHeader
= (objc_opt::objc_opt_t
*)optROData
;
2131 optROData
+= headerSize
;
2132 optRORemaining
-= headerSize
;
2134 if (E::get32(optROHeader
->version
) != objc_opt::VERSION
) {
2135 warn(archName(), "libobjc's read-only section version is unrecognized (metadata not optimized)");
2139 // Write nothing to optROHeader until everything else is written.
2140 // If something fails below, libobjc will not use the section.
2142 // Find objc-containing dylibs
2143 std::vector
<LayoutInfo
> objcDylibs
;
2144 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2145 macho_header
<P
> *mh
= (macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2146 if (mh
->getSection("__DATA", "__objc_imageinfo") || mh
->getSegment("__OBJC")) {
2147 objcDylibs
.push_back(*it
);
2153 // This is SAFE: the binaries themselves are unmodified.
2155 std::vector
<LayoutInfo
> addressSortedDylibs
= objcDylibs
;
2156 std::sort(addressSortedDylibs
.begin(), addressSortedDylibs
.end(), ByAddressSorter());
2158 uint64_t hinfoVMAddr
= optRWSection
->addr() + optRWSection
->size() - optRWRemaining
;
2159 HeaderInfoOptimizer
<A
> hinfoOptimizer
;
2160 err
= hinfoOptimizer
.init(objcDylibs
.size(), optRWData
, optRWRemaining
);
2162 warn(archName(), err
);
2165 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= addressSortedDylibs
.begin(); it
!= addressSortedDylibs
.end(); ++it
) {
2166 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2167 hinfoOptimizer
.update(this, mh
, pointersInData
);
2171 // Update selector references and build selector list
2173 // This is SAFE: if we run out of room for the selector table,
2174 // the modified binaries are still usable.
2176 // Heuristic: choose selectors from libraries with more cstring data first.
2177 // This tries to localize selector cstring memory.
2178 ObjCSelectorUniquer
<A
> uniq(this);
2179 std::vector
<LayoutInfo
> sizeSortedDylibs
= objcDylibs
;
2180 std::sort(sizeSortedDylibs
.begin(), sizeSortedDylibs
.end(), ByCStringSectionSizeSorter());
2182 SelectorOptimizer
<A
, ObjCSelectorUniquer
<A
> > selOptimizer(uniq
);
2183 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2184 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2185 LegacySelectorUpdater
<A
, ObjCSelectorUniquer
<A
> >::update(this, mh
, uniq
);
2186 selOptimizer
.optimize(this, mh
);
2189 uint64_t seloptVMAddr
= optROSection
->addr() + optROSection
->size() - optRORemaining
;
2190 objc_opt::objc_selopt_t
*selopt
= new(optROData
) objc_opt::objc_selopt_t
;
2191 err
= selopt
->write(seloptVMAddr
, optRORemaining
, uniq
.strings());
2193 warn(archName(), err
);
2196 optROData
+= selopt
->size();
2197 optRORemaining
-= selopt
->size();
2198 selopt
->byteswap(E::little_endian
), selopt
= NULL
;
2201 // Build class table.
2203 // This is SAFE: the binaries themselves are unmodified.
2205 ClassListBuilder
<A
> classes(hinfoOptimizer
);
2206 ClassWalker
< A
, ClassListBuilder
<A
> > classWalker(classes
);
2207 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2208 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2209 classWalker
.walk(this, mh
);
2212 uint64_t clsoptVMAddr
= optROSection
->addr() + optROSection
->size() - optRORemaining
;
2213 objc_opt::objc_clsopt_t
*clsopt
= new(optROData
) objc_opt::objc_clsopt_t
;
2214 err
= clsopt
->write(clsoptVMAddr
, optRORemaining
,
2215 classes
.classNames(), classes
.classes(), verbose
);
2217 warn(archName(), err
);
2220 optROData
+= clsopt
->size();
2221 optRORemaining
-= clsopt
->size();
2222 size_t duplicateCount
= clsopt
->duplicateCount();
2223 clsopt
->byteswap(E::little_endian
), clsopt
= NULL
;
2226 // Sort method lists.
2228 // This is SAFE: modified binaries are still usable as unsorted lists.
2229 // This must be done AFTER uniquing selectors.
2231 MethodListSorter
<A
> methodSorter
;
2232 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2233 macho_header
<P
> *mh
= (macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2234 methodSorter
.optimize(this, mh
);
2238 // Repair ivar offsets.
2240 // This is SAFE: the runtime always validates ivar offsets at runtime.
2242 IvarOffsetOptimizer
<A
> ivarOffsetOptimizer
;
2243 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2244 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2245 ivarOffsetOptimizer
.optimize(this, mh
);
2249 // Success. Mark dylibs as optimized.
2250 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sizeSortedDylibs
.begin(); it
!= sizeSortedDylibs
.end(); ++it
) {
2251 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
2252 const macho_section
<P
> *imageInfoSection
;
2253 imageInfoSection
= mh
->getSection("__DATA", "__objc_imageinfo");
2254 if (!imageInfoSection
) {
2255 imageInfoSection
= mh
->getSection("__OBJC", "__image_info");
2257 if (imageInfoSection
) {
2258 objc_image_info
<A
> *info
= (objc_image_info
<A
> *)
2259 mappedAddressForVMAddress(imageInfoSection
->addr());
2260 info
->setOptimizedByDyld();
2265 // Success. Update RO header last.
2266 E::set32(optROHeader
->selopt_offset
, seloptVMAddr
- optROSection
->addr());
2267 E::set32(optROHeader
->clsopt_offset
, clsoptVMAddr
- optROSection
->addr());
2268 E::set32(optROHeader
->headeropt_offset
, hinfoVMAddr
- optROSection
->addr());
2271 size_t roSize
= optROSection
->size() - optRORemaining
;
2272 size_t rwSize
= optRWSection
->size() - optRWRemaining
;
2273 fprintf(stderr
, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
2274 "(%d%%) used in libobjc read-only optimization section\n",
2275 archName(), roSize
, optROSection
->size(),
2276 percent(roSize
, optROSection
->size()));
2277 fprintf(stderr
, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
2278 "(%d%%) used in libobjc read/write optimization section\n",
2279 archName(), rwSize
, optRWSection
->size(),
2280 percent(rwSize
, optRWSection
->size()));
2281 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2282 "uniqued %zu selectors\n",
2283 archName(), uniq
.strings().size());
2284 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2285 "updated %zu selector references\n",
2286 archName(), uniq
.count());
2287 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2288 "updated %zu ivar offsets\n",
2289 archName(), ivarOffsetOptimizer
.optimized());
2290 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2291 "sorted %zu method lists\n",
2292 archName(), methodSorter
.optimized());
2293 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2294 "recorded %zu classes (%zu duplicates)\n",
2295 archName(), classes
.classNames().size(), duplicateCount
);
2296 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
2297 "wrote objc metadata optimization version %d\n",
2298 archName(), objc_opt::VERSION
);
2305 static const char* sCleanupFile
= NULL
;
2306 static void cleanup(int sig
)
2308 ::signal(sig
, SIG_DFL
);
2309 if ( sCleanupFile
!= NULL
)
2310 ::unlink(sCleanupFile
);
2312 // fprintf(stderr, "update_dyld_shared_cache: deleting temp file in response to a signal\n");
2313 if ( sig
== SIGINT
)
2319 template <> bool SharedCache
<x86_64
>::addCacheSlideInfo(){ return true; }
2320 template <> bool SharedCache
<arm
>::addCacheSlideInfo() { return true; }
2321 template <> bool SharedCache
<x86
>::addCacheSlideInfo() { return false; }
2325 template <typename A
>
2326 bool SharedCache
<A
>::update(bool force
, bool optimize
, bool deleteExistingFirst
, int archIndex
,
2327 int archCount
, bool keepSignatures
)
2329 bool didUpdate
= false;
2331 // already up to date?
2332 if ( force
|| fExistingIsNotUpToDate
) {
2334 fprintf(stderr
, "update_dyld_shared_cache: regenerating %s\n", fCacheFilePath
);
2335 if ( fDylibs
.size() == 0 ) {
2336 fprintf(stderr
, "update_dyld_shared_cache: warning, empty cache not generated for arch %s\n", archName());
2339 // delete existing cache while building the new one
2340 // this is a flag to dyld to stop pinging update_dyld_shared_cache
2341 if ( deleteExistingFirst
)
2342 ::unlink(fCacheFilePath
);
2343 uint8_t* inMemoryCache
= NULL
;
2344 uint32_t allocatedCacheSize
= 0;
2345 char tempCachePath
[strlen(fCacheFilePath
)+16];
2346 sprintf(tempCachePath
, "%s.tmp%u", fCacheFilePath
, getpid());
2348 // allocate a memory block to hold cache
2349 uint32_t cacheFileSize
= 0;
2350 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
2351 uint32_t end
= it
->sfm_file_offset
+ it
->sfm_size
;
2352 if ( end
> cacheFileSize
)
2353 cacheFileSize
= end
;
2355 if ( vm_allocate(mach_task_self(), (vm_address_t
*)(&inMemoryCache
), cacheFileSize
, VM_FLAGS_ANYWHERE
) != KERN_SUCCESS
)
2356 throwf("can't vm_allocate cache of size %u", cacheFileSize
);
2357 allocatedCacheSize
= cacheFileSize
;
2358 fInMemoryCache
= inMemoryCache
;
2361 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2362 const char* archPairName
= fArchGraph
->archName();
2364 strcpy(temp
, "dyld_v1 ");
2365 strcpy(&temp
[15-strlen(archPairName
)], archPairName
);
2366 header
->set_magic(temp
);
2367 //header->set_architecture(arch());
2368 header
->set_mappingOffset(sizeof(dyldCacheHeader
<E
>));
2369 header
->set_mappingCount(fMappings
.size());
2370 header
->set_imagesOffset(header
->mappingOffset() + fMappings
.size()*sizeof(dyldCacheFileMapping
<E
>));
2371 header
->set_imagesCount(fDylibs
.size()+fDylibAliases
.size());
2372 header
->set_dyldBaseAddress(fDyldBaseAddress
);
2373 header
->set_codeSignatureOffset(cacheFileSize
);
2374 header
->set_codeSignatureSize(0);
2375 header
->set_slideInfoOffset(0);
2376 header
->set_slideInfoSize(0);
2379 dyldCacheFileMapping
<E
>* mapping
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
2380 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
2382 fprintf(stderr
, "update_dyld_shared_cache: cache mappings: address=0x%0llX, size=0x%0llX, fileOffset=0x%0llX, prot=0x%X\n",
2383 it
->sfm_address
, it
->sfm_size
, it
->sfm_file_offset
, it
->sfm_init_prot
);
2384 mapping
->set_address(it
->sfm_address
);
2385 mapping
->set_size(it
->sfm_size
);
2386 mapping
->set_file_offset(it
->sfm_file_offset
);
2387 mapping
->set_max_prot(it
->sfm_max_prot
);
2388 mapping
->set_init_prot(it
->sfm_init_prot
);
2392 // fill in image table
2393 dyldCacheImageInfo
<E
>* image
= (dyldCacheImageInfo
<E
>*)mapping
;
2394 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2395 image
->set_address(it
->info
.address
);
2396 image
->set_modTime(it
->info
.modTime
);
2397 image
->set_inode(it
->info
.inode
);
2398 image
->set_pathFileOffset(cacheFileOffsetForVMAddress(it
->info
.address
+it
->info
.pathFileOffset
));
2402 // add aliases to end of image table
2403 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibAliases
.begin(); it
!= fDylibAliases
.end(); ++it
) {
2404 image
->set_address(it
->info
.address
);
2405 image
->set_modTime(it
->info
.modTime
);
2406 image
->set_inode(it
->info
.inode
);
2407 image
->set_pathFileOffset(it
->info
.pathFileOffset
);
2408 strcpy((char*)inMemoryCache
+it
->info
.pathFileOffset
, it
->aliases
[0]);
2409 //fprintf(stderr, "adding alias to offset 0x%08X %s\n", it->info.pathFileOffset, it->aliases[0]);
2413 // copy each segment to cache buffer
2414 const int dylibCount
= fDylibs
.size();
2416 int progressIndex
= 0;
2417 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++dylibIndex
) {
2418 const char* path
= it
->layout
->getFilePath();
2419 int src
= ::open(path
, O_RDONLY
, 0);
2421 throwf("can't open file %s, errnor=%d", it
->layout
->getID().name
, errno
);
2422 // mark source as "don't cache"
2423 (void)fcntl(src
, F_NOCACHE
, 1);
2424 // verify file has not changed since dependency analysis
2425 struct stat stat_buf
;
2426 if ( fstat(src
, &stat_buf
) == -1)
2427 throwf("can't stat open file %s, errno=%d", path
, errno
);
2428 if ( (it
->layout
->getInode() != stat_buf
.st_ino
) || (it
->layout
->getLastModTime() != stat_buf
.st_mtime
) )
2429 throwf("file modified during cache creation: %s", path
);
2432 fprintf(stderr
, "update_dyld_shared_cache: copying %s to cache\n", it
->layout
->getFilePath());
2434 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
2435 for (int i
=0; i
< segs
.size(); ++i
) {
2436 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
2438 fprintf(stderr
, "\t\tsegment %s, size=0x%0llX, cache address=0x%0llX\n", seg
.name(), seg
.fileSize(), seg
.newAddress());
2439 if ( seg
.size() > 0 ) {
2440 const uint64_t segmentSrcStartOffset
= it
->layout
->getOffsetInUniversalFile()+seg
.fileOffset();
2441 const uint64_t segmentSize
= seg
.fileSize();
2442 const uint64_t segmentDstStartOffset
= cacheFileOffsetForVMAddress(seg
.newAddress());
2443 ssize_t readResult
= ::pread(src
, &inMemoryCache
[segmentDstStartOffset
], segmentSize
, segmentSrcStartOffset
);
2444 if ( readResult
!= segmentSize
) {
2445 if ( readResult
== -1 )
2446 throwf("read failure copying dylib errno=%d for %s", errno
, it
->layout
->getID().name
);
2448 throwf("read failure copying dylib. Read of %lld bytes at file offset %lld returned %ld for %s",
2449 segmentSize
, segmentSrcStartOffset
, readResult
, it
->layout
->getID().name
);
2454 catch (const char* msg
) {
2455 throwf("%s while copying %s to shared cache", msg
, it
->layout
->getID().name
);
2459 // assuming read takes 40% of time
2460 int nextProgressIndex
= archIndex
*100+(40*dylibIndex
)/dylibCount
;
2461 if ( nextProgressIndex
!= progressIndex
)
2462 fprintf(stdout
, "%3u/%u\n", nextProgressIndex
, archCount
*100);
2463 progressIndex
= nextProgressIndex
;
2467 // set mapped address for each segment
2468 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2469 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
2470 for (int i
=0; i
< segs
.size(); ++i
) {
2471 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
2472 if ( seg
.size() > 0 )
2473 seg
.setMappedAddress(inMemoryCache
+ cacheFileOffsetForVMAddress(seg
.newAddress()));
2474 //fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
2478 // also construct list of all pointers in cache to other things in cache
2479 std::vector
<void*> pointersInData
;
2480 pointersInData
.reserve(1024);
2482 // add pointer in start of __DATA to start of __TEXT to remain compatible with previous dylds
2483 pint_t
* dataStartPtr
= (pint_t
*)(&inMemoryCache
[fMappings
[1].sfm_file_offset
]);
2484 P::setP(*dataStartPtr
, fMappings
[0].sfm_address
);
2486 // rebase each dylib in shared cache
2487 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2489 Rebaser
<A
> r(*it
->layout
);
2490 r
.rebase(pointersInData
);
2492 // fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
2494 catch (const char* msg
) {
2495 throwf("%s in %s", msg
, it
->layout
->getID().name
);
2500 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs
.size());
2501 // instantiate a Binder for each image and add to map
2502 typename Binder
<A
>::Map map
;
2503 std::vector
<Binder
<A
>*> binders
;
2504 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2505 //fprintf(stderr, "binding %s\n", it->layout->getID().name);
2506 Binder
<A
>* binder
= new Binder
<A
>(*it
->layout
, fDyldBaseAddress
);
2507 binders
.push_back(binder
);
2508 // only add dylibs to map
2509 if ( it
->layout
->getID().name
!= NULL
)
2510 map
[it
->layout
->getID().name
] = binder
;
2513 // tell each Binder about the others
2514 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2515 (*it
)->setDependentBinders(map
);
2518 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2520 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it
)->getDylibID());
2522 (*it
)->bind(pointersInData
);
2524 catch (const char* msg
) {
2525 throwf("%s in %s", msg
, (*it
)->getDylibID());
2529 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2533 catch (const char* msg
) {
2534 throwf("%s in %s", msg
, (*it
)->getDylibID());
2538 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
2542 // merge/optimize all LINKEDIT segments
2544 //fprintf(stderr, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize/(1024*1024));
2545 cacheFileSize
= (this->optimizeLINKEDIT(keepSignatures
) - inMemoryCache
);
2546 //fprintf(stderr, "update_dyld_shared_cache: optimized cache file size %uMB\n", cacheFileSize/(1024*1024));
2547 // update header to reduce mapping size
2548 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2549 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
2550 dyldCacheFileMapping
<E
>* lastMapping
= &mappings
[cacheHeader
->mappingCount()-1];
2551 lastMapping
->set_size(cacheFileSize
-lastMapping
->file_offset());
2552 // update fMappings so .map file will print correctly
2553 fMappings
.back().sfm_size
= cacheFileSize
-fMappings
.back().sfm_file_offset
;
2555 //fprintf(stderr, "update_dyld_shared_cache: changing end of cache address from 0x%08llX to 0x%08llX\n",
2556 // header->codeSignatureOffset(), fMappings.back().sfm_address + fMappings.back().sfm_size);
2557 header
->set_codeSignatureOffset(fMappings
.back().sfm_file_offset
+ fMappings
.back().sfm_size
);
2560 // unique objc selectors and update other objc metadata
2562 optimizeObjC(pointersInData
);
2564 // assuming objc optimizations takes 15% of time
2565 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*55, archCount
*100);
2569 if ( addCacheSlideInfo() ) {
2570 // build bitmap of which pointers need sliding
2571 uint8_t* const dataStart
= &inMemoryCache
[fMappings
[1].sfm_file_offset
]; // R/W mapping is always second
2572 uint8_t* const dataEnd
= &inMemoryCache
[fMappings
[1].sfm_file_offset
+fMappings
[1].sfm_size
];
2573 const int bitmapSize
= (dataEnd
- dataStart
)/(4*8);
2574 uint8_t* bitmap
= (uint8_t*)calloc(bitmapSize
, 1);
2575 void* lastPointer
= inMemoryCache
;
2576 for(std::vector
<void*>::iterator pit
=pointersInData
.begin(); pit
!= pointersInData
.end(); ++pit
) {
2577 if ( *pit
!= lastPointer
) {
2579 if ( (p
< dataStart
) || ( p
> dataEnd
) )
2580 throwf("DATA pointer for sliding, out of range 0x%08lX\n", (long)((uint8_t*)p
-inMemoryCache
));
2581 long offset
= (long)((uint8_t*)p
- dataStart
);
2582 if ( (offset
% 4) != 0 )
2583 throwf("pointer not 4-byte aligned in DATA offset 0x%08lX\n", offset
);
2584 long byteIndex
= offset
/ (4*8);
2585 long bitInByte
= (offset
% 32) >> 2;
2586 bitmap
[byteIndex
] |= (1 << bitInByte
);
2591 // allocate worst case size block of all slide info
2592 const int entry_size
= 4096/(8*4); // 8 bits per byte, possible pointer every 4 bytes.
2593 const int toc_count
= bitmapSize
/entry_size
;
2594 int slideInfoSize
= sizeof(dyldCacheSlideInfo
<E
>) + 2*toc_count
+ entry_size
*(toc_count
+1);
2595 dyldCacheSlideInfo
<E
>* slideInfo
= (dyldCacheSlideInfo
<E
>*)calloc(slideInfoSize
, 1);
2596 slideInfo
->set_version(1);
2597 slideInfo
->set_toc_offset(sizeof(dyldCacheSlideInfo
<E
>));
2598 slideInfo
->set_toc_count(toc_count
);
2599 slideInfo
->set_entries_offset((slideInfo
->toc_offset()+2*toc_count
+127)&(-128));
2600 slideInfo
->set_entries_count(0);
2601 slideInfo
->set_entries_size(entry_size
);
2602 // append each unique entry
2603 const dyldCacheSlideInfoEntry
* bitmapAsEntries
= (dyldCacheSlideInfoEntry
*)bitmap
;
2604 dyldCacheSlideInfoEntry
* const entriesInSlidInfo
= (dyldCacheSlideInfoEntry
*)((char*)slideInfo
+slideInfo
->entries_offset());
2605 int entry_count
= 0;
2606 for (int i
=0; i
< toc_count
; ++i
) {
2607 const dyldCacheSlideInfoEntry
* thisEntry
= &bitmapAsEntries
[i
];
2608 // see if it is same as one already added
2610 for (int j
=0; j
< entry_count
; ++j
) {
2611 if ( memcmp(thisEntry
, &entriesInSlidInfo
[j
], entry_size
) == 0 ) {
2612 //fprintf(stderr, "toc[%d] optimized to %d\n", i, j);
2613 slideInfo
->set_toc(i
, j
);
2620 memcpy(&entriesInSlidInfo
[entry_count
], thisEntry
, entry_size
);
2621 slideInfo
->set_toc(i
, entry_count
++);
2624 slideInfo
->set_entries_count(entry_count
);
2626 int slideInfoPageSize
= (slideInfo
->entries_offset() + entry_count
*entry_size
+ 4095) & (-4096);
2627 cacheFileSize
+= slideInfoPageSize
;
2629 // update mappings to increase RO size
2630 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2631 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
2632 dyldCacheFileMapping
<E
>* lastMapping
= &mappings
[cacheHeader
->mappingCount()-1];
2633 lastMapping
->set_size(lastMapping
->size()+slideInfoPageSize
);
2635 // update header to show location of slidePointers
2636 cacheHeader
->set_slideInfoOffset(cacheHeader
->codeSignatureOffset());
2637 cacheHeader
->set_slideInfoSize(slideInfoPageSize
);
2638 cacheHeader
->set_codeSignatureOffset(cacheHeader
->codeSignatureOffset()+slideInfoPageSize
);
2640 // update fMappings so .map file will print correctly
2641 fMappings
.back().sfm_size
= cacheFileSize
-fMappings
.back().sfm_file_offset
;
2643 // copy compressed into into buffer
2644 memcpy(&inMemoryCache
[cacheHeader
->slideInfoOffset()], slideInfo
, slideInfoPageSize
);
2649 // if no existing cache, say so
2650 if ( fExistingCacheForVerification
== NULL
) {
2651 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
2652 getpid(), archName());
2654 // new cache is built, compare header entries
2655 const dyldCacheHeader
<E
>* newHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
2656 const dyldCacheHeader
<E
>* oldHeader
= (dyldCacheHeader
<E
>*)fExistingCacheForVerification
;
2657 if ( newHeader
->mappingCount() != oldHeader
->mappingCount() ) {
2658 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because caches have a different number of mappings\n",
2659 getpid(), archName());
2661 const dyldCacheFileMapping
<E
>* newMappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[newHeader
->mappingOffset()];
2662 const dyldCacheFileMapping
<E
>* oldMappings
= (dyldCacheFileMapping
<E
>*)&fExistingCacheForVerification
[oldHeader
->mappingOffset()];
2663 for (int i
=0; i
< newHeader
->mappingCount(); ++i
) {
2664 if ( newMappings
[i
].address() != oldMappings
[i
].address() ) {
2665 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",
2666 getpid(), archName(), i
, newMappings
[i
].address(), oldMappings
[i
].address() );
2668 if ( newMappings
[i
].size() != oldMappings
[i
].size() ) {
2669 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because mapping %d has a different size\n",
2670 getpid(), archName(), i
);
2674 //fprintf(stderr, "%s existing cache = %p\n", archName(), fExistingCacheForVerification);
2675 //fprintf(stderr, "%s new cache = %p\n", archName(), inMemoryCache);
2676 // compare content to existing cache page by page
2677 for (int offset
=0; offset
< cacheFileSize
; offset
+= 4096) {
2678 if ( memcmp(&inMemoryCache
[offset
], &fExistingCacheForVerification
[offset
], 4096) != 0 ) {
2679 fprintf(stderr
, "verifier found differences on page offset 0x%08X for %s:\n", offset
, archName());
2680 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++dylibIndex
) {
2681 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
2682 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator sit
= segs
.begin(); sit
!= segs
.end(); ++sit
) {
2683 const MachOLayoutAbstraction::Segment
& seg
= *sit
;
2684 if ( (seg
.mappedAddress() <= &inMemoryCache
[offset
]) && (&inMemoryCache
[offset
] < ((uint8_t*)seg
.mappedAddress() + seg
.fileSize())) ) {
2685 // all LINKEDITs point to the same region, so just print one
2686 if ( strcmp(seg
.name(), "__LINKEDIT") == 0 )
2687 fprintf(stderr
, " in merged LINKEDIT segment\n");
2689 fprintf(stderr
, " in segment %s of dylib %s\n", seg
.name(), it
->layout
->getID().name
);
2694 for (int po
=0; po
< 4096; po
+= 16) {
2695 if ( memcmp(&inMemoryCache
[offset
+po
], &fExistingCacheForVerification
[offset
+po
], 16) != 0 ) {
2696 fprintf(stderr
, " existing: 0x%08X: ", offset
+po
);
2697 for ( int j
=0; j
< 16; ++j
)
2698 fprintf(stderr
, " 0x%02X", fExistingCacheForVerification
[offset
+po
+j
]);
2699 fprintf(stderr
, "\n");
2700 fprintf(stderr
, " should be: 0x%08X: ", offset
+po
);
2701 for ( int j
=0; j
< 16; ++j
)
2702 fprintf(stderr
, " 0x%02X", inMemoryCache
[offset
+po
+j
]);
2703 fprintf(stderr
, "\n");
2710 // install signal handlers to delete temp file if program is killed
2711 sCleanupFile
= tempCachePath
;
2712 ::signal(SIGINT
, cleanup
);
2713 ::signal(SIGBUS
, cleanup
);
2714 ::signal(SIGSEGV
, cleanup
);
2716 // create var/db/dyld dirs if needed
2717 char dyldDirs
[1024];
2718 strcpy(dyldDirs
, fCacheFilePath
);
2719 char* lastSlash
= strrchr(dyldDirs
, '/');
2720 if ( lastSlash
!= NULL
)
2721 lastSlash
[1] = '\0';
2722 struct stat stat_buf
;
2723 if ( stat(dyldDirs
, &stat_buf
) != 0 ) {
2724 const char* afterSlash
= &dyldDirs
[1];
2726 while ( (slash
= strchr(afterSlash
, '/')) != NULL
) {
2728 ::mkdir(dyldDirs
, S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
);
2730 afterSlash
= slash
+1;
2734 // create temp file for cache
2735 int fd
= ::open(tempCachePath
, O_CREAT
| O_RDWR
| O_TRUNC
, 0644);
2737 throwf("can't create temp file %s, errnor=%d", tempCachePath
, errno
);
2739 // try to allocate whole cache file contiguously
2740 fstore_t fcntlSpec
= { F_ALLOCATECONTIG
|F_ALLOCATEALL
, F_PEOFPOSMODE
, 0, cacheFileSize
, 0 };
2741 ::fcntl(fd
, F_PREALLOCATE
, &fcntlSpec
);
2743 // write out cache file
2745 fprintf(stderr
, "update_dyld_shared_cache: writing cache to disk: %s\n", tempCachePath
);
2746 if ( ::pwrite(fd
, inMemoryCache
, cacheFileSize
, 0) != cacheFileSize
)
2747 throwf("write() failure creating cache file, errno=%d", errno
);
2749 // assuming write takes 35% of time
2750 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*90, archCount
*100);
2753 // flush to disk and close
2754 int result
= ::fcntl(fd
, F_FULLFSYNC
, NULL
);
2756 fprintf(stderr
, "update_dyld_shared_cache: warning, fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno
, tempCachePath
);
2757 result
= ::close(fd
);
2759 fprintf(stderr
, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno
, tempCachePath
);
2761 // <rdar://problem/7901042> Make life easier for the kernel at shutdown.
2762 // If we just move the new cache file over the old, the old file
2763 // may need to exist in the open-unlink state. But because it
2764 // may be mapped into the shared region, it cannot be deleted
2765 // until all user processes are terminated. That leaves are
2766 // small to non-existent window for the kernel to delete the
2768 if ( fCacheFileInFinalLocation
) {
2769 char tmpDirPath
[64];
2770 const char* pathLastSlash
= strrchr(fCacheFilePath
, '/');
2771 if ( pathLastSlash
!= NULL
) {
2772 sprintf(tmpDirPath
, "/var/run%s.old.%u", pathLastSlash
, getpid());
2773 // move existing cache file to /var/run to be clean up next boot
2774 result
= ::rename(fCacheFilePath
, tmpDirPath
);
2775 if ( result
!= 0 ) {
2776 if ( errno
!= ENOENT
)
2777 fprintf(stderr
, "update_dyld_shared_cache: warning, unable to move existing cache to %s errno=%d for %s\n", tmpDirPath
, errno
, fCacheFilePath
);
2782 // move new cache file to correct location for use after reboot
2784 fprintf(stderr
, "update_dyld_shared_cache: atomically moving cache file into place: %s\n", fCacheFilePath
);
2785 result
= ::rename(tempCachePath
, fCacheFilePath
);
2787 throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath
, fCacheFilePath
, errno
);
2790 // flush everything to disk to assure rename() gets recorded
2794 // restore default signal handlers
2795 ::signal(SIGINT
, SIG_DFL
);
2796 ::signal(SIGBUS
, SIG_DFL
);
2797 ::signal(SIGSEGV
, SIG_DFL
);
2799 // generate human readable "map" file that shows the layout of the cache file
2801 fprintf(stderr
, "update_dyld_shared_cache: writing .map file to disk\n");
2802 char mapFilePath
[strlen(fCacheFilePath
)+16];
2803 sprintf(mapFilePath
, "%s.map", fCacheFilePath
);
2804 char tempMapFilePath
[strlen(fCacheFilePath
)+32];
2805 sprintf(tempMapFilePath
, "%s.map%u", fCacheFilePath
, getpid());
2806 FILE* fmap
= ::fopen(tempMapFilePath
, "w");
2807 if ( fmap
== NULL
) {
2808 fprintf(stderr
, "can't create map file %s, errnor=%d", tempCachePath
, errno
);
2811 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
2812 const char* prot
= "RW";
2813 if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_READ
) )
2815 else if ( it
->sfm_init_prot
== VM_PROT_READ
)
2817 else if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_WRITE
|VM_PROT_READ
) )
2819 if ( it
->sfm_size
> 1024*1024 )
2820 fprintf(fmap
, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/(1024*1024),
2821 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
2823 fprintf(fmap
, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/1024,
2824 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
2827 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX weak binding info\n",
2828 (fOffsetOfExportInfoInCombinedLinkedit
-fOffsetOfWeakBindInfoInCombinedLinkedit
)/1024,
2829 fLinkEditsStartAddress
+fOffsetOfWeakBindInfoInCombinedLinkedit
,
2830 fLinkEditsStartAddress
+fOffsetOfExportInfoInCombinedLinkedit
);
2831 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX export info\n",
2832 (fOffsetOfBindInfoInCombinedLinkedit
-fOffsetOfExportInfoInCombinedLinkedit
)/1024,
2833 fLinkEditsStartAddress
+fOffsetOfExportInfoInCombinedLinkedit
,
2834 fLinkEditsStartAddress
+fOffsetOfBindInfoInCombinedLinkedit
);
2835 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX binding info\n",
2836 (fOffsetOfLazyBindInfoInCombinedLinkedit
-fOffsetOfBindInfoInCombinedLinkedit
)/1024,
2837 fLinkEditsStartAddress
+fOffsetOfBindInfoInCombinedLinkedit
,
2838 fLinkEditsStartAddress
+fOffsetOfLazyBindInfoInCombinedLinkedit
);
2839 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX lazy binding info\n",
2840 (fOffsetOfOldSymbolTableInfoInCombinedLinkedit
-fOffsetOfLazyBindInfoInCombinedLinkedit
)/1024,
2841 fLinkEditsStartAddress
+fOffsetOfLazyBindInfoInCombinedLinkedit
,
2842 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
);
2843 fprintf(fmap
, "linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld symbol table size\n",
2844 (fSizeOfOldSymbolTableInfoInCombinedLinkedit
)/(1024*1024),
2845 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
,
2846 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
+fSizeOfOldSymbolTableInfoInCombinedLinkedit
);
2847 if ( fSizeOfFunctionStartsInCombinedLinkedit
!= 0 )
2848 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld functions starts size\n",
2849 fSizeOfFunctionStartsInCombinedLinkedit
/1024,
2850 fLinkEditsStartAddress
+fOffsetOfFunctionStartsInCombinedLinkedit
,
2851 fLinkEditsStartAddress
+fOffsetOfFunctionStartsInCombinedLinkedit
+fSizeOfFunctionStartsInCombinedLinkedit
);
2852 if ( fSizeOfDataInCodeInCombinedLinkedit
!= 0 )
2853 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld data-in-code info size\n",
2854 fSizeOfDataInCodeInCombinedLinkedit
/1024,
2855 fLinkEditsStartAddress
+fOffsetOfDataInCodeInCombinedLinkedit
,
2856 fLinkEditsStartAddress
+fOffsetOfDataInCodeInCombinedLinkedit
+fSizeOfDataInCodeInCombinedLinkedit
);
2857 if ( fSizeOfOldExternalRelocationsInCombinedLinkedit
!= 0 )
2858 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld external relocs size\n",
2859 fSizeOfOldExternalRelocationsInCombinedLinkedit
/1024,
2860 fLinkEditsStartAddress
+fOffsetOfOldExternalRelocationsInCombinedLinkedit
,
2861 fLinkEditsStartAddress
+fOffsetOfOldExternalRelocationsInCombinedLinkedit
+fSizeOfOldExternalRelocationsInCombinedLinkedit
);
2862 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld indirect symbol table size\n",
2863 fSizeOfOldIndirectSymbolsInCombinedLinkedit
/1024,
2864 fLinkEditsStartAddress
+fOffsetOfOldIndirectSymbolsInCombinedLinkedit
,
2865 fLinkEditsStartAddress
+fOffsetOfOldIndirectSymbolsInCombinedLinkedit
+fSizeOfOldIndirectSymbolsInCombinedLinkedit
);
2866 fprintf(fmap
, "linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld string pool\n",
2867 (fSizeOfOldStringPoolInCombinedLinkedit
)/(1024*1024),
2868 fLinkEditsStartAddress
+fOffsetOfOldStringPoolInCombinedLinkedit
,
2869 fLinkEditsStartAddress
+fOffsetOfOldStringPoolInCombinedLinkedit
+fSizeOfOldStringPoolInCombinedLinkedit
);
2871 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2872 fprintf(fmap
, "%s\n", it
->layout
->getID().name
);
2873 for (std::vector
<const char*>::const_iterator ait
= it
->aliases
.begin(); ait
!= it
->aliases
.end(); ++ait
)
2874 fprintf(fmap
, "%s\n", *ait
);
2875 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
2876 for (int i
=0; i
< segs
.size(); ++i
) {
2877 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
2878 fprintf(fmap
, "\t%16s 0x%0llX -> 0x%0llX\n", seg
.name(), seg
.newAddress(), seg
.newAddress()+seg
.size());
2881 if ( warnings
.size() > 0 ) {
2882 fprintf(fmap
, "# Warnings:\n");
2883 for (std::vector
<const char*>::iterator it
=warnings
.begin(); it
!= warnings
.end(); ++it
) {
2884 fprintf(fmap
, "# %s\n", *it
);
2888 result
= ::rename(tempMapFilePath
, mapFilePath
);
2892 // free in memory cache
2893 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
2894 inMemoryCache
= NULL
;
2897 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*100, archCount
*100);
2901 // remove temp cache file
2902 ::unlink(tempCachePath
);
2903 // remove in memory cache
2904 if ( inMemoryCache
!= NULL
)
2905 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
2915 // The shared cache is driven by /var/db/dyld/shared_region_roots which contains
2916 // the paths used to search for dylibs that should go in the shared cache
2918 // Leading and trailing white space is ignored
2919 // Blank lines are ignored
2920 // Lines starting with # are ignored
2922 static void parsePathsFile(const char* filePath
, std::vector
<const char*>& paths
)
2924 // read in whole file
2925 int fd
= open(filePath
, O_RDONLY
, 0);
2927 fprintf(stderr
, "update_dyld_shared_cache: can't open file: %s\n", filePath
);
2930 struct stat stat_buf
;
2931 fstat(fd
, &stat_buf
);
2932 char* p
= (char*)malloc(stat_buf
.st_size
);
2934 fprintf(stderr
, "update_dyld_shared_cache: malloc failure\n");
2937 if ( read(fd
, p
, stat_buf
.st_size
) != stat_buf
.st_size
) {
2938 fprintf(stderr
, "update_dyld_shared_cache: can't read file: %s\n", filePath
);
2943 // parse into paths and add to vector
2944 char * const end
= &p
[stat_buf
.st_size
];
2945 enum { lineStart
, inSymbol
, inComment
} state
= lineStart
;
2946 char* symbolStart
= NULL
;
2947 for (char* s
= p
; s
< end
; ++s
) {
2953 else if ( !isspace(*s
) ) {
2961 // removing any trailing spaces
2963 while ( isspace(*last
) ) {
2967 // <rdar://problem/8305479> images in shared cache are bound against different IOKit than found at runtime
2968 // HACK: Just ignore the known bad IOKit
2969 if ( strcmp(symbolStart
, "/System/Library/Frameworks/IOKit.framework/IOKit") == 0 ) {
2970 fprintf(stderr
, "update_dyld_shared_cache: warning, ignoring /System/Library/Frameworks/IOKit.framework/IOKit\n");
2971 warnings
.push_back("update_dyld_shared_cache: warning, ignoring /System/Library/Frameworks/IOKit.framework/IOKit\n");
2974 paths
.push_back(symbolStart
);
2986 // Note: we do not free() the malloc buffer, because the strings in it are used by exec()
2991 static void setSharedDylibs(const char* rootPath
, const char* overlayPath
, const std::set
<ArchPair
>& onlyArchs
, std::vector
<const char*> rootsPaths
)
2993 // set file system root
2994 ArchGraph::setFileSystemRoot(rootPath
);
2995 ArchGraph::setFileSystemOverlay(overlayPath
);
2997 // initialize all architectures requested
2998 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
2999 ArchGraph::addArchPair(*a
);
3001 // add roots to graph
3002 for(std::vector
<const char*>::const_iterator it
= rootsPaths
.begin(); it
!= rootsPaths
.end(); ++it
)
3003 ArchGraph::addRoot(*it
, onlyArchs
);
3005 // determine shared dylibs
3006 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
3007 ArchGraph::findSharedDylibs(*a
);
3011 static void scanForSharedDylibs(const char* rootPath
, const char* overlayPath
, const char* dirOfPathFiles
, const std::set
<ArchPair
>& onlyArchs
)
3013 char rootDirOfPathFiles
[strlen(rootPath
)+strlen(dirOfPathFiles
)+2];
3014 // in -root mode, look for roots in /rootpath/var/db/dyld
3015 if ( rootPath
[0] != '\0' ) {
3016 strcpy(rootDirOfPathFiles
, rootPath
);
3017 strcat(rootDirOfPathFiles
, dirOfPathFiles
);
3018 dirOfPathFiles
= rootDirOfPathFiles
;
3021 // extract all root paths from files in "/var/db/dyld/shared_region_roots/"
3023 fprintf(stderr
, "update_dyld_shared_cache: finding roots in: %s\n", dirOfPathFiles
);
3024 std::vector
<const char*> rootsPaths
;
3025 DIR* dir
= ::opendir(dirOfPathFiles
);
3027 throwf("%s does not exist, errno=%d\n", dirOfPathFiles
, errno
);
3028 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
3029 if ( entry
->d_type
== DT_REG
|| entry
->d_type
== DT_UNKNOWN
) {
3030 // only look at regular files ending in .paths
3031 if ( strcmp(&entry
->d_name
[entry
->d_namlen
-6], ".paths") == 0 ) {
3032 struct stat tmpStatPathsFile
;
3033 char fullPath
[strlen(dirOfPathFiles
)+entry
->d_namlen
+2];
3034 strcpy(fullPath
, dirOfPathFiles
);
3035 strcat(fullPath
, "/");
3036 strcat(fullPath
, entry
->d_name
);
3037 if ( lstat(fullPath
, &tmpStatPathsFile
) == -1 ) {
3038 fprintf(stderr
, "update_dyld_shared_cache: can't access %s\n", fullPath
);
3040 else if ( S_ISREG(tmpStatPathsFile
.st_mode
) ) {
3041 parsePathsFile(fullPath
, rootsPaths
);
3044 fprintf(stderr
, "update_dyld_shared_cache: wrong file type for %s\n", fullPath
);
3048 fprintf(stderr
, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry
->d_name
);
3054 if ( rootsPaths
.size() == 0 )
3055 fprintf(stderr
, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
3056 setSharedDylibs(rootPath
, overlayPath
, onlyArchs
, rootsPaths
);
3059 static void setSharedDylibs(const char* rootPath
, const char* overlayPath
, const char* pathsFile
, const std::set
<ArchPair
>& onlyArchs
)
3061 std::vector
<const char*> rootsPaths
;
3062 parsePathsFile(pathsFile
, rootsPaths
);
3063 setSharedDylibs(rootPath
, overlayPath
, onlyArchs
, rootsPaths
);
3067 // If the 10.5.0 version of update_dyld_shared_cache was killed or crashed, it
3068 // could leave large half written cache files laying around. The function deletes
3069 // those files. To prevent the deletion of tmp files being created by another
3070 // copy of update_dyld_shared_cache, it only deletes the temp cache file if its
3071 // creation time was before the last restart of this machine.
3072 static void deleteOrphanTempCacheFiles()
3074 DIR* dir
= ::opendir(MACOSX_DYLD_SHARED_CACHE_DIR
);
3075 if ( dir
!= NULL
) {
3076 std::vector
<const char*> filesToDelete
;
3077 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
3078 if ( entry
->d_type
== DT_REG
) {
3079 // only look at files with .tmp in name
3080 if ( strstr(entry
->d_name
, ".tmp") != NULL
) {
3081 char fullPath
[strlen(MACOSX_DYLD_SHARED_CACHE_DIR
)+entry
->d_namlen
+2];
3082 strcpy(fullPath
, MACOSX_DYLD_SHARED_CACHE_DIR
);
3083 strcat(fullPath
, "/");
3084 strcat(fullPath
, entry
->d_name
);
3085 struct stat tmpFileStatInfo
;
3086 if ( stat(fullPath
, &tmpFileStatInfo
) != -1 ) {
3087 int mib
[2] = {CTL_KERN
, KERN_BOOTTIME
};
3088 struct timeval boottime
;
3089 size_t size
= sizeof(boottime
);
3090 if ( (sysctl(mib
, 2, &boottime
, &size
, NULL
, 0) != -1) && (boottime
.tv_sec
!= 0) ) {
3091 // make sure this file is older than the boot time of this machine
3092 if ( tmpFileStatInfo
.st_mtime
< boottime
.tv_sec
) {
3093 filesToDelete
.push_back(strdup(fullPath
));
3101 for(std::vector
<const char*>::iterator it
= filesToDelete
.begin(); it
!= filesToDelete
.end(); ++it
) {
3102 fprintf(stderr
, "update_dyld_shared_cache: deleting old temp cache file: %s\n", *it
);
3110 static bool updateSharedeCacheFile(const char* rootPath
, const char* overlayPath
, const char* cacheDir
, bool explicitCacheDir
, const std::set
<ArchPair
>& onlyArchs
,
3111 bool force
, bool alphaSort
, bool optimize
, bool deleteExistingFirst
, bool verify
, bool keepSignatures
)
3113 bool didUpdate
= false;
3114 // get dyld load address info
3115 UniversalMachOLayout
* dyldLayout
= NULL
;
3116 char dyldPath
[1024];
3117 strlcpy(dyldPath
, rootPath
, 1024);
3118 strlcat(dyldPath
, "/usr/lib/dyld", 1024);
3119 struct stat stat_buf
;
3120 if ( stat(dyldPath
, &stat_buf
) == 0 ) {
3121 dyldLayout
= new UniversalMachOLayout(dyldPath
, &onlyArchs
);
3124 dyldLayout
= new UniversalMachOLayout("/usr/lib/dyld", &onlyArchs
);
3126 const int archCount
= onlyArchs
.size();
3128 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
, ++index
) {
3129 const MachOLayoutAbstraction
* dyldLayoutForArch
= dyldLayout
->getSlice(*a
);
3130 uint64_t dyldBaseAddress
= 0;
3131 if ( dyldLayoutForArch
!= NULL
)
3132 dyldBaseAddress
= dyldLayoutForArch
->getBaseAddress();
3134 fprintf(stderr
, "update_dyld_shared_cache: warning, dyld not available for specified architectures\n");
3135 switch ( a
->arch
) {
3138 SharedCache
<x86
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, overlayPath
, cacheDir
, explicitCacheDir
, alphaSort
, verify
, optimize
, dyldBaseAddress
);
3139 didUpdate
|= cache
.update(force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
);
3142 case CPU_TYPE_X86_64
:
3144 SharedCache
<x86_64
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, overlayPath
, cacheDir
, explicitCacheDir
, alphaSort
, verify
, optimize
, dyldBaseAddress
);
3145 didUpdate
|= cache
.update(force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
);
3150 SharedCache
<arm
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, overlayPath
, cacheDir
, explicitCacheDir
, alphaSort
, verify
, optimize
, dyldBaseAddress
);
3151 didUpdate
|= cache
.update(force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
);
3158 deleteOrphanTempCacheFiles();
3166 fprintf(stderr
, "update_dyld_shared_cache [-force] [-root dir] [-overlay dir] [-arch arch] [-debug]\n");
3170 int main(int argc
, const char* argv
[])
3172 std::set
<ArchPair
> onlyArchs
;
3173 const char* rootPath
= "";
3174 const char* overlayPath
= "";
3175 const char* dylibListFile
= NULL
;
3177 bool alphaSort
= false;
3178 bool optimize
= true;
3179 bool verify
= false;
3180 bool keepSignatures
= false;
3181 bool explicitCacheDir
= false;
3182 const char* cacheDir
= NULL
;
3185 // parse command line options
3186 for(int i
=1; i
< argc
; ++i
) {
3187 const char* arg
= argv
[i
];
3188 if ( arg
[0] == '-' ) {
3189 if ( strcmp(arg
, "-debug") == 0 ) {
3192 else if ( strcmp(arg
, "-force") == 0 ) {
3195 else if ( strcmp(arg
, "-verify") == 0 ) {
3198 else if ( strcmp(arg
, "-sort_by_name") == 0 ) {
3201 else if ( strcmp(arg
, "-progress") == 0 ) {
3204 else if ( strcmp(arg
, "-opt") == 0 ) {
3207 else if ( strcmp(arg
, "-no_opt") == 0 ) {
3210 else if ( strcmp(arg
, "-iPhone") == 0 ) {
3213 else if ( strcmp(arg
, "-dylib_list") == 0 ) {
3214 dylibListFile
= argv
[++i
];
3215 if ( dylibListFile
== NULL
)
3216 throw "-dylib_list missing path argument";
3218 else if ( (strcmp(arg
, "-root") == 0) || (strcmp(arg
, "--root") == 0) ) {
3219 rootPath
= argv
[++i
];
3220 if ( rootPath
== NULL
)
3221 throw "-root missing path argument";
3223 else if ( strcmp(arg
, "-overlay") == 0 ) {
3224 overlayPath
= argv
[++i
];
3225 if ( overlayPath
== NULL
)
3226 throw "-overlay missing path argument";
3228 else if ( strcmp(arg
, "-cache_dir") == 0 ) {
3229 cacheDir
= argv
[++i
];
3230 if ( cacheDir
== NULL
)
3231 throw "-cache_dir missing path argument";
3232 explicitCacheDir
= true;
3234 else if ( strcmp(arg
, "-arch") == 0 ) {
3235 const char* arch
= argv
[++i
];
3236 if ( strcmp(arch
, "i386") == 0 )
3237 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3238 else if ( strcmp(arch
, "x86_64") == 0 )
3239 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
3240 else if ( strcmp(arch
, "armv4t") == 0 )
3241 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V4T
));
3242 else if ( strcmp(arch
, "armv5") == 0 )
3243 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V5TEJ
));
3244 else if ( strcmp(arch
, "armv6") == 0 )
3245 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V6
));
3246 else if ( strcmp(arch
, "armv7") == 0 )
3247 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7
));
3248 else if ( strcmp(arch
, "armv7f") == 0 )
3249 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7F
));
3250 else if ( strcmp(arch
, "armv7k") == 0 )
3251 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7K
));
3253 throwf("unknown architecture %s", arch
);
3255 else if ( strcmp(arg
, "-universal_boot") == 0 ) {
3256 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
3257 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3261 throwf("unknown option: %s\n", arg
);
3266 throwf("unknown option: %s\n", arg
);
3270 // strip tailing slashes on -root
3271 // make it a real path so as to not make all dylibs look like symlink aliases
3272 if ( rootPath
[0] != '\0' ) {
3273 char realRootPath
[MAXPATHLEN
];
3274 if ( realpath(rootPath
, realRootPath
) == NULL
)
3275 throwf("realpath() failed on %s\n", rootPath
);
3276 rootPath
= strdup(realRootPath
);
3279 // strip tailing slashes on -overlay
3280 if ( overlayPath
[0] != '\0' ) {
3281 char realOverlayPath
[MAXPATHLEN
];
3282 if ( realpath(overlayPath
, realOverlayPath
) == NULL
)
3283 throwf("realpath() failed on %s\n", overlayPath
);
3284 overlayPath
= strdup(realOverlayPath
);
3287 // set default location to write cache dir
3288 if ( cacheDir
== NULL
)
3289 cacheDir
= (iPhoneOS
? IPHONE_DYLD_SHARED_CACHE_DIR
: MACOSX_DYLD_SHARED_CACHE_DIR
);
3291 // if no restrictions specified, use architectures that work on this machine
3292 if ( onlyArchs
.size() == 0 ) {
3294 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V6
));
3295 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7
));
3299 size_t len
= sizeof(int);
3300 #if __i386__ || __x86_64__
3301 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
3302 // check system is capable of running 64-bit programs
3303 if ( (sysctlbyname("hw.optional.x86_64", &available
, &len
, NULL
, 0) == 0) && available
)
3304 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
3306 #error unsupported architecture
3311 if ( !verify
&& (geteuid() != 0) )
3312 throw "you must be root to run this tool";
3314 // build list of shared dylibs
3315 if ( dylibListFile
!= NULL
)
3316 setSharedDylibs(rootPath
, overlayPath
, dylibListFile
, onlyArchs
);
3318 scanForSharedDylibs(rootPath
, overlayPath
, "/var/db/dyld/shared_region_roots/", onlyArchs
);
3319 updateSharedeCacheFile(rootPath
, overlayPath
, cacheDir
, explicitCacheDir
, onlyArchs
, force
, alphaSort
, optimize
,
3320 false, verify
, keepSignatures
);
3322 catch (const char* msg
) {
3323 fprintf(stderr
, "update_dyld_shared_cache failed: %s\n", msg
);