1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/mman.h>
28#include <mach/mach.h>
29#include <mach/mach_time.h>
30#include <limits.h>
31#include <stdarg.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <math.h>
35#include <fcntl.h>
36#include <dlfcn.h>
37#include <signal.h>
38#include <errno.h>
39#include <sys/uio.h>
40#include <unistd.h>
41#include <dirent.h>
42#include <sys/param.h>
43#include <sys/sysctl.h>
44#include <sys/resource.h>
45#include <dirent.h>
46#include <servers/bootstrap.h>
47#include <mach-o/loader.h>
48#include <mach-o/fat.h>
49#include <CoreFoundation/CoreFoundation.h>
50#include <Security/Security.h>
51#include <Security/SecCodeSigner.h>
52#include <CommonCrypto/CommonDigest.h>
53
54#include "dyld_cache_format.h"
55
56#include <vector>
57#include <set>
58#include <map>
59#include <unordered_map>
60
61#include "Architectures.hpp"
62#include "MachOLayout.hpp"
63#include "MachORebaser.hpp"
64#include "MachOBinder.hpp"
65#include "CacheFileAbstraction.hpp"
66#include "dyld_cache_config.h"
67
68#define SELOPT_WRITE
69#include "objc-shared-cache.h"
70
71#define FIRST_DYLIB_TEXT_OFFSET 0x8000
72
73#ifndef LC_FUNCTION_STARTS
74    #define LC_FUNCTION_STARTS 0x26
75#endif
76
77static bool							verbose = false;
78static bool							progress = false;
79static bool							iPhoneOS = false;
80static std::vector<const char*>		warnings;
81
82
83static void warn(const char *arch, const char *format, ...)
84{
85    char *msg;
86
87    va_list args;
88    va_start(args, format);
89    ::vasprintf(&msg, format, args);
90    va_end(args);
91
92    warnings.push_back(msg);
93
94    if ( verbose ) {
95        ::fprintf(::stderr, "update_dyld_shared_cache: warning: %s%s%s%s\n",
96                  arch ? "for arch " : "",
97                  arch ? arch : "",
98                  arch ? ", " : "",
99                  msg);
100    }
101}
102
103
104class CStringHash {
105public:
106	size_t operator()(const char* __s) const {
107		size_t __h = 0;
108		for ( ; *__s; ++__s)
109			__h = 5 * __h + *__s;
110		return __h;
111	};
112};
113class CStringEquals
114{
115public:
116	bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
117};
118
119
120
121class ArchGraph
122{
123public:
124	typedef std::unordered_map<const char*, const char*, CStringHash, CStringEquals> StringToString;
125
126	static void			addArchPair(ArchPair ap);
127	static void			addRoot(const char* vpath, const std::set<ArchPair>& archs);
128	static void			findSharedDylibs(ArchPair ap);
129	static ArchGraph*	graphForArchPair(ArchPair ap) { return fgPerArchGraph[ap]; }
130	static void			setFileSystemRoot(const char* root) { fgFileSystemRoot = root; }
131	static void			setFileSystemOverlay(const std::vector<const char*>& overlays);
132	static const char*	archName(ArchPair ap);
133
134	ArchPair											getArchPair() { return fArchPair; }
135	std::set<const class MachOLayoutAbstraction*>&		getSharedDylibs() { return fSharedDylibs; }
136	StringToString&										getDylibAliases() { return fAliasesMap; }
137	const char*											archName() { return archName(fArchPair); }
138
139private:
140
141	class DependencyNode
142	{
143	public:
144										DependencyNode(ArchGraph*, const char* path, const MachOLayoutAbstraction* layout);
145		void							loadDependencies(const MachOLayoutAbstraction*);
146		void							markNeededByRoot(DependencyNode*);
147		const char*						getPath() const { return fPath; }
148		const MachOLayoutAbstraction*	getLayout() const { return fLayout; }
149		size_t							useCount() const { return fRootsDependentOnThis.size(); }
150		bool							allDependentsFound() const { return !fDependentMissing; }
151	private:
152		ArchGraph*									fGraph;
153		const char*									fPath;
154		const MachOLayoutAbstraction*				fLayout;
155		bool										fDependenciesLoaded;
156		bool										fDependentMissing;
157		std::set<DependencyNode*>					fDependsOn;
158		std::set<DependencyNode*>					fRootsDependentOnThis;
159	};
160
161	typedef std::unordered_map<const char*, class DependencyNode*, CStringHash, CStringEquals> PathToNode;
162
163
164								ArchGraph(ArchPair ap) : fArchPair(ap) {}
165	void						addRoot(const char* path, const MachOLayoutAbstraction*);
166	DependencyNode*				getNode(const char* path);
167	DependencyNode*				getNodeForVirtualPath(const char* vpath);
168	static bool					canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, const std::set<const MachOLayoutAbstraction*>& possibleLibs, std::map<const MachOLayoutAbstraction*, bool>& shareableMap);
169	static bool					sharable(const MachOLayoutAbstraction* layout, ArchPair ap, char** msg);
170
171	static std::map<ArchPair, ArchGraph*>	fgPerArchGraph;
172	static const char*						fgFileSystemRoot;
173	static std::vector<const char*> 		fgFileSystemOverlays;
174
175	ArchPair									fArchPair;
176	std::set<DependencyNode*>					fRoots;
177	PathToNode									fNodes;
178	std::set<const MachOLayoutAbstraction*>		fSharedDylibs;  // use set to avoid duplicates when installname!=realpath
179	StringToString								fAliasesMap;
180};
181std::map<ArchPair, ArchGraph*>		ArchGraph::fgPerArchGraph;
182const char*							ArchGraph::fgFileSystemRoot = "";
183std::vector<const char*> 			ArchGraph::fgFileSystemOverlays;
184
185void ArchGraph::addArchPair(ArchPair ap)
186{
187	//fprintf(stderr, "adding ArchPair 0x%08X,0x%08X\n", ap.arch, ap.subtype);
188	fgPerArchGraph[ap] = new ArchGraph(ap);
189}
190
191void ArchGraph::setFileSystemOverlay(const std::vector<const char*>& overlays)
192{
193	for (std::vector<const char*>::const_iterator it=overlays.begin(); it != overlays.end(); ++it)
194		fgFileSystemOverlays.push_back(*it);
195}
196
197void ArchGraph::addRoot(const char* vpath, const std::set<ArchPair>& onlyArchs)
198{
199	//fprintf(stderr, "addRoot(%s)\n", vpath);
200	char completePath[MAXPATHLEN];
201	const char* path = NULL;
202	// check -overlay path first
203	for (std::vector<const char*>::const_iterator it=fgFileSystemOverlays.begin(); it != fgFileSystemOverlays.end(); ++it) {
204		strcpy(completePath, *it);
205		strcat(completePath, vpath);	// assumes vpath starts with '/'
206		struct stat stat_buf;
207		if ( stat(completePath, &stat_buf) == 0 ) {
208			path = completePath;
209			break;
210		}
211	}
212	// if not found in overlay, check for -root
213	if ( (path == NULL) && (fgFileSystemRoot[0] != '\0') ) {
214		strcpy(completePath, fgFileSystemRoot);
215		strcat(completePath, vpath);	// assumes vpath starts with '/'
216		struct stat stat_buf;
217		if ( stat(completePath, &stat_buf) == 0 )
218			path = completePath;
219	}
220	if ( path == NULL )
221		path = vpath;
222
223	try {
224		//fprintf(stderr, "    UniversalMachOLayout::find(%s)\n", path);
225		const UniversalMachOLayout& uni = UniversalMachOLayout::find(path, &onlyArchs);
226		for(std::set<ArchPair>::iterator ait = onlyArchs.begin(); ait != onlyArchs.end(); ++ait) {
227			try {
228				const MachOLayoutAbstraction* layout = uni.getSlice(*ait);
229				if ( layout != NULL )
230					fgPerArchGraph[*ait]->addRoot(path, layout);
231			}
232			catch (const char* msg) {
233				if ( verbose )
234					fprintf(stderr, "update_dyld_shared_cache: warning for %s can't use root '%s': %s\n", fgPerArchGraph[*ait]->archName(), path, msg);
235			}
236
237		}
238	}
239	catch (const char* msg) {
240		fprintf(stderr, "update_dyld_shared_cache: warning can't use root '%s': %s\n", path, msg);
241	}
242}
243
244
245
246void ArchGraph::addRoot(const char* path, const MachOLayoutAbstraction* layout)
247{
248	if ( verbose )
249		fprintf(stderr, "update_dyld_shared_cache: adding root: %s\n", path);
250	DependencyNode*	node = this->getNode(path);
251	fRoots.insert(node);
252	const MachOLayoutAbstraction* mainExecutableLayout = NULL;
253	if ( layout->getFileType() == MH_EXECUTE )
254		mainExecutableLayout = layout;
255	node->loadDependencies(mainExecutableLayout);
256	node->markNeededByRoot(node);
257	if ( layout->getFileType() == MH_DYLIB )
258		node->markNeededByRoot(NULL);
259}
260
261// a virtual path does not have the fgFileSystemRoot prefix
262ArchGraph::DependencyNode* ArchGraph::getNodeForVirtualPath(const char* vpath)
263{
264	//fprintf(stderr, "getNodeForVirtualPath(%s)\n", vpath);
265	char completePath[MAXPATHLEN];
266	for (std::vector<const char*>::const_iterator it=fgFileSystemOverlays.begin(); it != fgFileSystemOverlays.end(); ++it) {
267		const char* overlayPath = *it;
268		// using -overlay means if /overlay/path/dylib exists use it, otherwise use /path/dylib
269		strcpy(completePath, overlayPath);
270		strcat(completePath, vpath);	// assumes vpath starts with '/'
271		struct stat stat_buf;
272		if ( stat(completePath, &stat_buf) == 0 ) {
273			return this->getNode(completePath);
274		}
275		// <rdar://problem/9279770> support when install name is a symlink
276		const char* pathToSymlink = vpath;
277		if ( fgFileSystemRoot[0] != '\0' ) {
278			strcpy(completePath, fgFileSystemRoot);
279			strcat(completePath, vpath);
280			pathToSymlink = completePath;
281		}
282		if ( (lstat(pathToSymlink, &stat_buf) == 0) && S_ISLNK(stat_buf.st_mode) ) {
283			// requested path did not exist in /overlay, but leaf of path is a symlink in /
284			char pathInSymLink[MAXPATHLEN];
285			size_t res = readlink(pathToSymlink, pathInSymLink, sizeof(pathInSymLink));
286			if ( res != -1 ) {
287				pathInSymLink[res] = '\0';
288				if ( pathInSymLink[0] != '/' ) {
289					char symFullPath[MAXPATHLEN];
290					strcpy(symFullPath, vpath);
291					char* lastSlash = strrchr(symFullPath, '/');
292					if ( lastSlash != NULL ) {
293						strcpy(lastSlash+1, pathInSymLink);
294						// (re)try looking for what symlink points to, but in /overlay
295						return this->getNodeForVirtualPath(symFullPath);
296					}
297				}
298			}
299		}
300	}
301
302	if ( fgFileSystemRoot[0] != '\0' ) {
303		// using -root means always use /rootpath/usr/lib
304		strcpy(completePath, fgFileSystemRoot);
305		strcat(completePath, vpath);	// assumes vpath starts with '/'
306		return this->getNode(completePath);
307	}
308	// not found in -overlay or -root not used
309	return this->getNode(vpath);
310}
311
312ArchGraph::DependencyNode* ArchGraph::getNode(const char* path)
313{
314	//fprintf(stderr, "getNode(%s)\n", path);
315	// look up supplied path to see if node already exists
316	PathToNode::iterator pos = fNodes.find(path);
317	if ( pos != fNodes.end() )
318		return pos->second;
319
320	// get real path
321	char realPath[MAXPATHLEN];
322	if ( realpath(path, realPath) == NULL )
323		throwf("realpath() failed on %s\n", path);
324
325	// look up real path to see if node already exists
326	pos = fNodes.find(realPath);
327	if ( pos != fNodes.end() ) {
328		// update fAliasesMap with symlinks found
329		const char* aliasPath = path;
330		if ( (fgFileSystemRoot != NULL) && (strncmp(path, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
331			aliasPath = &path[strlen(fgFileSystemRoot)];
332		}
333		if ( fAliasesMap.find(aliasPath) == fAliasesMap.end() ) {
334			if ( strcmp(aliasPath, pos->second->getLayout()->getID().name) != 0 ) {
335				fAliasesMap[strdup(aliasPath)] = pos->second->getLayout()->getID().name;
336				//fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
337			}
338		}
339		return pos->second;
340	}
341
342	// still does not exist, so create a new node
343	const UniversalMachOLayout& uni = UniversalMachOLayout::find(realPath);
344	DependencyNode* node = new DependencyNode(this, realPath, uni.getSlice(fArchPair));
345	if ( node->getLayout() == NULL ) {
346		throwf("%s is missing arch %s", realPath, archName(fArchPair));
347	}
348	// add realpath to node map
349	fNodes[node->getPath()] = node;
350	// if install name is not real path, add install name to node map
351	if ( (node->getLayout()->getFileType() == MH_DYLIB) && (strcmp(realPath, node->getLayout()->getID().name) != 0) ) {
352		//fprintf(stderr, "adding %s node alias %s for %s\n", archName(fArchPair), node->getLayout()->getID().name, realPath);
353		pos = fNodes.find(node->getLayout()->getID().name);
354		if ( pos != fNodes.end() ) {
355			// get uuids of two dylibs to see if this is accidental copy of a dylib or two differnent dylibs with same -install_name
356			uuid_t uuid1;
357			uuid_t uuid2;
358			node->getLayout()->uuid(uuid1);
359			pos->second->getLayout()->uuid(uuid2);
360			if ( memcmp(&uuid1, &uuid2, 16) == 0 ) {
361				// <rdar://problem/8305479> warn if two dylib in cache have same install_name
362				char* msg;
363				asprintf(&msg, "update_dyld_shared_cache: warning, found two copies of the same dylib with same install path: %s\n\t%s\n\t%s\n",
364										node->getLayout()->getID().name, pos->second->getPath(), node->getPath());
365				fprintf(stderr, "%s", msg);
366				warnings.push_back(msg);
367			}
368			else {
369				// <rdar://problem/12763450> update_dyld_shared_cache should fail if two images have same install name
370				fprintf(stderr, "update_dyld_shared_cache: found two different dylibs with same install path: %s\n\t%s\n\t%s\n",
371							node->getLayout()->getID().name, pos->second->getPath(), node->getPath());
372				exit(1);
373			}
374		}
375		else
376			fNodes[node->getLayout()->getID().name] = node;
377		// update fAliasesMap with symlinks found
378		const char* aliasPath = realPath;
379		if ( (fgFileSystemRoot != NULL) && (fgFileSystemRoot[0] != '\0') && (strncmp(realPath, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
380			aliasPath = &realPath[strlen(fgFileSystemRoot)];
381		}
382		// <rdar://problem/11192810> Too many aliases in -overlay mode
383		for (std::vector<const char*>::const_iterator it=fgFileSystemOverlays.begin(); it != fgFileSystemOverlays.end(); ++it) {
384			const char* overlayPath = *it;
385			if ( strncmp(realPath, overlayPath, strlen(overlayPath)) == 0 ) {
386				aliasPath = &realPath[strlen(overlayPath)];
387				break;
388			}
389		}
390		if ( fAliasesMap.find(aliasPath) == fAliasesMap.end() ) {
391			if ( strcmp(aliasPath, node->getLayout()->getID().name) != 0 ) {
392				fAliasesMap[strdup(aliasPath)] = node->getLayout()->getID().name;
393				//fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
394			}
395		}
396	}
397	return node;
398}
399
400
401void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction* mainExecutableLayout)
402{
403	if ( !fDependenciesLoaded ) {
404		fDependenciesLoaded = true;
405		// add dependencies
406		const std::vector<MachOLayoutAbstraction::Library>&	dependsOn = fLayout->getLibraries();
407		for(std::vector<MachOLayoutAbstraction::Library>::const_iterator it = dependsOn.begin(); it != dependsOn.end(); ++it) {
408			try {
409				const char* dependentPath = it->name;
410				if ( strncmp(dependentPath, "@executable_path/", 17) == 0 ) {
411					if ( mainExecutableLayout == NULL )
412						throw "@executable_path without main executable";
413					// expand @executable_path path prefix
414					const char* executablePath = mainExecutableLayout->getFilePath();
415					char newPath[strlen(executablePath) + strlen(dependentPath)+2];
416					if ( (fgFileSystemRoot != NULL) && (strncmp(executablePath, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
417						// executablePath already has rootPath prefix, need to remove that to get to base virtual path
418						strcpy(newPath, &executablePath[strlen(fgFileSystemRoot)]);
419					}
420					else {
421						strcpy(newPath, executablePath);
422					}
423					char* addPoint = strrchr(newPath,'/');
424					if ( addPoint != NULL )
425						strcpy(&addPoint[1], &dependentPath[17]);
426					else
427						strcpy(newPath, &dependentPath[17]);
428					dependentPath = strdup(newPath);
429				}
430				else if ( strncmp(dependentPath, "@loader_path/", 13) == 0 ) {
431					// expand @loader_path path prefix
432					char newPath[strlen(fPath) + strlen(dependentPath)+2];
433					if ( (fgFileSystemRoot != NULL) && (strncmp(fPath, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
434						// fPath already has rootPath prefix, need to remove that to get to base virtual path
435						strcpy(newPath, &fPath[strlen(fgFileSystemRoot)]);
436					}
437					else {
438						strcpy(newPath, fPath);
439					}
440					char* addPoint = strrchr(newPath,'/');
441					if ( addPoint != NULL )
442						strcpy(&addPoint[1], &dependentPath[13]);
443					else
444						strcpy(newPath, &dependentPath[13]);
445					dependentPath = strdup(newPath);
446				}
447				else if ( strncmp(dependentPath, "@rpath/", 7) == 0 ) {
448					throw "@rpath not supported in dyld shared cache";
449				}
450				// <rdar://problem/9161945> silently ignore dependents from main executables that can't be in shared cache
451				bool addDependent = true;
452				if ( fLayout->getFileType() == MH_EXECUTE ) {
453					if ( (strncmp(dependentPath, "/usr/lib/", 9) != 0) && (strncmp(dependentPath, "/System/Library/", 16) != 0) ) {
454						addDependent = false;
455					}
456				}
457				if ( addDependent )
458					fDependsOn.insert(fGraph->getNodeForVirtualPath(dependentPath));
459			}
460			catch (const char* msg) {
461				if ( it->weakImport || ! fLayout->hasSplitSegInfo() ) {
462					// ok to ignore missing weak imported dylibs from things that are
463					// not going to be in the dyld shared cache
464				}
465				else {
466					fprintf(stderr, "warning, could not bind %s because %s\n", fPath, msg);
467					fDependentMissing = true;
468				}
469			}
470		}
471		// recurse
472		for(std::set<DependencyNode*>::iterator it = fDependsOn.begin(); it != fDependsOn.end(); ++it) {
473			(*it)->loadDependencies(mainExecutableLayout);
474		}
475	}
476}
477
478void ArchGraph::DependencyNode::markNeededByRoot(ArchGraph::DependencyNode* rootNode)
479{
480	if ( fRootsDependentOnThis.count(rootNode) == 0 ) {
481		fRootsDependentOnThis.insert(rootNode);
482		for(std::set<DependencyNode*>::iterator it = fDependsOn.begin(); it != fDependsOn.end(); ++it) {
483			(*it)->markNeededByRoot(rootNode);
484		}
485	}
486}
487
488
489ArchGraph::DependencyNode::DependencyNode(ArchGraph* graph, const char* path, const MachOLayoutAbstraction* layout)
490 : fGraph(graph), fPath(strdup(path)), fLayout(layout), fDependenciesLoaded(false), fDependentMissing(false)
491{
492	//fprintf(stderr, "new DependencyNode(0x%08X, %s)\n", graph->fArch, path);
493}
494
495void ArchGraph::findSharedDylibs(ArchPair ap)
496{
497	const PathToNode& nodes = fgPerArchGraph[ap]->fNodes;
498	std::set<const MachOLayoutAbstraction*> possibleLibs;
499	//fprintf(stderr, "shared for arch %s\n", archName(ap));
500	for(PathToNode::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
501		DependencyNode* node = it->second;
502		// <rdar://problem/6127437> put all dylibs in shared cache - not just ones used by more than one app
503		if ( node->allDependentsFound() /*&& (node->useCount() > 1)*/ ) {
504			const MachOLayoutAbstraction* layout = node->getLayout();
505			if ( layout->isDylib() ) {
506				char* msg;
507				if ( sharable(layout, ap, &msg) ) {
508					possibleLibs.insert(layout);
509				}
510				else {
511					if ( layout->getID().name[0] == '@' ) {
512						// <rdar://problem/7770139> update_dyld_shared_cache should suppress warnings for embedded frameworks
513					}
514					else {
515						warnings.push_back(msg);
516						fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
517					}
518				}
519			}
520		}
521	}
522
523	// prune so that all shareable libs depend only on other shareable libs
524	std::set<const MachOLayoutAbstraction*>& sharedLibs = fgPerArchGraph[ap]->fSharedDylibs;
525	std::map<const MachOLayoutAbstraction*,bool> shareableMap;
526	for (std::set<const MachOLayoutAbstraction*>::iterator lit = possibleLibs.begin(); lit != possibleLibs.end(); ++lit) {
527		if ( canBeShared(*lit, ap, possibleLibs, shareableMap) )
528			sharedLibs.insert(*lit);
529	}
530}
531
532const char*	ArchGraph::archName(ArchPair ap)
533{
534	switch ( ap.arch ) {
535		case CPU_TYPE_I386:
536			return "i386";
537		case CPU_TYPE_X86_64:
538			switch ( ap.subtype ) {
539				case CPU_SUBTYPE_X86_64_H:
540					return "x86_64h";
541				default:
542					return "x86_64";
543			}
544		case CPU_TYPE_ARM:
545			switch ( ap.subtype ) {
546				case CPU_SUBTYPE_ARM_V4T:
547					return "armv4t";
548				case CPU_SUBTYPE_ARM_V6:
549					return "armv6";
550				case CPU_SUBTYPE_ARM_V5TEJ:
551					return "armv5";
552				case CPU_SUBTYPE_ARM_XSCALE:
553					return "arm-xscale";
554				case CPU_SUBTYPE_ARM_V7:
555					return "armv7";
556				case CPU_SUBTYPE_ARM_V7F:
557					return "armv7f";
558				case CPU_SUBTYPE_ARM_V7K:
559					return "armv7k";
560				case CPU_SUBTYPE_ARM_V7S:
561					return "armv7s";
562				default:
563					return "arm";
564			}
565		case CPU_TYPE_ARM64:
566			return "arm64";
567		default:
568			return "unknown";
569	}
570}
571
572bool ArchGraph::sharable(const MachOLayoutAbstraction* layout, ArchPair ap, char** msg)
573{
574	if ( ! layout->isTwoLevelNamespace() )
575		asprintf(msg, "can't put %s in shared cache because it was built -flat_namespace", layout->getID().name);
576	else if ( ! layout->inSharableLocation() )
577		asprintf(msg, "can't put %s in shared cache because its -install_name is not in /usr/lib or /System/Library", layout->getID().name);
578	else if ( ! layout->hasSplitSegInfo() )
579		asprintf(msg, "can't put %s in shared cache because it was not built for %s or later", layout->getID().name, (iPhoneOS ? "iPhoneOS 3.1" : "MacOSX 10.5"));
580	else if ( ! layout->isRootOwned() )
581		asprintf(msg, "can't put %s in shared cache because it is not owned by root", layout->getID().name);
582	else if ( layout->hasDynamicLookupLinkage() )
583		asprintf(msg, "can't put %s in shared cache because it was built with '-undefined dynamic_lookup'", layout->getID().name);
584	else if ( layout->hasMainExecutableLookupLinkage() )
585		asprintf(msg, "can't put %s in shared cache because it was built with '-bundle_loader'", layout->getID().name);
586	else if ( layout->hasMultipleReadWriteSegments() )
587		asprintf(msg, "can't put %s in shared cache because it has multiple r/w segments", layout->getID().name);
588	else
589		return true;
590	return false;
591}
592
593bool ArchGraph::canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, const std::set<const MachOLayoutAbstraction*>& possibleLibs, std::map<const MachOLayoutAbstraction*, bool>& shareableMap)
594{
595	// check map which is a cache of results
596	std::map<const MachOLayoutAbstraction*, bool>::iterator mapPos = shareableMap.find(layout);
597	if ( mapPos != shareableMap.end() ) {
598		return mapPos->second;
599	}
600	// see if possible
601	if ( possibleLibs.count(layout) == 0 ) {
602		shareableMap[layout] = false;
603		char* msg;
604		if ( sharable(layout, ap, &msg) )
605			asprintf(&msg, "can't put %s in shared cache, unknown reason", layout->getID().name);
606		warnings.push_back(msg);
607		if ( verbose )
608			fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
609		return false;
610	}
611	// look recursively
612	shareableMap[layout] = true; // mark this shareable early in case of circular references
613	const PathToNode& nodes = fgPerArchGraph[ap]->fNodes;
614	const std::vector<MachOLayoutAbstraction::Library>&	dependents = layout->getLibraries();
615	for (std::vector<MachOLayoutAbstraction::Library>::const_iterator dit = dependents.begin(); dit != dependents.end(); ++dit) {
616		PathToNode::const_iterator pos = nodes.find(dit->name);
617		if ( pos == nodes.end() ) {
618			// path from load command does not match any loaded dylibs, maybe there is a temp symlink
619			char realPath[MAXPATHLEN];
620			if ( realpath(dit->name, realPath) != NULL ) {
621				if ( nodes.find(realPath) != nodes.end() )
622					continue;
623			}
624			// handle weak imported dylibs not found
625			if ( dit->weakImport )
626				continue;
627			shareableMap[layout] = false;
628			char* msg;
629			asprintf(&msg, "can't put %s in shared cache because it depends on %s which can't be found", layout->getID().name, dit->name);
630			warnings.push_back(msg);
631			if ( verbose )
632				fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
633			return false;
634		}
635		else {
636			if ( ! canBeShared(pos->second->getLayout(), ap, possibleLibs, shareableMap) ) {
637				shareableMap[layout] = false;
638				char* msg;
639				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);
640				warnings.push_back(msg);
641				if ( verbose )
642					fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
643				return false;
644			}
645		}
646	}
647	return true;
648}
649
650
651
652class StringPool
653{
654public:
655				StringPool();
656	const char*	getBuffer();
657	uint32_t	size();
658	uint32_t	add(const char* str);
659	uint32_t	addUnique(const char* str);
660	const char* stringAtIndex(uint32_t) const;
661
662private:
663	typedef std::unordered_map<const char*, uint32_t, CStringHash, CStringEquals> StringToOffset;
664
665	char*			fBuffer;
666	uint32_t		fBufferAllocated;
667	uint32_t		fBufferUsed;
668	StringToOffset	fUniqueStrings;
669};
670
671
672StringPool::StringPool()
673	: fBufferUsed(0), fBufferAllocated(64*1024*1024)
674{
675	fBuffer = (char*)malloc(fBufferAllocated);
676}
677
678uint32_t StringPool::add(const char* str)
679{
680	uint32_t len = strlen(str);
681	if ( (fBufferUsed + len + 1) > fBufferAllocated ) {
682		// grow buffer
683		throw "string buffer exhausted";
684	}
685	strcpy(&fBuffer[fBufferUsed], str);
686	uint32_t result = fBufferUsed;
687	fUniqueStrings[&fBuffer[fBufferUsed]] = result;
688	fBufferUsed += len+1;
689	return result;
690}
691
692uint32_t StringPool::addUnique(const char* str)
693{
694	StringToOffset::iterator pos = fUniqueStrings.find(str);
695	if ( pos != fUniqueStrings.end() )
696		return pos->second;
697	else {
698		//fprintf(stderr, "StringPool::addUnique() new string: %s\n", str);
699		return this->add(str);
700	}
701}
702
703uint32_t StringPool::size()
704{
705	return fBufferUsed;
706}
707
708const char*	StringPool::getBuffer()
709{
710	return fBuffer;
711}
712
713const char* StringPool::stringAtIndex(uint32_t index) const
714{
715	return &fBuffer[index];
716}
717
718
719
720struct LocalSymbolInfo
721{
722	uint32_t	dylibOffset;
723	uint32_t	nlistStartIndex;
724	uint32_t	nlistCount;
725};
726
727
728template <typename A>
729class SharedCache
730{
731public:
732							SharedCache(ArchGraph* graph, const char* rootPath, const std::vector<const char*>& overlayPaths, const char* cacheDir, bool explicitCacheDir,
733											bool alphaSort, bool verify, bool optimize, uint64_t dyldBaseAddress);
734	bool					update(bool force, bool optimize, bool deleteExistingFirst, int archIndex,
735										int archCount, bool keepSignatures, bool dontMapLocalSymbols);
736	static const char*		cacheFileSuffix(bool optimized, const char* archName);
737
738    // vm address = address AS WRITTEN into the cache
739    // mapped address = address AS MAPPED into the update process only
740    // file offset = offset relative to start of cache file
741    void *					mappedAddressForVMAddress(uint64_t vmaddr);
742    uint64_t 				VMAddressForMappedAddress(const void *mapaddr);
743	uint64_t				cacheFileOffsetForVMAddress(uint64_t addr) const;
744	uint64_t				VMAddressForCacheFileOffset(uint64_t addr) const;
745
746	static const char*		archName();
747
748private:
749	typedef typename A::P			P;
750    typedef typename A::P::E		E;
751    typedef typename A::P::uint_t	pint_t;
752
753	bool					notUpToDate(const char* path, unsigned int aliasCount);
754	bool					notUpToDate(const void* cache, unsigned int aliasCount);
755	uint8_t*				optimizeLINKEDIT(bool keepSignatures, bool dontMapLocalSymbols);
756	void					optimizeObjC(std::vector<void*>& pointersInData);
757
758	static void				getSharedCacheBasAddresses(cpu_type_t arch, uint64_t* baseReadOnly, uint64_t* baseWritable);
759	static cpu_type_t		arch();
760	static uint64_t			sharedRegionStartAddress();
761	static uint64_t			sharedRegionSize();
762	static uint64_t			sharedRegionStartWritableAddress(uint64_t);
763	static uint64_t			sharedRegionStartReadOnlyAddress(uint64_t, uint64_t);
764	static uint64_t			getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide);
765	static bool				addCacheSlideInfo();
766	static uint64_t			pathHash(const char*);
767
768	static uint64_t			pageAlign(uint64_t addr);
769	static uint64_t			regionAlign(uint64_t addr);
770	static uint64_t			pageAlign4KB(uint64_t addr);
771	void					assignNewBaseAddresses(bool verify);
772
773	struct LayoutInfo {
774		const MachOLayoutAbstraction*		layout;
775		std::vector<const char*>			aliases;
776		dyld_cache_image_info				info;
777	};
778
779	struct ByNameSorter {
780		bool operator()(const LayoutInfo& left, const LayoutInfo& right)
781				{ return (strcmp(left.layout->getID().name, right.layout->getID().name) < 0); }
782	};
783
784	struct ByAddressSorter {
785		bool operator()(const LayoutInfo& left, const LayoutInfo& right) {
786			return (left.layout->getSegments()[0].newAddress() < right.layout->getSegments()[0].newAddress());
787		}
788	};
789
790    struct ByCStringSectionSizeSorter {
791        bool operator()(const LayoutInfo& left, const LayoutInfo& right) {
792            const std::vector<MachOLayoutAbstraction::Segment>& segs_l =
793                left.layout->getSegments();
794            const std::vector<MachOLayoutAbstraction::Segment>& segs_r =
795                right.layout->getSegments();
796            if (segs_l.size() == 0  ||  segs_r.size() == 0) {
797                // one image has no segments
798                return segs_l.size() > segs_r.size();
799            }
800            const macho_header<P> *mh_l = (macho_header<P>*)segs_l[0].mappedAddress();
801            const macho_header<P> *mh_r = (macho_header<P>*)segs_r[0].mappedAddress();
802            const macho_section<P> *cstring_l = mh_l->getSection("__TEXT", "__cstring");
803            const macho_section<P> *cstring_r = mh_r->getSection("__TEXT", "__cstring");
804            if (!cstring_l  ||  !cstring_r) {
805                // one image has no cstrings
806                return cstring_l && !cstring_r;
807            }
808
809            return cstring_l->size() > cstring_r->size();
810        }
811    };
812
813	struct Sorter {
814		Sorter(std::map<const MachOLayoutAbstraction*, uint32_t>& map): fMap(map) {}
815		bool operator()(const LayoutInfo& left, const LayoutInfo& right) {
816			return (fMap[left.layout] < fMap[right.layout]);
817		}
818	private:
819		std::map<const MachOLayoutAbstraction*, uint32_t>& fMap;
820	};
821
822
823	ArchGraph*							fArchGraph;
824	const bool							fVerify;
825	bool								fExistingIsNotUpToDate;
826	bool								fCacheFileInFinalLocation;
827	const char*							fCacheFilePath;
828	uint8_t*							fExistingCacheForVerification;
829	std::vector<LayoutInfo>				fDylibs;
830	std::vector<LayoutInfo>				fDylibAliases;
831	std::vector<shared_file_mapping_np>	fMappings;
832	std::vector<macho_nlist<P> >		fUnmappedLocalSymbols;
833	StringPool							fUnmappedLocalsStringPool;
834	std::vector<LocalSymbolInfo>		fLocalSymbolInfos;
835	uint32_t							fHeaderSize;
836    uint8_t*							fInMemoryCache;
837	uint64_t							fDyldBaseAddress;
838	uint64_t							fLinkEditsTotalUnoptimizedSize;
839	uint64_t							fLinkEditsStartAddress;
840	MachOLayoutAbstraction::Segment*	fFirstLinkEditSegment;
841	uint32_t							fOffsetOfBindInfoInCombinedLinkedit;
842	uint32_t							fOffsetOfWeakBindInfoInCombinedLinkedit;
843	uint32_t							fOffsetOfLazyBindInfoInCombinedLinkedit;
844	uint32_t							fOffsetOfExportInfoInCombinedLinkedit;
845	uint32_t							fOffsetOfOldSymbolTableInfoInCombinedLinkedit;
846	uint32_t							fSizeOfOldSymbolTableInfoInCombinedLinkedit;
847	uint32_t							fOffsetOfOldExternalRelocationsInCombinedLinkedit;
848	uint32_t							fSizeOfOldExternalRelocationsInCombinedLinkedit;
849	uint32_t							fOffsetOfOldIndirectSymbolsInCombinedLinkedit;
850	uint32_t							fSizeOfOldIndirectSymbolsInCombinedLinkedit;
851	uint32_t							fOffsetOfOldStringPoolInCombinedLinkedit;
852	uint32_t							fSizeOfOldStringPoolInCombinedLinkedit;
853	uint32_t							fOffsetOfFunctionStartsInCombinedLinkedit;
854	uint32_t							fSizeOfFunctionStartsInCombinedLinkedit;
855	uint32_t							fOffsetOfDataInCodeInCombinedLinkedit;
856	uint32_t							fSizeOfDataInCodeInCombinedLinkedit;
857	uint32_t							fLinkEditsTotalOptimizedSize;
858	uint32_t							fUnmappedLocalSymbolsSize;
859};
860
861
862// Access a section containing a list of pointers
863template <typename A, typename T>
864class PointerSection
865{
866    typedef typename A::P P;
867    typedef typename A::P::uint_t pint_t;
868
869    SharedCache<A>* const			fCache;
870    const macho_section<P>* const	fSection;
871    pint_t * const					fBase;
872    uint64_t						fCount;
873
874public:
875    PointerSection(SharedCache<A>* cache, const macho_header<P>* header,
876                   const char *segname, const char *sectname)
877        : fCache(cache)
878        , fSection(header->getSection(segname, sectname))
879        , fBase(fSection ? (pint_t *)cache->mappedAddressForVMAddress(fSection->addr()) : 0)
880        , fCount(fSection ? fSection->size() / sizeof(pint_t) : 0)
881    {
882    }
883
884    uint64_t count() const { return fCount; }
885
886    uint64_t getUnmapped(uint64_t index) const {
887        if (index >= fCount) throwf("index out of range");
888        return P::getP(fBase[index]);
889    }
890
891    T get(uint64_t index) const {
892        return (T)fCache->mappedAddressForVMAddress(getUnmapped(index));
893    }
894
895    void set(uint64_t index, uint64_t value) {
896        if (index >= fCount) throwf("index out of range");
897        P::setP(fBase[index], value);
898    }
899
900    void removeNulls() {
901        uint64_t shift = 0;
902        for (uint64_t i = 0; i < fCount; i++) {
903            pint_t value = fBase[i];
904            if (value) {
905                fBase[i-shift] = value;
906            } else {
907                shift++;
908            }
909        }
910        fCount -= shift;
911		const_cast<macho_section<P>*>(fSection)->set_size(fCount * sizeof(pint_t));
912    }
913};
914
915// Access a section containing an array of structures
916template <typename A, typename T>
917class ArraySection
918{
919    typedef typename A::P P;
920
921    SharedCache<A>* const fCache;
922    const macho_section<P>* const fSection;
923    T * const fBase;
924    uint64_t const fCount;
925
926public:
927    ArraySection(SharedCache<A>* cache, const macho_header<P>* header,
928                 const char *segname, const char *sectname)
929        : fCache(cache)
930        , fSection(header->getSection(segname, sectname))
931        , fBase(fSection ? (T *)cache->mappedAddressForVMAddress(fSection->addr()) : 0)
932        , fCount(fSection ? fSection->size() / sizeof(T) : 0)
933    {
934    }
935
936    uint64_t count() const { return fCount; }
937
938    T& get(uint64_t index) const {
939        if (index >= fCount) throwf("index out of range");
940        return fBase[index];
941    }
942};
943
944
945// GrP fixme
946#include "ObjCLegacyAbstraction.hpp"
947#include "ObjCModernAbstraction.hpp"
948
949
950
951template <>	 cpu_type_t	SharedCache<x86>::arch()	{ return CPU_TYPE_I386; }
952template <>	 cpu_type_t	SharedCache<x86_64>::arch()	{ return CPU_TYPE_X86_64; }
953template <>	 cpu_type_t	SharedCache<arm>::arch()	{ return CPU_TYPE_ARM; }
954template <>	 cpu_type_t	SharedCache<arm64>::arch()	{ return CPU_TYPE_ARM64; }
955
956template <>	 uint64_t	SharedCache<x86>::sharedRegionStartAddress()			{ return 0x90000000; }
957template <>	 uint64_t	SharedCache<x86_64>::sharedRegionStartAddress()			{ return 0x7FFF80000000LL; }
958template <>	 uint64_t	SharedCache<arm>::sharedRegionStartAddress()			{ return ARM_SHARED_REGION_START; }
959template <>	 uint64_t	SharedCache<arm64>::sharedRegionStartAddress()			{ return ARM64_SHARED_REGION_START; }
960
961template <>	 uint64_t	SharedCache<x86>::sharedRegionSize()					{ return 0x20000000; }
962template <>	 uint64_t	SharedCache<x86_64>::sharedRegionSize()					{ return 0x40000000; }
963template <>	 uint64_t	SharedCache<arm>::sharedRegionSize()					{ return ARM_SHARED_REGION_SIZE; }
964template <>	 uint64_t	SharedCache<arm64>::sharedRegionSize()					{ return ARM64_SHARED_REGION_SIZE; }
965
966template <>	 uint64_t	SharedCache<x86>::sharedRegionStartWritableAddress(uint64_t exEnd)			{ return exEnd + 0x04000000; }
967template <>	 uint64_t	SharedCache<x86_64>::sharedRegionStartWritableAddress(uint64_t exEnd)		{ return 0x7FFF70000000LL; }
968template <>	 uint64_t	SharedCache<arm>::sharedRegionStartWritableAddress(uint64_t exEnd)			{ return (exEnd + 16383) & (-16384); }
969template <>	 uint64_t	SharedCache<arm64>::sharedRegionStartWritableAddress(uint64_t exEnd)		{ return exEnd; }
970
971template <>	 uint64_t	SharedCache<x86>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd, uint64_t exEnd)	 { return wrEnd + 0x04000000; }
972template <>	 uint64_t	SharedCache<x86_64>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd, uint64_t exEnd){ return exEnd; }
973template <>	 uint64_t	SharedCache<arm>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd, uint64_t exEnd)	 { return (wrEnd + 16383) & (-16384); }
974template <>	 uint64_t	SharedCache<arm64>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd, uint64_t exEnd) { return (wrEnd + 16383) & (-16384); }
975
976template <>	 const char*	SharedCache<x86>::archName()	{ return "i386"; }
977template <>	 const char*	SharedCache<x86_64>::archName()	{ return "x86_64"; }
978template <>	 const char*	SharedCache<arm>::archName()	{ return "arm"; }
979template <>	 const char*	SharedCache<arm64>::archName()	{ return "arm64"; }
980
981template <>	 const char*	SharedCache<x86>::cacheFileSuffix(bool, const char* archName)	{ return archName; }
982template <>	 const char*	SharedCache<x86_64>::cacheFileSuffix(bool, const char* archName){ return archName; }
983template <>	 const char*	SharedCache<arm>::cacheFileSuffix(bool, const char* archName)	{ return archName; }
984template <>	 const char*	SharedCache<arm64>::cacheFileSuffix(bool, const char* archName)	{ return archName; }
985
986template <>  uint64_t		SharedCache<x86>::pageAlign(uint64_t addr)    { return ( (addr + 4095) & (-4096) ); }
987template <>  uint64_t		SharedCache<x86_64>::pageAlign(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
988template <>  uint64_t		SharedCache<arm>::pageAlign(uint64_t addr)    { return ( (addr + 4095) & (-4096) ); }
989template <>  uint64_t		SharedCache<arm64>::pageAlign(uint64_t addr)  { return ( (addr + 16383) & (-16384) ); }
990
991template <>  uint64_t		SharedCache<x86>::regionAlign(uint64_t addr)    { return ( (addr + 4095) & (-4096) ); }
992template <>  uint64_t		SharedCache<x86_64>::regionAlign(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
993template <>  uint64_t		SharedCache<arm>::regionAlign(uint64_t addr)    { return ( (addr + 16383) & (-16384) ); }
994template <>  uint64_t		SharedCache<arm64>::regionAlign(uint64_t addr)  { return ( (addr + 16383) & (-16384) ); }
995
996
997template <typename A>
998uint64_t SharedCache<A>::pageAlign4KB(uint64_t addr)    { return ( (addr + 4095) & (-4096) ); }
999
1000template <typename A>
1001SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const std::vector<const char*>& overlayPaths, const char* cacheDir, bool explicitCacheDir, bool alphaSort, bool verify, bool optimize, uint64_t dyldBaseAddress)
1002  : fArchGraph(graph), fVerify(verify), fExistingIsNotUpToDate(true),
1003	fCacheFileInFinalLocation(rootPath[0] == '\0'), fCacheFilePath(NULL),
1004	fExistingCacheForVerification(NULL), fDyldBaseAddress(dyldBaseAddress),
1005	fOffsetOfBindInfoInCombinedLinkedit(0), fOffsetOfWeakBindInfoInCombinedLinkedit(0),
1006	fOffsetOfLazyBindInfoInCombinedLinkedit(0), fOffsetOfExportInfoInCombinedLinkedit(0),
1007	fOffsetOfOldSymbolTableInfoInCombinedLinkedit(0), fSizeOfOldSymbolTableInfoInCombinedLinkedit(0),
1008	fOffsetOfOldExternalRelocationsInCombinedLinkedit(0), fSizeOfOldExternalRelocationsInCombinedLinkedit(0),
1009	fOffsetOfOldIndirectSymbolsInCombinedLinkedit(0), fSizeOfOldIndirectSymbolsInCombinedLinkedit(0),
1010	fOffsetOfOldStringPoolInCombinedLinkedit(0), fSizeOfOldStringPoolInCombinedLinkedit(0),
1011	fOffsetOfFunctionStartsInCombinedLinkedit(0), fSizeOfFunctionStartsInCombinedLinkedit(0),
1012	fOffsetOfDataInCodeInCombinedLinkedit(0), fSizeOfDataInCodeInCombinedLinkedit(0),
1013	fUnmappedLocalSymbolsSize(0)
1014{
1015	if ( fArchGraph->getArchPair().arch != arch() )
1016		throwf("SharedCache object is wrong architecture: 0x%08X vs 0x%08X", fArchGraph->getArchPair().arch, arch());
1017
1018	// build vector of all shared dylibs
1019	unsigned int aliasCount = 0;
1020	std::set<const MachOLayoutAbstraction*>& dylibs = fArchGraph->getSharedDylibs();
1021	ArchGraph::StringToString& aliases = fArchGraph->getDylibAliases();
1022	for(std::set<const MachOLayoutAbstraction*>::iterator it = dylibs.begin(); it != dylibs.end(); ++it) {
1023		const MachOLayoutAbstraction* lib = *it;
1024		LayoutInfo temp;
1025		temp.layout = lib;
1026		temp.info.address = 0;
1027		temp.info.inode = lib->getInode();
1028		temp.info.modTime = lib->getLastModTime();
1029		if ( iPhoneOS ) {
1030			temp.info.inode = pathHash(lib->getID().name);
1031			temp.info.modTime = 0;
1032		}
1033		temp.info.pathFileOffset = lib->getNameFileOffset();  // for now this is the offset within the dylib
1034		for(ArchGraph::StringToString::iterator ait = aliases.begin(); ait != aliases.end(); ++ait) {
1035			if ( strcmp(ait->second, lib->getID().name) == 0 ) {
1036				temp.aliases.push_back(ait->first);
1037				++aliasCount;
1038			}
1039		}
1040		fDylibs.push_back(temp);
1041	}
1042
1043	// create path to cache file
1044	char cachePathCanonical[MAXPATHLEN];
1045	strcpy(cachePathCanonical, cacheDir);
1046	if ( cachePathCanonical[strlen(cachePathCanonical)-1] != '/' )
1047		strcat(cachePathCanonical, "/");
1048	strcat(cachePathCanonical, DYLD_SHARED_CACHE_BASE_NAME);
1049	strcat(cachePathCanonical, cacheFileSuffix(optimize, fArchGraph->archName()));
1050	char cachePath[MAXPATHLEN];
1051	if ( explicitCacheDir ) {
1052		fCacheFilePath = strdup(cachePathCanonical);
1053	}
1054	else if ( overlayPaths.size() == 1 ) {
1055		// if no -cache_dir and exactly on -overlay, write cache file into that overlay dir
1056		strcpy(cachePath, overlayPaths[0]);
1057		strcat(cachePath, "/");
1058		strcat(cachePath, cachePathCanonical);
1059		fCacheFilePath = strdup(cachePath);
1060	}
1061	else if ( rootPath[0] != '\0' ) {
1062		strcpy(cachePath, rootPath);
1063		strcat(cachePath, "/");
1064		strcat(cachePath, cachePathCanonical);
1065		fCacheFilePath = strdup(cachePath);
1066	}
1067	else {
1068		fCacheFilePath = strdup(cachePathCanonical);
1069	}
1070	if ( overlayPaths.size() == 1 ) {
1071		// in overlay mode if there already is a cache file in the overlay,
1072		// check if it is up to date.
1073		struct stat stat_buf;
1074		if ( stat(fCacheFilePath, &stat_buf) == 0 ) {
1075			fExistingIsNotUpToDate = this->notUpToDate(fCacheFilePath, aliasCount);
1076		}
1077		else if ( rootPath[0] != '\0' ) {
1078			// using -root and -overlay, but no cache file in overlay, check one in -root
1079			char cachePathRoot[MAXPATHLEN];
1080			strcpy(cachePathRoot, rootPath);
1081			strcat(cachePathRoot, "/");
1082			strcat(cachePathRoot, cachePathCanonical);
1083			fExistingIsNotUpToDate = this->notUpToDate(cachePathRoot, aliasCount);
1084		}
1085		else {
1086			// uisng -overlay, but no cache file in overlay, check one in boot volume
1087			fExistingIsNotUpToDate = this->notUpToDate(cachePathCanonical, aliasCount);
1088		}
1089	}
1090	else {
1091		fExistingIsNotUpToDate = this->notUpToDate(fCacheFilePath, aliasCount);
1092	}
1093
1094	// sort shared dylibs
1095	if ( verify ) {
1096		// already sorted by notUpToDate()
1097	}
1098	else if ( alphaSort ) {
1099		std::sort(fDylibs.begin(), fDylibs.end(), ByNameSorter());
1100	}
1101	else {
1102		// random sort for Address Space Randomization
1103		std::map<const MachOLayoutAbstraction*, uint32_t> map;
1104		for(typename std::vector<struct LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it)
1105			map[it->layout] = arc4random();
1106		std::sort(fDylibs.begin(), fDylibs.end(), Sorter(map));
1107	}
1108
1109	// assign segments in each dylib a new address
1110	this->assignNewBaseAddresses(verify);
1111
1112	// calculate where string pool offset will start
1113	// calculate cache file header size
1114	fHeaderSize = sizeof(dyld_cache_header)
1115							+ fMappings.size()*sizeof(shared_file_mapping_np)
1116							+ (fDylibs.size()+aliasCount)*sizeof(dyld_cache_image_info);
1117	const uint64_t baseHeaderSize = fHeaderSize;
1118	//fprintf(stderr, "aliasCount=%d, fHeaderSize=0x%08X\n", aliasCount, fHeaderSize);
1119	// build list of aliases and compute where each ones path string will go
1120	for(typename std::vector<struct LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1121		for(std::vector<const char*>::const_iterator ait = it->aliases.begin(); ait != it->aliases.end(); ++ait) {
1122			LayoutInfo temp = *it;
1123			// alias looks just like real dylib, but has a different name string
1124			const char* aliasPath = *ait;
1125			temp.aliases.clear();
1126			temp.aliases.push_back(aliasPath);
1127			temp.info.pathFileOffset = fHeaderSize;
1128			if ( iPhoneOS ) {
1129				temp.info.inode = pathHash(aliasPath);
1130				temp.info.modTime = 0;
1131			}
1132			fDylibAliases.push_back(temp);
1133			fHeaderSize += strlen(aliasPath)+1;
1134		}
1135	}
1136	std::sort(fDylibAliases.begin(), fDylibAliases.end(), ByNameSorter());
1137	//fprintf(stderr, "fHeaderSize=0x%08X, fDylibAliases.size()=%lu\n", fHeaderSize, fDylibAliases.size());
1138	fHeaderSize = pageAlign(fHeaderSize);
1139
1140	// check that cache we are about to create for verification purposes has same layout as existing cache
1141	if ( verify ) {
1142		// if no existing cache, say so
1143		if ( fExistingCacheForVerification == NULL ) {
1144			throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
1145			 getpid(), fArchGraph->archName());
1146		}
1147		const dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)fExistingCacheForVerification;
1148		const dyldCacheImageInfo<E>* cacheEntry = (dyldCacheImageInfo<E>*)(fExistingCacheForVerification + header->imagesOffset());
1149		for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it, ++cacheEntry) {
1150			if ( cacheEntry->address() != it->layout->getSegments()[0].newAddress() ) {
1151				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",
1152							getpid(), fArchGraph->archName(), it->layout->getID().name, cacheEntry->address(), it->layout->getSegments()[0].newAddress());
1153			}
1154		}
1155	}
1156
1157
1158	if ( fHeaderSize > FIRST_DYLIB_TEXT_OFFSET )
1159		throwf("header size overflow: allowed=0x%08X, base=0x%08llX, aliases=0x%08llX", FIRST_DYLIB_TEXT_OFFSET, baseHeaderSize, fHeaderSize-baseHeaderSize);
1160}
1161
1162
1163template <typename A>
1164uint64_t SharedCache<A>::getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide)
1165{
1166	return proposedNewAddress;
1167}
1168
1169template <typename A>
1170uint64_t SharedCache<A>::pathHash(const char* path)
1171{
1172	uint64_t sum = 0;
1173	for (const char* s=path; *s != '\0'; ++s)
1174		sum += sum*4 + *s;
1175	return sum;
1176}
1177
1178
1179template <typename A>
1180void SharedCache<A>::assignNewBaseAddresses(bool verify)
1181{
1182	// first layout TEXT for dylibs
1183	const uint64_t startExecuteAddress = sharedRegionStartAddress();
1184	uint64_t currentExecuteAddress = startExecuteAddress + FIRST_DYLIB_TEXT_OFFSET;
1185	for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1186		std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
1187		for (int i=0; i < segs.size(); ++i) {
1188			MachOLayoutAbstraction::Segment& seg = segs[i];
1189			seg.reset();
1190			if ( seg.executable() && !seg.writable() ) {
1191				// <rdar://problem/15947734> Some dylib require extra alignment
1192				currentExecuteAddress = (currentExecuteAddress + seg.alignment() - 1) & (-seg.alignment());
1193				// __TEXT segment
1194				if ( it->info.address == 0 )
1195					it->info.address = currentExecuteAddress;
1196				seg.setNewAddress(currentExecuteAddress);
1197				currentExecuteAddress += pageAlign(seg.size());
1198			}
1199		}
1200	}
1201	// align __TEXT region
1202	currentExecuteAddress = regionAlign(currentExecuteAddress);
1203
1204	// layout DATA for dylibs
1205	const uint64_t startWritableAddress = sharedRegionStartWritableAddress(currentExecuteAddress);
1206	uint64_t currentWritableAddress = startWritableAddress;
1207	for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1208		std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
1209		for (int i=0; i < segs.size(); ++i) {
1210			MachOLayoutAbstraction::Segment& seg = segs[i];
1211			seg.reset();
1212			if ( seg.writable() ) {
1213				if ( seg.executable() )
1214					throw "found writable and executable segment";
1215				// __DATA segment
1216				seg.setNewAddress(currentWritableAddress);
1217				// <rdar://problem/13089366> always 4KB align data pages to allow padding to be removed
1218				currentWritableAddress = pageAlign4KB(seg.newAddress() + seg.size());
1219			}
1220		}
1221	}
1222	// align __DATA region
1223	currentWritableAddress = regionAlign(currentWritableAddress);
1224
1225	// layout all read-only (but not LINKEDIT) segments
1226	const uint64_t startReadOnlyAddress = sharedRegionStartReadOnlyAddress(currentWritableAddress, currentExecuteAddress);
1227	uint64_t currentReadOnlyAddress = startReadOnlyAddress;
1228	for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1229		std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
1230		for(int i=0; i < segs.size(); ++i) {
1231			MachOLayoutAbstraction::Segment& seg = segs[i];
1232			if ( seg.readable() && !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") != 0) ) {
1233				// __UNICODE segment
1234				seg.setNewAddress(currentReadOnlyAddress);
1235				currentReadOnlyAddress += pageAlign(seg.size());
1236			}
1237		}
1238	}
1239
1240	// layout all LINKEDIT segments at end of all read-only segments
1241	currentReadOnlyAddress = regionAlign(currentReadOnlyAddress); // <rdar://problem/16491435>
1242	fLinkEditsStartAddress = currentReadOnlyAddress;
1243	fFirstLinkEditSegment = NULL;
1244	for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1245		std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
1246		for(int i=0; i < segs.size(); ++i) {
1247			MachOLayoutAbstraction::Segment& seg = segs[i];
1248			if ( seg.readable() && !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") == 0) ) {
1249				if ( fFirstLinkEditSegment == NULL )
1250					fFirstLinkEditSegment = &seg;
1251				seg.setNewAddress(currentReadOnlyAddress);
1252				currentReadOnlyAddress += pageAlign(seg.size());
1253			}
1254		}
1255	}
1256	fLinkEditsTotalUnoptimizedSize = pageAlign(currentReadOnlyAddress - fLinkEditsStartAddress);
1257
1258	// populate large mappings
1259	uint64_t cacheFileOffset = 0;
1260	if ( currentExecuteAddress > startExecuteAddress ) {
1261		shared_file_mapping_np  executeMapping;
1262		executeMapping.sfm_address		= startExecuteAddress;
1263		executeMapping.sfm_size			= currentExecuteAddress - startExecuteAddress;
1264		executeMapping.sfm_file_offset	= cacheFileOffset;
1265		executeMapping.sfm_max_prot		= VM_PROT_READ | VM_PROT_EXECUTE;
1266		executeMapping.sfm_init_prot	= VM_PROT_READ | VM_PROT_EXECUTE;
1267		fMappings.push_back(executeMapping);
1268		cacheFileOffset += executeMapping.sfm_size;
1269
1270		shared_file_mapping_np  writableMapping;
1271		writableMapping.sfm_address		= startWritableAddress;
1272		writableMapping.sfm_size		= currentWritableAddress - startWritableAddress;
1273		writableMapping.sfm_file_offset	= cacheFileOffset;
1274		writableMapping.sfm_max_prot	= VM_PROT_READ | VM_PROT_WRITE;
1275		writableMapping.sfm_init_prot	= VM_PROT_READ | VM_PROT_WRITE;
1276		fMappings.push_back(writableMapping);
1277		cacheFileOffset += writableMapping.sfm_size;
1278
1279		// make read-only (contains LINKEDIT segments) last, so it can be cut back when optimized
1280		shared_file_mapping_np  readOnlyMapping;
1281		readOnlyMapping.sfm_address		= startReadOnlyAddress;
1282		readOnlyMapping.sfm_size		= currentReadOnlyAddress - startReadOnlyAddress;
1283		readOnlyMapping.sfm_file_offset	= cacheFileOffset;
1284		readOnlyMapping.sfm_max_prot	= VM_PROT_READ;
1285		readOnlyMapping.sfm_init_prot	= VM_PROT_READ;
1286		fMappings.push_back(readOnlyMapping);
1287		cacheFileOffset += readOnlyMapping.sfm_size;
1288	}
1289	else {
1290		// empty cache
1291		shared_file_mapping_np  cacheHeaderMapping;
1292		cacheHeaderMapping.sfm_address		= startExecuteAddress;
1293		cacheHeaderMapping.sfm_size			= FIRST_DYLIB_TEXT_OFFSET;
1294		cacheHeaderMapping.sfm_file_offset	= cacheFileOffset;
1295		cacheHeaderMapping.sfm_max_prot		= VM_PROT_READ;
1296		cacheHeaderMapping.sfm_init_prot	= VM_PROT_READ;
1297		fMappings.push_back(cacheHeaderMapping);
1298		cacheFileOffset += cacheHeaderMapping.sfm_size;
1299	}
1300}
1301
1302
1303template <typename A>
1304uint64_t SharedCache<A>::cacheFileOffsetForVMAddress(uint64_t vmaddr) const
1305{
1306	for(std::vector<shared_file_mapping_np>::const_iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
1307		if ( (it->sfm_address <= vmaddr) && (vmaddr < it->sfm_address+it->sfm_size) )
1308			return it->sfm_file_offset + vmaddr - it->sfm_address;
1309	}
1310	throwf("address 0x%0llX is not in cache", vmaddr);
1311}
1312
1313template <typename A>
1314uint64_t SharedCache<A>::VMAddressForCacheFileOffset(uint64_t offset) const
1315{
1316    for(std::vector<shared_file_mapping_np>::const_iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
1317        if ( (it->sfm_file_offset <= offset) && (offset < it->sfm_file_offset+it->sfm_size) )
1318            return it->sfm_address + offset - it->sfm_file_offset;
1319    }
1320    throwf("offset 0x%0llX is not in cache", offset);
1321}
1322
1323template <typename A>
1324void *SharedCache<A>::mappedAddressForVMAddress(uint64_t vmaddr)
1325{
1326    if (!vmaddr) return NULL;
1327    else return fInMemoryCache + cacheFileOffsetForVMAddress(vmaddr);
1328}
1329
1330template <typename A>
1331uint64_t SharedCache<A>::VMAddressForMappedAddress(const void *mapaddr)
1332{
1333    if (!mapaddr) return 0;
1334    uint64_t offset = (uint8_t *)mapaddr - (uint8_t *)fInMemoryCache;
1335    return VMAddressForCacheFileOffset(offset);
1336}
1337
1338
1339template <typename A>
1340bool SharedCache<A>::notUpToDate(const void* cache, unsigned int aliasCount)
1341{
1342	dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
1343	// not valid if header signature is wrong
1344	const char* archPairName = fArchGraph->archName();
1345	char temp[16];
1346	strcpy(temp, "dyld_v1        ");
1347	strcpy(&temp[15-strlen(archPairName)], archPairName);
1348	if ( strcmp(header->magic(), temp) != 0 ) {
1349		if ( fVerify ) {
1350			fprintf(stderr, "update_dyld_shared_cache[%u] cannot verify %s because current cache file has invalid header\n", getpid(), archPairName);
1351			return false;
1352		}
1353		else {
1354			fprintf(stderr, "update_dyld_shared_cache[%u] updating cache because current cache file has invalid header\n", getpid());
1355			return true;
1356		}
1357	}
1358	// not valid if count of images does not match current images needed
1359	if ( header->imagesCount() != (fDylibs.size()+aliasCount) ) {
1360		if ( fVerify ) {
1361			fprintf(stderr, "update_dyld_shared_cache[%u] cannot verify %s because current cache file contains a different set of dylibs\n", getpid(), archPairName);
1362			return false;
1363		}
1364		else {
1365			fprintf(stderr, "update_dyld_shared_cache[%u] updating %s cache because current cache file contains a different set of dylibs\n", getpid(), archPairName);
1366			return true;
1367		}
1368	}
1369	// get end of TEXT region
1370	const dyldCacheFileMapping<E>* textMapping = (dyldCacheFileMapping<E>*)((uint8_t*)cache+sizeof(dyldCacheHeader<E>));
1371	const uint32_t textSize = textMapping->size();
1372
1373	// verify every dylib in constructed graph is in existing cache with same inode and modTime
1374	std::map<const MachOLayoutAbstraction*, uint32_t> sortingMap;
1375	const dyldCacheImageInfo<E>* imagesStart = (dyldCacheImageInfo<E>*)((uint8_t*)cache + header->imagesOffset());
1376	const dyldCacheImageInfo<E>* imagesEnd = &imagesStart[header->imagesCount()];
1377	for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1378		bool found = false;
1379		//fprintf(stderr, "inode=0x%llX, mTime=0x%llX, path=%s\n", it->info.inode, it->info.modTime, it->layout->getID().name);
1380		for(const dyldCacheImageInfo<E>* cacheEntry = imagesStart; cacheEntry < imagesEnd; ++cacheEntry) {
1381			if ( fVerify ) {
1382				if ( cacheEntry->pathFileOffset() > textSize ) {
1383					throwf("update_dyld_shared_cache[%u]: for arch=%s, image entries corrupt, bad path offset in %s\n",
1384								getpid(), archPairName, it->layout->getID().name);
1385				}
1386				// in -verify mode, just match by path and warn if file looks different
1387				if ( strcmp((char*)cache+cacheEntry->pathFileOffset(), it->layout->getID().name) == 0 ) {
1388					found = true;
1389					sortingMap[it->layout] = cacheEntry-imagesStart;
1390					if ( (cacheEntry->inode() != it->info.inode) || (cacheEntry->modTime() != it->info.modTime) ) {
1391						fprintf(stderr, "update_dyld_shared_cache[%u] warning: for arch=%s, %s has changed since cache was built\n",
1392								getpid(), archPairName, it->layout->getID().name);
1393					}
1394					break;
1395				}
1396			}
1397			else {
1398				if ( cacheEntry->pathFileOffset() > textSize ) {
1399					// cache corrupt, needs to be regenerated
1400					return true;
1401				}
1402				// in normal update mode, everything has to match for cache to be up-to-date
1403				if ( (cacheEntry->inode() == it->info.inode)
1404						&& (cacheEntry->modTime() == it->info.modTime)
1405						&& (strcmp((char*)cache+cacheEntry->pathFileOffset(), it->layout->getID().name) == 0) ) {
1406					found = true;
1407					break;
1408				}
1409			}
1410		}
1411		if ( !found ) {
1412			if ( fVerify ) {
1413				throwf("update_dyld_shared_cache[%u] can't verify %s cache because %s is not in existing cache\n", getpid(), archPairName, it->layout->getID().name);
1414			}
1415			else {
1416				fprintf(stderr, "update_dyld_shared_cache[%u] updating %s cache because dylib at %s has changed\n", getpid(), archPairName, it->layout->getID().name);
1417				return true;
1418			}
1419		}
1420	}
1421	// all dylibs in existing cache file match those determined need to be in shared cache
1422	if ( fVerify ) {
1423		// sort fDylibs to match existing cache file so we can compare content
1424		std::sort(fDylibs.begin(), fDylibs.end(), Sorter(sortingMap));
1425		//fprintf(stderr, "dylibs sorted like existing cache:\n");
1426		//for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1427		//	fprintf(stderr,"   %s\n", it->layout->getID().name);
1428		//}
1429		// do regenerate a new cache so we can compare content with existing
1430		return true;
1431	}
1432	else {
1433		// existing cache file is up-to-date, don't need to regenerate
1434		return false;
1435	}
1436}
1437
1438
1439template <typename A>
1440bool SharedCache<A>::notUpToDate(const char* path, unsigned int aliasCount)
1441{
1442	// mmap existing cache file
1443	int fd = ::open(path, O_RDONLY);
1444	if ( fd == -1 )
1445		return true;
1446	struct stat stat_buf;
1447	::fstat(fd, &stat_buf);
1448    uint32_t cacheFileSize = stat_buf.st_size;
1449    uint32_t cacheAllocatedSize = pageAlign(cacheFileSize);
1450    uint8_t* mappingAddr = NULL;
1451	if ( vm_allocate(mach_task_self(), (vm_address_t*)(&mappingAddr), cacheAllocatedSize, VM_FLAGS_ANYWHERE) != KERN_SUCCESS )
1452        throwf("can't vm_allocate cache of size %u", cacheFileSize);
1453    // <rdar://problem/8960832> update_dyld_shared_cache -verify finds differences
1454 	(void)fcntl(fd, F_NOCACHE, 1);
1455    ssize_t readResult = pread(fd, mappingAddr, cacheFileSize, 0);
1456    if ( readResult != cacheFileSize )
1457        throwf("can't read all of existing cache file (%lu of %u): %s", readResult, cacheFileSize, path);
1458	::close(fd);
1459
1460	// validate it
1461	bool result = this->notUpToDate(mappingAddr, aliasCount);
1462	if ( fVerify ) {
1463		// don't unmap yet, leave so it can be verified later
1464		fExistingCacheForVerification = mappingAddr;
1465	}
1466	else {
1467		// unmap
1468        vm_deallocate(mach_task_self(), (vm_address_t)mappingAddr, cacheAllocatedSize);
1469		if ( verbose && !result )
1470			fprintf(stderr, "update_dyld_shared_cache: %s is up-to-date\n", path);
1471	}
1472	return result;
1473}
1474
1475
1476
1477template <typename A>
1478class LinkEditOptimizer
1479{
1480public:
1481											LinkEditOptimizer(const MachOLayoutAbstraction&, const SharedCache<A>&, uint8_t*, StringPool&);
1482	virtual									~LinkEditOptimizer() {}
1483
1484		void								copyBindInfo(uint32_t&);
1485		void								copyWeakBindInfo(uint32_t&);
1486		void								copyLazyBindInfo(uint32_t&);
1487		void								copyExportInfo(uint32_t&);
1488		void								copyLocalSymbols(uint32_t symbolTableOffset, uint32_t&, bool dontMapLocalSymbols,
1489															uint8_t* cacheStart, StringPool& unmappedLocalsStringPool,
1490															std::vector<macho_nlist<typename A::P> >& unmappedSymbols,
1491															std::vector<LocalSymbolInfo>& info);
1492		void								copyExportedSymbols(uint32_t symbolTableOffset, uint32_t&);
1493		void								copyImportedSymbols(uint32_t symbolTableOffset, uint32_t&);
1494		void								copyExternalRelocations(uint32_t& offset);
1495		void								copyIndirectSymbolTable(uint32_t& offset);
1496		void								copyFunctionStarts(uint32_t& offset);
1497		void								copyDataInCode(uint32_t& offset);
1498		void								updateLoadCommands(uint64_t newVMAddress, uint64_t size, uint32_t stringPoolOffset,
1499																uint32_t linkEditsFileOffset, bool keepSignatures);
1500
1501
1502protected:
1503	typedef typename A::P					P;
1504	typedef typename A::P::E				E;
1505	typedef typename A::P::uint_t			pint_t;
1506
1507private:
1508
1509	const SharedCache<A>&						fSharedCache;
1510	const macho_header<P>*						fHeader;
1511	uint8_t*									fNewLinkEditStart;
1512	uint8_t*									fLinkEditBase;
1513	const MachOLayoutAbstraction&				fLayout;
1514	macho_dyld_info_command<P>*					fDyldInfo;
1515	macho_dysymtab_command<P>*					fDynamicSymbolTable;
1516	macho_linkedit_data_command<P>*				fFunctionStarts;
1517	macho_linkedit_data_command<P>*				fDataInCode;
1518	macho_symtab_command<P>*					fSymbolTableLoadCommand;
1519	const macho_nlist<P>*						fSymbolTable;
1520	const char*									fStrings;
1521	StringPool&									fNewStringPool;
1522	std::map<uint32_t,uint32_t>					fOldToNewSymbolIndexes;
1523	uint32_t									fBindInfoOffsetIntoNewLinkEdit;
1524	uint32_t									fBindInfoSizeInNewLinkEdit;
1525	uint32_t									fWeakBindInfoOffsetIntoNewLinkEdit;
1526	uint32_t									fWeakBindInfoSizeInNewLinkEdit;
1527	uint32_t									fLazyBindInfoOffsetIntoNewLinkEdit;
1528	uint32_t									fLazyBindInfoSizeInNewLinkEdit;
1529	uint32_t									fExportInfoOffsetIntoNewLinkEdit;
1530	uint32_t									fExportInfoSizeInNewLinkEdit;
1531	uint32_t									fSymbolTableStartOffsetInNewLinkEdit;
1532	uint32_t									fLocalSymbolsStartIndexInNewLinkEdit;
1533	uint32_t									fLocalSymbolsCountInNewLinkEdit;
1534	uint32_t									fExportedSymbolsStartIndexInNewLinkEdit;
1535	uint32_t									fExportedSymbolsCountInNewLinkEdit;
1536	uint32_t									fImportSymbolsStartIndexInNewLinkEdit;
1537	uint32_t									fImportedSymbolsCountInNewLinkEdit;
1538	uint32_t									fExternalRelocationsOffsetIntoNewLinkEdit;
1539	uint32_t									fIndirectSymbolTableOffsetInfoNewLinkEdit;
1540	uint32_t									fFunctionStartsOffsetInNewLinkEdit;
1541	uint32_t									fDataInCodeOffsetInNewLinkEdit;
1542	uint32_t									fUnmappedLocalSymbolsStartIndexInNewLinkEdit;
1543	uint32_t									fUnmappedLocalSymbolsCountInNewLinkEdit;
1544};
1545
1546
1547
1548template <typename A>
1549LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, const SharedCache<A>& sharedCache, uint8_t* newLinkEdit, StringPool& stringPool)
1550 : 	fSharedCache(sharedCache), fLayout(layout), fLinkEditBase(NULL), fNewLinkEditStart(newLinkEdit), fDyldInfo(NULL),
1551	fDynamicSymbolTable(NULL), fFunctionStarts(NULL), fDataInCode(NULL),
1552	fSymbolTableLoadCommand(NULL), fSymbolTable(NULL), fStrings(NULL), fNewStringPool(stringPool),
1553	fBindInfoOffsetIntoNewLinkEdit(0), fBindInfoSizeInNewLinkEdit(0),
1554	fWeakBindInfoOffsetIntoNewLinkEdit(0), fWeakBindInfoSizeInNewLinkEdit(0),
1555	fLazyBindInfoOffsetIntoNewLinkEdit(0), fLazyBindInfoSizeInNewLinkEdit(0),
1556	fExportInfoOffsetIntoNewLinkEdit(0), fExportInfoSizeInNewLinkEdit(0),
1557	fSymbolTableStartOffsetInNewLinkEdit(0),
1558	fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
1559	fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
1560	fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
1561	fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0),
1562	fFunctionStartsOffsetInNewLinkEdit(0), fDataInCodeOffsetInNewLinkEdit(0),
1563	fUnmappedLocalSymbolsStartIndexInNewLinkEdit(0), fUnmappedLocalSymbolsCountInNewLinkEdit(0)
1564
1565{
1566	fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
1567
1568	const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
1569	for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
1570		const MachOLayoutAbstraction::Segment& seg = *it;
1571		if ( strcmp(seg.name(), "__LINKEDIT") == 0 )
1572			fLinkEditBase = (uint8_t*)seg.mappedAddress() - seg.fileOffset();
1573	}
1574	if ( fLinkEditBase == NULL )
1575		throw "no __LINKEDIT segment";
1576
1577	const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
1578	const uint32_t cmd_count = fHeader->ncmds();
1579	const macho_load_command<P>* cmd = cmds;
1580	for (uint32_t i = 0; i < cmd_count; ++i) {
1581		switch (cmd->cmd()) {
1582			case LC_SYMTAB:
1583				{
1584					fSymbolTableLoadCommand = (macho_symtab_command<P>*)cmd;
1585					fSymbolTable = (macho_nlist<P>*)(&fLinkEditBase[fSymbolTableLoadCommand->symoff()]);
1586					fStrings = (char*)&fLinkEditBase[fSymbolTableLoadCommand->stroff()];
1587				}
1588				break;
1589			case LC_DYSYMTAB:
1590				fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
1591				break;
1592			case LC_DYLD_INFO:
1593			case LC_DYLD_INFO_ONLY:
1594				fDyldInfo = (macho_dyld_info_command<P>*)cmd;
1595				break;
1596			case LC_FUNCTION_STARTS:
1597				fFunctionStarts = (macho_linkedit_data_command<P>*)cmd;
1598			case LC_DATA_IN_CODE:
1599				fDataInCode = (macho_linkedit_data_command<P>*)cmd;
1600				break;
1601		}
1602		cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
1603	}
1604	if ( fSymbolTable == NULL )
1605		throw "no LC_SYMTAB";
1606	if ( fDynamicSymbolTable == NULL )
1607		throw "no LC_DYSYMTAB";
1608
1609}
1610
1611
1612template <typename A>
1613class SymbolSorter
1614{
1615public:
1616	typedef typename A::P P;
1617	SymbolSorter(const StringPool& pool) : fStringPool(pool) {}
1618	bool operator()(const macho_nlist<P>& left, const macho_nlist<P>& right) {
1619		return (strcmp(fStringPool.stringAtIndex(left.n_strx()) , fStringPool.stringAtIndex(right.n_strx())) < 0);
1620	}
1621
1622private:
1623	const StringPool& fStringPool;
1624};
1625
1626
1627template <typename A>
1628void LinkEditOptimizer<A>::copyBindInfo(uint32_t& offset)
1629{
1630	if ( (fDyldInfo != NULL) && (fDyldInfo->bind_off() != 0) ) {
1631		fBindInfoOffsetIntoNewLinkEdit = offset;
1632		fBindInfoSizeInNewLinkEdit = fDyldInfo->bind_size();
1633		memcpy(fNewLinkEditStart+offset, &fLinkEditBase[fDyldInfo->bind_off()], fDyldInfo->bind_size());
1634		offset += fDyldInfo->bind_size();
1635	}
1636}
1637
1638template <typename A>
1639void LinkEditOptimizer<A>::copyWeakBindInfo(uint32_t& offset)
1640{
1641	if ( (fDyldInfo != NULL) && (fDyldInfo->weak_bind_off() != 0) ) {
1642		fWeakBindInfoOffsetIntoNewLinkEdit = offset;
1643		fWeakBindInfoSizeInNewLinkEdit = fDyldInfo->weak_bind_size();
1644		memcpy(fNewLinkEditStart+offset, &fLinkEditBase[fDyldInfo->weak_bind_off()], fDyldInfo->weak_bind_size());
1645		offset += fDyldInfo->weak_bind_size();
1646	}
1647}
1648
1649template <typename A>
1650void LinkEditOptimizer<A>::copyLazyBindInfo(uint32_t& offset)
1651{
1652	if ( (fDyldInfo != NULL) && (fDyldInfo->lazy_bind_off() != 0) ) {
1653		fLazyBindInfoOffsetIntoNewLinkEdit = offset;
1654		fLazyBindInfoSizeInNewLinkEdit = fDyldInfo->lazy_bind_size();
1655		memcpy(fNewLinkEditStart+offset, &fLinkEditBase[fDyldInfo->lazy_bind_off()], fDyldInfo->lazy_bind_size());
1656		offset += fDyldInfo->lazy_bind_size();
1657	}
1658}
1659
1660template <typename A>
1661void LinkEditOptimizer<A>::copyExportInfo(uint32_t& offset)
1662{
1663	if ( (fDyldInfo != NULL) && (fLayout.getDyldInfoExports() != NULL) ) {
1664		fExportInfoOffsetIntoNewLinkEdit = offset;
1665		fExportInfoSizeInNewLinkEdit = fDyldInfo->export_size();
1666		memcpy(fNewLinkEditStart+offset, fLayout.getDyldInfoExports(), fDyldInfo->export_size());
1667		offset += fDyldInfo->export_size();
1668	}
1669}
1670
1671
1672template <typename A>
1673void LinkEditOptimizer<A>::copyLocalSymbols(uint32_t symbolTableOffset, uint32_t& symbolIndex, bool dontMapLocalSymbols, uint8_t* cacheStart,
1674											StringPool&	unmappedLocalsStringPool, std::vector<macho_nlist<P> >& unmappedSymbols,
1675											std::vector<LocalSymbolInfo>& dylibInfos)
1676{
1677	fLocalSymbolsStartIndexInNewLinkEdit = symbolIndex;
1678	LocalSymbolInfo localInfo;
1679	localInfo.dylibOffset = ((uint8_t*)fHeader) - cacheStart;
1680	localInfo.nlistStartIndex = unmappedSymbols.size();
1681	localInfo.nlistCount = 0;
1682	fSymbolTableStartOffsetInNewLinkEdit = symbolTableOffset + symbolIndex*sizeof(macho_nlist<P>);
1683	macho_nlist<P>* const newSymbolTableStart = (macho_nlist<P>*)(fNewLinkEditStart+symbolTableOffset);
1684	const macho_nlist<P>* const firstLocal = &fSymbolTable[fDynamicSymbolTable->ilocalsym()];
1685	const macho_nlist<P>* const lastLocal  = &fSymbolTable[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()];
1686	uint32_t oldIndex = fDynamicSymbolTable->ilocalsym();
1687	for (const macho_nlist<P>* entry = firstLocal; entry < lastLocal; ++entry, ++oldIndex) {
1688		// <rdar://problem/12237639> don't copy stab symbols
1689		if ( (entry->n_sect() != NO_SECT) && ((entry->n_type() & N_STAB) == 0) ) {
1690			const char* name = &fStrings[entry->n_strx()];
1691			macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
1692			*newSymbolEntry = *entry;
1693			if ( dontMapLocalSymbols ) {
1694				// if local in __text, add <redacted> symbol name to shared cache so backtraces don't have bogus names
1695				if ( entry->n_sect() == 1 ) {
1696					newSymbolEntry->set_n_strx(fNewStringPool.addUnique("<redacted>"));
1697					++symbolIndex;
1698				}
1699				// copy local symbol to unmmapped locals area
1700				unmappedSymbols.push_back(*entry);
1701				unmappedSymbols.back().set_n_strx(unmappedLocalsStringPool.addUnique(name));
1702			}
1703			else {
1704				newSymbolEntry->set_n_strx(fNewStringPool.addUnique(name));
1705				++symbolIndex;
1706			}
1707		}
1708	}
1709	fLocalSymbolsCountInNewLinkEdit = symbolIndex - fLocalSymbolsStartIndexInNewLinkEdit;
1710	localInfo.nlistCount = unmappedSymbols.size() - localInfo.nlistStartIndex;
1711	dylibInfos.push_back(localInfo);
1712	//fprintf(stderr, "%u locals starting at %u for %s\n", fLocalSymbolsCountInNewLinkEdit, fLocalSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1713}
1714
1715
1716template <typename A>
1717void LinkEditOptimizer<A>::copyExportedSymbols(uint32_t symbolTableOffset, uint32_t& symbolIndex)
1718{
1719	fExportedSymbolsStartIndexInNewLinkEdit = symbolIndex;
1720	macho_nlist<P>* const newSymbolTableStart = (macho_nlist<P>*)(fNewLinkEditStart+symbolTableOffset);
1721	const macho_nlist<P>* const firstExport = &fSymbolTable[fDynamicSymbolTable->iextdefsym()];
1722	const macho_nlist<P>* const lastExport  = &fSymbolTable[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
1723	uint32_t oldIndex = fDynamicSymbolTable->iextdefsym();
1724	for (const macho_nlist<P>* entry = firstExport; entry < lastExport; ++entry, ++oldIndex) {
1725		if ( ((entry->n_type() & N_TYPE) == N_SECT) && (strncmp(&fStrings[entry->n_strx()], ".objc_", 6) != 0)
1726						&& (strncmp(&fStrings[entry->n_strx()], "$ld$", 4) != 0) ) {
1727			macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
1728			*newSymbolEntry = *entry;
1729			newSymbolEntry->set_n_strx(fNewStringPool.addUnique(&fStrings[entry->n_strx()]));
1730			fOldToNewSymbolIndexes[oldIndex] = symbolIndex-fLocalSymbolsStartIndexInNewLinkEdit;
1731			++symbolIndex;
1732		}
1733	}
1734	fExportedSymbolsCountInNewLinkEdit = symbolIndex - fExportedSymbolsStartIndexInNewLinkEdit;
1735	//fprintf(stderr, "%u exports starting at %u for %s\n", fExportedSymbolsCountInNewLinkEdit, fExportedSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1736	// sort by name, so that dyld does not need a toc
1737	macho_nlist<P>* newSymbolsStart = &newSymbolTableStart[fExportedSymbolsStartIndexInNewLinkEdit];
1738	macho_nlist<P>* newSymbolsEnd = &newSymbolTableStart[fExportedSymbolsStartIndexInNewLinkEdit+fExportedSymbolsCountInNewLinkEdit];
1739	std::sort(newSymbolsStart, newSymbolsEnd, SymbolSorter<A>(fNewStringPool));
1740	//for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1741	//	fprintf(stderr, "\t%u\t %s\n", (entry-newSymbolsStart)+fExportedSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1742}
1743
1744
1745template <typename A>
1746void LinkEditOptimizer<A>::copyImportedSymbols(uint32_t symbolTableOffset, uint32_t& symbolIndex)
1747{
1748	fImportSymbolsStartIndexInNewLinkEdit = symbolIndex;
1749	macho_nlist<P>* const newSymbolTableStart = (macho_nlist<P>*)(fNewLinkEditStart+symbolTableOffset);
1750	const macho_nlist<P>* const firstImport = &fSymbolTable[fDynamicSymbolTable->iundefsym()];
1751	const macho_nlist<P>* const lastImport  = &fSymbolTable[fDynamicSymbolTable->iundefsym()+fDynamicSymbolTable->nundefsym()];
1752	uint32_t oldIndex = fDynamicSymbolTable->iundefsym();
1753	for (const macho_nlist<P>* entry = firstImport; entry < lastImport; ++entry, ++oldIndex) {
1754		if ( ((entry->n_type() & N_TYPE) == N_UNDF) && (strncmp(&fStrings[entry->n_strx()], ".objc_", 6) != 0) ) {
1755			macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
1756			*newSymbolEntry = *entry;
1757			newSymbolEntry->set_n_strx(fNewStringPool.addUnique(&fStrings[entry->n_strx()]));
1758			fOldToNewSymbolIndexes[oldIndex] = symbolIndex-fLocalSymbolsStartIndexInNewLinkEdit;
1759			++symbolIndex;
1760		}
1761	}
1762	fImportedSymbolsCountInNewLinkEdit = symbolIndex - fImportSymbolsStartIndexInNewLinkEdit;
1763	//fprintf(stderr, "%u imports starting at %u for %s\n", fImportedSymbolsCountInNewLinkEdit, fImportSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1764	//macho_nlist<P>* newSymbolsStart = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit];
1765	//macho_nlist<P>* newSymbolsEnd = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit];
1766	//for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1767	//	fprintf(stderr, "\t%u\t%s\n", (entry-newSymbolsStart)+fImportSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1768}
1769
1770
1771template <typename A>
1772void LinkEditOptimizer<A>::copyExternalRelocations(uint32_t& offset)
1773{
1774	fExternalRelocationsOffsetIntoNewLinkEdit = offset;
1775	const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&fLinkEditBase[fDynamicSymbolTable->extreloff()]);
1776	const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nextrel()];
1777	for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
1778		macho_relocation_info<P>* newReloc = (macho_relocation_info<P>*)(&fNewLinkEditStart[offset]);
1779		*newReloc = *reloc;
1780		uint32_t newSymbolIndex = fOldToNewSymbolIndexes[reloc->r_symbolnum()];
1781		//fprintf(stderr, "copyExternalRelocations() old=%d, new=%u name=%s in %s\n", reloc->r_symbolnum(), newSymbolIndex,
1782		//	 &fStrings[fSymbolTable[reloc->r_symbolnum()].n_strx()], fLayout.getFilePath());
1783		newReloc->set_r_symbolnum(newSymbolIndex);
1784		offset += sizeof(macho_relocation_info<P>);
1785	}
1786}
1787
1788template <typename A>
1789void LinkEditOptimizer<A>::copyFunctionStarts(uint32_t& offset)
1790{
1791	if ( fFunctionStarts != NULL ) {
1792		fFunctionStartsOffsetInNewLinkEdit = offset;
1793		memcpy(&fNewLinkEditStart[offset], &fLinkEditBase[fFunctionStarts->dataoff()], fFunctionStarts->datasize());
1794		offset += fFunctionStarts->datasize();
1795	}
1796}
1797
1798template <typename A>
1799void LinkEditOptimizer<A>::copyDataInCode(uint32_t& offset)
1800{
1801	if ( fDataInCode != NULL ) {
1802		fDataInCodeOffsetInNewLinkEdit = offset;
1803		memcpy(&fNewLinkEditStart[offset], &fLinkEditBase[fDataInCode->dataoff()], fDataInCode->datasize());
1804		offset += fDataInCode->datasize();
1805	}
1806}
1807
1808
1809template <typename A>
1810void LinkEditOptimizer<A>::copyIndirectSymbolTable(uint32_t& offset)
1811{
1812	fIndirectSymbolTableOffsetInfoNewLinkEdit = offset;
1813	const uint32_t* const indirectTable = (uint32_t*)&this->fLinkEditBase[fDynamicSymbolTable->indirectsymoff()];
1814	uint32_t* newIndirectTable = (uint32_t*)&fNewLinkEditStart[offset];
1815	for (int i=0; i < fDynamicSymbolTable->nindirectsyms(); ++i) {
1816		uint32_t oldSymbolIndex = E::get32(indirectTable[i]);
1817		uint32_t newSymbolIndex = oldSymbolIndex;
1818		if ( (oldSymbolIndex != INDIRECT_SYMBOL_ABS) && (oldSymbolIndex != INDIRECT_SYMBOL_LOCAL) ) {
1819			newSymbolIndex = fOldToNewSymbolIndexes[oldSymbolIndex];
1820			//fprintf(stderr, "copyIndirectSymbolTable() old=%d, new=%u name=%s in %s\n", oldSymbolIndex, newSymbolIndex,
1821			// &fStrings[fSymbolTable[oldSymbolIndex].n_strx()], fLayout.getFilePath());
1822		}
1823		E::set32(newIndirectTable[i], newSymbolIndex);
1824	}
1825	offset += (fDynamicSymbolTable->nindirectsyms() * 4);
1826}
1827
1828template <typename A>
1829void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t leSize, uint32_t stringPoolOffset,
1830												uint32_t linkEditsFileOffset, bool keepSignatures)
1831{
1832	// set LINKEDIT segment commmand to new merged LINKEDIT
1833	const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
1834	const uint32_t cmd_count = fHeader->ncmds();
1835	const macho_load_command<P>* cmd = cmds;
1836	for (uint32_t i = 0; i < cmd_count; ++i) {
1837		if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
1838			macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
1839			if ( strcmp(seg->segname(), "__LINKEDIT") == 0 ) {
1840				seg->set_vmaddr(newVMAddress);
1841				seg->set_vmsize(leSize);
1842				seg->set_filesize(leSize);
1843				seg->set_fileoff(linkEditsFileOffset);
1844			}
1845			else {
1846				pint_t oldFileOff = seg->fileoff();
1847				// don't alter __TEXT until <rdar://problem/7022345> is fixed
1848				if ( strcmp(seg->segname(), "__TEXT") != 0 ) {
1849					// update all other segments fileoff to be offset from start of cache file
1850					seg->set_fileoff(fSharedCache.cacheFileOffsetForVMAddress(seg->vmaddr()));
1851				}
1852				pint_t fileOffsetDelta = seg->fileoff() - oldFileOff;
1853				const MachOLayoutAbstraction::Segment* layoutSeg = fLayout.getSegment(seg->segname());
1854				if ( layoutSeg != NULL ) {
1855					//if ( seg->filesize() != layoutSeg->fileSize() ) {
1856					//	fprintf(stderr, "LC filesize=0x%08llX, trimmed seg file size=0x%08llX, seg=%s, path=%s\n",
1857					//					seg->filesize(), layoutSeg->fileSize(), seg->segname(), fLayout.getFilePath());
1858					//}
1859					//if ( seg->vmsize() != layoutSeg->size() ) {
1860					//	fprintf(stderr, "LC   vmsize=0x%08llX, trimmed seg      size=0x%08llX, seg=%s, path=%s\n",
1861					//					seg->vmsize(), layoutSeg->size(), seg->segname(), fLayout.getFilePath());
1862					//}
1863					seg->set_vmsize(layoutSeg->size());
1864					seg->set_filesize(layoutSeg->fileSize());
1865				}
1866				// update all sections in this segment
1867				macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
1868				macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
1869				for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
1870					if ( sect->offset() != 0 )
1871						sect->set_offset(sect->offset()+fileOffsetDelta);
1872				}
1873			}
1874		}
1875		cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
1876	}
1877
1878	// update dyld_info with new offsets
1879	if ( fDyldInfo != NULL ) {
1880		fDyldInfo->set_rebase_off(0);
1881		fDyldInfo->set_rebase_size(0);
1882		fDyldInfo->set_bind_off(linkEditsFileOffset+fBindInfoOffsetIntoNewLinkEdit);
1883		fDyldInfo->set_bind_size(fBindInfoSizeInNewLinkEdit);
1884		fDyldInfo->set_weak_bind_off(linkEditsFileOffset+fWeakBindInfoOffsetIntoNewLinkEdit);
1885		fDyldInfo->set_weak_bind_size(fWeakBindInfoSizeInNewLinkEdit);
1886		fDyldInfo->set_lazy_bind_off(linkEditsFileOffset+fLazyBindInfoOffsetIntoNewLinkEdit);
1887		fDyldInfo->set_lazy_bind_size(fLazyBindInfoSizeInNewLinkEdit);
1888		fDyldInfo->set_export_off(linkEditsFileOffset+fExportInfoOffsetIntoNewLinkEdit);
1889		fDyldInfo->set_export_size(fExportInfoSizeInNewLinkEdit);
1890
1891//		fprintf(stderr, "dylib %s\n", fLayout.getFilePath());
1892//		fprintf(stderr, "  bind_off=0x%08X\n", fDyldInfo->bind_off());
1893//		fprintf(stderr, "  export_off=0x%08X\n", fDyldInfo->export_off());
1894//		fprintf(stderr, "  export_size=%d\n", fDyldInfo->export_size());
1895
1896	}
1897
1898	// update symbol table and dynamic symbol table with new offsets
1899	fSymbolTableLoadCommand->set_symoff(linkEditsFileOffset+fSymbolTableStartOffsetInNewLinkEdit);
1900	fSymbolTableLoadCommand->set_nsyms(fLocalSymbolsCountInNewLinkEdit+fExportedSymbolsCountInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit);
1901	fSymbolTableLoadCommand->set_stroff(linkEditsFileOffset+stringPoolOffset);
1902	fSymbolTableLoadCommand->set_strsize(fNewStringPool.size());
1903	fDynamicSymbolTable->set_ilocalsym(0);
1904	fDynamicSymbolTable->set_nlocalsym(fLocalSymbolsCountInNewLinkEdit);
1905	fDynamicSymbolTable->set_iextdefsym(fExportedSymbolsStartIndexInNewLinkEdit-fLocalSymbolsStartIndexInNewLinkEdit);
1906	fDynamicSymbolTable->set_nextdefsym(fExportedSymbolsCountInNewLinkEdit);
1907	fDynamicSymbolTable->set_iundefsym(fImportSymbolsStartIndexInNewLinkEdit-fLocalSymbolsStartIndexInNewLinkEdit);
1908	fDynamicSymbolTable->set_nundefsym(fImportedSymbolsCountInNewLinkEdit);
1909	fDynamicSymbolTable->set_tocoff(0);
1910	fDynamicSymbolTable->set_ntoc(0);
1911	fDynamicSymbolTable->set_modtaboff(0);
1912	fDynamicSymbolTable->set_nmodtab(0);
1913	fDynamicSymbolTable->set_indirectsymoff(linkEditsFileOffset+fIndirectSymbolTableOffsetInfoNewLinkEdit);
1914	fDynamicSymbolTable->set_extreloff(linkEditsFileOffset+fExternalRelocationsOffsetIntoNewLinkEdit);
1915	fDynamicSymbolTable->set_locreloff(0);
1916	fDynamicSymbolTable->set_nlocrel(0);
1917
1918	// update function starts
1919	if ( fFunctionStarts != NULL ) {
1920		fFunctionStarts->set_dataoff(linkEditsFileOffset+fFunctionStartsOffsetInNewLinkEdit);
1921	}
1922	// update data-in-code info
1923	if ( fDataInCode != NULL ) {
1924		fDataInCode->set_dataoff(linkEditsFileOffset+fDataInCodeOffsetInNewLinkEdit);
1925	}
1926
1927	// now remove load commands no longer needed
1928	const macho_load_command<P>* srcCmd = cmds;
1929	macho_load_command<P>* dstCmd = (macho_load_command<P>*)cmds;
1930	int32_t newCount = 0;
1931	for (uint32_t i = 0; i < cmd_count; ++i) {
1932		uint32_t cmdSize = srcCmd->cmdsize();
1933		switch ( srcCmd->cmd() ) {
1934			case LC_SEGMENT_SPLIT_INFO:
1935			case LC_DYLIB_CODE_SIGN_DRS:
1936				// don't copy
1937				break;
1938			case LC_CODE_SIGNATURE:
1939				if ( !keepSignatures )
1940					break;
1941				// otherwise fall into copy case
1942			default:
1943				memmove(dstCmd, srcCmd, cmdSize);
1944				dstCmd = (macho_load_command<P>*)(((uint8_t*)dstCmd)+cmdSize);
1945				++newCount;
1946				break;
1947		}
1948		srcCmd = (const macho_load_command<P>*)(((uint8_t*)srcCmd)+cmdSize);
1949	}
1950	// zero out stuff removed
1951	bzero(dstCmd, (uint8_t*)srcCmd - (uint8_t*)dstCmd);
1952
1953	// update mach_header
1954	macho_header<P>* writableHeader = (macho_header<P>*)fHeader;
1955	writableHeader->set_ncmds(newCount);
1956	writableHeader->set_sizeofcmds((uint8_t*)dstCmd - ((uint8_t*)fHeader + sizeof(macho_header<P>)));
1957
1958	// this invalidates some ivars
1959	fDynamicSymbolTable = NULL;
1960	fSymbolTableLoadCommand = NULL;
1961	fDyldInfo = NULL;
1962	fSymbolTable = NULL;
1963	fStrings = NULL;
1964}
1965
1966
1967
1968template <typename A>
1969uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures, bool dontMapLocalSymbols)
1970{
1971	// allocate space for optimized LINKEDIT area
1972	uint8_t* newLinkEdit = new uint8_t[fLinkEditsTotalUnoptimizedSize];
1973	bzero(newLinkEdit, fLinkEditsTotalUnoptimizedSize);
1974
1975	// make a string pool
1976	StringPool stringPool;
1977
1978	// create optimizer object for each LINKEDIT segment
1979	std::vector<LinkEditOptimizer<A>*> optimizers;
1980	for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1981		optimizers.push_back(new LinkEditOptimizer<A>(*it->layout, *this, newLinkEdit, stringPool));
1982	}
1983
1984	// rebase info is not copied because images in shared cache are never rebased
1985
1986	// copy weak bind info
1987	uint32_t offset = 0;
1988	fOffsetOfWeakBindInfoInCombinedLinkedit = offset;
1989	for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
1990		(*it)->copyWeakBindInfo(offset);
1991	}
1992
1993	// copy export info
1994	fOffsetOfExportInfoInCombinedLinkedit = offset;
1995	for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
1996		(*it)->copyExportInfo(offset);
1997	}
1998
1999	// copy bind info
2000	fOffsetOfBindInfoInCombinedLinkedit = offset;
2001	for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2002		(*it)->copyBindInfo(offset);
2003	}
2004
2005	// copy lazy bind info
2006	fOffsetOfLazyBindInfoInCombinedLinkedit = offset;
2007	for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2008		(*it)->copyLazyBindInfo(offset);
2009	}
2010
2011	// copy symbol table entries
2012	fOffsetOfOldSymbolTableInfoInCombinedLinkedit = offset;
2013	uint32_t symbolTableOffset = offset;
2014	uint32_t symbolTableIndex = 0;
2015	if ( dontMapLocalSymbols )
2016		fUnmappedLocalSymbols.reserve(16384);
2017	for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2018		(*it)->copyLocalSymbols(symbolTableOffset, symbolTableIndex, dontMapLocalSymbols, fInMemoryCache,
2019								fUnmappedLocalsStringPool, fUnmappedLocalSymbols, fLocalSymbolInfos);
2020		(*it)->copyExportedSymbols(symbolTableOffset, symbolTableIndex);
2021		(*it)->copyImportedSymbols(symbolTableOffset, symbolTableIndex);
2022	}
2023	fSizeOfOldSymbolTableInfoInCombinedLinkedit =  symbolTableIndex * sizeof(macho_nlist<typename A::P>);
2024	offset = symbolTableOffset + fSizeOfOldSymbolTableInfoInCombinedLinkedit & (-8);
2025
2026	// copy external relocations, 8-byte aligned after end of symbol table
2027	fOffsetOfOldExternalRelocationsInCombinedLinkedit = offset;
2028	for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2029		(*it)->copyExternalRelocations(offset);
2030	}
2031	fSizeOfOldExternalRelocationsInCombinedLinkedit = offset - fOffsetOfOldExternalRelocationsInCombinedLinkedit;
2032
2033	// copy function starts
2034	fOffsetOfFunctionStartsInCombinedLinkedit = offset;
2035	for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2036		(*it)->copyFunctionStarts(offset);
2037	}
2038	fSizeOfFunctionStartsInCombinedLinkedit = offset - fOffsetOfFunctionStartsInCombinedLinkedit;
2039
2040	// copy data-in-code info
2041	fOffsetOfDataInCodeInCombinedLinkedit = offset;
2042	for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2043		(*it)->copyDataInCode(offset);
2044	}
2045	fSizeOfDataInCodeInCombinedLinkedit = offset - fOffsetOfDataInCodeInCombinedLinkedit;
2046
2047	// copy indirect symbol tables
2048	fOffsetOfOldIndirectSymbolsInCombinedLinkedit = offset;
2049	for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2050		(*it)->copyIndirectSymbolTable(offset);
2051	}
2052	fSizeOfOldIndirectSymbolsInCombinedLinkedit = offset - fOffsetOfOldIndirectSymbolsInCombinedLinkedit;
2053
2054	// copy string pool
2055	fOffsetOfOldStringPoolInCombinedLinkedit = offset;
2056	memcpy(&newLinkEdit[offset], stringPool.getBuffer(), stringPool.size());
2057	fSizeOfOldStringPoolInCombinedLinkedit = stringPool.size();
2058
2059	// total new size round up to page size
2060	fLinkEditsTotalOptimizedSize = pageAlign(fOffsetOfOldStringPoolInCombinedLinkedit + fSizeOfOldStringPoolInCombinedLinkedit);
2061
2062	// choose new linkedit file offset
2063	uint32_t linkEditsFileOffset = cacheFileOffsetForVMAddress(fLinkEditsStartAddress);
2064//	uint32_t linkEditsFileOffset = fLinkEditsStartAddress - sharedRegionStartAddress();
2065
2066	// update load commands so that all dylibs shared different areas of the same LINKEDIT segment
2067	for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2068		(*it)->updateLoadCommands(fLinkEditsStartAddress, fLinkEditsTotalOptimizedSize, fOffsetOfOldStringPoolInCombinedLinkedit, linkEditsFileOffset, keepSignatures);
2069	}
2070
2071	//fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, fLinkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, fLinkEditsTotalOptimizedSize);
2072	//printf(stderr, "mega link edit mapped starting at: %p\n", fFirstLinkEditSegment->mappedAddress());
2073
2074	// overwrite mapped LINKEDIT area with new optimized LINKEDIT segment
2075	memcpy(fFirstLinkEditSegment->mappedAddress(), newLinkEdit, fLinkEditsTotalUnoptimizedSize);
2076
2077	// update all LINKEDIT Segment objects to point to same merged LINKEDIT area
2078	for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
2079		std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
2080		for(int i=0; i < segs.size(); ++i) {
2081			MachOLayoutAbstraction::Segment& seg = segs[i];
2082			if ( !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") == 0) ) {
2083				seg.setNewAddress(fLinkEditsStartAddress);
2084				seg.setMappedAddress(fFirstLinkEditSegment->mappedAddress());
2085				seg.setSize(fLinkEditsTotalOptimizedSize);
2086				seg.setFileSize(fLinkEditsTotalOptimizedSize);
2087				seg.setFileOffset(linkEditsFileOffset);
2088			}
2089		}
2090	}
2091
2092	// return new end of cache
2093	return (uint8_t*)fFirstLinkEditSegment->mappedAddress() + regionAlign(fLinkEditsTotalOptimizedSize);
2094}
2095
2096
2097template <typename A>
2098class ObjCSelectorUniquer
2099{
2100private:
2101    objc_opt::string_map fSelectorStrings;
2102    SharedCache<A> *fCache;
2103    size_t fCount;
2104
2105public:
2106
2107    ObjCSelectorUniquer(SharedCache<A> *newCache)
2108        : fSelectorStrings()
2109        , fCache(newCache)
2110        , fCount(0)
2111    { }
2112
2113    typename A::P::uint_t visit(typename A::P::uint_t oldValue)
2114    {
2115        fCount++;
2116        const char *s = (const char *)
2117            fCache->mappedAddressForVMAddress(oldValue);
2118        objc_opt::string_map::iterator element =
2119            fSelectorStrings.insert(objc_opt::string_map::value_type(s, oldValue)).first;
2120        return (typename A::P::uint_t)element->second;
2121    }
2122
2123    objc_opt::string_map& strings() {
2124        return fSelectorStrings;
2125    }
2126
2127    size_t count() const { return fCount; }
2128};
2129
2130
2131template <typename A>
2132class ClassListBuilder
2133{
2134private:
2135    typedef typename A::P P;
2136
2137    objc_opt::string_map fClassNames;
2138    objc_opt::class_map fClasses;
2139    size_t fCount;
2140    HeaderInfoOptimizer<A>& fHinfos;
2141
2142public:
2143
2144    ClassListBuilder(HeaderInfoOptimizer<A>& hinfos)
2145        : fClassNames()
2146        , fClasses()
2147        , fCount(0)
2148        , fHinfos(hinfos)
2149    { }
2150
2151    void visitClass(SharedCache<A>* cache,
2152                    const macho_header<P>* header,
2153                    objc_class_t<A>* cls)
2154    {
2155        if (cls->isMetaClass(cache)) return;
2156
2157        const char *name = cls->getName(cache);
2158        uint64_t name_vmaddr = cache->VMAddressForMappedAddress(name);
2159        uint64_t cls_vmaddr = cache->VMAddressForMappedAddress(cls);
2160        uint64_t hinfo_vmaddr = cache->VMAddressForMappedAddress(fHinfos.hinfoForHeader(cache, header));
2161        fClassNames.insert(objc_opt::string_map::value_type(name, name_vmaddr));
2162        fClasses.insert(objc_opt::class_map::value_type(name, std::pair<uint64_t, uint64_t>(cls_vmaddr, hinfo_vmaddr)));
2163        fCount++;
2164    }
2165
2166    objc_opt::string_map& classNames() {
2167        return fClassNames;
2168    }
2169
2170    objc_opt::class_map& classes() {
2171        return fClasses;
2172    }
2173
2174    size_t count() const { return fCount; }
2175};
2176
2177
2178static int percent(size_t num, size_t denom) {
2179    if (denom) return (int)(num / (double)denom * 100);
2180    else return 100;
2181}
2182
2183template <typename A>
2184void SharedCache<A>::optimizeObjC(std::vector<void*>& pointersInData)
2185{
2186    const char *err;
2187
2188    if ( verbose ) {
2189        fprintf(stderr, "update_dyld_shared_cache: for %s, optimizing objc metadata\n", archName());
2190    }
2191
2192    size_t headerSize = P::round_up(sizeof(objc_opt::objc_opt_t));
2193    if (headerSize != sizeof(objc_opt::objc_opt_t)) {
2194		warn(archName(), "libobjc's optimization structure size is wrong (metadata not optimized)");
2195    }
2196
2197    // Find libobjc's empty sections to fill in
2198    const macho_section<P> *optROSection = NULL;
2199    const macho_section<P> *optRWSection = NULL;
2200	for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
2201        if ( strstr(it->layout->getFilePath(), "libobjc") != NULL ) {
2202			const macho_header<P>* mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2203			optROSection = mh->getSection("__TEXT", "__objc_opt_ro");
2204			optRWSection = mh->getSection("__DATA", "__objc_opt_rw");
2205			break;
2206		}
2207	}
2208
2209	if ( optROSection == NULL ) {
2210		warn(archName(), "libobjc's read-only section missing (metadata not optimized)");
2211		return;
2212	}
2213
2214	if ( optRWSection == NULL ) {
2215		warn(archName(), "libobjc's read/write section missing (metadata not optimized)");
2216		return;
2217	}
2218
2219	uint8_t* optROData = (uint8_t*)mappedAddressForVMAddress(optROSection->addr());
2220    size_t optRORemaining = optROSection->size();
2221
2222	uint8_t* optRWData = (uint8_t*)mappedAddressForVMAddress(optRWSection->addr());
2223    size_t optRWRemaining = optRWSection->size();
2224
2225	if (optRORemaining < headerSize) {
2226		warn(archName(), "libobjc's read-only section is too small (metadata not optimized)");
2227		return;
2228	}
2229	objc_opt::objc_opt_t* optROHeader = (objc_opt::objc_opt_t *)optROData;
2230    optROData += headerSize;
2231    optRORemaining -= headerSize;
2232
2233	if (E::get32(optROHeader->version) != objc_opt::VERSION) {
2234		warn(archName(), "libobjc's read-only section version is unrecognized (metadata not optimized)");
2235		return;
2236	}
2237
2238    // Write nothing to optROHeader until everything else is written.
2239    // If something fails below, libobjc will not use the section.
2240
2241    // Find objc-containing dylibs
2242    std::vector<LayoutInfo> objcDylibs;
2243    for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
2244        macho_header<P> *mh = (macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2245        if (mh->getSection("__DATA", "__objc_imageinfo")  ||  mh->getSegment("__OBJC")) {
2246            objcDylibs.push_back(*it);
2247        }
2248    }
2249
2250    // Build image list
2251
2252    // This is SAFE: the binaries themselves are unmodified.
2253
2254    std::vector<LayoutInfo> addressSortedDylibs = objcDylibs;
2255    std::sort(addressSortedDylibs.begin(), addressSortedDylibs.end(), ByAddressSorter());
2256
2257    uint64_t hinfoVMAddr = optRWSection->addr() + optRWSection->size() - optRWRemaining;
2258    HeaderInfoOptimizer<A> hinfoOptimizer;
2259    err = hinfoOptimizer.init(objcDylibs.size(), optRWData, optRWRemaining);
2260    if (err) {
2261		warn(archName(), err);
2262		return;
2263    }
2264    for(typename std::vector<LayoutInfo>::const_iterator it = addressSortedDylibs.begin(); it != addressSortedDylibs.end(); ++it) {
2265        const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2266        hinfoOptimizer.update(this, mh, pointersInData);
2267    }
2268
2269
2270    // Update selector references and build selector list
2271
2272    // This is SAFE: if we run out of room for the selector table,
2273    // the modified binaries are still usable.
2274
2275    // Heuristic: choose selectors from libraries with more cstring data first.
2276    // This tries to localize selector cstring memory.
2277    ObjCSelectorUniquer<A> uniq(this);
2278    std::vector<LayoutInfo> sizeSortedDylibs = objcDylibs;
2279    std::sort(sizeSortedDylibs.begin(), sizeSortedDylibs.end(), ByCStringSectionSizeSorter());
2280
2281    SelectorOptimizer<A, ObjCSelectorUniquer<A> > selOptimizer(uniq);
2282	for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
2283        const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2284        LegacySelectorUpdater<A, ObjCSelectorUniquer<A> >::update(this, mh, uniq);
2285        selOptimizer.optimize(this, mh);
2286	}
2287
2288    uint64_t seloptVMAddr = optROSection->addr() + optROSection->size() - optRORemaining;
2289    objc_opt::objc_selopt_t *selopt = new(optROData) objc_opt::objc_selopt_t;
2290    err = selopt->write(seloptVMAddr, optRORemaining, uniq.strings());
2291    if (err) {
2292        warn(archName(), err);
2293        return;
2294    }
2295    optROData += selopt->size();
2296    optRORemaining -= selopt->size();
2297    selopt->byteswap(E::little_endian), selopt = NULL;
2298
2299
2300    // Build class table.
2301
2302    // This is SAFE: the binaries themselves are unmodified.
2303
2304    ClassListBuilder<A> classes(hinfoOptimizer);
2305    ClassWalker< A, ClassListBuilder<A> > classWalker(classes);
2306	for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
2307        const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2308        classWalker.walk(this, mh);
2309	}
2310
2311    uint64_t clsoptVMAddr = optROSection->addr() + optROSection->size() - optRORemaining;
2312    objc_opt::objc_clsopt_t *clsopt = new(optROData) objc_opt::objc_clsopt_t;
2313    err = clsopt->write(clsoptVMAddr, optRORemaining,
2314                        classes.classNames(), classes.classes(), verbose);
2315    if (err) {
2316        warn(archName(), err);
2317        return;
2318    }
2319    optROData += clsopt->size();
2320    optRORemaining -= clsopt->size();
2321    size_t duplicateCount = clsopt->duplicateCount();
2322    clsopt->byteswap(E::little_endian), clsopt = NULL;
2323
2324
2325    // Sort method lists.
2326
2327    // This is SAFE: modified binaries are still usable as unsorted lists.
2328    // This must be done AFTER uniquing selectors.
2329
2330    MethodListSorter<A> methodSorter;
2331    for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
2332        macho_header<P> *mh = (macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2333        methodSorter.optimize(this, mh);
2334    }
2335
2336
2337    // Repair ivar offsets.
2338
2339    // This is SAFE: the runtime always validates ivar offsets at runtime.
2340
2341    IvarOffsetOptimizer<A> ivarOffsetOptimizer;
2342	for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
2343        const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2344        ivarOffsetOptimizer.optimize(this, mh);
2345	}
2346
2347
2348    // Success. Mark dylibs as optimized.
2349	for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
2350        const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2351        const macho_section<P> *imageInfoSection;
2352        imageInfoSection = mh->getSection("__DATA", "__objc_imageinfo");
2353        if (!imageInfoSection) {
2354            imageInfoSection = mh->getSection("__OBJC", "__image_info");
2355        }
2356        if (imageInfoSection) {
2357            objc_image_info<A> *info = (objc_image_info<A> *)
2358                mappedAddressForVMAddress(imageInfoSection->addr());
2359            info->setOptimizedByDyld();
2360        }
2361    }
2362
2363
2364    // Success. Update RO header last.
2365    E::set32(optROHeader->selopt_offset, seloptVMAddr - optROSection->addr());
2366    E::set32(optROHeader->clsopt_offset, clsoptVMAddr - optROSection->addr());
2367    E::set32(optROHeader->headeropt_offset, hinfoVMAddr - optROSection->addr());
2368
2369    if ( verbose ) {
2370        size_t roSize = optROSection->size() - optRORemaining;
2371        size_t rwSize = optRWSection->size() - optRWRemaining;
2372        fprintf(stderr, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
2373                "(%d%%) used in libobjc read-only optimization section\n",
2374                archName(), roSize, optROSection->size(),
2375                percent(roSize, optROSection->size()));
2376        fprintf(stderr, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
2377                "(%d%%) used in libobjc read/write optimization section\n",
2378                archName(), rwSize, optRWSection->size(),
2379                percent(rwSize, optRWSection->size()));
2380        fprintf(stderr, "update_dyld_shared_cache: for %s, "
2381                "uniqued %zu selectors\n",
2382                archName(), uniq.strings().size());
2383        fprintf(stderr, "update_dyld_shared_cache: for %s, "
2384                "updated %zu selector references\n",
2385                archName(), uniq.count());
2386        fprintf(stderr, "update_dyld_shared_cache: for %s, "
2387                "updated %zu ivar offsets\n",
2388                archName(), ivarOffsetOptimizer.optimized());
2389        fprintf(stderr, "update_dyld_shared_cache: for %s, "
2390                "sorted %zu method lists\n",
2391                archName(), methodSorter.optimized());
2392        fprintf(stderr, "update_dyld_shared_cache: for %s, "
2393                "recorded %zu classes (%zu duplicates)\n",
2394                archName(), classes.classNames().size(), duplicateCount);
2395        fprintf(stderr, "update_dyld_shared_cache: for %s, "
2396                "wrote objc metadata optimization version %d\n",
2397                archName(), objc_opt::VERSION);
2398    }
2399
2400    return;
2401}
2402
2403
2404static const char* sCleanupFile = NULL;
2405static void cleanup(int sig)
2406{
2407	::signal(sig, SIG_DFL);
2408	if ( sCleanupFile != NULL )
2409		::unlink(sCleanupFile);
2410	//if ( verbose )
2411	//	fprintf(stderr, "update_dyld_shared_cache: deleting temp file in response to a signal\n");
2412	if ( sig == SIGINT )
2413		::exit(1);
2414}
2415
2416
2417// <rdar://problem/10730767> update_dyld_shared_cache should use sync_volume_np() instead of sync()
2418static void sync_volume(const char* volumePath)
2419{
2420#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
2421	int error = sync_volume_np(volumePath, SYNC_VOLUME_FULLSYNC|SYNC_VOLUME_FULLSYNC);
2422#else
2423	int full_sync = 3; // SYNC_VOLUME_FULLSYNC | SYNC_VOLUME_FULLSYNC
2424	int error = 0;
2425	if ( fsctl(volumePath, 0x80004101 /*FSCTL_SYNC_VOLUME*/, &full_sync, 0) == -1)
2426		error = errno;
2427#endif
2428	if ( error )
2429		::sync();
2430}
2431
2432
2433// <rdar://problem/12552226> update shared cache should sign the shared cache
2434static bool adhoc_codesign_share_cache(const char* path)
2435{
2436	CFURLRef target = ::CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *)path, strlen(path), FALSE);
2437	if ( target == NULL )
2438		return false;
2439
2440	SecStaticCodeRef code;
2441	OSStatus status = ::SecStaticCodeCreateWithPath(target, kSecCSDefaultFlags, &code);
2442	CFRelease(target);
2443	if ( status ) {
2444		::fprintf(stderr, "codesign: failed to create url to signed object\n");
2445		return false;
2446	}
2447
2448	const void * keys[1] = { (void *)kSecCodeSignerIdentity } ;
2449	const void * values[1] = { (void *)kCFNull };
2450	CFDictionaryRef params = ::CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2451	if ( params == NULL ) {
2452		CFRelease(code);
2453		return false;
2454	}
2455
2456	SecCodeSignerRef signer;
2457	status = ::SecCodeSignerCreate(params, kSecCSDefaultFlags, &signer);
2458	CFRelease(params);
2459	if ( status ) {
2460		CFRelease(code);
2461		::fprintf(stderr, "codesign: failed to create signer object\n");
2462		return false;
2463	}
2464
2465	status = ::SecCodeSignerAddSignatureWithErrors(signer, code, kSecCSDefaultFlags, NULL);
2466	CFRelease(code);
2467	CFRelease(signer);
2468	if ( status ) {
2469		::fprintf(stderr, "codesign: failed to sign object: %s\n", path);
2470		return false;
2471	}
2472
2473	if ( verbose )
2474		::fprintf(stderr, "codesigning complete of %s\n", path);
2475
2476	return true;
2477}
2478
2479
2480
2481template <>	 bool	SharedCache<x86_64>::addCacheSlideInfo(){ return true; }
2482template <>	 bool	SharedCache<arm>::addCacheSlideInfo()	{ return true; }
2483template <>	 bool	SharedCache<x86>::addCacheSlideInfo()	{ return false; }
2484template <>	 bool	SharedCache<arm64>::addCacheSlideInfo()	{ return true; }
2485
2486
2487template <typename A>
2488bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst, int archIndex,
2489								int archCount, bool keepSignatures, bool dontMapLocalSymbols)
2490{
2491	bool didUpdate = false;
2492
2493	// already up to date?
2494	if ( force || fExistingIsNotUpToDate ) {
2495		if ( verbose )
2496			fprintf(stderr, "update_dyld_shared_cache: regenerating %s\n", fCacheFilePath);
2497		if ( fDylibs.size() == 0 ) {
2498			fprintf(stderr, "update_dyld_shared_cache: warning, empty cache not generated for arch %s\n", archName());
2499			return false;
2500		}
2501		// delete existing cache while building the new one
2502		// this is a flag to dyld to stop pinging update_dyld_shared_cache
2503		if ( deleteExistingFirst )
2504			::unlink(fCacheFilePath);
2505		uint8_t* inMemoryCache = NULL;
2506		uint32_t allocatedCacheSize = 0;
2507		char tempCachePath[strlen(fCacheFilePath)+16];
2508		sprintf(tempCachePath, "%s.tmp%u", fCacheFilePath, getpid());
2509		try {
2510			// allocate a memory block to hold cache
2511			uint32_t cacheFileSize = 0;
2512			for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
2513				uint32_t end = it->sfm_file_offset + it->sfm_size;
2514				if ( end > cacheFileSize )
2515					cacheFileSize = end;
2516			}
2517			if ( vm_allocate(mach_task_self(), (vm_address_t*)(&inMemoryCache), cacheFileSize, VM_FLAGS_ANYWHERE) != KERN_SUCCESS )
2518				throwf("can't vm_allocate cache of size %u", cacheFileSize);
2519			allocatedCacheSize = cacheFileSize;
2520            fInMemoryCache = inMemoryCache;
2521
2522			// fill in header
2523			dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)inMemoryCache;
2524			const char* archPairName = fArchGraph->archName();
2525			char temp[16];
2526			strcpy(temp, "dyld_v1        ");
2527			strcpy(&temp[15-strlen(archPairName)], archPairName);
2528			header->set_magic(temp);
2529			//header->set_architecture(arch());
2530			header->set_mappingOffset(sizeof(dyldCacheHeader<E>));
2531			header->set_mappingCount(fMappings.size());
2532			header->set_imagesOffset(header->mappingOffset() + fMappings.size()*sizeof(dyldCacheFileMapping<E>));
2533			header->set_imagesCount(fDylibs.size()+fDylibAliases.size());
2534			header->set_dyldBaseAddress(fDyldBaseAddress);
2535			header->set_codeSignatureOffset(cacheFileSize);
2536			header->set_codeSignatureSize(0);
2537			header->set_slideInfoOffset(0);
2538			header->set_slideInfoSize(0);
2539			header->set_localSymbolsOffset(0);
2540			header->set_localSymbolsSize(0);
2541
2542			// fill in mappings
2543			dyldCacheFileMapping<E>* mapping = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
2544			for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
2545				if ( verbose )
2546					fprintf(stderr, "update_dyld_shared_cache: cache mappings: address=0x%0llX, size=0x%0llX, fileOffset=0x%0llX, prot=0x%X\n",
2547									it->sfm_address, it->sfm_size, it->sfm_file_offset, it->sfm_init_prot);
2548				mapping->set_address(it->sfm_address);
2549				mapping->set_size(it->sfm_size);
2550				mapping->set_file_offset(it->sfm_file_offset);
2551				mapping->set_max_prot(it->sfm_max_prot);
2552				mapping->set_init_prot(it->sfm_init_prot);
2553				++mapping;
2554			}
2555
2556			// fill in image table
2557			dyldCacheImageInfo<E>* image = (dyldCacheImageInfo<E>*)mapping;
2558			for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
2559				image->set_address(it->info.address);
2560				image->set_modTime(it->info.modTime);
2561				image->set_inode(it->info.inode);
2562				image->set_pathFileOffset(cacheFileOffsetForVMAddress(it->info.address+it->info.pathFileOffset));
2563				++image;
2564			}
2565
2566			// add aliases to end of image table
2567			for(typename std::vector<LayoutInfo>::iterator it = fDylibAliases.begin(); it != fDylibAliases.end(); ++it) {
2568				image->set_address(it->info.address);
2569				image->set_modTime(it->info.modTime);
2570				image->set_inode(it->info.inode);
2571				image->set_pathFileOffset(it->info.pathFileOffset);
2572				strcpy((char*)inMemoryCache+it->info.pathFileOffset, it->aliases[0]);
2573				//fprintf(stderr, "adding alias to offset 0x%08X %s\n", it->info.pathFileOffset, it->aliases[0]);
2574				++image;
2575			}
2576
2577			// copy each segment to cache buffer
2578			const int dylibCount = fDylibs.size();
2579			int dylibIndex = 0;
2580			int progressIndex = 0;
2581			for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it, ++dylibIndex) {
2582				const char* path = it->layout->getFilePath();
2583				int src = ::open(path, O_RDONLY, 0);
2584				if ( src == -1 )
2585					throwf("can't open file %s, errnor=%d", it->layout->getID().name, errno);
2586				// mark source as "don't cache"
2587				(void)fcntl(src, F_NOCACHE, 1);
2588				// verify file has not changed since dependency analysis
2589				struct stat stat_buf;
2590				if ( fstat(src, &stat_buf) == -1)
2591					throwf("can't stat open file %s, errno=%d", path, errno);
2592				if ( (it->layout->getInode() != stat_buf.st_ino) )
2593					throwf("file inode changed from %llu to %llu during cache creation: %s", it->layout->getInode(), stat_buf.st_ino, path);
2594				else if ( it->layout->getLastModTime() != stat_buf.st_mtime )
2595					throwf("file mtime changed from 0x%lX to 0x%lX during cache creation: %s", it->layout->getLastModTime(), stat_buf.st_mtime, path);
2596
2597				if ( verbose )
2598					fprintf(stderr, "update_dyld_shared_cache: copying %s to cache\n", it->layout->getFilePath());
2599				try {
2600					const std::vector<MachOLayoutAbstraction::Segment>& segs = it->layout->getSegments();
2601					for (int i=0; i < segs.size(); ++i) {
2602						const MachOLayoutAbstraction::Segment& seg = segs[i];
2603						if ( verbose )
2604							fprintf(stderr, "\t\tsegment %s, size=0x%0llX, cache address=0x%0llX\n", seg.name(), seg.fileSize(), seg.newAddress());
2605						if ( seg.size() > 0 ) {
2606							const uint64_t segmentSrcStartOffset = it->layout->getOffsetInUniversalFile()+seg.fileOffset();
2607							const uint64_t segmentSize = seg.fileSize();
2608							const uint64_t segmentDstStartOffset = cacheFileOffsetForVMAddress(seg.newAddress());
2609							ssize_t readResult = ::pread(src, &inMemoryCache[segmentDstStartOffset], segmentSize, segmentSrcStartOffset);
2610							if ( readResult != segmentSize ) {
2611								if ( readResult == -1 )
2612									throwf("read failure copying dylib errno=%d for %s", errno, it->layout->getID().name);
2613								else
2614									throwf("read failure copying dylib. Read of %lld bytes at file offset %lld returned %ld for %s",
2615											segmentSize, segmentSrcStartOffset, readResult, it->layout->getID().name);
2616							}
2617						}
2618					}
2619				}
2620				catch (const char* msg) {
2621					throwf("%s while copying %s to shared cache", msg, it->layout->getID().name);
2622				}
2623				::close(src);
2624				if ( progress ) {
2625					// assuming read takes 40% of time
2626					int nextProgressIndex = archIndex*100+(40*dylibIndex)/dylibCount;
2627					if ( nextProgressIndex != progressIndex )
2628						fprintf(stdout, "%3u/%u\n", nextProgressIndex, archCount*100);
2629					progressIndex = nextProgressIndex;
2630				}
2631			}
2632
2633			// set mapped address for each segment
2634			for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
2635				std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
2636				for (int i=0; i < segs.size(); ++i) {
2637					MachOLayoutAbstraction::Segment& seg = segs[i];
2638					if ( seg.size() > 0 )
2639						seg.setMappedAddress(inMemoryCache + cacheFileOffsetForVMAddress(seg.newAddress()));
2640					//fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
2641				}
2642			}
2643
2644			// also construct list of all pointers in cache to other things in cache
2645			std::vector<void*> pointersInData;
2646			pointersInData.reserve(1024);
2647
2648			// rebase each dylib in shared cache
2649			for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
2650				try {
2651					Rebaser<A> r(*it->layout);
2652					r.rebase(pointersInData);
2653					//if ( verbose )
2654					//	fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
2655				}
2656				catch (const char* msg) {
2657					throwf("%s in %s", msg, it->layout->getID().name);
2658				}
2659			}
2660
2661			if ( verbose )
2662				fprintf(stderr, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs.size());
2663			// instantiate a Binder for each image and add to map
2664			typename Binder<A>::Map map;
2665			std::vector<Binder<A>*> binders;
2666			for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
2667				//fprintf(stderr, "binding %s\n", it->layout->getID().name);
2668				Binder<A>* binder = new Binder<A>(*it->layout, fDyldBaseAddress);
2669				binders.push_back(binder);
2670				// only add dylibs to map
2671				if ( it->layout->getID().name != NULL )
2672					map[it->layout->getID().name] = binder;
2673			}
2674
2675			// tell each Binder about the others
2676			for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
2677				(*it)->setDependentBinders(map);
2678			}
2679			// perform binding
2680			for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
2681				if ( verbose )
2682					fprintf(stderr, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it)->getDylibID());
2683				try {
2684					(*it)->bind(pointersInData);
2685				}
2686				catch (const char* msg) {
2687					throwf("%s in %s", msg, (*it)->getDylibID());
2688				}
2689			}
2690			// optimize binding
2691			for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
2692				try {
2693					(*it)->optimize();
2694				}
2695				catch (const char* msg) {
2696					throwf("%s in %s", msg, (*it)->getDylibID());
2697				}
2698			}
2699			// delete binders
2700			for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
2701				delete *it;
2702			}
2703
2704			// merge/optimize all LINKEDIT segments
2705			if ( optimize ) {
2706				//fprintf(stderr, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize/(1024*1024));
2707				cacheFileSize = (this->optimizeLINKEDIT(keepSignatures, dontMapLocalSymbols) - inMemoryCache);
2708				//fprintf(stderr, "update_dyld_shared_cache: optimized cache file size 0x%08X %uMB\n", cacheFileSize, cacheFileSize/(1024*1024));
2709				// update header to reduce mapping size
2710				dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
2711				dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
2712				dyldCacheFileMapping<E>* lastMapping = &mappings[cacheHeader->mappingCount()-1];
2713				lastMapping->set_size(cacheFileSize-lastMapping->file_offset());
2714				// update fMappings so .map file will print correctly
2715				fMappings.back().sfm_size = cacheFileSize-fMappings.back().sfm_file_offset;
2716				// update header
2717				//fprintf(stderr, "update_dyld_shared_cache: changing end of cache address from 0x%08llX to 0x%08llX\n",
2718				//		header->codeSignatureOffset(), fMappings.back().sfm_address + fMappings.back().sfm_size);
2719				header->set_codeSignatureOffset(fMappings.back().sfm_file_offset + fMappings.back().sfm_size);
2720			}
2721
2722			// unique objc selectors and update other objc metadata
2723            if ( optimize ) {
2724				optimizeObjC(pointersInData);
2725				if ( progress ) {
2726					// assuming objc optimizations takes 15% of time
2727					fprintf(stdout, "%3u/%u\n", (archIndex+1)*55, archCount*100);
2728				}
2729			}
2730
2731			if ( addCacheSlideInfo() ) {
2732				// build bitmap of which pointers need sliding
2733				uint8_t* const dataStart = &inMemoryCache[fMappings[1].sfm_file_offset]; // R/W mapping is always second
2734				uint8_t* const dataEnd   = &inMemoryCache[fMappings[1].sfm_file_offset+fMappings[1].sfm_size];
2735				const int bitmapSize = (dataEnd - dataStart)/(4*8);
2736				uint8_t* bitmap = (uint8_t*)calloc(bitmapSize, 1);
2737				void* lastPointer = inMemoryCache;
2738				for(std::vector<void*>::iterator pit=pointersInData.begin(); pit != pointersInData.end(); ++pit) {
2739					if ( *pit != lastPointer ) {
2740						void* p = *pit;
2741						if ( (p < dataStart) || ( p > dataEnd) )
2742							throwf("DATA pointer for sliding, out of range 0x%08lX\n", (long)((uint8_t*)p-inMemoryCache));
2743						long offset = (long)((uint8_t*)p - dataStart);
2744						if ( (offset % 4) != 0 )
2745							throwf("pointer not 4-byte aligned in DATA offset 0x%08lX\n", offset);
2746						long byteIndex = offset / (4*8);
2747						long bitInByte =  (offset % 32) >> 2;
2748						bitmap[byteIndex] |= (1 << bitInByte);
2749						lastPointer = p;
2750					}
2751				}
2752
2753				// allocate worst case size block of all slide info
2754				const int entry_size = 4096/(8*4); // 8 bits per byte, possible pointer every 4 bytes.
2755				const int toc_count = bitmapSize/entry_size;
2756				int slideInfoSize = sizeof(dyldCacheSlideInfo<E>) + 2*toc_count + entry_size*(toc_count+1);
2757				dyldCacheSlideInfo<E>* slideInfo = (dyldCacheSlideInfo<E>*)calloc(slideInfoSize, 1);
2758				slideInfo->set_version(1);
2759				slideInfo->set_toc_offset(sizeof(dyldCacheSlideInfo<E>));
2760				slideInfo->set_toc_count(toc_count);
2761				slideInfo->set_entries_offset((slideInfo->toc_offset()+2*toc_count+127)&(-128));
2762				slideInfo->set_entries_count(0);
2763				slideInfo->set_entries_size(entry_size);
2764				// append each unique entry
2765				const dyldCacheSlideInfoEntry* bitmapAsEntries = (dyldCacheSlideInfoEntry*)bitmap;
2766				dyldCacheSlideInfoEntry* const entriesInSlidInfo = (dyldCacheSlideInfoEntry*)((char*)slideInfo+slideInfo->entries_offset());
2767				int entry_count = 0;
2768				for (int i=0; i < toc_count; ++i) {
2769					const dyldCacheSlideInfoEntry* thisEntry = &bitmapAsEntries[i];
2770					// see if it is same as one already added
2771					bool found = false;
2772					for (int j=0; j < entry_count; ++j) {
2773						if ( memcmp(thisEntry, &entriesInSlidInfo[j], entry_size) == 0 ) {
2774							//fprintf(stderr, "toc[%d] optimized to %d\n", i, j);
2775							slideInfo->set_toc(i, j);
2776							found = true;
2777							break;
2778						}
2779					}
2780					if ( ! found ) {
2781						// append to end
2782						memcpy(&entriesInSlidInfo[entry_count], thisEntry, entry_size);
2783						slideInfo->set_toc(i, entry_count++);
2784					}
2785				}
2786				slideInfo->set_entries_count(entry_count);
2787
2788				int slideInfoPageSize = regionAlign(slideInfo->entries_offset() + entry_count*entry_size);
2789				cacheFileSize += slideInfoPageSize;
2790
2791				// update mappings to increase RO size
2792				dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
2793				dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
2794				dyldCacheFileMapping<E>* lastMapping = &mappings[cacheHeader->mappingCount()-1];
2795				lastMapping->set_size(lastMapping->size()+slideInfoPageSize);
2796
2797				// update header to show location of slidePointers
2798				cacheHeader->set_slideInfoOffset(cacheHeader->codeSignatureOffset());
2799				cacheHeader->set_slideInfoSize(slideInfoPageSize);
2800				cacheHeader->set_codeSignatureOffset(cacheHeader->codeSignatureOffset()+slideInfoPageSize);
2801
2802				// update fMappings so .map file will print correctly
2803				fMappings.back().sfm_size = cacheFileSize-fMappings.back().sfm_file_offset;
2804
2805				// copy compressed into into buffer
2806				memcpy(&inMemoryCache[cacheHeader->slideInfoOffset()], slideInfo, slideInfoPageSize);
2807			}
2808
2809			// append local symbol info in an unmapped region
2810			if ( dontMapLocalSymbols ) {
2811				uint32_t spaceAtEnd = allocatedCacheSize - cacheFileSize;
2812				uint32_t localSymbolsOffset = pageAlign(cacheFileSize);
2813				dyldCacheLocalSymbolsInfo<E>* infoHeader = (dyldCacheLocalSymbolsInfo<E>*)(&inMemoryCache[localSymbolsOffset]);
2814				const uint32_t entriesOffset = sizeof(dyldCacheLocalSymbolsInfo<E>);
2815				const uint32_t entriesCount = fLocalSymbolInfos.size();
2816				const uint32_t nlistOffset = entriesOffset + entriesCount * sizeof(dyldCacheLocalSymbolEntry<E>);
2817				const uint32_t nlistCount = fUnmappedLocalSymbols.size();
2818				const uint32_t stringsOffset = nlistOffset + nlistCount * sizeof(macho_nlist<P>);
2819				const uint32_t stringsSize = fUnmappedLocalsStringPool.size();
2820				if ( stringsOffset+stringsSize > spaceAtEnd )
2821					throwf("update_dyld_shared_cache[%u] for arch=%s, out of space for local symbols. Have 0x%X, Need 0x%X\n",
2822							getpid(), fArchGraph->archName(), spaceAtEnd, stringsOffset+stringsSize);
2823				// fill in local symbols info
2824				infoHeader->set_nlistOffset(nlistOffset);
2825				infoHeader->set_nlistCount(nlistCount);
2826				infoHeader->set_stringsOffset(stringsOffset);
2827				infoHeader->set_stringsSize(stringsSize);
2828				infoHeader->set_entriesOffset(entriesOffset);
2829				infoHeader->set_entriesCount(entriesCount);
2830				// copy info for each dylib
2831				dyldCacheLocalSymbolEntry<E>* entries = (dyldCacheLocalSymbolEntry<E>*)(&inMemoryCache[localSymbolsOffset+entriesOffset]);
2832				for (int i=0; i < entriesCount; ++i) {
2833					entries[i].set_dylibOffset(fLocalSymbolInfos[i].dylibOffset);
2834					entries[i].set_nlistStartIndex(fLocalSymbolInfos[i].nlistStartIndex);
2835					entries[i].set_nlistCount(fLocalSymbolInfos[i].nlistCount);
2836				}
2837				// copy nlists
2838				memcpy(&inMemoryCache[localSymbolsOffset+nlistOffset], &fUnmappedLocalSymbols[0], nlistCount*sizeof(macho_nlist<P>));
2839				// copy string pool
2840				memcpy(&inMemoryCache[localSymbolsOffset+stringsOffset], fUnmappedLocalsStringPool.getBuffer(), stringsSize);
2841
2842				// update state
2843				fUnmappedLocalSymbolsSize = pageAlign(stringsOffset + stringsSize);
2844				cacheFileSize = regionAlign(localSymbolsOffset + fUnmappedLocalSymbolsSize);
2845
2846				// update header to show location of slidePointers
2847				dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
2848				cacheHeader->set_localSymbolsOffset(localSymbolsOffset);
2849				cacheHeader->set_localSymbolsSize(stringsOffset+stringsSize);
2850				cacheHeader->set_codeSignatureOffset(cacheFileSize);
2851			}
2852
2853			// make sure after all optimizations, that whole cache file fits into shared region address range
2854			{
2855				dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
2856				dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[cacheHeader->mappingOffset()];
2857				// <rdar://problem/16128830> incorporate code signature size into overflow check
2858				uint32_t estCodeSigSize = regionAlign(cacheFileSize/200); // guess 0.5% for code signature
2859				for (int i=0; i < cacheHeader->mappingCount(); ++i) {
2860					uint64_t endAddr = mappings[i].address() + mappings[i].size() + estCodeSigSize;
2861					if ( endAddr > (sharedRegionStartAddress() + sharedRegionSize()) ) {
2862						throwf("update_dyld_shared_cache[%u] for arch=%s, shared cache will not fit in shared regionsaddress space.  Overflow amount: %lluKB\n",
2863							getpid(), fArchGraph->archName(), (endAddr-(sharedRegionStartAddress() + sharedRegionSize()))/1024);
2864					}
2865				}
2866			}
2867
2868			// compute UUID of whole cache
2869			uint8_t digest[16];
2870			CC_MD5(inMemoryCache, cacheFileSize, digest);
2871			// <rdar://problem/6723729> uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
2872			digest[6] = ( digest[6] & 0x0F ) | ( 3 << 4 );
2873			digest[8] = ( digest[8] & 0x3F ) | 0x80;
2874			((dyldCacheHeader<E>*)inMemoryCache)->set_uuid(digest);
2875
2876			if ( fVerify ) {
2877				// if no existing cache, say so
2878				if ( fExistingCacheForVerification == NULL ) {
2879					throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
2880					 getpid(), archName());
2881				}
2882				// new cache is built, compare header entries
2883				const dyldCacheHeader<E>* newHeader = (dyldCacheHeader<E>*)inMemoryCache;
2884				const dyldCacheHeader<E>* oldHeader = (dyldCacheHeader<E>*)fExistingCacheForVerification;
2885				if ( newHeader->mappingCount() != oldHeader->mappingCount() ) {
2886					throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because caches have a different number of mappings\n",
2887					 getpid(), archName());
2888				}
2889				const dyldCacheFileMapping<E>* newMappings = (dyldCacheFileMapping<E>*)&inMemoryCache[newHeader->mappingOffset()];
2890				const dyldCacheFileMapping<E>* oldMappings = (dyldCacheFileMapping<E>*)&fExistingCacheForVerification[oldHeader->mappingOffset()];
2891				for (int i=0; i < newHeader->mappingCount(); ++i) {
2892					if ( newMappings[i].address() != oldMappings[i].address() ) {
2893						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",
2894							getpid(), archName(), i, newMappings[i].address(), oldMappings[i].address() );
2895					}
2896					if ( newMappings[i].size() != oldMappings[i].size() ) {
2897						throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because mapping %d has a different size\n",
2898						 getpid(), archName(), i);
2899					}
2900				}
2901
2902				//fprintf(stderr, "%s existing cache = %p\n", archName(), fExistingCacheForVerification);
2903				//fprintf(stderr, "%s new cache = %p\n", archName(), inMemoryCache);
2904				// compare content to existing cache page by page
2905				for (int offset=0; offset < cacheFileSize; offset += 4096) {
2906					if ( memcmp(&inMemoryCache[offset], &fExistingCacheForVerification[offset], 4096) != 0 ) {
2907						fprintf(stderr, "verifier found differences on page offset 0x%08X for %s:\n", offset, archName());
2908						for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it, ++dylibIndex) {
2909							const std::vector<MachOLayoutAbstraction::Segment>& segs = it->layout->getSegments();
2910							for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator sit = segs.begin(); sit != segs.end(); ++sit) {
2911								const MachOLayoutAbstraction::Segment& seg = *sit;
2912								if ( (seg.mappedAddress() <= &inMemoryCache[offset]) && (&inMemoryCache[offset] < ((uint8_t*)seg.mappedAddress() + seg.fileSize())) ) {
2913									// all LINKEDITs point to the same region, so just print one
2914									if ( strcmp(seg.name(), "__LINKEDIT") == 0 )
2915										fprintf(stderr, "  in merged LINKEDIT segment\n");
2916									else
2917										fprintf(stderr, "  in segment %s of dylib %s\n", seg.name(), it->layout->getID().name);
2918									break;
2919								}
2920							}
2921						}
2922						for (int po=0; po < 4096; po += 16) {
2923							if ( memcmp(&inMemoryCache[offset+po], &fExistingCacheForVerification[offset+po], 16) != 0 ) {
2924								fprintf(stderr, "   existing: 0x%08X: ", offset+po);
2925								for ( int j=0; j < 16; ++j)
2926									fprintf(stderr, " 0x%02X", fExistingCacheForVerification[offset+po+j]);
2927								fprintf(stderr, "\n");
2928								fprintf(stderr, "  should be: 0x%08X: ", offset+po);
2929								for ( int j=0; j < 16; ++j)
2930									fprintf(stderr, " 0x%02X", inMemoryCache[offset+po+j]);
2931								fprintf(stderr, "\n");
2932							}
2933						}
2934					}
2935				}
2936			}
2937			else {
2938				// install signal handlers to delete temp file if program is killed
2939				sCleanupFile = tempCachePath;
2940				::signal(SIGINT, cleanup);
2941				::signal(SIGBUS, cleanup);
2942				::signal(SIGSEGV, cleanup);
2943
2944				// create var/db/dyld dirs if needed
2945				char dyldDirs[1024];
2946				strcpy(dyldDirs, fCacheFilePath);
2947				char* lastSlash = strrchr(dyldDirs, '/');
2948				if ( lastSlash != NULL )
2949					lastSlash[1] = '\0';
2950				struct stat stat_buf;
2951				if ( stat(dyldDirs, &stat_buf) != 0 ) {
2952					const char* afterSlash = &dyldDirs[1];
2953					char* slash;
2954					while ( (slash = strchr(afterSlash, '/')) != NULL ) {
2955						*slash = '\0';
2956						::mkdir(dyldDirs, S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH);
2957						*slash = '/';
2958						afterSlash = slash+1;
2959					}
2960				}
2961
2962				// create temp file for cache
2963				int fd = ::open(tempCachePath, O_CREAT | O_RDWR | O_TRUNC, 0644);
2964				if ( fd == -1 )
2965					throwf("can't create temp file %s, errnor=%d", tempCachePath, errno);
2966
2967				// try to allocate whole cache file contiguously
2968				fstore_t fcntlSpec = { F_ALLOCATECONTIG|F_ALLOCATEALL, F_PEOFPOSMODE, 0, cacheFileSize, 0 };
2969				::fcntl(fd, F_PREALLOCATE, &fcntlSpec);
2970
2971				// write out cache file
2972				if ( verbose )
2973					fprintf(stderr, "update_dyld_shared_cache: writing cache to disk: %s\n", tempCachePath);
2974				if ( ::pwrite(fd, inMemoryCache, cacheFileSize, 0) != cacheFileSize )
2975					throwf("write() failure creating cache file, errno=%d", errno);
2976				if ( progress ) {
2977					// assuming write takes 35% of time
2978					fprintf(stdout, "%3u/%u\n", (archIndex+1)*90, archCount*100);
2979				}
2980
2981				// flush to disk and close
2982				int result = ::fcntl(fd, F_FULLFSYNC, NULL);
2983				if ( result == -1 )
2984					fprintf(stderr, "update_dyld_shared_cache: warning, fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno, tempCachePath);
2985				result = ::close(fd);
2986				if ( result != 0 )
2987					fprintf(stderr, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno, tempCachePath);
2988
2989				if ( !iPhoneOS )
2990					adhoc_codesign_share_cache(tempCachePath);
2991
2992				// <rdar://problem/7901042> Make life easier for the kernel at shutdown.
2993				// If we just move the new cache file over the old, the old file
2994				// may need to exist in the open-unlink state.  But because it
2995				// may be mapped into the shared region, it cannot be deleted
2996				// until all user processes are terminated.  That leaves are
2997				// small to non-existent window for the kernel to delete the
2998				// old cache file.
2999				if ( fCacheFileInFinalLocation ) {
3000					char tmpDirPath[64];
3001					const char* pathLastSlash = strrchr(fCacheFilePath, '/');
3002					if ( pathLastSlash != NULL ) {
3003						sprintf(tmpDirPath, "/var/run%s.old.%u", pathLastSlash, getpid());
3004						// move existing cache file to /var/run to be clean up next boot
3005						result = ::rename(fCacheFilePath, tmpDirPath);
3006						if ( result != 0 ) {
3007							if ( errno != ENOENT )
3008								fprintf(stderr, "update_dyld_shared_cache: warning, unable to move existing cache to %s errno=%d for %s\n", tmpDirPath, errno, fCacheFilePath);
3009						}
3010					}
3011				}
3012
3013				// move new cache file to correct location for use after reboot
3014				if ( verbose )
3015					fprintf(stderr, "update_dyld_shared_cache: atomically moving cache file into place: %s\n", fCacheFilePath);
3016				result = ::rename(tempCachePath, fCacheFilePath);
3017				if ( result != 0 )
3018					throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath, fCacheFilePath, errno);
3019
3020
3021				// flush everything to disk to assure rename() gets recorded
3022				sync_volume(fCacheFilePath);
3023				didUpdate = true;
3024
3025				// restore default signal handlers
3026				::signal(SIGINT, SIG_DFL);
3027				::signal(SIGBUS, SIG_DFL);
3028				::signal(SIGSEGV, SIG_DFL);
3029
3030				// generate human readable "map" file that shows the layout of the cache file
3031				if ( verbose )
3032					fprintf(stderr, "update_dyld_shared_cache: writing .map file to disk\n");
3033				char mapFilePath[strlen(fCacheFilePath)+16];
3034				sprintf(mapFilePath, "%s.map", fCacheFilePath);
3035				char tempMapFilePath[strlen(fCacheFilePath)+32];
3036				sprintf(tempMapFilePath, "%s.map%u", fCacheFilePath, getpid());
3037				FILE* fmap = ::fopen(tempMapFilePath, "w");
3038				if ( fmap == NULL ) {
3039					fprintf(stderr, "can't create map file %s, errnor=%d", tempCachePath, errno);
3040				}
3041				else {
3042					for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
3043						const char* prot = "RW";
3044						if ( it->sfm_init_prot == (VM_PROT_EXECUTE|VM_PROT_READ) )
3045							prot = "EX";
3046						else if ( it->sfm_init_prot == VM_PROT_READ )
3047							prot = "RO";
3048						else if ( it->sfm_init_prot == (VM_PROT_EXECUTE|VM_PROT_WRITE|VM_PROT_READ) )
3049							prot = "WX";
3050						if ( it->sfm_size > 1024*1024 )
3051							fprintf(fmap, "mapping  %s %4lluMB 0x%0llX -> 0x%0llX\n", prot, it->sfm_size/(1024*1024),
3052																it->sfm_address, it->sfm_address+it->sfm_size);
3053						else
3054							fprintf(fmap, "mapping  %s %4lluKB 0x%0llX -> 0x%0llX\n", prot, it->sfm_size/1024,
3055																it->sfm_address, it->sfm_address+it->sfm_size);
3056					}
3057
3058					fprintf(fmap, " linkedit   %4uKB 0x%0llX -> 0x%0llX weak binding info\n",
3059								(fOffsetOfExportInfoInCombinedLinkedit-fOffsetOfWeakBindInfoInCombinedLinkedit)/1024,
3060								fLinkEditsStartAddress+fOffsetOfWeakBindInfoInCombinedLinkedit,
3061								fLinkEditsStartAddress+fOffsetOfExportInfoInCombinedLinkedit);
3062					fprintf(fmap, " linkedit   %4uKB 0x%0llX -> 0x%0llX export info\n",
3063								(fOffsetOfBindInfoInCombinedLinkedit-fOffsetOfExportInfoInCombinedLinkedit)/1024,
3064								fLinkEditsStartAddress+fOffsetOfExportInfoInCombinedLinkedit,
3065								fLinkEditsStartAddress+fOffsetOfBindInfoInCombinedLinkedit);
3066					fprintf(fmap, " linkedit   %4uKB 0x%0llX -> 0x%0llX binding info\n",
3067								(fOffsetOfLazyBindInfoInCombinedLinkedit-fOffsetOfBindInfoInCombinedLinkedit)/1024,
3068								fLinkEditsStartAddress+fOffsetOfBindInfoInCombinedLinkedit,
3069								fLinkEditsStartAddress+fOffsetOfLazyBindInfoInCombinedLinkedit);
3070					fprintf(fmap, " linkedit   %4uKB 0x%0llX -> 0x%0llX lazy binding info\n",
3071								(fOffsetOfOldSymbolTableInfoInCombinedLinkedit-fOffsetOfLazyBindInfoInCombinedLinkedit)/1024,
3072								fLinkEditsStartAddress+fOffsetOfLazyBindInfoInCombinedLinkedit,
3073								fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit);
3074					fprintf(fmap, " linkedit   %4uMB 0x%0llX -> 0x%0llX non-dyld symbol table size\n",
3075								(fSizeOfOldSymbolTableInfoInCombinedLinkedit)/(1024*1024),
3076								fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit,
3077								fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit+fSizeOfOldSymbolTableInfoInCombinedLinkedit);
3078					if ( fSizeOfFunctionStartsInCombinedLinkedit != 0 )
3079						fprintf(fmap, " linkedit   %4uKB 0x%0llX -> 0x%0llX non-dyld functions starts size\n",
3080								fSizeOfFunctionStartsInCombinedLinkedit/1024,
3081								fLinkEditsStartAddress+fOffsetOfFunctionStartsInCombinedLinkedit,
3082								fLinkEditsStartAddress+fOffsetOfFunctionStartsInCombinedLinkedit+fSizeOfFunctionStartsInCombinedLinkedit);
3083					if ( fSizeOfDataInCodeInCombinedLinkedit != 0 )
3084						fprintf(fmap, " linkedit   %4uKB 0x%0llX -> 0x%0llX non-dyld data-in-code info size\n",
3085								fSizeOfDataInCodeInCombinedLinkedit/1024,
3086								fLinkEditsStartAddress+fOffsetOfDataInCodeInCombinedLinkedit,
3087								fLinkEditsStartAddress+fOffsetOfDataInCodeInCombinedLinkedit+fSizeOfDataInCodeInCombinedLinkedit);
3088					if ( fSizeOfOldExternalRelocationsInCombinedLinkedit != 0 )
3089						fprintf(fmap, " linkedit   %4uKB 0x%0llX -> 0x%0llX non-dyld external relocs size\n",
3090								fSizeOfOldExternalRelocationsInCombinedLinkedit/1024,
3091								fLinkEditsStartAddress+fOffsetOfOldExternalRelocationsInCombinedLinkedit,
3092								fLinkEditsStartAddress+fOffsetOfOldExternalRelocationsInCombinedLinkedit+fSizeOfOldExternalRelocationsInCombinedLinkedit);
3093					fprintf(fmap, " linkedit   %4uKB 0x%0llX -> 0x%0llX non-dyld indirect symbol table size\n",
3094								fSizeOfOldIndirectSymbolsInCombinedLinkedit/1024,
3095								fLinkEditsStartAddress+fOffsetOfOldIndirectSymbolsInCombinedLinkedit,
3096								fLinkEditsStartAddress+fOffsetOfOldIndirectSymbolsInCombinedLinkedit+fSizeOfOldIndirectSymbolsInCombinedLinkedit);
3097					fprintf(fmap, " linkedit   %4uMB 0x%0llX -> 0x%0llX non-dyld string pool\n",
3098								(fSizeOfOldStringPoolInCombinedLinkedit)/(1024*1024),
3099								fLinkEditsStartAddress+fOffsetOfOldStringPoolInCombinedLinkedit,
3100								fLinkEditsStartAddress+fOffsetOfOldStringPoolInCombinedLinkedit+fSizeOfOldStringPoolInCombinedLinkedit);
3101
3102					dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
3103					if ( cacheHeader->slideInfoSize() != 0 ) {
3104						fprintf(fmap, " linkedit   %4lluKB kernel slide info\n", (cacheHeader->slideInfoSize())/1024);
3105					}
3106
3107					fprintf(fmap, "unmapped -- %4uMB local symbol info\n", fUnmappedLocalSymbolsSize/(1024*1024));
3108
3109					uint64_t endMappingAddr = fMappings[2].sfm_address + fMappings[2].sfm_size;
3110					fprintf(fmap, "total map   %4lluMB\n", (endMappingAddr - sharedRegionStartAddress())/(1024*1024));
3111					if ( sharedRegionStartWritableAddress(0) == 0x7FFF70000000LL ) {
3112						// x86_64 has different slide constraints
3113						uint64_t freeSpace = 256*1024*1024 - fMappings[1].sfm_size;
3114						fprintf(fmap, "r/w space   %4lluMB -> %d bits of entropy for ASLR\n\n", freeSpace/(1024*1024), (int)log2(freeSpace/4096));
3115					}
3116					else {
3117						uint64_t freeSpace = sharedRegionStartAddress() + sharedRegionSize() - endMappingAddr;
3118						fprintf(fmap, "free space  %4lluMB -> %d bits of entropy for ASLR\n\n", freeSpace/(1024*1024), (int)log2(freeSpace/4096));
3119					}
3120
3121					for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
3122						fprintf(fmap, "%s\n", it->layout->getID().name);
3123						for (std::vector<const char*>::const_iterator ait = it->aliases.begin(); ait != it->aliases.end(); ++ait)
3124							fprintf(fmap, "%s\n", *ait);
3125						const std::vector<MachOLayoutAbstraction::Segment>&	segs = it->layout->getSegments();
3126						for (int i=0; i < segs.size(); ++i) {
3127							const MachOLayoutAbstraction::Segment& seg = segs[i];
3128							fprintf(fmap, "\t%16s 0x%0llX -> 0x%0llX\n", seg.name(), seg.newAddress(), seg.newAddress()+seg.size());
3129						}
3130					}
3131					if ( warnings.size() > 0 ) {
3132						fprintf(fmap, "# Warnings:\n");
3133						for (std::vector<const char*>::iterator it=warnings.begin(); it != warnings.end(); ++it) {
3134							fprintf(fmap, "# %s\n", *it);
3135						}
3136					}
3137					fclose(fmap);
3138					result = ::rename(tempMapFilePath, mapFilePath);
3139				}
3140			}
3141
3142			// free in memory cache
3143			vm_deallocate(mach_task_self(), (vm_address_t)inMemoryCache, allocatedCacheSize);
3144			inMemoryCache = NULL;
3145			if ( progress ) {
3146				// finished
3147				fprintf(stdout, "%3u/%u\n", (archIndex+1)*100, archCount*100);
3148			}
3149		}
3150		catch (...){
3151			// remove temp cache file
3152			::unlink(tempCachePath);
3153			// remove in memory cache
3154			if ( inMemoryCache != NULL )
3155				vm_deallocate(mach_task_self(), (vm_address_t)inMemoryCache, allocatedCacheSize);
3156			throw;
3157		}
3158	}
3159	return didUpdate;
3160}
3161
3162
3163
3164//
3165//	The shared cache is driven by /var/db/dyld/shared_region_roots which contains
3166//	the paths used to search for dylibs that should go in the shared cache
3167//
3168//	Leading and trailing white space is ignored
3169//	Blank lines are ignored
3170//	Lines starting with # are ignored
3171//
3172static void parsePathsFile(const char* filePath, std::vector<const char*>& paths)
3173{
3174	// read in whole file
3175	int fd = open(filePath, O_RDONLY, 0);
3176	if ( fd == -1 ) {
3177		fprintf(stderr, "update_dyld_shared_cache: can't open file: %s\n", filePath);
3178		exit(1);
3179	}
3180	struct stat stat_buf;
3181	fstat(fd, &stat_buf);
3182	char* p = (char*)malloc(stat_buf.st_size);
3183	if ( p == NULL ) {
3184		fprintf(stderr, "update_dyld_shared_cache: malloc failure\n");
3185		exit(1);
3186	}
3187	if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) {
3188		fprintf(stderr, "update_dyld_shared_cache: can't read file: %s\n", filePath);
3189		exit(1);
3190	}
3191	::close(fd);
3192
3193	// parse into paths and add to vector
3194	char * const end = &p[stat_buf.st_size];
3195	enum { lineStart, inSymbol, inComment } state = lineStart;
3196	char* symbolStart = NULL;
3197	for (char* s = p; s < end; ++s ) {
3198		switch ( state ) {
3199			case lineStart:
3200				if ( *s =='#' ) {
3201					state = inComment;
3202				}
3203				else if ( !isspace(*s) ) {
3204					state = inSymbol;
3205					symbolStart = s;
3206				}
3207				break;
3208			case inSymbol:
3209				if ( *s == '\n' ) {
3210					*s = '\0';
3211					// removing any trailing spaces
3212					char* last = s-1;
3213					while ( isspace(*last) ) {
3214						*last = '\0';
3215						--last;
3216					}
3217					paths.push_back(symbolStart);
3218					symbolStart = NULL;
3219					state = lineStart;
3220				}
3221				break;
3222			case inComment:
3223				if ( *s == '\n' )
3224					state = lineStart;
3225				break;
3226		}
3227	}
3228	// Note: we do not free() the malloc buffer, because the strings in it are used by exec()
3229}
3230
3231
3232
3233static void setSharedDylibs(const char* rootPath, const std::vector<const char*>& overlayPaths, const std::set<ArchPair>& onlyArchs, std::vector<const char*> rootsPaths)
3234{
3235	// set file system root
3236	ArchGraph::setFileSystemRoot(rootPath);
3237	ArchGraph::setFileSystemOverlay(overlayPaths);
3238
3239	// initialize all architectures requested
3240	for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a)
3241		ArchGraph::addArchPair(*a);
3242
3243	// add roots to graph
3244	for(std::vector<const char*>::const_iterator it = rootsPaths.begin(); it != rootsPaths.end(); ++it)
3245		ArchGraph::addRoot(*it, onlyArchs);
3246
3247	// determine shared dylibs
3248	for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a)
3249		ArchGraph::findSharedDylibs(*a);
3250}
3251
3252
3253static void scanForSharedDylibs(const char* rootPath, const std::vector<const char*>& overlayPaths, const char* dirOfPathFiles, const std::set<ArchPair>& onlyArchs)
3254{
3255	char rootDirOfPathFiles[strlen(rootPath)+strlen(dirOfPathFiles)+2];
3256	// in -root mode, look for roots in /rootpath/var/db/dyld
3257	if ( rootPath[0] != '\0' ) {
3258		strcpy(rootDirOfPathFiles, rootPath);
3259		strcat(rootDirOfPathFiles, dirOfPathFiles);
3260		dirOfPathFiles = rootDirOfPathFiles;
3261	}
3262
3263	// extract all root paths from files in "/var/db/dyld/shared_region_roots/"
3264	if ( verbose )
3265		fprintf(stderr, "update_dyld_shared_cache: finding roots in: %s\n", dirOfPathFiles);
3266	std::vector<const char*> rootsPaths;
3267	DIR* dir = ::opendir(dirOfPathFiles);
3268	if ( dir == NULL )
3269		throwf("%s does not exist, errno=%d\n", dirOfPathFiles, errno);
3270	for (dirent* entry = ::readdir(dir); entry != NULL; entry = ::readdir(dir)) {
3271		if ( entry->d_type == DT_REG || entry->d_type == DT_UNKNOWN ) {
3272			// only look at regular files ending in .paths
3273			if ( strcmp(&entry->d_name[entry->d_namlen-6], ".paths") == 0 ) {
3274				struct stat tmpStatPathsFile;
3275				char fullPath[strlen(dirOfPathFiles)+entry->d_namlen+2];
3276				strcpy(fullPath, dirOfPathFiles);
3277				strcat(fullPath, "/");
3278				strcat(fullPath, entry->d_name);
3279				if ( lstat(fullPath, &tmpStatPathsFile) == -1 ) {
3280					fprintf(stderr, "update_dyld_shared_cache: can't access %s\n", fullPath);
3281				}
3282				else if ( S_ISREG(tmpStatPathsFile.st_mode) ) {
3283					parsePathsFile(fullPath, rootsPaths);
3284				}
3285				else {
3286					fprintf(stderr, "update_dyld_shared_cache: wrong file type for %s\n", fullPath);
3287				}
3288			}
3289			else {
3290				fprintf(stderr, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry->d_name);
3291			}
3292		}
3293	}
3294	::closedir(dir);
3295
3296	if ( rootsPaths.size() == 0 )
3297		fprintf(stderr, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
3298	setSharedDylibs(rootPath, overlayPaths, onlyArchs, rootsPaths);
3299}
3300
3301static void setSharedDylibs(const char* rootPath, const std::vector<const char*>& overlayPaths, const char* pathsFile, const std::set<ArchPair>& onlyArchs)
3302{
3303	std::vector<const char*> rootsPaths;
3304	parsePathsFile(pathsFile, rootsPaths);
3305	setSharedDylibs(rootPath, overlayPaths, onlyArchs, rootsPaths);
3306}
3307
3308
3309// If the 10.5.0 version of update_dyld_shared_cache was killed or crashed, it
3310// could leave large half written cache files laying around.  The function deletes
3311// those files.  To prevent the deletion of tmp files being created by another
3312// copy of update_dyld_shared_cache, it only deletes the temp cache file if its
3313// creation time was before the last restart of this machine.
3314static void deleteOrphanTempCacheFiles()
3315{
3316	DIR* dir = ::opendir(MACOSX_DYLD_SHARED_CACHE_DIR);
3317	if ( dir != NULL ) {
3318		std::vector<const char*> filesToDelete;
3319		for (dirent* entry = ::readdir(dir); entry != NULL; entry = ::readdir(dir)) {
3320			if ( entry->d_type == DT_REG ) {
3321				// only look at files with .tmp in name
3322				if ( strstr(entry->d_name, ".tmp") != NULL ) {
3323					char fullPath[strlen(MACOSX_DYLD_SHARED_CACHE_DIR)+entry->d_namlen+2];
3324					strcpy(fullPath, MACOSX_DYLD_SHARED_CACHE_DIR);
3325					strcat(fullPath, "/");
3326					strcat(fullPath, entry->d_name);
3327					struct stat tmpFileStatInfo;
3328					if ( stat(fullPath, &tmpFileStatInfo) != -1 ) {
3329						int mib[2] = {CTL_KERN, KERN_BOOTTIME};
3330						struct timeval boottime;
3331						size_t size = sizeof(boottime);
3332						if ( (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1) && (boottime.tv_sec != 0) ) {
3333							// make sure this file is older than the boot time of this machine
3334							if ( tmpFileStatInfo.st_mtime < boottime.tv_sec ) {
3335								filesToDelete.push_back(strdup(fullPath));
3336							}
3337						}
3338					}
3339				}
3340			}
3341		}
3342		::closedir(dir);
3343		for(std::vector<const char*>::iterator it = filesToDelete.begin(); it != filesToDelete.end(); ++it) {
3344			fprintf(stderr, "update_dyld_shared_cache: deleting old temp cache file: %s\n", *it);
3345			::unlink(*it);
3346		}
3347	}
3348}
3349
3350
3351
3352static bool updateSharedeCacheFile(const char* rootPath, const std::vector<const char*>& overlayPaths, const char* cacheDir, bool explicitCacheDir, const std::set<ArchPair>& onlyArchs,
3353									bool force, bool alphaSort, bool optimize, bool deleteExistingFirst, bool verify, bool keepSignatures, bool dontMapLocalSymbols)
3354{
3355	bool didUpdate = false;
3356	// get dyld load address info
3357	UniversalMachOLayout* dyldLayout = NULL;
3358	char dyldPath[1024];
3359	strlcpy(dyldPath, rootPath, 1024);
3360	strlcat(dyldPath, "/usr/lib/dyld", 1024);
3361	struct stat stat_buf;
3362	if ( stat(dyldPath, &stat_buf) == 0 ) {
3363		dyldLayout = new UniversalMachOLayout(dyldPath, &onlyArchs);
3364	}
3365	else {
3366		dyldLayout = new UniversalMachOLayout("/usr/lib/dyld", &onlyArchs);
3367	}
3368	const int archCount = onlyArchs.size();
3369	int index = 0;
3370	for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a, ++index) {
3371		const MachOLayoutAbstraction* dyldLayoutForArch = dyldLayout->getSlice(*a);
3372		uint64_t dyldBaseAddress = 0;
3373		if ( dyldLayoutForArch != NULL )
3374			dyldBaseAddress = dyldLayoutForArch->getBaseAddress();
3375		else
3376			fprintf(stderr, "update_dyld_shared_cache: warning, dyld not available for specified architectures\n");
3377		switch ( a->arch ) {
3378			case CPU_TYPE_I386:
3379				{
3380					SharedCache<x86> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPaths, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
3381					didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures, dontMapLocalSymbols);
3382				}
3383				break;
3384			case CPU_TYPE_X86_64:
3385				{
3386					SharedCache<x86_64> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPaths, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
3387					didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures, dontMapLocalSymbols);
3388				}
3389				break;
3390			case CPU_TYPE_ARM:
3391				{
3392					SharedCache<arm> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPaths, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
3393					didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures, dontMapLocalSymbols);
3394				}
3395				break;
3396			case CPU_TYPE_ARM64:
3397				{
3398					SharedCache<arm64> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPaths, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
3399					didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures, dontMapLocalSymbols);
3400				}
3401				break;
3402		}
3403	}
3404
3405	if ( !iPhoneOS )
3406		deleteOrphanTempCacheFiles();
3407
3408	return didUpdate;
3409}
3410
3411
3412static void usage()
3413{
3414	fprintf(stderr, "update_dyld_shared_cache [-force] [-root dir] [-overlay dir] [-arch arch] [-debug]\n");
3415}
3416
3417
3418int main(int argc, const char* argv[])
3419{
3420	std::set<ArchPair> onlyArchs;
3421	const char* rootPath = "";
3422	std::vector<const char*> overlayPaths;
3423	const char* dylibListFile = NULL;
3424	bool force = false;
3425	bool alphaSort = false;
3426	bool optimize = true;
3427	bool verify = false;
3428	bool keepSignatures = false;
3429	bool explicitCacheDir = false;
3430	bool dontMapLocalSymbols = false;
3431	bool relaunchForHaswell = false;
3432	const char* cacheDir = NULL;
3433
3434	try {
3435		// parse command line options
3436		for(int i=1; i < argc; ++i) {
3437			const char* arg = argv[i];
3438			if ( arg[0] == '-' ) {
3439				if ( strcmp(arg, "-debug") == 0 ) {
3440					verbose = true;
3441				}
3442				else if ( strcmp(arg, "-force") == 0 ) {
3443					force = true;
3444				}
3445				else if ( strcmp(arg, "-verify") == 0 ) {
3446					verify = true;
3447				}
3448				else if ( strcmp(arg, "-sort_by_name") == 0 ) {
3449					alphaSort = true;
3450				}
3451				else if ( strcmp(arg, "-progress") == 0 ) {
3452					progress = true;
3453				}
3454				else if ( strcmp(arg, "-opt") == 0 ) {
3455					optimize = true;
3456				}
3457				else if ( strcmp(arg, "-no_opt") == 0 ) {
3458					optimize = false;
3459				}
3460				else if ( strcmp(arg, "-dont_map_local_symbols") == 0 ) {
3461					dontMapLocalSymbols = true;
3462				}
3463				else if ( strcmp(arg, "-iPhone") == 0 ) {
3464					iPhoneOS = true;
3465					alphaSort = true;
3466				}
3467				else if ( strcmp(arg, "-dylib_list") == 0 ) {
3468					dylibListFile = argv[++i];
3469					if ( dylibListFile == NULL )
3470						throw "-dylib_list missing path argument";
3471				}
3472				else if ( (strcmp(arg, "-root") == 0) || (strcmp(arg, "--root") == 0) ) {
3473					rootPath = argv[++i];
3474					if ( rootPath == NULL )
3475						throw "-root missing path argument";
3476				}
3477				else if ( strcmp(arg, "-overlay") == 0 ) {
3478					const char* path = argv[++i];
3479					if ( path == NULL )
3480						throw "-overlay missing path argument";
3481					overlayPaths.push_back(path);
3482				}
3483				else if ( strcmp(arg, "-cache_dir") == 0 ) {
3484					cacheDir = argv[++i];
3485					if ( cacheDir == NULL )
3486						throw "-cache_dir missing path argument";
3487					explicitCacheDir = true;
3488				}
3489				else if ( strcmp(arg, "-arch") == 0 ) {
3490					const char* arch = argv[++i];
3491					if ( strcmp(arch, "i386") == 0 )
3492						onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
3493					else if ( strcmp(arch, "x86_64") == 0 )
3494						onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
3495					else if ( strcmp(arch, "x86_64h") == 0 )
3496						onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H));
3497					else if ( strcmp(arch, "armv4t") == 0 )
3498						onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V4T));
3499					else if ( strcmp(arch, "armv5") == 0 )
3500						onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V5TEJ));
3501					else if ( strcmp(arch, "armv6") == 0 )
3502						onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6));
3503					else if ( strcmp(arch, "armv7") == 0 )
3504						onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7));
3505					else if ( strcmp(arch, "armv7f") == 0 )
3506						onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7F));
3507					else if ( strcmp(arch, "armv7k") == 0 )
3508						onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7K));
3509					else if ( strcmp(arch, "armv7s") == 0 )
3510						onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S));
3511					else if ( strcmp(arch, "arm64") == 0 )
3512						onlyArchs.insert(ArchPair(CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL));
3513					else
3514						throwf("unknown architecture %s", arch);
3515				}
3516				else if ( strcmp(arg, "-universal_boot") == 0 ) {
3517					onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
3518					onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
3519					relaunchForHaswell = true;
3520				}
3521				else {
3522					usage();
3523					throwf("unknown option: %s\n", arg);
3524				}
3525			}
3526			else {
3527				usage();
3528				throwf("unknown option: %s\n", arg);
3529			}
3530		}
3531
3532		// strip tailing slashes on -root
3533		// make it a real path so as to not make all dylibs look like symlink aliases
3534		if ( rootPath[0] != '\0' ) {
3535			char realRootPath[MAXPATHLEN];
3536			if ( realpath(rootPath, realRootPath) == NULL )
3537				throwf("realpath() failed on %s\n", rootPath);
3538			rootPath = strdup(realRootPath);
3539		}
3540
3541		// strip tailing slashes on -overlay
3542		for (std::vector<const char*>::iterator it=overlayPaths.begin(); it != overlayPaths.end(); ++it) {
3543			char realOverlayPath[MAXPATHLEN];
3544			if ( realpath(*it, realOverlayPath) == NULL )
3545				throwf("realpath() failed on %s\n", *it);
3546			*it = strdup(realOverlayPath);
3547		}
3548
3549		// set default location to write cache dir
3550		if ( cacheDir == NULL )
3551			cacheDir = (iPhoneOS ? IPHONE_DYLD_SHARED_CACHE_DIR : MACOSX_DYLD_SHARED_CACHE_DIR);
3552
3553		// if no restrictions specified, use architectures that work on this machine
3554		if ( onlyArchs.size() == 0 ) {
3555			if ( iPhoneOS ) {
3556				onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6));
3557				onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7));
3558			}
3559			else {
3560				int available;
3561				size_t len = sizeof(int);
3562			#if __i386__ || __x86_64__
3563				onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
3564				// check system is capable of running 64-bit programs
3565				if ( (sysctlbyname("hw.optional.x86_64", &available, &len, NULL, 0) == 0) && available ) {
3566					// check system is capable of running x86_64h code
3567					struct host_basic_info info;
3568					mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
3569					mach_port_t hostPort = mach_host_self();
3570					kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count);
3571					mach_port_deallocate(mach_task_self(), hostPort);
3572					if ( result != KERN_SUCCESS )
3573						throw "host_info() failed";
3574					if ( info.cpu_subtype == CPU_SUBTYPE_X86_64_H )
3575						onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H));
3576					else
3577						onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_ALL));
3578				}
3579			#else
3580				#error unsupported architecture
3581			#endif
3582			}
3583		}
3584
3585		if ( !verify && (geteuid() != 0) )
3586			throw "you must be root to run this tool";
3587
3588		// build list of shared dylibs
3589		if ( dylibListFile != NULL )
3590			setSharedDylibs(rootPath, overlayPaths, dylibListFile, onlyArchs);
3591		else
3592			scanForSharedDylibs(rootPath, overlayPaths, "/var/db/dyld/shared_region_roots/", onlyArchs);
3593		bool didUpdate = updateSharedeCacheFile(rootPath, overlayPaths, cacheDir, explicitCacheDir, onlyArchs, force, alphaSort, optimize,
3594								false, verify, keepSignatures, dontMapLocalSymbols);
3595
3596		if ( didUpdate && !iPhoneOS ) {
3597			void* handle = dlopen("/usr/lib/libspindump.dylib", RTLD_LAZY);
3598			if ( handle != NULL ) {
3599				typedef bool (*dscsym_proc_t)(const char *root);
3600				dscsym_proc_t proc = (dscsym_proc_t)dlsym(handle, "dscsym_save_nuggets_for_current_caches");
3601				const char* nuggetRootPath = "/";
3602				if ( !overlayPaths.empty() )
3603					nuggetRootPath = overlayPaths[0];
3604				else if ( rootPath[0] != '\0' )
3605					nuggetRootPath = rootPath;
3606				(*proc)(nuggetRootPath);
3607			}
3608			dlclose(handle);
3609		}
3610
3611		if ( relaunchForHaswell ) {
3612			char cmd[2048];
3613			strlcpy(cmd, argv[0], 2048);
3614			strlcat(cmd, " -arch x86_64h", 2048);
3615			if ( force )
3616				strlcat(cmd, " -force", 2048);
3617			if ( verify )
3618				strlcat(cmd, " -verify", 2048);
3619			if ( alphaSort )
3620				strlcat(cmd, " -sort_by_name", 2048);
3621			if ( (rootPath != NULL) && (rootPath[0] != '\0') ) {
3622				strlcat(cmd, " -root ", 2048);
3623				strlcat(cmd, rootPath, 2048);
3624			}
3625			return system(cmd);
3626		}
3627
3628	}
3629	catch (const char* msg) {
3630		fprintf(stderr, "update_dyld_shared_cache failed: %s\n", msg);
3631		return 1;
3632	}
3633
3634	return 0;
3635}
3636
3637
3638
3639