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);
1301 fprintf(stderr
, "update_dyld_shared_cache: copying %s to cache\n", it
->layout
->getID().name
);
1303 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
1304 for (int i
=0; i
< segs
.size(); ++i
) {
1305 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1307 fprintf(stderr
, "\t\tsegment %s, size=0x%0llX, cache address=0x%0llX\n", seg
.name(), seg
.fileSize(), seg
.newAddress());
1308 if ( seg
.size() > 0 ) {
1309 const uint64_t segmentSrcStartOffset
= it
->layout
->getOffsetInUniversalFile()+seg
.fileOffset();
1310 const uint64_t segmentSize
= seg
.fileSize();
1311 const uint64_t segmentDstStartOffset
= cacheFileOffsetForAddress(seg
.newAddress());
1312 if ( ::pread(src
, &inMemoryCache
[segmentDstStartOffset
], segmentSize
, segmentSrcStartOffset
) != segmentSize
)
1313 throwf("read failure copying dylib errno=%d for %s", errno
, it
->layout
->getID().name
);
1317 catch (const char* msg
) {
1318 throwf("%s while copying %s to shared cache", msg
, it
->layout
->getID().name
);
1323 // set mapped address for each segment
1324 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1325 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1326 for (int i
=0; i
< segs
.size(); ++i
) {
1327 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1328 if ( seg
.size() > 0 )
1329 seg
.setMappedAddress(inMemoryCache
+ cacheFileOffsetForAddress(seg
.newAddress()));
1330 //fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
1334 // rebase each dylib in shared cache
1335 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1337 Rebaser
<A
> r(*it
->layout
);
1340 // fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
1342 catch (const char* msg
) {
1343 throwf("%s in %s", msg
, it
->layout
->getID().name
);
1347 // merge/optimize all LINKEDIT segments
1349 //fprintf(stderr, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize/(1024*1024));
1350 cacheFileSize
= (this->optimizeLINKEDIT() - inMemoryCache
);
1351 //fprintf(stderr, "update_dyld_shared_cache: optimized cache file size %uMB\n", cacheFileSize/(1024*1024));
1352 // update header to reduce mapping size
1353 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
1354 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
1355 dyldCacheFileMapping
<E
>* lastMapping
= &mappings
[cacheHeader
->mappingCount()-1];
1356 lastMapping
->set_size(cacheFileSize
-lastMapping
->file_offset());
1357 // update fMappings so .map file will print correctly
1358 fMappings
.back().sfm_size
= cacheFileSize
-fMappings
.back().sfm_file_offset
;
1362 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs
.size());
1363 // instantiate a Binder for each image and add to map
1364 typename Binder
<A
>::Map map
;
1365 std::vector
<Binder
<A
>*> binders
;
1366 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1367 //fprintf(stderr, "binding %s\n", it->layout->getID().name);
1368 Binder
<A
>* binder
= new Binder
<A
>(*it
->layout
, fDyldBaseAddress
);
1369 binders
.push_back(binder
);
1370 // only add dylibs to map
1371 if ( it
->layout
->getID().name
!= NULL
)
1372 map
[it
->layout
->getID().name
] = binder
;
1374 // tell each Binder about the others
1375 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
1376 (*it
)->setDependentBinders(map
);
1379 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
1381 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it
)->getDylibID());
1385 catch (const char* msg
) {
1386 throwf("%s in %s", msg
, (*it
)->getDylibID());
1390 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
1394 // install signal handlers to delete temp file if program is killed
1395 sCleanupFile
= tempCachePath
;
1396 ::signal(SIGINT
, cleanup
);
1397 ::signal(SIGBUS
, cleanup
);
1398 ::signal(SIGSEGV
, cleanup
);
1400 // create temp file for cache
1401 int fd
= ::open(tempCachePath
, O_CREAT
| O_RDWR
| O_TRUNC
, 0644);
1403 throwf("can't create temp file %s, errnor=%d", tempCachePath
, errno
);
1405 // try to allocate whole cache file contiguously
1406 fstore_t fcntlSpec
= { F_ALLOCATECONTIG
|F_ALLOCATEALL
, F_PEOFPOSMODE
, 0, cacheFileSize
, 0 };
1407 ::fcntl(fd
, F_PREALLOCATE
, &fcntlSpec
);
1409 // write out cache file
1411 fprintf(stderr
, "update_dyld_shared_cache: writing cache to disk\n");
1412 if ( ::pwrite(fd
, inMemoryCache
, cacheFileSize
, 0) != cacheFileSize
)
1413 throwf("write() failure creating cache file, errno=%d", errno
);
1415 // flush to disk and close
1416 int result
= ::fcntl(fd
, F_FULLFSYNC
, NULL
);
1418 fprintf(stderr
, "update_dyld_shared_cache: warning, fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno
, tempCachePath
);
1419 result
= ::close(fd
);
1421 fprintf(stderr
, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno
, tempCachePath
);
1423 // atomically swap in new cache file, do this after F_FULLFSYNC
1424 result
= ::rename(tempCachePath
, cachePath
);
1426 throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath
, cachePath
, errno
);
1428 // flush everything to disk to assure rename() gets recorded
1432 // restore default signal handlers
1433 ::signal(SIGINT
, SIG_DFL
);
1434 ::signal(SIGBUS
, SIG_DFL
);
1435 ::signal(SIGSEGV
, SIG_DFL
);
1437 // generate human readable "map" file that shows the layout of the cache file
1439 fprintf(stderr
, "update_dyld_shared_cache: writing .map file to disk\n");
1440 sprintf(tempCachePath
, "%s.map", cachePath
);// re-use path buffer
1441 FILE* fmap
= ::fopen(tempCachePath
, "w");
1442 if ( fmap
== NULL
) {
1443 fprintf(stderr
, "can't create map file %s, errnor=%d", tempCachePath
, errno
);
1446 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1447 const char* prot
= "RW";
1448 if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_READ
) )
1450 else if ( it
->sfm_init_prot
== VM_PROT_READ
)
1452 else if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_WRITE
|VM_PROT_READ
) )
1454 if ( it
->sfm_size
> 1024*1024 )
1455 fprintf(fmap
, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/(1024*1024),
1456 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
1458 fprintf(fmap
, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/1024,
1459 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
1461 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1462 fprintf(fmap
, "%s\n", it
->layout
->getID().name
);
1463 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
1464 for (int i
=0; i
< segs
.size(); ++i
) {
1465 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1466 fprintf(fmap
, "\t%16s 0x%0llX -> 0x%0llX\n", seg
.name(), seg
.newAddress(), seg
.newAddress()+seg
.size());
1469 if ( warnings
.size() > 0 ) {
1470 fprintf(fmap
, "# Warnings:\n");
1471 for (std::vector
<const char*>::iterator it
=warnings
.begin(); it
!= warnings
.end(); ++it
) {
1472 fprintf(fmap
, "# %s\n", *it
);
1478 // free in memory cache
1479 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
1480 inMemoryCache
= NULL
;
1483 // remove temp cache file
1484 ::unlink(tempCachePath
);
1485 // remove in memory cache
1486 if ( inMemoryCache
!= NULL
)
1487 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
1497 // The shared cache is driven by /var/db/dyld/shared_region_roots which contains
1498 // the paths used to search for dylibs that should go in the shared cache
1500 // Leading and trailing white space is ignored
1501 // Blank lines are ignored
1502 // Lines starting with # are ignored
1504 static void parsePathsFile(const char* filePath
, std::vector
<const char*>& paths
)
1506 // read in whole file
1507 int fd
= open(filePath
, O_RDONLY
, 0);
1509 fprintf(stderr
, "update_dyld_shared_cache: can't open file: %s\n", filePath
);
1512 struct stat stat_buf
;
1513 fstat(fd
, &stat_buf
);
1514 char* p
= (char*)malloc(stat_buf
.st_size
);
1516 fprintf(stderr
, "update_dyld_shared_cache: malloc failure\n");
1519 if ( read(fd
, p
, stat_buf
.st_size
) != stat_buf
.st_size
) {
1520 fprintf(stderr
, "update_dyld_shared_cache: can't read file: %s\n", filePath
);
1525 // parse into paths and add to vector
1526 char * const end
= &p
[stat_buf
.st_size
];
1527 enum { lineStart
, inSymbol
, inComment
} state
= lineStart
;
1528 char* symbolStart
= NULL
;
1529 for (char* s
= p
; s
< end
; ++s
) {
1535 else if ( !isspace(*s
) ) {
1543 // removing any trailing spaces
1545 while ( isspace(*last
) ) {
1549 paths
.push_back(symbolStart
);
1560 // Note: we do not free() the malloc buffer, because the strings in it are used by exec()
1564 static void scanForSharedDylibs(const char* rootPath
, const char* dirOfPathFiles
, const std::set
<cpu_type_t
>& onlyArchs
)
1566 char rootDirOfPathFiles
[strlen(rootPath
)+strlen(dirOfPathFiles
)+2];
1567 if ( strlen(rootPath
) != 0 ) {
1568 strcpy(rootDirOfPathFiles
, rootPath
);
1569 strcat(rootDirOfPathFiles
, dirOfPathFiles
);
1570 dirOfPathFiles
= rootDirOfPathFiles
;
1573 // extract all root paths from files in "/var/db/dyld/shared_region_roots/"
1575 fprintf(stderr
, "update_dyld_shared_cache: finding roots in: %s\n", dirOfPathFiles
);
1576 std::vector
<const char*> rootsPaths
;
1577 DIR* dir
= ::opendir(dirOfPathFiles
);
1579 throwf("%s does not exist, errno=%d\n", dirOfPathFiles
, errno
);
1580 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
1581 if ( entry
->d_type
== DT_REG
) {
1582 // only look at files ending in .paths
1583 if ( strcmp(&entry
->d_name
[entry
->d_namlen
-6], ".paths") == 0 ) {
1584 char fullPath
[strlen(dirOfPathFiles
)+entry
->d_namlen
+2];
1585 strcpy(fullPath
, dirOfPathFiles
);
1586 strcat(fullPath
, "/");
1587 strcat(fullPath
, entry
->d_name
);
1588 parsePathsFile(fullPath
, rootsPaths
);
1591 fprintf(stderr
, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry
->d_name
);
1597 // set file system root
1598 ArchGraph::setFileSystemRoot(rootPath
);
1600 // initialize all architectures requested
1601 for(std::set
<cpu_type_t
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
1602 ArchGraph::addArch(*a
);
1604 // add roots to graph
1605 for(std::vector
<const char*>::iterator it
= rootsPaths
.begin(); it
!= rootsPaths
.end(); ++it
)
1606 ArchGraph::addRoot(*it
, onlyArchs
);
1608 // determine shared dylibs
1609 for(std::set
<cpu_type_t
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
1610 ArchGraph::findSharedDylibs(*a
);
1612 if ( rootsPaths
.size() == 0 )
1613 fprintf(stderr
, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
1617 // If the 10.5.0 version of update_dyld_shared_cache was killed or crashed, it
1618 // could leave large half written cache files laying around. The function deletes
1619 // those files. To prevent the deletion of tmp files being created by another
1620 // copy of update_dyld_shared_cache, it only deletes the temp cache file if its
1621 // creation time was before the last restart of this machine.
1622 static void deleteOrphanTempCacheFiles()
1624 DIR* dir
= ::opendir(DYLD_SHARED_CACHE_DIR
);
1625 if ( dir
!= NULL
) {
1626 std::vector
<const char*> filesToDelete
;
1627 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
1628 if ( entry
->d_type
== DT_REG
) {
1629 // only look at files with .tmp in name
1630 if ( strstr(entry
->d_name
, ".tmp") != NULL
) {
1631 char fullPath
[strlen(DYLD_SHARED_CACHE_DIR
)+entry
->d_namlen
+2];
1632 strcpy(fullPath
, DYLD_SHARED_CACHE_DIR
);
1633 strcat(fullPath
, "/");
1634 strcat(fullPath
, entry
->d_name
);
1635 struct stat tmpFileStatInfo
;
1636 if ( stat(fullPath
, &tmpFileStatInfo
) != -1 ) {
1637 int mib
[2] = {CTL_KERN
, KERN_BOOTTIME
};
1638 struct timeval boottime
;
1639 size_t size
= sizeof(boottime
);
1640 if ( (sysctl(mib
, 2, &boottime
, &size
, NULL
, 0) != -1) && (boottime
.tv_sec
!= 0) ) {
1641 // make sure this file is older than the boot time of this machine
1642 if ( tmpFileStatInfo
.st_mtime
< boottime
.tv_sec
) {
1643 filesToDelete
.push_back(strdup(fullPath
));
1651 for(std::vector
<const char*>::iterator it
= filesToDelete
.begin(); it
!= filesToDelete
.end(); ++it
) {
1652 fprintf(stderr
, "update_dyld_shared_cache: deleting old temp cache file: %s\n", *it
);
1660 static bool updateSharedeCacheFile(const char* rootPath
, const char* cacheDir
, const std::set
<cpu_type_t
>& onlyArchs
,
1661 bool force
, bool alphaSort
, bool optimize
, bool deleteExistingFirst
)
1663 bool didUpdate
= false;
1664 // get dyld load address info
1665 UniversalMachOLayout
* dyldLayout
= new UniversalMachOLayout("/usr/lib/dyld", &onlyArchs
);
1667 const int archCount
= onlyArchs
.size();
1669 for(std::set
<cpu_type_t
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
, ++index
) {
1670 const MachOLayoutAbstraction
* dyldLayoutForArch
= dyldLayout
->getArch(*a
);
1671 if ( dyldLayoutForArch
== NULL
)
1672 throw "dyld not avaiable for specified architecture";
1673 uint64_t dyldBaseAddress
= dyldLayoutForArch
->getBaseAddress();
1675 case CPU_TYPE_POWERPC
:
1677 SharedCache
<ppc
> cache(ArchGraph::getArch(*a
), alphaSort
, dyldBaseAddress
);
1679 // <rdar://problem/5217377> Rosetta does not work with optimized dyld shared cache
1680 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, false, deleteExistingFirst
, index
, archCount
);
1682 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, optimize
, deleteExistingFirst
, index
, archCount
);
1686 case CPU_TYPE_POWERPC64
:
1688 SharedCache
<ppc64
> cache(ArchGraph::getArch(*a
), alphaSort
, dyldBaseAddress
);
1689 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, optimize
, deleteExistingFirst
, index
, archCount
);
1694 SharedCache
<x86
> cache(ArchGraph::getArch(*a
), alphaSort
, dyldBaseAddress
);
1695 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, optimize
, deleteExistingFirst
, index
, archCount
);
1698 case CPU_TYPE_X86_64
:
1700 SharedCache
<x86_64
> cache(ArchGraph::getArch(*a
), alphaSort
, dyldBaseAddress
);
1701 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, optimize
, deleteExistingFirst
, index
, archCount
);
1707 deleteOrphanTempCacheFiles();
1715 fprintf(stderr
, "update_dyld_shared_cache [-force] [-root dir] [-arch arch] [-debug]\n");
1718 // flag so that we only update cache once per invocation
1719 static bool doNothingAndDrainQueue
= false;
1721 static kern_return_t
do_update_cache(cpu_type_t arch
, bool deleteExistingCacheFileFirst
)
1723 if ( !doNothingAndDrainQueue
) {
1724 std::set
<cpu_type_t
> onlyArchs
;
1725 onlyArchs
.insert(arch
);
1727 scanForSharedDylibs("", "/var/db/dyld/shared_region_roots/", onlyArchs
);
1728 if ( updateSharedeCacheFile("", DYLD_SHARED_CACHE_DIR
, onlyArchs
, false, false, true, deleteExistingCacheFileFirst
) )
1729 fprintf(stderr
, "update_dyld_shared_cache[%u] regenerated cache for arch=%s\n", getpid(), ArchGraph::archName(arch
));
1731 catch (const char* msg
) {
1732 fprintf(stderr
, "update_dyld_shared_cache[%u] for arch=%s failed: %s\n", getpid(), ArchGraph::archName(arch
), msg
);
1733 return KERN_FAILURE
;
1736 return KERN_SUCCESS
;
1741 kern_return_t
do_dyld_shared_cache_missing(mach_port_t dyld_port
, cpu_type_t arch
)
1743 return do_update_cache(arch
, false);
1747 kern_return_t
do_dyld_shared_cache_out_of_date(mach_port_t dyld_port
, cpu_type_t arch
)
1749 // If cache exists but is out of date, delete the file while building the new one.
1750 // This will stop dyld from pinging update_dyld_share_cache while the cache is being built.
1751 return do_update_cache(arch
, true);
1755 int main(int argc
, const char* argv
[])
1758 if ( bootstrap_check_in(bootstrap_port
, "com.apple.dyld", &mp
) == KERN_SUCCESS
) {
1759 // started by launchd
1760 mach_msg_size_t mxmsgsz
= sizeof(union __RequestUnion__do_dyld_server_subsystem
) + MAX_TRAILER_SIZE
;
1761 doNothingAndDrainQueue
= false;
1762 while ( mach_msg_server(dyld_server_server
, mxmsgsz
, mp
, MACH_RCV_TIMEOUT
) == KERN_SUCCESS
) {
1763 // keep processing messages
1764 doNothingAndDrainQueue
= true;
1765 // but set flag so work is no longer done.
1766 // This is because the rest of the tool leaks and processing more than once
1767 // can hog system resources: <rdar://problem/5392427> 9A516 - Keep getting disk full errors
1768 // We drain the queue of messages because there is usually are a couple of duplicate messages.
1769 // It is ok to miss some messages. If the cache is out of date or missing, some new process
1770 // will discover it and send another message.
1775 // started as command line tool
1776 std::set
<cpu_type_t
> onlyArchs
;
1777 const char* rootPath
= "";
1779 bool alphaSort
= false;
1780 bool optimize
= true;
1781 bool makeSymLink
= false;
1784 // parse command line options
1785 for(int i
=1; i
< argc
; ++i
) {
1786 const char* arg
= argv
[i
];
1787 if ( arg
[0] == '-' ) {
1788 if ( strcmp(arg
, "-debug") == 0 ) {
1791 else if ( strcmp(arg
, "-force") == 0 ) {
1794 else if ( strcmp(arg
, "-sort_by_name") == 0 ) {
1797 else if ( strcmp(arg
, "-opt") == 0 ) {
1800 else if ( strcmp(arg
, "-no_opt") == 0 ) {
1803 else if ( (strcmp(arg
, "-root") == 0) || (strcmp(arg
, "--root") == 0) ) {
1804 rootPath
= argv
[++i
];
1805 if ( rootPath
== NULL
)
1806 throw "-root missing path argument";
1807 // strip tailing slashes
1808 int len
= strlen(rootPath
)-1;
1809 if ( rootPath
[len
] == '/' ) {
1810 char* newRootPath
= strdup(rootPath
);
1811 while ( newRootPath
[len
] == '/' )
1812 newRootPath
[len
--] = '\0';
1813 rootPath
= newRootPath
;
1816 else if ( strcmp(arg
, "-arch") == 0 ) {
1817 const char* arch
= argv
[++i
];
1818 if ( strcmp(arch
, "ppc") == 0 )
1819 onlyArchs
.insert(CPU_TYPE_POWERPC
);
1820 else if ( strcmp(arch
, "ppc64") == 0 )
1821 onlyArchs
.insert(CPU_TYPE_POWERPC64
);
1822 else if ( strcmp(arch
, "i386") == 0 )
1823 onlyArchs
.insert(CPU_TYPE_I386
);
1824 else if ( strcmp(arch
, "x86_64") == 0 )
1825 onlyArchs
.insert(CPU_TYPE_X86_64
);
1827 throwf("unknown architecture %s", arch
);
1829 else if ( strcmp(arg
, "-universal_boot") == 0 ) {
1831 throwf("universal_boot option can only be used on Intel machines");
1833 onlyArchs
.insert(CPU_TYPE_POWERPC
);
1834 onlyArchs
.insert(CPU_TYPE_I386
);
1839 throwf("unknown option: %s\n", arg
);
1844 throwf("unknown option: %s\n", arg
);
1848 // if no restrictions specified, use architectures that work on this machine
1849 if ( onlyArchs
.size() == 0 ) {
1851 size_t len
= sizeof(int);
1853 onlyArchs
.insert(CPU_TYPE_POWERPC
);
1854 if ( (sysctlbyname("hw.optional.64bitops", &available
, &len
, NULL
, 0) == 0) && available
)
1855 onlyArchs
.insert(CPU_TYPE_POWERPC64
);
1857 onlyArchs
.insert(CPU_TYPE_I386
);
1858 onlyArchs
.insert(CPU_TYPE_POWERPC
); // assume rosetta always available
1859 if ( (sysctlbyname("hw.optional.x86_64", &available
, &len
, NULL
, 0) == 0) && available
)
1860 onlyArchs
.insert(CPU_TYPE_X86_64
);
1862 #error unknown architecture
1866 if ( geteuid() != 0 )
1867 throw "you must be root to run this tool";
1869 // build list of shared dylibs
1870 scanForSharedDylibs(rootPath
, "/var/db/dyld/shared_region_roots/", onlyArchs
);
1871 updateSharedeCacheFile(rootPath
, DYLD_SHARED_CACHE_DIR
, onlyArchs
, force
, alphaSort
, optimize
, false);
1873 // To make a universal bootable image with dyld caches,
1874 // build the rosetta cache and symlink ppc to point to it.
1875 // A rosetta cache is just an unoptimized ppc cache, so ppc machine can use it too.
1876 // rdar://problem/5498469
1877 if ( makeSymLink
) {
1878 char symLinkLocation
[1024];
1879 strcpy(symLinkLocation
, rootPath
);
1880 strcat(symLinkLocation
, DYLD_SHARED_CACHE_DIR
);
1881 strcat(symLinkLocation
, DYLD_SHARED_CACHE_BASE_NAME
);
1882 strcat(symLinkLocation
, SharedCache
<ppc
>::filename(true));
1883 char symLinkTarget
[1024];
1884 strcpy(symLinkTarget
, DYLD_SHARED_CACHE_BASE_NAME
);
1885 strcat(symLinkTarget
, SharedCache
<ppc
>::filename(false));
1886 if ( symlink(symLinkTarget
, symLinkLocation
) == -1 ) {
1887 if ( errno
!= EEXIST
)
1888 throwf("symlink() returned errno=%d", errno
);
1892 catch (const char* msg
) {
1893 fprintf(stderr
, "update_dyld_shared_cache failed: %s\n", msg
);