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