]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/parsers/macho_dylib_file.cpp
ld64-278.4.tar.gz
[apple/ld64.git] / src / ld / parsers / macho_dylib_file.cpp
index 24d69c861e28d40004d171bea4fabd019306bf95..56b327ac097c595e803c963de111e75ae5209c85 100644 (file)
@@ -61,8 +61,8 @@ public:
                                                                                        File(const uint8_t* fileContent, uint64_t fileLength, const char* path,   
                                                                                                        time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace, 
                                                                                                        bool linkingMainExecutable, bool hoistImplicitPublicDylibs, 
-                                                                                                       Options::Platform platform, uint32_t linkMinOSVersion, bool allowSimToMacOSX,
-                                                                                                       bool addVers,  bool buildingForSimulator,
+                                                                                                       Options::Platform platform, uint32_t linkMinOSVersion, bool allowWeakImports,
+                                                                                                       bool allowSimToMacOSX, bool addVers,  bool buildingForSimulator,
                                                                                                        bool logAllFiles, const char* installPath,
                                                                                                        bool indirectDylib, bool ignoreMismatchPlatform, bool usingBitcode);
        virtual                                                                 ~File() noexcept {}
@@ -70,6 +70,7 @@ public:
 private:
        using P = typename A::P;
        using E = typename A::P::E;
+       using pint_t = typename A::P::uint_t;
 
        void                            addDyldFastStub();
        void                            buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo,
@@ -77,6 +78,7 @@ private:
        void                            buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo,
                                                                                                                const macho_nlist<P>* symbolTable, const char* strings,
                                                                                                                const uint8_t* fileContent);
+       void                            addSymbol(const char* name, bool weakDef = false, bool tlv = false, pint_t address = 0);
        static const char*      objCInfoSegmentName();
        static const char*      objCInfoSectionName();
 
@@ -97,11 +99,11 @@ template <typename A> const char* File<A>::objCInfoSectionName() { return "__ima
 template <typename A>
 File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t mTime,
                          ld::File::Ordinal ord, bool linkingFlatNamespace, bool linkingMainExecutable,
-                         bool hoistImplicitPublicDylibs, Options::Platform platform, uint32_t linkMinOSVersion,
+                         bool hoistImplicitPublicDylibs, Options::Platform platform, uint32_t linkMinOSVersion, bool allowWeakImports,
                          bool allowSimToMacOSX, bool addVers, bool buildingForSimulator, bool logAllFiles,
                          const char* targetInstallPath, bool indirectDylib, bool ignoreMismatchPlatform, bool usingBitcode)
-       : Base(strdup(path), mTime, ord, platform, linkMinOSVersion, linkingFlatNamespace,
-                  hoistImplicitPublicDylibs,   allowSimToMacOSX, addVers), _fileLength(fileLength), _linkeditStartOffset(0)
+       : Base(strdup(path), mTime, ord, platform, linkMinOSVersion, allowWeakImports, linkingFlatNamespace,
+                  hoistImplicitPublicDylibs, allowSimToMacOSX, addVers), _fileLength(fileLength), _linkeditStartOffset(0)
 {
        const macho_header<P>* header = (const macho_header<P>*)fileContent;
        const uint32_t cmd_count = header->ncmds();
@@ -185,6 +187,9 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
                                // <rdar://problem/20627554> Don't hoist "public" (in /usr/lib/) dylibs that should not be directly linked
                                this->_hasPublicInstallName = false;
                                break;
+                       case LC_RPATH:
+                               this->_rpaths.push_back(strdup(((macho_rpath_command<P>*)cmd)->path()));
+                               break;
                        case LC_VERSION_MIN_MACOSX:
                        case LC_VERSION_MIN_IPHONEOS:
                        case LC_VERSION_MIN_WATCHOS:
@@ -521,6 +526,67 @@ void File<A>::buildExportHashTableFromExportInfo(const macho_dyld_info_command<P
        }
 }
 
