]> git.saurik.com Git - apple/ld64.git/blame - src/ld/parsers/archive_file.cpp
ld64-242.tar.gz
[apple/ld64.git] / src / ld / parsers / archive_file.cpp
CommitLineData
a645023d
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
afe874b1 3 * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
a645023d
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
25#include <stdint.h>
26#include <math.h>
27#include <unistd.h>
28#include <sys/param.h>
29#include <mach-o/ranlib.h>
30#include <ar.h>
31
32#include <vector>
33#include <set>
afe874b1 34#include <map>
a645023d 35#include <algorithm>
d425e388 36#include <unordered_map>
a645023d
A
37
38#include "MachOFileAbstraction.hpp"
39#include "Architectures.hpp"
40
41#include "macho_relocatable_file.h"
42#include "lto_file.h"
43#include "archive_file.h"
44
45
46namespace archive {
47
48typedef const struct ranlib* ConstRanLibPtr;
49
50// forward reference
51template <typename A> class File;
52
53
54template <typename A>
55class Parser
56{
57public:
58 typedef typename A::P P;
59
60 static bool validFile(const uint8_t* fileContent, uint64_t fileLength,
61 const mach_o::relocatable::ParserOptions& opts) {
62 return File<A>::validFile(fileContent, fileLength, opts); }
63 static File<A>* parse(const uint8_t* fileContent, uint64_t fileLength,
64 const char* path, time_t mTime,
ebf6f434 65 ld::File::Ordinal ordinal, const ParserOptions& opts) {
a645023d
A
66 return new File<A>(fileContent, fileLength, path, mTime,
67 ordinal, opts);
68 }
69
70};
71
72template <typename A>
afe874b1 73class File : public ld::archive::File
a645023d
A
74{
75public:
76 static bool validFile(const uint8_t* fileContent, uint64_t fileLength,
77 const mach_o::relocatable::ParserOptions& opts);
78 File(const uint8_t* fileContent, uint64_t fileLength,
79 const char* pth, time_t modTime,
ebf6f434 80 ld::File::Ordinal ord, const ParserOptions& opts);
a645023d
A
81 virtual ~File() {}
82
83 // overrides of ld::File
84 virtual bool forEachAtom(ld::File::AtomHandler&) const;
85 virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const;
86 virtual uint32_t subFileCount() const { return _archiveFilelength/sizeof(ar_hdr); }
87
afe874b1
A
88 // overrides of ld::archive::File
89 virtual bool justInTimeDataOnlyforEachAtom(const char* name, ld::File::AtomHandler& handler) const;
90
a645023d
A
91private:
92 static bool validMachOFile(const uint8_t* fileContent, uint64_t fileLength,
93 const mach_o::relocatable::ParserOptions& opts);
94 static bool validLTOFile(const uint8_t* fileContent, uint64_t fileLength,
95 const mach_o::relocatable::ParserOptions& opts);
96 static cpu_type_t architecture();
97
a645023d
A
98 class Entry : ar_hdr
99 {
100 public:
ebf6f434 101 void getName(char *, int) const;
a645023d
A
102 time_t modificationTime() const;
103 const uint8_t* content() const;
104 uint32_t contentSize() const;
105 const Entry* next() const;
106 private:
107 bool hasLongName() const;
108 unsigned int getLongNameSpace() const;
109
110 };
111
f80fe69f 112 struct MemberState { ld::relocatable::File* file; const Entry *entry; bool logged; bool loaded; uint32_t index;};
ebf6f434
A
113 bool loadMember(MemberState& state, ld::File::AtomHandler& handler, const char *format, ...) const;
114
d425e388 115 typedef std::unordered_map<const char*, const struct ranlib*, ld::CStringHash, ld::CStringEquals> NameToEntryMap;
a645023d
A
116
117 typedef typename A::P P;
118 typedef typename A::P::E E;
119
afe874b1
A
120 typedef std::map<const class Entry*, MemberState> MemberToStateMap;
121
a645023d 122 const struct ranlib* ranlibHashSearch(const char* name) const;
afe874b1 123 MemberState& makeObjectFileForMember(const Entry* member) const;
a645023d
A
124 bool memberHasObjCCategories(const Entry* member) const;
125 void dumpTableOfContents();
126 void buildHashTable();
127
128 const uint8_t* _archiveFileContent;
129 uint64_t _archiveFilelength;
130 const struct ranlib* _tableOfContents;
131 uint32_t _tableOfContentCount;
132 const char* _tableOfContentStrings;
afe874b1 133 mutable MemberToStateMap _instantiatedEntries;
a645023d
A
134 NameToEntryMap _hashTable;
135 const bool _forceLoadAll;
136 const bool _forceLoadObjC;
137 const bool _forceLoadThis;
afe874b1 138 const bool _objc2ABI;
a645023d
A
139 const bool _verboseLoad;
140 const bool _logAllFiles;
141 const mach_o::relocatable::ParserOptions _objOpts;
142};
143
144
145template <typename A>
146bool File<A>::Entry::hasLongName() const
147{
148 return ( strncmp(this->ar_name, AR_EFMT1, strlen(AR_EFMT1)) == 0 );
149}
150
151template <typename A>
152unsigned int File<A>::Entry::getLongNameSpace() const
153{
154 char* endptr;
155 long result = strtol(&this->ar_name[strlen(AR_EFMT1)], &endptr, 10);
156 return result;
157}
158
159template <typename A>
ebf6f434 160void File<A>::Entry::getName(char *buf, int bufsz) const
a645023d
A
161{
162 if ( this->hasLongName() ) {
163 int len = this->getLongNameSpace();
ebf6f434
A
164 assert(bufsz >= len+1);
165 strncpy(buf, ((char*)this)+sizeof(ar_hdr), len);
166 buf[len] = '\0';
a645023d
A
167 }
168 else {
ebf6f434
A
169 assert(bufsz >= 16+1);
170 strncpy(buf, this->ar_name, 16);
171 buf[16] = '\0';
172 char* space = strchr(buf, ' ');
a645023d
A
173 if ( space != NULL )
174 *space = '\0';
a645023d
A
175 }
176}
177
178template <typename A>
179time_t File<A>::Entry::modificationTime() const
180{
181 char temp[14];
182 strncpy(temp, this->ar_date, 12);
183 temp[12] = '\0';
184 char* endptr;
185 return (time_t)strtol(temp, &endptr, 10);
186}
187
188
189template <typename A>
190const uint8_t* File<A>::Entry::content() const
191{
192 if ( this->hasLongName() )
193 return ((uint8_t*)this) + sizeof(ar_hdr) + this->getLongNameSpace();
194 else
195 return ((uint8_t*)this) + sizeof(ar_hdr);
196}
197
198
199template <typename A>
200uint32_t File<A>::Entry::contentSize() const
201{
202 char temp[12];
203 strncpy(temp, this->ar_size, 10);
204 temp[10] = '\0';
205 char* endptr;
206 long size = strtol(temp, &endptr, 10);
207 // long name is included in ar_size
208 if ( this->hasLongName() )
209 size -= this->getLongNameSpace();
210 return size;
211}
212
213
214template <typename A>
215const class File<A>::Entry* File<A>::Entry::next() const
216{
217 const uint8_t* p = this->content() + contentSize();
218 p = (const uint8_t*)(((uintptr_t)p+3) & (-4)); // 4-byte align
219 return (class File<A>::Entry*)p;
220}
221
222
a645023d
A
223template <> cpu_type_t File<x86>::architecture() { return CPU_TYPE_I386; }
224template <> cpu_type_t File<x86_64>::architecture() { return CPU_TYPE_X86_64; }
225template <> cpu_type_t File<arm>::architecture() { return CPU_TYPE_ARM; }
f80fe69f 226template <> cpu_type_t File<arm64>::architecture() { return CPU_TYPE_ARM64; }
a645023d
A
227
228
229template <typename A>
230bool File<A>::validMachOFile(const uint8_t* fileContent, uint64_t fileLength, const mach_o::relocatable::ParserOptions& opts)
231{
232 return mach_o::relocatable::isObjectFile(fileContent, fileLength, opts);
233}
234
235template <typename A>
236bool File<A>::validLTOFile(const uint8_t* fileContent, uint64_t fileLength, const mach_o::relocatable::ParserOptions& opts)
237{
238 return lto::isObjectFile(fileContent, fileLength, opts.architecture, opts.subType);
239}
240
241
242
243template <typename A>
244bool File<A>::validFile(const uint8_t* fileContent, uint64_t fileLength, const mach_o::relocatable::ParserOptions& opts)
245{
246 // must have valid archive header
247 if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
248 return false;
249
250 // peak at first .o file and verify it is correct architecture
251 const Entry* const start = (Entry*)&fileContent[8];
252 const Entry* const end = (Entry*)&fileContent[fileLength];
253 for (const Entry* p=start; p < end; p = p->next()) {
ebf6f434
A
254 char memberName[256];
255 p->getName(memberName, sizeof(memberName));
a645023d
A
256 // skip option table-of-content member
257 if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
258 continue;
259 // archive is valid if first .o file is valid
260 return (validMachOFile(p->content(), p->contentSize(), opts) || validLTOFile(p->content(), p->contentSize(), opts));
261 }
262 // empty archive
263 return true;
264}
265
266
267template <typename A>
268File<A>::File(const uint8_t fileContent[], uint64_t fileLength, const char* pth, time_t modTime,
ebf6f434 269 ld::File::Ordinal ord, const ParserOptions& opts)
afe874b1 270 : ld::archive::File(strdup(pth), modTime, ord),
a645023d
A
271 _archiveFileContent(fileContent), _archiveFilelength(fileLength),
272 _tableOfContents(NULL), _tableOfContentCount(0), _tableOfContentStrings(NULL),
273 _forceLoadAll(opts.forceLoadAll), _forceLoadObjC(opts.forceLoadObjC),
afe874b1 274 _forceLoadThis(opts.forceLoadThisArchive), _objc2ABI(opts.objcABI2), _verboseLoad(opts.verboseLoad),
a645023d
A
275 _logAllFiles(opts.logAllFiles), _objOpts(opts.objOpts)
276{
277 if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
278 throw "not an archive";
279
280 if ( !_forceLoadAll ) {
281 const Entry* const firstMember = (Entry*)&_archiveFileContent[8];
ebf6f434
A
282 char memberName[256];
283 firstMember->getName(memberName, sizeof(memberName));
284 if ( (strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0) ) {
a645023d
A
285 const uint8_t* contents = firstMember->content();
286 uint32_t ranlibArrayLen = E::get32(*((uint32_t*)contents));
287 _tableOfContents = (const struct ranlib*)&contents[4];
288 _tableOfContentCount = ranlibArrayLen / sizeof(struct ranlib);
289 _tableOfContentStrings = (const char*)&contents[ranlibArrayLen+8];
290 if ( ((uint8_t*)(&_tableOfContents[_tableOfContentCount]) > &fileContent[fileLength])
291 || ((uint8_t*)_tableOfContentStrings > &fileContent[fileLength]) )
292 throw "malformed archive, perhaps wrong architecture";
293 this->buildHashTable();
294 }
295 else
296 throw "archive has no table of contents";
297 }
298}
299
300template <>
301bool File<x86>::memberHasObjCCategories(const Entry* member) const
302{
afe874b1
A
303 if ( _objc2ABI ) {
304 // i386 for iOS simulator uses ObjC2 which has no global symbol for categories
305 return mach_o::relocatable::hasObjC2Categories(member->content());
306 }
307 else {
308 // i386 uses ObjC1 ABI which has .objc_category* global symbols
ebf6f434
A
309 // <rdar://problem/11342022> strip -S on i386 pulls out .objc_category_name symbols from static frameworks
310 return mach_o::relocatable::hasObjC1Categories(member->content());
afe874b1 311 }
a645023d
A
312}
313
a645023d
A
314
315
316template <typename A>
317bool File<A>::memberHasObjCCategories(const Entry* member) const
318{
319 // x86_64 and ARM use ObjC2 which has no global symbol for categories
320 return mach_o::relocatable::hasObjC2Categories(member->content());
321}
322
323
324template <typename A>
afe874b1 325typename File<A>::MemberState& File<A>::makeObjectFileForMember(const Entry* member) const
a645023d 326{
f80fe69f 327 uint32_t memberIndex = 0;
afe874b1
A
328 // in case member was instantiated earlier but not needed yet
329 typename MemberToStateMap::iterator pos = _instantiatedEntries.find(member);
ebf6f434
A
330 if ( pos == _instantiatedEntries.end() ) {
331 // Have to find the index of this member
332 const Entry* start;
f80fe69f 333 uint32_t index;
ebf6f434
A
334 if (_instantiatedEntries.size() == 0) {
335 start = (Entry*)&_archiveFileContent[8];
336 index = 1;
337 } else {
338 MemberState &lastKnown = _instantiatedEntries.rbegin()->second;
339 start = lastKnown.entry->next();
340 index = lastKnown.index+1;
341 }
342 for (const Entry* p=start; p <= member; p = p->next(), index++) {
343 MemberState state = {NULL, p, false, false, index};
344 _instantiatedEntries[p] = state;
345 if (member == p) {
346 memberIndex = index;
347 }
348 }
349 } else {
350 MemberState& state = pos->second;
351 if (state.file)
352 return state;
353 memberIndex = state.index;
354 }
355 assert(memberIndex != 0);
356 char memberName[256];
357 member->getName(memberName, sizeof(memberName));
a645023d
A
358 char memberPath[strlen(this->path()) + strlen(memberName)+4];
359 strcpy(memberPath, this->path());
360 strcat(memberPath, "(");
361 strcat(memberPath, memberName);
362 strcat(memberPath, ")");
363 //fprintf(stderr, "using %s from %s\n", memberName, this->path());
364 try {
365 // range check
366 if ( member > (Entry*)(_archiveFileContent+_archiveFilelength) )
367 throwf("corrupt archive, member starts past end of file");
368 if ( (member->content() + member->contentSize()) > (_archiveFileContent+_archiveFilelength) )
369 throwf("corrupt archive, member contents extends past end of file");
370 const char* mPath = strdup(memberPath);
a645023d 371 // see if member is mach-o file
ebf6f434 372 ld::File::Ordinal ordinal = this->ordinal().archiveOrdinalWithMemberIndex(memberIndex);
a645023d
A
373 ld::relocatable::File* result = mach_o::relocatable::parse(member->content(), member->contentSize(),
374 mPath, member->modificationTime(),
ebf6f434 375 ordinal, _objOpts);
afe874b1 376 if ( result != NULL ) {
ebf6f434 377 MemberState state = {result, member, false, false, memberIndex};
afe874b1
A
378 _instantiatedEntries[member] = state;
379 return _instantiatedEntries[member];
380 }
a645023d
A
381 // see if member is llvm bitcode file
382 result = lto::parse(member->content(), member->contentSize(),
b1f7435d 383 mPath, member->modificationTime(), ordinal,
9543cb2f 384 _objOpts.architecture, _objOpts.subType, _logAllFiles, _objOpts.verboseOptimizationHints);
afe874b1 385 if ( result != NULL ) {
ebf6f434 386 MemberState state = {result, member, false, false, memberIndex};
afe874b1
A
387 _instantiatedEntries[member] = state;
388 return _instantiatedEntries[member];
389 }
a645023d
A
390
391 throwf("archive member '%s' with length %d is not mach-o or llvm bitcode", memberName, member->contentSize());
392 }
393 catch (const char* msg) {
394 throwf("in %s, %s", memberPath, msg);
395 }
396}
397
398
ebf6f434
A
399template <typename A>
400bool File<A>::loadMember(MemberState& state, ld::File::AtomHandler& handler, const char *format, ...) const
401{
402 bool didSomething = false;
403 if (!state.loaded) {
404 if ( _verboseLoad && !state.logged ) {
405 va_list list;
406 va_start(list, format);
407 vprintf(format, list);
408 va_end(list);
409 state.logged = true;
410 }
411 state.loaded = true;
412 didSomething = state.file->forEachAtom(handler);
413 }
414 return didSomething;
415}
416
417
a645023d
A
418template <typename A>
419bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
420{
421 bool didSome = false;
422 if ( _forceLoadAll || _forceLoadThis ) {
423 // call handler on all .o files in this archive
424 const Entry* const start = (Entry*)&_archiveFileContent[8];
425 const Entry* const end = (Entry*)&_archiveFileContent[_archiveFilelength];
426 for (const Entry* p=start; p < end; p = p->next()) {
ebf6f434
A
427 char memberName[256];
428 p->getName(memberName, sizeof(memberName));
a645023d
A
429 if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
430 continue;
afe874b1 431 MemberState& state = this->makeObjectFileForMember(p);
ebf6f434 432 didSome |= loadMember(state, handler, "%s forced load of %s(%s)\n", _forceLoadThis ? "-force_load" : "-all_load", this->path(), memberName);
a645023d
A
433 }
434 }
435 else if ( _forceLoadObjC ) {
436 // call handler on all .o files in this archive containing objc classes
437 for(typename NameToEntryMap::const_iterator it = _hashTable.begin(); it != _hashTable.end(); ++it) {
438 if ( (strncmp(it->first, ".objc_c", 7) == 0) || (strncmp(it->first, "_OBJC_CLASS_$_", 14) == 0) ) {
439 const Entry* member = (Entry*)&_archiveFileContent[E::get32(it->second->ran_off)];
afe874b1 440 MemberState& state = this->makeObjectFileForMember(member);
ebf6f434
A
441 char memberName[256];
442 member->getName(memberName, sizeof(memberName));
443 didSome |= loadMember(state, handler, "-ObjC forced load of %s(%s)\n", this->path(), memberName);
a645023d
A
444 }
445 }
afe874b1 446 // ObjC2 has no symbols in .o files with categories but not classes, look deeper for those
a645023d
A
447 const Entry* const start = (Entry*)&_archiveFileContent[8];
448 const Entry* const end = (Entry*)&_archiveFileContent[_archiveFilelength];
449 for (const Entry* member=start; member < end; member = member->next()) {
ebf6f434
A
450 char mname[256];
451 member->getName(mname, sizeof(mname));
452 // skip table-of-content member
453 if ( (member==start) && ((strcmp(mname, SYMDEF_SORTED) == 0) || (strcmp(mname, SYMDEF) == 0)) )
454 continue;
455 MemberState& state = this->makeObjectFileForMember(member);
456 // only look at files not already loaded
457 if ( ! state.loaded ) {
a645023d 458 if ( this->memberHasObjCCategories(member) ) {
afe874b1 459 MemberState& state = this->makeObjectFileForMember(member);
ebf6f434
A
460 char memberName[256];
461 member->getName(memberName, sizeof(memberName));
462 didSome |= loadMember(state, handler, "-ObjC forced load of %s(%s)\n", this->path(), memberName);
a645023d
A
463 }
464 }
465 }
466 }
467 return didSome;
468}
469
470template <typename A>
471bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& handler) const
472{
473 // in force load case, all members already loaded
474 if ( _forceLoadAll || _forceLoadThis )
475 return false;
476
477 // do a hash search of table of contents looking for requested symbol
478 const struct ranlib* result = ranlibHashSearch(name);
479 if ( result != NULL ) {
480 const Entry* member = (Entry*)&_archiveFileContent[E::get32(result->ran_off)];
afe874b1 481 MemberState& state = this->makeObjectFileForMember(member);
ebf6f434
A
482 char memberName[256];
483 member->getName(memberName, sizeof(memberName));
484 return loadMember(state, handler, "%s forced load of %s(%s)\n", name, this->path(), memberName);
afe874b1
A
485 }
486 //fprintf(stderr, "%s NOT found in archive %s\n", name, this->path());
487 return false;
488}
489
490class CheckIsDataSymbolHandler : public ld::File::AtomHandler
491{
492public:
493 CheckIsDataSymbolHandler(const char* n) : _name(n), _isData(false) {}
494 virtual void doAtom(const class ld::Atom& atom) {
495 if ( strcmp(atom.name(), _name) == 0 ) {
496 if ( atom.section().type() != ld::Section::typeCode )
497 _isData = true;
498 }
499 }
500 virtual void doFile(const class ld::File&) {}
501 bool symbolIsDataDefinition() { return _isData; }
502
503private:
504 const char* _name;
505 bool _isData;
506
507};
508
509template <typename A>
510bool File<A>::justInTimeDataOnlyforEachAtom(const char* name, ld::File::AtomHandler& handler) const
511{
512 // in force load case, all members already loaded
513 if ( _forceLoadAll || _forceLoadThis )
514 return false;
515
516 // do a hash search of table of contents looking for requested symbol
517 const struct ranlib* result = ranlibHashSearch(name);
518 if ( result != NULL ) {
519 const Entry* member = (Entry*)&_archiveFileContent[E::get32(result->ran_off)];
520 MemberState& state = this->makeObjectFileForMember(member);
521 // only call handler for each member once
522 if ( ! state.loaded ) {
523 CheckIsDataSymbolHandler checker(name);
524 state.file->forEachAtom(checker);
525 if ( checker.symbolIsDataDefinition() ) {
ebf6f434
A
526 char memberName[256];
527 member->getName(memberName, sizeof(memberName));
528 return loadMember(state, handler, "%s forced load of %s(%s)\n", name, this->path(), memberName);
afe874b1 529 }
a645023d
A
530 }
531 }
532 //fprintf(stderr, "%s NOT found in archive %s\n", name, this->path());
533 return false;
534}
535
536
537typedef const struct ranlib* ConstRanLibPtr;
538
539template <typename A>
540ConstRanLibPtr File<A>::ranlibHashSearch(const char* name) const
541{
542 typename NameToEntryMap::const_iterator pos = _hashTable.find(name);
543 if ( pos != _hashTable.end() )
544 return pos->second;
545 else
546 return NULL;
547}
548
549template <typename A>
550void File<A>::buildHashTable()
551{
552 // walk through list backwards, adding/overwriting entries
553 // this assures that with duplicates those earliest in the list will be found
554 for (int i = _tableOfContentCount-1; i >= 0; --i) {
555 const struct ranlib* entry = &_tableOfContents[i];
556 const char* entryName = &_tableOfContentStrings[E::get32(entry->ran_un.ran_strx)];
557 if ( E::get32(entry->ran_off) > _archiveFilelength ) {
558 throwf("malformed archive TOC entry for %s, offset %d is beyond end of file %lld\n",
559 entryName, entry->ran_off, _archiveFilelength);
560 }
561
562 //const Entry* member = (Entry*)&_archiveFileContent[E::get32(entry->ran_off)];
563 //fprintf(stderr, "adding hash %d, %s -> %p\n", i, entryName, entry);
564 _hashTable[entryName] = entry;
565 }
566}
567
568template <typename A>
569void File<A>::dumpTableOfContents()
570{
571 for (unsigned int i=0; i < _tableOfContentCount; ++i) {
572 const struct ranlib* e = &_tableOfContents[i];
573 printf("%s in %s\n", &_tableOfContentStrings[E::get32(e->ran_un.ran_strx)], ((Entry*)&_archiveFileContent[E::get32(e->ran_off)])->name());
574 }
575}
576
577
578//
579// main function used by linker to instantiate archive files
580//
afe874b1 581ld::archive::File* parse(const uint8_t* fileContent, uint64_t fileLength,
ebf6f434 582 const char* path, time_t modTime, ld::File::Ordinal ordinal, const ParserOptions& opts)
a645023d
A
583{
584 switch ( opts.objOpts.architecture ) {
ebf6f434 585#if SUPPORT_ARCH_x86_64
a645023d
A
586 case CPU_TYPE_X86_64:
587 if ( archive::Parser<x86_64>::validFile(fileContent, fileLength, opts.objOpts) )
588 return archive::Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
589 break;
ebf6f434
A
590#endif
591#if SUPPORT_ARCH_i386
a645023d
A
592 case CPU_TYPE_I386:
593 if ( archive::Parser<x86>::validFile(fileContent, fileLength, opts.objOpts) )
594 return archive::Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
595 break;
ebf6f434
A
596#endif
597#if SUPPORT_ARCH_arm_any
a645023d
A
598 case CPU_TYPE_ARM:
599 if ( archive::Parser<arm>::validFile(fileContent, fileLength, opts.objOpts) )
600 return archive::Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
601 break;
f80fe69f
A
602#endif
603#if SUPPORT_ARCH_arm64
604 case CPU_TYPE_ARM64:
605 if ( archive::Parser<arm64>::validFile(fileContent, fileLength, opts.objOpts) )
606 return archive::Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
607 break;
ebf6f434 608#endif
a645023d
A
609 }
610 return NULL;
611}
612
613
614
615}; // namespace archive
616
617