]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/ld.cpp
ld64-302.3.tar.gz
[apple/ld64.git] / src / ld / ld.cpp
index a856598108348ed33ea12dd04a53cfa2693658bf..a8d2276651f078ca402709b4a81c7f94696599e3 100644 (file)
@@ -118,6 +118,8 @@ public:
 
        virtual                                                                 ~InternalState() {}
 private:
+       bool                                                                    inMoveRWChain(const ld::Atom& atom, const char* filePath, const char*& dstSeg, bool& wildCardMatch);
+       bool                                                                    inMoveROChain(const ld::Atom& atom, const char* filePath, const char*& dstSeg, bool& wildCardMatch);
 
        class FinalSection : public ld::Internal::FinalSection 
        {
@@ -161,6 +163,7 @@ private:
        SectionInToOut                  _sectionInToFinalMap;
        const Options&                  _options;
        bool                                    _atomsOrderedInSections;
+       std::unordered_map<const ld::Atom*, const char*> _pendingSegMove;
 };
 
 ld::Section    InternalState::FinalSection::_s_DATA_data( "__DATA", "__data",  ld::Section::typeUnclassified);
@@ -196,7 +199,7 @@ InternalState::FinalSection::FinalSection(const ld::Section& sect, uint32_t sect
          _segmentOrder(segmentOrder(sect, opts)),
          _sectionOrder(sectionOrder(sect, sectionsSeen, opts))
 {
-       //fprintf(stderr, "FinalSection(%s, %s) _segmentOrder=%d, _sectionOrder=%d\n", 
+       //fprintf(stderr, "FinalSection(%16s, %16s) _segmentOrder=%3d, _sectionOrder=0x%08X\n",
        //              this->segmentName(), this->sectionName(), _segmentOrder, _sectionOrder);
 }
 
@@ -290,18 +293,33 @@ uint32_t InternalState::FinalSection::segmentOrder(const ld::Section& sect, cons
                if ( strcmp(sect.segmentName(), "__DATA") == 0 ) 
                        return order.size()+2;
        }
+       else if ( options.outputKind() == Options::kStaticExecutable ) {
+               const std::vector<const char*>& order = options.segmentOrder();
+               for (size_t i=0; i != order.size(); ++i) {
+                       if ( strcmp(sect.segmentName(), order[i]) == 0 )
+                               return i+1;
+               }
+               if ( strcmp(sect.segmentName(), "__PAGEZERO") == 0 )
+                       return 0;
+               if ( strcmp(sect.segmentName(), "__TEXT") == 0 )
+                       return order.size()+1;
+               if ( strcmp(sect.segmentName(), "__DATA") == 0 )
+                       return order.size()+2;
+       }
        else {
                if ( strcmp(sect.segmentName(), "__PAGEZERO") == 0 ) 
                        return 0;
                if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) 
                        return 1;
+               if ( strcmp(sect.segmentName(), "__TEXT_EXEC") == 0 )
+                       return 2;
                // in -r mode, want __DATA  last so zerofill sections are at end
                if ( strcmp(sect.segmentName(), "__DATA") == 0 ) 
-                       return (options.outputKind() == Options::kObjectFile) ? 5 : 2;
+                       return (options.outputKind() == Options::kObjectFile) ? 6 : 3;
                if ( strcmp(sect.segmentName(), "__OBJC") == 0 ) 
-                       return 3;
-               if ( strcmp(sect.segmentName(), "__IMPORT") == 0 ) 
                        return 4;
+               if ( strcmp(sect.segmentName(), "__IMPORT") == 0 )
+                       return 5;
        }
        // layout non-standard segments in order seen (+100 to shift beyond standard segments)
        for (uint32_t i=0; i < _s_segmentsSeen.size(); ++i) {
@@ -336,16 +354,21 @@ uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint
                                        return 10;
                                else
                                        return 11;
+                       case ld::Section::typeNonStdCString:
+                               if ( (strcmp(sect.sectionName(), "__oslogstring") == 0) && options.makeEncryptable() )
+                                       return INT_MAX-1;
+                               else
+                                       return sectionsSeen+20;
                        case ld::Section::typeStub:
                                return 12;
                        case ld::Section::typeStubHelper:
                                return 13;
                        case ld::Section::typeLSDA:
-                               return INT_MAX-3;
+                               return INT_MAX-4;
                        case ld::Section::typeUnwindInfo:
-                               return INT_MAX-2;
+                               return INT_MAX-3;
                        case ld::Section::typeCFI:
-                               return INT_MAX-1;
+                               return INT_MAX-2;
                        case ld::Section::typeStubClose:
                                return INT_MAX;
                        default:
@@ -367,15 +390,15 @@ uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint
                        case ld::Section::typeTerminatorPointers:
                                return 13;
                        case ld::Section::typeTLVInitialValues:
-                               return INT_MAX-4; // need TLV zero-fill to follow TLV init values
+                               return INT_MAX-259; // need TLV zero-fill to follow TLV init values
                        case ld::Section::typeTLVZeroFill:
-                               return INT_MAX-3;
+                               return INT_MAX-258;
                        case ld::Section::typeZeroFill:
                                // make sure __huge is always last zerofill section
                                if ( strcmp(sect.sectionName(), "__huge") == 0 )
                                        return INT_MAX-1;
                                else
-                                       return INT_MAX-2;
+                                       return INT_MAX-256+sectionsSeen; // <rdar://problem/25448494> zero fill need to be last and in "seen" order
                        default:
                                // <rdar://problem/14348664> __DATA,__const section should be near __mod_init_func not __data
                                if ( strcmp(sect.sectionName(), "__const") == 0 )
@@ -418,7 +441,7 @@ uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint
        }
        // make sure zerofill in any other section is at end of segment
        if ( sect.type() == ld::Section::typeZeroFill )
