]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/passes/got.cpp
ld64-274.2.tar.gz
[apple/ld64.git] / src / ld / passes / got.cpp
index 66caf346cc9a05ed6e3035036c52b8e846ce0aa1..01c2e308ba53f0905b75a891ab0a22e7ce9b54a0 100644 (file)
@@ -44,8 +44,8 @@ class File; // forward reference
 
 class GOTEntryAtom : public ld::Atom {
 public:
-                                                                                       GOTEntryAtom(ld::Internal& internal, const ld::Atom* target, bool weakImport, bool is64)
-                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                                                       GOTEntryAtom(ld::Internal& internal, const ld::Atom* target, bool weakImport, bool weakDef, bool is64)
+                               : ld::Atom(weakDef ? _s_sectionWeak : _s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
                                                        symbolTableNotIn, false, false, false, (is64 ? ld::Atom::Alignment(3) : ld::Atom::Alignment(2))),
                                _fixup(0, ld::Fixup::k1of1, (is64 ? ld::Fixup::kindStoreTargetAddressLittleEndian64 : ld::Fixup::kindStoreTargetAddressLittleEndian32), target),
@@ -68,13 +68,16 @@ private:
        bool                                                                    _is64;
        
        static ld::Section                                              _s_section;
+       static ld::Section                                              _s_sectionWeak;
 };
 
 ld::Section GOTEntryAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
+ld::Section GOTEntryAtom::_s_sectionWeak("__DATA", "__got_weak", ld::Section::typeNonLazyPointer);
 
 
-static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom* targetOfGOT, const ld::Fixup* fixup, bool* optimizable)
+static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom* targetOfGOT, const ld::Fixup* fixup, bool* optimizable, bool* targetIsExternalWeakDef)
 {
+       *targetIsExternalWeakDef = false;
        switch (fixup->kind) {
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
 #if SUPPORT_ARCH_arm64
@@ -92,14 +95,15 @@ static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom
                                                                                                || (targetOfGOT->section().type() == ld::Section::typeTentativeDefs)) ) {
                                *optimizable = false;
                        }
-                       if ( targetOfGOT->scope() == ld::Atom::scopeGlobal ) {  
+                       if ( targetOfGOT->scope() == ld::Atom::scopeGlobal ) {
                                // cannot do LEA optimization if target is weak exported symbol
-                               if ( (targetOfGOT->definition() == ld::Atom::definitionRegular) && (targetOfGOT->combine() == ld::Atom::combineByName) ) {
+                               if ( ((targetOfGOT->definition() == ld::Atom::definitionRegular) || (targetOfGOT->definition() == ld::Atom::definitionProxy)) && (targetOfGOT->combine() == ld::Atom::combineByName) ) {
                                        switch ( opts.outputKind() ) {
                                                case Options::kDynamicExecutable:
                                                case Options::kDynamicLibrary:
                                                case Options::kDynamicBundle:
                                                case Options::kKextBundle:
+                                                       *targetIsExternalWeakDef = true;
                                                        *optimizable = false;
                                                        break;
                                                case Options::kStaticExecutable:
@@ -199,6 +203,7 @@ void doPass(const Options& opts, ld::Internal& internal)
        // don't create GOT atoms during this loop because that could invalidate the sections iterator
        std::vector<const ld::Atom*> atomsReferencingGOT;
        std::map<const ld::Atom*,bool>          weakImportMap;
+       std::map<const ld::Atom*,bool>          weakDefMap;
        atomsReferencingGOT.reserve(128);
        for (std::vector<ld::Internal::FinalSection*>::iterator sit=internal.sections.begin(); sit != internal.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
@@ -223,7 +228,8 @@ void doPass(const Options& opts, ld::Internal& internal)
                         break;   
                                }
                                bool optimizable;
-                               if ( !gotFixup(opts, internal, targetOfGOT, fit, &optimizable) )
+                               bool targetIsExternalWeakDef;
+                               if ( !gotFixup(opts, internal, targetOfGOT, fit, &optimizable, &targetIsExternalWeakDef) )
                                        continue;
                                if ( optimizable ) {
                                        // change from load of GOT entry to lea of target
@@ -264,6 +270,8 @@ void doPass(const Options& opts, ld::Internal& internal)
                                        }
                                        if ( gotMap.count(targetOfGOT) == 0 )
                                                gotMap[targetOfGOT] = NULL;
+                                       // record if target is weak def
+                                       weakDefMap[targetOfGOT] = targetIsExternalWeakDef;
                                        // record weak_import attribute
                                        std::map<const ld::Atom*,bool>::iterator pos = weakImportMap.find(targetOfGOT);
                                        if ( pos == weakImportMap.end() ) {
@@ -319,7 +327,7 @@ void doPass(const Options& opts, ld::Internal& internal)
        // make GOT entries
        for (auto& entry : gotMap) {
                if ( entry.second == NULL ) {
-                       entry.second = new GOTEntryAtom(internal, entry.first, weakImportMap[entry.first], is64);
+                       entry.second = new GOTEntryAtom(internal, entry.first, weakImportMap[entry.first], opts.useDataConstSegment() && weakDefMap[entry.first], is64);
                        if (log) fprintf(stderr, "making new GOT slot for %s, gotMap[%p] = %p\n", entry.first->name(), entry.first, entry.second);
                }
        }
@@ -348,7 +356,8 @@ void doPass(const Options& opts, ld::Internal& internal)
                     break;    
                        }
                        bool optimizable;
-                       if ( (targetOfGOT == NULL) || !gotFixup(opts, internal, targetOfGOT, fit, &optimizable) )
+                       bool targetIsExternalWeakDef;
+                       if ( (targetOfGOT == NULL) || !gotFixup(opts, internal, targetOfGOT, fit, &optimizable, &targetIsExternalWeakDef) )
                                continue;
                        if ( !optimizable ) {
                                // GOT use not optimized away, update to bind to GOT entry