1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.h>
28 #include <mach/mach.h>
29 #include <mach/mach_time.h>
40 #include <sys/param.h>
41 #include <sys/sysctl.h>
42 #include <sys/resource.h>
44 #include <servers/bootstrap.h>
45 #include <mach-o/loader.h>
46 #include <mach-o/fat.h>
48 #include <vproc_priv.h>
50 #include "dyld_cache_format.h"
55 #include <ext/hash_map>
57 #include "Architectures.hpp"
58 #include "MachOLayout.hpp"
59 #include "MachORebaser.hpp"
60 #include "MachOBinder.hpp"
61 #include "CacheFileAbstraction.hpp"
64 #include <objc/objc-selopt.h>
67 static bool verbose
= false;
68 static bool progress
= false;
69 static std::vector
<const char*> warnings
;
72 static void warn(const char *arch
, const char *format
, ...)
77 va_start(args
, format
);
78 ::vasprintf(&msg
, format
, args
);
81 warnings
.push_back(msg
);
84 ::fprintf(::stderr
, "update_dyld_shared_cache: warning: %s%s%s%s\n",
85 arch
? "for arch " : "",
93 static uint64_t pageAlign(uint64_t addr
) { return ( (addr
+ 4095) & (-4096) ); }
98 static void addArchPair(ArchPair ap
);
99 static void addRoot(const char* vpath
, const std::set
<ArchPair
>& archs
);
100 static void findSharedDylibs(ArchPair ap
);
101 static ArchGraph
* graphForArchPair(ArchPair ap
) { return fgPerArchGraph
[ap
]; }
102 static void setFileSystemRoot(const char* root
, bool usesOverlay
) { fgFileSystemRoot
= root
; fgUsesOverlay
= usesOverlay
; }
103 static const char* archName(ArchPair ap
);
105 ArchPair
getArchPair() { return fArchPair
; }
106 std::set
<const class MachOLayoutAbstraction
*>& getSharedDylibs() { return fSharedDylibs
; }
107 const char* archName() { return archName(fArchPair
); }
114 DependencyNode(ArchGraph
*, const char* path
, const MachOLayoutAbstraction
* layout
);
115 void loadDependencies(const MachOLayoutAbstraction
*);
116 void markNeededByRoot(DependencyNode
*);
117 const char* getPath() const { return fPath
; }
118 const MachOLayoutAbstraction
* getLayout() const { return fLayout
; }
119 size_t useCount() const { return fRootsDependentOnThis
.size(); }
120 bool allDependentsFound() const { return !fDependentMissing
; }
124 const MachOLayoutAbstraction
* fLayout
;
125 bool fDependenciesLoaded
;
126 bool fDependentMissing
;
127 std::set
<DependencyNode
*> fDependsOn
;
128 std::set
<DependencyNode
*> fRootsDependentOnThis
;
131 struct CStringEquals
{
132 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
134 typedef __gnu_cxx::hash_map
<const char*, class DependencyNode
*, __gnu_cxx::hash
<const char*>, CStringEquals
> PathToNode
;
137 ArchGraph(ArchPair ap
) : fArchPair(ap
) {}
138 void addRoot(const char* path
, const MachOLayoutAbstraction
*);
139 DependencyNode
* getNode(const char* path
);
140 DependencyNode
* getNodeForVirtualPath(const char* vpath
);
141 static bool canBeShared(const MachOLayoutAbstraction
* layout
, ArchPair ap
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
);
143 static std::map
<ArchPair
, ArchGraph
*> fgPerArchGraph
;
144 static const char* fgFileSystemRoot
;
145 static bool fgUsesOverlay
;
148 std::set
<DependencyNode
*> fRoots
;
150 std::set
<const MachOLayoutAbstraction
*> fSharedDylibs
; // use set to avoid duplicates when installname!=realpath
152 std::map
<ArchPair
, ArchGraph
*> ArchGraph::fgPerArchGraph
;
153 const char* ArchGraph::fgFileSystemRoot
= "";
154 bool ArchGraph::fgUsesOverlay
= false;
156 void ArchGraph::addArchPair(ArchPair ap
)
158 //fprintf(stderr, "adding ArchPair 0x%08X,0x%08X\n", ap.arch, ap.subtype);
159 fgPerArchGraph
[ap
] = new ArchGraph(ap
);
162 void ArchGraph::addRoot(const char* vpath
, const std::set
<ArchPair
>& onlyArchs
)
164 char completePath
[strlen(fgFileSystemRoot
)+strlen(vpath
)+2];
165 const char* path
= NULL
;
166 if ( strlen(fgFileSystemRoot
) == 0 ) {
170 strcpy(completePath
, fgFileSystemRoot
);
171 strcat(completePath
, vpath
); // assumes vpath starts with '/'
172 if ( fgUsesOverlay
) {
173 // using -overlay means if /overlay/usr/lib exists use it, otherwise use original path
174 struct stat stat_buf
;
175 if ( stat(completePath
, &stat_buf
) == 0 )
181 // using -root means alway redirect /usr/lib to /rootpath/usr/lib
186 const UniversalMachOLayout
& uni
= UniversalMachOLayout::find(path
, &onlyArchs
);
187 for(std::set
<ArchPair
>::iterator ait
= onlyArchs
.begin(); ait
!= onlyArchs
.end(); ++ait
) {
189 const MachOLayoutAbstraction
* layout
= uni
.getSlice(*ait
);
190 fgPerArchGraph
[*ait
]->addRoot(path
, layout
);
192 catch (const char* msg
) {
194 fprintf(stderr
, "update_dyld_shared_cache: warning for %s can't use root %s: %s\n", fgPerArchGraph
[*ait
]->archName(), path
, msg
);
199 catch (const char* msg
) {
200 fprintf(stderr
, "update_dyld_shared_cache: warning can't use root %s: %s\n", path
, msg
);
206 void ArchGraph::addRoot(const char* path
, const MachOLayoutAbstraction
* layout
)
209 fprintf(stderr
, "update_dyld_shared_cache: adding root: %s\n", path
);
210 DependencyNode
* node
= this->getNode(path
);
212 const MachOLayoutAbstraction
* mainExecutableLayout
= NULL
;
213 if ( layout
->getFileType() == MH_EXECUTE
)
214 mainExecutableLayout
= layout
;
215 node
->loadDependencies(mainExecutableLayout
);
216 node
->markNeededByRoot(node
);
217 if ( layout
->getFileType() == MH_DYLIB
)
218 node
->markNeededByRoot(NULL
);
221 // a virtual path does not have the fgFileSystemRoot prefix
222 ArchGraph::DependencyNode
* ArchGraph::getNodeForVirtualPath(const char* vpath
)
224 if ( fgFileSystemRoot
== NULL
) {
225 return this->getNode(vpath
);
228 char completePath
[strlen(fgFileSystemRoot
)+strlen(vpath
)+2];
229 strcpy(completePath
, fgFileSystemRoot
);
230 strcat(completePath
, vpath
); // assumes vpath starts with '/'
231 if ( fgUsesOverlay
) {
232 // using -overlay means if /overlay/usr/lib exists use it, otherwise use original path
233 struct stat stat_buf
;
234 if ( stat(completePath
, &stat_buf
) == 0 )
235 return this->getNode(completePath
);
237 return this->getNode(vpath
);
240 // using -root means always use /rootpath/usr/lib
241 return this->getNode(completePath
);
246 ArchGraph::DependencyNode
* ArchGraph::getNode(const char* path
)
248 // look up supplied path to see if node already exists
249 PathToNode::iterator pos
= fNodes
.find(path
);
250 if ( pos
!= fNodes
.end() )
254 char realPath
[MAXPATHLEN
];
255 if ( realpath(path
, realPath
) == NULL
)
256 throwf("realpath() failed on %s\n", path
);
258 // look up real path to see if node already exists
259 pos
= fNodes
.find(realPath
);
260 if ( pos
!= fNodes
.end() )
263 // still does not exist, so create a new node
264 const UniversalMachOLayout
& uni
= UniversalMachOLayout::find(realPath
);
265 DependencyNode
* node
= new DependencyNode(this, realPath
, uni
.getSlice(fArchPair
));
266 if ( node
->getLayout() == NULL
) {
267 throwf("%s is missing arch %s", realPath
, archName(fArchPair
));
269 // add realpath to node map
270 fNodes
[node
->getPath()] = node
;
271 // if install name is not real path, add install name to node map
272 if ( (node
->getLayout()->getFileType() == MH_DYLIB
) && (strcmp(realPath
, node
->getLayout()->getID().name
) != 0) ) {
273 //fprintf(stderr, "adding node alias 0x%08X %s for %s\n", fArch, node->getLayout()->getID().name, realPath);
274 fNodes
[node
->getLayout()->getID().name
] = node
;
280 void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction
* mainExecutableLayout
)
282 if ( !fDependenciesLoaded
) {
283 fDependenciesLoaded
= true;
285 const std::vector
<MachOLayoutAbstraction::Library
>& dependsOn
= fLayout
->getLibraries();
286 for(std::vector
<MachOLayoutAbstraction::Library
>::const_iterator it
= dependsOn
.begin(); it
!= dependsOn
.end(); ++it
) {
288 const char* dependentPath
= it
->name
;
289 if ( strncmp(dependentPath
, "@executable_path/", 17) == 0 ) {
290 if ( mainExecutableLayout
== NULL
)
291 throw "@executable_path without main executable";
292 // expand @executable_path path prefix
293 const char* executablePath
= mainExecutableLayout
->getFilePath();
294 char newPath
[strlen(executablePath
) + strlen(dependentPath
)+2];
295 strcpy(newPath
, executablePath
);
296 char* addPoint
= strrchr(newPath
,'/');
297 if ( addPoint
!= NULL
)
298 strcpy(&addPoint
[1], &dependentPath
[17]);
300 strcpy(newPath
, &dependentPath
[17]);
301 dependentPath
= strdup(newPath
);
303 else if ( strncmp(dependentPath
, "@loader_path/", 13) == 0 ) {
304 // expand @loader_path path prefix
305 char newPath
[strlen(fPath
) + strlen(dependentPath
)+2];
306 strcpy(newPath
, fPath
);
307 char* addPoint
= strrchr(newPath
,'/');
308 if ( addPoint
!= NULL
)
309 strcpy(&addPoint
[1], &dependentPath
[13]);
311 strcpy(newPath
, &dependentPath
[13]);
312 dependentPath
= strdup(newPath
);
314 else if ( strncmp(dependentPath
, "@rpath/", 7) == 0 ) {
315 throw "@rpath not supported in dyld shared cache";
317 fDependsOn
.insert(fGraph
->getNodeForVirtualPath(dependentPath
));
319 catch (const char* msg
) {
320 if ( it
->weakImport
&& ! fLayout
->hasSplitSegInfo() ) {
321 // ok to ignore missing weak imported dylibs from things that are
322 // not going to be in the dyld shared cache
325 fprintf(stderr
, "warning, could not bind %s because %s\n", fPath
, msg
);
326 fDependentMissing
= true;
331 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
332 (*it
)->loadDependencies(mainExecutableLayout
);
337 void ArchGraph::DependencyNode::markNeededByRoot(ArchGraph::DependencyNode
* rootNode
)
339 if ( fRootsDependentOnThis
.count(rootNode
) == 0 ) {
340 fRootsDependentOnThis
.insert(rootNode
);
341 for(std::set
<DependencyNode
*>::iterator it
= fDependsOn
.begin(); it
!= fDependsOn
.end(); ++it
) {
342 (*it
)->markNeededByRoot(rootNode
);
348 ArchGraph::DependencyNode::DependencyNode(ArchGraph
* graph
, const char* path
, const MachOLayoutAbstraction
* layout
)
349 : fGraph(graph
), fPath(strdup(path
)), fLayout(layout
), fDependenciesLoaded(false), fDependentMissing(false)
351 //fprintf(stderr, "new DependencyNode(0x%08X, %s)\n", graph->fArch, path);
354 void ArchGraph::findSharedDylibs(ArchPair ap
)
356 const PathToNode
& nodes
= fgPerArchGraph
[ap
]->fNodes
;
357 std::set
<const MachOLayoutAbstraction
*> possibleLibs
;
358 //fprintf(stderr, "shared for arch 0x%08X\n", arch);
359 for(PathToNode::const_iterator it
= nodes
.begin(); it
!= nodes
.end(); ++it
) {
360 DependencyNode
* node
= it
->second
;
361 // <rdar://problem/6127437> put all dylibs in shared cache - not just ones used by more than one app
362 if ( node
->allDependentsFound() /*&& (node->useCount() > 1)*/ ) {
363 const MachOLayoutAbstraction
* layout
= node
->getLayout();
364 if ( layout
->hasSplitSegInfo() && layout
->isRootOwned() && layout
->inSharableLocation() )
365 possibleLibs
.insert(layout
);
366 //fprintf(stderr, "\t%s\n", it->first);
370 // prune so that all shareable libs depend only on other shareable libs
371 std::set
<const MachOLayoutAbstraction
*>& sharedLibs
= fgPerArchGraph
[ap
]->fSharedDylibs
;
372 std::map
<const MachOLayoutAbstraction
*,bool> shareableMap
;
373 for (std::set
<const MachOLayoutAbstraction
*>::iterator lit
= possibleLibs
.begin(); lit
!= possibleLibs
.end(); ++lit
) {
374 if ( canBeShared(*lit
, ap
, possibleLibs
, shareableMap
) )
375 sharedLibs
.insert(*lit
);
379 const char* ArchGraph::archName(ArchPair ap
)
382 case CPU_TYPE_POWERPC
:
386 case CPU_TYPE_X86_64
:
389 switch ( ap
.subtype
) {
390 case CPU_SUBTYPE_ARM_V4T
:
392 case CPU_SUBTYPE_ARM_V6
:
394 case CPU_SUBTYPE_ARM_V5TEJ
:
396 case CPU_SUBTYPE_ARM_XSCALE
:
398 case CPU_SUBTYPE_ARM_V7
:
408 bool ArchGraph::canBeShared(const MachOLayoutAbstraction
* layout
, ArchPair ap
, const std::set
<const MachOLayoutAbstraction
*>& possibleLibs
, std::map
<const MachOLayoutAbstraction
*, bool>& shareableMap
)
410 // check map which is a cache of results
411 std::map
<const MachOLayoutAbstraction
*, bool>::iterator mapPos
= shareableMap
.find(layout
);
412 if ( mapPos
!= shareableMap
.end() ) {
413 return mapPos
->second
;
416 if ( possibleLibs
.count(layout
) == 0 ) {
417 shareableMap
[layout
] = false;
419 if ( ! layout
->hasSplitSegInfo() )
420 asprintf(&msg
, "can't put %s in shared cache because it was not built for 10.5 or later", layout
->getID().name
);
421 else if ( ! layout
->isRootOwned() )
422 asprintf(&msg
, "can't put %s in shared cache because it is not owned by root", layout
->getID().name
);
423 else if ( ! layout
->inSharableLocation() )
424 asprintf(&msg
, "can't put %s in shared cache because it is not in /usr/lib or /System/Library", layout
->getID().name
);
426 asprintf(&msg
, "can't put %s in shared cache", layout
->getID().name
);
427 warnings
.push_back(msg
);
429 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
433 shareableMap
[layout
] = true; // mark this shareable early in case of circular references
434 const PathToNode
& nodes
= fgPerArchGraph
[ap
]->fNodes
;
435 const std::vector
<MachOLayoutAbstraction::Library
>& dependents
= layout
->getLibraries();
436 for (std::vector
<MachOLayoutAbstraction::Library
>::const_iterator dit
= dependents
.begin(); dit
!= dependents
.end(); ++dit
) {
437 PathToNode::const_iterator pos
= nodes
.find(dit
->name
);
438 if ( pos
== nodes
.end() ) {
439 // path from load command does not match any loaded dylibs, maybe there is a temp symlink
440 char realPath
[MAXPATHLEN
];
441 if ( realpath(dit
->name
, realPath
) != NULL
) {
442 if ( nodes
.find(realPath
) != nodes
.end() )
445 shareableMap
[layout
] = false;
447 asprintf(&msg
, "can't put %s in shared cache because it depends on %s which can't be found", layout
->getID().name
, dit
->name
);
448 warnings
.push_back(msg
);
450 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
454 if ( ! canBeShared(pos
->second
->getLayout(), ap
, possibleLibs
, shareableMap
) ) {
455 shareableMap
[layout
] = false;
457 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
);
458 warnings
.push_back(msg
);
460 fprintf(stderr
, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap
), msg
);
469 template <typename A
>
473 SharedCache(ArchGraph
* graph
, const char* rootPath
, bool alphaSort
, bool verify
, bool optimize
, bool overlay
, uint64_t dyldBaseAddress
);
474 bool update(bool usesOverlay
, bool force
, bool optimize
, bool deleteExistingFirst
, int archIndex
,
475 int archCount
, bool keepSignatures
);
476 static const char* cacheFileSuffix(bool optimized
, const char* archName
);
478 uint64_t mappedCacheAddressForAddress(uint64_t addr
);
481 typedef typename
A::P P
;
482 typedef typename
A::P::E E
;
483 typedef typename
A::P::uint_t pint_t
;
485 bool notUpToDate(const char* path
);
486 bool notUpToDate(const void* cache
);
487 uint8_t* optimizeLINKEDIT(bool keepSignatures
);
490 static void getSharedCacheBasAddresses(cpu_type_t arch
, uint64_t* baseReadOnly
, uint64_t* baseWritable
);
491 static cpu_type_t
arch();
492 static const char* archName();
493 static uint64_t sharedRegionReadOnlyStartAddress();
494 static uint64_t sharedRegionWritableStartAddress();
495 static uint64_t sharedRegionReadOnlySize();
496 static uint64_t sharedRegionWritableSize();
497 static uint64_t getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
);
500 void assignNewBaseAddresses();
501 uint64_t cacheFileOffsetForAddress(uint64_t addr
);
504 const MachOLayoutAbstraction
* layout
;
505 dyld_cache_image_info info
;
508 struct ByNameSorter
{
509 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
)
510 { return (strcmp(left
.layout
->getID().name
, right
.layout
->getID().name
) < 0); }
513 struct ByCStringSectionSizeSorter
{
514 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
515 const std::vector
<MachOLayoutAbstraction::Segment
>& segs_l
=
516 left
.layout
->getSegments();
517 const std::vector
<MachOLayoutAbstraction::Segment
>& segs_r
=
518 right
.layout
->getSegments();
519 if (segs_l
.size() == 0 || segs_r
.size() == 0) {
520 // one image has no segments
521 return segs_l
.size() > segs_r
.size();
523 const macho_header
<P
> *mh_l
= (const macho_header
<P
>*)segs_l
[0].mappedAddress();
524 const macho_header
<P
> *mh_r
= (const macho_header
<P
>*)segs_r
[0].mappedAddress();
525 const macho_section
<P
> *cstring_l
= mh_l
->getSection("__TEXT", "__cstring");
526 const macho_section
<P
> *cstring_r
= mh_r
->getSection("__TEXT", "__cstring");
527 if (!cstring_l
|| !cstring_r
) {
528 // one image has no cstrings
529 return cstring_l
&& !cstring_r
;
532 return cstring_l
->size() > cstring_r
->size();
537 Sorter(std::map
<const MachOLayoutAbstraction
*, uint32_t>& map
): fMap(map
) {}
538 bool operator()(const LayoutInfo
& left
, const LayoutInfo
& right
) {
539 return (fMap
[left
.layout
] < fMap
[right
.layout
]);
542 std::map
<const MachOLayoutAbstraction
*, uint32_t>& fMap
;
546 ArchGraph
* fArchGraph
;
548 bool fExistingIsNotUpToDate
;
549 const char* fCacheFilePath
;
550 uint8_t* fExistingCacheForVerification
;
551 std::vector
<LayoutInfo
> fDylibs
;
552 std::vector
<shared_file_mapping_np
> fMappings
;
553 uint32_t fHeaderSize
;
554 uint8_t* fInMemoryCache
;
555 uint64_t fDyldBaseAddress
;
556 uint64_t fLinkEditsTotalUnoptimizedSize
;
557 uint64_t fLinkEditsStartAddress
;
558 MachOLayoutAbstraction::Segment
* fFirstLinkEditSegment
;
559 uint32_t fOffsetOfBindInfoInCombinedLinkedit
;
560 uint32_t fOffsetOfWeakBindInfoInCombinedLinkedit
;
561 uint32_t fOffsetOfLazyBindInfoInCombinedLinkedit
;
562 uint32_t fOffsetOfExportInfoInCombinedLinkedit
;
563 uint32_t fOffsetOfOldSymbolTableInfoInCombinedLinkedit
;
564 uint32_t fLinkEditsTotalOptimizedSize
;
568 // Access a section containing a list of pointers
569 template <typename A
, typename T
>
572 typedef typename
A::P P
;
573 typedef typename
A::P::uint_t pint_t
;
575 SharedCache
<A
>* const fCache
;
576 const macho_section
<P
>* const fSection
;
577 pint_t
* const fBase
;
578 uint64_t const fCount
;
581 PointerSection(SharedCache
<A
>* cache
, const macho_header
<P
>* header
,
582 const char *segname
, const char *sectname
)
584 , fSection(header
->getSection(segname
, sectname
))
585 , fBase(fSection
? (pint_t
*)cache
->mappedCacheAddressForAddress(fSection
->addr()) : 0)
586 , fCount(fSection
? fSection
->size() / sizeof(pint_t
) : 0)
590 uint64_t count() const { return fCount
; }
592 uint64_t getUnmapped(uint64_t index
) const {
593 if (index
>= fCount
) throwf("index out of range");
594 return P::getP(fBase
[index
]);
597 T
get(uint64_t index
) const {
598 return (T
)fCache
->mappedCacheAddressForAddress(getUnmapped(index
));
601 void set(uint64_t index
, uint64_t value
) {
602 if (index
>= fCount
) throwf("index out of range");
603 P::setP(fBase
[index
], value
);
607 // Access a section containing an array of structures
608 template <typename A
, typename T
>
611 typedef typename
A::P P
;
613 SharedCache
<A
>* const fCache
;
614 const macho_section
<P
>* const fSection
;
616 uint64_t const fCount
;
619 ArraySection(SharedCache
<A
>* cache
, const macho_header
<P
>* header
,
620 const char *segname
, const char *sectname
)
622 , fSection(header
->getSection(segname
, sectname
))
623 , fBase(fSection
? (T
*)cache
->mappedCacheAddressForAddress(fSection
->addr()) : 0)
624 , fCount(fSection
? fSection
->size() / sizeof(T
) : 0)
628 uint64_t count() const { return fCount
; }
630 T
& get(uint64_t index
) const {
631 if (index
>= fCount
) throwf("index out of range");
638 #include "ObjCLegacyAbstraction.hpp"
639 #include "ObjCModernAbstraction.hpp"
643 template <> cpu_type_t SharedCache
<ppc
>::arch() { return CPU_TYPE_POWERPC
; }
644 template <> cpu_type_t SharedCache
<x86
>::arch() { return CPU_TYPE_I386
; }
645 template <> cpu_type_t SharedCache
<x86_64
>::arch() { return CPU_TYPE_X86_64
; }
646 template <> cpu_type_t SharedCache
<arm
>::arch() { return CPU_TYPE_ARM
; }
648 template <> uint64_t SharedCache
<ppc
>::sharedRegionReadOnlyStartAddress() { return 0x90000000; }
649 template <> uint64_t SharedCache
<x86
>::sharedRegionReadOnlyStartAddress() { return 0x90000000; }
650 template <> uint64_t SharedCache
<x86_64
>::sharedRegionReadOnlyStartAddress() { return 0x7FFF80000000LL
; }
651 template <> uint64_t SharedCache
<arm
>::sharedRegionReadOnlyStartAddress() { return 0x30000000; }
653 template <> uint64_t SharedCache
<ppc
>::sharedRegionWritableStartAddress() { return 0xA0000000; }
654 template <> uint64_t SharedCache
<x86
>::sharedRegionWritableStartAddress() { return 0xA0000000; }
655 template <> uint64_t SharedCache
<x86_64
>::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL
; }
656 template <> uint64_t SharedCache
<arm
>::sharedRegionWritableStartAddress() { return 0x38000000; }
658 template <> uint64_t SharedCache
<ppc
>::sharedRegionReadOnlySize() { return 0x10000000; }
659 template <> uint64_t SharedCache
<x86
>::sharedRegionReadOnlySize() { return 0x10000000; }
660 template <> uint64_t SharedCache
<x86_64
>::sharedRegionReadOnlySize() { return 0x7FE00000; }
661 template <> uint64_t SharedCache
<arm
>::sharedRegionReadOnlySize() { return 0x08000000; }
663 template <> uint64_t SharedCache
<ppc
>::sharedRegionWritableSize() { return 0x10000000; }
664 template <> uint64_t SharedCache
<x86
>::sharedRegionWritableSize() { return 0x10000000; }
665 template <> uint64_t SharedCache
<x86_64
>::sharedRegionWritableSize() { return 0x20000000; }
666 template <> uint64_t SharedCache
<arm
>::sharedRegionWritableSize() { return 0x08000000; }
669 template <> const char* SharedCache
<ppc
>::archName() { return "ppc"; }
670 template <> const char* SharedCache
<x86
>::archName() { return "i386"; }
671 template <> const char* SharedCache
<x86_64
>::archName() { return "x86_64"; }
672 template <> const char* SharedCache
<arm
>::archName() { return "arm"; }
674 template <> const char* SharedCache
<ppc
>::cacheFileSuffix(bool optimized
, const char*) { return optimized
? "ppc" : "rosetta"; }
675 template <> const char* SharedCache
<x86
>::cacheFileSuffix(bool, const char* archName
) { return archName
; }
676 template <> const char* SharedCache
<x86_64
>::cacheFileSuffix(bool, const char* archName
){ return archName
; }
677 template <> const char* SharedCache
<arm
>::cacheFileSuffix(bool, const char* archName
) { return archName
; }
679 template <typename A
>
680 SharedCache
<A
>::SharedCache(ArchGraph
* graph
, const char* rootPath
, bool alphaSort
, bool verify
, bool optimize
, bool overlay
, uint64_t dyldBaseAddress
)
681 : fArchGraph(graph
), fVerify(verify
), fExistingIsNotUpToDate(true), fCacheFilePath(NULL
),
682 fExistingCacheForVerification(NULL
), fDyldBaseAddress(dyldBaseAddress
)
684 if ( fArchGraph
->getArchPair().arch
!= arch() )
685 throwf("SharedCache object is wrong architecture: 0x%08X vs 0x%08X", fArchGraph
->getArchPair().arch
, arch());
687 // build vector of all shared dylibs
688 std::set
<const MachOLayoutAbstraction
*>& dylibs
= fArchGraph
->getSharedDylibs();
689 for(std::set
<const MachOLayoutAbstraction
*>::iterator it
= dylibs
.begin(); it
!= dylibs
.end(); ++it
) {
690 const MachOLayoutAbstraction
* lib
= *it
;
693 temp
.info
.address
= 0;
694 temp
.info
.modTime
= lib
->getLastModTime();
695 temp
.info
.inode
= lib
->getInode();
696 temp
.info
.pathFileOffset
= lib
->getNameFileOffset();
697 fDylibs
.push_back(temp
);
700 // examine the existing shared cache file
701 char cachePath
[1024];
702 strcpy(cachePath
, rootPath
);
703 strcat(cachePath
, DYLD_SHARED_CACHE_DIR
);
704 strcat(cachePath
, DYLD_SHARED_CACHE_BASE_NAME
);
705 strcat(cachePath
, cacheFileSuffix(optimize
, fArchGraph
->archName()));
706 fCacheFilePath
= strdup(cachePath
);
707 const char* pathToExistingCacheFile
= fCacheFilePath
;
708 char cachePathNonOverlay
[1024];
710 strcpy(cachePathNonOverlay
, DYLD_SHARED_CACHE_DIR
);
711 strcat(cachePathNonOverlay
, DYLD_SHARED_CACHE_BASE_NAME
);
712 strcat(cachePathNonOverlay
, cacheFileSuffix(optimize
, fArchGraph
->archName()));
713 pathToExistingCacheFile
= cachePathNonOverlay
;
715 fExistingIsNotUpToDate
= this->notUpToDate(pathToExistingCacheFile
);
717 // sort shared dylibs
719 // already sorted by notUpToDate()
721 else if ( alphaSort
) {
722 std::sort(fDylibs
.begin(), fDylibs
.end(), ByNameSorter());
725 // random sort for Address Space Randomization
726 std::map
<const MachOLayoutAbstraction
*, uint32_t> map
;
727 for(typename
std::vector
<struct LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
)
728 map
[it
->layout
] = arc4random();
729 std::sort(fDylibs
.begin(), fDylibs
.end(), Sorter(map
));
732 // assign segments in each dylib a new address
733 this->assignNewBaseAddresses();
735 // check that cache we are about to create for verification purposes has same layout as existing cache
737 // if no existing cache, say so
738 if ( fExistingCacheForVerification
== NULL
) {
739 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
740 getpid(), archName());
742 const dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)fExistingCacheForVerification
;
743 const dyldCacheImageInfo
<E
>* cacheEntry
= (dyldCacheImageInfo
<E
>*)(fExistingCacheForVerification
+ header
->imagesOffset());
744 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++cacheEntry
) {
745 if ( cacheEntry
->address() != it
->layout
->getSegments()[0].newAddress() ) {
746 throwf("update_dyld_shared_cache[%u] warning: for arch=%s, could not verify cache because start address of %s is 0x%llX in cache, but should be 0x%llX\n",
747 getpid(), archName(), it
->layout
->getID().name
, cacheEntry
->address(), it
->layout
->getSegments()[0].newAddress());
752 // calculate cache file header size
753 fHeaderSize
= pageAlign(sizeof(dyld_cache_header
)
754 + fMappings
.size()*sizeof(shared_file_mapping_np
)
755 + fDylibs
.size()*sizeof(dyld_cache_image_info
) );
756 //+ fDependencyPool.size()*sizeof(uint16_t));
758 if ( fHeaderSize
> 0x3000 )
759 throwf("header size miscalculation 0x%08X", fHeaderSize
);
763 template <typename A
>
764 uint64_t SharedCache
<A
>::getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
)
766 return proposedNewAddress
;
770 uint64_t SharedCache
<ppc
>::getWritableSegmentNewAddress(uint64_t proposedNewAddress
, uint64_t originalAddress
, uint64_t executableSlide
)
772 // for ppc writable segments can only move in increments of 64K (so only hi16 instruction needs to be modified)
773 return (((executableSlide
& 0x000000000000F000ULL
) - ((proposedNewAddress
- originalAddress
) & 0x000000000000F000ULL
)) & 0x000000000000F000ULL
) + proposedNewAddress
;
777 template <typename A
>
778 void SharedCache
<A
>::assignNewBaseAddresses()
780 // first layout TEXT and DATA for split-seg (or can be split-seg) dylibs
781 uint64_t currentExecuteAddress
= sharedRegionReadOnlyStartAddress() + 0x3000;
782 uint64_t currentWritableAddress
= sharedRegionWritableStartAddress();
783 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
784 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
785 MachOLayoutAbstraction::Segment
* executableSegment
= NULL
;
786 for (int i
=0; i
< segs
.size(); ++i
) {
787 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
789 if ( seg
.writable() ) {
790 if ( seg
.executable() && it
->layout
->hasSplitSegInfo() ) {
791 // skip __IMPORT segments in this pass
795 // for ppc, writable segments have to move in 64K increments
796 if ( it
->layout
->hasSplitSegInfo() ) {
797 if ( executableSegment
== NULL
)
798 throwf("first segment in dylib is not executable for %s", it
->layout
->getID().name
);
799 seg
.setNewAddress(getWritableSegmentNewAddress(currentWritableAddress
, seg
.address(), executableSegment
->newAddress() - executableSegment
->address()));
802 seg
.setNewAddress(currentWritableAddress
);
803 currentWritableAddress
= pageAlign(seg
.newAddress() + seg
.size());
807 if ( seg
.executable() ) {
809 if ( it
->info
.address
== 0 )
810 it
->info
.address
= currentExecuteAddress
;
811 executableSegment
= &seg
;
812 seg
.setNewAddress(currentExecuteAddress
);
813 currentExecuteAddress
+= pageAlign(seg
.size());
816 // skip read-only segments in this pass
822 // append all read-only (but not LINKEDIT) segments at end of all TEXT segments
823 // append all IMPORT segments at end of all DATA segments rounded to next 2MB
824 uint64_t currentReadOnlyAddress
= currentExecuteAddress
;
825 uint64_t startWritableExecutableAddress
= (currentWritableAddress
+ 0x200000 - 1) & (-0x200000);
826 uint64_t currentWritableExecutableAddress
= startWritableExecutableAddress
;
827 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
828 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
829 for(int i
=0; i
< segs
.size(); ++i
) {
830 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
831 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") != 0) ) {
832 // allocate non-executable,read-only segments from end of read only shared region
833 seg
.setNewAddress(currentReadOnlyAddress
);
834 currentReadOnlyAddress
+= pageAlign(seg
.size());
836 else if ( seg
.writable() && seg
.executable() && it
->layout
->hasSplitSegInfo() ) {
837 // allocate IMPORT segments to end of writable shared region
838 seg
.setNewAddress(currentWritableExecutableAddress
);
839 currentWritableExecutableAddress
+= pageAlign(seg
.size());
844 // append all LINKEDIT segments at end of all read-only segments
845 fLinkEditsStartAddress
= currentReadOnlyAddress
;
846 fFirstLinkEditSegment
= NULL
;
847 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
848 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
849 for(int i
=0; i
< segs
.size(); ++i
) {
850 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
851 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
852 if ( fFirstLinkEditSegment
== NULL
)
853 fFirstLinkEditSegment
= &seg
;
854 // allocate non-executable,read-only segments from end of read only shared region
855 seg
.setNewAddress(currentReadOnlyAddress
);
856 currentReadOnlyAddress
+= pageAlign(seg
.size());
860 fLinkEditsTotalUnoptimizedSize
= (currentReadOnlyAddress
- fLinkEditsStartAddress
+ 4095) & (-4096);
863 // populate large mappings
864 uint64_t cacheFileOffset
= 0;
865 if ( currentExecuteAddress
> sharedRegionReadOnlyStartAddress() + 0x3000 ) {
866 shared_file_mapping_np executeMapping
;
867 executeMapping
.sfm_address
= sharedRegionReadOnlyStartAddress();
868 executeMapping
.sfm_size
= currentExecuteAddress
- sharedRegionReadOnlyStartAddress();
869 executeMapping
.sfm_file_offset
= cacheFileOffset
;
870 executeMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
871 executeMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_EXECUTE
;
872 fMappings
.push_back(executeMapping
);
873 cacheFileOffset
+= executeMapping
.sfm_size
;
875 shared_file_mapping_np writableMapping
;
876 writableMapping
.sfm_address
= sharedRegionWritableStartAddress();
877 writableMapping
.sfm_size
= currentWritableAddress
- sharedRegionWritableStartAddress();
878 writableMapping
.sfm_file_offset
= cacheFileOffset
;
879 writableMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
880 writableMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_WRITE
;
881 fMappings
.push_back(writableMapping
);
882 cacheFileOffset
+= writableMapping
.sfm_size
;
884 if ( currentWritableExecutableAddress
> startWritableExecutableAddress
) {
885 shared_file_mapping_np writableExecutableMapping
;
886 writableExecutableMapping
.sfm_address
= startWritableExecutableAddress
;
887 writableExecutableMapping
.sfm_size
= currentWritableExecutableAddress
- startWritableExecutableAddress
;
888 writableExecutableMapping
.sfm_file_offset
= cacheFileOffset
;
889 writableExecutableMapping
.sfm_max_prot
= VM_PROT_READ
| VM_PROT_WRITE
| VM_PROT_EXECUTE
;
890 writableExecutableMapping
.sfm_init_prot
= VM_PROT_READ
| VM_PROT_WRITE
| VM_PROT_EXECUTE
;
891 fMappings
.push_back(writableExecutableMapping
);
892 cacheFileOffset
+= writableExecutableMapping
.sfm_size
;
895 // make read-only (contains LINKEDIT segments) last, so it can be cut back when optimized
896 shared_file_mapping_np readOnlyMapping
;
897 readOnlyMapping
.sfm_address
= currentExecuteAddress
;
898 readOnlyMapping
.sfm_size
= currentReadOnlyAddress
- currentExecuteAddress
;
899 readOnlyMapping
.sfm_file_offset
= cacheFileOffset
;
900 readOnlyMapping
.sfm_max_prot
= VM_PROT_READ
;
901 readOnlyMapping
.sfm_init_prot
= VM_PROT_READ
;
902 fMappings
.push_back(readOnlyMapping
);
903 cacheFileOffset
+= readOnlyMapping
.sfm_size
;
907 shared_file_mapping_np cacheHeaderMapping
;
908 cacheHeaderMapping
.sfm_address
= sharedRegionWritableStartAddress();
909 cacheHeaderMapping
.sfm_size
= 0x3000;
910 cacheHeaderMapping
.sfm_file_offset
= cacheFileOffset
;
911 cacheHeaderMapping
.sfm_max_prot
= VM_PROT_READ
;
912 cacheHeaderMapping
.sfm_init_prot
= VM_PROT_READ
;
913 fMappings
.push_back(cacheHeaderMapping
);
914 cacheFileOffset
+= cacheHeaderMapping
.sfm_size
;
919 template <typename A
>
920 uint64_t SharedCache
<A
>::cacheFileOffsetForAddress(uint64_t addr
)
922 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
923 if ( (it
->sfm_address
<= addr
) && (addr
< it
->sfm_address
+it
->sfm_size
) )
924 return it
->sfm_file_offset
+ addr
- it
->sfm_address
;
926 throwf("address 0x%0llX is not in cache", addr
);
930 template <typename A
>
931 uint64_t SharedCache
<A
>::mappedCacheAddressForAddress(uint64_t addr
)
934 else return (uint64_t)(fInMemoryCache
+ cacheFileOffsetForAddress(addr
));
938 template <typename A
>
939 bool SharedCache
<A
>::notUpToDate(const void* cache
)
941 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)cache
;
942 // not valid if header signature is wrong
943 const char* archPairName
= fArchGraph
->archName();
945 strcpy(temp
, "dyld_v1 ");
946 strcpy(&temp
[15-strlen(archPairName
)], archPairName
);
947 if ( strcmp(header
->magic(), temp
) != 0 ) {
949 fprintf(stderr
, "update_dyld_shared_cache[%u] cannot verify %s because current cache file has invalid header\n", getpid(), archName());
953 fprintf(stderr
, "update_dyld_shared_cache[%u] current cache file has invalid header\n", getpid());
957 // not valid if count of images does not match current images needed
958 if ( header
->imagesCount() != fDylibs
.size() ) {
960 fprintf(stderr
, "update_dyld_shared_cache[%u] cannot verify %s because current cache file contains a different set of dylibs\n", getpid(), archName());
964 fprintf(stderr
, "update_dyld_shared_cache[%u] current cache file is invalid because it contains a different set of dylibs\n", getpid());
968 // verify every dylib in constructed graph is in existing cache with same inode and modTime
969 std::map
<const MachOLayoutAbstraction
*, uint32_t> sortingMap
;
970 const dyldCacheImageInfo
<E
>* imagesStart
= (dyldCacheImageInfo
<E
>*)((uint8_t*)cache
+ header
->imagesOffset());
971 const dyldCacheImageInfo
<E
>* imagesEnd
= &imagesStart
[header
->imagesCount()];
972 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
974 //fprintf(stderr, "inode=0x%llX, mTime=0x%llX, path=%s\n", it->info.inode, it->info.modTime, it->layout->getID().name);
975 for(const dyldCacheImageInfo
<E
>* cacheEntry
= imagesStart
; cacheEntry
< imagesEnd
; ++cacheEntry
) {
977 // in -verify mode, just match by path and warn if file looks different
978 if ( strcmp((char*)cache
+cacheEntry
->pathFileOffset(), it
->layout
->getID().name
) == 0 ) {
980 sortingMap
[it
->layout
] = cacheEntry
-imagesStart
;
981 if ( (cacheEntry
->inode() != it
->info
.inode
) || (cacheEntry
->modTime() != it
->info
.modTime
) ) {
982 fprintf(stderr
, "update_dyld_shared_cache[%u] warning: for arch=%s, %s has changed since cache was built\n",
983 getpid(), archName(), it
->layout
->getID().name
);
989 // in normal update mode, everything has to match for cache to be up-to-date
990 if ( (cacheEntry
->inode() == it
->info
.inode
)
991 && (cacheEntry
->modTime() == it
->info
.modTime
)
992 && (strcmp((char*)cache
+cacheEntry
->pathFileOffset(), it
->layout
->getID().name
) == 0) ) {
1000 throwf("update_dyld_shared_cache[%u] can't verify %s cache because %s is not in existing cache\n", getpid(), archName(), it
->layout
->getID().name
);
1003 fprintf(stderr
, "update_dyld_shared_cache[%u] current %s cache file invalid because %s has changed\n", getpid(), archName(), it
->layout
->getID().name
);
1008 // all dylibs in existing cache file match those determined need to be in shared cache
1010 // sort fDylibs to match existing cache file so we can compare content
1011 std::sort(fDylibs
.begin(), fDylibs
.end(), Sorter(sortingMap
));
1012 //fprintf(stderr, "dylibs sorted like existing cache:\n");
1013 //for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1014 // fprintf(stderr," %s\n", it->layout->getID().name);
1016 // do regenerate a new cache so we can compare content with existing
1020 // existing cache file is up-to-date, don't need to regenerate
1026 template <typename A
>
1027 bool SharedCache
<A
>::notUpToDate(const char* path
)
1029 // mmap existing cache file
1030 int fd
= ::open(path
, O_RDONLY
);
1033 struct stat stat_buf
;
1034 ::fstat(fd
, &stat_buf
);
1035 uint8_t* mappingAddr
= (uint8_t*)mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
1037 if ( mappingAddr
== (uint8_t*)(-1) )
1041 bool result
= this->notUpToDate(mappingAddr
);
1043 // don't unmap yet, leave so it can be verified later
1044 fExistingCacheForVerification
= mappingAddr
;
1048 ::munmap(mappingAddr
, stat_buf
.st_size
);
1049 if ( verbose
&& !result
)
1050 fprintf(stderr
, "update_dyld_shared_cache: %s is up-to-date\n", path
);
1058 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
1065 const char* getBuffer();
1067 uint32_t add(const char* str
);
1068 uint32_t addUnique(const char* str
);
1069 const char* stringAtIndex(uint32_t) const;
1071 typedef __gnu_cxx::hash_map
<const char*, uint32_t, __gnu_cxx::hash
<const char*>, CStringEquals
> StringToOffset
;
1074 uint32_t fBufferAllocated
;
1075 uint32_t fBufferUsed
;
1076 StringToOffset fUniqueStrings
;
1080 StringPool::StringPool()
1081 : fBufferUsed(0), fBufferAllocated(32*1024*1024)
1083 fBuffer
= (char*)malloc(fBufferAllocated
);
1086 uint32_t StringPool::add(const char* str
)
1088 uint32_t len
= strlen(str
);
1089 if ( (fBufferUsed
+ len
+ 1) > fBufferAllocated
) {
1091 throw "string buffer exhausted";
1093 strcpy(&fBuffer
[fBufferUsed
], str
);
1094 uint32_t result
= fBufferUsed
;
1095 fUniqueStrings
[&fBuffer
[fBufferUsed
]] = result
;
1096 fBufferUsed
+= len
+1;
1100 uint32_t StringPool::addUnique(const char* str
)
1102 StringToOffset::iterator pos
= fUniqueStrings
.find(str
);
1103 if ( pos
!= fUniqueStrings
.end() )
1106 //fprintf(stderr, "StringPool::addUnique() new string: %s\n", str);
1107 return this->add(str
);
1111 uint32_t StringPool::size()
1116 const char* StringPool::getBuffer()
1121 const char* StringPool::stringAtIndex(uint32_t index
) const
1123 return &fBuffer
[index
];
1127 template <typename A
>
1128 class LinkEditOptimizer
1131 LinkEditOptimizer(const MachOLayoutAbstraction
&, uint8_t*, StringPool
&);
1132 virtual ~LinkEditOptimizer() {}
1134 void copyBindInfo(uint32_t&);
1135 void copyWeakBindInfo(uint32_t&);
1136 void copyLazyBindInfo(uint32_t&);
1137 void copyExportInfo(uint32_t&);
1138 void copyLocalSymbols(uint32_t symbolTableOffset
, uint32_t&);
1139 void copyExportedSymbols(uint32_t symbolTableOffset
, uint32_t&);
1140 void copyImportedSymbols(uint32_t symbolTableOffset
, uint32_t&);
1141 void copyExternalRelocations(uint32_t& offset
);
1142 void copyIndirectSymbolTable(uint32_t& offset
);
1143 void updateLoadCommands(uint64_t newVMAddress
, uint64_t size
, uint32_t stringPoolOffset
,
1144 uint32_t linkEditsFileOffset
, bool keepSignatures
);
1148 typedef typename
A::P P
;
1149 typedef typename
A::P::E E
;
1150 typedef typename
A::P::uint_t pint_t
;
1154 const macho_header
<P
>* fHeader
;
1155 uint8_t* fNewLinkEditStart
;
1156 uint8_t* fLinkEditBase
;
1157 const MachOLayoutAbstraction
& fLayout
;
1158 macho_dyld_info_command
<P
>* fDyldInfo
;
1159 macho_dysymtab_command
<P
>* fDynamicSymbolTable
;
1160 macho_symtab_command
<P
>* fSymbolTableLoadCommand
;
1161 const macho_nlist
<P
>* fSymbolTable
;
1162 const char* fStrings
;
1163 StringPool
& fNewStringPool
;
1164 std::map
<uint32_t,uint32_t> fOldToNewSymbolIndexes
;
1165 uint32_t fBindInfoOffsetIntoNewLinkEdit
;
1166 uint32_t fBindInfoSizeInNewLinkEdit
;
1167 uint32_t fWeakBindInfoOffsetIntoNewLinkEdit
;
1168 uint32_t fWeakBindInfoSizeInNewLinkEdit
;
1169 uint32_t fLazyBindInfoOffsetIntoNewLinkEdit
;
1170 uint32_t fLazyBindInfoSizeInNewLinkEdit
;
1171 uint32_t fExportInfoOffsetIntoNewLinkEdit
;
1172 uint32_t fExportInfoSizeInNewLinkEdit
;
1173 uint32_t fSymbolTableStartOffsetInNewLinkEdit
;
1174 uint32_t fLocalSymbolsStartIndexInNewLinkEdit
;
1175 uint32_t fLocalSymbolsCountInNewLinkEdit
;
1176 uint32_t fExportedSymbolsStartIndexInNewLinkEdit
;
1177 uint32_t fExportedSymbolsCountInNewLinkEdit
;
1178 uint32_t fImportSymbolsStartIndexInNewLinkEdit
;
1179 uint32_t fImportedSymbolsCountInNewLinkEdit
;
1180 uint32_t fExternalRelocationsOffsetIntoNewLinkEdit
;
1181 uint32_t fIndirectSymbolTableOffsetInfoNewLinkEdit
;
1186 template <typename A
>
1187 LinkEditOptimizer
<A
>::LinkEditOptimizer(const MachOLayoutAbstraction
& layout
, uint8_t* newLinkEdit
, StringPool
& stringPool
)
1188 : fLayout(layout
), fLinkEditBase(NULL
), fNewLinkEditStart(newLinkEdit
), fDyldInfo(NULL
),
1189 fDynamicSymbolTable(NULL
), fSymbolTableLoadCommand(NULL
), fSymbolTable(NULL
), fStrings(NULL
), fNewStringPool(stringPool
),
1190 fBindInfoOffsetIntoNewLinkEdit(0), fBindInfoSizeInNewLinkEdit(0),
1191 fWeakBindInfoOffsetIntoNewLinkEdit(0), fWeakBindInfoSizeInNewLinkEdit(0),
1192 fLazyBindInfoOffsetIntoNewLinkEdit(0), fLazyBindInfoSizeInNewLinkEdit(0),
1193 fExportInfoOffsetIntoNewLinkEdit(0), fExportInfoSizeInNewLinkEdit(0),
1194 fSymbolTableStartOffsetInNewLinkEdit(0),
1195 fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
1196 fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
1197 fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
1198 fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0)
1201 fHeader
= (const macho_header
<P
>*)fLayout
.getSegments()[0].mappedAddress();
1203 const std::vector
<MachOLayoutAbstraction::Segment
>& segments
= fLayout
.getSegments();
1204 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator it
= segments
.begin(); it
!= segments
.end(); ++it
) {
1205 const MachOLayoutAbstraction::Segment
& seg
= *it
;
1206 if ( strcmp(seg
.name(), "__LINKEDIT") == 0 )
1207 fLinkEditBase
= (uint8_t*)seg
.mappedAddress() - seg
.fileOffset();
1209 if ( fLinkEditBase
== NULL
)
1210 throw "no __LINKEDIT segment";
1212 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
1213 const uint32_t cmd_count
= fHeader
->ncmds();
1214 const macho_load_command
<P
>* cmd
= cmds
;
1215 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1216 switch (cmd
->cmd()) {
1219 fSymbolTableLoadCommand
= (macho_symtab_command
<P
>*)cmd
;
1220 fSymbolTable
= (macho_nlist
<P
>*)(&fLinkEditBase
[fSymbolTableLoadCommand
->symoff()]);
1221 fStrings
= (char*)&fLinkEditBase
[fSymbolTableLoadCommand
->stroff()];
1225 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
1228 case LC_DYLD_INFO_ONLY
:
1229 fDyldInfo
= (macho_dyld_info_command
<P
>*)cmd
;
1232 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1234 if ( fSymbolTable
== NULL
)
1235 throw "no LC_SYMTAB";
1236 if ( fDynamicSymbolTable
== NULL
)
1237 throw "no LC_DYSYMTAB";
1242 template <typename A
>
1246 typedef typename
A::P P
;
1247 SymbolSorter(const StringPool
& pool
) : fStringPool(pool
) {}
1248 bool operator()(const macho_nlist
<P
>& left
, const macho_nlist
<P
>& right
) {
1249 return (strcmp(fStringPool
.stringAtIndex(left
.n_strx()) , fStringPool
.stringAtIndex(right
.n_strx())) < 0);
1253 const StringPool
& fStringPool
;
1257 template <typename A
>
1258 void LinkEditOptimizer
<A
>::copyBindInfo(uint32_t& offset
)
1260 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->bind_off() != 0) ) {
1261 fBindInfoOffsetIntoNewLinkEdit
= offset
;
1262 fBindInfoSizeInNewLinkEdit
= fDyldInfo
->bind_size();
1263 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->bind_off()], fDyldInfo
->bind_size());
1264 offset
+= fDyldInfo
->bind_size();
1268 template <typename A
>
1269 void LinkEditOptimizer
<A
>::copyWeakBindInfo(uint32_t& offset
)
1271 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->weak_bind_off() != 0) ) {
1272 fWeakBindInfoOffsetIntoNewLinkEdit
= offset
;
1273 fWeakBindInfoSizeInNewLinkEdit
= fDyldInfo
->weak_bind_size();
1274 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->weak_bind_off()], fDyldInfo
->weak_bind_size());
1275 offset
+= fDyldInfo
->weak_bind_size();
1279 template <typename A
>
1280 void LinkEditOptimizer
<A
>::copyLazyBindInfo(uint32_t& offset
)
1282 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->lazy_bind_off() != 0) ) {
1283 fLazyBindInfoOffsetIntoNewLinkEdit
= offset
;
1284 fLazyBindInfoSizeInNewLinkEdit
= fDyldInfo
->lazy_bind_size();
1285 memcpy(fNewLinkEditStart
+offset
, &fLinkEditBase
[fDyldInfo
->lazy_bind_off()], fDyldInfo
->lazy_bind_size());
1286 offset
+= fDyldInfo
->lazy_bind_size();
1290 template <typename A
>
1291 void LinkEditOptimizer
<A
>::copyExportInfo(uint32_t& offset
)
1293 if ( (fDyldInfo
!= NULL
) && (fDyldInfo
->export_off() != 0) ) {
1294 fExportInfoOffsetIntoNewLinkEdit
= offset
;
1295 fExportInfoSizeInNewLinkEdit
= fDyldInfo
->export_size();
1296 // warning, export_off is only 32-bits so if the trie grows it must be allocated with 32-bits of fLinkeditBase
1297 memcpy(fNewLinkEditStart
+offset
, fLinkEditBase
+(int32_t)fDyldInfo
->export_off(), fDyldInfo
->export_size());
1298 offset
+= fDyldInfo
->export_size();
1304 template <typename A
>
1305 void LinkEditOptimizer
<A
>::copyLocalSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1307 fLocalSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1308 fSymbolTableStartOffsetInNewLinkEdit
= symbolTableOffset
+ symbolIndex
*sizeof(macho_nlist
<P
>);
1309 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1310 const macho_nlist
<P
>* const firstLocal
= &fSymbolTable
[fDynamicSymbolTable
->ilocalsym()];
1311 const macho_nlist
<P
>* const lastLocal
= &fSymbolTable
[fDynamicSymbolTable
->ilocalsym()+fDynamicSymbolTable
->nlocalsym()];
1312 uint32_t oldIndex
= fDynamicSymbolTable
->ilocalsym();
1313 for (const macho_nlist
<P
>* entry
= firstLocal
; entry
< lastLocal
; ++entry
, ++oldIndex
) {
1314 if ( (entry
->n_type() & N_TYPE
) == N_SECT
) {
1315 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1316 *newSymbolEntry
= *entry
;
1317 newSymbolEntry
->set_n_strx(fNewStringPool
.add(&fStrings
[entry
->n_strx()]));
1321 fLocalSymbolsCountInNewLinkEdit
= symbolIndex
- fLocalSymbolsStartIndexInNewLinkEdit
;
1322 //fprintf(stderr, "%u locals starting at %u for %s\n", fLocalSymbolsCountInNewLinkEdit, fLocalSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1326 template <typename A
>
1327 void LinkEditOptimizer
<A
>::copyExportedSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1329 fExportedSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1330 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1331 const macho_nlist
<P
>* const firstExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()];
1332 const macho_nlist
<P
>* const lastExport
= &fSymbolTable
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1333 uint32_t oldIndex
= fDynamicSymbolTable
->iextdefsym();
1334 for (const macho_nlist
<P
>* entry
= firstExport
; entry
< lastExport
; ++entry
, ++oldIndex
) {
1335 if ( ((entry
->n_type() & N_TYPE
) == N_SECT
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0)
1336 && (strncmp(&fStrings
[entry
->n_strx()], "$ld$", 4) != 0) ) {
1337 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1338 *newSymbolEntry
= *entry
;
1339 newSymbolEntry
->set_n_strx(fNewStringPool
.add(&fStrings
[entry
->n_strx()]));
1340 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
-fLocalSymbolsStartIndexInNewLinkEdit
;
1344 fExportedSymbolsCountInNewLinkEdit
= symbolIndex
- fExportedSymbolsStartIndexInNewLinkEdit
;
1345 //fprintf(stderr, "%u exports starting at %u for %s\n", fExportedSymbolsCountInNewLinkEdit, fExportedSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1346 // sort by name, so that dyld does not need a toc
1347 macho_nlist
<P
>* newSymbolsStart
= &newSymbolTableStart
[fExportedSymbolsStartIndexInNewLinkEdit
];
1348 macho_nlist
<P
>* newSymbolsEnd
= &newSymbolTableStart
[fExportedSymbolsStartIndexInNewLinkEdit
+fExportedSymbolsCountInNewLinkEdit
];
1349 std::sort(newSymbolsStart
, newSymbolsEnd
, SymbolSorter
<A
>(fNewStringPool
));
1350 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1351 // fprintf(stderr, "\t%u\t %s\n", (entry-newSymbolsStart)+fExportedSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1355 template <typename A
>
1356 void LinkEditOptimizer
<A
>::copyImportedSymbols(uint32_t symbolTableOffset
, uint32_t& symbolIndex
)
1358 fImportSymbolsStartIndexInNewLinkEdit
= symbolIndex
;
1359 macho_nlist
<P
>* const newSymbolTableStart
= (macho_nlist
<P
>*)(fNewLinkEditStart
+symbolTableOffset
);
1360 const macho_nlist
<P
>* const firstImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()];
1361 const macho_nlist
<P
>* const lastImport
= &fSymbolTable
[fDynamicSymbolTable
->iundefsym()+fDynamicSymbolTable
->nundefsym()];
1362 uint32_t oldIndex
= fDynamicSymbolTable
->iundefsym();
1363 for (const macho_nlist
<P
>* entry
= firstImport
; entry
< lastImport
; ++entry
, ++oldIndex
) {
1364 if ( ((entry
->n_type() & N_TYPE
) == N_UNDF
) && (strncmp(&fStrings
[entry
->n_strx()], ".objc_", 6) != 0) ) {
1365 macho_nlist
<P
>* newSymbolEntry
= &newSymbolTableStart
[symbolIndex
];
1366 *newSymbolEntry
= *entry
;
1367 newSymbolEntry
->set_n_strx(fNewStringPool
.addUnique(&fStrings
[entry
->n_strx()]));
1368 fOldToNewSymbolIndexes
[oldIndex
] = symbolIndex
-fLocalSymbolsStartIndexInNewLinkEdit
;
1372 fImportedSymbolsCountInNewLinkEdit
= symbolIndex
- fImportSymbolsStartIndexInNewLinkEdit
;
1373 //fprintf(stderr, "%u imports starting at %u for %s\n", fImportedSymbolsCountInNewLinkEdit, fImportSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1374 //macho_nlist<P>* newSymbolsStart = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit];
1375 //macho_nlist<P>* newSymbolsEnd = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit];
1376 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1377 // fprintf(stderr, "\t%u\t%s\n", (entry-newSymbolsStart)+fImportSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1381 template <typename A
>
1382 void LinkEditOptimizer
<A
>::copyExternalRelocations(uint32_t& offset
)
1384 fExternalRelocationsOffsetIntoNewLinkEdit
= offset
;
1385 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(&fLinkEditBase
[fDynamicSymbolTable
->extreloff()]);
1386 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
1387 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1388 macho_relocation_info
<P
>* newReloc
= (macho_relocation_info
<P
>*)(&fNewLinkEditStart
[offset
]);
1390 uint32_t newSymbolIndex
= fOldToNewSymbolIndexes
[reloc
->r_symbolnum()];
1391 //fprintf(stderr, "copyExternalRelocations() old=%d, new=%u name=%s in %s\n", reloc->r_symbolnum(), newSymbolIndex,
1392 // &fStrings[fSymbolTable[reloc->r_symbolnum()].n_strx()], fLayout.getFilePath());
1393 newReloc
->set_r_symbolnum(newSymbolIndex
);
1394 offset
+= sizeof(macho_relocation_info
<P
>);
1398 template <typename A
>
1399 void LinkEditOptimizer
<A
>::copyIndirectSymbolTable(uint32_t& offset
)
1401 fIndirectSymbolTableOffsetInfoNewLinkEdit
= offset
;
1402 const uint32_t* const indirectTable
= (uint32_t*)&this->fLinkEditBase
[fDynamicSymbolTable
->indirectsymoff()];
1403 uint32_t* newIndirectTable
= (uint32_t*)&fNewLinkEditStart
[offset
];
1404 for (int i
=0; i
< fDynamicSymbolTable
->nindirectsyms(); ++i
) {
1405 uint32_t oldSymbolIndex
= E::get32(indirectTable
[i
]);
1406 uint32_t newSymbolIndex
= oldSymbolIndex
;
1407 if ( (oldSymbolIndex
!= INDIRECT_SYMBOL_ABS
) && (oldSymbolIndex
!= INDIRECT_SYMBOL_LOCAL
) ) {
1408 newSymbolIndex
= fOldToNewSymbolIndexes
[oldSymbolIndex
];
1409 //fprintf(stderr, "copyIndirectSymbolTable() old=%d, new=%u name=%s in %s\n", oldSymbolIndex, newSymbolIndex,
1410 // &fStrings[fSymbolTable[oldSymbolIndex].n_strx()], fLayout.getFilePath());
1412 E::set32(newIndirectTable
[i
], newSymbolIndex
);
1414 offset
+= (fDynamicSymbolTable
->nindirectsyms() * 4);
1417 template <typename A
>
1418 void LinkEditOptimizer
<A
>::updateLoadCommands(uint64_t newVMAddress
, uint64_t size
, uint32_t stringPoolOffset
,
1419 uint32_t linkEditsFileOffset
, bool keepSignatures
)
1421 // set LINKEDIT segment commmand to new merged LINKEDIT
1422 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
1423 const uint32_t cmd_count
= fHeader
->ncmds();
1424 const macho_load_command
<P
>* cmd
= cmds
;
1425 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1426 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
1427 macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
1428 if ( strcmp(seg
->segname(), "__LINKEDIT") == 0 ) {
1429 seg
->set_vmaddr(newVMAddress
);
1430 seg
->set_vmsize(size
);
1431 seg
->set_filesize(size
);
1432 seg
->set_fileoff(linkEditsFileOffset
);
1435 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
1438 // update dyld_info with new offsets
1439 if ( fDyldInfo
!= NULL
) {
1440 fDyldInfo
->set_rebase_off(0);
1441 fDyldInfo
->set_rebase_size(0);
1442 fDyldInfo
->set_bind_off(linkEditsFileOffset
+fBindInfoOffsetIntoNewLinkEdit
);
1443 fDyldInfo
->set_bind_size(fBindInfoSizeInNewLinkEdit
);
1444 fDyldInfo
->set_weak_bind_off(linkEditsFileOffset
+fWeakBindInfoOffsetIntoNewLinkEdit
);
1445 fDyldInfo
->set_weak_bind_size(fWeakBindInfoSizeInNewLinkEdit
);
1446 fDyldInfo
->set_lazy_bind_off(linkEditsFileOffset
+fLazyBindInfoOffsetIntoNewLinkEdit
);
1447 fDyldInfo
->set_lazy_bind_size(fLazyBindInfoSizeInNewLinkEdit
);
1448 fDyldInfo
->set_export_off(linkEditsFileOffset
+fExportInfoOffsetIntoNewLinkEdit
);
1449 fDyldInfo
->set_export_size(fExportInfoSizeInNewLinkEdit
);
1451 // fprintf(stderr, "dylib %s\n", fLayout.getFilePath());
1452 // fprintf(stderr, " bind_off=0x%08X\n", fDyldInfo->bind_off());
1453 // fprintf(stderr, " export_off=0x%08X\n", fDyldInfo->export_off());
1454 // fprintf(stderr, " export_size=%d\n", fDyldInfo->export_size());
1458 // update symbol table and dynamic symbol table with new offsets
1459 fSymbolTableLoadCommand
->set_symoff(linkEditsFileOffset
+fSymbolTableStartOffsetInNewLinkEdit
);
1460 fSymbolTableLoadCommand
->set_nsyms(fLocalSymbolsCountInNewLinkEdit
+fExportedSymbolsCountInNewLinkEdit
+fImportedSymbolsCountInNewLinkEdit
);
1461 fSymbolTableLoadCommand
->set_stroff(linkEditsFileOffset
+stringPoolOffset
);
1462 fSymbolTableLoadCommand
->set_strsize(fNewStringPool
.size());
1463 fDynamicSymbolTable
->set_ilocalsym(0);
1464 fDynamicSymbolTable
->set_nlocalsym(fLocalSymbolsCountInNewLinkEdit
);
1465 fDynamicSymbolTable
->set_iextdefsym(fExportedSymbolsStartIndexInNewLinkEdit
-fLocalSymbolsStartIndexInNewLinkEdit
);
1466 fDynamicSymbolTable
->set_nextdefsym(fExportedSymbolsCountInNewLinkEdit
);
1467 fDynamicSymbolTable
->set_iundefsym(fImportSymbolsStartIndexInNewLinkEdit
-fLocalSymbolsStartIndexInNewLinkEdit
);
1468 fDynamicSymbolTable
->set_nundefsym(fImportedSymbolsCountInNewLinkEdit
);
1469 fDynamicSymbolTable
->set_tocoff(0);
1470 fDynamicSymbolTable
->set_ntoc(0);
1471 fDynamicSymbolTable
->set_modtaboff(0);
1472 fDynamicSymbolTable
->set_nmodtab(0);
1473 fDynamicSymbolTable
->set_indirectsymoff(linkEditsFileOffset
+fIndirectSymbolTableOffsetInfoNewLinkEdit
);
1474 fDynamicSymbolTable
->set_extreloff(linkEditsFileOffset
+fExternalRelocationsOffsetIntoNewLinkEdit
);
1475 fDynamicSymbolTable
->set_locreloff(0);
1476 fDynamicSymbolTable
->set_nlocrel(0);
1478 // now remove load commands no longer needed
1479 const macho_load_command
<P
>* srcCmd
= cmds
;
1480 macho_load_command
<P
>* dstCmd
= (macho_load_command
<P
>*)cmds
;
1481 int32_t newCount
= 0;
1482 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1483 uint32_t cmdSize
= srcCmd
->cmdsize();
1484 switch ( srcCmd
->cmd() ) {
1485 case LC_SEGMENT_SPLIT_INFO
:
1488 case LC_CODE_SIGNATURE
:
1489 if ( !keepSignatures
)
1491 // otherwise fall into copy case
1493 memmove(dstCmd
, srcCmd
, cmdSize
);
1494 dstCmd
= (macho_load_command
<P
>*)(((uint8_t*)dstCmd
)+cmdSize
);
1498 srcCmd
= (const macho_load_command
<P
>*)(((uint8_t*)srcCmd
)+cmdSize
);
1500 // zero out stuff removed
1501 bzero(dstCmd
, (uint8_t*)srcCmd
- (uint8_t*)dstCmd
);
1503 // update mach_header
1504 macho_header
<P
>* writableHeader
= (macho_header
<P
>*)fHeader
;
1505 writableHeader
->set_ncmds(newCount
);
1506 writableHeader
->set_sizeofcmds((uint8_t*)dstCmd
- ((uint8_t*)fHeader
+ sizeof(macho_header
<P
>)));
1508 // this invalidates some ivars
1509 fDynamicSymbolTable
= NULL
;
1510 fSymbolTableLoadCommand
= NULL
;
1512 fSymbolTable
= NULL
;
1518 template <typename A
>
1519 uint8_t* SharedCache
<A
>::optimizeLINKEDIT(bool keepSignatures
)
1521 // allocate space for optimized LINKEDIT area
1522 uint8_t* newLinkEdit
= new uint8_t[fLinkEditsTotalUnoptimizedSize
];
1523 bzero(newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
1525 // make a string pool
1526 StringPool stringPool
;
1528 // create optimizer object for each LINKEDIT segment
1529 std::vector
<LinkEditOptimizer
<A
>*> optimizers
;
1530 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1531 optimizers
.push_back(new LinkEditOptimizer
<A
>(*it
->layout
, newLinkEdit
, stringPool
));
1534 // rebase info is not copied because images in shared cache are never rebased
1536 // copy weak bind info
1537 uint32_t offset
= 0;
1538 fOffsetOfWeakBindInfoInCombinedLinkedit
= offset
;
1539 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1540 (*it
)->copyWeakBindInfo(offset
);
1544 fOffsetOfExportInfoInCombinedLinkedit
= offset
;
1545 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1546 (*it
)->copyExportInfo(offset
);
1550 fOffsetOfBindInfoInCombinedLinkedit
= offset
;
1551 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1552 (*it
)->copyBindInfo(offset
);
1555 // copy lazy bind info
1556 fOffsetOfLazyBindInfoInCombinedLinkedit
= offset
;
1557 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1558 (*it
)->copyLazyBindInfo(offset
);
1561 // copy symbol table entries
1562 fOffsetOfOldSymbolTableInfoInCombinedLinkedit
= offset
;
1563 uint32_t symbolTableOffset
= offset
;
1564 uint32_t symbolTableIndex
= 0;
1565 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1566 (*it
)->copyLocalSymbols(symbolTableOffset
, symbolTableIndex
);
1567 (*it
)->copyExportedSymbols(symbolTableOffset
, symbolTableIndex
);
1568 (*it
)->copyImportedSymbols(symbolTableOffset
, symbolTableIndex
);
1571 // copy external relocations, 8-byte aligned after end of symbol table
1572 uint32_t externalRelocsOffset
= symbolTableOffset
+ (symbolTableIndex
* sizeof(macho_nlist
<typename
A::P
>) + 7) & (-8);
1573 //uint32_t externalRelocsStartOffset = externalRelocsOffset;
1574 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1575 (*it
)->copyExternalRelocations(externalRelocsOffset
);
1578 // copy indirect symbol tables
1579 uint32_t indirectSymbolTableOffset
= externalRelocsOffset
;
1580 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1581 (*it
)->copyIndirectSymbolTable(indirectSymbolTableOffset
);
1585 uint32_t stringPoolOffset
= indirectSymbolTableOffset
;
1586 memcpy(&newLinkEdit
[stringPoolOffset
], stringPool
.getBuffer(), stringPool
.size());
1589 fLinkEditsTotalOptimizedSize
= (stringPoolOffset
+ stringPool
.size() + 4095) & (-4096);
1591 // choose new linkedit file offset
1592 uint32_t linkEditsFileOffset
= fLinkEditsStartAddress
- sharedRegionReadOnlyStartAddress();
1594 // update load commands so that all dylibs shared different areas of the same LINKEDIT segment
1595 for(typename
std::vector
<LinkEditOptimizer
<A
>*>::iterator it
= optimizers
.begin(); it
!= optimizers
.end(); ++it
) {
1596 (*it
)->updateLoadCommands(fLinkEditsStartAddress
, fLinkEditsTotalUnoptimizedSize
, stringPoolOffset
, linkEditsFileOffset
, keepSignatures
);
1599 //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, fLinkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, fLinkEditsTotalOptimizedSize);
1600 //printf(stderr, "mega link edit mapped starting at: %p\n", fFirstLinkEditSegment->mappedAddress());
1602 // overwrite mapped LINKEDIT area with new optimized LINKEDIT segment
1603 memcpy(fFirstLinkEditSegment
->mappedAddress(), newLinkEdit
, fLinkEditsTotalUnoptimizedSize
);
1605 // update all LINKEDIT Segment objects to point to same merged LINKEDIT area
1606 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1607 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1608 for(int i
=0; i
< segs
.size(); ++i
) {
1609 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1610 if ( !seg
.writable() && !seg
.executable() && (strcmp(seg
.name(), "__LINKEDIT") == 0) ) {
1611 seg
.setNewAddress(fLinkEditsStartAddress
);
1612 seg
.setMappedAddress(fFirstLinkEditSegment
->mappedAddress());
1613 seg
.setSize(fLinkEditsTotalOptimizedSize
);
1614 seg
.setFileSize(fLinkEditsTotalOptimizedSize
);
1615 seg
.setFileOffset(linkEditsFileOffset
);
1620 // return new end of cache
1621 return (uint8_t*)fFirstLinkEditSegment
->mappedAddress() + fLinkEditsTotalOptimizedSize
;
1626 template <typename A
>
1627 class ObjCSelectorUniquer
1630 objc_selopt::string_map fSelectorStrings
;
1631 SharedCache
<A
> *fCache
;
1636 ObjCSelectorUniquer(SharedCache
<A
> *newCache
)
1637 : fSelectorStrings()
1642 typename
A::P::uint_t
visit(typename
A::P::uint_t oldValue
)
1645 const char *s
= (const char *)
1646 fCache
->mappedCacheAddressForAddress(oldValue
);
1647 objc_selopt::string_map::iterator element
=
1648 fSelectorStrings
.insert(objc_selopt::string_map::value_type(s
, oldValue
)).first
;
1649 return (typename
A::P::uint_t
)element
->second
;
1652 objc_selopt::string_map
& strings() {
1653 return fSelectorStrings
;
1656 size_t count() const { return fCount
; }
1660 void SharedCache
<arm
>::optimizeObjC()
1662 // objc optimizations on arm not yet supported
1665 template <typename A
>
1666 void SharedCache
<A
>::optimizeObjC()
1669 fprintf(stderr
, "update_dyld_shared_cache: for %s, uniquing objc selectors\n", archName());
1672 // Find libobjc's __TEXT,__objc_selopt section
1673 const macho_section
<P
> *seloptSection
= NULL
;
1674 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1675 if (0 == strstr(it
->layout
->getFilePath(), "libobjc")) continue;
1676 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
1677 if ((seloptSection
= mh
->getSection("__TEXT", "__objc_selopt"))) break;
1680 if (!seloptSection
) {
1681 warn(archName(), "couldn't find libobjc's unique selector section (selectors not optimized)");
1685 objc_selopt::objc_selopt_t
*seloptData
= (objc_selopt::objc_selopt_t
*)
1686 mappedCacheAddressForAddress(seloptSection
->addr());
1687 if (seloptSection
->size() < sizeof(seloptData
->version
)) {
1688 warn(archName(), "libobjc's unique selector section is too small (selectors not optimized)");
1692 if (E::get32(seloptData
->version
) != objc_selopt::VERSION
) {
1693 warn(archName(), "libobjc's unique selector section version is unrecognized (selectors not optimized)");
1698 // Update selector references and build selector list
1699 ObjCSelectorUniquer
<A
> uniq(this);
1701 // Heuristic: choose selectors from libraries with more cstring data first.
1702 // This tries to localize selector cstring memory.
1703 std::vector
<LayoutInfo
> sortedDylibs
= fDylibs
;
1704 std::sort(sortedDylibs
.begin(), sortedDylibs
.end(), ByCStringSectionSizeSorter());
1706 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= sortedDylibs
.begin(); it
!= sortedDylibs
.end(); ++it
) {
1707 const macho_header
<P
> *mh
= (const macho_header
<P
>*)(*it
->layout
).getSegments()[0].mappedAddress();
1708 LegacySelectorUpdater
<A
, ObjCSelectorUniquer
<A
> >::update(this, mh
, uniq
);
1709 SelectorUpdater
<A
, ObjCSelectorUniquer
<A
> >::update(this, mh
, uniq
);
1713 fprintf(stderr
, "update_dyld_shared_cache: for %s, found %zu unique objc selectors\n", archName(), uniq
.strings().size());
1716 // Write selector hash table to libobjc's __TEXT,__objc_selopt section
1719 objc_selopt::write_selopt(seloptData
, seloptSection
->addr(),
1720 seloptSection
->size(), uniq
.strings(),
1721 E::little_endian
, &bytesUsed
);
1723 warn(archName(), err
);
1728 fprintf(stderr
, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
1729 "(%d%%) used in libobjc unique selector section\n",
1730 archName(), bytesUsed
, seloptSection
->size(),
1731 (int)(bytesUsed
/ (double)seloptSection
->size() * 100));
1732 fprintf(stderr
, "update_dyld_shared_cache: for %s, "
1733 "updated %zu selector references\n",
1734 archName(), uniq
.count());
1741 static const char* sCleanupFile
= NULL
;
1742 static void cleanup(int sig
)
1744 ::signal(sig
, SIG_DFL
);
1745 if ( sCleanupFile
!= NULL
)
1746 ::unlink(sCleanupFile
);
1748 // fprintf(stderr, "update_dyld_shared_cache: deleting temp file in response to a signal\n");
1749 if ( sig
== SIGINT
)
1754 template <typename A
>
1755 bool SharedCache
<A
>::update(bool usesOverlay
, bool force
, bool optimize
, bool deleteExistingFirst
, int archIndex
,
1756 int archCount
, bool keepSignatures
)
1758 bool didUpdate
= false;
1760 // already up to date?
1761 if ( force
|| fExistingIsNotUpToDate
) {
1763 fprintf(stderr
, "update_dyld_shared_cache: regenerating %s\n", fCacheFilePath
);
1764 if ( fDylibs
.size() == 0 ) {
1765 fprintf(stderr
, "update_dyld_shared_cache: warning, empty cache not generated for arch %s\n", archName());
1768 // delete existing cache while building the new one
1769 // this is a flag to dyld to stop pinging update_dyld_shared_cache
1770 if ( deleteExistingFirst
)
1771 ::unlink(fCacheFilePath
);
1772 uint8_t* inMemoryCache
= NULL
;
1773 uint32_t allocatedCacheSize
= 0;
1774 char tempCachePath
[strlen(fCacheFilePath
)+16];
1775 sprintf(tempCachePath
, "%s.tmp%u", fCacheFilePath
, getpid());
1777 // allocate a memory block to hold cache
1778 uint32_t cacheFileSize
= 0;
1779 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1780 uint32_t end
= it
->sfm_file_offset
+ it
->sfm_size
;
1781 if ( end
> cacheFileSize
)
1782 cacheFileSize
= end
;
1784 if ( vm_allocate(mach_task_self(), (vm_address_t
*)(&inMemoryCache
), cacheFileSize
, VM_FLAGS_ANYWHERE
) != KERN_SUCCESS
)
1785 throwf("can't vm_allocate cache of size %u", cacheFileSize
);
1786 allocatedCacheSize
= cacheFileSize
;
1787 fInMemoryCache
= inMemoryCache
;
1790 dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)inMemoryCache
;
1791 const char* archPairName
= fArchGraph
->archName();
1793 strcpy(temp
, "dyld_v1 ");
1794 strcpy(&temp
[15-strlen(archPairName
)], archPairName
);
1795 header
->set_magic(temp
);
1796 //header->set_architecture(arch());
1797 header
->set_mappingOffset(sizeof(dyldCacheHeader
<E
>));
1798 header
->set_mappingCount(fMappings
.size());
1799 header
->set_imagesOffset(header
->mappingOffset() + fMappings
.size()*sizeof(dyldCacheFileMapping
<E
>));
1800 header
->set_imagesCount(fDylibs
.size());
1801 header
->set_dyldBaseAddress(fDyldBaseAddress
);
1802 //header->set_dependenciesOffset(sizeof(dyldCacheHeader<E>) + fMappings.size()*sizeof(dyldCacheFileMapping<E>) + fDylibs.size()*sizeof(dyldCacheImageInfo<E>));
1803 //header->set_dependenciesCount(fDependencyPool.size());
1806 dyldCacheFileMapping
<E
>* mapping
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
1807 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
1809 fprintf(stderr
, "update_dyld_shared_cache: cache mappings: address=0x%0llX, size=0x%0llX, fileOffset=0x%0llX, prot=0x%X\n",
1810 it
->sfm_address
, it
->sfm_size
, it
->sfm_file_offset
, it
->sfm_init_prot
);
1811 mapping
->set_address(it
->sfm_address
);
1812 mapping
->set_size(it
->sfm_size
);
1813 mapping
->set_file_offset(it
->sfm_file_offset
);
1814 mapping
->set_max_prot(it
->sfm_max_prot
);
1815 mapping
->set_init_prot(it
->sfm_init_prot
);
1819 // fill in image table
1820 dyldCacheImageInfo
<E
>* image
= (dyldCacheImageInfo
<E
>*)mapping
;
1821 for(typename
std::vector
<LayoutInfo
>::iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1822 image
->set_address(it
->info
.address
);
1823 image
->set_modTime(it
->info
.modTime
);
1824 image
->set_inode(it
->info
.inode
);
1825 image
->set_pathFileOffset(cacheFileOffsetForAddress(it
->info
.address
+it
->info
.pathFileOffset
));
1826 //image->set_dependenciesStartOffset(it->info.dependenciesStartOffset);
1830 // copy each segment to cache buffer
1831 const int dylibCount
= fDylibs
.size();
1833 int progressIndex
= 0;
1834 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++dylibIndex
) {
1835 const char* path
= it
->layout
->getFilePath();
1836 int src
= ::open(path
, O_RDONLY
, 0);
1838 throwf("can't open file %s, errnor=%d", it
->layout
->getID().name
, errno
);
1839 // mark source as "don't cache"
1840 (void)fcntl(src
, F_NOCACHE
, 1);
1841 // verify file has not changed since dependency analysis
1842 struct stat stat_buf
;
1843 if ( fstat(src
, &stat_buf
) == -1)
1844 throwf("can't stat open file %s, errno=%d", path
, errno
);
1845 if ( (it
->layout
->getInode() != stat_buf
.st_ino
) || (it
->layout
->getLastModTime() != stat_buf
.st_mtime
) )
1846 throwf("file modified during cache creation: %s", path
);
1849 fprintf(stderr
, "update_dyld_shared_cache: copying %s to cache\n", it
->layout
->getID().name
);
1851 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
1852 for (int i
=0; i
< segs
.size(); ++i
) {
1853 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1855 fprintf(stderr
, "\t\tsegment %s, size=0x%0llX, cache address=0x%0llX\n", seg
.name(), seg
.fileSize(), seg
.newAddress());
1856 if ( seg
.size() > 0 ) {
1857 const uint64_t segmentSrcStartOffset
= it
->layout
->getOffsetInUniversalFile()+seg
.fileOffset();
1858 const uint64_t segmentSize
= seg
.fileSize();
1859 const uint64_t segmentDstStartOffset
= cacheFileOffsetForAddress(seg
.newAddress());
1860 ssize_t readResult
= ::pread(src
, &inMemoryCache
[segmentDstStartOffset
], segmentSize
, segmentSrcStartOffset
);
1861 if ( readResult
!= segmentSize
) {
1862 if ( readResult
== -1 )
1863 throwf("read failure copying dylib errno=%d for %s", errno
, it
->layout
->getID().name
);
1865 throwf("read failure copying dylib. Read of %lld bytes at file offset %lld returned %ld for %s",
1866 segmentSize
, segmentSrcStartOffset
, readResult
, it
->layout
->getID().name
);
1871 catch (const char* msg
) {
1872 throwf("%s while copying %s to shared cache", msg
, it
->layout
->getID().name
);
1876 // assuming read takes 40% of time
1877 int nextProgressIndex
= archIndex
*100+(40*dylibIndex
)/dylibCount
;
1878 if ( nextProgressIndex
!= progressIndex
)
1879 fprintf(stdout
, "%3u/%u\n", nextProgressIndex
, archCount
*100);
1880 progressIndex
= nextProgressIndex
;
1884 // set mapped address for each segment
1885 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1886 std::vector
<MachOLayoutAbstraction::Segment
>& segs
= ((MachOLayoutAbstraction
*)(it
->layout
))->getSegments();
1887 for (int i
=0; i
< segs
.size(); ++i
) {
1888 MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
1889 if ( seg
.size() > 0 )
1890 seg
.setMappedAddress(inMemoryCache
+ cacheFileOffsetForAddress(seg
.newAddress()));
1891 //fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
1895 // rebase each dylib in shared cache
1896 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1898 Rebaser
<A
> r(*it
->layout
);
1901 // fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
1903 catch (const char* msg
) {
1904 throwf("%s in %s", msg
, it
->layout
->getID().name
);
1908 // merge/optimize all LINKEDIT segments
1910 //fprintf(stderr, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize/(1024*1024));
1911 cacheFileSize
= (this->optimizeLINKEDIT(keepSignatures
) - inMemoryCache
);
1912 //fprintf(stderr, "update_dyld_shared_cache: optimized cache file size %uMB\n", cacheFileSize/(1024*1024));
1913 // update header to reduce mapping size
1914 dyldCacheHeader
<E
>* cacheHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
1915 dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[sizeof(dyldCacheHeader
<E
>)];
1916 dyldCacheFileMapping
<E
>* lastMapping
= &mappings
[cacheHeader
->mappingCount()-1];
1917 lastMapping
->set_size(cacheFileSize
-lastMapping
->file_offset());
1918 // update fMappings so .map file will print correctly
1919 fMappings
.back().sfm_size
= cacheFileSize
-fMappings
.back().sfm_file_offset
;
1923 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs
.size());
1924 // instantiate a Binder for each image and add to map
1925 typename Binder
<A
>::Map map
;
1926 std::vector
<Binder
<A
>*> binders
;
1927 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
1928 //fprintf(stderr, "binding %s\n", it->layout->getID().name);
1929 Binder
<A
>* binder
= new Binder
<A
>(*it
->layout
, fDyldBaseAddress
);
1930 binders
.push_back(binder
);
1931 // only add dylibs to map
1932 if ( it
->layout
->getID().name
!= NULL
)
1933 map
[it
->layout
->getID().name
] = binder
;
1936 // tell each Binder about the others
1937 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
1938 (*it
)->setDependentBinders(map
);
1941 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
1943 fprintf(stderr
, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it
)->getDylibID());
1947 catch (const char* msg
) {
1948 throwf("%s in %s", msg
, (*it
)->getDylibID());
1952 for(typename
std::vector
<Binder
<A
>*>::iterator it
= binders
.begin(); it
!= binders
.end(); ++it
) {
1956 // unique objc selectors and update other objc metadata
1961 // assuming objc optimizations takes 15% of time
1962 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*55, archCount
*100);
1966 // new cache is built, compare header entries
1967 const dyldCacheHeader
<E
>* newHeader
= (dyldCacheHeader
<E
>*)inMemoryCache
;
1968 const dyldCacheHeader
<E
>* oldHeader
= (dyldCacheHeader
<E
>*)fExistingCacheForVerification
;
1969 if ( newHeader
->mappingCount() != oldHeader
->mappingCount() ) {
1970 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because caches have a different number of mappings\n",
1971 getpid(), archName());
1973 const dyldCacheFileMapping
<E
>* newMappings
= (dyldCacheFileMapping
<E
>*)&inMemoryCache
[newHeader
->mappingOffset()];
1974 const dyldCacheFileMapping
<E
>* oldMappings
= (dyldCacheFileMapping
<E
>*)&fExistingCacheForVerification
[oldHeader
->mappingOffset()];
1975 for (int i
=0; i
< newHeader
->mappingCount(); ++i
) {
1976 if ( newMappings
[i
].address() != oldMappings
[i
].address() ) {
1977 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because mapping %d starts at a different address 0x%0llX vs 0x%0llX\n",
1978 getpid(), archName(), i
, newMappings
[i
].address(), oldMappings
[i
].address() );
1980 if ( newMappings
[i
].size() != oldMappings
[i
].size() ) {
1981 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because mapping %d has a different size\n",
1982 getpid(), archName(), i
);
1986 //fprintf(stderr, "%s existing cache = %p\n", archName(), fExistingCacheForVerification);
1987 //fprintf(stderr, "%s new cache = %p\n", archName(), inMemoryCache);
1988 // compare content to existing cache page by page
1989 for (int offset
=0; offset
< cacheFileSize
; offset
+= 4096) {
1990 if ( memcmp(&inMemoryCache
[offset
], &fExistingCacheForVerification
[offset
], 4096) != 0 ) {
1991 fprintf(stderr
, "verifier found differences on page offset 0x%08X for %s:\n", offset
, archName());
1992 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
, ++dylibIndex
) {
1993 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
1994 for(std::vector
<MachOLayoutAbstraction::Segment
>::const_iterator sit
= segs
.begin(); sit
!= segs
.end(); ++sit
) {
1995 const MachOLayoutAbstraction::Segment
& seg
= *sit
;
1996 if ( (seg
.mappedAddress() <= &inMemoryCache
[offset
]) && (&inMemoryCache
[offset
] < ((uint8_t*)seg
.mappedAddress() + seg
.fileSize())) ) {
1997 // all LINKEDITs point to the same region, so just print one
1998 if ( strcmp(seg
.name(), "__LINKEDIT") == 0 )
1999 fprintf(stderr
, " in merged LINKEDIT segment\n");
2001 fprintf(stderr
, " in segment %s of dylib %s\n", seg
.name(), it
->layout
->getID().name
);
2006 for (int po
=0; po
< 4096; po
+= 16) {
2007 if ( memcmp(&inMemoryCache
[offset
+po
], &fExistingCacheForVerification
[offset
+po
], 16) != 0 ) {
2008 fprintf(stderr
, " existing: 0x%08X: ", offset
+po
);
2009 for ( int j
=0; j
< 16; ++j
)
2010 fprintf(stderr
, " 0x%02X", fExistingCacheForVerification
[offset
+po
+j
]);
2011 fprintf(stderr
, "\n");
2012 fprintf(stderr
, " should be: 0x%08X: ", offset
+po
);
2013 for ( int j
=0; j
< 16; ++j
)
2014 fprintf(stderr
, " 0x%02X", inMemoryCache
[offset
+po
+j
]);
2015 fprintf(stderr
, "\n");
2022 // install signal handlers to delete temp file if program is killed
2023 sCleanupFile
= tempCachePath
;
2024 ::signal(SIGINT
, cleanup
);
2025 ::signal(SIGBUS
, cleanup
);
2026 ::signal(SIGSEGV
, cleanup
);
2028 // create var/db/dyld dirs if needed
2029 char dyldDirs
[1024];
2030 strcpy(dyldDirs
, fCacheFilePath
);
2031 char* lastSlash
= strrchr(dyldDirs
, '/');
2032 if ( lastSlash
!= NULL
)
2033 lastSlash
[1] = '\0';
2034 struct stat stat_buf
;
2035 if ( stat(dyldDirs
, &stat_buf
) != 0 ) {
2036 const char* afterSlash
= &dyldDirs
[1];
2038 while ( (slash
= strchr(afterSlash
, '/')) != NULL
) {
2040 ::mkdir(dyldDirs
, S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
);
2042 afterSlash
= slash
+1;
2046 // create temp file for cache
2047 int fd
= ::open(tempCachePath
, O_CREAT
| O_RDWR
| O_TRUNC
, 0644);
2049 throwf("can't create temp file %s, errnor=%d", tempCachePath
, errno
);
2051 // try to allocate whole cache file contiguously
2052 fstore_t fcntlSpec
= { F_ALLOCATECONTIG
|F_ALLOCATEALL
, F_PEOFPOSMODE
, 0, cacheFileSize
, 0 };
2053 ::fcntl(fd
, F_PREALLOCATE
, &fcntlSpec
);
2055 // write out cache file
2057 fprintf(stderr
, "update_dyld_shared_cache: writing cache to disk\n");
2058 if ( ::pwrite(fd
, inMemoryCache
, cacheFileSize
, 0) != cacheFileSize
)
2059 throwf("write() failure creating cache file, errno=%d", errno
);
2061 // assuming write takes 35% of time
2062 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*90, archCount
*100);
2065 // flush to disk and close
2066 int result
= ::fcntl(fd
, F_FULLFSYNC
, NULL
);
2068 fprintf(stderr
, "update_dyld_shared_cache: warning, fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno
, tempCachePath
);
2069 result
= ::close(fd
);
2071 fprintf(stderr
, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno
, tempCachePath
);
2073 // atomically swap in new cache file, do this after F_FULLFSYNC
2074 result
= ::rename(tempCachePath
, fCacheFilePath
);
2076 throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath
, fCacheFilePath
, errno
);
2078 // flush everything to disk to assure rename() gets recorded
2082 // restore default signal handlers
2083 ::signal(SIGINT
, SIG_DFL
);
2084 ::signal(SIGBUS
, SIG_DFL
);
2085 ::signal(SIGSEGV
, SIG_DFL
);
2087 // generate human readable "map" file that shows the layout of the cache file
2089 fprintf(stderr
, "update_dyld_shared_cache: writing .map file to disk\n");
2090 char mapFilePath
[strlen(fCacheFilePath
)+16];
2091 sprintf(mapFilePath
, "%s.map", fCacheFilePath
);
2092 char tempMapFilePath
[strlen(fCacheFilePath
)+32];
2093 sprintf(tempMapFilePath
, "%s.map%u", fCacheFilePath
, getpid());
2094 FILE* fmap
= ::fopen(tempMapFilePath
, "w");
2095 if ( fmap
== NULL
) {
2096 fprintf(stderr
, "can't create map file %s, errnor=%d", tempCachePath
, errno
);
2099 for(std::vector
<shared_file_mapping_np
>::iterator it
= fMappings
.begin(); it
!= fMappings
.end(); ++it
) {
2100 const char* prot
= "RW";
2101 if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_READ
) )
2103 else if ( it
->sfm_init_prot
== VM_PROT_READ
)
2105 else if ( it
->sfm_init_prot
== (VM_PROT_EXECUTE
|VM_PROT_WRITE
|VM_PROT_READ
) )
2107 if ( it
->sfm_size
> 1024*1024 )
2108 fprintf(fmap
, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/(1024*1024),
2109 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
2111 fprintf(fmap
, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot
, it
->sfm_size
/1024,
2112 it
->sfm_address
, it
->sfm_address
+it
->sfm_size
);
2115 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX weak binding info\n",
2116 (fOffsetOfExportInfoInCombinedLinkedit
-fOffsetOfWeakBindInfoInCombinedLinkedit
)/1024,
2117 fLinkEditsStartAddress
+fOffsetOfWeakBindInfoInCombinedLinkedit
,
2118 fLinkEditsStartAddress
+fOffsetOfExportInfoInCombinedLinkedit
);
2119 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX export info\n",
2120 (fOffsetOfBindInfoInCombinedLinkedit
-fOffsetOfExportInfoInCombinedLinkedit
)/1024,
2121 fLinkEditsStartAddress
+fOffsetOfExportInfoInCombinedLinkedit
,
2122 fLinkEditsStartAddress
+fOffsetOfBindInfoInCombinedLinkedit
);
2123 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX binding info\n",
2124 (fOffsetOfLazyBindInfoInCombinedLinkedit
-fOffsetOfBindInfoInCombinedLinkedit
)/1024,
2125 fLinkEditsStartAddress
+fOffsetOfBindInfoInCombinedLinkedit
,
2126 fLinkEditsStartAddress
+fOffsetOfLazyBindInfoInCombinedLinkedit
);
2127 fprintf(fmap
, "linkedit %4uKB 0x%0llX -> 0x%0llX lazy binding info\n",
2128 (fOffsetOfOldSymbolTableInfoInCombinedLinkedit
-fOffsetOfLazyBindInfoInCombinedLinkedit
)/1024,
2129 fLinkEditsStartAddress
+fOffsetOfLazyBindInfoInCombinedLinkedit
,
2130 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
);
2131 fprintf(fmap
, "linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld symbol table info\n",
2132 (fLinkEditsTotalOptimizedSize
-fOffsetOfOldSymbolTableInfoInCombinedLinkedit
)/(1024*1024),
2133 fLinkEditsStartAddress
+fOffsetOfOldSymbolTableInfoInCombinedLinkedit
,
2134 fLinkEditsStartAddress
+fLinkEditsTotalOptimizedSize
);
2136 for(typename
std::vector
<LayoutInfo
>::const_iterator it
= fDylibs
.begin(); it
!= fDylibs
.end(); ++it
) {
2137 fprintf(fmap
, "%s\n", it
->layout
->getID().name
);
2138 const std::vector
<MachOLayoutAbstraction::Segment
>& segs
= it
->layout
->getSegments();
2139 for (int i
=0; i
< segs
.size(); ++i
) {
2140 const MachOLayoutAbstraction::Segment
& seg
= segs
[i
];
2141 fprintf(fmap
, "\t%16s 0x%0llX -> 0x%0llX\n", seg
.name(), seg
.newAddress(), seg
.newAddress()+seg
.size());
2144 if ( warnings
.size() > 0 ) {
2145 fprintf(fmap
, "# Warnings:\n");
2146 for (std::vector
<const char*>::iterator it
=warnings
.begin(); it
!= warnings
.end(); ++it
) {
2147 fprintf(fmap
, "# %s\n", *it
);
2151 result
= ::rename(tempMapFilePath
, mapFilePath
);
2155 // free in memory cache
2156 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
2157 inMemoryCache
= NULL
;
2160 fprintf(stdout
, "%3u/%u\n", (archIndex
+1)*100, archCount
*100);
2164 // remove temp cache file
2165 ::unlink(tempCachePath
);
2166 // remove in memory cache
2167 if ( inMemoryCache
!= NULL
)
2168 vm_deallocate(mach_task_self(), (vm_address_t
)inMemoryCache
, allocatedCacheSize
);
2178 // The shared cache is driven by /var/db/dyld/shared_region_roots which contains
2179 // the paths used to search for dylibs that should go in the shared cache
2181 // Leading and trailing white space is ignored
2182 // Blank lines are ignored
2183 // Lines starting with # are ignored
2185 static void parsePathsFile(const char* filePath
, std::vector
<const char*>& paths
)
2187 // read in whole file
2188 int fd
= open(filePath
, O_RDONLY
, 0);
2190 fprintf(stderr
, "update_dyld_shared_cache: can't open file: %s\n", filePath
);
2193 struct stat stat_buf
;
2194 fstat(fd
, &stat_buf
);
2195 char* p
= (char*)malloc(stat_buf
.st_size
);
2197 fprintf(stderr
, "update_dyld_shared_cache: malloc failure\n");
2200 if ( read(fd
, p
, stat_buf
.st_size
) != stat_buf
.st_size
) {
2201 fprintf(stderr
, "update_dyld_shared_cache: can't read file: %s\n", filePath
);
2206 // parse into paths and add to vector
2207 char * const end
= &p
[stat_buf
.st_size
];
2208 enum { lineStart
, inSymbol
, inComment
} state
= lineStart
;
2209 char* symbolStart
= NULL
;
2210 for (char* s
= p
; s
< end
; ++s
) {
2216 else if ( !isspace(*s
) ) {
2224 // removing any trailing spaces
2226 while ( isspace(*last
) ) {
2230 paths
.push_back(symbolStart
);
2241 // Note: we do not free() the malloc buffer, because the strings in it are used by exec()
2246 static void setSharedDylibs(const char* rootPath
, bool usesOverlay
, const std::set
<ArchPair
>& onlyArchs
, std::vector
<const char*> rootsPaths
)
2248 // set file system root
2249 ArchGraph::setFileSystemRoot(rootPath
, usesOverlay
);
2251 // initialize all architectures requested
2252 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
2253 ArchGraph::addArchPair(*a
);
2255 // add roots to graph
2256 for(std::vector
<const char*>::const_iterator it
= rootsPaths
.begin(); it
!= rootsPaths
.end(); ++it
)
2257 ArchGraph::addRoot(*it
, onlyArchs
);
2259 // determine shared dylibs
2260 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
)
2261 ArchGraph::findSharedDylibs(*a
);
2265 static void scanForSharedDylibs(const char* rootPath
, bool usesOverlay
, const char* dirOfPathFiles
, const std::set
<ArchPair
>& onlyArchs
)
2267 char rootDirOfPathFiles
[strlen(rootPath
)+strlen(dirOfPathFiles
)+2];
2268 // in -overlay mode, still look for roots in /var/db/dyld
2269 // in -root mode, look for roots in /rootpath/var/db/dyld
2270 if ( !usesOverlay
&& (strlen(rootPath
) != 0) ) {
2271 strcpy(rootDirOfPathFiles
, rootPath
);
2272 strcat(rootDirOfPathFiles
, dirOfPathFiles
);
2273 dirOfPathFiles
= rootDirOfPathFiles
;
2276 // extract all root paths from files in "/var/db/dyld/shared_region_roots/"
2278 fprintf(stderr
, "update_dyld_shared_cache: finding roots in: %s\n", dirOfPathFiles
);
2279 std::vector
<const char*> rootsPaths
;
2280 DIR* dir
= ::opendir(dirOfPathFiles
);
2282 throwf("%s does not exist, errno=%d\n", dirOfPathFiles
, errno
);
2283 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
2284 if ( entry
->d_type
== DT_REG
) {
2285 // only look at files ending in .paths
2286 if ( strcmp(&entry
->d_name
[entry
->d_namlen
-6], ".paths") == 0 ) {
2287 char fullPath
[strlen(dirOfPathFiles
)+entry
->d_namlen
+2];
2288 strcpy(fullPath
, dirOfPathFiles
);
2289 strcat(fullPath
, "/");
2290 strcat(fullPath
, entry
->d_name
);
2291 parsePathsFile(fullPath
, rootsPaths
);
2294 fprintf(stderr
, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry
->d_name
);
2300 if ( rootsPaths
.size() == 0 )
2301 fprintf(stderr
, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
2302 setSharedDylibs(rootPath
, usesOverlay
, onlyArchs
, rootsPaths
);
2305 static void setSharedDylibs(const char* rootPath
, bool usesOverlay
, const char* pathsFile
, const std::set
<ArchPair
>& onlyArchs
)
2307 std::vector
<const char*> rootsPaths
;
2308 parsePathsFile(pathsFile
, rootsPaths
);
2309 setSharedDylibs(rootPath
, usesOverlay
, onlyArchs
, rootsPaths
);
2313 // If the 10.5.0 version of update_dyld_shared_cache was killed or crashed, it
2314 // could leave large half written cache files laying around. The function deletes
2315 // those files. To prevent the deletion of tmp files being created by another
2316 // copy of update_dyld_shared_cache, it only deletes the temp cache file if its
2317 // creation time was before the last restart of this machine.
2318 static void deleteOrphanTempCacheFiles()
2320 DIR* dir
= ::opendir(DYLD_SHARED_CACHE_DIR
);
2321 if ( dir
!= NULL
) {
2322 std::vector
<const char*> filesToDelete
;
2323 for (dirent
* entry
= ::readdir(dir
); entry
!= NULL
; entry
= ::readdir(dir
)) {
2324 if ( entry
->d_type
== DT_REG
) {
2325 // only look at files with .tmp in name
2326 if ( strstr(entry
->d_name
, ".tmp") != NULL
) {
2327 char fullPath
[strlen(DYLD_SHARED_CACHE_DIR
)+entry
->d_namlen
+2];
2328 strcpy(fullPath
, DYLD_SHARED_CACHE_DIR
);
2329 strcat(fullPath
, "/");
2330 strcat(fullPath
, entry
->d_name
);
2331 struct stat tmpFileStatInfo
;
2332 if ( stat(fullPath
, &tmpFileStatInfo
) != -1 ) {
2333 int mib
[2] = {CTL_KERN
, KERN_BOOTTIME
};
2334 struct timeval boottime
;
2335 size_t size
= sizeof(boottime
);
2336 if ( (sysctl(mib
, 2, &boottime
, &size
, NULL
, 0) != -1) && (boottime
.tv_sec
!= 0) ) {
2337 // make sure this file is older than the boot time of this machine
2338 if ( tmpFileStatInfo
.st_mtime
< boottime
.tv_sec
) {
2339 filesToDelete
.push_back(strdup(fullPath
));
2347 for(std::vector
<const char*>::iterator it
= filesToDelete
.begin(); it
!= filesToDelete
.end(); ++it
) {
2348 fprintf(stderr
, "update_dyld_shared_cache: deleting old temp cache file: %s\n", *it
);
2356 static bool updateSharedeCacheFile(const char* rootPath
, bool usesOverlay
, const char* cacheDir
, const std::set
<ArchPair
>& onlyArchs
,
2357 bool force
, bool alphaSort
, bool optimize
, bool deleteExistingFirst
, bool verify
, bool keepSignatures
)
2359 bool didUpdate
= false;
2360 // get dyld load address info
2361 UniversalMachOLayout
* dyldLayout
= NULL
;
2362 char dyldPath
[1024];
2363 strlcpy(dyldPath
, rootPath
, 1024);
2364 strlcat(dyldPath
, "/usr/lib/dyld", 1024);
2365 struct stat stat_buf
;
2366 if ( stat(dyldPath
, &stat_buf
) == 0 ) {
2367 dyldLayout
= new UniversalMachOLayout(dyldPath
, &onlyArchs
);
2370 dyldLayout
= new UniversalMachOLayout("/usr/lib/dyld", &onlyArchs
);
2372 const int archCount
= onlyArchs
.size();
2374 for(std::set
<ArchPair
>::iterator a
= onlyArchs
.begin(); a
!= onlyArchs
.end(); ++a
, ++index
) {
2375 const MachOLayoutAbstraction
* dyldLayoutForArch
= dyldLayout
->getSlice(*a
);
2376 uint64_t dyldBaseAddress
= 0;
2377 if ( dyldLayoutForArch
!= NULL
)
2378 dyldBaseAddress
= dyldLayoutForArch
->getBaseAddress();
2380 fprintf(stderr
, "update_dyld_shared_cache: warning, dyld not available for specified architectures\n");
2381 switch ( a
->arch
) {
2382 case CPU_TYPE_POWERPC
:
2384 #if __i386__ || __x86_64__
2385 // <rdar://problem/5217377> Rosetta does not work with optimized dyld shared cache
2386 SharedCache
<ppc
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, alphaSort
, verify
, false, usesOverlay
, dyldBaseAddress
);
2387 didUpdate
|= cache
.update(usesOverlay
, force
, false, deleteExistingFirst
, index
, archCount
, keepSignatures
);
2389 SharedCache
<ppc
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, alphaSort
, verify
, optimize
, usesOverlay
, dyldBaseAddress
);
2390 didUpdate
|= cache
.update(usesOverlay
, force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
);
2396 SharedCache
<x86
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, alphaSort
, verify
, optimize
, usesOverlay
, dyldBaseAddress
);
2397 didUpdate
|= cache
.update(usesOverlay
, force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
);
2400 case CPU_TYPE_X86_64
:
2402 SharedCache
<x86_64
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, alphaSort
, verify
, optimize
, usesOverlay
, dyldBaseAddress
);
2403 didUpdate
|= cache
.update(usesOverlay
, force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
);
2408 SharedCache
<arm
> cache(ArchGraph::graphForArchPair(*a
), rootPath
, alphaSort
, verify
, optimize
, usesOverlay
, dyldBaseAddress
);
2409 didUpdate
|= cache
.update(usesOverlay
, force
, optimize
, deleteExistingFirst
, index
, archCount
, keepSignatures
);
2415 deleteOrphanTempCacheFiles();
2423 fprintf(stderr
, "update_dyld_shared_cache [-force] [-root dir] [-overlay dir] [-arch arch] [-debug]\n");
2427 int main(int argc
, const char* argv
[])
2429 std::set
<ArchPair
> onlyArchs
;
2430 const char* rootPath
= "";
2431 const char* dylibListFile
= NULL
;
2433 bool alphaSort
= false;
2434 bool optimize
= true;
2435 bool hasRoot
= false;
2436 bool hasOverlay
= false;
2437 bool verify
= false;
2438 bool keepSignatures
= false;
2441 // parse command line options
2442 for(int i
=1; i
< argc
; ++i
) {
2443 const char* arg
= argv
[i
];
2444 if ( arg
[0] == '-' ) {
2445 if ( strcmp(arg
, "-debug") == 0 ) {
2448 else if ( strcmp(arg
, "-force") == 0 ) {
2451 else if ( strcmp(arg
, "-verify") == 0 ) {
2454 else if ( strcmp(arg
, "-sort_by_name") == 0 ) {
2457 else if ( strcmp(arg
, "-progress") == 0 ) {
2460 else if ( strcmp(arg
, "-opt") == 0 ) {
2463 else if ( strcmp(arg
, "-no_opt") == 0 ) {
2466 else if ( strcmp(arg
, "-dylib_list") == 0 ) {
2467 dylibListFile
= argv
[++i
];
2468 if ( dylibListFile
== NULL
)
2469 throw "-dylib_list missing path argument";
2470 keepSignatures
= true;
2472 else if ( (strcmp(arg
, "-root") == 0) || (strcmp(arg
, "--root") == 0) ) {
2474 throw "cannot use both -root and -overlay";
2475 rootPath
= argv
[++i
];
2476 if ( rootPath
== NULL
)
2477 throw "-root missing path argument";
2480 else if ( strcmp(arg
, "-overlay") == 0 ) {
2482 throw "cannot use both -root and -overlay";
2483 rootPath
= argv
[++i
];
2484 if ( rootPath
== NULL
)
2485 throw "-root missing path argument";
2488 else if ( strcmp(arg
, "-arch") == 0 ) {
2489 const char* arch
= argv
[++i
];
2490 if ( strcmp(arch
, "ppc") == 0 )
2491 onlyArchs
.insert(ArchPair(CPU_TYPE_POWERPC
, CPU_SUBTYPE_POWERPC_ALL
));
2492 else if ( strcmp(arch
, "i386") == 0 )
2493 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
2494 else if ( strcmp(arch
, "x86_64") == 0 )
2495 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
2496 else if ( strcmp(arch
, "armv4t") == 0 )
2497 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V4T
));
2498 else if ( strcmp(arch
, "armv5") == 0 )
2499 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V5TEJ
));
2500 else if ( strcmp(arch
, "armv6") == 0 )
2501 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V6
));
2502 else if ( strcmp(arch
, "armv7") == 0 )
2503 onlyArchs
.insert(ArchPair(CPU_TYPE_ARM
, CPU_SUBTYPE_ARM_V7
));
2505 throwf("unknown architecture %s", arch
);
2507 else if ( strcmp(arg
, "-universal_boot") == 0 ) {
2509 throwf("universal_boot option can only be used on Intel machines");
2511 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
2512 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
2516 throwf("unknown option: %s\n", arg
);
2521 throwf("unknown option: %s\n", arg
);
2525 // strip tailing slashes on -root or -overlay
2526 if ( rootPath
[0] != '\0' ) {
2527 int len
= strlen(rootPath
)-1;
2528 if ( rootPath
[len
] == '/' ) {
2529 char* newRootPath
= strdup(rootPath
);
2530 while ( newRootPath
[len
] == '/' )
2531 newRootPath
[len
--] = '\0';
2532 rootPath
= newRootPath
;
2536 // if no restrictions specified, use architectures that work on this machine
2537 if ( onlyArchs
.size() == 0 ) {
2539 size_t len
= sizeof(int);
2540 #if __i386__ || __x86_64__
2541 onlyArchs
.insert(ArchPair(CPU_TYPE_I386
, CPU_SUBTYPE_I386_ALL
));
2542 // check rosetta is installed
2543 char rosettaPath
[1024];
2544 strlcpy(rosettaPath
, rootPath
, 1024);
2545 strlcat(rosettaPath
, "/usr/libexec/oah/translate", 1024);
2546 struct stat stat_buf
;
2547 if ( stat(rosettaPath
, &stat_buf
) == 0 ) {
2548 onlyArchs
.insert(ArchPair(CPU_TYPE_POWERPC
, CPU_SUBTYPE_POWERPC_ALL
));
2550 else if ( hasOverlay
) {
2551 // in overlay mode, rosetta may be installed on base system, but is not in update root
2552 if ( stat("/usr/libexec/oah/translate", &stat_buf
) == 0 )
2553 onlyArchs
.insert(ArchPair(CPU_TYPE_POWERPC
, CPU_SUBTYPE_POWERPC_ALL
));
2555 // check system is capable of running 64-bit programs
2556 if ( (sysctlbyname("hw.optional.x86_64", &available
, &len
, NULL
, 0) == 0) && available
)
2557 onlyArchs
.insert(ArchPair(CPU_TYPE_X86_64
, CPU_SUBTYPE_X86_64_ALL
));
2559 #error unknown architecture
2563 if ( !verify
&& (geteuid() != 0) )
2564 throw "you must be root to run this tool";
2566 // build list of shared dylibs
2567 if ( dylibListFile
!= NULL
)
2568 setSharedDylibs(rootPath
, hasOverlay
, dylibListFile
, onlyArchs
);
2570 scanForSharedDylibs(rootPath
, hasOverlay
, "/var/db/dyld/shared_region_roots/", onlyArchs
);
2571 updateSharedeCacheFile(rootPath
, hasOverlay
, DYLD_SHARED_CACHE_DIR
, onlyArchs
, force
, alphaSort
, optimize
,
2572 false, verify
, keepSignatures
);
2574 catch (const char* msg
) {
2575 fprintf(stderr
, "update_dyld_shared_cache failed: %s\n", msg
);