]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/parsers/archive_file.cpp
ld64-274.1.tar.gz
[apple/ld64.git] / src / ld / parsers / archive_file.cpp
index 66f9432af5f203c01d4df8bd2575b02ee0384e08..a1fec1a6f9f867421abc107445201a63b683182e 100644 (file)
@@ -33,7 +33,7 @@
 #include <set>
 #include <map>
 #include <algorithm>
-#include <ext/hash_map>
+#include <unordered_map>
 
 #include "MachOFileAbstraction.hpp"
 #include "Architectures.hpp"
@@ -45,7 +45,6 @@
 
 namespace archive {
 
-typedef const struct ranlib* ConstRanLibPtr;
 
 // forward reference
 template <typename A> class File;
@@ -62,7 +61,7 @@ public:
                                                                                                                return File<A>::validFile(fileContent, fileLength, opts); }
        static File<A>*                                                                 parse(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                        const char* path, time_t mTime, 
-                                                                                                                       uint32_t ordinal, const ParserOptions& opts) {
+                                                                                                                       ld::File::Ordinal ordinal, const ParserOptions& opts) {
                                                                                                                         return new File<A>(fileContent, fileLength, path, mTime,
                                                                                                                                                        ordinal, opts);
                                                                                                                }
@@ -77,7 +76,7 @@ public:
                                                                                                                                const mach_o::relocatable::ParserOptions& opts);
                                                                                                        File(const uint8_t* fileContent, uint64_t fileLength,
                                                                                                                        const char* pth, time_t modTime, 
-                                                                                                                       uint32_t ord, const ParserOptions& opts);
+                                                                                                                       ld::File::Ordinal ord, const ParserOptions& opts);
        virtual                                                                                 ~File() {}
 
        // overrides of ld::File
@@ -98,7 +97,7 @@ private:
        class Entry : ar_hdr
        {
        public:
-               const char*                     name() const;
+               void                            getName(char *, int) const;
                time_t                          modificationTime() const;
                const uint8_t*          content() const;
                uint32_t                        contentSize() const;
@@ -109,33 +108,33 @@ private:
 
        };
 
-       class CStringEquals
-       {
-       public:
-               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-       };
-       typedef __gnu_cxx::hash_map<const char*, const struct ranlib*, __gnu_cxx::hash<const char*>, CStringEquals> NameToEntryMap;
+       struct MemberState { ld::relocatable::File* file; const Entry *entry; bool logged; bool loaded; uint32_t index;};
+       bool                                                                                    loadMember(MemberState& state, ld::File::AtomHandler& handler, const char *format, ...) const;
+
+       typedef std::unordered_map<const char*, uint64_t, ld::CStringHash, ld::CStringEquals> NameToOffsetMap;
 
        typedef typename A::P                                                   P;
        typedef typename A::P::E                                                E;
 
-       struct MemberState { ld::relocatable::File* file; bool logged; bool loaded; };
-       
        typedef std::map<const class Entry*, MemberState> MemberToStateMap;
 
-       const struct ranlib*                                                    ranlibHashSearch(const char* name) const;
        MemberState&                                                                    makeObjectFileForMember(const Entry* member) const;
        bool                                                                                    memberHasObjCCategories(const Entry* member) const;
        void                                                                                    dumpTableOfContents();
        void                                                                                    buildHashTable();
-
+#ifdef SYMDEF_64
+       void                                                                                    buildHashTable64();
+#endif
        const uint8_t*                                                                  _archiveFileContent;
        uint64_t                                                                                _archiveFilelength;
        const struct ranlib*                                                    _tableOfContents;
+#ifdef SYMDEF_64
+       const struct ranlib_64*                                                 _tableOfContents64;
+#endif
        uint32_t                                                                                _tableOfContentCount;
        const char*                                                                             _tableOfContentStrings;
        mutable MemberToStateMap                                                _instantiatedEntries;
