2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 namespace ObjectFileDylibMachO
{
28 class Reader
: public ObjectFile::Reader
31 Reader(const macho_header
* header
, const char* path
, const ObjectFile::ReaderOptions
& options
);
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
&);
47 struct CStringComparor
49 bool operator()(const char* left
, const char* right
) { return (strcmp(left
, right
) > 0); }
51 typedef std::map
<const char*, ObjectFile::Atom
*, CStringComparor
> Mapper
;
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
);
61 const macho_header
* fHeader
;
63 const macho_dysymtab_command
* fDynamicInfo
;
64 const macho_dylib_command
* fDylibID
;
65 const macho_nlist
* fSymbols
;
66 uint32_t fSymbolCount
;
68 std::vector
<Reader
*> fReExportedDylibs
;
70 static std::vector
<class ObjectFile::Atom
*> fEmptyAtomList
;
73 std::vector
<class ObjectFile::Atom
*> Reader::fEmptyAtomList
;
76 class Segment
: public ObjectFile::Segment
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; }
89 class ExportAtom
: public ObjectFile::Atom
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 {}
117 virtual void setScope(Scope
) { }
118 virtual void setImportWeakness(bool weakImport
) { fWeakImportSetting
= weakImport
? kWeakImport
: kNonWeakImport
; }
123 ExportAtom(Reader
& owner
, const char* name
) : fOwner(owner
), fName(name
), fWeakImportSetting(kWeakUnset
) {}
124 virtual ~ExportAtom() {}
128 WeakImportSetting fWeakImportSetting
;
130 static std::vector
<ObjectFile::Reference
*> fgEmptyReferenceList
;
131 static Segment fgImportSegment
;
134 Segment
ExportAtom::fgImportSegment("__LINKEDIT");
135 std::vector
<ObjectFile::Reference
*> ExportAtom::fgEmptyReferenceList
;
137 const char* ExportAtom::getDisplayName() const
139 static char temp
[300];
141 strcat(temp
, "$import");
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)
150 typedef std::pair
<const macho_dylib_command
*, bool> DylibAndReExportFlag
;
151 std::vector
<DylibAndReExportFlag
> dependentDylibs
;
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()) {
161 case LC_LOAD_WEAK_DYLIB
:
163 DylibAndReExportFlag info
;
164 info
.first
= (struct macho_dylib_command
*)cmd
;
165 info
.second
= options
.fFlatNamespace
;
166 dependentDylibs
.push_back(info
);
170 cmd
= (const macho_load_command
*)(((char*)cmd
)+cmd
->cmdsize());
173 // cache interesting pointers
175 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
176 switch (cmd
->cmd()) {
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();
186 fDynamicInfo
= (macho_dysymtab_command
*)cmd
;
189 fDylibID
= (macho_dylib_command
*)cmd
;
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) )
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 )
221 cmd
= (const macho_load_command
*)(((char*)cmd
)+cmd
->cmdsize());
224 // load dylibs we need to re-export
225 for (std::vector
<DylibAndReExportFlag
>::iterator it
= dependentDylibs
.begin(); it
!= dependentDylibs
.end(); it
++) {
227 // printf("%s need to re-export %s\n", path, it->first->name());
228 //fReExportedDylibs.push_back(
238 const char* Reader::getPath()
244 std::vector
<class ObjectFile::Atom
*>& Reader::getAtoms()
246 return fEmptyAtomList
;
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
)
254 int32_t high
= symbolCount
-1;
255 int32_t mid
= symbolCount
/2;
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
);
277 const macho_nlist
* Reader::binarySearch(const char* key
, const char stringPool
[], const macho_nlist symbols
[], uint32_t symbolCount
)
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
);
288 // move base to symbol after pivot
300 const macho_nlist
* Reader::findExport(const char* name
)
302 if ( fDynamicInfo
->tocoff() == 0 )
303 return binarySearch(name
, fStrings
, &fSymbols
[fDynamicInfo
->iextdefsym()], fDynamicInfo
->nextdefsym());
305 return binarySearchWithToc(name
, fStrings
, fSymbols
, (dylib_table_of_contents
*)((char*)fHeader
+ fDynamicInfo
->tocoff()),
306 fDynamicInfo
->nextdefsym());
310 bool Reader::hasExport(const char* name
)
312 return ( findExport(name
) != NULL
);
315 std::vector
<class ObjectFile::Atom
*>* Reader::getJustInTimeAtomsFor(const char* name
)
317 std::vector
<class ObjectFile::Atom
*>* atoms
= NULL
;
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() ) {
327 atom
= new ExportAtom(*this, name
);
330 // return a vector of one atom
331 atoms
= new std::vector
<class ObjectFile::Atom
*>;
332 atoms
->push_back(atom
);
337 for (std::vector
<Reader
*>::iterator it
= fReExportedDylibs
.begin(); it
!= fReExportedDylibs
.end(); it
++) {
338 Reader
* reExportedReader
= *it
;
339 atoms
= reExportedReader
->getJustInTimeAtomsFor(name
);
348 std::vector
<ObjectFile::StabsInfo
>* Reader::getStabsDebugInfo()
353 const char* Reader::getInstallPath()
355 return fDylibID
->name();
358 uint32_t Reader::getTimestamp()
360 return fDylibID
->timestamp();
363 uint32_t Reader::getCurrentVersion()
365 return fDylibID
->current_version();
368 uint32_t Reader::getCompatibilityVersion()
370 return fDylibID
->compatibility_version();
373 std::vector
<const char*>* Reader::getDependentLibraryPaths()
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()) {
382 case LC_LOAD_WEAK_DYLIB
:
384 result
->push_back(((struct macho_dylib_command
*)cmd
)->name());
388 cmd
= (const macho_load_command
*)(((char*)cmd
)+cmd
->cmdsize());
393 bool Reader::reExports(ObjectFile::Reader
* child
)
395 // A dependent dylib is re-exported under two conditions:
396 // 1) parent contains LC_SUB_UMBRELLA or LC_SUB_LIBRARY with child name
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
:
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) )
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 )
429 cmd
= (const macho_load_command
*)(((char*)cmd
)+cmd
->cmdsize());
433 // 2) child contains LC_SUB_FRAMEWORK with parent name
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
:
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) )
450 cmd
= (const macho_load_command
*)(((char*)cmd
)+cmd
->cmdsize());
458 bool Reader::isDefinitionWeak(const ObjectFile::Atom
& atom
)
460 const macho_nlist
* sym
= findExport(atom
.getName());
462 if ( (sym
->n_desc() & N_WEAK_DEF
) != 0 )
470 Reader
* MakeReader(const macho_header
* mh
, const char* path
, const ObjectFile::ReaderOptions
& options
)
472 return new Reader(mh
, path
, options
);