]> git.saurik.com Git - apple/ld64.git/blame - src/ld/ArchiveReader.hpp
ld64-96.5.tar.gz
[apple/ld64.git] / src / ld / ArchiveReader.hpp
CommitLineData
d696c285
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
2f2f92e4 3 * Copyright (c) 2005-2008 Apple Inc. All rights reserved.
d696c285
A
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
2f2f92e4
A
25#ifndef __OBJECT_FILE_ARCHIVE__
26#define __OBJECT_FILE_ARCHIVE__
d696c285
A
27
28#include <stdint.h>
29#include <math.h>
30#include <unistd.h>
31#include <sys/param.h>
32#include <mach-o/ranlib.h>
33#include <ar.h>
34
35#include <vector>
36#include <set>
37#include <algorithm>
38#include <ext/hash_map>
39
40#include "MachOFileAbstraction.hpp"
41#include "ObjectFile.h"
42#include "MachOReaderRelocatable.hpp"
2f2f92e4
A
43#if LTO_SUPPORT
44 #include "LTOReader.hpp"
45#endif
46
d696c285
A
47namespace archive {
48
49typedef const struct ranlib* ConstRanLibPtr;
50
51template <typename A>
52class Reader : public ObjectFile::Reader
53{
54public:
55 static bool validFile(const uint8_t* fileContent, uint64_t fileLength);
a61fdf0a
A
56 Reader(const uint8_t fileContent[], uint64_t fileLength,
57 const char* path, time_t modTime,
55e3d2f6 58 const LibraryOptions& archiveOptions,
a61fdf0a 59 const ObjectFile::ReaderOptions& options, uint32_t ordinalBase);
d696c285
A
60 virtual ~Reader() {}
61
62 virtual const char* getPath() { return fPath; }
a61fdf0a 63 virtual time_t getModificationTime(){ return fModTime; }
d696c285
A
64 virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; }
65 virtual std::vector<class ObjectFile::Atom*>& getAtoms();
66 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name);
67 virtual std::vector<Stab>* getStabs() { return NULL; }
55e3d2f6
A
68 virtual bool optimize(const std::vector<ObjectFile::Atom*>&, std::vector<ObjectFile::Atom*>&,
69 std::vector<const char*>&, const std::set<ObjectFile::Atom*>&,
70 std::vector<ObjectFile::Atom*>& newDeadAtoms,
71 uint32_t, ObjectFile::Reader* writer,
72 ObjectFile::Atom* entryPointAtom,
73 const std::vector<const char*>& llvmOptions,
2f2f92e4
A
74 bool allGlobalsAReDeadStripRoots, int okind,
75 bool verbose, bool saveTemps, const char* outputFilePath,
76 bool pie, bool allowTextRelocs);
d696c285
A
77
78private:
2f2f92e4
A
79 static bool validMachOFile(const uint8_t* fileContent, uint64_t fileLength);
80 static bool validLTOFile(const uint8_t* fileContent, uint64_t fileLength);
81 static cpu_type_t architecture();
82
83
d696c285
A
84 class Entry : ar_hdr
85 {
86 public:
87 const char* getName() const;
88 time_t getModTime() const;
89 const uint8_t* getContent() const;
90 uint32_t getContentSize() const;
91 const Entry* getNext() const;
92 private:
93 bool hasLongName() const;
94 unsigned int getLongNameSpace() const;
95
96 };
97
98 class CStringEquals
99 {
100 public:
101 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
102 };
103 typedef __gnu_cxx::hash_map<const char*, const struct ranlib*, __gnu_cxx::hash<const char*>, CStringEquals> NameToEntryMap;
104
105 typedef typename A::P P;
106 typedef typename A::P::E E;
107
d696c285
A
108 const struct ranlib* ranlibHashSearch(const char* name);
109 ObjectFile::Reader* makeObjectReaderForMember(const Entry* member);
110 void dumpTableOfContents();
111 void buildHashTable();
112
113 const char* fPath;
114 time_t fModTime;
115 const ObjectFile::ReaderOptions& fOptions;
a61fdf0a 116 uint32_t fOrdinalBase;
d696c285
A
117 const uint8_t* fFileContent;
118 uint64_t fFileLength;
119 const struct ranlib* fTableOfContents;
120 uint32_t fTableOfContentCount;
121 const char* fStringPool;
122 std::vector<class ObjectFile::Atom*> fAllAtoms;
2f2f92e4 123 std::vector<class ObjectFile::Reader*> fInstantiatedReaders;
d696c285
A
124 std::set<const class Entry*> fInstantiatedEntries;
125 std::set<const class Entry*> fPossibleEntries;
126 NameToEntryMap fHashTable;
55e3d2f6 127 bool fForceLoad;
d696c285
A
128
129 static std::vector<class ObjectFile::Atom*> fgEmptyList;
130};
131
132template <typename A>
133std::vector<class ObjectFile::Atom*> Reader<A>::fgEmptyList;
134
135
136template <typename A>
137bool Reader<A>::Entry::hasLongName() const
138{
139 return ( strncmp(this->ar_name, AR_EFMT1, strlen(AR_EFMT1)) == 0 );
140}
141
142template <typename A>
143unsigned int Reader<A>::Entry::getLongNameSpace() const
144{
145 char* endptr;
146 long result = strtol(&this->ar_name[strlen(AR_EFMT1)], &endptr, 10);
147 return result;
148}
149
150template <typename A>
151const char* Reader<A>::Entry::getName() const
152{
153 if ( this->hasLongName() ) {
154 int len = this->getLongNameSpace();
155 static char longName[256];
156 strncpy(longName, ((char*)this)+sizeof(ar_hdr), len);
157 longName[len] = '\0';
158 return longName;
159 }
160 else {
161 static char shortName[20];
162 strncpy(shortName, this->ar_name, 16);
163 shortName[16] = '\0';
164 char* space = strchr(shortName, ' ');
165 if ( space != NULL )
166 *space = '\0';
167 return shortName;
168 }
169}
170
171template <typename A>
172time_t Reader<A>::Entry::getModTime() const
173{
174 char temp[14];
a61fdf0a 175 strncpy(temp, this->ar_date, 12);
d696c285
A
176 temp[12] = '\0';
177 char* endptr;
a61fdf0a 178 return (time_t)strtol(temp, &endptr, 10);
d696c285
A
179}
180
181
182template <typename A>
183const uint8_t* Reader<A>::Entry::getContent() const
184{
185 if ( this->hasLongName() )
186 return ((uint8_t*)this) + sizeof(ar_hdr) + this->getLongNameSpace();
187 else
188 return ((uint8_t*)this) + sizeof(ar_hdr);
189}
190
191
192template <typename A>
193uint32_t Reader<A>::Entry::getContentSize() const
194{
195 char temp[12];
196 strncpy(temp, this->ar_size, 10);
197 temp[10] = '\0';
198 char* endptr;
199 long size = strtol(temp, &endptr, 10);
200 // long name is included in ar_size
201 if ( this->hasLongName() )
202 size -= this->getLongNameSpace();
203 return size;
204}
205
206
207template <typename A>
208const class Reader<A>::Entry* Reader<A>::Entry::getNext() const
209{
210 const uint8_t* p = this->getContent() + getContentSize();
211 p = (const uint8_t*)(((uintptr_t)p+3) & (-4)); // 4-byte align
212 return (class Reader<A>::Entry*)p;
213}
214
2f2f92e4
A
215
216template <> cpu_type_t Reader<ppc>::architecture() { return CPU_TYPE_POWERPC; }
217template <> cpu_type_t Reader<ppc64>::architecture() { return CPU_TYPE_POWERPC64; }
218template <> cpu_type_t Reader<x86>::architecture() { return CPU_TYPE_I386; }
219template <> cpu_type_t Reader<x86_64>::architecture() { return CPU_TYPE_X86_64; }
220template <> cpu_type_t Reader<arm>::architecture() { return CPU_TYPE_ARM; }
221
222
223template <typename A>
224bool Reader<A>::validMachOFile(const uint8_t* fileContent, uint64_t fileLength)
225{
226 return mach_o::relocatable::Reader<A>::validFile(fileContent);
227}
228
229template <typename A>
230bool Reader<A>::validLTOFile(const uint8_t* fileContent, uint64_t fileLength)
231{
232#if LTO_SUPPORT
233 return lto::Reader::validFile(fileContent, fileLength, architecture());
234#else
235 return false;
236#endif
237}
238
239
240
d696c285
A
241template <typename A>
242bool Reader<A>::validFile(const uint8_t* fileContent, uint64_t fileLength)
243{
244 // must have valid archive header
245 if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
246 return false;
247
248 // peak at first .o file and verify it is correct architecture
249 const Entry* const start = (Entry*)&fileContent[8];
250 const Entry* const end = (Entry*)&fileContent[fileLength];
251 for (const Entry* p=start; p < end; p = p->getNext()) {
252 const char* memberName = p->getName();
253 // skip option table-of-content member
254 if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
255 continue;
256 // archive is valid if first .o file is valid
2f2f92e4 257 return (validMachOFile(p->getContent(), p->getContentSize()) || validLTOFile(p->getContent(), p->getContentSize()));
d696c285
A
258 }
259 // empty archive
260 return true;
261}
262
263template <typename A>
a61fdf0a 264Reader<A>::Reader(const uint8_t fileContent[], uint64_t fileLength, const char* path, time_t modTime,
55e3d2f6 265 const LibraryOptions& archiveOptions,
a61fdf0a
A
266 const ObjectFile::ReaderOptions& options, uint32_t ordinalBase)
267 : fPath(NULL), fModTime(modTime), fOptions(options), fOrdinalBase(ordinalBase), fFileContent(NULL),
55e3d2f6 268 fTableOfContents(NULL), fTableOfContentCount(0), fStringPool(NULL), fForceLoad(archiveOptions.fForceLoad)
d696c285
A
269{
270 fPath = strdup(path);
271 fFileContent = fileContent;
272 fFileLength = fileLength;
273
274 if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
275 throw "not an archive";
276
a61fdf0a
A
277 // write out path for -whatsloaded option
278 if ( options.fLogAllFiles )
279 printf("%s\n", path);
280
55e3d2f6 281 if ( !options.fFullyLoadArchives && !fForceLoad ) {
d696c285
A
282 const Entry* const firstMember = (Entry*)&fFileContent[8];
283 if ( (strcmp(firstMember->getName(), SYMDEF_SORTED) == 0) || (strcmp(firstMember->getName(), SYMDEF) == 0) ) {
284 const uint8_t* contents = firstMember->getContent();
285 uint32_t ranlibArrayLen = E::get32(*((uint32_t*)contents));
286 fTableOfContents = (const struct ranlib*)&contents[4];
287 fTableOfContentCount = ranlibArrayLen / sizeof(struct ranlib);
288 fStringPool = (const char*)&contents[ranlibArrayLen+8];
289 if ( ((uint8_t*)(&fTableOfContents[fTableOfContentCount]) > &fileContent[fileLength])
290 || ((uint8_t*)fStringPool > &fileContent[fileLength]) )
291 throw "malformed archive, perhaps wrong architecture";
292 this->buildHashTable();
293 }
294 else
295 throw "archive has no table of contents";
296 }
297}
298
299
300template <typename A>
301ObjectFile::Reader* Reader<A>::makeObjectReaderForMember(const Entry* member)
302{
303 const char* memberName = member->getName();
304 char memberPath[strlen(fPath) + strlen(memberName)+4];
305 strcpy(memberPath, fPath);
306 strcat(memberPath, "(");
307 strcat(memberPath, memberName);
308 strcat(memberPath, ")");
309 //fprintf(stderr, "using %s from %s\n", memberName, fPath);
310 try {
a61fdf0a
A
311 // offset the ordinals in this mach-o .o file, so that atoms layout in same order as in archive
312 uint32_t ordinalBase = fOrdinalBase + (uint8_t*)member - fFileContent;
2f2f92e4
A
313 if ( validMachOFile(member->getContent(), member->getContentSize()) ) {
314 return new typename mach_o::relocatable::Reader<A>::Reader(member->getContent(), memberPath, member->getModTime(), fOptions, ordinalBase);
315 }
316#if LTO_SUPPORT
317 else if ( validLTOFile(member->getContent(), member->getContentSize()) ) {
318 return new typename lto::Reader(member->getContent(), member->getContentSize(), memberPath, member->getModTime(), fOptions, architecture());
319 }
320#endif
55e3d2f6 321 throwf("archive member '%s' with length %d is not mach-o or bitcode", memberName, member->getContentSize());
d696c285
A
322 }
323 catch (const char* msg) {
324 throwf("in %s, %s", memberPath, msg);
325 }
326}
327
a61fdf0a 328
d696c285
A
329template <typename A>
330std::vector<class ObjectFile::Atom*>& Reader<A>::getAtoms()
331{
55e3d2f6 332 if ( fOptions.fFullyLoadArchives || fForceLoad ) {
d696c285
A
333 // build vector of all atoms from all .o files in this archive
334 const Entry* const start = (Entry*)&fFileContent[8];
335 const Entry* const end = (Entry*)&fFileContent[fFileLength];
d696c285
A
336 for (const Entry* p=start; p < end; p = p->getNext()) {
337 const char* memberName = p->getName();
338 if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
339 continue;
55e3d2f6
A
340 if ( fOptions.fWhyLoad ) {
341 if ( fForceLoad )
342 printf("-force_load forced load of %s(%s)\n", this->getPath(), memberName);
343 else
344 printf("-all_load forced load of %s(%s)\n", this->getPath(), memberName);
345 }
d696c285 346 ObjectFile::Reader* r = this->makeObjectReaderForMember(p);
d696c285
A
347 std::vector<class ObjectFile::Atom*>& atoms = r->getAtoms();
348 fAllAtoms.insert(fAllAtoms.end(), atoms.begin(), atoms.end());
2f2f92e4 349 fInstantiatedReaders.push_back(r);
d696c285
A
350 }
351 return fAllAtoms;
352 }
a61fdf0a
A
353 else if ( fOptions.fLoadAllObjcObjectsFromArchives ) {
354 // build vector of all atoms from all .o files containing objc classes in this archive
355 for(class NameToEntryMap::iterator it = fHashTable.begin(); it != fHashTable.end(); ++it) {
356 if ( (strncmp(it->first, ".objc_c", 7) == 0) || (strncmp(it->first, "_OBJC_CLASS_$_", 14) == 0) ) {
357 const Entry* member = (Entry*)&fFileContent[E::get32(it->second->ran_off)];
358 if ( fInstantiatedEntries.count(member) == 0 ) {
359 if ( fOptions.fWhyLoad )
360 printf("-ObjC forced load of %s(%s)\n", this->getPath(), member->getName());
361 // only return these atoms once
362 fInstantiatedEntries.insert(member);
363 ObjectFile::Reader* r = makeObjectReaderForMember(member);
364 std::vector<class ObjectFile::Atom*>& atoms = r->getAtoms();
365 fAllAtoms.insert(fAllAtoms.end(), atoms.begin(), atoms.end());
2f2f92e4 366 fInstantiatedReaders.push_back(r);
a61fdf0a
A
367 }
368 }
369 }
370 return fAllAtoms;
371 }
d696c285
A
372 else {
373 // return nonthing for now, getJustInTimeAtomsFor() will return atoms as needed
374 return fgEmptyList;
375 }
376}
377
2f2f92e4 378template <typename A>
55e3d2f6
A
379bool Reader<A>::optimize(const std::vector<ObjectFile::Atom*>& allAtoms, std::vector<ObjectFile::Atom*>& newAtoms,
380 std::vector<const char*>& additionalUndefines, const std::set<ObjectFile::Atom*>& deadAtoms,
381 std::vector<ObjectFile::Atom*>& newDeadAtoms,
382 uint32_t nextOrdinal, ObjectFile::Reader* writer, ObjectFile::Atom* entryPointAtom,
383 const std::vector<const char*>& llvmOptions,
2f2f92e4
A
384 bool allGlobalsAReDeadStripRoots, int okind,
385 bool verbose, bool saveTemps, const char* outputFilePath,
386 bool pie, bool allowTextRelocs)
387{
55e3d2f6 388 bool result = false;
2f2f92e4 389 for(std::vector<ObjectFile::Reader*>::iterator it=fInstantiatedReaders.begin(); it != fInstantiatedReaders.end(); ++it) {
55e3d2f6
A
390 result |= (*it)->optimize(allAtoms, newAtoms, additionalUndefines, deadAtoms, newDeadAtoms, nextOrdinal,
391 writer, entryPointAtom, llvmOptions, allGlobalsAReDeadStripRoots, okind,
392 verbose, saveTemps, outputFilePath, pie, allowTextRelocs);
2f2f92e4 393 }
55e3d2f6 394 return result;
2f2f92e4
A
395}
396
397
d696c285 398
d696c285
A
399template <typename A>
400ConstRanLibPtr Reader<A>::ranlibHashSearch(const char* name)
401{
402 class NameToEntryMap::iterator pos = fHashTable.find(name);
403 if ( pos != fHashTable.end() )
404 return pos->second;
405 else
406 return NULL;
407}
408
409template <typename A>
410void Reader<A>::buildHashTable()
411{
412 // walk through list backwards, adding/overwriting entries
413 // this assures that with duplicates those earliest in the list will be found
414 for (int i = fTableOfContentCount-1; i >= 0; --i) {
415 const struct ranlib* entry = &fTableOfContents[i];
416 const char* entryName = &fStringPool[E::get32(entry->ran_un.ran_strx)];
417 const Entry* member = (Entry*)&fFileContent[E::get32(entry->ran_off)];
418 //fprintf(stderr, "adding hash %d, %s -> %p\n", i, entryName, entry);
419 fHashTable[entryName] = entry;
420 fPossibleEntries.insert(member);
421 }
422}
423
424template <typename A>
425void Reader<A>::dumpTableOfContents()
426{
427 for (unsigned int i=0; i < fTableOfContentCount; ++i) {
428 const struct ranlib* e = &fTableOfContents[i];
429 printf("%s in %s\n", &fStringPool[E::get32(e->ran_un.ran_strx)], ((Entry*)&fFileContent[E::get32(e->ran_off)])->getName());
430 }
431}
432
433template <typename A>
434std::vector<class ObjectFile::Atom*>* Reader<A>::getJustInTimeAtomsFor(const char* name)
435{
55e3d2f6 436 if ( fOptions.fFullyLoadArchives || fForceLoad ) {
d696c285
A
437 return NULL;
438 }
439 else {
440 const struct ranlib* result = NULL;
441 // do a hash search of table of contents looking for requested symbol
442 result = ranlibHashSearch(name);
443 if ( result != NULL ) {
444 const Entry* member = (Entry*)&fFileContent[E::get32(result->ran_off)];
445 if ( fInstantiatedEntries.count(member) == 0 ) {
55e3d2f6 446 if ( fOptions.fWhyLoad )
69a49097 447 printf("%s forced load of %s(%s)\n", name, this->getPath(), member->getName());
d696c285
A
448 // only return these atoms once
449 fInstantiatedEntries.insert(member);
450 ObjectFile::Reader* r = makeObjectReaderForMember(member);
2f2f92e4 451 fInstantiatedReaders.push_back(r);
d696c285
A
452 return new std::vector<class ObjectFile::Atom*>(r->getAtoms());
453 }
454 }
455 //fprintf(stderr, "%s NOT found in archive %s\n", name, fPath);
456 return NULL;
457 }
458}
459
460
461
462
463
464}; // namespace archive
d696c285
A
465
466
2f2f92e4 467#endif // __OBJECT_FILE_ARCHIVE__