-       NameToEntryMap                                                                  _hashTable;
+       NameToOffsetMap                                                                 _hashTable;
        const bool                                                                              _forceLoadAll;
        const bool                                                                              _forceLoadObjC;
        const bool                                                                              _forceLoadThis;
@@ -161,23 +160,21 @@ unsigned int File<A>::Entry::getLongNameSpace() const
 }
 
 template <typename A>
-const char* File<A>::Entry::name() const
+void File<A>::Entry::getName(char *buf, int bufsz) const
 {
        if ( this->hasLongName() ) {
                int len = this->getLongNameSpace();
-               static char longName[256];
-               strncpy(longName, ((char*)this)+sizeof(ar_hdr), len);
-               longName[len] = '\0';
-               return longName;
+               assert(bufsz >= len+1);
+               strncpy(buf, ((char*)this)+sizeof(ar_hdr), len);
+               buf[len] = '\0';
        }
        else {
-               static char shortName[20];
-               strncpy(shortName, this->ar_name, 16);
-               shortName[16] = '\0';
-               char* space = strchr(shortName, ' ');
+               assert(bufsz >= 16+1);
+               strncpy(buf, this->ar_name, 16);
+               buf[16] = '\0';
+               char* space = strchr(buf, ' ');
                if ( space != NULL )
                        *space = '\0';
-               return shortName;
        }
 }
 
@@ -226,12 +223,10 @@ const class File<A>::Entry* File<A>::Entry::next() const
 }
 
 
-template <> cpu_type_t File<ppc>::architecture()    { return CPU_TYPE_POWERPC; }
-template <> cpu_type_t File<ppc64>::architecture()  { return CPU_TYPE_POWERPC64; }
 template <> cpu_type_t File<x86>::architecture()    { return CPU_TYPE_I386; }
 template <> cpu_type_t File<x86_64>::architecture() { return CPU_TYPE_X86_64; }
 template <> cpu_type_t File<arm>::architecture()    { return CPU_TYPE_ARM; }
-
+template <> cpu_type_t File<arm64>::architecture()  { return CPU_TYPE_ARM64; }
 
 template <typename A>
 bool File<A>::validMachOFile(const uint8_t* fileContent, uint64_t fileLength, const mach_o::relocatable::ParserOptions& opts)
