]> git.saurik.com Git - apple/ld64.git/blob - src/Readers/ObjectFileDylibMachO.cpp
ld64-21.tar.gz
[apple/ld64.git] / src / Readers / ObjectFileDylibMachO.cpp
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25
26 namespace ObjectFileDylibMachO {
27
28 class Reader : public ObjectFile::Reader
29 {
30 public:
31 Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options);
32 virtual ~Reader();
33
34 virtual const char* getPath();
35 virtual std::vector<class ObjectFile::Atom*>& getAtoms();
36 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name);
37 virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo();
38 virtual const char* getInstallPath();
39 virtual uint32_t getTimestamp();
40 virtual uint32_t getCurrentVersion();
41 virtual uint32_t getCompatibilityVersion();
42 virtual std::vector<const char*>* getDependentLibraryPaths();
43 virtual bool reExports(ObjectFile::Reader*);
44 virtual bool isDefinitionWeak(const ObjectFile::Atom&);
45
46 private:
47 struct CStringComparor
48 {
49 bool operator()(const char* left, const char* right) { return (strcmp(left, right) > 0); }
50 };
51 typedef std::map<const char*, ObjectFile::Atom*, CStringComparor> Mapper;
52
53
54 void init(const macho_header* header,const char* path);
55 const macho_nlist* binarySearchWithToc(const char* key, const char stringPool[], const macho_nlist symbols[], const struct dylib_table_of_contents toc[], uint32_t symbolCount);
56 const macho_nlist* binarySearch(const char* key, const char stringPool[], const macho_nlist symbols[], uint32_t symbolCount);
57 bool hasExport(const char* name);
58 const macho_nlist* findExport(const char* name);
59
60 const char* fPath;
61 const macho_header* fHeader;
62 const char* fStrings;
63 const macho_dysymtab_command* fDynamicInfo;
64 const macho_dylib_command* fDylibID;
65 const macho_nlist* fSymbols;
66 uint32_t fSymbolCount;
67 Mapper fAtoms;
68 std::vector<Reader*> fReExportedDylibs;
69
70 static std::vector<class ObjectFile::Atom*> fEmptyAtomList;
71 };
72
73 std::vector<class ObjectFile::Atom*> Reader::fEmptyAtomList;
74
75
76 class Segment : public ObjectFile::Segment
77 {
78 public:
79 Segment(const char* name) { fName = name; }
80 virtual const char* getName() const { return fName; }
81 virtual bool isContentReadable() const { return true; }
82 virtual bool isContentWritable() const { return false; }
83 virtual bool isContentExecutable() const { return false; }
84 private:
85 const char* fName;
86 };
87
88
89 class ExportAtom : public ObjectFile::Atom
90 {
91 public:
92 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
93 virtual const char* getName() const { return fName; }
94 virtual const char* getDisplayName() const;
95 virtual Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
96 virtual bool isTentativeDefinition() const { return false; }
97 virtual bool isWeakDefinition() const { return false; }
98 virtual bool isCoalesableByName() const { return false; }
99 virtual bool isCoalesableByValue() const { return false; }
100 virtual bool isZeroFill() const { return false; }
101 virtual bool dontDeadStrip() const { return false; }
102 virtual bool dontStripName() const { return false; }
103 virtual bool isImportProxy() const { return true; }
104 virtual uint64_t getSize() const { return 0; }
105 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
106 virtual bool mustRemainInSection() const { return false; }
107 virtual const char* getSectionName() const { return "._imports"; }
108 virtual Segment& getSegment() const { return fgImportSegment; }
109 virtual bool requiresFollowOnAtom() const{ return false; }
110 virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
111 virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo() const { return NULL; }
112 virtual uint8_t getAlignment() const { return 0; }
113 virtual WeakImportSetting getImportWeakness() const { return fWeakImportSetting; }
114 virtual void copyRawContent(uint8_t buffer[]) const {}
115 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
116
117 virtual void setScope(Scope) { }
118 virtual void setImportWeakness(bool weakImport) { fWeakImportSetting = weakImport ? kWeakImport : kNonWeakImport; }
119
120 protected:
121 friend class Reader;
122
123 ExportAtom(Reader& owner, const char* name) : fOwner(owner), fName(name), fWeakImportSetting(kWeakUnset) {}
124 virtual ~ExportAtom() {}
125
126 Reader& fOwner;
127 const char* fName;
128 WeakImportSetting fWeakImportSetting;
129
130 static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
131 static Segment fgImportSegment;
132 };
133
134 Segment ExportAtom::fgImportSegment("__LINKEDIT");
135 std::vector<ObjectFile::Reference*> ExportAtom::fgEmptyReferenceList;
136
137 const char* ExportAtom::getDisplayName() const
138 {
139 static char temp[300];
140 strcpy(temp, fName);
141 strcat(temp, "$import");
142 return temp;
143 }
144
145
146
147 Reader::Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options)
148 : fHeader(header), fStrings(NULL), fDylibID(NULL), fSymbols(NULL), fSymbolCount(0)
149 {
150 typedef std::pair<const macho_dylib_command*, bool> DylibAndReExportFlag;
151 std::vector<DylibAndReExportFlag> dependentDylibs;
152
153 fPath = strdup(path);
154 const uint32_t cmd_count = header->ncmds();
155 const macho_load_command* const cmds = (macho_load_command*)((char*)header + macho_header::size);
156 // get all dylib load commands
157 const macho_load_command* cmd = cmds;
158 for (uint32_t i = 0; i < cmd_count; ++i) {
159 switch (cmd->cmd()) {
160 case LC_LOAD_DYLIB:
161 case LC_LOAD_WEAK_DYLIB:
162 {
163 DylibAndReExportFlag info;
164 info.first = (struct macho_dylib_command*)cmd;
165 info.second = options.fFlatNamespace;
166 dependentDylibs.push_back(info);
167 }
168 break;
169 }
170 cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
171 }
172
173 // cache interesting pointers
174 cmd = cmds;
175 for (uint32_t i = 0; i < cmd_count; ++i) {
176 switch (cmd->cmd()) {
177 case LC_SYMTAB:
178 {
179 const macho_symtab_command* symtab = (macho_symtab_command*)cmd;
180 fSymbolCount = symtab->nsyms();
181 fSymbols = (const macho_nlist*)((char*)header + symtab->symoff());
182 fStrings = (char*)header + symtab->stroff();
183 }
184 break;
185 case LC_DYSYMTAB:
186 fDynamicInfo = (macho_dysymtab_command*)cmd;
187 break;
188 case LC_ID_DYLIB:
189 fDylibID = (macho_dylib_command*)cmd;
190 break;
191 case LC_SUB_UMBRELLA:
192 if ( !options.fFlatNamespace ) {
193 const char* frameworkLeafName = ((macho_sub_umbrella_command*)cmd)->name();
194 for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
195 const char* dylibName = it->first->name();
196 const char* lastSlash = strrchr(dylibName, '/');
197 if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
198 it->second = true;
199 }
200 }
201 break;
202 case LC_SUB_LIBRARY:
203 if ( !options.fFlatNamespace ) {
204 const char* dylibBaseName = ((macho_sub_library_command*)cmd)->name();
205 for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
206 const char* dylibName = it->first->name();
207 const char* lastSlash = strrchr(dylibName, '/');
208 const char* leafStart = &lastSlash[1];
209 if ( lastSlash == NULL )
210 leafStart = dylibName;
211 const char* firstDot = strchr(leafStart, '.');
212 int len = strlen(leafStart);
213 if ( firstDot != NULL )
214 len = firstDot - leafStart;
215 if ( strncmp(leafStart, dylibBaseName, len) == 0 )
216 it->second = true;
217 }
218 }
219 break;
220 }
221 cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
222 }
223
224 // load dylibs we need to re-export
225 for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
226 if ( it->second ) {
227 // printf("%s need to re-export %s\n", path, it->first->name());
228 //fReExportedDylibs.push_back(
229 }
230 }
231 }
232
233
234 Reader::~Reader()
235 {
236 }
237
238 const char* Reader::getPath()
239 {
240 return fPath;
241 }
242
243
244 std::vector<class ObjectFile::Atom*>& Reader::getAtoms()
245 {
246 return fEmptyAtomList;
247 }
248
249
250
251 const macho_nlist* Reader::binarySearchWithToc(const char* key, const char stringPool[], const macho_nlist symbols[],
252 const struct dylib_table_of_contents toc[], uint32_t symbolCount)
253 {
254 int32_t high = symbolCount-1;
255 int32_t mid = symbolCount/2;
256
257 for (int32_t low = 0; low <= high; mid = (low+high)/2) {
258 const uint32_t index = ENDIAN_READ32(toc[mid].symbol_index);
259 const macho_nlist* pivot = &symbols[index];
260 const char* pivotStr = &stringPool[pivot->n_strx()];
261 int cmp = strcmp(key, pivotStr);
262 if ( cmp == 0 )
263 return pivot;
264 if ( cmp > 0 ) {
265 // key > pivot
266 low = mid + 1;
267 }
268 else {
269 // key < pivot
270 high = mid - 1;
271 }
272 }
273 return NULL;
274 }
275
276
277 const macho_nlist* Reader::binarySearch(const char* key, const char stringPool[], const macho_nlist symbols[], uint32_t symbolCount)
278 {
279 const macho_nlist* base = symbols;
280 for (uint32_t n = symbolCount; n > 0; n /= 2) {
281 const macho_nlist* pivot = &base[n/2];
282 const char* pivotStr = &stringPool[pivot->n_strx()];
283 int cmp = strcmp(key, pivotStr);
284 if ( cmp == 0 )
285 return pivot;
286 if ( cmp > 0 ) {
287 // key > pivot
288 // move base to symbol after pivot
289 base = &pivot[1];
290 --n;
291 }
292 else {
293 // key < pivot
294 // keep same base
295 }
296 }
297 return NULL;
298 }
299
300 const macho_nlist* Reader::findExport(const char* name)
301 {
302 if ( fDynamicInfo->tocoff() == 0 )
303 return binarySearch(name, fStrings, &fSymbols[fDynamicInfo->iextdefsym()], fDynamicInfo->nextdefsym());
304 else {
305 return binarySearchWithToc(name, fStrings, fSymbols, (dylib_table_of_contents*)((char*)fHeader + fDynamicInfo->tocoff()),
306 fDynamicInfo->nextdefsym());
307 }
308 }
309
310 bool Reader::hasExport(const char* name)
311 {
312 return ( findExport(name) != NULL );
313 }
314
315 std::vector<class ObjectFile::Atom*>* Reader::getJustInTimeAtomsFor(const char* name)
316 {
317 std::vector<class ObjectFile::Atom*>* atoms = NULL;
318 // search exports
319 if ( this->hasExport(name) ) {
320 // see if this atom already synthesized
321 ObjectFile::Atom* atom = NULL;
322 Mapper::iterator pos = fAtoms.find(name);
323 if ( pos != fAtoms.end() ) {
324 atom = pos->second;
325 }
326 else {
327 atom = new ExportAtom(*this, name);
328 fAtoms[name] = atom;
329 }
330 // return a vector of one atom
331 atoms = new std::vector<class ObjectFile::Atom*>;
332 atoms->push_back(atom);
333 return atoms;
334 }
335
336 // check re-exports
337 for (std::vector<Reader*>::iterator it = fReExportedDylibs.begin(); it != fReExportedDylibs.end(); it++) {
338 Reader* reExportedReader = *it;
339 atoms = reExportedReader->getJustInTimeAtomsFor(name);
340 if ( atoms != NULL )
341 return atoms;
342 }
343
344 return NULL;
345 }
346
347
348 std::vector<ObjectFile::StabsInfo>* Reader::getStabsDebugInfo()
349 {
350 return NULL;
351 }
352
353 const char* Reader::getInstallPath()
354 {
355 return fDylibID->name();
356 }
357
358 uint32_t Reader::getTimestamp()
359 {
360 return fDylibID->timestamp();
361 }
362
363 uint32_t Reader::getCurrentVersion()
364 {
365 return fDylibID->current_version();
366 }
367
368 uint32_t Reader::getCompatibilityVersion()
369 {
370 return fDylibID->compatibility_version();
371 }
372
373 std::vector<const char*>* Reader::getDependentLibraryPaths()
374 {
375 std::vector<const char*>* result = new std::vector<const char*>;
376 const uint32_t cmd_count = fHeader->ncmds();
377 const macho_load_command* const cmds = (macho_load_command*)((char*)fHeader + macho_header::size);
378 const macho_load_command* cmd = cmds;
379 for (uint32_t i = 0; i < cmd_count; ++i) {
380 switch (cmd->cmd()) {
381 case LC_LOAD_DYLIB:
382 case LC_LOAD_WEAK_DYLIB:
383 {
384 result->push_back(((struct macho_dylib_command*)cmd)->name());
385 }
386 break;
387 }
388 cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
389 }
390 return result;
391 }
392
393 bool Reader::reExports(ObjectFile::Reader* child)
394 {
395 // A dependent dylib is re-exported under two conditions:
396 // 1) parent contains LC_SUB_UMBRELLA or LC_SUB_LIBRARY with child name
397 {
398 const uint32_t cmd_count = fHeader->ncmds();
399 const macho_load_command* const cmds = (macho_load_command*)((char*)fHeader + macho_header::size);
400 const macho_load_command* cmd = cmds;
401 for (uint32_t i = 0; i < cmd_count; ++i) {
402 switch (cmd->cmd()) {
403 case LC_SUB_UMBRELLA:
404 {
405 const char* frameworkLeafName = ((macho_sub_umbrella_command*)cmd)->name();
406 const char* dylibName = child->getPath();
407 const char* lastSlash = strrchr(dylibName, '/');
408 if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
409 return true;
410 }
411 break;
412 case LC_SUB_LIBRARY:
413 {
414 const char* dylibBaseName = ((macho_sub_library_command*)cmd)->name();
415 const char* dylibName = child->getPath();
416 const char* lastSlash = strrchr(dylibName, '/');
417 const char* leafStart = &lastSlash[1];
418 if ( lastSlash == NULL )
419 leafStart = dylibName;
420 const char* firstDot = strchr(leafStart, '.');
421 int len = strlen(leafStart);
422 if ( firstDot != NULL )
423 len = firstDot - leafStart;
424 if ( strncmp(leafStart, dylibBaseName, len) == 0 )
425 return true;
426 }
427 break;
428 }
429 cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
430 }
431 }
432
433 // 2) child contains LC_SUB_FRAMEWORK with parent name
434 {
435 const uint32_t cmd_count = ((Reader*)child)->fHeader->ncmds();
436 const macho_load_command* const cmds = (macho_load_command*)((char*)(((Reader*)child)->fHeader) + macho_header::size);
437 const macho_load_command* cmd = cmds;
438 for (uint32_t i = 0; i < cmd_count; ++i) {
439 switch (cmd->cmd()) {
440 case LC_SUB_FRAMEWORK:
441 {
442 const char* frameworkLeafName = ((macho_sub_framework_command*)cmd)->name();
443 const char* parentName = this->getPath();
444 const char* lastSlash = strrchr(parentName, '/');
445 if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
446 return true;
447 }
448 break;
449 }
450 cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
451 }
452 }
453
454
455 return false;
456 }
457
458 bool Reader::isDefinitionWeak(const ObjectFile::Atom& atom)
459 {
460 const macho_nlist* sym = findExport(atom.getName());
461 if ( sym != NULL ) {
462 if ( (sym->n_desc() & N_WEAK_DEF) != 0 )
463 return true;
464 }
465 return false;
466 }
467
468
469
470 Reader* MakeReader(const macho_header* mh, const char* path, const ObjectFile::ReaderOptions& options)
471 {
472 return new Reader(mh, path, options);
473 }
474
475
476
477 };
478
479
480
481
482
483
484