1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2006-2007 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>
39 #include <sys/param.h>
40 #include <sys/sysctl.h>
41 #include <sys/resource.h>
43 #include <servers/bootstrap.h>
44 #include <mach-o/loader.h>
45 #include <mach-o/fat.h>
47 #include "dyld_cache_format.h"
52 #include <ext/hash_map>
54 #include "Architectures.hpp"
55 #include "MachOLayout.hpp"
56 #include "MachORebaser.hpp"
57 #include "MachOBinder.hpp"
58 #include "CacheFileAbstraction.hpp"
61 #include "dyld_shared_cache_server.h"
65 static bool verbose
= false;
66 static std::vector
<const char*> warnings
;
69 static uint64_t pageAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
74 static void addArch(cpu_type_t arch
);
75 static void addRoot(const char* vpath
, const std::set
<cpu_type_t
>& archs
);
76 static void findSharedDylibs(cpu_type_t arch
);
77 static ArchGraph
* getArch(cpu_type_t arch
) { return fgPerArchGraph
[arch
]; }
78 static void setFileSystemRoot(const char* root
) { fgFileSystemRoot
= root
; }
79 static const char* archName(cpu_type_t arch
);
81 cpu_type_t
getArch() { return fArch
; }
82 std::set
<const class MachOLayoutAbstraction
*>& getSharedDylibs() { return fSharedDylibs
; }
89 DependencyNode(ArchGraph
*, const char* path
, const MachOLayoutAbstraction
* layout
);
90 void loadDependencies(const MachOLayoutAbstraction
*);
91 void markNeededByRoot(DependencyNode
*);
92 const char* getPath() const { return fPath
; }
93 const MachOLayoutAbstraction
* getLayout() const { return fLayout
; }
94 size_t useCount() const { return fRootsDependentOnThis
.size(); }
95 bool allDependentsFound() const { return !fDependentMissing
; }
99 const MachOLayoutAbstraction
* fLayout
;
100 bool fDependenciesLoaded
;
101 bool fDependentMissing
;
102 std::set
<DependencyNode
*> fDependsOn
;
103 std::set
<DependencyNode
*> fRootsDependentOnThis
;
106 struct CStringEquals
{
107 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
109 typedef __gnu_cxx::hash_map
<const char*, class DependencyNode
*, __gnu_cxx::hash
<const char*>, CStringEquals
> PathToNode
;
112 ArchGraph(cpu_type_t arch
) : fArch(arch
) {}
113 static void addRootForArch(const char* path
, const MachOLayoutAbstraction
*);
114 void addRoot(const char* path
, const MachOLayoutAbstraction
*);
115 DependencyNode
* getNode(const char* path
);
116 DependencyNode
* getNodeForVirtualPath(const char* vpath
);
117 static bool canBeShared(const MachOLayoutAbstraction
* layout
, cpu_type_t arch
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
);
119 static std::map
<cpu_type_t
, ArchGraph
*> fgPerArchGraph
;
120 static const char* fgFileSystemRoot
;
123 std::set
<DependencyNode
*> fRoots
;
125 std::set
<const MachOLayoutAbstraction
*> fSharedDylibs
; // use set to avoid duplicates when installname!=realpath
127 std::map
<cpu_type_t
, ArchGraph
*> ArchGraph::fgPerArchGraph
;
128 const char* ArchGraph::fgFileSystemRoot
= "";
130 void ArchGraph::addArch(cpu_type_t arch
)
132 //fprintf(stderr, "adding arch 0x%08X\n", arch);
133 fgPerArchGraph
[arch
] = new ArchGraph(arch
);
136 void ArchGraph::addRoot(const char* vpath
, const std::set
<cpu_type_t
>& archs
)
138 char completePath
[strlen(fgFileSystemRoot
)+strlen(vpath
)+2];
140 if ( strlen(fgFileSystemRoot
) == 0 ) {
144 strcpy(completePath
, fgFileSystemRoot
);
145 strcat(completePath
, vpath
); // assumes vpath starts with '/'
149 const UniversalMachOLayout
* uni
= UniversalMachOLayout::find(path
, &archs
);
150 const std::vector
<MachOLayoutAbstraction
*>& layouts
= uni
->getArchs();
151 for(std::vector
<MachOLayoutAbstraction
*>::const_iterator it
= layouts
.begin(); it
!= layouts
.end(); ++it
) {
152 const MachOLayoutAbstraction
* layout
= *it
;
153 if ( archs
.count(layout
->getArchitecture()) > 0 )
154 ArchGraph::addRootForArch(path
, layout
);
156 // don't delete uni, it is owned by UniversalMachOLayout cache
158 catch (const char* msg
) {
159 fprintf(stderr
, "update_dyld_shared_cache: warning can't use root %s: %s\n", path
, msg
);
163 void ArchGraph::addRootForArch(const char* path
, const MachOLayoutAbstraction
* layout
)
165 ArchGraph
* graph
= fgPerArchGraph
[layout
->getArchitecture()];
166 graph
->addRoot(path
, layout
);
169 void ArchGraph::addRoot(const char* path
, const MachOLayoutAbstraction
* layout
)
172 fprintf(stderr
, "update_dyld_shared_cache: adding root: %s\n", path
);
173 DependencyNode
* node
= this->getNode(path
);
175 const MachOLayoutAbstraction
* mainExecutableLayout
= NULL
;
176 if ( layout
->getFileType() == MH_EXECUTE
)
177 mainExecutableLayout
= layout
;
178 node
->loadDependencies(mainExecutableLayout
);
179 node
->markNeededByRoot(node
);
180 if ( layout
->getFileType() == MH_DYLIB
)
181 node
->markNeededByRoot(NULL
);
184 // a virtual path does not have the fgFileSystemRoot prefix
185 ArchGraph::DependencyNode
* ArchGraph::getNodeForVirtualPath(const char* vpath
)
187 if ( fgFileSystemRoot
== NULL
) {
188 return this->getNode(vpath
);
191 char completePath
[strlen(fgFileSystemRoot
)+strlen(vpath
)+2];
192 strcpy(completePath
, fgFileSystemRoot
);
193 strcat(completePath
, vpath
); // assumes vpath starts with '/'
194 return this->getNode(completePath
);
198 ArchGraph::DependencyNode
* ArchGraph::getNode(const char* path
)
200 // look up supplied path to see if node already exists
201 PathToNode::iterator pos
= fNodes
.find(path
);
202 if ( pos
!= fNodes
.end() )
206 char realPath
[MAXPATHLEN
];
207 if ( realpath(path
, realPath
) == NULL
)
208 throwf("realpath() failed on %s\n", path
);
210 // look up real path to see if node already exists
211 pos
= fNodes
.find(realPath
);
212 if ( pos
!= fNodes
.end() )
215 // still does not exist, so create a new node
216 const UniversalMachOLayout
* uni
= UniversalMachOLayout::find(realPath
);
217 DependencyNode
* node
= new DependencyNode(this, realPath
, uni
->getArch(fArch
));
218 if ( node
->getLayout() == NULL
) {
219 throwf("%s is missing arch %s", realPath
, archName(fArch
));
221 // add realpath to node map
222 fNodes
[node
->getPath()] = node
;
223 // if install name is not real path, add install name to node map
224 if ( (node
->getLayout()->getFileType() == MH_DYLIB
) && (strcmp(realPath
, node
->getLayout()->getID().name
) != 0) ) {
225 //fprintf(stderr, "adding node alias 0x%08X %s for %s\n", fArch, node->getLayout()->getID().name, realPath);
226 fNodes
[node
->getLayout()->getID().name
] = node
;
232 void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction
* mainExecutableLayout
)
234 if ( !fDependenciesLoaded
) {
235 fDependenciesLoaded
= true;
237 const std::vector
<MachOLayoutAbstraction::Library
>& dependsOn
= fLayout
->getLibraries();
238 for(std::vector
<MachOLayoutAbstraction::Library
>::const_iterator it
= dependsOn
.begin(); it
!= dependsOn
.end(); ++it
) {
240 const char* dependentPath
= it
->name
;
241 if ( strncmp(dependentPath
, "@executable_path/", 17) == 0 ) {
242 if ( mainExecutableLayout
== NULL
)
243 throw "@executable_path without main executable";
244 // expand @executable_path path prefix
245 const char* executablePath
= mainExecutableLayout
->getFilePath();
246 char newPath
[strlen(executablePath
) + strlen(dependentPath
)+2];
247 strcpy(newPath
, executablePath
);
248 char* addPoint
= strrchr(newPath
,'/');
249 if ( addPoint
!= NULL
)
250 strcpy(&addPoint
[1], &dependentPath
[17]);
252 strcpy(newPath
, &dependentPath
[17]);
253 dependentPath
= strdup(newPath
);
255 else if ( strncmp(dependentPath
, "@loader_path/", 13) == 0 ) {
256 // expand @loader_path path prefix
257 char newPath
[strlen(fPath
) + strlen(dependentPath
)+2];
258 strcpy(newPath
, fPath
);
259 char* addPoint
= strrchr(newPath
,'/');
260 if ( addPoint
!= NULL
)
261 strcpy(&addPoint
[1], &dependentPath
[13]);
263 strcpy(newPath
, &dependentPath
[13]);
264 dependentPath
= strdup(newPath
);
266 else if ( strncmp(dependentPath
, "@rpath/", 7) == 0 ) {
267 throw "@rpath not supported in dyld shared cache";
269 fDependsOn
.insert(fGraph
->getNodeForVirtualPath(dependentPath
));
271 catch (const char* msg
) {
272 fprintf(stderr
, "warning, could not bind %s because %s\n", fPath
, msg
);
273 fDependentMissing
= true;
277 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
278 (*it
)->loadDependencies(mainExecutableLayout
);
283 void ArchGraph::DependencyNode::markNeededByRoot(ArchGraph::DependencyNode
* rootNode
)
285 if ( fRootsDependentOnThis
.count(rootNode
) == 0 ) {
286 fRootsDependentOnThis
.insert(rootNode
);
287 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
288 (*it
)->markNeededByRoot(rootNode
);
294 ArchGraph::DependencyNode::DependencyNode(ArchGraph
* graph
, const char* path
, const MachOLayoutAbstraction
* layout
)
295 : fGraph(graph
), fPath(strdup(path
)), fLayout(layout
), fDependenciesLoaded(false), fDependentMissing(false)
297 //fprintf(stderr, "new DependencyNode(0x%08X, %s)\n", graph->fArch, path);
300 void ArchGraph::findSharedDylibs(cpu_type_t arch
)
302 const PathToNode
& nodes
= fgPerArchGraph
[arch
]->fNodes
;
303 std::set
<const MachOLayoutAbstraction
*> possibleLibs
;
304 //fprintf(stderr, "shared for arch 0x%08X\n", arch);
305 for(PathToNode::const_iterator it
= nodes
.begin(); it
!= nodes
.end(); ++it
) {
306 DependencyNode
* node
= it
->second
;
307 if ( node
->allDependentsFound() && (node
->useCount() > 1) ) {
308 if ( node
->getLayout()->hasSplitSegInfo() )
309 possibleLibs
.insert(node
->getLayout());
310 //fprintf(stderr, "\t%s\n", it->first);
314 // prune so that all shareable libs depend only on other shareable libs
315 std::set
<const MachOLayoutAbstraction
*>& sharedLibs
= fgPerArchGraph
[arch
]->fSharedDylibs
;
316 std::map
<const MachOLayoutAbstraction
*,bool> shareableMap
;
317 for (std::set
<const MachOLayoutAbstraction
*>::iterator lit
= possibleLibs
.begin(); lit
!= possibleLibs
.end(); ++lit
) {
318 if ( canBeShared(*lit
, arch
, possibleLibs
, shareableMap
) )
319 sharedLibs
.insert(*lit
);
323 const char* ArchGraph::archName(cpu_type_t arch
)
326 case CPU_TYPE_POWERPC
:
328 case CPU_TYPE_POWERPC64
:
332 case CPU_TYPE_X86_64
:
339 bool ArchGraph::canBeShared(const MachOLayoutAbstraction
* layout
, cpu_type_t arch
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
)
341 // check map which is a cache of results
342 std::map
<const MachOLayoutAbstraction
*, bool>::iterator mapPos
= shareableMap
.find(layout
);
343 if ( mapPos
!= shareableMap
.end() ) {
344 return mapPos
->second
;
347 if ( possibleLibs
.count(layout
) == 0 ) {
348 shareableMap
[layout
] = false;
350 if ( ! layout
->hasSplitSegInfo() )
351 asprintf(&msg
, "can't put %s in shared cache because it was not built for 10.5", layout
->getID().name
);
353 asprintf(&msg
, "can't put %s in shared cache", layout
->getID().name
);
354 warnings
.push_back(msg
);
356 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(arch
), msg
);
360 shareableMap
[layout
] = true; // mark this shareable early in case of circular references
361 const PathToNode
& nodes
= fgPerArchGraph
[arch
]->fNodes
;
362 const std::vector
<MachOLayoutAbstraction::Library
>& dependents
= layout
->getLibraries();
363 for (std::vector
<MachOLayoutAbstraction::Library
>::const_iterator dit
= dependents
.begin(); dit
!= dependents
.end(); ++dit
) {
364 PathToNode::const_iterator pos
= nodes
.find(dit
->name
);
365 if ( pos
== nodes
.end() ) {
366 shareableMap
[layout
] = false;
368 asprintf(&msg
, "can't put %s in shared cache because it depends on %s which can't be found", layout
->getID().name
, dit
->name
);
369 warnings
.push_back(msg
);
371 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(arch
), msg
);
375 if ( ! canBeShared(pos
->second
->getLayout(), arch
, possibleLibs
, shareableMap
) ) {
376 shareableMap
[layout
] = false;
378 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
);
379 warnings
.push_back(msg
);
381 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(arch
), msg
);
390 template <typename A
>
394 SharedCache(ArchGraph
* graph
, bool alphaSort
, uint64_t dyldBaseAddress
);
395 bool update(const char* rootPath
, const char* cacheDir
, bool force
, bool optimize
, bool deleteExistingFirst
, int archIndex
, int archCount
);
396 static const char* filename(bool optimized
);
399 typedef typename
A::P::E E
;
401 bool notUpToDate(const char* cachePath
);
402 bool notUpToDate(const void* cache
);
403 uint8_t* optimizeLINKEDIT();
405 static void getSharedCacheBasAddresses(cpu_type_t arch
, uint64_t* baseReadOnly
, uint64_t* baseWritable
);
406 static cpu_type_t
arch();
407 static const char* archName();
408 static uint64_t sharedRegionReadOnlyStartAddress();
409 static uint64_t sharedRegionWritableStartAddress();
410 static uint64_t sharedRegionReadOnlySize();
411 static uint64_t sharedRegionWritableSize();
412 static uint64_t getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
);
415 void assignNewBaseAddresses();
416 uint64_t cacheFileOffsetForAddress(uint64_t addr
);
419 const MachOLayoutAbstraction
* layout
;
420 dyld_cache_image_info info
;
423 struct ByNameSorter
{
424 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
)
425 { return (strcmp(left
.layout
->getID().name
, right
.layout
->getID().name
) < 0); }
428 struct RandomSorter
{
429 RandomSorter(const std::vector
<LayoutInfo
>& infos
) {
430 for(typename
std::vector
<struct LayoutInfo
>::const_iterator it
= infos
.begin(); it
!= infos
.end(); ++it
)
431 fMap
[it
->layout
] = arc4random();
433 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
434 return (fMap
[left
.layout
] < fMap
[right
.layout
]);
437 std::map
<const MachOLayoutAbstraction
*, uint32_t> fMap
;
441 ArchGraph
* fArchGraph
;
442 std::vector
<LayoutInfo
> fDylibs
;
443 std::vector
<shared_file_mapping_np
> fMappings
;
444 uint32_t fHeaderSize
;
445 uint64_t fDyldBaseAddress
;
446 uint64_t fLinkEditsTotalUnoptimizedSize
;
447 uint64_t fLinkEditsStartAddress
;
448 MachOLayoutAbstraction::Segment
* fFirstLinkEditSegment
;
454 template <> cpu_type_t SharedCache
<ppc
>::arch() { return CPU_TYPE_POWERPC
; }
455 template <> cpu_type_t SharedCache
<ppc64
>::arch() { return CPU_TYPE_POWERPC64
; }
456 template <> cpu_type_t SharedCache
<x86
>::arch() { return CPU_TYPE_I386
; }
457 template <> cpu_type_t SharedCache
<x86_64
>::arch() { return CPU_TYPE_X86_64
; }
459 template <> uint64_t SharedCache
<ppc
>::sharedRegionReadOnlyStartAddress() { return 0x90000000; }
460 template <> uint64_t SharedCache
<ppc64
>::sharedRegionReadOnlyStartAddress() { return 0x7FFF80000000LL
; }
461 template <> uint64_t SharedCache
<x86
>::sharedRegionReadOnlyStartAddress() { return 0x90000000; }
462 template <> uint64_t SharedCache
<x86_64
>::sharedRegionReadOnlyStartAddress() { return 0x7FFF80000000LL
; }
464 template <> uint64_t SharedCache
<ppc
>::sharedRegionWritableStartAddress() { return 0xA0000000; }
465 template <> uint64_t SharedCache
<ppc64
>::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL
; }
466 template <> uint64_t SharedCache
<x86
>::sharedRegionWritableStartAddress() { return 0xA0000000; }
467 template <> uint64_t SharedCache
<x86_64
>::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL
; }
469 template <> uint64_t SharedCache
<ppc
>::sharedRegionReadOnlySize() { return 0x10000000; }
470 template <> uint64_t SharedCache
<ppc64
>::sharedRegionReadOnlySize() { return 0x7FE00000; }
471 template <> uint64_t SharedCache
<x86
>::sharedRegionReadOnlySize() { return 0x10000000; }
472 template <> uint64_t SharedCache
<x86_64
>::sharedRegionReadOnlySize() { return 0x7FE00000; }
474 template <> uint64_t SharedCache
<ppc
>::sharedRegionWritableSize() { return 0x10000000; }
475 template <> uint64_t SharedCache
<ppc64
>::sharedRegionWritableSize() { return 0x20000000; }
476 template <> uint64_t SharedCache
<x86
>::sharedRegionWritableSize() { return 0x10000000; }
477 template <> uint64_t SharedCache
<x86_64
>::sharedRegionWritableSize() { return 0x20000000; }
480 template <> const char* SharedCache
<ppc
>::archName() { return "ppc"; }
481 template <> const char* SharedCache
<ppc64
>::archName() { return "ppc64"; }
482 template <> const char* SharedCache
<x86
>::archName() { return "i386"; }
483 template <> const char* SharedCache
<x86_64
>::archName() { return "x86_64"; }
485 template <> const char* SharedCache
<ppc
>::filename(bool optimized
) { return optimized
? "ppc" : "rosetta"; }
486 template <> const char* SharedCache
<ppc64
>::filename(bool) { return "ppc64"; }
487 template <> const char* SharedCache
<x86
>::filename(bool) { return "i386"; }
488 template <> const char* SharedCache
<x86_64
>::filename(bool) { return "x86_64"; }
490 template <typename A
>
491 SharedCache
<A
>::SharedCache(ArchGraph
* graph
, bool alphaSort
, uint64_t dyldBaseAddress
)
492 : fArchGraph(graph
), fDyldBaseAddress(dyldBaseAddress
)
494 if ( fArchGraph
->getArch() != arch() )
495 throw "wrong architecture";
497 // build vector of all shared dylibs
498 std::set
<const MachOLayoutAbstraction
*>& dylibs
= fArchGraph
->getSharedDylibs();
499 for(std::set
<const MachOLayoutAbstraction
*>::iterator it
= dylibs
.begin(); it
!= dylibs
.end(); ++it
) {
500 const MachOLayoutAbstraction
* lib
= *it
;
503 temp
.info
.address
= 0;
504 temp
.info
.modTime
= lib
->getLastModTime();
505 temp
.info
.inode
= lib
->getInode();
506 temp
.info
.pathFileOffset
= lib
->getNameFileOffset();
507 fDylibs
.push_back(temp
);
510 // sort shared dylibs
512 std::sort(fDylibs
.begin(), fDylibs
.end(), ByNameSorter());
514 std::sort(fDylibs
.begin(), fDylibs
.end(), RandomSorter(fDylibs
));
517 // assign segments in each dylib a new address
518 this->assignNewBaseAddresses();
520 // calculate cache file header size
521 fHeaderSize
= pageAlign(sizeof(dyld_cache_header
)
522 + fMappings
.size()*sizeof(shared_file_mapping_np
)
523 + fDylibs
.size()*sizeof(dyld_cache_image_info
) );
524 //+ fDependencyPool.size()*sizeof(uint16_t));
526 if ( fHeaderSize
> 0x3000 )
527 throwf("header size miscalculation 0x%08X", fHeaderSize
);
531 template <typename A
>
532 uint64_t SharedCache
<A
>::getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
)
534 return proposedNewAddress
;
538 uint64_t SharedCache
<ppc
>::getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
)
540 // for ppc64 writable segments can only move in increments of 64K (so only hi16 instruction needs to be modified)
541 return (((executableSlide
& 0x000000000000F000ULL
) - ((proposedNewAddress
- originalAddress
) & 0x000000000000F000ULL
)) & 0x000000000000F000ULL
) + proposedNewAddress
;
545 uint64_t SharedCache
<ppc64
>::getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
)
547 // for ppc64 writable segments can only move in increments of 64K (so only hi16 instruction needs to be modified)
548 return (((executableSlide
& 0x000000000000F000ULL
) - ((proposedNewAddress
- originalAddress
) & 0x000000000000F000ULL
)) & 0x000000000000F000ULL
) + proposedNewAddress
;
552 template <typename A
>
553 void SharedCache
<A
>::assignNewBaseAddresses()
555 // first layout TEXT and DATA for split-seg (or can be split-seg) dylibs
556 uint64_t currentExecuteAddress
= sharedRegionReadOnlyStartAddress() + 0x3000;
557 uint64_t currentWritableAddress
= sharedRegionWritableStartAddress();
558 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
559 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
560 MachOLayoutAbstraction::Segment
* executableSegment
= NULL
;
561 for (int i
=0; i
< segs
.size(); ++i
) {
562 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
563 if ( seg
.writable() ) {
564 if ( seg
.executable() && it
->layout
->hasSplitSegInfo() ) {
565 // skip __IMPORT segments in this pass
569 // for ppc, writable segments have to move in 64K increments
570 if ( it
->layout
->hasSplitSegInfo() ) {
571 if ( executableSegment
== NULL
)
572 throwf("first segment in dylib is not executable for %s", it
->layout
->getID().name
);
573 seg
.setNewAddress(getWritableSegmentNewAddress(currentWritableAddress
, seg
.address(), executableSegment
->newAddress() - executableSegment
->address()));
576 seg
.setNewAddress(currentWritableAddress
);
577 currentWritableAddress
= pageAlign(seg
.newAddress() + seg
.size());
581 if ( seg
.executable() ) {
583 if ( it
->info
.address
== 0 )
584 it
->info
.address
= currentExecuteAddress
;
585 executableSegment
= &seg
;
586 seg
.setNewAddress(currentExecuteAddress
);
587 currentExecuteAddress
+= pageAlign(seg
.size());
590 // skip read-only segments in this pass
591 // any non-LINKEDIT read-only segments leave a hole so that all R/W segment slide together
592 if ( (strcmp(seg
.name(), "__LINKEDIT") != 0) && (i
< (segs
.size()-2)) ) {
593 fprintf(stderr
, "update_dyld_shared_cache: warning %s segment in %s leaves a hole\n", seg
.name(), it
->layout
->getID().name
);
594 currentWritableAddress
= pageAlign(currentWritableAddress
+ seg
.size());
601 // append all read-only (but not LINKEDIT) segments at end of all TEXT segments
602 // append all IMPORT segments at end of all DATA segments rounded to next 2MB
603 uint64_t currentReadOnlyAddress
= currentExecuteAddress
;
604 uint64_t startWritableExecutableAddress
= (currentWritableAddress
+ 0x200000 - 1) & (-0x200000);
605 uint64_t currentWritableExecutableAddress
= startWritableExecutableAddress
;
606 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
607 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
608 for(int i
=0; i
< segs
.size(); ++i
) {
609 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
610 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") != 0) ) {
611 // allocate non-executable,read-only segments from end of read only shared region
612 seg
.setNewAddress(currentReadOnlyAddress
);
613 currentReadOnlyAddress
+= pageAlign(seg
.size());
615 else if ( seg
.writable() && seg
.executable() && it
->layout
->hasSplitSegInfo() ) {
616 // allocate IMPORT segments to end of writable shared region
617 seg
.setNewAddress(currentWritableExecutableAddress
);
618 seg
.setWritable(false); // __IMPORT segments are not-writable in shared cache
619 currentWritableExecutableAddress
+= pageAlign(seg
.size());
624 // append all LINKEDIT segments at end of all read-only segments
625 fLinkEditsStartAddress
= currentReadOnlyAddress
;
626 fFirstLinkEditSegment
= NULL
;
627 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
628 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
629 for(int i
=0; i
< segs
.size(); ++i
) {
630 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
631 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
632 if ( fFirstLinkEditSegment
== NULL
)
633 fFirstLinkEditSegment
= &seg
;
634 // allocate non-executable,read-only segments from end of read only shared region
635 seg
.setNewAddress(currentReadOnlyAddress
);
636 currentReadOnlyAddress
+= pageAlign(seg
.size());
640 fLinkEditsTotalUnoptimizedSize
= (currentReadOnlyAddress
- fLinkEditsStartAddress
+ 4095) & (-4096);
643 // populate large mappings
644 uint64_t cacheFileOffset
= 0;
645 if ( currentExecuteAddress
> sharedRegionReadOnlyStartAddress() + 0x3000 ) {
646 shared_file_mapping_np executeMapping
;
647 executeMapping
.sfm_address
= sharedRegionReadOnlyStartAddress();
648 executeMapping
.sfm_size
= currentExecuteAddress
- sharedRegionReadOnlyStartAddress();
649 executeMapping
.sfm_file_offset
= cacheFileOffset
;
650 executeMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
651 executeMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
652 fMappings
.push_back(executeMapping
);
653 cacheFileOffset
+= executeMapping
.sfm_size
;
655 shared_file_mapping_np writableMapping
;
656 writableMapping
.sfm_address
= sharedRegionWritableStartAddress();
657 writableMapping
.sfm_size
= currentWritableAddress
- sharedRegionWritableStartAddress();
658 writableMapping
.sfm_file_offset
= cacheFileOffset
;
659 writableMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
660 writableMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
661 fMappings
.push_back(writableMapping
);
662 cacheFileOffset
+= writableMapping
.sfm_size
;
664 if ( currentWritableExecutableAddress
> startWritableExecutableAddress
) {
665 shared_file_mapping_np writableExecutableMapping
;
666 writableExecutableMapping
.sfm_address
= startWritableExecutableAddress
;
667 writableExecutableMapping
.sfm_size
= currentWritableExecutableAddress
- startWritableExecutableAddress
;
668 writableExecutableMapping
.sfm_file_offset
= cacheFileOffset
;
669 writableExecutableMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_WRITE
| VM_PROT_EXECUTE
;
670 // __IMPORT segments in shared cache are not writable
671 writableExecutableMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
672 fMappings
.push_back(writableExecutableMapping
);
673 cacheFileOffset
+= writableExecutableMapping
.sfm_size
;
676 // make read-only (contains LINKEDIT segments) last, so it can be cut back when optimized
677 shared_file_mapping_np readOnlyMapping
;
678 readOnlyMapping
.sfm_address
= currentExecuteAddress
;
679 readOnlyMapping
.sfm_size
= currentReadOnlyAddress
- currentExecuteAddress
;
680 readOnlyMapping
.sfm_file_offset
= cacheFileOffset
;
681 readOnlyMapping
.sfm_max_prot
= VM_PROT_READ
;
682 readOnlyMapping
.sfm_init_prot
= VM_PROT_READ
;
683 fMappings
.push_back(readOnlyMapping
);
684 cacheFileOffset
+= readOnlyMapping
.sfm_size
;
688 shared_file_mapping_np cacheHeaderMapping
;
689 cacheHeaderMapping
.sfm_address
= sharedRegionWritableStartAddress();
690 cacheHeaderMapping
.sfm_size
= 0x3000;
691 cacheHeaderMapping
.sfm_file_offset
= cacheFileOffset
;
692 cacheHeaderMapping
.sfm_max_prot
= VM_PROT_READ
;
693 cacheHeaderMapping
.sfm_init_prot
= VM_PROT_READ
;
694 fMappings
.push_back(cacheHeaderMapping
);
695 cacheFileOffset
+= cacheHeaderMapping
.sfm_size
;
700 template <typename A
>
701 uint64_t SharedCache
<A
>::cacheFileOffsetForAddress(uint64_t addr
)
703 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
704 if ( (it
->sfm_address
<= addr
) && (addr
< it
->sfm_address
+it
->sfm_size
) )
705 return it
->sfm_file_offset
+ addr
- it
->sfm_address
;
707 throwf("address 0x%0llX is not in cache", addr
);
711 template <typename A
>
712 bool SharedCache
<A
>::notUpToDate(const void* cache
)
714 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)cache
;
715 // not valid if header signature is wrong
717 strcpy(temp
, "dyld_v1 ");
718 strcpy(&temp
[15-strlen(archName())], archName());
719 if ( strcmp(header
->magic(), temp
) != 0 )
721 // not valid if count of images does not match current images needed
722 if ( header
->imagesCount() != fDylibs
.size() )
724 // verify every dylib in constructed graph is in existing cache with same inode and modTime
725 const dyldCacheImageInfo
<E
>* imagesStart
= (dyldCacheImageInfo
<E
>*)((uint8_t*)cache
+ header
->imagesOffset());
726 const dyldCacheImageInfo
<E
>* imagesEnd
= &imagesStart
[header
->imagesCount()];
727 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
729 //fprintf(stderr, "inode=0x%llX, mTime=0x%llX, path=%s\n", it->info.inode, it->info.modTime, it->layout->getID().name);
730 for(const dyldCacheImageInfo
<E
>* cacheEntry
= imagesStart
; cacheEntry
< imagesEnd
; ++cacheEntry
) {
731 if ( (cacheEntry
->inode() == it
->info
.inode
)
732 && (cacheEntry
->modTime() == it
->info
.modTime
)
733 && (strcmp((char*)cache
+cacheEntry
->pathFileOffset(), it
->layout
->getID().name
) == 0) ) {
739 fprintf(stderr
, "update_dyld_shared_cache[%u] current cache invalid because %s has changed\n", getpid(), it
->layout
->getID().name
);
747 template <typename A
>
748 bool SharedCache
<A
>::notUpToDate(const char* cachePath
)
750 // mmap existing cache file
751 int fd
= ::open(cachePath
, O_RDONLY
);
754 struct stat stat_buf
;
755 ::fstat(fd
, &stat_buf
);
756 uint8_t* mappingAddr
= (uint8_t*)mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
758 if ( mappingAddr
== (uint8_t*)(-1) )
762 bool result
= this->notUpToDate(mappingAddr
);
764 ::munmap(mappingAddr
, stat_buf
.st_size
);
765 if ( verbose
&& !result
)
766 fprintf(stderr
, "update_dyld_shared_cache: %s is up-to-date\n", cachePath
);
774 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
781 const char* getBuffer();
783 uint32_t add(const char* str
);
784 uint32_t addUnique(const char* str
);
785 const char* stringAtIndex(uint32_t) const;
787 typedef __gnu_cxx::hash_map
<const char*, uint32_t, __gnu_cxx::hash
<const char*>, CStringEquals
> StringToOffset
;
790 uint32_t fBufferAllocated
;
791 uint32_t fBufferUsed
;
792 StringToOffset fUniqueStrings
;
796 StringPool::StringPool()
797 : fBufferUsed(0), fBufferAllocated(4*1024*1024)
799 fBuffer
= (char*)malloc(fBufferAllocated
);
802 uint32_t StringPool::add(const char* str
)
804 uint32_t len
= strlen(str
);
805 if ( (fBufferUsed
+ len
+ 1) > fBufferAllocated
) {
807 fBufferAllocated
= fBufferAllocated
*2;
808 fBuffer
= (char*)realloc(fBuffer
, fBufferAllocated
);
810 strcpy(&fBuffer
[fBufferUsed
], str
);
811 uint32_t result
= fBufferUsed
;
812 fUniqueStrings
[&fBuffer
[fBufferUsed
]] = result
;
813 fBufferUsed
+= len
+1;
817 uint32_t StringPool::addUnique(const char* str
)
819 StringToOffset::iterator pos
= fUniqueStrings
.find(str
);
820 if ( pos
!= fUniqueStrings
.end() )
823 //fprintf(stderr, "StringPool::addUnique() new string: %s\n", str);
824 return this->add(str
);
828 uint32_t StringPool::size()
833 const char* StringPool::getBuffer()
838 const char* StringPool::stringAtIndex(uint32_t index
) const
840 return &fBuffer
[index
];
844 template <typename A
>
845 class LinkEditOptimizer
848 LinkEditOptimizer(const MachOLayoutAbstraction
&, uint8_t*, StringPool
&);
849 virtual ~LinkEditOptimizer() {}
851 static void makeDummyLocalSymbol(uint32_t&, uint8_t*, StringPool
&);
852 void copyLocalSymbols();
853 void copyExportedSymbols(uint32_t&);
854 void copyImportedSymbols(uint32_t&);
855 void copyExternalRelocations(uint32_t&);
856 void copyIndirectSymbolTable(uint32_t&);
857 void updateLoadCommands(uint64_t newVMAddress
, uint64_t size
, uint32_t stringPoolOffset
);
861 typedef typename
A::P P
;
862 typedef typename
A::P::E E
;
863 typedef typename
A::P::uint_t pint_t
;
867 const macho_header
<P
>* fHeader
;
868 uint8_t* fNewLinkEditStart
;
869 uint8_t* fLinkEditBase
;
870 const MachOLayoutAbstraction
& fLayout
;
871 macho_dysymtab_command
<P
>* fDynamicSymbolTable
;
872 macho_symtab_command
<P
>* fSymbolTableLoadCommand
;
873 const macho_nlist
<P
>* fSymbolTable
;
874 const char* fStrings
;
875 StringPool
& fNewStringPool
;
876 std::map
<uint32_t,uint32_t> fOldToNewSymbolIndexes
;
877 uint32_t fLocalSymbolsStartIndexInNewLinkEdit
;
878 uint32_t fLocalSymbolsCountInNewLinkEdit
;
879 uint32_t fExportedSymbolsStartIndexInNewLinkEdit
;
880 uint32_t fExportedSymbolsCountInNewLinkEdit
;
881 uint32_t fImportSymbolsStartIndexInNewLinkEdit
;
882 uint32_t fImportedSymbolsCountInNewLinkEdit
;
883 uint32_t fExternalRelocationsOffsetIntoNewLinkEdit
;
884 uint32_t fIndirectSymbolTableOffsetInfoNewLinkEdit
;
885 static int32_t fgLocalSymbolsStartIndexInNewLinkEdit
;
888 template <typename A
> int32_t LinkEditOptimizer
<A
>::fgLocalSymbolsStartIndexInNewLinkEdit
= 0;
891 template <typename A
>
892 LinkEditOptimizer
<A
>::LinkEditOptimizer(const MachOLayoutAbstraction
& layout
, uint8_t* newLinkEdit
, StringPool
& stringPool
)
893 : fLayout(layout
), fLinkEditBase(NULL
), fNewLinkEditStart(newLinkEdit
),
894 fDynamicSymbolTable(NULL
), fSymbolTableLoadCommand(NULL
), fSymbolTable(NULL
), fStrings(NULL
), fNewStringPool(stringPool
),
895 fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
896 fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
897 fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
898 fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0)
901 fHeader
= (const macho_header
<P
>*)fLayout
.getSegments()[0].mappedAddress();
903 const std::vector
<MachOLayoutAbstraction::Segment
>& segments
= fLayout
.getSegments();
904 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator it
= segments
.begin(); it
!= segments
.end(); ++it
) {
905 const MachOLayoutAbstraction::Segment
& seg
= *it
;
906 if ( strcmp(seg
.name(), "__LINKEDIT") == 0 )
907 fLinkEditBase
= (uint8_t*)seg
.mappedAddress() - seg
.fileOffset();
909 if ( fLinkEditBase
== NULL
)
910 throw "no __LINKEDIT segment";
912 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
913 const uint32_t cmd_count
= fHeader
->ncmds();
914 const macho_load_command
<P
>* cmd
= cmds
;
915 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
916 switch (cmd
->cmd()) {
919 fSymbolTableLoadCommand
= (macho_symtab_command
<P
>*)cmd
;
920 fSymbolTable
= (macho_nlist
<P
>*)(&fLinkEditBase
[fSymbolTableLoadCommand
->symoff()]);
921 fStrings
= (char*)&fLinkEditBase
[fSymbolTableLoadCommand
->stroff()];
925 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
928 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
930 if ( fSymbolTable
== NULL
)
931 throw "no LC_SYMTAB";
932 if ( fDynamicSymbolTable
== NULL
)
933 throw "no LC_DYSYMTAB";
938 template <typename A
>
942 typedef typename
A::P P
;
943 SymbolSorter(const StringPool
& pool
) : fStringPool(pool
) {}
944 bool operator()(const macho_nlist
<P
>& left
, const macho_nlist
<P
>& right
) {
945 return (strcmp(fStringPool
.stringAtIndex(left
.n_strx()) , fStringPool
.stringAtIndex(right
.n_strx())) < 0);
949 const StringPool
& fStringPool
;
953 template <typename A
>
954 void LinkEditOptimizer
<A
>::makeDummyLocalSymbol(uint32_t& symbolIndex
, uint8_t* storage
, StringPool
& pool
)
956 fgLocalSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
957 macho_nlist
<P
>* newSymbolEntry
= (macho_nlist
<P
>*)storage
;
958 newSymbolEntry
->set_n_strx(pool
.add("__no_local_symbols_in_dyld_shared_cache"));
959 newSymbolEntry
->set_n_type(N_SECT
);
960 newSymbolEntry
->set_n_sect(1);
961 newSymbolEntry
->set_n_desc(0);
962 newSymbolEntry
->set_n_value(0);
966 template <typename A
>
967 void LinkEditOptimizer
<A
>::copyLocalSymbols()
969 if ( fDynamicSymbolTable
->nlocalsym() > 0 ) {
970 // if image has any local symbols, make cache look like it has one local symbol
971 // which is actually shared by all images
972 fLocalSymbolsCountInNewLinkEdit
= 1;
973 fLocalSymbolsStartIndexInNewLinkEdit
= fgLocalSymbolsStartIndexInNewLinkEdit
;
978 template <typename A
>
979 void LinkEditOptimizer
<A
>::copyExportedSymbols(uint32_t& symbolIndex
)
981 fExportedSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
982 const macho_nlist
<P
>* const firstExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()];
983 const macho_nlist
<P
>* const lastExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
984 uint32_t oldIndex
= fDynamicSymbolTable
->iextdefsym();
985 for (const macho_nlist
<P
>* entry
= firstExport
; entry
< lastExport
; ++entry
, ++oldIndex
) {
986 if ( ((entry
->n_type() & N_TYPE
) == N_SECT
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0) ) {
987 macho_nlist
<P
>* newSymbolEntry
= &((macho_nlist
<P
>*)fNewLinkEditStart
)[symbolIndex
];
988 *newSymbolEntry
= *entry
;
989 newSymbolEntry
->set_n_strx(fNewStringPool
.add(&fStrings
[entry
->n_strx()]));
990 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
;
994 fExportedSymbolsCountInNewLinkEdit
= symbolIndex
- fExportedSymbolsStartIndexInNewLinkEdit
;
995 //fprintf(stderr, "%u exports starting at %u for %s\n", fExportedSymbolsCountInNewLinkEdit, fExportedSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
996 // sort by name, so that dyld does not need a toc
997 macho_nlist
<P
>* newSymbolsStart
= &((macho_nlist
<P
>*)fNewLinkEditStart
)[fExportedSymbolsStartIndexInNewLinkEdit
];
998 macho_nlist
<P
>* newSymbolsEnd
= &((macho_nlist
<P
>*)fNewLinkEditStart
)[fExportedSymbolsStartIndexInNewLinkEdit
+fExportedSymbolsCountInNewLinkEdit
];
999 std::sort(newSymbolsStart
, newSymbolsEnd
, SymbolSorter
<A
>(fNewStringPool
));
1000 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1001 // fprintf(stderr, "\t%u\t %s\n", (entry-newSymbolsStart)+fExportedSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1005 template <typename A
>
1006 void LinkEditOptimizer
<A
>::copyImportedSymbols(uint32_t& symbolIndex
)
1008 fImportSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1009 const macho_nlist
<P
>* const firstImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()];
1010 const macho_nlist
<P
>* const lastImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()+fDynamicSymbolTable
->nundefsym()];
1011 uint32_t oldIndex
= fDynamicSymbolTable
->iundefsym();
1012 for (const macho_nlist
<P
>* entry
= firstImport
; entry
< lastImport
; ++entry
, ++oldIndex
) {
1013 if ( ((entry
->n_type() & N_TYPE
) == N_UNDF
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0) ) {
1014 macho_nlist
<P
>* newSymbolEntry
= &((macho_nlist
<P
>*)fNewLinkEditStart
)[symbolIndex
];
1015 *newSymbolEntry
= *entry
;
1016 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1017 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
;
1021 fImportedSymbolsCountInNewLinkEdit
= symbolIndex
- fImportSymbolsStartIndexInNewLinkEdit
;
1022 //fprintf(stderr, "%u imports starting at %u for %s\n", fImportedSymbolsCountInNewLinkEdit, fImportSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1023 //macho_nlist<P>* newSymbolsStart = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit];
1024 //macho_nlist<P>* newSymbolsEnd = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit];
1025 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1026 // fprintf(stderr, "\t%u\t%s\n", (entry-newSymbolsStart)+fImportSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1030 template <typename A
>
1031 void LinkEditOptimizer
<A
>::copyExternalRelocations(uint32_t& offset
)
1033 fExternalRelocationsOffsetIntoNewLinkEdit
= offset
;
1034 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(&fLinkEditBase
[fDynamicSymbolTable
->extreloff()]);
1035 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
1036 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1037 macho_relocation_info
<P
>* newReloc
= (macho_relocation_info
<P
>*)(&fNewLinkEditStart
[offset
]);
1039 uint32_t newSymbolIndex
= fOldToNewSymbolIndexes
[reloc
->r_symbolnum()];
1040 //fprintf(stderr, "copyExternalRelocations() old=%d, new=%u name=%s in %s\n", reloc->r_symbolnum(), newSymbolIndex,
1041 // &fStrings[fSymbolTable[reloc->r_symbolnum()].n_strx()], fLayout.getFilePath());
1042 newReloc
->set_r_symbolnum(newSymbolIndex
);
1043 offset
+= sizeof(macho_relocation_info
<P
>);
1047 template <typename A
>
1048 void LinkEditOptimizer
<A
>::copyIndirectSymbolTable(uint32_t& offset
)
1050 fIndirectSymbolTableOffsetInfoNewLinkEdit
= offset
;
1051 const uint32_t* const indirectTable
= (uint32_t*)&this->fLinkEditBase
[fDynamicSymbolTable
->indirectsymoff()];
1052 uint32_t* newIndirectTable
= (uint32_t*)&fNewLinkEditStart
[offset
];
1053 for (int i
=0; i
< fDynamicSymbolTable
->nindirectsyms(); ++i
) {
1054 uint32_t oldSymbolIndex
= E::get32(indirectTable
[i
]);
1055 uint32_t newSymbolIndex
= oldSymbolIndex
;
1056 if ( (oldSymbolIndex
!= INDIRECT_SYMBOL_ABS
) && (oldSymbolIndex
!= INDIRECT_SYMBOL_LOCAL
) ) {
1057 newSymbolIndex
= fOldToNewSymbolIndexes
[oldSymbolIndex
];
1058 //fprintf(stderr, "copyIndirectSymbolTable() old=%d, new=%u name=%s in %s\n", oldSymbolIndex, newSymbolIndex,
1059 // &fStrings[fSymbolTable[oldSymbolIndex].n_strx()], fLayout.getFilePath());
1061 E::set32(newIndirectTable
[i
], newSymbolIndex
);
1063 offset
+= (fDynamicSymbolTable
->nindirectsyms() * 4);
1066 template <typename A
>
1067 void LinkEditOptimizer
<A
>::updateLoadCommands(uint64_t newVMAddress
, uint64_t size
, uint32_t stringPoolOffset
)
1069 // set LINKEDIT segment commmand to new merged LINKEDIT
1070 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
1071 const uint32_t cmd_count
= fHeader
->ncmds();
1072 const macho_load_command
<P
>* cmd
= cmds
;
1073 uint32_t linkEditStartFileOffset
= 0;
1074 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1075 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
1076 macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
1077 if ( strcmp(seg
->segname(), "__LINKEDIT") == 0 ) {
1078 seg
->set_vmaddr(newVMAddress
);
1079 seg
->set_vmsize(size
);
1080 seg
->set_filesize(size
);
1081 linkEditStartFileOffset
= seg
->fileoff();
1084 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1087 // update symbol table and dynamic symbol table with new offsets
1088 fSymbolTableLoadCommand
->set_symoff(linkEditStartFileOffset
);
1089 fSymbolTableLoadCommand
->set_nsyms(fExportedSymbolsCountInNewLinkEdit
+fImportedSymbolsCountInNewLinkEdit
);
1090 fSymbolTableLoadCommand
->set_stroff(linkEditStartFileOffset
+stringPoolOffset
);
1091 fSymbolTableLoadCommand
->set_strsize(fNewStringPool
.size());
1092 fDynamicSymbolTable
->set_ilocalsym(fLocalSymbolsStartIndexInNewLinkEdit
);
1093 fDynamicSymbolTable
->set_nlocalsym(fLocalSymbolsCountInNewLinkEdit
);
1094 fDynamicSymbolTable
->set_iextdefsym(fExportedSymbolsStartIndexInNewLinkEdit
);
1095 fDynamicSymbolTable
->set_nextdefsym(fExportedSymbolsCountInNewLinkEdit
);
1096 fDynamicSymbolTable
->set_iundefsym(fImportSymbolsStartIndexInNewLinkEdit
);
1097 fDynamicSymbolTable
->set_nundefsym(fImportedSymbolsCountInNewLinkEdit
);
1098 fDynamicSymbolTable
->set_tocoff(0);
1099 fDynamicSymbolTable
->set_ntoc(0);
1100 fDynamicSymbolTable
->set_modtaboff(0);
1101 fDynamicSymbolTable
->set_nmodtab(0);
1102 fDynamicSymbolTable
->set_indirectsymoff(linkEditStartFileOffset
+fIndirectSymbolTableOffsetInfoNewLinkEdit
);
1103 fDynamicSymbolTable
->set_extreloff(linkEditStartFileOffset
+fExternalRelocationsOffsetIntoNewLinkEdit
);
1104 fDynamicSymbolTable
->set_locreloff(0);
1105 fDynamicSymbolTable
->set_nlocrel(0);
1110 template <typename A
>
1111 uint8_t* SharedCache
<A
>::optimizeLINKEDIT()
1113 // allocate space for optimized LINKEDIT area
1114 uint8_t* newLinkEdit
= new uint8_t[fLinkEditsTotalUnoptimizedSize
];
1115 bzero(newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
1117 // make a string pool
1118 StringPool stringPool
;
1120 // create optimizer object for each LINKEDIT segment
1121 std::vector
<LinkEditOptimizer
<A
>*> optimizers
;
1122 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1123 optimizers
.push_back(new LinkEditOptimizer
<A
>(*it
->layout
, newLinkEdit
, stringPool
));
1126 // copy local symbol table entries
1127 uint32_t symbolTableIndex
= 0;
1128 LinkEditOptimizer
<A
>::makeDummyLocalSymbol(symbolTableIndex
, newLinkEdit
, stringPool
);
1129 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1130 (*it
)->copyLocalSymbols();
1133 // copy exported symbol table entries
1134 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1135 (*it
)->copyExportedSymbols(symbolTableIndex
);
1137 //fprintf(stderr, "%u exported symbols, with %d bytes of strings\n", symbolTableIndex, stringPool.size());
1138 //uint32_t importStart = symbolTableIndex;
1139 //uint32_t importPoolStart = stringPool.size();
1141 // copy imported symbol table entries
1142 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1143 (*it
)->copyImportedSymbols(symbolTableIndex
);
1145 //fprintf(stderr, "%u imported symbols, with %d bytes of strings\n", symbolTableIndex-importStart, stringPool.size()-importPoolStart);
1147 // copy external relocations, 8-byte aligned after end of symbol table
1148 uint32_t externalRelocsOffset
= (symbolTableIndex
* sizeof(macho_nlist
<typename
A::P
>) + 7) & (-8);
1149 //uint32_t externalRelocsStartOffset = externalRelocsOffset;
1150 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1151 (*it
)->copyExternalRelocations(externalRelocsOffset
);
1153 //fprintf(stderr, "%u bytes of external relocs\n", externalRelocsOffset-externalRelocsStartOffset);
1155 // copy indirect symbol tables
1156 uint32_t indirectSymbolTableOffset
= externalRelocsOffset
;
1157 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1158 (*it
)->copyIndirectSymbolTable(indirectSymbolTableOffset
);
1162 uint32_t stringPoolOffset
= indirectSymbolTableOffset
;
1163 memcpy(&newLinkEdit
[stringPoolOffset
], stringPool
.getBuffer(), stringPool
.size());
1166 uint32_t linkEditsTotalOptimizedSize
= (stringPoolOffset
+ stringPool
.size() + 4095) & (-4096);
1168 // update load commands so that all dylibs shared different areas of the same LINKEDIT segment
1169 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1170 (*it
)->updateLoadCommands(fLinkEditsStartAddress
, fLinkEditsTotalUnoptimizedSize
, stringPoolOffset
);
1173 //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, linkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, linkEditsTotalOptimizedSize);
1174 //fprintf(stderr, "mega link edit mapped starting at: %p\n", fFirstLinkEditSegment->mappedAddress());
1176 // overwrite mapped LINKEDIT area with new optimized LINKEDIT segment
1177 memcpy(fFirstLinkEditSegment
->mappedAddress(), newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
1179 // update all LINKEDIT Segment objects to point to same merged LINKEDIT area
1180 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1181 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1182 for(int i
=0; i
< segs
.size(); ++i
) {
1183 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1184 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
1185 seg
.setNewAddress(fLinkEditsStartAddress
);
1186 seg
.setMappedAddress(fFirstLinkEditSegment
->mappedAddress());
1187 seg
.setSize(linkEditsTotalOptimizedSize
);
1188 seg
.setFileSize(linkEditsTotalOptimizedSize
);
1189 //seg.setFileOffset(0);
1194 // return new end of cache
1195 return (uint8_t*)fFirstLinkEditSegment
->mappedAddress() + linkEditsTotalOptimizedSize
;
1199 static const char* sCleanupFile
= NULL
;
1200 static void cleanup(int sig
)
1202 ::signal(sig
, SIG_DFL
);
1203 if ( sCleanupFile
!= NULL
)
1204 ::unlink(sCleanupFile
);
1206 // fprintf(stderr, "update_dyld_shared_cache: deleting temp file in response to a signal\n");
1207 if ( sig
== SIGINT
)
1212 template <typename A
>
1213 bool SharedCache
<A
>::update(const char* rootPath
, const char* cacheDir
, bool force
, bool optimize
, bool deleteExistingFirst
, int archIndex
, int archCount
)
1215 bool didUpdate
= false;
1216 char cachePath
[1024];
1217 strcpy(cachePath
, rootPath
);
1218 strcat(cachePath
, cacheDir
);
1219 strcat(cachePath
, DYLD_SHARED_CACHE_BASE_NAME
);
1220 strcat(cachePath
, filename(optimize
));
1222 // already up to date?
1223 if ( force
|| this->notUpToDate(cachePath
) ) {
1225 fprintf(stderr
, "update_dyld_shared_cache: regenerating %s\n", cachePath
);
1226 if ( fDylibs
.size() == 0 ) {
1227 fprintf(stderr
, "update_dyld_shared_cache: warning, empty cache not generated for arch %s\n", archName());
1230 // delete existing cache while building the new one
1231 // this is a flag to dyld to stop pinging update_dyld_shared_cache
1232 if ( deleteExistingFirst
)
1233 ::unlink(cachePath
);
1234 uint8_t* inMemoryCache
= NULL
;
1235 uint32_t allocatedCacheSize
= 0;
1236 char tempCachePath
[strlen(cachePath
)+16];
1237 sprintf(tempCachePath
, "%s.tmp%u", cachePath
, getpid());
1239 // allocate a memory block to hold cache
1240 uint32_t cacheFileSize
= 0;
1241 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1242 uint32_t end
= it
->sfm_file_offset
+ it
->sfm_size
;
1243 if ( end
> cacheFileSize
)
1244 cacheFileSize
= end
;
1246 if ( vm_allocate(mach_task_self(), (vm_address_t
*)(&inMemoryCache
), cacheFileSize
, VM_FLAGS_ANYWHERE
) != KERN_SUCCESS
)
1247 throwf("can't vm_allocate cache of size %u", cacheFileSize
);
1248 allocatedCacheSize
= cacheFileSize
;
1251 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)inMemoryCache
;
1253 strcpy(temp
, "dyld_v1 ");
1254 strcpy(&temp
[15-strlen(archName())], archName());
1255 header
->set_magic(temp
);
1256 //header->set_architecture(arch());
1257 header
->set_mappingOffset(sizeof(dyldCacheHeader
<E
>));
1258 header
->set_mappingCount(fMappings
.size());
1259 header
->set_imagesOffset(header
->mappingOffset() + fMappings
.size()*sizeof(dyldCacheFileMapping
<E
>));
1260 header
->set_imagesCount(fDylibs
.size());
1261 header
->set_dyldBaseAddress(fDyldBaseAddress
);
1262 //header->set_dependenciesOffset(sizeof(dyldCacheHeader<E>) + fMappings.size()*sizeof(dyldCacheFileMapping<E>) + fDylibs.size()*sizeof(dyldCacheImageInfo<E>));
1263 //header->set_dependenciesCount(fDependencyPool.size());
1266 dyldCacheFileMapping
<E
>* mapping
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
1267 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1269 fprintf(stderr
, "update_dyld_shared_cache: cache mappings: address=0x%0llX, size=0x%0llX, fileOffset=0x%0llX, prot=0x%X\n",
1270 it
->sfm_address
, it
->sfm_size
, it
->sfm_file_offset
, it
->sfm_init_prot
);
1271 mapping
->set_address(it
->sfm_address
);
1272 mapping
->set_size(it
->sfm_size
);
1273 mapping
->set_file_offset(it
->sfm_file_offset
);
1274 mapping
->set_max_prot(it
->sfm_max_prot
);
1275 mapping
->set_init_prot(it
->sfm_init_prot
);
1279 // fill in image table
1280 dyldCacheImageInfo
<E
>* image
= (dyldCacheImageInfo
<E
>*)mapping
;
1281 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1282 image
->set_address(it
->info
.address
);
1283 image
->set_modTime(it
->info
.modTime
);
1284 image
->set_inode(it
->info
.inode
);
1285 image
->set_pathFileOffset(cacheFileOffsetForAddress(it
->info
.address
+it
->info
.pathFileOffset
));
1286 //image->set_dependenciesStartOffset(it->info.dependenciesStartOffset);
1290 // copy each segment to cache buffer
1292 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++dylibIndex
) {
1293 const char* path
= it
->layout
->getFilePath();
1294 int src
= ::open(path
, O_RDONLY
, 0);
1296 throwf("can't open file %s, errnor=%d", it
->layout
->getID().name
, errno
);
1297 // mark source as "don't cache"
1298 (void)fcntl(src
, F_NOCACHE
, 1);
1299 // verify file has not changed since dependency analysis
1300 struct stat stat_buf
;
1301 if ( fstat(src
, &stat_buf
) == -1)
1302 throwf("can't stat open file %s, errno=%d", path
, errno
);
1303 if ( (it
->layout
->getInode() != stat_buf
.st_ino
) || (it
->layout
->getLastModTime() != stat_buf
.st_mtime
) )
1304 throwf("aborting because OS dylib modified during cache creation: %s", path
);
1307 fprintf(stderr
, "update_dyld_shared_cache: copying %s to cache\n", it
->layout
->getID().name
);
1309 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
1310 for (int i
=0; i
< segs
.size(); ++i
) {
1311 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1313 fprintf(stderr
, "\t\tsegment %s, size=0x%0llX, cache address=0x%0llX\n", seg
.name(), seg
.fileSize(), seg
.newAddress());
1314 if ( seg
.size() > 0 ) {
1315 const uint64_t segmentSrcStartOffset
= it
->layout
->getOffsetInUniversalFile()+seg
.fileOffset();
1316 const uint64_t segmentSize
= seg
.fileSize();
1317 const uint64_t segmentDstStartOffset
= cacheFileOffsetForAddress(seg
.newAddress());
1318 ssize_t readResult
= ::pread(src
, &inMemoryCache
[segmentDstStartOffset
], segmentSize
, segmentSrcStartOffset
);
1319 if ( readResult
!= segmentSize
)
1320 if ( readResult
== -1 )
1321 throwf("read failure copying dylib errno=%d for %s", errno
, it
->layout
->getID().name
);
1323 throwf("read failure copying dylib. Read of %lld bytes at file offset %lld returned %ld for %s",
1324 segmentSize
, segmentSrcStartOffset
, readResult
, it
->layout
->getID().name
);
1325 // verify __TEXT segment has no zeroed out pages
1326 if ( strcmp(seg
.name(), "__TEXT") == 0 ) {
1327 // only scan first 128KB. Some OS dylibs have zero filled TEXT pages later in __const...
1328 int scanEnd
= segmentSize
;
1329 if ( scanEnd
> 0x20000 )
1331 for (int pageOffset
= 0; pageOffset
< scanEnd
; pageOffset
+= 4096) {
1332 const uint32_t* page
= (uint32_t*)(&inMemoryCache
[segmentDstStartOffset
+pageOffset
]);
1333 bool foundNonZero
= false;
1334 for(int p
=0; p
< 1024; ++p
) {
1335 if ( page
[p
] != 0 ) {
1336 //fprintf(stderr, "found non-zero at pageOffset=0x%08X, p=0x%08X in memory=%p for %s\n", pageOffset, p, page, it->layout->getID().name);
1337 foundNonZero
= true;
1341 if ( !foundNonZero
)
1342 throwf("suspected bad read. Found __TEXT segment page at offset 0x%08X that is all zeros for %s in %s", pageOffset
, archName(), it
->layout
->getID().name
);
1348 catch (const char* msg
) {
1349 throwf("%s while copying %s to shared cache", msg
, it
->layout
->getID().name
);
1354 // set mapped address for each segment
1355 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1356 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1357 for (int i
=0; i
< segs
.size(); ++i
) {
1358 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1359 if ( seg
.size() > 0 )
1360 seg
.setMappedAddress(inMemoryCache
+ cacheFileOffsetForAddress(seg
.newAddress()));
1361 //fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
1365 // rebase each dylib in shared cache
1366 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1368 Rebaser
<A
> r(*it
->layout
);
1371 // fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
1373 catch (const char* msg
) {
1374 throwf("%s in %s", msg
, it
->layout
->getID().name
);
1378 // merge/optimize all LINKEDIT segments
1380 //fprintf(stderr, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize/(1024*1024));
1381 cacheFileSize
= (this->optimizeLINKEDIT() - inMemoryCache
);
1382 //fprintf(stderr, "update_dyld_shared_cache: optimized cache file size %uMB\n", cacheFileSize/(1024*1024));
1383 // update header to reduce mapping size
1384 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
1385 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
1386 dyldCacheFileMapping
<E
>* lastMapping
= &mappings
[cacheHeader
->mappingCount()-1];
1387 lastMapping
->set_size(cacheFileSize
-lastMapping
->file_offset());
1388 // update fMappings so .map file will print correctly
1389 fMappings
.back().sfm_size
= cacheFileSize
-fMappings
.back().sfm_file_offset
;
1393 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs
.size());
1394 // instantiate a Binder for each image and add to map
1395 typename Binder
<A
>::Map map
;
1396 std::vector
<Binder
<A
>*> binders
;
1397 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1398 //fprintf(stderr, "binding %s\n", it->layout->getID().name);
1399 Binder
<A
>* binder
= new Binder
<A
>(*it
->layout
, fDyldBaseAddress
);
1400 binders
.push_back(binder
);
1401 // only add dylibs to map
1402 if ( it
->layout
->getID().name
!= NULL
)
1403 map
[it
->layout
->getID().name
] = binder
;
1405 // tell each Binder about the others
1406 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
1407 (*it
)->setDependentBinders(map
);
1410 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
1412 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it
)->getDylibID());
1416 catch (const char* msg
) {
1417 throwf("%s in %s", msg
, (*it
)->getDylibID());
1421 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
1425 // install signal handlers to delete temp file if program is killed
1426 sCleanupFile
= tempCachePath
;
1427 ::signal(SIGINT
, cleanup
);
1428 ::signal(SIGBUS
, cleanup
);
1429 ::signal(SIGSEGV
, cleanup
);
1431 // create temp file for cache
1432 int fd
= ::open(tempCachePath
, O_CREAT
| O_RDWR
| O_TRUNC
, 0644);
1434 throwf("can't create temp file %s, errnor=%d", tempCachePath
, errno
);
1436 // try to allocate whole cache file contiguously
1437 fstore_t fcntlSpec
= { F_ALLOCATECONTIG
|F_ALLOCATEALL
, F_PEOFPOSMODE
, 0, cacheFileSize
, 0 };
1438 ::fcntl(fd
, F_PREALLOCATE
, &fcntlSpec
);
1440 // write out cache file
1442 fprintf(stderr
, "update_dyld_shared_cache: writing cache to disk\n");
1443 if ( ::pwrite(fd
, inMemoryCache
, cacheFileSize
, 0) != cacheFileSize
)
1444 throwf("write() failure creating cache file, errno=%d", errno
);
1446 // flush to disk and close
1447 int result
= ::fcntl(fd
, F_FULLFSYNC
, NULL
);
1449 fprintf(stderr
, "update_dyld_shared_cache: warning, fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno
, tempCachePath
);
1450 result
= ::close(fd
);
1452 fprintf(stderr
, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno
, tempCachePath
);
1454 // atomically swap in new cache file, do this after F_FULLFSYNC
1455 result
= ::rename(tempCachePath
, cachePath
);
1457 throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath
, cachePath
, errno
);
1459 // flush everything to disk to assure rename() gets recorded
1463 // restore default signal handlers
1464 ::signal(SIGINT
, SIG_DFL
);
1465 ::signal(SIGBUS
, SIG_DFL
);
1466 ::signal(SIGSEGV
, SIG_DFL
);
1468 // generate human readable "map" file that shows the layout of the cache file
1470 fprintf(stderr
, "update_dyld_shared_cache: writing .map file to disk\n");
1471 sprintf(tempCachePath
, "%s.map", cachePath
);// re-use path buffer
1472 FILE* fmap
= ::fopen(tempCachePath
, "w");
1473 if ( fmap
== NULL
) {
1474 fprintf(stderr
, "can't create map file %s, errnor=%d", tempCachePath
, errno
);
1477 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1478 const char* prot
= "RW";
1479 if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_READ
) )
1481 else if ( it
->sfm_init_prot
== VM_PROT_READ
)
1483 else if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_WRITE
|VM_PROT_READ
) )
1485 if ( it
->sfm_size
> 1024*1024 )
1486 fprintf(fmap
, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/(1024*1024),
1487 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
1489 fprintf(fmap
, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/1024,
1490 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
1492 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1493 fprintf(fmap
, "%s\n", it
->layout
->getID().name
);
1494 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
1495 for (int i
=0; i
< segs
.size(); ++i
) {
1496 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1497 fprintf(fmap
, "\t%16s 0x%0llX -> 0x%0llX\n", seg
.name(), seg
.newAddress(), seg
.newAddress()+seg
.size());
1500 if ( warnings
.size() > 0 ) {
1501 fprintf(fmap
, "# Warnings:\n");
1502 for (std::vector
<const char*>::iterator it
=warnings
.begin(); it
!= warnings
.end(); ++it
) {
1503 fprintf(fmap
, "# %s\n", *it
);
1509 // free in memory cache
1510 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
1511 inMemoryCache
= NULL
;
1514 // remove temp cache file
1515 ::unlink(tempCachePath
);
1516 // remove in memory cache
1517 if ( inMemoryCache
!= NULL
)
1518 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
1528 // The shared cache is driven by /var/db/dyld/shared_region_roots which contains
1529 // the paths used to search for dylibs that should go in the shared cache
1531 // Leading and trailing white space is ignored
1532 // Blank lines are ignored
1533 // Lines starting with # are ignored
1535 static void parsePathsFile(const char* filePath
, std::vector
<const char*>& paths
)
1537 // read in whole file
1538 int fd
= open(filePath
, O_RDONLY
, 0);
1540 fprintf(stderr
, "update_dyld_shared_cache: can't open file: %s\n", filePath
);
1543 struct stat stat_buf
;
1544 fstat(fd
, &stat_buf
);
1545 char* p
= (char*)malloc(stat_buf
.st_size
);
1547 fprintf(stderr
, "update_dyld_shared_cache: malloc failure\n");
1550 if ( read(fd
, p
, stat_buf
.st_size
) != stat_buf
.st_size
) {
1551 fprintf(stderr
, "update_dyld_shared_cache: can't read file: %s\n", filePath
);
1556 // parse into paths and add to vector
1557 char * const end
= &p
[stat_buf
.st_size
];
1558 enum { lineStart
, inSymbol
, inComment
} state
= lineStart
;
1559 char* symbolStart
= NULL
;
1560 for (char* s
= p
; s
< end
; ++s
) {
1566 else if ( !isspace(*s
) ) {
1574 // removing any trailing spaces
1576 while ( isspace(*last
) ) {
1580 paths
.push_back(symbolStart
);
1591 // Note: we do not free() the malloc buffer, because the strings in it are used by exec()
1595 static void scanForSharedDylibs(const char* rootPath
, const char* dirOfPathFiles
, const std::set
<cpu_type_t
>& onlyArchs
)
1597 char rootDirOfPathFiles
[strlen(rootPath
)+strlen(dirOfPathFiles
)+2];
1598 if ( strlen(rootPath
) != 0 ) {
1599 strcpy(rootDirOfPathFiles
, rootPath
);
1600 strcat(rootDirOfPathFiles
, dirOfPathFiles
);
1601 dirOfPathFiles
= rootDirOfPathFiles
;
1604 // extract all root paths from files in "/var/db/dyld/shared_region_roots/"
1606 fprintf(stderr
, "update_dyld_shared_cache: finding roots in: %s\n", dirOfPathFiles
);
1607 std::vector
<const char*> rootsPaths
;
1608 DIR* dir
= ::opendir(dirOfPathFiles
);
1610 throwf("%s does not exist, errno=%d\n", dirOfPathFiles
, errno
);
1611 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
1612 if ( entry
->d_type
== DT_REG
) {
1613 // only look at files ending in .paths
1614 if ( strcmp(&entry
->d_name
[entry
->d_namlen
-6], ".paths") == 0 ) {
1615 char fullPath
[strlen(dirOfPathFiles
)+entry
->d_namlen
+2];
1616 strcpy(fullPath
, dirOfPathFiles
);
1617 strcat(fullPath
, "/");
1618 strcat(fullPath
, entry
->d_name
);
1619 parsePathsFile(fullPath
, rootsPaths
);
1622 fprintf(stderr
, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry
->d_name
);
1628 // set file system root
1629 ArchGraph::setFileSystemRoot(rootPath
);
1631 // initialize all architectures requested
1632 for(std::set
<cpu_type_t
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
1633 ArchGraph::addArch(*a
);
1635 // add roots to graph
1636 for(std::vector
<const char*>::iterator it
= rootsPaths
.begin(); it
!= rootsPaths
.end(); ++it
)
1637 ArchGraph::addRoot(*it
, onlyArchs
);
1639 // determine shared dylibs
1640 for(std::set
<cpu_type_t
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
1641 ArchGraph::findSharedDylibs(*a
);
1643 if ( rootsPaths
.size() == 0 )
1644 fprintf(stderr
, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
1648 // If the 10.5.0 version of update_dyld_shared_cache was killed or crashed, it
1649 // could leave large half written cache files laying around. The function deletes
1650 // those files. To prevent the deletion of tmp files being created by another
1651 // copy of update_dyld_shared_cache, it only deletes the temp cache file if its
1652 // creation time was before the last restart of this machine.
1653 static void deleteOrphanTempCacheFiles()
1655 DIR* dir
= ::opendir(DYLD_SHARED_CACHE_DIR
);
1656 if ( dir
!= NULL
) {
1657 std::vector
<const char*> filesToDelete
;
1658 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
1659 if ( entry
->d_type
== DT_REG
) {
1660 // only look at files with .tmp in name
1661 if ( strstr(entry
->d_name
, ".tmp") != NULL
) {
1662 char fullPath
[strlen(DYLD_SHARED_CACHE_DIR
)+entry
->d_namlen
+2];
1663 strcpy(fullPath
, DYLD_SHARED_CACHE_DIR
);
1664 strcat(fullPath
, "/");
1665 strcat(fullPath
, entry
->d_name
);
1666 struct stat tmpFileStatInfo
;
1667 if ( stat(fullPath
, &tmpFileStatInfo
) != -1 ) {
1668 int mib
[2] = {CTL_KERN
, KERN_BOOTTIME
};
1669 struct timeval boottime
;
1670 size_t size
= sizeof(boottime
);
1671 if ( (sysctl(mib
, 2, &boottime
, &size
, NULL
, 0) != -1) && (boottime
.tv_sec
!= 0) ) {
1672 // make sure this file is older than the boot time of this machine
1673 if ( tmpFileStatInfo
.st_mtime
< boottime
.tv_sec
) {
1674 filesToDelete
.push_back(strdup(fullPath
));
1682 for(std::vector
<const char*>::iterator it
= filesToDelete
.begin(); it
!= filesToDelete
.end(); ++it
) {
1683 fprintf(stderr
, "update_dyld_shared_cache: deleting old temp cache file: %s\n", *it
);
1691 static bool updateSharedeCacheFile(const char* rootPath
, const char* cacheDir
, const std::set
<cpu_type_t
>& onlyArchs
,
1692 bool force
, bool alphaSort
, bool optimize
, bool deleteExistingFirst
)
1694 bool didUpdate
= false;
1695 // get dyld load address info
1696 UniversalMachOLayout
* dyldLayout
= new UniversalMachOLayout("/usr/lib/dyld", &onlyArchs
);
1698 const int archCount
= onlyArchs
.size();
1700 for(std::set
<cpu_type_t
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
, ++index
) {
1701 const MachOLayoutAbstraction
* dyldLayoutForArch
= dyldLayout
->getArch(*a
);
1702 if ( dyldLayoutForArch
== NULL
)
1703 throw "dyld not avaiable for specified architecture";
1704 uint64_t dyldBaseAddress
= dyldLayoutForArch
->getBaseAddress();
1706 case CPU_TYPE_POWERPC
:
1708 SharedCache
<ppc
> cache(ArchGraph::getArch(*a
), alphaSort
, dyldBaseAddress
);
1710 // <rdar://problem/5217377> Rosetta does not work with optimized dyld shared cache
1711 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, false, deleteExistingFirst
, index
, archCount
);
1713 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, optimize
, deleteExistingFirst
, index
, archCount
);
1717 case CPU_TYPE_POWERPC64
:
1719 SharedCache
<ppc64
> cache(ArchGraph::getArch(*a
), alphaSort
, dyldBaseAddress
);
1720 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, optimize
, deleteExistingFirst
, index
, archCount
);
1725 SharedCache
<x86
> cache(ArchGraph::getArch(*a
), alphaSort
, dyldBaseAddress
);
1726 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, optimize
, deleteExistingFirst
, index
, archCount
);
1729 case CPU_TYPE_X86_64
:
1731 SharedCache
<x86_64
> cache(ArchGraph::getArch(*a
), alphaSort
, dyldBaseAddress
);
1732 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, optimize
, deleteExistingFirst
, index
, archCount
);
1738 deleteOrphanTempCacheFiles();
1746 fprintf(stderr
, "update_dyld_shared_cache [-force] [-root dir] [-arch arch] [-debug]\n");
1749 // flag so that we only update cache once per invocation
1750 static bool doNothingAndDrainQueue
= false;
1752 static kern_return_t
do_update_cache(cpu_type_t arch
, bool deleteExistingCacheFileFirst
)
1754 if ( !doNothingAndDrainQueue
) {
1755 std::set
<cpu_type_t
> onlyArchs
;
1756 onlyArchs
.insert(arch
);
1758 scanForSharedDylibs("", "/var/db/dyld/shared_region_roots/", onlyArchs
);
1759 if ( updateSharedeCacheFile("", DYLD_SHARED_CACHE_DIR
, onlyArchs
, false, false, true, deleteExistingCacheFileFirst
) )
1760 fprintf(stderr
, "update_dyld_shared_cache[%u] regenerated cache for arch=%s\n", getpid(), ArchGraph::archName(arch
));
1762 catch (const char* msg
) {
1763 fprintf(stderr
, "update_dyld_shared_cache[%u] for arch=%s failed: %s\n", getpid(), ArchGraph::archName(arch
), msg
);
1764 return KERN_FAILURE
;
1766 // <rdar://problem/6378354> only build one cache file per life of process
1767 doNothingAndDrainQueue
= true;
1769 return KERN_SUCCESS
;
1774 kern_return_t
do_dyld_shared_cache_missing(mach_port_t dyld_port
, cpu_type_t arch
)
1776 return do_update_cache(arch
, false);
1780 kern_return_t
do_dyld_shared_cache_out_of_date(mach_port_t dyld_port
, cpu_type_t arch
)
1782 // If cache exists but is out of date, delete the file while building the new one.
1783 // This will stop dyld from pinging update_dyld_share_cache while the cache is being built.
1784 return do_update_cache(arch
, true);
1788 int main(int argc
, const char* argv
[])
1791 if ( bootstrap_check_in(bootstrap_port
, "com.apple.dyld", &mp
) == KERN_SUCCESS
) {
1792 // started by launchd
1793 mach_msg_size_t mxmsgsz
= sizeof(union __RequestUnion__do_dyld_server_subsystem
) + MAX_TRAILER_SIZE
;
1794 doNothingAndDrainQueue
= false;
1795 while ( mach_msg_server(dyld_server_server
, mxmsgsz
, mp
, MACH_RCV_TIMEOUT
) == KERN_SUCCESS
) {
1796 // keep processing messages
1797 doNothingAndDrainQueue
= true;
1798 // but set flag so work is no longer done.
1799 // This is because the rest of the tool leaks and processing more than once
1800 // can hog system resources: <rdar://problem/5392427> 9A516 - Keep getting disk full errors
1801 // We drain the queue of messages because there is usually are a couple of duplicate messages.
1802 // It is ok to miss some messages. If the cache is out of date or missing, some new process
1803 // will discover it and send another message.
1808 // started as command line tool
1809 std::set
<cpu_type_t
> onlyArchs
;
1810 const char* rootPath
= "";
1812 bool alphaSort
= false;
1813 bool optimize
= true;
1814 bool makeSymLink
= false;
1817 // parse command line options
1818 for(int i
=1; i
< argc
; ++i
) {
1819 const char* arg
= argv
[i
];
1820 if ( arg
[0] == '-' ) {
1821 if ( strcmp(arg
, "-debug") == 0 ) {
1824 else if ( strcmp(arg
, "-force") == 0 ) {
1827 else if ( strcmp(arg
, "-sort_by_name") == 0 ) {
1830 else if ( strcmp(arg
, "-opt") == 0 ) {
1833 else if ( strcmp(arg
, "-no_opt") == 0 ) {
1836 else if ( (strcmp(arg
, "-root") == 0) || (strcmp(arg
, "--root") == 0) ) {
1837 rootPath
= argv
[++i
];
1838 if ( rootPath
== NULL
)
1839 throw "-root missing path argument";
1840 // strip tailing slashes
1841 int len
= strlen(rootPath
)-1;
1842 if ( rootPath
[len
] == '/' ) {
1843 char* newRootPath
= strdup(rootPath
);
1844 while ( newRootPath
[len
] == '/' )
1845 newRootPath
[len
--] = '\0';
1846 rootPath
= newRootPath
;
1849 else if ( strcmp(arg
, "-arch") == 0 ) {
1850 const char* arch
= argv
[++i
];
1851 if ( strcmp(arch
, "ppc") == 0 )
1852 onlyArchs
.insert(CPU_TYPE_POWERPC
);
1853 else if ( strcmp(arch
, "ppc64") == 0 )
1854 onlyArchs
.insert(CPU_TYPE_POWERPC64
);
1855 else if ( strcmp(arch
, "i386") == 0 )
1856 onlyArchs
.insert(CPU_TYPE_I386
);
1857 else if ( strcmp(arch
, "x86_64") == 0 )
1858 onlyArchs
.insert(CPU_TYPE_X86_64
);
1860 throwf("unknown architecture %s", arch
);
1862 else if ( strcmp(arg
, "-universal_boot") == 0 ) {
1864 throwf("universal_boot option can only be used on Intel machines");
1866 onlyArchs
.insert(CPU_TYPE_POWERPC
);
1867 onlyArchs
.insert(CPU_TYPE_I386
);
1872 throwf("unknown option: %s\n", arg
);
1877 throwf("unknown option: %s\n", arg
);
1881 // if no restrictions specified, use architectures that work on this machine
1882 if ( onlyArchs
.size() == 0 ) {
1884 size_t len
= sizeof(int);
1886 onlyArchs
.insert(CPU_TYPE_POWERPC
);
1887 if ( (sysctlbyname("hw.optional.64bitops", &available
, &len
, NULL
, 0) == 0) && available
)
1888 onlyArchs
.insert(CPU_TYPE_POWERPC64
);
1890 onlyArchs
.insert(CPU_TYPE_I386
);
1891 onlyArchs
.insert(CPU_TYPE_POWERPC
); // assume rosetta always available
1892 if ( (sysctlbyname("hw.optional.x86_64", &available
, &len
, NULL
, 0) == 0) && available
)
1893 onlyArchs
.insert(CPU_TYPE_X86_64
);
1895 #error unknown architecture
1899 if ( geteuid() != 0 )
1900 throw "you must be root to run this tool";
1902 // build list of shared dylibs
1903 scanForSharedDylibs(rootPath
, "/var/db/dyld/shared_region_roots/", onlyArchs
);
1904 updateSharedeCacheFile(rootPath
, DYLD_SHARED_CACHE_DIR
, onlyArchs
, force
, alphaSort
, optimize
, false);
1906 // To make a universal bootable image with dyld caches,
1907 // build the rosetta cache and symlink ppc to point to it.
1908 // A rosetta cache is just an unoptimized ppc cache, so ppc machine can use it too.
1909 // rdar://problem/5498469
1910 if ( makeSymLink
) {
1911 char symLinkLocation
[1024];
1912 strcpy(symLinkLocation
, rootPath
);
1913 strcat(symLinkLocation
, DYLD_SHARED_CACHE_DIR
);
1914 strcat(symLinkLocation
, DYLD_SHARED_CACHE_BASE_NAME
);
1915 strcat(symLinkLocation
, SharedCache
<ppc
>::filename(true));
1916 char symLinkTarget
[1024];
1917 strcpy(symLinkTarget
, DYLD_SHARED_CACHE_BASE_NAME
);
1918 strcat(symLinkTarget
, SharedCache
<ppc
>::filename(false));
1919 if ( symlink(symLinkTarget
, symLinkLocation
) == -1 ) {
1920 if ( errno
!= EEXIST
)
1921 throwf("symlink() returned errno=%d", errno
);
1925 catch (const char* msg
) {
1926 fprintf(stderr
, "update_dyld_shared_cache failed: %s\n", msg
);