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