+template <typename A>
+void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address)
+{
+       // symbols that start with $ld$ are meta-data to the static linker
+       // <rdar://problem/5182537> need way for ld and dyld to see different exported symbols in a dylib
+       if ( strncmp(name, "$ld$", 4) == 0 ) {
+               //    $ld$ <action> $ <condition> $ <symbol-name>
+               const char* symAction = &name[4];
+               const char* symCond = strchr(symAction, '$');
+               if ( symCond != nullptr ) {
+                       char curOSVers[16];
+                       sprintf(curOSVers, "$os%d.%d$", (this->_linkMinOSVersion >> 16), ((this->_linkMinOSVersion >> 8) & 0xFF));
+                       if ( strncmp(symCond, curOSVers, strlen(curOSVers)) == 0 ) {
+                               const char* symName = strchr(&symCond[1], '$');
+                               if ( symName != nullptr ) {
+                                       ++symName;
+                                       if ( strncmp(symAction, "hide$", 5) == 0 ) {
+                                               if ( this->_s_logHashtable )
+                                                       fprintf(stderr, "  adding %s to ignore set for %s\n", symName, this->path());
+                                               this->_ignoreExports.insert(strdup(symName));
+                                               return;
+                                       }
+                                       else if ( strncmp(symAction, "add$", 4) == 0 ) {
+                                               this->addSymbol(symName, weakDef);
+                                               return;
+                                       }
+                                       else if ( strncmp(symAction, "weak$", 5) == 0 ) {
+                                               if ( !this->_allowWeakImports )
+                                                       this->_ignoreExports.insert(strdup(symName));
+                                       }
+                                       else if ( strncmp(symAction, "install_name$", 13) == 0 ) {
+                                               this->_dylibInstallPath = symName;
+                                               this->_installPathOverride = true;
+                                               // <rdar://problem/14448206> CoreGraphics redirects to ApplicationServices, but with wrong compat version
+                                               if ( strcmp(this->_dylibInstallPath, "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices") == 0 )
+                                                       this->_dylibCompatibilityVersion = Options::parseVersionNumber32("1.0");
+                                               return;
+                                       }
+                                       else if ( strncmp(symAction, "compatibility_version$", 22) == 0 ) {
+                                               this->_dylibCompatibilityVersion = Options::parseVersionNumber32(symName);
+                                               return;
+                                       }
+                                       else {
+                                               warning("bad symbol action: %s in dylib %s", name, this->path());
+                                       }
+                               }
+                       }
+               }
+               else {
+                       warning("bad symbol condition: %s in dylib %s", name, this->path());
+               }
+       }
+
+       // add symbol as possible export if we are not supposed to ignore it
+       if ( this->_ignoreExports.count(name) == 0 ) {
+               typename Base::AtomAndWeak bucket = { nullptr, weakDef, tlv, address };
+               if ( this->_s_logHashtable )
+                       fprintf(stderr, "  adding %s to hash table for %s\n", name, this->path());
+               this->_atoms[strdup(name)] = bucket;
+       }
+}
 
 template <>
 void File<x86_64>::addDyldFastStub()
@@ -554,7 +620,7 @@ public:
        {
                return new File<A>(fileContent, fileLength, path, mTime, ordinal, opts.flatNamespace(),
                                                   opts.linkingMainExecutable(), opts.implicitlyLinkIndirectPublicDylibs(),
-                                                  opts.platform(), opts.minOSversion(),
+                                                  opts.platform(), opts.minOSversion(), opts.allowWeakImports(),
                                                   opts.allowSimulatorToLinkWithMacOSX(), opts.addVersionLoadCommand(),
                                                   opts.targetIOSSimulator(), opts.logAllFiles(), opts.installPath(),
                                                   indirectDylib, opts.outputKind() == Options::kPreload, opts.bundleBitcode());
@@ -755,6 +821,7 @@ const char* Parser<arm64>::fileKind(const uint8_t* fileContent)
 }
 #endif
 
+
 //
 // used by linker is error messages to describe mismatched files
 //