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>
37 #include <sys/param.h>
38 #include <sys/sysctl.h>
39 #include <sys/resource.h>
41 #include <servers/bootstrap.h>
42 #include <mach-o/loader.h>
43 #include <mach-o/fat.h>
45 #include "dyld_cache_format.h"
50 #include <ext/hash_map>
52 #include "Architectures.hpp"
53 #include "MachOLayout.hpp"
54 #include "MachORebaser.hpp"
55 #include "MachOBinder.hpp"
56 #include "CacheFileAbstraction.hpp"
59 #include "dyld_shared_cache_server.h"
63 static bool verbose
= false;
64 static std::vector
<const char*> warnings
;
67 static uint64_t pageAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
72 static void addArch(cpu_type_t arch
);
73 static void addRoot(const char* vpath
, const std::set
<cpu_type_t
>& archs
);
74 static void findSharedDylibs(cpu_type_t arch
);
75 static ArchGraph
* getArch(cpu_type_t arch
) { return fgPerArchGraph
[arch
]; }
76 static void setFileSystemRoot(const char* root
) { fgFileSystemRoot
= root
; }
77 static const char* archName(cpu_type_t arch
);
79 cpu_type_t
getArch() { return fArch
; }
80 std::set
<const class MachOLayoutAbstraction
*>& getSharedDylibs() { return fSharedDylibs
; }
87 DependencyNode(ArchGraph
*, const char* path
, const MachOLayoutAbstraction
* layout
);
88 void loadDependencies(const MachOLayoutAbstraction
*);
89 void markNeededByRoot(DependencyNode
*);
90 const char* getPath() const { return fPath
; }
91 const MachOLayoutAbstraction
* getLayout() const { return fLayout
; }
92 size_t useCount() const { return fRootsDependentOnThis
.size(); }
93 bool allDependentsFound() const { return !fDependentMissing
; }
97 const MachOLayoutAbstraction
* fLayout
;
98 bool fDependenciesLoaded
;
99 bool fDependentMissing
;
100 std::set
<DependencyNode
*> fDependsOn
;
101 std::set
<DependencyNode
*> fRootsDependentOnThis
;
104 struct CStringEquals
{
105 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
107 typedef __gnu_cxx::hash_map
<const char*, class DependencyNode
*, __gnu_cxx::hash
<const char*>, CStringEquals
> PathToNode
;
110 ArchGraph(cpu_type_t arch
) : fArch(arch
) {}
111 static void addRootForArch(const char* path
, const MachOLayoutAbstraction
*);
112 void addRoot(const char* path
, const MachOLayoutAbstraction
*);
113 DependencyNode
* getNode(const char* path
);
114 DependencyNode
* getNodeForVirtualPath(const char* vpath
);
115 static bool canBeShared(const MachOLayoutAbstraction
* layout
, cpu_type_t arch
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
);
117 static std::map
<cpu_type_t
, ArchGraph
*> fgPerArchGraph
;
118 static const char* fgFileSystemRoot
;
121 std::set
<DependencyNode
*> fRoots
;
123 std::set
<const MachOLayoutAbstraction
*> fSharedDylibs
; // use set to avoid duplicates when installname!=realpath
125 std::map
<cpu_type_t
, ArchGraph
*> ArchGraph::fgPerArchGraph
;
126 const char* ArchGraph::fgFileSystemRoot
= "";
128 void ArchGraph::addArch(cpu_type_t arch
)
130 //fprintf(stderr, "adding arch 0x%08X\n", arch);
131 fgPerArchGraph
[arch
] = new ArchGraph(arch
);
134 void ArchGraph::addRoot(const char* vpath
, const std::set
<cpu_type_t
>& archs
)
136 char completePath
[strlen(fgFileSystemRoot
)+strlen(vpath
)+2];
138 if ( strlen(fgFileSystemRoot
) == 0 ) {
142 strcpy(completePath
, fgFileSystemRoot
);
143 strcat(completePath
, vpath
); // assumes vpath starts with '/'
147 const UniversalMachOLayout
* uni
= UniversalMachOLayout::find(path
, &archs
);
148 const std::vector
<MachOLayoutAbstraction
*>& layouts
= uni
->getArchs();
149 for(std::vector
<MachOLayoutAbstraction
*>::const_iterator it
= layouts
.begin(); it
!= layouts
.end(); ++it
) {
150 const MachOLayoutAbstraction
* layout
= *it
;
151 if ( archs
.count(layout
->getArchitecture()) > 0 )
152 ArchGraph::addRootForArch(path
, layout
);
154 // don't delete uni, it is owned by UniversalMachOLayout cache
156 catch (const char* msg
) {
157 fprintf(stderr
, "update_dyld_shared_cache: warning can't use root %s: %s\n", path
, msg
);
161 void ArchGraph::addRootForArch(const char* path
, const MachOLayoutAbstraction
* layout
)
163 ArchGraph
* graph
= fgPerArchGraph
[layout
->getArchitecture()];
164 graph
->addRoot(path
, layout
);
167 void ArchGraph::addRoot(const char* path
, const MachOLayoutAbstraction
* layout
)
170 fprintf(stderr
, "update_dyld_shared_cache: adding root: %s\n", path
);
171 DependencyNode
* node
= this->getNode(path
);
173 const MachOLayoutAbstraction
* mainExecutableLayout
= NULL
;
174 if ( layout
->getFileType() == MH_EXECUTE
)
175 mainExecutableLayout
= layout
;
176 node
->loadDependencies(mainExecutableLayout
);
177 node
->markNeededByRoot(node
);
178 if ( layout
->getFileType() == MH_DYLIB
)
179 node
->markNeededByRoot(NULL
);
182 // a virtual path does not have the fgFileSystemRoot prefix
183 ArchGraph::DependencyNode
* ArchGraph::getNodeForVirtualPath(const char* vpath
)
185 if ( fgFileSystemRoot
== NULL
) {
186 return this->getNode(vpath
);
189 char completePath
[strlen(fgFileSystemRoot
)+strlen(vpath
)+2];
190 strcpy(completePath
, fgFileSystemRoot
);
191 strcat(completePath
, vpath
); // assumes vpath starts with '/'
192 return this->getNode(completePath
);
196 ArchGraph::DependencyNode
* ArchGraph::getNode(const char* path
)
198 // look up supplied path to see if node already exists
199 PathToNode::iterator pos
= fNodes
.find(path
);
200 if ( pos
!= fNodes
.end() )
204 char realPath
[MAXPATHLEN
];
205 if ( realpath(path
, realPath
) == NULL
)
206 throwf("realpath() failed on %s\n", path
);
208 // look up real path to see if node already exists
209 pos
= fNodes
.find(realPath
);
210 if ( pos
!= fNodes
.end() )
213 // still does not exist, so create a new node
214 const UniversalMachOLayout
* uni
= UniversalMachOLayout::find(realPath
);
215 DependencyNode
* node
= new DependencyNode(this, realPath
, uni
->getArch(fArch
));
216 if ( node
->getLayout() == NULL
) {
217 throwf("%s is missing arch %s", realPath
, archName(fArch
));
219 // add realpath to node map
220 fNodes
[node
->getPath()] = node
;
221 // if install name is not real path, add install name to node map
222 if ( (node
->getLayout()->getFileType() == MH_DYLIB
) && (strcmp(realPath
, node
->getLayout()->getID().name
) != 0) ) {
223 //fprintf(stderr, "adding node alias 0x%08X %s for %s\n", fArch, node->getLayout()->getID().name, realPath);
224 fNodes
[node
->getLayout()->getID().name
] = node
;
230 void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction
* mainExecutableLayout
)
232 if ( !fDependenciesLoaded
) {
233 fDependenciesLoaded
= true;
235 const std::vector
<MachOLayoutAbstraction::Library
>& dependsOn
= fLayout
->getLibraries();
236 for(std::vector
<MachOLayoutAbstraction::Library
>::const_iterator it
= dependsOn
.begin(); it
!= dependsOn
.end(); ++it
) {
238 const char* dependentPath
= it
->name
;
239 if ( strncmp(dependentPath
, "@executable_path/", 17) == 0 ) {
240 if ( mainExecutableLayout
== NULL
)
241 throw "@executable_path without main executable";
242 // expand @executable_path path prefix
243 const char* executablePath
= mainExecutableLayout
->getFilePath();
244 char newPath
[strlen(executablePath
) + strlen(dependentPath
)+2];
245 strcpy(newPath
, executablePath
);
246 char* addPoint
= strrchr(newPath
,'/');
247 if ( addPoint
!= NULL
)
248 strcpy(&addPoint
[1], &dependentPath
[17]);
250 strcpy(newPath
, &dependentPath
[17]);
251 dependentPath
= strdup(newPath
);
253 else if ( strncmp(dependentPath
, "@loader_path/", 13) == 0 ) {
254 // expand @loader_path path prefix
255 char newPath
[strlen(fPath
) + strlen(dependentPath
)+2];
256 strcpy(newPath
, fPath
);
257 char* addPoint
= strrchr(newPath
,'/');
258 if ( addPoint
!= NULL
)
259 strcpy(&addPoint
[1], &dependentPath
[13]);
261 strcpy(newPath
, &dependentPath
[13]);
262 dependentPath
= strdup(newPath
);
264 else if ( strncmp(dependentPath
, "@rpath/", 7) == 0 ) {
265 throw "@rpath not supported in dyld shared cache";
267 fDependsOn
.insert(fGraph
->getNodeForVirtualPath(dependentPath
));
269 catch (const char* msg
) {
270 fprintf(stderr
, "warning, could not bind %s because %s\n", fPath
, msg
);
271 fDependentMissing
= true;
275 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
276 (*it
)->loadDependencies(mainExecutableLayout
);
281 void ArchGraph::DependencyNode::markNeededByRoot(ArchGraph::DependencyNode
* rootNode
)
283 if ( fRootsDependentOnThis
.count(rootNode
) == 0 ) {
284 fRootsDependentOnThis
.insert(rootNode
);
285 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
286 (*it
)->markNeededByRoot(rootNode
);
292 ArchGraph::DependencyNode::DependencyNode(ArchGraph
* graph
, const char* path
, const MachOLayoutAbstraction
* layout
)
293 : fGraph(graph
), fPath(strdup(path
)), fLayout(layout
), fDependenciesLoaded(false), fDependentMissing(false)
295 //fprintf(stderr, "new DependencyNode(0x%08X, %s)\n", graph->fArch, path);
298 void ArchGraph::findSharedDylibs(cpu_type_t arch
)
300 const PathToNode
& nodes
= fgPerArchGraph
[arch
]->fNodes
;
301 std::set
<const MachOLayoutAbstraction
*> possibleLibs
;
302 //fprintf(stderr, "shared for arch 0x%08X\n", arch);
303 for(PathToNode::const_iterator it
= nodes
.begin(); it
!= nodes
.end(); ++it
) {
304 DependencyNode
* node
= it
->second
;
305 if ( node
->allDependentsFound() && (node
->useCount() > 1) ) {
306 if ( node
->getLayout()->hasSplitSegInfo() )
307 possibleLibs
.insert(node
->getLayout());
308 //fprintf(stderr, "\t%s\n", it->first);
312 // prune so that all shareable libs depend only on other shareable libs
313 std::set
<const MachOLayoutAbstraction
*>& sharedLibs
= fgPerArchGraph
[arch
]->fSharedDylibs
;
314 std::map
<const MachOLayoutAbstraction
*,bool> shareableMap
;
315 for (std::set
<const MachOLayoutAbstraction
*>::iterator lit
= possibleLibs
.begin(); lit
!= possibleLibs
.end(); ++lit
) {
316 if ( canBeShared(*lit
, arch
, possibleLibs
, shareableMap
) )
317 sharedLibs
.insert(*lit
);
321 const char* ArchGraph::archName(cpu_type_t arch
)
324 case CPU_TYPE_POWERPC
:
326 case CPU_TYPE_POWERPC64
:
330 case CPU_TYPE_X86_64
:
337 bool ArchGraph::canBeShared(const MachOLayoutAbstraction
* layout
, cpu_type_t arch
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
)
339 // check map which is a cache of results
340 std::map
<const MachOLayoutAbstraction
*, bool>::iterator mapPos
= shareableMap
.find(layout
);
341 if ( mapPos
!= shareableMap
.end() ) {
342 return mapPos
->second
;
345 if ( possibleLibs
.count(layout
) == 0 ) {
346 shareableMap
[layout
] = false;
348 if ( ! layout
->hasSplitSegInfo() )
349 asprintf(&msg
, "can't put %s in shared cache because it was not built for 10.5", layout
->getID().name
);
351 asprintf(&msg
, "can't put %s in shared cache", layout
->getID().name
);
352 warnings
.push_back(msg
);
354 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(arch
), msg
);
358 shareableMap
[layout
] = true; // mark this shareable early in case of circular references
359 const PathToNode
& nodes
= fgPerArchGraph
[arch
]->fNodes
;
360 const std::vector
<MachOLayoutAbstraction::Library
>& dependents
= layout
->getLibraries();
361 for (std::vector
<MachOLayoutAbstraction::Library
>::const_iterator dit
= dependents
.begin(); dit
!= dependents
.end(); ++dit
) {
362 PathToNode::const_iterator pos
= nodes
.find(dit
->name
);
363 if ( pos
== nodes
.end() ) {
364 shareableMap
[layout
] = false;
366 asprintf(&msg
, "can't put %s in shared cache because it depends on %s which can't be found", layout
->getID().name
, dit
->name
);
367 warnings
.push_back(msg
);
369 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(arch
), msg
);
373 if ( ! canBeShared(pos
->second
->getLayout(), arch
, possibleLibs
, shareableMap
) ) {
374 shareableMap
[layout
] = false;
376 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
);
377 warnings
.push_back(msg
);
379 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(arch
), msg
);
388 template <typename A
>
392 SharedCache(ArchGraph
* graph
, bool alphaSort
, uint64_t dyldBaseAddress
);
393 bool update(const char* rootPath
, const char* cacheDir
, bool force
, bool optimize
, int archIndex
, int archCount
);
394 static const char* filename(bool optimized
);
397 typedef typename
A::P::E E
;
399 bool notUpToDate(const char* cachePath
);
400 bool notUpToDate(const void* cache
);
401 uint8_t* optimizeLINKEDIT();
403 static void getSharedCacheBasAddresses(cpu_type_t arch
, uint64_t* baseReadOnly
, uint64_t* baseWritable
);
404 static cpu_type_t
arch();
405 static const char* archName();
406 static uint64_t sharedRegionReadOnlyStartAddress();
407 static uint64_t sharedRegionWritableStartAddress();
408 static uint64_t sharedRegionReadOnlySize();
409 static uint64_t sharedRegionWritableSize();
410 static uint64_t getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
);
413 void assignNewBaseAddresses();
414 uint64_t cacheFileOffsetForAddress(uint64_t addr
);
417 const MachOLayoutAbstraction
* layout
;
418 dyld_cache_image_info info
;
421 struct ByNameSorter
{
422 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
)
423 { return (strcmp(left
.layout
->getID().name
, right
.layout
->getID().name
) < 0); }
426 struct RandomSorter
{
427 RandomSorter(const std::vector
<LayoutInfo
>& infos
) {
428 for(typename
std::vector
<struct LayoutInfo
>::const_iterator it
= infos
.begin(); it
!= infos
.end(); ++it
)
429 fMap
[it
->layout
] = arc4random();
431 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
432 return (fMap
[left
.layout
] < fMap
[right
.layout
]);
435 std::map
<const MachOLayoutAbstraction
*, uint32_t> fMap
;
439 ArchGraph
* fArchGraph
;
440 std::vector
<LayoutInfo
> fDylibs
;
441 std::vector
<shared_file_mapping_np
> fMappings
;
442 uint32_t fHeaderSize
;
443 uint8_t* fMappedCacheFile
;
444 uint64_t fDyldBaseAddress
;
445 uint64_t fLinkEditsTotalUnoptimizedSize
;
446 uint64_t fLinkEditsStartAddress
;
447 MachOLayoutAbstraction::Segment
* fFirstLinkEditSegment
;
453 template <> cpu_type_t SharedCache
<ppc
>::arch() { return CPU_TYPE_POWERPC
; }
454 template <> cpu_type_t SharedCache
<ppc64
>::arch() { return CPU_TYPE_POWERPC64
; }
455 template <> cpu_type_t SharedCache
<x86
>::arch() { return CPU_TYPE_I386
; }
456 template <> cpu_type_t SharedCache
<x86_64
>::arch() { return CPU_TYPE_X86_64
; }
458 template <> uint64_t SharedCache
<ppc
>::sharedRegionReadOnlyStartAddress() { return 0x90000000; }
459 template <> uint64_t SharedCache
<ppc64
>::sharedRegionReadOnlyStartAddress() { return 0x7FFF80000000LL
; }
460 template <> uint64_t SharedCache
<x86
>::sharedRegionReadOnlyStartAddress() { return 0x90000000; }
461 template <> uint64_t SharedCache
<x86_64
>::sharedRegionReadOnlyStartAddress() { return 0x7FFF80000000LL
; }
463 template <> uint64_t SharedCache
<ppc
>::sharedRegionWritableStartAddress() { return 0xA0000000; }
464 template <> uint64_t SharedCache
<ppc64
>::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL
; }
465 template <> uint64_t SharedCache
<x86
>::sharedRegionWritableStartAddress() { return 0xA0000000; }
466 template <> uint64_t SharedCache
<x86_64
>::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL
; }
468 template <> uint64_t SharedCache
<ppc
>::sharedRegionReadOnlySize() { return 0x10000000; }
469 template <> uint64_t SharedCache
<ppc64
>::sharedRegionReadOnlySize() { return 0x7FE00000; }
470 template <> uint64_t SharedCache
<x86
>::sharedRegionReadOnlySize() { return 0x10000000; }
471 template <> uint64_t SharedCache
<x86_64
>::sharedRegionReadOnlySize() { return 0x7FE00000; }
473 template <> uint64_t SharedCache
<ppc
>::sharedRegionWritableSize() { return 0x10000000; }
474 template <> uint64_t SharedCache
<ppc64
>::sharedRegionWritableSize() { return 0x20000000; }
475 template <> uint64_t SharedCache
<x86
>::sharedRegionWritableSize() { return 0x10000000; }
476 template <> uint64_t SharedCache
<x86_64
>::sharedRegionWritableSize() { return 0x20000000; }
479 template <> const char* SharedCache
<ppc
>::archName() { return "ppc"; }
480 template <> const char* SharedCache
<ppc64
>::archName() { return "ppc64"; }
481 template <> const char* SharedCache
<x86
>::archName() { return "i386"; }
482 template <> const char* SharedCache
<x86_64
>::archName() { return "x86_64"; }
484 template <> const char* SharedCache
<ppc
>::filename(bool optimized
) { return optimized
? "ppc" : "rosetta"; }
485 template <> const char* SharedCache
<ppc64
>::filename(bool) { return "ppc64"; }
486 template <> const char* SharedCache
<x86
>::filename(bool) { return "i386"; }
487 template <> const char* SharedCache
<x86_64
>::filename(bool) { return "x86_64"; }
489 template <typename A
>
490 SharedCache
<A
>::SharedCache(ArchGraph
* graph
, bool alphaSort
, uint64_t dyldBaseAddress
)
491 : fArchGraph(graph
), fDyldBaseAddress(dyldBaseAddress
)
493 if ( fArchGraph
->getArch() != arch() )
494 throw "wrong architecture";
496 // build vector of all shared dylibs
497 std::set
<const MachOLayoutAbstraction
*>& dylibs
= fArchGraph
->getSharedDylibs();
498 for(std::set
<const MachOLayoutAbstraction
*>::iterator it
= dylibs
.begin(); it
!= dylibs
.end(); ++it
) {
499 const MachOLayoutAbstraction
* lib
= *it
;
502 temp
.info
.address
= 0;
503 temp
.info
.modTime
= lib
->getLastModTime();
504 temp
.info
.inode
= lib
->getInode();
505 temp
.info
.pathFileOffset
= lib
->getNameFileOffset();
506 fDylibs
.push_back(temp
);
509 // sort shared dylibs
511 std::sort(fDylibs
.begin(), fDylibs
.end(), ByNameSorter());
513 std::sort(fDylibs
.begin(), fDylibs
.end(), RandomSorter(fDylibs
));
516 // assign segments in each dylib a new address
517 this->assignNewBaseAddresses();
519 // calculate cache file header size
520 fHeaderSize
= pageAlign(sizeof(dyld_cache_header
)
521 + fMappings
.size()*sizeof(shared_file_mapping_np
)
522 + fDylibs
.size()*sizeof(dyld_cache_image_info
) );
523 //+ fDependencyPool.size()*sizeof(uint16_t));
525 if ( fHeaderSize
> 0x3000 )
526 throwf("header size miscalculation 0x%08X", fHeaderSize
);
530 template <typename A
>
531 uint64_t SharedCache
<A
>::getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
)
533 return proposedNewAddress
;
537 uint64_t SharedCache
<ppc
>::getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
)
539 // for ppc64 writable segments can only move in increments of 64K (so only hi16 instruction needs to be modified)
540 return (((executableSlide
& 0x000000000000F000ULL
) - ((proposedNewAddress
- originalAddress
) & 0x000000000000F000ULL
)) & 0x000000000000F000ULL
) + proposedNewAddress
;
544 uint64_t SharedCache
<ppc64
>::getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
)
546 // for ppc64 writable segments can only move in increments of 64K (so only hi16 instruction needs to be modified)
547 return (((executableSlide
& 0x000000000000F000ULL
) - ((proposedNewAddress
- originalAddress
) & 0x000000000000F000ULL
)) & 0x000000000000F000ULL
) + proposedNewAddress
;
551 template <typename A
>
552 void SharedCache
<A
>::assignNewBaseAddresses()
554 // first layout TEXT and DATA for split-seg (or can be split-seg) dylibs
555 uint64_t currentExecuteAddress
= sharedRegionReadOnlyStartAddress() + 0x3000;
556 uint64_t currentWritableAddress
= sharedRegionWritableStartAddress();
557 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
558 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
559 MachOLayoutAbstraction::Segment
* executableSegment
= NULL
;
560 for (int i
=0; i
< segs
.size(); ++i
) {
561 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
562 if ( seg
.writable() ) {
563 if ( seg
.executable() && it
->layout
->hasSplitSegInfo() ) {
564 // skip __IMPORT segments in this pass
568 // for ppc, writable segments have to move in 64K increments
569 if ( it
->layout
->hasSplitSegInfo() ) {
570 if ( executableSegment
== NULL
)
571 throwf("first segment in dylib is not executable for %s", it
->layout
->getID().name
);
572 seg
.setNewAddress(getWritableSegmentNewAddress(currentWritableAddress
, seg
.address(), executableSegment
->newAddress() - executableSegment
->address()));
575 seg
.setNewAddress(currentWritableAddress
);
576 currentWritableAddress
= pageAlign(seg
.newAddress() + seg
.size());
580 if ( seg
.executable() ) {
582 if ( it
->info
.address
== 0 )
583 it
->info
.address
= currentExecuteAddress
;
584 executableSegment
= &seg
;
585 seg
.setNewAddress(currentExecuteAddress
);
586 currentExecuteAddress
+= pageAlign(seg
.size());
589 // skip read-only segments in this pass
590 // any non-LINKEDIT read-only segments leave a hole so that all R/W segment slide together
591 if ( (strcmp(seg
.name(), "__LINKEDIT") != 0) && (i
< (segs
.size()-2)) ) {
592 fprintf(stderr
, "update_dyld_shared_cache: warning %s segment in %s leaves a hole\n", seg
.name(), it
->layout
->getID().name
);
593 currentWritableAddress
= pageAlign(currentWritableAddress
+ seg
.size());
600 // append all read-only (but not LINKEDIT) segments at end of all TEXT segments
601 // append all IMPORT segments at end of all DATA segments rounded to next 2MB
602 uint64_t currentReadOnlyAddress
= currentExecuteAddress
;
603 uint64_t startWritableExecutableAddress
= (currentWritableAddress
+ 0x200000 - 1) & (-0x200000);
604 uint64_t currentWritableExecutableAddress
= startWritableExecutableAddress
;
605 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
606 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
607 for(int i
=0; i
< segs
.size(); ++i
) {
608 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
609 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") != 0) ) {
610 // allocate non-executable,read-only segments from end of read only shared region
611 seg
.setNewAddress(currentReadOnlyAddress
);
612 currentReadOnlyAddress
+= pageAlign(seg
.size());
614 else if ( seg
.writable() && seg
.executable() && it
->layout
->hasSplitSegInfo() ) {
615 // allocate IMPORT segments to end of writable shared region
616 seg
.setNewAddress(currentWritableExecutableAddress
);
617 seg
.setWritable(false); // __IMPORT segments are not-writable in shared cache
618 currentWritableExecutableAddress
+= pageAlign(seg
.size());
623 // append all LINKEDIT segments at end of all read-only segments
624 fLinkEditsStartAddress
= currentReadOnlyAddress
;
625 fFirstLinkEditSegment
= NULL
;
626 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
627 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
628 for(int i
=0; i
< segs
.size(); ++i
) {
629 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
630 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
631 if ( fFirstLinkEditSegment
== NULL
)
632 fFirstLinkEditSegment
= &seg
;
633 // allocate non-executable,read-only segments from end of read only shared region
634 seg
.setNewAddress(currentReadOnlyAddress
);
635 currentReadOnlyAddress
+= pageAlign(seg
.size());
639 fLinkEditsTotalUnoptimizedSize
= (currentReadOnlyAddress
- fLinkEditsStartAddress
+ 4095) & (-4096);
642 // populate large mappings
643 uint64_t cacheFileOffset
= 0;
644 if ( currentExecuteAddress
> sharedRegionReadOnlyStartAddress() + 0x3000 ) {
645 shared_file_mapping_np executeMapping
;
646 executeMapping
.sfm_address
= sharedRegionReadOnlyStartAddress();
647 executeMapping
.sfm_size
= currentExecuteAddress
- sharedRegionReadOnlyStartAddress();
648 executeMapping
.sfm_file_offset
= cacheFileOffset
;
649 executeMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
650 executeMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
651 fMappings
.push_back(executeMapping
);
652 cacheFileOffset
+= executeMapping
.sfm_size
;
654 shared_file_mapping_np writableMapping
;
655 writableMapping
.sfm_address
= sharedRegionWritableStartAddress();
656 writableMapping
.sfm_size
= currentWritableAddress
- sharedRegionWritableStartAddress();
657 writableMapping
.sfm_file_offset
= cacheFileOffset
;
658 writableMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
659 writableMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
660 fMappings
.push_back(writableMapping
);
661 cacheFileOffset
+= writableMapping
.sfm_size
;
663 if ( currentWritableExecutableAddress
> startWritableExecutableAddress
) {
664 shared_file_mapping_np writableExecutableMapping
;
665 writableExecutableMapping
.sfm_address
= startWritableExecutableAddress
;
666 writableExecutableMapping
.sfm_size
= currentWritableExecutableAddress
- startWritableExecutableAddress
;
667 writableExecutableMapping
.sfm_file_offset
= cacheFileOffset
;
668 writableExecutableMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_WRITE
| VM_PROT_EXECUTE
;
669 // __IMPORT segments in shared cache are not writable
670 writableExecutableMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
671 fMappings
.push_back(writableExecutableMapping
);
672 cacheFileOffset
+= writableExecutableMapping
.sfm_size
;
675 // make read-only (contains LINKEDIT segments) last, so it can be cut back when optimized
676 shared_file_mapping_np readOnlyMapping
;
677 readOnlyMapping
.sfm_address
= currentExecuteAddress
;
678 readOnlyMapping
.sfm_size
= currentReadOnlyAddress
- currentExecuteAddress
;
679 readOnlyMapping
.sfm_file_offset
= cacheFileOffset
;
680 readOnlyMapping
.sfm_max_prot
= VM_PROT_READ
;
681 readOnlyMapping
.sfm_init_prot
= VM_PROT_READ
;
682 fMappings
.push_back(readOnlyMapping
);
683 cacheFileOffset
+= readOnlyMapping
.sfm_size
;
687 shared_file_mapping_np cacheHeaderMapping
;
688 cacheHeaderMapping
.sfm_address
= sharedRegionWritableStartAddress();
689 cacheHeaderMapping
.sfm_size
= 0x3000;
690 cacheHeaderMapping
.sfm_file_offset
= cacheFileOffset
;
691 cacheHeaderMapping
.sfm_max_prot
= VM_PROT_READ
;
692 cacheHeaderMapping
.sfm_init_prot
= VM_PROT_READ
;
693 fMappings
.push_back(cacheHeaderMapping
);
694 cacheFileOffset
+= cacheHeaderMapping
.sfm_size
;
699 template <typename A
>
700 uint64_t SharedCache
<A
>::cacheFileOffsetForAddress(uint64_t addr
)
702 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
703 if ( (it
->sfm_address
<= addr
) && (addr
< it
->sfm_address
+it
->sfm_size
) )
704 return it
->sfm_file_offset
+ addr
- it
->sfm_address
;
706 throwf("address 0x%0llX is not in cache", addr
);
710 template <typename A
>
711 bool SharedCache
<A
>::notUpToDate(const void* cache
)
713 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)cache
;
714 // not valid if header signature is wrong
716 strcpy(temp
, "dyld_v1 ");
717 strcpy(&temp
[15-strlen(archName())], archName());
718 if ( strcmp(header
->magic(), temp
) != 0 )
720 // not valid if count of images does not match current images needed
721 if ( header
->imagesCount() != fDylibs
.size() )
723 // verify every dylib in constructed graph is in existing cache with same inode and modTime
724 const dyldCacheImageInfo
<E
>* imagesStart
= (dyldCacheImageInfo
<E
>*)((uint8_t*)cache
+ header
->imagesOffset());
725 const dyldCacheImageInfo
<E
>* imagesEnd
= &imagesStart
[header
->imagesCount()];
726 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
728 //fprintf(stderr, "inode=0x%llX, mTime=0x%llX, path=%s\n", it->info.inode, it->info.modTime, it->layout->getID().name);
729 for(const dyldCacheImageInfo
<E
>* cacheEntry
= imagesStart
; cacheEntry
< imagesEnd
; ++cacheEntry
) {
730 if ( (cacheEntry
->inode() == it
->info
.inode
)
731 && (cacheEntry
->modTime() == it
->info
.modTime
)
732 && (strcmp((char*)cache
+cacheEntry
->pathFileOffset(), it
->layout
->getID().name
) == 0) ) {
738 fprintf(stderr
, "update_dyld_shared_cache[%u] current cache invalid because %s has changed\n", getpid(), it
->layout
->getID().name
);
746 template <typename A
>
747 bool SharedCache
<A
>::notUpToDate(const char* cachePath
)
749 // mmap existing cache file
750 int fd
= ::open(cachePath
, O_RDONLY
);
753 struct stat stat_buf
;
754 ::fstat(fd
, &stat_buf
);
755 uint8_t* mappingAddr
= (uint8_t*)mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
757 if ( mappingAddr
== (uint8_t*)(-1) )
761 bool result
= this->notUpToDate(mappingAddr
);
763 ::munmap(mappingAddr
, stat_buf
.st_size
);
764 if ( verbose
&& !result
)
765 fprintf(stderr
, "update_dyld_shared_cache: %s is up-to-date\n", cachePath
);
773 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
780 const char* getBuffer();
782 uint32_t add(const char* str
);
783 uint32_t addUnique(const char* str
);
784 const char* stringAtIndex(uint32_t) const;
786 typedef __gnu_cxx::hash_map
<const char*, uint32_t, __gnu_cxx::hash
<const char*>, CStringEquals
> StringToOffset
;
789 uint32_t fBufferAllocated
;
790 uint32_t fBufferUsed
;
791 StringToOffset fUniqueStrings
;
795 StringPool::StringPool()
796 : fBufferUsed(0), fBufferAllocated(4*1024*1024)
798 fBuffer
= (char*)malloc(fBufferAllocated
);
801 uint32_t StringPool::add(const char* str
)
803 uint32_t len
= strlen(str
);
804 if ( (fBufferUsed
+ len
+ 1) > fBufferAllocated
) {
806 fBufferAllocated
= fBufferAllocated
*2;
807 fBuffer
= (char*)realloc(fBuffer
, fBufferAllocated
);
809 strcpy(&fBuffer
[fBufferUsed
], str
);
810 uint32_t result
= fBufferUsed
;
811 fUniqueStrings
[&fBuffer
[fBufferUsed
]] = result
;
812 fBufferUsed
+= len
+1;
816 uint32_t StringPool::addUnique(const char* str
)
818 StringToOffset::iterator pos
= fUniqueStrings
.find(str
);
819 if ( pos
!= fUniqueStrings
.end() )
822 //fprintf(stderr, "StringPool::addUnique() new string: %s\n", str);
823 return this->add(str
);
827 uint32_t StringPool::size()
832 const char* StringPool::getBuffer()
837 const char* StringPool::stringAtIndex(uint32_t index
) const
839 return &fBuffer
[index
];
843 template <typename A
>
844 class LinkEditOptimizer
847 LinkEditOptimizer(const MachOLayoutAbstraction
&, uint8_t*, StringPool
&);
848 virtual ~LinkEditOptimizer() {}
850 static void makeDummyLocalSymbol(uint32_t&, uint8_t*, StringPool
&);
851 void copyLocalSymbols();
852 void copyExportedSymbols(uint32_t&);
853 void copyImportedSymbols(uint32_t&);
854 void copyExternalRelocations(uint32_t&);
855 void copyIndirectSymbolTable(uint32_t&);
856 void updateLoadCommands(uint64_t newVMAddress
, uint64_t size
, uint32_t stringPoolOffset
);
860 typedef typename
A::P P
;
861 typedef typename
A::P::E E
;
862 typedef typename
A::P::uint_t pint_t
;
866 const macho_header
<P
>* fHeader
;
867 uint8_t* fNewLinkEditStart
;
868 uint8_t* fLinkEditBase
;
869 const MachOLayoutAbstraction
& fLayout
;
870 macho_dysymtab_command
<P
>* fDynamicSymbolTable
;
871 macho_symtab_command
<P
>* fSymbolTableLoadCommand
;
872 const macho_nlist
<P
>* fSymbolTable
;
873 const char* fStrings
;
874 StringPool
& fNewStringPool
;
875 std::map
<uint32_t,uint32_t> fOldToNewSymbolIndexes
;
876 uint32_t fLocalSymbolsStartIndexInNewLinkEdit
;
877 uint32_t fLocalSymbolsCountInNewLinkEdit
;
878 uint32_t fExportedSymbolsStartIndexInNewLinkEdit
;
879 uint32_t fExportedSymbolsCountInNewLinkEdit
;
880 uint32_t fImportSymbolsStartIndexInNewLinkEdit
;
881 uint32_t fImportedSymbolsCountInNewLinkEdit
;
882 uint32_t fExternalRelocationsOffsetIntoNewLinkEdit
;
883 uint32_t fIndirectSymbolTableOffsetInfoNewLinkEdit
;
884 static int32_t fgLocalSymbolsStartIndexInNewLinkEdit
;
887 template <typename A
> int32_t LinkEditOptimizer
<A
>::fgLocalSymbolsStartIndexInNewLinkEdit
= 0;
890 template <typename A
>
891 LinkEditOptimizer
<A
>::LinkEditOptimizer(const MachOLayoutAbstraction
& layout
, uint8_t* newLinkEdit
, StringPool
& stringPool
)
892 : fLayout(layout
), fLinkEditBase(NULL
), fNewLinkEditStart(newLinkEdit
),
893 fDynamicSymbolTable(NULL
), fSymbolTableLoadCommand(NULL
), fSymbolTable(NULL
), fStrings(NULL
), fNewStringPool(stringPool
),
894 fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
895 fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
896 fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
897 fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0)
900 fHeader
= (const macho_header
<P
>*)fLayout
.getSegments()[0].mappedAddress();
902 const std::vector
<MachOLayoutAbstraction::Segment
>& segments
= fLayout
.getSegments();
903 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator it
= segments
.begin(); it
!= segments
.end(); ++it
) {
904 const MachOLayoutAbstraction::Segment
& seg
= *it
;
905 if ( strcmp(seg
.name(), "__LINKEDIT") == 0 )
906 fLinkEditBase
= (uint8_t*)seg
.mappedAddress() - seg
.fileOffset();
908 if ( fLinkEditBase
== NULL
)
909 throw "no __LINKEDIT segment";
911 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
912 const uint32_t cmd_count
= fHeader
->ncmds();
913 const macho_load_command
<P
>* cmd
= cmds
;
914 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
915 switch (cmd
->cmd()) {
918 fSymbolTableLoadCommand
= (macho_symtab_command
<P
>*)cmd
;
919 fSymbolTable
= (macho_nlist
<P
>*)(&fLinkEditBase
[fSymbolTableLoadCommand
->symoff()]);
920 fStrings
= (char*)&fLinkEditBase
[fSymbolTableLoadCommand
->stroff()];
924 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
927 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
929 if ( fSymbolTable
== NULL
)
930 throw "no LC_SYMTAB";
931 if ( fDynamicSymbolTable
== NULL
)
932 throw "no LC_DYSYMTAB";
937 template <typename A
>
941 typedef typename
A::P P
;
942 SymbolSorter(const StringPool
& pool
) : fStringPool(pool
) {}
943 bool operator()(const macho_nlist
<P
>& left
, const macho_nlist
<P
>& right
) {
944 return (strcmp(fStringPool
.stringAtIndex(left
.n_strx()) , fStringPool
.stringAtIndex(right
.n_strx())) < 0);
948 const StringPool
& fStringPool
;
952 template <typename A
>
953 void LinkEditOptimizer
<A
>::makeDummyLocalSymbol(uint32_t& symbolIndex
, uint8_t* storage
, StringPool
& pool
)
955 fgLocalSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
956 macho_nlist
<P
>* newSymbolEntry
= (macho_nlist
<P
>*)storage
;
957 newSymbolEntry
->set_n_strx(pool
.add("__no_local_symbols_in_dyld_shared_cache"));
958 newSymbolEntry
->set_n_type(N_SECT
);
959 newSymbolEntry
->set_n_sect(1);
960 newSymbolEntry
->set_n_desc(0);
961 newSymbolEntry
->set_n_value(0);
965 template <typename A
>
966 void LinkEditOptimizer
<A
>::copyLocalSymbols()
968 if ( fDynamicSymbolTable
->nlocalsym() > 0 ) {
969 // if image has any local symbols, make cache look like it has one local symbol
970 // which is actually shared by all images
971 fLocalSymbolsCountInNewLinkEdit
= 1;
972 fLocalSymbolsStartIndexInNewLinkEdit
= fgLocalSymbolsStartIndexInNewLinkEdit
;
977 template <typename A
>
978 void LinkEditOptimizer
<A
>::copyExportedSymbols(uint32_t& symbolIndex
)
980 fExportedSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
981 const macho_nlist
<P
>* const firstExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()];
982 const macho_nlist
<P
>* const lastExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
983 uint32_t oldIndex
= fDynamicSymbolTable
->iextdefsym();
984 for (const macho_nlist
<P
>* entry
= firstExport
; entry
< lastExport
; ++entry
, ++oldIndex
) {
985 if ( ((entry
->n_type() & N_TYPE
) == N_SECT
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0) ) {
986 macho_nlist
<P
>* newSymbolEntry
= &((macho_nlist
<P
>*)fNewLinkEditStart
)[symbolIndex
];
987 *newSymbolEntry
= *entry
;
988 newSymbolEntry
->set_n_strx(fNewStringPool
.add(&fStrings
[entry
->n_strx()]));
989 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
;
993 fExportedSymbolsCountInNewLinkEdit
= symbolIndex
- fExportedSymbolsStartIndexInNewLinkEdit
;
994 //fprintf(stderr, "%u exports starting at %u for %s\n", fExportedSymbolsCountInNewLinkEdit, fExportedSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
995 // sort by name, so that dyld does not need a toc
996 macho_nlist
<P
>* newSymbolsStart
= &((macho_nlist
<P
>*)fNewLinkEditStart
)[fExportedSymbolsStartIndexInNewLinkEdit
];
997 macho_nlist
<P
>* newSymbolsEnd
= &((macho_nlist
<P
>*)fNewLinkEditStart
)[fExportedSymbolsStartIndexInNewLinkEdit
+fExportedSymbolsCountInNewLinkEdit
];
998 std::sort(newSymbolsStart
, newSymbolsEnd
, SymbolSorter
<A
>(fNewStringPool
));
999 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1000 // fprintf(stderr, "\t%u\t %s\n", (entry-newSymbolsStart)+fExportedSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1004 template <typename A
>
1005 void LinkEditOptimizer
<A
>::copyImportedSymbols(uint32_t& symbolIndex
)
1007 fImportSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1008 const macho_nlist
<P
>* const firstImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()];
1009 const macho_nlist
<P
>* const lastImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()+fDynamicSymbolTable
->nundefsym()];
1010 uint32_t oldIndex
= fDynamicSymbolTable
->iundefsym();
1011 for (const macho_nlist
<P
>* entry
= firstImport
; entry
< lastImport
; ++entry
, ++oldIndex
) {
1012 if ( ((entry
->n_type() & N_TYPE
) == N_UNDF
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0) ) {
1013 macho_nlist
<P
>* newSymbolEntry
= &((macho_nlist
<P
>*)fNewLinkEditStart
)[symbolIndex
];
1014 *newSymbolEntry
= *entry
;
1015 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1016 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
;
1020 fImportedSymbolsCountInNewLinkEdit
= symbolIndex
- fImportSymbolsStartIndexInNewLinkEdit
;
1021 //fprintf(stderr, "%u imports starting at %u for %s\n", fImportedSymbolsCountInNewLinkEdit, fImportSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1022 //macho_nlist<P>* newSymbolsStart = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit];
1023 //macho_nlist<P>* newSymbolsEnd = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit];
1024 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1025 // fprintf(stderr, "\t%u\t%s\n", (entry-newSymbolsStart)+fImportSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1029 template <typename A
>
1030 void LinkEditOptimizer
<A
>::copyExternalRelocations(uint32_t& offset
)
1032 fExternalRelocationsOffsetIntoNewLinkEdit
= offset
;
1033 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(&fLinkEditBase
[fDynamicSymbolTable
->extreloff()]);
1034 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
1035 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1036 macho_relocation_info
<P
>* newReloc
= (macho_relocation_info
<P
>*)(&fNewLinkEditStart
[offset
]);
1038 uint32_t newSymbolIndex
= fOldToNewSymbolIndexes
[reloc
->r_symbolnum()];
1039 //fprintf(stderr, "copyExternalRelocations() old=%d, new=%u name=%s in %s\n", reloc->r_symbolnum(), newSymbolIndex,
1040 // &fStrings[fSymbolTable[reloc->r_symbolnum()].n_strx()], fLayout.getFilePath());
1041 newReloc
->set_r_symbolnum(newSymbolIndex
);
1042 offset
+= sizeof(macho_relocation_info
<P
>);
1046 template <typename A
>
1047 void LinkEditOptimizer
<A
>::copyIndirectSymbolTable(uint32_t& offset
)
1049 fIndirectSymbolTableOffsetInfoNewLinkEdit
= offset
;
1050 const uint32_t* const indirectTable
= (uint32_t*)&this->fLinkEditBase
[fDynamicSymbolTable
->indirectsymoff()];
1051 uint32_t* newIndirectTable
= (uint32_t*)&fNewLinkEditStart
[offset
];
1052 for (int i
=0; i
< fDynamicSymbolTable
->nindirectsyms(); ++i
) {
1053 uint32_t oldSymbolIndex
= E::get32(indirectTable
[i
]);
1054 uint32_t newSymbolIndex
= oldSymbolIndex
;
1055 if ( (oldSymbolIndex
!= INDIRECT_SYMBOL_ABS
) && (oldSymbolIndex
!= INDIRECT_SYMBOL_LOCAL
) ) {
1056 newSymbolIndex
= fOldToNewSymbolIndexes
[oldSymbolIndex
];
1057 //fprintf(stderr, "copyIndirectSymbolTable() old=%d, new=%u name=%s in %s\n", oldSymbolIndex, newSymbolIndex,
1058 // &fStrings[fSymbolTable[oldSymbolIndex].n_strx()], fLayout.getFilePath());
1060 E::set32(newIndirectTable
[i
], newSymbolIndex
);
1062 offset
+= (fDynamicSymbolTable
->nindirectsyms() * 4);
1065 template <typename A
>
1066 void LinkEditOptimizer
<A
>::updateLoadCommands(uint64_t newVMAddress
, uint64_t size
, uint32_t stringPoolOffset
)
1068 // set LINKEDIT segment commmand to new merged LINKEDIT
1069 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
1070 const uint32_t cmd_count
= fHeader
->ncmds();
1071 const macho_load_command
<P
>* cmd
= cmds
;
1072 uint32_t linkEditStartFileOffset
= 0;
1073 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1074 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
1075 macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
1076 if ( strcmp(seg
->segname(), "__LINKEDIT") == 0 ) {
1077 seg
->set_vmaddr(newVMAddress
);
1078 seg
->set_vmsize(size
);
1079 seg
->set_filesize(size
);
1080 linkEditStartFileOffset
= seg
->fileoff();
1083 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1086 // update symbol table and dynamic symbol table with new offsets
1087 fSymbolTableLoadCommand
->set_symoff(linkEditStartFileOffset
);
1088 fSymbolTableLoadCommand
->set_nsyms(fExportedSymbolsCountInNewLinkEdit
+fImportedSymbolsCountInNewLinkEdit
);
1089 fSymbolTableLoadCommand
->set_stroff(linkEditStartFileOffset
+stringPoolOffset
);
1090 fSymbolTableLoadCommand
->set_strsize(fNewStringPool
.size());
1091 fDynamicSymbolTable
->set_ilocalsym(fLocalSymbolsStartIndexInNewLinkEdit
);
1092 fDynamicSymbolTable
->set_nlocalsym(fLocalSymbolsCountInNewLinkEdit
);
1093 fDynamicSymbolTable
->set_iextdefsym(fExportedSymbolsStartIndexInNewLinkEdit
);
1094 fDynamicSymbolTable
->set_nextdefsym(fExportedSymbolsCountInNewLinkEdit
);
1095 fDynamicSymbolTable
->set_iundefsym(fImportSymbolsStartIndexInNewLinkEdit
);
1096 fDynamicSymbolTable
->set_nundefsym(fImportedSymbolsCountInNewLinkEdit
);
1097 fDynamicSymbolTable
->set_tocoff(0);
1098 fDynamicSymbolTable
->set_ntoc(0);
1099 fDynamicSymbolTable
->set_modtaboff(0);
1100 fDynamicSymbolTable
->set_nmodtab(0);
1101 fDynamicSymbolTable
->set_indirectsymoff(linkEditStartFileOffset
+fIndirectSymbolTableOffsetInfoNewLinkEdit
);
1102 fDynamicSymbolTable
->set_extreloff(linkEditStartFileOffset
+fExternalRelocationsOffsetIntoNewLinkEdit
);
1103 fDynamicSymbolTable
->set_locreloff(0);
1104 fDynamicSymbolTable
->set_nlocrel(0);
1109 template <typename A
>
1110 uint8_t* SharedCache
<A
>::optimizeLINKEDIT()
1112 // allocate space for optimized LINKEDIT area
1113 uint8_t* newLinkEdit
= new uint8_t[fLinkEditsTotalUnoptimizedSize
];
1114 bzero(newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
1116 // make a string pool
1117 StringPool stringPool
;
1119 // create optimizer object for each LINKEDIT segment
1120 std::vector
<LinkEditOptimizer
<A
>*> optimizers
;
1121 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1122 optimizers
.push_back(new LinkEditOptimizer
<A
>(*it
->layout
, newLinkEdit
, stringPool
));
1125 // copy local symbol table entries
1126 uint32_t symbolTableIndex
= 0;
1127 LinkEditOptimizer
<A
>::makeDummyLocalSymbol(symbolTableIndex
, newLinkEdit
, stringPool
);
1128 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1129 (*it
)->copyLocalSymbols();
1132 // copy exported symbol table entries
1133 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1134 (*it
)->copyExportedSymbols(symbolTableIndex
);
1136 //fprintf(stderr, "%u exported symbols, with %d bytes of strings\n", symbolTableIndex, stringPool.size());
1137 //uint32_t importStart = symbolTableIndex;
1138 //uint32_t importPoolStart = stringPool.size();
1140 // copy imported symbol table entries
1141 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1142 (*it
)->copyImportedSymbols(symbolTableIndex
);
1144 //fprintf(stderr, "%u imported symbols, with %d bytes of strings\n", symbolTableIndex-importStart, stringPool.size()-importPoolStart);
1146 // copy external relocations, 8-byte aligned after end of symbol table
1147 uint32_t externalRelocsOffset
= (symbolTableIndex
* sizeof(macho_nlist
<typename
A::P
>) + 7) & (-8);
1148 //uint32_t externalRelocsStartOffset = externalRelocsOffset;
1149 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1150 (*it
)->copyExternalRelocations(externalRelocsOffset
);
1152 //fprintf(stderr, "%u bytes of external relocs\n", externalRelocsOffset-externalRelocsStartOffset);
1154 // copy indirect symbol tables
1155 uint32_t indirectSymbolTableOffset
= externalRelocsOffset
;
1156 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1157 (*it
)->copyIndirectSymbolTable(indirectSymbolTableOffset
);
1161 uint32_t stringPoolOffset
= indirectSymbolTableOffset
;
1162 memcpy(&newLinkEdit
[stringPoolOffset
], stringPool
.getBuffer(), stringPool
.size());
1165 uint32_t linkEditsTotalOptimizedSize
= (stringPoolOffset
+ stringPool
.size() + 4095) & (-4096);
1167 // update load commands so that all dylibs shared different areas of the same LINKEDIT segment
1168 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1169 (*it
)->updateLoadCommands(fLinkEditsStartAddress
, fLinkEditsTotalUnoptimizedSize
, stringPoolOffset
);
1172 //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, linkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, linkEditsTotalOptimizedSize);
1173 //fprintf(stderr, "mega link edit mapped starting at: %p\n", fFirstLinkEditSegment->mappedAddress());
1175 // overwrite mapped LINKEDIT area with new optimized LINKEDIT segment
1176 memcpy(fFirstLinkEditSegment
->mappedAddress(), newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
1178 // update all LINKEDIT Segment objects to point to same merged LINKEDIT area
1179 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1180 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1181 for(int i
=0; i
< segs
.size(); ++i
) {
1182 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1183 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
1184 seg
.setNewAddress(fLinkEditsStartAddress
);
1185 seg
.setMappedAddress(fFirstLinkEditSegment
->mappedAddress());
1186 seg
.setSize(linkEditsTotalOptimizedSize
);
1187 seg
.setFileSize(linkEditsTotalOptimizedSize
);
1188 //seg.setFileOffset(0);
1193 // return new end of cache
1194 return (uint8_t*)fFirstLinkEditSegment
->mappedAddress() + linkEditsTotalOptimizedSize
;
1198 template <typename A
>
1199 bool SharedCache
<A
>::update(const char* rootPath
, const char* cacheDir
, bool force
, bool optimize
, int archIndex
, int archCount
)
1201 bool didUpdate
= false;
1202 char cachePath
[1024];
1203 strcpy(cachePath
, rootPath
);
1204 strcat(cachePath
, cacheDir
);
1205 strcat(cachePath
, DYLD_SHARED_CACHE_BASE_NAME
);
1206 strcat(cachePath
, filename(optimize
));
1208 // already up to date?
1209 if ( force
|| this->notUpToDate(cachePath
) ) {
1211 fprintf(stderr
, "update_dyld_shared_cache: regenerating %s\n", cachePath
);
1212 if ( fDylibs
.size() == 0 ) {
1213 fprintf(stderr
, "update_dyld_shared_cache: warning, empty cache not generated for arch %s\n", archName());
1216 char tempCachePath
[strlen(cachePath
)+16];
1217 sprintf(tempCachePath
, "%s.tmp%u", cachePath
, getpid());
1219 int fd
= ::open(tempCachePath
, O_CREAT
| O_RDWR
| O_TRUNC
, 0644);
1221 throwf("can't create temp file %s, errnor=%d", tempCachePath
, errno
);
1223 // try to allocate whole cache file contiguously
1224 uint32_t cacheFileSize
= 0;
1225 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1226 uint32_t end
= it
->sfm_file_offset
+ it
->sfm_size
;
1227 if ( end
> cacheFileSize
)
1228 cacheFileSize
= end
;
1230 fstore_t fcntlSpec
= { F_ALLOCATECONTIG
|F_ALLOCATEALL
, F_PEOFPOSMODE
, 0, cacheFileSize
, 0 };
1231 fcntl(fd
, F_PREALLOCATE
, &fcntlSpec
);
1233 // fill in cache header memory buffer
1234 uint8_t buffer
[pageAlign(fHeaderSize
)];
1235 bzero(buffer
, sizeof(buffer
));
1238 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)buffer
;
1240 strcpy(temp
, "dyld_v1 ");
1241 strcpy(&temp
[15-strlen(archName())], archName());
1242 header
->set_magic(temp
);
1243 //header->set_architecture(arch());
1244 header
->set_mappingOffset(sizeof(dyldCacheHeader
<E
>));
1245 header
->set_mappingCount(fMappings
.size());
1246 header
->set_imagesOffset(header
->mappingOffset() + fMappings
.size()*sizeof(dyldCacheFileMapping
<E
>));
1247 header
->set_imagesCount(fDylibs
.size());
1248 header
->set_dyldBaseAddress(fDyldBaseAddress
);
1249 //header->set_dependenciesOffset(sizeof(dyldCacheHeader<E>) + fMappings.size()*sizeof(dyldCacheFileMapping<E>) + fDylibs.size()*sizeof(dyldCacheImageInfo<E>));
1250 //header->set_dependenciesCount(fDependencyPool.size());
1253 dyldCacheFileMapping
<E
>* mapping
= (dyldCacheFileMapping
<E
>*)&buffer
[sizeof(dyldCacheHeader
<E
>)];
1254 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1256 fprintf(stderr
, "update_dyld_shared_cache: cache mappings: address=0x%0llX, size=0x%0llX, fileOffset=0x%0llX, prot=0x%X\n",
1257 it
->sfm_address
, it
->sfm_size
, it
->sfm_file_offset
, it
->sfm_init_prot
);
1258 mapping
->set_address(it
->sfm_address
);
1259 mapping
->set_size(it
->sfm_size
);
1260 mapping
->set_file_offset(it
->sfm_file_offset
);
1261 mapping
->set_max_prot(it
->sfm_max_prot
);
1262 mapping
->set_init_prot(it
->sfm_init_prot
);
1266 // fill in image table
1267 dyldCacheImageInfo
<E
>* image
= (dyldCacheImageInfo
<E
>*)mapping
;
1268 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1269 image
->set_address(it
->info
.address
);
1270 image
->set_modTime(it
->info
.modTime
);
1271 image
->set_inode(it
->info
.inode
);
1272 image
->set_pathFileOffset(cacheFileOffsetForAddress(it
->info
.address
+it
->info
.pathFileOffset
));
1273 //image->set_dependenciesStartOffset(it->info.dependenciesStartOffset);
1277 // write whole header to disk
1278 pwrite(fd
, buffer
, sizeof(buffer
), 0);
1280 // allocate copy buffer
1281 const uint64_t kCopyBufferSize
= 256*1024;
1282 uint8_t* copyBuffer
;
1283 vm_address_t addr
= 0;
1284 if ( vm_allocate(mach_task_self(), &addr
, kCopyBufferSize
, VM_FLAGS_ANYWHERE
) == KERN_SUCCESS
)
1285 copyBuffer
= (uint8_t*)addr
;
1287 throw "can't allcoate copy buffer";
1289 // make zero-fill buffer
1290 uint8_t zerofill
[4096];
1291 bzero(zerofill
, sizeof(zerofill
));
1293 // write each segment to cache file
1295 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++dylibIndex
) {
1296 const char* path
= it
->layout
->getFilePath();
1297 int src
= ::open(path
, O_RDONLY
, 0);
1299 throwf("can't open file %s, errnor=%d", it
->layout
->getID().name
, errno
);
1300 // mark source as "don't cache"
1301 (void)fcntl(src
, F_NOCACHE
, 1);
1304 fprintf(stderr
, "update_prebinding: copying %s to cache\n", it
->layout
->getID().name
);
1306 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
1307 for (int i
=0; i
< segs
.size(); ++i
) {
1308 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1310 fprintf(stderr
, "\t\tsegment %s, size=0x%0llX, cache address=0x%0llX\n", seg
.name(), seg
.fileSize(), seg
.newAddress());
1311 if ( seg
.size() > 0 ) {
1312 const uint64_t segmentSrcStartOffset
= it
->layout
->getOffsetInUniversalFile()+seg
.fileOffset();
1313 const uint64_t segmentSize
= seg
.fileSize();
1314 const uint64_t segmentDstStartOffset
= cacheFileOffsetForAddress(seg
.newAddress());
1315 for(uint64_t copiedAmount
=0; copiedAmount
< segmentSize
; copiedAmount
+= kCopyBufferSize
) {
1316 uint64_t amount
= std::min(segmentSize
-copiedAmount
, kCopyBufferSize
);
1317 //fprintf(stderr, "copy 0x%08llX bytes at offset 0x%08llX for segment %s in %s to cache offset 0x%08llX\n",
1318 // amount, segmentSrcStartOffset+copiedAmount, seg.name(), it->layout->getID().name, segmentDstStartOffset+copiedAmount);
1319 if ( ::pread(src
, copyBuffer
, amount
, segmentSrcStartOffset
+copiedAmount
) != amount
)
1320 throwf("read failure copying dylib errno=%d for %s", errno
, it
->layout
->getID().name
);
1321 if ( ::pwrite(fd
, copyBuffer
, amount
, segmentDstStartOffset
+copiedAmount
) != amount
)
1322 throwf("write failure copying dylib errno=%d for %s", errno
, it
->layout
->getID().name
);
1324 if ( seg
.size() > seg
.fileSize() ) {
1325 // write zero-filled area
1326 for(uint64_t copiedAmount
=seg
.fileSize(); copiedAmount
< seg
.size(); copiedAmount
+= sizeof(zerofill
)) {
1327 uint64_t amount
= std::min(seg
.size()-copiedAmount
, (uint64_t)(sizeof(zerofill
)));
1328 if ( ::pwrite(fd
, zerofill
, amount
, segmentDstStartOffset
+copiedAmount
) != amount
)
1329 throwf("write failure copying dylib errno=%d for %s", errno
, it
->layout
->getID().name
);
1335 catch (const char* msg
) {
1336 throwf("%s while copying %s to shared cache", msg
, it
->layout
->getID().name
);
1342 vm_deallocate(mach_task_self(), addr
, kCopyBufferSize
);
1345 fMappedCacheFile
= (uint8_t*)mmap(NULL
, cacheFileSize
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0);
1346 if ( fMappedCacheFile
== (uint8_t*)(-1) )
1347 throw "can't mmap cache file";
1353 // set mapped address for each segment
1354 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1355 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1356 for (int i
=0; i
< segs
.size(); ++i
) {
1357 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1358 if ( seg
.size() > 0 )
1359 seg
.setMappedAddress(fMappedCacheFile
+ cacheFileOffsetForAddress(seg
.newAddress()));
1360 //fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
1364 // rebase each dylib in shared cache
1365 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1367 Rebaser
<A
> r(*it
->layout
);
1370 // fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
1372 catch (const char* msg
) {
1373 throwf("%s in %s", msg
, it
->layout
->getID().name
);
1377 // merge/optimize all LINKEDIT segments
1379 //fprintf(stderr, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize/(1024*1024));
1380 cacheFileSize
= (this->optimizeLINKEDIT() - fMappedCacheFile
);
1381 //fprintf(stderr, "update_dyld_shared_cache: optimized cache file size %uMB\n", cacheFileSize/(1024*1024));
1382 // update header to reduce mapping size
1383 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)fMappedCacheFile
;
1384 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&fMappedCacheFile
[sizeof(dyldCacheHeader
<E
>)];
1385 dyldCacheFileMapping
<E
>* lastMapping
= &mappings
[cacheHeader
->mappingCount()-1];
1386 lastMapping
->set_size(cacheFileSize
-lastMapping
->file_offset());
1387 // update fMappings so .map file will print correctly
1388 fMappings
.back().sfm_size
= cacheFileSize
-fMappings
.back().sfm_file_offset
;
1392 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs
.size());
1393 // instantiate a Binder for each image and add to map
1394 typename Binder
<A
>::Map map
;
1395 std::vector
<Binder
<A
>*> binders
;
1396 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1397 //fprintf(stderr, "binding %s\n", it->layout->getID().name);
1398 Binder
<A
>* binder
= new Binder
<A
>(*it
->layout
, fDyldBaseAddress
);
1399 binders
.push_back(binder
);
1400 // only add dylibs to map
1401 if ( it
->layout
->getID().name
!= NULL
)
1402 map
[it
->layout
->getID().name
] = binder
;
1404 // tell each Binder about the others
1405 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
1406 (*it
)->setDependentBinders(map
);
1409 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
1411 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it
)->getDylibID());
1415 catch (const char* msg
) {
1416 throwf("%s in %s", msg
, (*it
)->getDylibID());
1420 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
1425 int result
= ::msync(fMappedCacheFile
, cacheFileSize
, MS_SYNC
);
1427 throw "error syncing cache file";
1428 result
= ::munmap(fMappedCacheFile
, cacheFileSize
);
1430 throw "error unmapping cache file";
1432 // cut back cache file to match optmized size
1434 if ( ::truncate(tempCachePath
, cacheFileSize
) != 0 )
1435 throw "error truncating cache file";
1440 // flush everything to disk, otherwise if kernel panics before the cache file is completely written to disk
1441 // then next reboot will use a corrupted cache and die
1442 result
= ::rename(tempCachePath
, cachePath
);
1444 throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath
, cachePath
, errno
);
1445 // flush everything to disk to assure rename() gets recorded
1449 // generate human readable "map" file that shows the layout of the cache file
1450 sprintf(tempCachePath
, "%s.map", cachePath
);// re-use path buffer
1451 FILE* fmap
= ::fopen(tempCachePath
, "w");
1452 if ( fmap
== NULL
) {
1453 fprintf(stderr
, "can't create map file %s, errnor=%d", tempCachePath
, errno
);
1456 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1457 const char* prot
= "RW";
1458 if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_READ
) )
1460 else if ( it
->sfm_init_prot
== VM_PROT_READ
)
1462 else if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_WRITE
|VM_PROT_READ
) )
1464 if ( it
->sfm_size
> 1024*1024 )
1465 fprintf(fmap
, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/(1024*1024),
1466 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
1468 fprintf(fmap
, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/1024,
1469 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
1471 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1472 fprintf(fmap
, "%s\n", it
->layout
->getID().name
);
1473 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
1474 for (int i
=0; i
< segs
.size(); ++i
) {
1475 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1476 fprintf(fmap
, "\t%16s 0x%0llX -> 0x%0llX\n", seg
.name(), seg
.newAddress(), seg
.newAddress()+seg
.size());
1479 if ( warnings
.size() > 0 ) {
1480 fprintf(fmap
, "# Warnings:\n");
1481 for (std::vector
<const char*>::iterator it
=warnings
.begin(); it
!= warnings
.end(); ++it
) {
1482 fprintf(fmap
, "# %s\n", *it
);
1489 // remove temp cache
1490 ::unlink(tempCachePath
);
1500 // The shared cache is driven by /var/db/dyld/shared_region_roots which contains
1501 // the paths used to search for dylibs that should go in the shared cache
1503 // Leading and trailing white space is ignored
1504 // Blank lines are ignored
1505 // Lines starting with # are ignored
1507 static void parsePathsFile(const char* filePath
, std::vector
<const char*>& paths
)
1509 // read in whole file
1510 int fd
= open(filePath
, O_RDONLY
, 0);
1512 fprintf(stderr
, "update_dyld_shared_cache: can't open file: %s\n", filePath
);
1515 struct stat stat_buf
;
1516 fstat(fd
, &stat_buf
);
1517 char* p
= (char*)malloc(stat_buf
.st_size
);
1519 fprintf(stderr
, "update_dyld_shared_cache: malloc failure\n");
1522 if ( read(fd
, p
, stat_buf
.st_size
) != stat_buf
.st_size
) {
1523 fprintf(stderr
, "update_dyld_shared_cache: can't read file: %s\n", filePath
);
1528 // parse into paths and add to vector
1529 char * const end
= &p
[stat_buf
.st_size
];
1530 enum { lineStart
, inSymbol
, inComment
} state
= lineStart
;
1531 char* symbolStart
= NULL
;
1532 for (char* s
= p
; s
< end
; ++s
) {
1538 else if ( !isspace(*s
) ) {
1546 // removing any trailing spaces
1548 while ( isspace(*last
) ) {
1552 paths
.push_back(symbolStart
);
1563 // Note: we do not free() the malloc buffer, because the strings in it are used by exec()
1567 static void scanForSharedDylibs(const char* rootPath
, const char* dirOfPathFiles
, const std::set
<cpu_type_t
>& onlyArchs
)
1569 char rootDirOfPathFiles
[strlen(rootPath
)+strlen(dirOfPathFiles
)+2];
1570 if ( strlen(rootPath
) != 0 ) {
1571 strcpy(rootDirOfPathFiles
, rootPath
);
1572 strcat(rootDirOfPathFiles
, dirOfPathFiles
);
1573 dirOfPathFiles
= rootDirOfPathFiles
;
1576 // extract all root paths from files in "/var/db/dyld/shared_region_roots/"
1578 fprintf(stderr
, "update_dyld_shared_cache: finding roots in: %s\n", dirOfPathFiles
);
1579 std::vector
<const char*> rootsPaths
;
1580 DIR* dir
= ::opendir(dirOfPathFiles
);
1582 throwf("%s does not exist, errno=%d\n", dirOfPathFiles
, errno
);
1583 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
1584 if ( entry
->d_type
== DT_REG
) {
1585 // only look at files ending in .paths
1586 if ( strcmp(&entry
->d_name
[entry
->d_namlen
-6], ".paths") == 0 ) {
1587 char fullPath
[strlen(dirOfPathFiles
)+entry
->d_namlen
+2];
1588 strcpy(fullPath
, dirOfPathFiles
);
1589 strcat(fullPath
, "/");
1590 strcat(fullPath
, entry
->d_name
);
1591 parsePathsFile(fullPath
, rootsPaths
);
1594 fprintf(stderr
, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry
->d_name
);
1600 // set file system root
1601 ArchGraph::setFileSystemRoot(rootPath
);
1603 // initialize all architectures requested
1604 for(std::set
<cpu_type_t
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
1605 ArchGraph::addArch(*a
);
1607 // add roots to graph
1608 for(std::vector
<const char*>::iterator it
= rootsPaths
.begin(); it
!= rootsPaths
.end(); ++it
)
1609 ArchGraph::addRoot(*it
, onlyArchs
);
1611 // determine shared dylibs
1612 for(std::set
<cpu_type_t
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
1613 ArchGraph::findSharedDylibs(*a
);
1615 if ( rootsPaths
.size() == 0 )
1616 fprintf(stderr
, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
1621 static bool updateSharedeCacheFile(const char* rootPath
, const char* cacheDir
, const std::set
<cpu_type_t
>& onlyArchs
,
1622 bool force
, bool alphaSort
, bool optimize
)
1624 bool didUpdate
= false;
1625 // get dyld load address info
1626 UniversalMachOLayout
* dyldLayout
= new UniversalMachOLayout("/usr/lib/dyld", &onlyArchs
);
1628 const int archCount
= onlyArchs
.size();
1630 for(std::set
<cpu_type_t
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
, ++index
) {
1631 const MachOLayoutAbstraction
* dyldLayoutForArch
= dyldLayout
->getArch(*a
);
1632 if ( dyldLayoutForArch
== NULL
)
1633 throw "dyld not avaiable for specified architecture";
1634 uint64_t dyldBaseAddress
= dyldLayoutForArch
->getBaseAddress();
1636 case CPU_TYPE_POWERPC
:
1638 SharedCache
<ppc
> cache(ArchGraph::getArch(*a
), alphaSort
, dyldBaseAddress
);
1640 // <rdar://problem/5217377> Rosetta does not work with optimized dyld shared cache
1641 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, false, index
, archCount
);
1643 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, optimize
, index
, archCount
);
1647 case CPU_TYPE_POWERPC64
:
1649 SharedCache
<ppc64
> cache(ArchGraph::getArch(*a
), alphaSort
, dyldBaseAddress
);
1650 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, optimize
, index
, archCount
);
1655 SharedCache
<x86
> cache(ArchGraph::getArch(*a
), alphaSort
, dyldBaseAddress
);
1656 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, optimize
, index
, archCount
);
1659 case CPU_TYPE_X86_64
:
1661 SharedCache
<x86_64
> cache(ArchGraph::getArch(*a
), alphaSort
, dyldBaseAddress
);
1662 didUpdate
|= cache
.update(rootPath
, cacheDir
, force
, optimize
, index
, archCount
);
1673 fprintf(stderr
, "update_dyld_shared_cache [-force] [-root dir] [-arch arch] [-debug]\n");
1677 kern_return_t
do_dyld_shared_cache_missing(mach_port_t dyld_port
, cpu_type_t arch
)
1679 std::set
<cpu_type_t
> onlyArchs
;
1680 onlyArchs
.insert(arch
);
1682 scanForSharedDylibs("", "/var/db/dyld/shared_region_roots/", onlyArchs
);
1683 if ( updateSharedeCacheFile("", DYLD_SHARED_CACHE_DIR
, onlyArchs
, false, false, true) )
1684 fprintf(stderr
, "update_dyld_shared_cache[%u] regenerated cache for arch=%s\n", getpid(), ArchGraph::archName(arch
));
1686 catch (const char* msg
) {
1687 fprintf(stderr
, "update_dyld_shared_cache[%u] for arch=%s failed: %s\n", getpid(), ArchGraph::archName(arch
), msg
);
1688 return KERN_FAILURE
;
1690 return KERN_SUCCESS
;
1694 kern_return_t
do_dyld_shared_cache_out_of_date(mach_port_t dyld_port
, cpu_type_t arch
)
1696 // reduce priority of this process so it only runs at the lowest priority
1697 setpriority(PRIO_PROCESS
, 0, PRIO_MAX
);
1699 // and then rebuild cache
1700 return do_dyld_shared_cache_missing(dyld_port
, arch
);
1704 int main(int argc
, const char* argv
[])
1707 if ( bootstrap_check_in(bootstrap_port
, "com.apple.dyld", &mp
) == KERN_SUCCESS
) {
1708 // started by launchd
1709 // Just process one message and quit
1710 mach_msg_size_t mxmsgsz
= sizeof(union __RequestUnion__do_dyld_server_subsystem
) + MAX_TRAILER_SIZE
;
1711 mach_msg_server_once(dyld_server_server
, mxmsgsz
, mp
, MACH_RCV_TIMEOUT
);
1712 // The problem with staying alive and processing messages is that the rest of this
1713 // tool leaks mapped memory and file descriptors. Quiting will clean that up.
1714 // <rdar://problem/5392427> 9A516 - Keep getting disk full errors
1718 // started as command line tool
1719 std::set
<cpu_type_t
> onlyArchs
;
1720 const char* rootPath
= "";
1722 bool alphaSort
= false;
1723 bool optimize
= true;
1724 bool makeSymLink
= false;
1727 // parse command line options
1728 for(int i
=1; i
< argc
; ++i
) {
1729 const char* arg
= argv
[i
];
1730 if ( arg
[0] == '-' ) {
1731 if ( strcmp(arg
, "-debug") == 0 ) {
1734 else if ( strcmp(arg
, "-force") == 0 ) {
1737 else if ( strcmp(arg
, "-sort_by_name") == 0 ) {
1740 else if ( strcmp(arg
, "-opt") == 0 ) {
1743 else if ( strcmp(arg
, "-no_opt") == 0 ) {
1746 else if ( (strcmp(arg
, "-root") == 0) || (strcmp(arg
, "--root") == 0) ) {
1747 rootPath
= argv
[++i
];
1748 if ( rootPath
== NULL
)
1749 throw "-root missing path argument";
1750 // strip tailing slashes
1751 int len
= strlen(rootPath
)-1;
1752 if ( rootPath
[len
] == '/' ) {
1753 char* newRootPath
= strdup(rootPath
);
1754 while ( newRootPath
[len
] == '/' )
1755 newRootPath
[len
--] = '\0';
1756 rootPath
= newRootPath
;
1759 else if ( strcmp(arg
, "-arch") == 0 ) {
1760 const char* arch
= argv
[++i
];
1761 if ( strcmp(arch
, "ppc") == 0 )
1762 onlyArchs
.insert(CPU_TYPE_POWERPC
);
1763 else if ( strcmp(arch
, "ppc64") == 0 )
1764 onlyArchs
.insert(CPU_TYPE_POWERPC64
);
1765 else if ( strcmp(arch
, "i386") == 0 )
1766 onlyArchs
.insert(CPU_TYPE_I386
);
1767 else if ( strcmp(arch
, "x86_64") == 0 )
1768 onlyArchs
.insert(CPU_TYPE_X86_64
);
1770 throwf("unknown architecture %s", arch
);
1772 else if ( strcmp(arg
, "-universal_boot") == 0 ) {
1774 throwf("universal_boot option can only be used on Intel machines");
1776 onlyArchs
.insert(CPU_TYPE_POWERPC
);
1777 onlyArchs
.insert(CPU_TYPE_I386
);
1782 throwf("unknown option: %s\n", arg
);
1787 throwf("unknown option: %s\n", arg
);
1791 // if no restrictions specified, use architectures that work on this machine
1792 if ( onlyArchs
.size() == 0 ) {
1794 size_t len
= sizeof(int);
1796 onlyArchs
.insert(CPU_TYPE_POWERPC
);
1797 if ( (sysctlbyname("hw.optional.64bitops", &available
, &len
, NULL
, 0) == 0) && available
)
1798 onlyArchs
.insert(CPU_TYPE_POWERPC64
);
1800 onlyArchs
.insert(CPU_TYPE_I386
);
1801 onlyArchs
.insert(CPU_TYPE_POWERPC
); // assume rosetta always available
1802 if ( (sysctlbyname("hw.optional.x86_64", &available
, &len
, NULL
, 0) == 0) && available
)
1803 onlyArchs
.insert(CPU_TYPE_X86_64
);
1805 #error unknown architecture
1809 if ( geteuid() != 0 )
1810 throw "you must be root to run this tool";
1812 // build list of shared dylibs
1813 scanForSharedDylibs(rootPath
, "/var/db/dyld/shared_region_roots/", onlyArchs
);
1814 updateSharedeCacheFile(rootPath
, DYLD_SHARED_CACHE_DIR
, onlyArchs
, force
, alphaSort
, optimize
);
1816 // To make a universal bootable image with dyld caches,
1817 // build the rosetta cache and symlink ppc to point to it.
1818 // A rosetta cache is just an unoptimized ppc cache, so ppc machine can use it too.
1819 // rdar://problem/5498469
1820 if ( makeSymLink
) {
1821 char symLinkLocation
[1024];
1822 strcpy(symLinkLocation
, rootPath
);
1823 strcat(symLinkLocation
, DYLD_SHARED_CACHE_DIR
);
1824 strcat(symLinkLocation
, DYLD_SHARED_CACHE_BASE_NAME
);
1825 strcat(symLinkLocation
, SharedCache
<ppc
>::filename(true));
1826 char symLinkTarget
[1024];
1827 strcpy(symLinkTarget
, DYLD_SHARED_CACHE_BASE_NAME
);
1828 strcat(symLinkTarget
, SharedCache
<ppc
>::filename(false));
1829 if ( symlink(symLinkTarget
, symLinkLocation
) == -1 ) {
1830 if ( errno
!= EEXIST
)
1831 throwf("symlink() returned errno=%d", errno
);
1835 catch (const char* msg
) {
1836 fprintf(stderr
, "update_dyld_shared_cache failed: %s\n", msg
);