@@ -258,10 +253,15 @@ bool File<A>::validFile(const uint8_t* fileContent, uint64_t fileLength, const m
        const Entry* const start = (Entry*)&fileContent[8];
        const Entry* const end = (Entry*)&fileContent[fileLength];
        for (const Entry* p=start; p < end; p = p->next()) {
-               const char* memberName = p->name();
+               char memberName[256];
+               p->getName(memberName, sizeof(memberName));
                // skip option table-of-content member
                if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
                        continue;
+#ifdef SYMDEF_64
+               if ( (p==start) && ((strcmp(memberName, SYMDEF_64_SORTED) == 0) || (strcmp(memberName, SYMDEF_64) == 0)) )
+                       continue;
+#endif
                // archive is valid if first .o file is valid
                return (validMachOFile(p->content(), p->contentSize(), opts) || validLTOFile(p->content(), p->contentSize(), opts));
        }       
@@ -272,10 +272,14 @@ bool File<A>::validFile(const uint8_t* fileContent, uint64_t fileLength, const m
 
 template <typename A>
 File<A>::File(const uint8_t fileContent[], uint64_t fileLength, const char* pth, time_t modTime, 
-                                       uint32_t ord, const ParserOptions& opts)
+                                       ld::File::Ordinal ord, const ParserOptions& opts)
  : ld::archive::File(strdup(pth), modTime, ord),
        _archiveFileContent(fileContent), _archiveFilelength(fileLength), 
-       _tableOfContents(NULL), _tableOfContentCount(0), _tableOfContentStrings(NULL), 
+       _tableOfContents(NULL),
+#ifdef SYMDEF_64
+       _tableOfContents64(NULL),
+#endif
+       _tableOfContentCount(0), _tableOfContentStrings(NULL),
        _forceLoadAll(opts.forceLoadAll), _forceLoadObjC(opts.forceLoadObjC), 
        _forceLoadThis(opts.forceLoadThisArchive), _objc2ABI(opts.objcABI2), _verboseLoad(opts.verboseLoad), 
        _logAllFiles(opts.logAllFiles), _objOpts(opts.objOpts)
@@ -285,7 +289,9 @@ File<A>::File(const uint8_t fileContent[], uint64_t fileLength, const char* pth,
 
        if ( !_forceLoadAll ) {
                const Entry* const firstMember = (Entry*)&_archiveFileContent[8];
-               if ( (strcmp(firstMember->name(), SYMDEF_SORTED) == 0) || (strcmp(firstMember->name(), SYMDEF) == 0) ) {
+               char memberName[256];
+               firstMember->getName(memberName, sizeof(memberName));
+               if ( (strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0) ) {
                        const uint8_t* contents = firstMember->content();
                        uint32_t ranlibArrayLen = E::get32(*((uint32_t*)contents));
                        _tableOfContents = (const struct ranlib*)&contents[4];
@@ -296,6 +302,19 @@ File<A>::File(const uint8_t fileContent[], uint64_t fileLength, const char* pth,
                                throw "malformed archive, perhaps wrong architecture";
                        this->buildHashTable();
                }
+#ifdef SYMDEF_64
+               else if ( (strcmp(memberName, SYMDEF_64_SORTED) == 0) || (strcmp(memberName, SYMDEF_64) == 0) ) {
+                       const uint8_t* contents = firstMember->content();
+                       uint64_t ranlibArrayLen = E::get64(*((uint64_t*)contents));
+                       _tableOfContents64 = (const struct ranlib_64*)&contents[8];
+                       _tableOfContentCount = ranlibArrayLen / sizeof(struct ranlib_64);
+                       _tableOfContentStrings = (const char*)&contents[ranlibArrayLen+16];
+                       if ( ((uint8_t*)(&_tableOfContents[_tableOfContentCount]) > &fileContent[fileLength])
+                               || ((uint8_t*)_tableOfContentStrings > &fileContent[fileLength]) )
+                               throw "malformed archive, perhaps wrong architecture";
+                       this->buildHashTable64();
+               }
+#endif
                else
                        throw "archive has no table of contents";
        }
@@ -310,16 +329,11 @@ bool File<x86>::memberHasObjCCategories(const Entry* member) const
        }
        else {
                // i386 uses ObjC1 ABI which has .objc_category* global symbols
-               return false;
+    // <rdar://problem/11342022> strip -S on i386 pulls out .objc_category_name symbols from static frameworks
+               return mach_o::relocatable::hasObjC1Categories(member->content());
        }
 }
 
-template <>
-bool File<ppc>::memberHasObjCCategories(const Entry* member) const
-{
-       // ppc uses ObjC1 ABI which has .objc_category* global symbols
-       return false;
-}
 
 
 template <typename A>
@@ -333,12 +347,37 @@ bool File<A>::memberHasObjCCategories(const Entry* member) const
 template <typename A>
 typename File<A>::MemberState& File<A>::makeObjectFileForMember(const Entry* member) const
 {
+       uint32_t memberIndex = 0;
        // in case member was instantiated earlier but not needed yet
        typename MemberToStateMap::iterator pos = _instantiatedEntries.find(member);
-       if ( pos != _instantiatedEntries.end() )
-               return pos->second;
-
-       const char* memberName = member->name();
+       if ( pos == _instantiatedEntries.end() ) {
+               // Have to find the index of this member
+               const Entry* start;
+               uint32_t index;
+               if (_instantiatedEntries.size() == 0) {
+                       start = (Entry*)&_archiveFileContent[8];
+                       index = 1;
+               } else {
+                       MemberState &lastKnown = _instantiatedEntries.rbegin()->second;
+                       start = lastKnown.entry->next();
+                       index = lastKnown.index+1;
+               }
+               for (const Entry* p=start; p <= member; p = p->next(), index++) {
+                       MemberState state = {NULL, p, false, false, index};
+                       _instantiatedEntries[p] = state;
+                       if (member == p) {
+                               memberIndex = index;
+                       }
+               }
+       } else {
+               MemberState& state = pos->second;
+               if (state.file)
+                       return state;
+               memberIndex = state.index;
+       }
+       assert(memberIndex != 0);
+       char memberName[256];
+       member->getName(memberName, sizeof(memberName));
        char memberPath[strlen(this->path()) + strlen(memberName)+4];
        strcpy(memberPath, this->path());
        strcat(memberPath, "(");
@@ -352,23 +391,22 @@ typename File<A>::MemberState& File<A>::makeObjectFileForMember(const Entry* mem
                if ( (member->content() + member->contentSize()) > (_archiveFileContent+_archiveFilelength) )
                        throwf("corrupt archive, member contents extends past end of file");                                                                            
                const char* mPath = strdup(memberPath);
-               // offset the ordinals in this mach-o .o file, so that atoms layout in same order as in archive
-               uint32_t memberIndex = ((uint8_t*)member - _archiveFileContent)/sizeof(ar_hdr);
                // see if member is mach-o file
+               ld::File::Ordinal ordinal = this->ordinal().archiveOrdinalWithMemberIndex(memberIndex);
                ld::relocatable::File* result = mach_o::relocatable::parse(member->content(), member->contentSize(), 
                                                                                                                                        mPath, member->modificationTime(), 
-                                                                                                                                       this->ordinal() + memberIndex, _objOpts);
+                                                                                                                                       ordinal, _objOpts);
                if ( result != NULL ) {
-                       MemberState state = {result, false, false};
+                       MemberState state = {result, member, false, false, memberIndex};
                        _instantiatedEntries[member] = state;
                        return _instantiatedEntries[member];
                }
                // see if member is llvm bitcode file
                result = lto::parse(member->content(), member->contentSize(), 
-                                                               mPath, member->modificationTime(), this->ordinal() + memberIndex
-                                                               _objOpts.architecture, _objOpts.subType, _logAllFiles);
+                                                               mPath, member->modificationTime(), ordinal
+                                                               _objOpts.architecture, _objOpts.subType, _logAllFiles, _objOpts.verboseOptimizationHints);
                if ( result != NULL ) {
-                       MemberState state = {result, false, false};
+                       MemberState state = {result, member, false, false, memberIndex};
                        _instantiatedEntries[member] = state;
                        return _instantiatedEntries[member];
                }
@@ -381,6 +419,25 @@ typename File<A>::MemberState& File<A>::makeObjectFileForMember(const Entry* mem
 }
 
 
+template <typename A>
+bool File<A>::loadMember(MemberState& state, ld::File::AtomHandler& handler, const char *format, ...) const
+{
+       bool didSomething = false;
+       if (!state.loaded) {
+               if ( _verboseLoad && !state.logged ) {
+                       va_list list;
+                       va_start(list, format);
+                       vprintf(format, list);
+                       va_end(list);
+                       state.logged = true;
+               }
+               state.loaded = true;
+               didSomething = state.file->forEachAtom(handler);
+       }
+       return didSomething;
+}
+
+
 template <typename A>
 bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
 {
@@ -390,53 +447,62 @@ bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
                const Entry* const start = (Entry*)&_archiveFileContent[8];
                const Entry* const end = (Entry*)&_archiveFileContent[_archiveFilelength];
                for (const Entry* p=start; p < end; p = p->next()) {
-                       const char* memberName = p->name();
+                       char memberName[256];
+                       p->getName(memberName, sizeof(memberName));
                        if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
                                continue;
+#ifdef SYMDEF_64
+                       if ( (p==start) && ((strcmp(memberName, SYMDEF_64_SORTED) == 0) || (strcmp(memberName, SYMDEF_64) == 0)) )
+                               continue;
+#endif
                        MemberState& state = this->makeObjectFileForMember(p);
-                       if ( _verboseLoad ) {
-                               if ( _forceLoadThis )
-                                       printf("-force_load forced load of %s(%s)\n", this->path(), memberName);
-                               else
-                                       printf("-all_load forced load of %s(%s)\n", this->path(), memberName);
-                               state.logged = true;
-                       }
-                       didSome |= state.file->forEachAtom(handler);
-                       state.loaded = true;
+                       didSome |= loadMember(state, handler, "%s forced load of %s(%s)\n", _forceLoadThis ? "-force_load" : "-all_load", this->path(), memberName);
                }
        }
        else if ( _forceLoadObjC ) {
                // call handler on all .o files in this archive containing objc classes
-               for(typename NameToEntryMap::const_iterator it = _hashTable.begin(); it != _hashTable.end(); ++it) {
-                       if ( (strncmp(it->first, ".objc_c", 7) == 0) || (strncmp(it->first, "_OBJC_CLASS_$_", 14) == 0) ) {
-                               const Entry* member = (Entry*)&_archiveFileContent[E::get32(it->second->ran_off)];
+               for (const auto& entry : _hashTable) {
+                       if ( (strncmp(entry.first, ".objc_c", 7) == 0) || (strncmp(entry.first, "_OBJC_CLASS_$_", 14) == 0) ) {
+                               const Entry* member = (Entry*)&_archiveFileContent[entry.second];
                                MemberState& state = this->makeObjectFileForMember(member);
-                               if ( _verboseLoad && !state.logged ) {
-                                       printf("-ObjC forced load of %s(%s)\n", this->path(), member->name());
-                                       state.logged = true;
-                               }
-                               if ( ! state.loaded ) {
-                                       didSome |= state.file->forEachAtom(handler);
-                                       state.loaded = true;
-                               }
+                               char memberName[256];
+                               member->getName(memberName, sizeof(memberName));
+                               didSome |= loadMember(state, handler, "-ObjC forced load of %s(%s)\n", this->path(), memberName);
                        }
                }
                // ObjC2 has no symbols in .o files with categories but not classes, look deeper for those
                const Entry* const start = (Entry*)&_archiveFileContent[8];
                const Entry* const end = (Entry*)&_archiveFileContent[_archiveFilelength];
                for (const Entry* member=start; member < end; member = member->next()) {
-                       // only look at files not already instantiated
-                       if ( _instantiatedEntries.count(member) == 0 ) {
-                               //fprintf(stderr, "checking member %s\n", member->name());
-                               if ( this->memberHasObjCCategories(member) ) {
-                                       MemberState& state = this->makeObjectFileForMember(member);
-                                       if ( _verboseLoad && !state.logged ) {
-                                               printf("-ObjC forced load of %s(%s)\n", this->path(), member->name());
-                                               state.logged = true;
+                       char mname[256];
+                       member->getName(mname, sizeof(mname));
+                       // skip table-of-content member
+                       if ( (member==start) && ((strcmp(mname, SYMDEF_SORTED) == 0) || (strcmp(mname, SYMDEF) == 0)) )
+                               continue;
+#ifdef SYMDEF_64
+                       if ( (member==start) && ((strcmp(mname, SYMDEF_64_SORTED) == 0) || (strcmp(mname, SYMDEF_64) == 0)) )
+                               continue;
+#endif
+                       if ( validMachOFile(member->content(), member->contentSize(), _objOpts) ) {
+                               MemberState& state = this->makeObjectFileForMember(member);
+                               // only look at files not already loaded
+                               if ( ! state.loaded ) {
+                                       if ( this->memberHasObjCCategories(member) ) {
+                                               MemberState& state = this->makeObjectFileForMember(member);
+                                               char memberName[256];
+                                               member->getName(memberName, sizeof(memberName));
+                                               didSome |= loadMember(state, handler, "-ObjC forced load of %s(%s)\n", this->path(), memberName);
                                        }
+                               }
+                       }
+                       else if ( validLTOFile(member->content(), member->contentSize(), _objOpts) ) {
+                               if ( lto::hasObjCCategory(member->content(), member->contentSize()) ) {
+                                       MemberState& state = this->makeObjectFileForMember(member);
+                                       // only look at files not already loaded
                                        if ( ! state.loaded ) {
-                                               didSome |= state.file->forEachAtom(handler);
-                                               state.loaded = true;
+                                               char memberName[256];
+                                               member->getName(memberName, sizeof(memberName));
+                                               didSome |= loadMember(state, handler, "-ObjC forced load of %s(%s)\n", this->path(), memberName);
                                        }
                                }
                        }
@@ -453,22 +519,16 @@ bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& han
                return false;
        
        // do a hash search of table of contents looking for requested symbol
-       const struct ranlib* result = ranlibHashSearch(name);
-       if ( result != NULL ) {
-               const Entry* member = (Entry*)&_archiveFileContent[E::get32(result->ran_off)];
-               MemberState& state = this->makeObjectFileForMember(member);
-               // only call handler for each member once
-               if ( ! state.loaded && !state.logged ) {
-                       if ( _verboseLoad ) {
-                               printf("%s forced load of %s(%s)\n", name, this->path(), member->name());
-                               state.logged = true;
-                       }
-                       state.loaded = true;
-                       return state.file->forEachAtom(handler);
-               }
-       }
-       //fprintf(stderr, "%s NOT found in archive %s\n", name, this->path());
-       return false;
+       const auto& pos = _hashTable.find(name);
+       if ( pos == _hashTable.end() )
+               return false;
+
+       // do a hash search of table of contents looking for requested symbol
+       const Entry* member = (Entry*)&_archiveFileContent[pos->second];
+       MemberState& state = this->makeObjectFileForMember(member);
+       char memberName[256];
+       member->getName(memberName, sizeof(memberName));
+       return loadMember(state, handler, "%s forced load of %s(%s)\n", name, this->path(), memberName);
 }
 
 class CheckIsDataSymbolHandler : public ld::File::AtomHandler
@@ -498,41 +558,27 @@ bool File<A>::justInTimeDataOnlyforEachAtom(const char* name, ld::File::AtomHand
                return false;
        
        // do a hash search of table of contents looking for requested symbol
-       const struct ranlib* result = ranlibHashSearch(name);
-       if ( result != NULL ) {
-               const Entry* member = (Entry*)&_archiveFileContent[E::get32(result->ran_off)];
-               MemberState& state = this->makeObjectFileForMember(member);
-               // only call handler for each member once
-               if ( ! state.loaded ) {
-                       CheckIsDataSymbolHandler checker(name);
-                       state.file->forEachAtom(checker);
-                       if ( checker.symbolIsDataDefinition() ) {
-                               if ( _verboseLoad && !state.logged ) {
-                                       printf("%s forced load of %s(%s)\n", name, this->path(), member->name());
-                                       state.logged = true;
-                               }
-                               state.loaded = true;
-                               return state.file->forEachAtom(handler);
-                       }
+       const auto& pos = _hashTable.find(name);
+       if ( pos == _hashTable.end() )
+               return false;
+
+       const Entry* member = (Entry*)&_archiveFileContent[pos->second];
+       MemberState& state = this->makeObjectFileForMember(member);
+       // only call handler for each member once
+       if ( ! state.loaded ) {
+               CheckIsDataSymbolHandler checker(name);
+               state.file->forEachAtom(checker);
+               if ( checker.symbolIsDataDefinition() ) {
+                       char memberName[256];
+                       member->getName(memberName, sizeof(memberName));
+                       return loadMember(state, handler, "%s forced load of %s(%s)\n", name, this->path(), memberName);
                }
        }
+
        //fprintf(stderr, "%s NOT found in archive %s\n", name, this->path());
        return false;
 }
 
-
-typedef const struct ranlib* ConstRanLibPtr;
-
-template <typename A>
-ConstRanLibPtr  File<A>::ranlibHashSearch(const char* name) const
-{
-       typename NameToEntryMap::const_iterator pos = _hashTable.find(name);
-       if ( pos != _hashTable.end() )
-               return pos->second;
-       else
-               return NULL;
-}
-
 template <typename A>
 void File<A>::buildHashTable()
 {
@@ -541,16 +587,38 @@ void File<A>::buildHashTable()
        for (int i = _tableOfContentCount-1; i >= 0; --i) {
                const struct ranlib* entry = &_tableOfContents[i];
                const char* entryName = &_tableOfContentStrings[E::get32(entry->ran_un.ran_strx)];
-               if ( E::get32(entry->ran_off) > _archiveFilelength ) {
+               uint64_t offset = E::get32(entry->ran_off);
+               if ( offset > _archiveFilelength ) {
                        throwf("malformed archive TOC entry for %s, offset %d is beyond end of file %lld\n",
                                entryName, entry->ran_off, _archiveFilelength);
                }
                
                //const Entry* member = (Entry*)&_archiveFileContent[E::get32(entry->ran_off)];
                //fprintf(stderr, "adding hash %d, %s -> %p\n", i, entryName, entry);
-               _hashTable[entryName] = entry;
+               _hashTable[entryName] = offset;
+       }
+}
+
+#ifdef SYMDEF_64
+template <typename A>
+void File<A>::buildHashTable64()
+{
+       // walk through list backwards, adding/overwriting entries
+       // this assures that with duplicates those earliest in the list will be found
+       for (int i = _tableOfContentCount-1; i >= 0; --i) {
+               const struct ranlib_64* entry = &_tableOfContents64[i];
+               const char* entryName = &_tableOfContentStrings[E::get64(entry->ran_un.ran_strx)];
+               uint64_t offset = E::get64(entry->ran_off);
+               if ( offset > _archiveFilelength ) {
+                       throwf("malformed archive TOC entry for %s, offset %lld is beyond end of file %lld\n",
+                               entryName, entry->ran_off, _archiveFilelength);
+               }
+
+               //fprintf(stderr, "adding hash %d: %s -> 0x%0llX\n", i, entryName, offset);
+               _hashTable[entryName] = offset;
        }
 }
+#endif
 
 template <typename A>
 void File<A>::dumpTableOfContents()
@@ -566,29 +634,33 @@ void File<A>::dumpTableOfContents()
 // main function used by linker to instantiate archive files
 //
 ld::archive::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
-                               const char* path, time_t modTime, uint32_t ordinal, const ParserOptions& opts)
+                               const char* path, time_t modTime, ld::File::Ordinal ordinal, const ParserOptions& opts)
 {
        switch ( opts.objOpts.architecture ) {
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        if ( archive::Parser<x86_64>::validFile(fileContent, fileLength, opts.objOpts) )
                                return archive::Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
                        break;
+#endif
+#if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        if ( archive::Parser<x86>::validFile(fileContent, fileLength, opts.objOpts) )
                                return archive::Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
                        break;
+#endif
+#if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
                        if ( archive::Parser<arm>::validFile(fileContent, fileLength, opts.objOpts) )
                                return archive::Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
                        break;
-               case CPU_TYPE_POWERPC:
-                       if ( archive::Parser<ppc>::validFile(fileContent, fileLength, opts.objOpts) )
-                               return archive::Parser<ppc>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
-                       break;
-               case CPU_TYPE_POWERPC64:
-                       if ( archive::Parser<ppc64>::validFile(fileContent, fileLength, opts.objOpts) )
-                               return archive::Parser<ppc64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       if ( archive::Parser<arm64>::validFile(fileContent, fileLength, opts.objOpts) )
+                               return archive::Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
                        break;
+#endif
        }
        return NULL;
 }