X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/a645023da60d22e86be13f7b4d97adeff8bc6665..b2fa67a80bc53211e4d1ea81f23e9f953ee1dd6c:/src/ld/parsers/archive_file.cpp diff --git a/src/ld/parsers/archive_file.cpp b/src/ld/parsers/archive_file.cpp index 8c866cd..cf0a058 100644 --- a/src/ld/parsers/archive_file.cpp +++ b/src/ld/parsers/archive_file.cpp @@ -1,6 +1,6 @@ /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- * - * Copyright (c) 2005-2009 Apple Inc. All rights reserved. + * Copyright (c) 2005-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -69,7 +70,7 @@ public: }; template -class File : public ld::File +class File : public ld::archive::File { public: static bool validFile(const uint8_t* fileContent, uint64_t fileLength, @@ -84,6 +85,9 @@ public: virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const; virtual uint32_t subFileCount() const { return _archiveFilelength/sizeof(ar_hdr); } + // overrides of ld::archive::File + virtual bool justInTimeDataOnlyforEachAtom(const char* name, ld::File::AtomHandler& handler) const; + private: static bool validMachOFile(const uint8_t* fileContent, uint64_t fileLength, const mach_o::relocatable::ParserOptions& opts); @@ -91,7 +95,6 @@ private: const mach_o::relocatable::ParserOptions& opts); static cpu_type_t architecture(); - class Entry : ar_hdr { public: @@ -116,8 +119,12 @@ private: typedef typename A::P P; typedef typename A::P::E E; + struct MemberState { ld::relocatable::File* file; bool logged; bool loaded; }; + + typedef std::map MemberToStateMap; + const struct ranlib* ranlibHashSearch(const char* name) const; - ld::relocatable::File* makeObjectFileForMember(const Entry* member) const; + MemberState& makeObjectFileForMember(const Entry* member) const; bool memberHasObjCCategories(const Entry* member) const; void dumpTableOfContents(); void buildHashTable(); @@ -127,12 +134,12 @@ private: const struct ranlib* _tableOfContents; uint32_t _tableOfContentCount; const char* _tableOfContentStrings; - mutable std::vector _instantiatedFiles; - mutable std::set _instantiatedEntries; + mutable MemberToStateMap _instantiatedEntries; NameToEntryMap _hashTable; const bool _forceLoadAll; const bool _forceLoadObjC; const bool _forceLoadThis; + const bool _objc2ABI; const bool _verboseLoad; const bool _logAllFiles; const mach_o::relocatable::ParserOptions _objOpts; @@ -219,8 +226,6 @@ const class File::Entry* File::Entry::next() const } -template <> cpu_type_t File::architecture() { return CPU_TYPE_POWERPC; } -template <> cpu_type_t File::architecture() { return CPU_TYPE_POWERPC64; } template <> cpu_type_t File::architecture() { return CPU_TYPE_I386; } template <> cpu_type_t File::architecture() { return CPU_TYPE_X86_64; } template <> cpu_type_t File::architecture() { return CPU_TYPE_ARM; } @@ -266,11 +271,11 @@ bool File::validFile(const uint8_t* fileContent, uint64_t fileLength, const m template File::File(const uint8_t fileContent[], uint64_t fileLength, const char* pth, time_t modTime, uint32_t ord, const ParserOptions& opts) - : ld::File(strdup(pth), modTime, ord), + : ld::archive::File(strdup(pth), modTime, ord), _archiveFileContent(fileContent), _archiveFilelength(fileLength), _tableOfContents(NULL), _tableOfContentCount(0), _tableOfContentStrings(NULL), _forceLoadAll(opts.forceLoadAll), _forceLoadObjC(opts.forceLoadObjC), - _forceLoadThis(opts.forceLoadThisArchive), _verboseLoad(opts.verboseLoad), + _forceLoadThis(opts.forceLoadThisArchive), _objc2ABI(opts.objcABI2), _verboseLoad(opts.verboseLoad), _logAllFiles(opts.logAllFiles), _objOpts(opts.objOpts) { if ( strncmp((const char*)fileContent, "!\n", 8) != 0 ) @@ -297,16 +302,16 @@ File::File(const uint8_t fileContent[], uint64_t fileLength, const char* pth, template <> bool File::memberHasObjCCategories(const Entry* member) const { - // i386 uses ObjC1 ABI which has .objc_category* global symbols - return false; + if ( _objc2ABI ) { + // i386 for iOS simulator uses ObjC2 which has no global symbol for categories + return mach_o::relocatable::hasObjC2Categories(member->content()); + } + else { + // i386 uses ObjC1 ABI which has .objc_category* global symbols + return false; + } } -template <> -bool File::memberHasObjCCategories(const Entry* member) const -{ - // ppc uses ObjC1 ABI which has .objc_category* global symbols - return false; -} template @@ -318,8 +323,13 @@ bool File::memberHasObjCCategories(const Entry* member) const template -ld::relocatable::File* File::makeObjectFileForMember(const Entry* member) const +typename File::MemberState& File::makeObjectFileForMember(const Entry* member) const { + // 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(); char memberPath[strlen(this->path()) + strlen(memberName)+4]; strcpy(memberPath, this->path()); @@ -340,14 +350,20 @@ ld::relocatable::File* File::makeObjectFileForMember(const Entry* member) con ld::relocatable::File* result = mach_o::relocatable::parse(member->content(), member->contentSize(), mPath, member->modificationTime(), this->ordinal() + memberIndex, _objOpts); - if ( result != NULL ) - return result; + if ( result != NULL ) { + MemberState state = {result, false, false}; + _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); - if ( result != NULL ) - return result; + if ( result != NULL ) { + MemberState state = {result, false, false}; + _instantiatedEntries[member] = state; + return _instantiatedEntries[member]; + } throwf("archive member '%s' with length %d is not mach-o or llvm bitcode", memberName, member->contentSize()); } @@ -369,14 +385,16 @@ bool File::forEachAtom(ld::File::AtomHandler& handler) const const char* memberName = p->name(); if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) ) continue; + 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; } - ld::relocatable::File* file = this->makeObjectFileForMember(p); - didSome |= file->forEachAtom(handler); + didSome |= state.file->forEachAtom(handler); + state.loaded = true; } } else if ( _forceLoadObjC ) { @@ -384,18 +402,18 @@ bool File::forEachAtom(ld::File::AtomHandler& handler) const 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)]; - if ( _instantiatedEntries.count(member) == 0 ) { - if ( _verboseLoad ) - printf("-ObjC forced load of %s(%s)\n", this->path(), member->name()); - // only return these atoms once - _instantiatedEntries.insert(member); - ld::relocatable::File* file = this->makeObjectFileForMember(member); - didSome |= file->forEachAtom(handler); - _instantiatedFiles.push_back(file); + 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; } } } - // ObjC2 has no symbols in .o files with categories, but not classes, look deeper for those + // 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()) { @@ -403,13 +421,15 @@ bool File::forEachAtom(ld::File::AtomHandler& handler) const if ( _instantiatedEntries.count(member) == 0 ) { //fprintf(stderr, "checking member %s\n", member->name()); if ( this->memberHasObjCCategories(member) ) { - if ( _verboseLoad ) + MemberState& state = this->makeObjectFileForMember(member); + if ( _verboseLoad && !state.logged ) { printf("-ObjC forced load of %s(%s)\n", this->path(), member->name()); - // only return these atoms once - _instantiatedEntries.insert(member); - ld::relocatable::File* file = this->makeObjectFileForMember(member); - didSome |= file->forEachAtom(handler); - _instantiatedFiles.push_back(file); + state.logged = true; + } + if ( ! state.loaded ) { + didSome |= state.file->forEachAtom(handler); + state.loaded = true; + } } } } @@ -428,14 +448,64 @@ bool File::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& han 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 ( _instantiatedEntries.count(member) == 0 ) { - _instantiatedEntries.insert(member); - if ( _verboseLoad ) + if ( ! state.loaded && !state.logged ) { + if ( _verboseLoad ) { printf("%s forced load of %s(%s)\n", name, this->path(), member->name()); - ld::relocatable::File* file = this->makeObjectFileForMember(member); - _instantiatedFiles.push_back(file); - return file->forEachAtom(handler); + 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; +} + +class CheckIsDataSymbolHandler : public ld::File::AtomHandler +{ +public: + CheckIsDataSymbolHandler(const char* n) : _name(n), _isData(false) {} + virtual void doAtom(const class ld::Atom& atom) { + if ( strcmp(atom.name(), _name) == 0 ) { + if ( atom.section().type() != ld::Section::typeCode ) + _isData = true; + } + } + virtual void doFile(const class ld::File&) {} + bool symbolIsDataDefinition() { return _isData; } + +private: + const char* _name; + bool _isData; + +}; + +template +bool File::justInTimeDataOnlyforEachAtom(const char* name, ld::File::AtomHandler& handler) const +{ + // in force load case, all members already loaded + if ( _forceLoadAll || _forceLoadThis ) + 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); + } } } //fprintf(stderr, "%s NOT found in archive %s\n", name, this->path()); @@ -487,7 +557,7 @@ void File::dumpTableOfContents() // // main function used by linker to instantiate archive files // -ld::File* parse(const uint8_t* fileContent, uint64_t fileLength, +ld::archive::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, uint32_t ordinal, const ParserOptions& opts) { switch ( opts.objOpts.architecture ) { @@ -503,14 +573,6 @@ ld::File* parse(const uint8_t* fileContent, uint64_t fileLength, if ( archive::Parser::validFile(fileContent, fileLength, opts.objOpts) ) return archive::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); break; - case CPU_TYPE_POWERPC: - if ( archive::Parser::validFile(fileContent, fileLength, opts.objOpts) ) - return archive::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); - break; - case CPU_TYPE_POWERPC64: - if ( archive::Parser::validFile(fileContent, fileLength, opts.objOpts) ) - return archive::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); - break; } return NULL; }