-               return INT_MAX-1;
+               return INT_MAX-256+sectionsSeen;
        return sectionsSeen+20;
 }
 
@@ -537,10 +560,90 @@ bool InternalState::hasReferenceToWeakExternal(const ld::Atom& atom)
        return false;
 }
 
+bool InternalState::inMoveRWChain(const ld::Atom& atom, const char* filePath, const char*& dstSeg, bool& wildCardMatch)
+{
+       if ( !_options.hasDataSymbolMoves() )
+               return false;
+
+       auto pos = _pendingSegMove.find(&atom);
+       if ( pos != _pendingSegMove.end() ) {
+               dstSeg = pos->second;
+               return true;
+       }
+
+       bool result = false;
+       if ( _options.moveRwSymbol(atom.name(), filePath, dstSeg, wildCardMatch) )
+               result = true;
+
+       for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
+               if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+                       if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                               if ( inMoveRWChain(*(fit->u.target), filePath, dstSeg, wildCardMatch) )
+                                       result = true;
+                       }
+               }
+       }
+
+       if ( result ) {
+               for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
+                       if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+                               if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                                       _pendingSegMove[fit->u.target] = dstSeg;
+                               }
+                       }
+               }
+       }
+
+       return result;
+}
+
+
+bool InternalState::inMoveROChain(const ld::Atom& atom, const char* filePath, const char*& dstSeg, bool& wildCardMatch)
+{
+       if ( !_options.hasCodeSymbolMoves() )
+               return false;
+
+       auto pos = _pendingSegMove.find(&atom);
+       if ( pos != _pendingSegMove.end() ) {
+               dstSeg = pos->second;
+               return true;
+       }
+
+       bool result = false;
+       if ( _options.moveRoSymbol(atom.name(), filePath, dstSeg, wildCardMatch) )
+               result = true;
+
+       for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
+               if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+                       if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                               if ( inMoveROChain(*(fit->u.target), filePath, dstSeg, wildCardMatch) )
+                                       result = true;
+                       }
+               }
+       }
+
+       if ( result ) {
+               for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
+                       if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+                               if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                                       _pendingSegMove[fit->u.target] = dstSeg;
+                               }
+                       }
+               }
+       }
+
+       return result;
+}
+
+
+
+
 ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
 {
+       //fprintf(stderr, "addAtom: %s\n", atom.name());
        ld::Internal::FinalSection* fs = NULL;
-       const char* sectName = atom.section().sectionName();
+       const char* curSectName = atom.section().sectionName();
+       const char* curSegName = atom.section().segmentName();
        ld::Section::Type sectType = atom.section().type();
        const ld::File* f = atom.file();
        const char* path = (f != NULL) ? f->path() : NULL;
@@ -548,16 +651,15 @@ ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
                // tentative defintions don't have a real section name yet
                sectType = ld::Section::typeZeroFill;
                if ( _options.mergeZeroFill() )
-                       sectName = FinalSection::_s_DATA_zerofill.sectionName();
+                       curSectName = FinalSection::_s_DATA_zerofill.sectionName();
                else
-                       sectName = FinalSection::_s_DATA_common.sectionName();
+                       curSectName = FinalSection::_s_DATA_common.sectionName();
        }
        // Support for -move_to_r._segment
        if ( atom.symbolTableInclusion() == ld::Atom::symbolTableIn ) {
                const char* dstSeg;
-               //fprintf(stderr, "%s\n", atom.name());
                bool wildCardMatch;
-               if ( _options.moveRwSymbol(atom.name(), path, dstSeg, wildCardMatch) ) {
+               if ( inMoveRWChain(atom, path, dstSeg, wildCardMatch) ) {
                        if ( (sectType != ld::Section::typeZeroFill) 
                          && (sectType != ld::Section::typeUnclassified) 
                          && (sectType != ld::Section::typeTentativeDefs)
@@ -566,60 +668,59 @@ ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
                                        warning("cannot move symbol '%s' from file %s to segment '%s' because symbol is not data (is %d)", atom.name(), path, dstSeg, sectType);
                        }
                        else {
+                               curSegName = dstSeg;
                                if ( _options.traceSymbolLayout() )
-                                       printf("symbol '%s', -move_to_rw_segment mapped it to %s/%s\n", atom.name(), dstSeg, sectName);
-                               fs = this->getFinalSection(dstSeg, sectName, sectType);
+                                       printf("symbol '%s', -move_to_rw_segment mapped it to %s/%s\n", atom.name(), curSegName, curSectName);
+                               fs = this->getFinalSection(curSegName, curSectName, sectType);
                        }
                }
-               if ( (fs == NULL) && _options.moveRoSymbol(atom.name(), path, dstSeg, wildCardMatch) ) {
+               if ( (fs == NULL) && inMoveROChain(atom, path, dstSeg, wildCardMatch) ) {
                        if ( (sectType != ld::Section::typeCode)
                          && (sectType != ld::Section::typeUnclassified) ) {
                                if ( !wildCardMatch )
                                        warning("cannot move symbol '%s' from file %s to segment '%s' because symbol is not code (is %d)", atom.name(), path, dstSeg, sectType);
                        }
                        else {
+                               curSegName = dstSeg;
                                if ( _options.traceSymbolLayout() )
-                                       printf("symbol '%s', -move_to_ro_segment mapped it to %s/%s\n", atom.name(), dstSeg, sectName);
-                               fs = this->getFinalSection(dstSeg, sectName, ld::Section::typeCode);
+                                       printf("symbol '%s', -move_to_ro_segment mapped it to %s/%s\n", atom.name(), curSegName, curSectName);
+                               fs = this->getFinalSection(curSegName, curSectName, ld::Section::typeCode);
                        }
                }
        }
        // support for -rename_section and -rename_segment
-       if ( fs == NULL ) {
-               const std::vector<Options::SectionRename>& sectRenames = _options.sectionRenames();
-               const std::vector<Options::SegmentRename>& segRenames = _options.segmentRenames();
-               for ( std::vector<Options::SectionRename>::const_iterator it=sectRenames.begin(); it != sectRenames.end(); ++it) {
-                       if ( (strcmp(sectName, it->fromSection) == 0) && (strcmp(atom.section().segmentName(), it->fromSegment) == 0) ) {
-                               if ( _options.useDataConstSegment() && (strcmp(sectName, "__const") == 0)
-                                               && (strcmp(atom.section().segmentName(), "__DATA") == 0) && hasReferenceToWeakExternal(atom) ) {
-                                       // if __DATA,__const atom has pointer to weak external symbol, don't move to __DATA_CONST
-                                       fs = this->getFinalSection("__DATA", "__const_weak", sectType);
-                                       if ( _options.traceSymbolLayout() )
-                                               printf("symbol '%s', contains pointers to weak symbols, so mapped it to __DATA/_const_weak\n", atom.name());
-                               }
-                               else if ( _options.useDataConstSegment() && (sectType == ld::Section::typeNonLazyPointer) && hasReferenceToWeakExternal(atom) ) {
-                                       // if __DATA,__nl_symbol_ptr atom has pointer to weak external symbol, don't move to __DATA_CONST
-                                       fs = this->getFinalSection("__DATA", "__got_weak", sectType);
-                                       if ( _options.traceSymbolLayout() )
-                                               printf("symbol '%s', contains pointers to weak symbols, so mapped it to __DATA/__got_weak\n", atom.name());
-                               }
-                               else {
-                                       fs = this->getFinalSection(it->toSegment, it->toSection, sectType);
-                                       if ( _options.traceSymbolLayout() )
-                                               printf("symbol '%s', -rename_section mapped it to %s/%s\n", atom.name(), fs->segmentName(), fs->sectionName());
-                               }
+       for (const Options::SectionRename& rename : _options.sectionRenames()) {
+               if ( (strcmp(curSectName, rename.fromSection) == 0) && (strcmp(curSegName, rename.fromSegment) == 0) ) {
+                       if ( _options.useDataConstSegment() && (strcmp(curSectName, "__const") == 0) && (strcmp(curSegName, "__DATA") == 0) && hasReferenceToWeakExternal(atom) ) {
+                               // if __DATA,__const atom has pointer to weak external symbol, don't move to __DATA_CONST
+                               curSectName = "__const_weak";
+                               fs = this->getFinalSection(curSegName, curSectName, sectType);
+                               if ( _options.traceSymbolLayout() )
+                                       printf("symbol '%s', contains pointers to weak symbols, so mapped it to __DATA/__const_weak\n", atom.name());
                        }
-               }
-               if ( fs == NULL ) {
-                       for ( std::vector<Options::SegmentRename>::const_iterator it=segRenames.begin(); it != segRenames.end(); ++it) {
-                               if ( strcmp(atom.section().segmentName(), it->fromSegment) == 0 ) {
-                                       if ( _options.traceSymbolLayout() )
-                                               printf("symbol '%s', -rename_segment mapped it to %s/%s\n", atom.name(), it->toSegment, sectName);
-                                       fs = this->getFinalSection(it->toSegment, sectName, sectType);
-                               }
+                       else if ( _options.useDataConstSegment() && (sectType == ld::Section::typeNonLazyPointer) && hasReferenceToWeakExternal(atom) ) {
+                               // if __DATA,__nl_symbol_ptr atom has pointer to weak external symbol, don't move to __DATA_CONST
+                               curSectName = "__got_weak";
+                               fs = this->getFinalSection("__DATA", curSectName, sectType);
+                               if ( _options.traceSymbolLayout() )
+                                       printf("symbol '%s', contains pointers to weak symbols, so mapped it to __DATA/__got_weak\n", atom.name());
+                       }
+                       else {
+                               curSegName = rename.toSegment;
+                               curSectName = rename.toSection;
+                               fs = this->getFinalSection(rename.toSegment, rename.toSection, sectType);
+                               if ( _options.traceSymbolLayout() )
+                                       printf("symbol '%s', -rename_section mapped it to %s/%s\n", atom.name(), fs->segmentName(), fs->sectionName());
                        }
                }
        }
+       for (const Options::SegmentRename& rename : _options.segmentRenames()) {
+               if ( strcmp(curSegName, rename.fromSegment) == 0 ) {
+                       if ( _options.traceSymbolLayout() )
+                               printf("symbol '%s', -rename_segment mapped it to %s/%s\n", atom.name(), rename.toSegment, curSectName);
+                       fs = this->getFinalSection(rename.toSegment, curSectName, sectType);
+               }
+       }
 
        // if no override, use default location
        if ( fs == NULL ) {
@@ -628,7 +729,7 @@ ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
                        printf("symbol '%s', use default mapping to %s/%s\n", atom.name(), fs->segmentName(), fs->sectionName());
        }
 
-       //fprintf(stderr, "InternalState::doAtom(%p), name=%s, sect=%s, finalsect=%p\n", &atom, atom.name(), atom.section().sectionName(), fs);
+       //fprintf(stderr, "InternalState::doAtom(%p), name=%s, sect=%s, finalseg=%s\n", &atom, atom.name(), atom.section().sectionName(), fs->segmentName());
 #ifndef NDEBUG
        validateFixups(atom);
 #endif
@@ -861,6 +962,21 @@ void InternalState::setSectionSizesAndAlignments()
                                this->hasThreadLocalVariableDefinitions = true;
                }
        }
+
+       // <rdar://problem/24221680> All __thread_data and __thread_bss sections must have same alignment
+       uint8_t maxThreadAlign = 0;
+       for (ld::Internal::FinalSection* sect : sections) {
+               if ( (sect->type() == ld::Section::typeTLVInitialValues) || (sect->type() == ld::Section::typeTLVZeroFill) ) {
+                       if ( sect->alignment > maxThreadAlign )
+                               maxThreadAlign = sect->alignment;
+               }
+       }
+       for (ld::Internal::FinalSection* sect : sections) {
+               if ( (sect->type() == ld::Section::typeTLVInitialValues) || (sect->type() == ld::Section::typeTLVZeroFill) ) {
+                       sect->alignment = maxThreadAlign;
+               }
+       }
+
 }
 
 uint64_t InternalState::assignFileOffsets() 
@@ -1270,7 +1386,9 @@ int main(int argc, const char* argv[])
                }
        }
        catch (const char* msg) {
-               if ( archInferred )
+               if ( strstr(msg, "malformed") != NULL )
+                       fprintf(stderr, "ld: %s\n", msg);
+               else if ( archInferred )
                        fprintf(stderr, "ld: %s for inferred architecture %s\n", msg, archName);
                else if ( showArch )
                        fprintf(stderr, "ld: %s for architecture %s\n", msg, archName);