From d92462995e19e0e740e5068b9540ca3ed9c93572 Mon Sep 17 00:00:00 2001 From: Apple Date: Tue, 27 Jul 2010 02:16:02 +0000 Subject: [PATCH] ld64-97.14.tar.gz --- ChangeLog | 112 ++++++++++++++++++ doc/man/man1/ld.1 | 8 +- ld64.xcodeproj/project.pbxproj | 1 + src/ld/MachOReaderRelocatable.hpp | 96 ++++++++++++--- src/ld/MachOWriterExecutable.hpp | 74 +++++++----- src/ld/ObjectFile.h | 2 +- src/ld/Options.cpp | 42 ++++++- src/ld/Options.h | 3 + src/ld/ld.cpp | 22 ++-- unit-tests/test-cases/relocs-asm/relocs-asm.s | 110 +++++++++++++++-- .../test-cases/tentative-to-real-r/Makefile | 45 +++++++ .../test-cases/tentative-to-real-r/test.c | 13 ++ unit-tests/test-cases/weak-def-flag/Makefile | 6 +- .../weak-def-flag/main-strip-weak.c | 16 +++ 14 files changed, 479 insertions(+), 71 deletions(-) create mode 100644 unit-tests/test-cases/tentative-to-real-r/Makefile create mode 100644 unit-tests/test-cases/tentative-to-real-r/test.c create mode 100644 unit-tests/test-cases/weak-def-flag/main-strip-weak.c diff --git a/ChangeLog b/ChangeLog index ffe4190..38543bc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,116 @@ +----- Tagged ld64-97.14 + +2010-04-20 Nick Kledzik + + if last section is zero-fill don't add size to filesize total in -r mode + +----- Tagged ld64-97.13 + +2010-03-17 Nick Kledzik + + Support for iPhoneSimulator with OBJC 2.0 ABI + + +----- Tagged ld64-97.12 + +2010-03-17 Nick Kledzik + + if last section is zero-fill don't add size to filesize total in -r mode + +----- Tagged ld64-97.11 + +2010-01-26 Nick Kledzik + + Libc-624.1 causes latent ld bug + * build linker -no_pie + + +----- Tagged ld64-97.10 + +2010-01-26 Nick Kledzik + + LC_SEGMENT command 0 filesize field greater than vmsize field + * Move __DATA to end in -r mode + + +2010-01-26 Nick Kledzik + + symboled __ustring strings of just 0x0000 mis-parsed + * Parse __ustring section based on content - not just labels + + +----- Tagged ld64-97.9 + +2010-01-14 Nick Kledzik + + LC_SEGMENT command 0 filesize field greater than vmsize field + * for i386 -r mode sort __IMPORT segment before __DATA segment + + +2010-01-11 Nick Kledzik + + * fix ARM -r -d references to tentative definitions + +----- Tagged ld64-97.8 + +2009-12-08 Nick Kledzik + + many mach-o images in Barolo have MH_WEAK_DEFINES bit incorrectly set + * don't let auto-strip weak symbols set MH_WEAK_DEFINES + + +----- Tagged ld64-97.7 + +2009-11-30 Nick Kledzik + + llvmgcc now puts const short arrays in __ustring section, linker does not handle that + * Only auto-coalesce UTF16 strings that are labeled with "___utf16_string*" + + +----- Tagged ld64-97.6 + +2009-11-06 Nick Kledzik + + make -pie default for x86_64 for 10.7 and later + + +2009-10-28 Nick Kledzik + + Add a -no_pie flag + * support -no_pie and LD_NO_PIE + + +----- Tagged ld64-97.5 + +2009-10-27 Nick Kledzik + + crash when __ustring section has zero length string + * stop trying to suppress tailing 0x0000 from synthesized string used to coalese utf16 strings + + +----- Tagged ld64-97.4 + +2009-10-21 Nick Kledzik + + missing thumb bit when thumb function takes address of itself + * move toao.atom == srcao.atom test to after fromao.atom == srcao.atom test + + +----- Tagged ld64-97.3 + +2009-10-06 Nick Kledzik + + * Add missing LittleEndian::set32() in arm::kPointerDiff + +2009-10-05 Nick Kledzik + + ARM: handle pointer-diff to weak thumb that is overridden by non-weak ARM + * When parsing ARM relocations, if target is a thumb function, remove one from addend + * When writing out content for arm::kPointerDiff, add one if target is thumb + * When writing ARM_RELOC_SECTDIFF, use target offsets if they fit in function + + ----- Tagged ld64-97.2 2009-09-25 Nick Kledzik diff --git a/doc/man/man1/ld.1 b/doc/man/man1/ld.1 index 3a84e0a..b6363fc 100644 --- a/doc/man/man1/ld.1 +++ b/doc/man/man1/ld.1 @@ -308,10 +308,12 @@ This option is also called -dylib_current_version for compatibility. .Ss Options when creating a main executable .Bl -tag .It Fl pie -This makes a special kind of main executable that is position independent (PIE). On Mac OS X 10.5, the OS -will load a PIE at a random address each time it is executed. You cannot create a PIE from .o files compiled +This makes a special kind of main executable that is position independent (PIE). On Mac OS X 10.5 and later, the OS +the OS will load a PIE at a random address each time it is executed. You cannot create a PIE from .o files compiled with -mdynamic-no-pic. That means the codegen is less optimal, but the address randomization adds some -security. +security. When targeting Mac OS X 10.7 or later PIE is the default for x86_64 main executables. +.It Fl no_pie +Do not make a position independent executable (PIE). This is the default, except for x86_64 for 10.7 or later. .It Fl pagezero_size Ar size By default the linker creates an unreadable segment starting at address zero named __PAGEZERO. Its existence will cause a bus error if a NULL pointer is dereferenced. The argument diff --git a/ld64.xcodeproj/project.pbxproj b/ld64.xcodeproj/project.pbxproj index 55fd5ea..9c5493c 100644 --- a/ld64.xcodeproj/project.pbxproj +++ b/ld64.xcodeproj/project.pbxproj @@ -765,6 +765,7 @@ INSTALL_PATH = /usr/bin; OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)"; OTHER_LDFLAGS = ( + "-Wl,-no_pie", "@$(DERIVED_FILE_DIR)/linker_opts", "-Wl,-exported_symbol,__mh_execute_header", ); diff --git a/src/ld/MachOReaderRelocatable.hpp b/src/ld/MachOReaderRelocatable.hpp index 0792f51..2aa7926 100644 --- a/src/ld/MachOReaderRelocatable.hpp +++ b/src/ld/MachOReaderRelocatable.hpp @@ -1075,9 +1075,6 @@ AnonymousAtom::AnonymousAtom(Reader& owner, const macho_section

* sectio char* s = &name[13]; const uint16_t* words = (uint16_t*)((char*)(owner.fHeader) + section->offset() + addr - section->addr()); unsigned int wordCount = size/2; - // note, the compiler sometimes puts trailing zeros on the end of the data - if ( E::get32(words[wordCount-1]) == 0 ) - --wordCount; bool needSeperator = false; for(unsigned int i=0; i < wordCount; ++i) { if ( needSeperator ) @@ -2044,28 +2041,76 @@ Reader::Reader(const uint8_t* fileContent, const char* path, time_t modTime, } } } - else if ( (strcmp(sect->sectname(), "__ustring") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) ) { - // if there is a __ustring section parse it into AnonymousAtoms based on labels + else if ( (strcmp(sect->sectname(), "__ustring") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) && (sect->size() != 0) ) { + // if there is a __ustring section parse it into atoms fUTF16Section = sect; + // first find all cleave points + const uint16_t* words = (uint16_t*)((char*)(fHeader) + fUTF16Section->offset()); + unsigned int wordCount = fUTF16Section->size()/2; std::vector utf16Addreses; + bool inString = false; + for (unsigned int i=0; i < wordCount; ++i) { + if ( inString ) { + if ( words[i] == 0x0000 ) { + inString = false; + } + } + else { + if ( words[i] == 0x0000 ) { + // skip over zero padding + } + else { + inString = true; + utf16Addreses.push_back(fUTF16Section->addr() + i*2); + } + } + } + utf16Addreses.push_back(fUTF16Section->addr() + sect->size()); + // build map of symbols + std::map* > symbolMap; for (int i=fSymbolCount-1; i >= 0 ; --i) { const macho_nlist

& sym = fSymbols[i]; if ( (sym.n_type() & N_STAB) == 0 ) { uint8_t type = (sym.n_type() & N_TYPE); if ( type == N_SECT ) { if ( &fSectionsStart[sym.n_sect()-1] == fUTF16Section ) { - utf16Addreses.push_back(sym.n_value()); + // rdar://problem/7429384 don't coalesce UTF16 strings unless label starts with ___utf16_string + if ( strncmp(&fStrings[sym.n_strx()], "___utf16_string", 15) != 0 ) { + symbolMap[sym.n_value()] = &sym; + // if this symbol is a string of just 0x0000, it may not be in utf16Addreses + if ( words[(sym.n_value() - sect->addr())/2] == 0x0000 ) { + for(typename std::vector::iterator sit=utf16Addreses.begin(); sit != utf16Addreses.end(); ++sit) { + if ( *sit == sym.n_value() ) { + // already in utf16Addreses + break; + } + if ( *sit > sym.n_value() ) { + // need to insert + utf16Addreses.insert(sit, sym.n_value()); + break; + } + } + } + } } } } } - utf16Addreses.push_back(fUTF16Section->addr()+fUTF16Section->size()); - std::sort(utf16Addreses.begin(), utf16Addreses.end()); + // make atom for each string for(int i=utf16Addreses.size()-2; i >=0 ; --i) { pint_t size = utf16Addreses[i+1] - utf16Addreses[i]; - AnonymousAtom* strAtom = new AnonymousAtom(*this, fUTF16Section, utf16Addreses[i], size); - fAtoms.push_back(strAtom); - fAddrToAtom[utf16Addreses[i]] = strAtom; + typename std::map* >::iterator pos = symbolMap.find(utf16Addreses[i]); + if ( pos == symbolMap.end() ) { + AnonymousAtom* strAtom = new AnonymousAtom(*this, fUTF16Section, utf16Addreses[i], size); + fAtoms.push_back(strAtom); + fAddrToAtom[utf16Addreses[i]] = strAtom; + } + else { + SymbolAtom* newAtom = new SymbolAtom(*this, pos->second, fUTF16Section); + fAtoms.push_back(newAtom); + fAddrToAtom[utf16Addreses[i]] = newAtom; + newAtom->setSize(size); + } } } } @@ -5322,6 +5367,9 @@ bool Reader::addRelocReference(const macho_section* sect, if ( weakImport ) kind = arm::kPointerWeakImport; if ( reloc->r_extern() ) { + const macho_nlist

* targetSymbol = &fSymbols[reloc->r_symbolnum()]; + if ( (targetSymbol->n_desc() & N_ARM_THUMB_DEF) && (pointerValue == 1) ) + pointerValue = 0; makeByNameReference(kind, srcAddr, targetName, pointerValue); } else { @@ -5345,6 +5393,7 @@ bool Reader::addRelocReference(const macho_section* sect, else { const macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; const macho_scattered_relocation_info

* nextSReloc = &sreloc[1]; + int32_t addend; srcAddr = sect->addr() + sreloc->r_address(); dstAddr = sreloc->r_value(); uint32_t betterDstAddr; @@ -5429,13 +5478,28 @@ bool Reader::addRelocReference(const macho_section* sect, AtomAndOffset toao = findAtomAndOffset(dstAddr); // check for addend encoded in the section content pointerValue = LittleEndian::get32(*fixUpPtr); + addend = pointerValue - (dstAddr - nextRelocValue); + if ( toao.atom->isThumb() && (addend & 1) ) + addend &= -2; // remove thumb bit if ( (dstAddr - nextRelocValue) != pointerValue ) { - if ( toao.atom == srcao.atom ) - toao.offset += (pointerValue + nextRelocValue) - dstAddr; - else if ( fromao.atom == srcao.atom ) - toao.offset += (pointerValue + nextRelocValue) - dstAddr; + if ( fromao.atom == srcao.atom ) { + if ( ((const macho_section

*)(((BaseAtom*)(srcao.atom))->getSectionRecord()))->flags() & S_ATTR_PURE_INSTRUCTIONS ) { + int pcBaseOffset = srcao.atom->isThumb() ? 4 : 8; + if ( addend == -pcBaseOffset ) { + fromao.offset -= addend; + } + else { + toao.offset += addend; + } + } + else { + toao.offset += addend; + } + } + else if ( toao.atom == srcao.atom ) + toao.offset += addend; else - fromao.offset += (dstAddr - pointerValue) - nextRelocValue; + fromao.offset -= addend; } new Reference(arm::kPointerDiff, srcao, fromao, toao); } diff --git a/src/ld/MachOWriterExecutable.hpp b/src/ld/MachOWriterExecutable.hpp index 9596733..5313669 100644 --- a/src/ld/MachOWriterExecutable.hpp +++ b/src/ld/MachOWriterExecutable.hpp @@ -1706,14 +1706,15 @@ class ObjCInfoAtom : public WriterAtom { public: ObjCInfoAtom(Writer& writer, ObjectFile::Reader::ObjcConstraint objcContraint, - bool objcReplacementClasses); + bool objcReplacementClasses, bool abi2override); virtual const char* getName() const { return "objc$info"; } virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } virtual uint64_t getSize() const { return 8; } virtual const char* getSectionName() const; virtual void copyRawContent(uint8_t buffer[]) const; private: - Segment& getInfoSegment() const; + Segment& getInfoSegment(bool abi2override) const; + bool fAbi2override; uint32_t fContent[2]; }; @@ -3280,7 +3281,8 @@ int Writer::compressedOrdinalForImortedAtom(ObjectFile::Atom* target) template ObjectFile::Atom& Writer::makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses) { - return *(new ObjCInfoAtom(*this, objcContraint, objcReplacementClasses)); + + return *(new ObjCInfoAtom(*this, objcContraint, objcReplacementClasses, fOptions.objCABIVersion2POverride())); } template @@ -4350,14 +4352,23 @@ uint32_t Writer::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Refere else sreloc1->set_r_type(ARM_RELOC_SECTDIFF); sreloc1->set_r_address(address); - sreloc1->set_r_value(target.getAddress()); + if ( ref->getTargetOffset() >= target.getSize() ) + sreloc1->set_r_value(target.getAddress()); + else + sreloc1->set_r_value(target.getAddress()+ref->getTargetOffset()); sreloc2->set_r_scattered(true); sreloc2->set_r_pcrel(false); sreloc2->set_r_length(2); sreloc2->set_r_type(ARM_RELOC_PAIR); sreloc2->set_r_address(0); - if ( &ref->getFromTarget() == atom ) - sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset()); + if ( &ref->getFromTarget() == atom ) { + unsigned int pcBaseOffset = atom->isThumb() ? 4 : 8; + if ( (ref->getFromTargetOffset() > pcBaseOffset) && (strncmp(atom->getSectionName(), "__text", 6) == 0) ) { + sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset()-pcBaseOffset); + } + else + sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset()); + } else sreloc2->set_r_value(ref->getFromTarget().getAddress()); fSectionRelocs.push_back(reloc2); @@ -6250,6 +6261,7 @@ void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const Ob uint32_t firstDisp; uint32_t nextDisp; uint32_t opcode = 0; + int32_t diff; bool relocateableExternal = false; bool is_bl; bool is_blx; @@ -6330,8 +6342,10 @@ void Writer::fixUpReferenceFinal(const ObjectFile::Reference* ref, const Ob } break; case arm::kPointerDiff: - LittleEndian::set32(*fixUp, - (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) ); + diff = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()); + if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) ) + diff |= 1; + LittleEndian::set32(*fixUp, diff); break; case arm::kReadOnlyPointer: if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0)) @@ -6552,6 +6566,7 @@ void Writer::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, co uint32_t firstDisp; uint32_t nextDisp; uint32_t opcode = 0; + int32_t diff; bool relocateableExternal = false; bool is_bl; bool is_blx; @@ -6572,7 +6587,6 @@ void Writer::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, co case arm::kPointer: case arm::kReadOnlyPointer: case arm::kPointerWeakImport: - { if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) { // indirect symbol table has INDIRECT_SYMBOL_LOCAL, so we must put address in content if ( this->indirectSymbolInRelocatableIsLocal(ref) ) @@ -6600,23 +6614,17 @@ void Writer::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, co } } else { - // internal relocation - if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) { - // pointer contains target address - if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0)) + // internal relocation => pointer contains target address + if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) ) targetAddr |= 1; - LittleEndian::set32(*fixUp, targetAddr); - } - else { - // pointer contains addend - LittleEndian::set32(*fixUp, ref->getTargetOffset()); - } - } + LittleEndian::set32(*fixUp, targetAddr); } break; case arm::kPointerDiff: - LittleEndian::set32(*fixUp, - (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) ); + diff = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()); + if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) ) + diff |= 1; + LittleEndian::set32(*fixUp, diff); break; case arm::kDtraceProbeSite: case arm::kDtraceIsEnabledSite: @@ -9624,7 +9632,10 @@ void SegmentLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const cmd->set_vmaddr(sectInfo->getBaseAddress()); cmd->set_fileoff(sectInfo->fFileOffset); } - cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff()); + // if last section is zero-fill don't add size to filesize total + if ( !sectInfo->fAllZeroFill ) { + cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff()); + } cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize); } sect->set_sectname(sectInfo->fSectionName); @@ -11269,8 +11280,9 @@ void SegmentSplitInfoContentAtom::encode() template -ObjCInfoAtom::ObjCInfoAtom(Writer& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, bool objcReplacementClasses) - : WriterAtom(writer, getInfoSegment()) +ObjCInfoAtom::ObjCInfoAtom(Writer& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, + bool objcReplacementClasses, bool abi2override) + : WriterAtom(writer, getInfoSegment(abi2override)), fAbi2override(abi2override) { fContent[0] = 0; uint32_t value = 0; @@ -11306,16 +11318,16 @@ void ObjCInfoAtom::copyRawContent(uint8_t buffer[]) const // objc info section is in a different segment and section for 32 vs 64 bit runtimes template <> const char* ObjCInfoAtom::getSectionName() const { return "__image_info"; } -template <> const char* ObjCInfoAtom::getSectionName() const { return "__image_info"; } +template <> const char* ObjCInfoAtom::getSectionName() const { return fAbi2override ? "__objc_imageinfo" : "__image_info"; } template <> const char* ObjCInfoAtom::getSectionName() const { return "__objc_imageinfo"; } template <> const char* ObjCInfoAtom::getSectionName() const { return "__objc_imageinfo"; } template <> const char* ObjCInfoAtom::getSectionName() const { return "__objc_imageinfo"; } -template <> Segment& ObjCInfoAtom::getInfoSegment() const { return Segment::fgObjCSegment; } -template <> Segment& ObjCInfoAtom::getInfoSegment() const { return Segment::fgObjCSegment; } -template <> Segment& ObjCInfoAtom::getInfoSegment() const { return Segment::fgDataSegment; } -template <> Segment& ObjCInfoAtom::getInfoSegment() const { return Segment::fgDataSegment; } -template <> Segment& ObjCInfoAtom::getInfoSegment() const { return Segment::fgDataSegment; } +template <> Segment& ObjCInfoAtom::getInfoSegment(bool abi2override) const { return Segment::fgObjCSegment; } +template <> Segment& ObjCInfoAtom::getInfoSegment(bool abi2override) const { return abi2override ? Segment::fgDataSegment : Segment::fgObjCSegment; } +template <> Segment& ObjCInfoAtom::getInfoSegment(bool abi2override) const { return Segment::fgDataSegment; } +template <> Segment& ObjCInfoAtom::getInfoSegment(bool abi2override) const { return Segment::fgDataSegment; } +template <> Segment& ObjCInfoAtom::getInfoSegment(bool abi2override) const { return Segment::fgDataSegment; } diff --git a/src/ld/ObjectFile.h b/src/ld/ObjectFile.h index e3ad601..2710bfb 100644 --- a/src/ld/ObjectFile.h +++ b/src/ld/ObjectFile.h @@ -76,7 +76,7 @@ public: fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false), fTraceOutputFile(NULL), fMacVersionMin(kMinMacVersionUnset), fIPhoneVersionMin(kMinIPhoneVersionUnset) {} enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull }; - enum MacVersionMin { kMinMacVersionUnset, k10_1, k10_2, k10_3, k10_4, k10_5, k10_6 }; + enum MacVersionMin { kMinMacVersionUnset, k10_1, k10_2, k10_3, k10_4, k10_5, k10_6, k10_7 }; enum IPhoneVersionMin { kMinIPhoneVersionUnset, k2_0, k2_1, k2_2, k3_0, k3_1, k3_2, k4_0 }; struct AliasPair { diff --git a/src/ld/Options.cpp b/src/ld/Options.cpp index f63a123..01ce10f 100644 --- a/src/ld/Options.cpp +++ b/src/ld/Options.cpp @@ -99,12 +99,13 @@ Options::Options(int argc, const char* argv[]) fVerbose(false), fKeepRelocations(false), fWarnStabs(false), fTraceDylibSearching(false), fPause(false), fStatistics(false), fPrintOptions(false), fSharedRegionEligible(false), fPrintOrderFileStatistics(false), - fReadOnlyx86Stubs(false), fPositionIndependentExecutable(false), fMaxMinimumHeaderPad(false), + fReadOnlyx86Stubs(false), fPositionIndependentExecutable(false), + fDisablePositionIndependentExecutable(false), fMaxMinimumHeaderPad(false), fDeadStripDylibs(false), fAllowTextRelocs(false), fWarnTextRelocs(false), fUsingLazyDylibLinking(false), fEncryptable(true), fOrderData(true), fMarkDeadStrippableDylib(false), fMakeClassicDyldInfo(true), fMakeCompressedDyldInfo(true), fAllowCpuSubtypeMismatches(false), - fUseSimplifiedDylibReExports(false), fSaveTempFiles(false) + fUseSimplifiedDylibReExports(false), fObjCABIVersion2POverride(false), fSaveTempFiles(false) { this->checkForClassic(argc, argv); this->parsePreCommandLineEnvironmentSettings(); @@ -1248,8 +1249,11 @@ void Options::setMacOSXVersionMin(const char* version) case 6: fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_6; break; + case 7: + fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_7; + break; default: - fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_6; + fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_7; break; } } @@ -2430,6 +2434,9 @@ void Options::parse(int argc, const char* argv[]) else if ( strcmp(arg, "-pie") == 0 ) { fPositionIndependentExecutable = true; } + else if ( strcmp(arg, "-no_pie") == 0 ) { + fDisablePositionIndependentExecutable = true; + } else if ( strncmp(arg, "-reexport-l", 11) == 0 ) { FileInfo info = findLibrary(&arg[11], true); info.options.fReExport = true; @@ -2504,6 +2511,15 @@ void Options::parse(int argc, const char* argv[]) else if ( strcmp(arg, "-no_zero_fill_sections") == 0 ) { fReaderOptions.fOptimizeZeroFill = false; } + else if ( strcmp(arg, "-objc_abi_version") == 0 ) { + const char* version = argv[++i]; + if ( version == NULL ) + throw "-objc_abi_version missing version number"; + if ( strcmp(version, "2") == 0 ) + fObjCABIVersion2POverride = true; + else + warning("ignoring unrecognized argument (%s) to -objc_abi_version", version); + } else { throwf("unknown option: %s", arg); } @@ -2752,6 +2768,11 @@ void Options::parsePreCommandLineEnvironmentSettings() fMakeCompressedDyldInfo = false; fMakeClassicDyldInfo = true; } + // temporary until projects adopt -no_pie + if ( getenv("LD_NO_PIE") != NULL ) { + warning("LD_NO_PIE being used to disble building a position independent executable"); + fDisablePositionIndependentExecutable = true; + } sWarningsSideFilePath = getenv("LD_WARN_FILE"); } @@ -3179,6 +3200,12 @@ void Options::reconfigureDefaults() // Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB if ( minOS(ObjectFile::ReaderOptions::k10_5, ObjectFile::ReaderOptions::k2_0) ) fUseSimplifiedDylibReExports = true; + + // x86_64 for MacOSX 10.7 defaults to PIE + if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind == kDynamicExecutable) + && (fReaderOptions.fMacVersionMin >= ObjectFile::ReaderOptions::k10_7) ) { + fPositionIndependentExecutable = true; + } } void Options::checkIllegalOptionCombinations() @@ -3375,6 +3402,11 @@ void Options::checkIllegalOptionCombinations() if ( strncmp(name, ".objc_class_name_", 17) == 0 ) { // rdar://problem/4718189 map ObjC class names to new runtime names switch (fArchitecture) { + case CPU_TYPE_I386: + // i386 only uses new symbols when using objc2 ABI + if ( !fObjCABIVersion2POverride ) + break; + // when using objc2 ABI to same as archs below case CPU_TYPE_POWERPC64: case CPU_TYPE_X86_64: case CPU_TYPE_ARM: @@ -3486,6 +3518,10 @@ void Options::checkIllegalOptionCombinations() if ( fPositionIndependentExecutable ) { switch ( fOutputKind ) { case Options::kDynamicExecutable: + // -no_pie anywhere on command line disable PIE + if ( fDisablePositionIndependentExecutable ) + fPositionIndependentExecutable = false; + break; case Options::kPreload: break; case Options::kDynamicLibrary: diff --git a/src/ld/Options.h b/src/ld/Options.h index 2fa364e..4a06a5e 100644 --- a/src/ld/Options.h +++ b/src/ld/Options.h @@ -232,6 +232,7 @@ public: bool markAutoDeadStripDylib() { return fMarkDeadStrippableDylib; } bool removeEHLabels() { return fReaderOptions.fNoEHLabels; } bool useSimplifiedDylibReExports() { return fUseSimplifiedDylibReExports; } + bool objCABIVersion2POverride() { return fObjCABIVersion2POverride; } private: class CStringEquals @@ -369,6 +370,7 @@ private: bool fPrintOrderFileStatistics; bool fReadOnlyx86Stubs; bool fPositionIndependentExecutable; + bool fDisablePositionIndependentExecutable; bool fMaxMinimumHeaderPad; bool fDeadStripDylibs; bool fAllowTextRelocs; @@ -382,6 +384,7 @@ private: bool fNoEHLabels; bool fAllowCpuSubtypeMismatches; bool fUseSimplifiedDylibReExports; + bool fObjCABIVersion2POverride; std::vector fInitialUndefines; NameSet fAllowedUndefined; NameSet fWhyLive; diff --git a/src/ld/ld.cpp b/src/ld/ld.cpp index 6b6d114..48e1e88 100644 --- a/src/ld/ld.cpp +++ b/src/ld/ld.cpp @@ -87,7 +87,7 @@ class Section : public ObjectFile::Section { public: static Section* find(const char* sectionName, const char* segmentName, bool zeroFill, bool untrustedZeroFill, bool createIfNeeded=true); - static void assignIndexes(); + static void assignIndexes(bool objfile); const char* getName() { return fSectionName; } private: Section(const char* sectionName, const char* segmentName, bool zeroFill, bool untrustedZeroFill); @@ -109,11 +109,13 @@ private: static NameToSection fgMapping; static std::vector fgSections; static NameToOrdinal fgSegmentDiscoverOrder; + static bool fgMakingObjectFile; }; Section::NameToSection Section::fgMapping; std::vector Section::fgSections; Section::NameToOrdinal Section::fgSegmentDiscoverOrder; +bool Section::fgMakingObjectFile; Section::Section(const char* sectionName, const char* segmentName, bool zeroFill, bool untrustedZeroFill) : fZeroFill(zeroFill), fUntrustedZeroFill(untrustedZeroFill) @@ -254,10 +256,10 @@ int Section::Sorter::segmentOrdinal(const char* segName) if ( strcmp(segName, "__TEXT") == 0 ) return 2; if ( strcmp(segName, "__DATA") == 0 ) - return 3; + return (fgMakingObjectFile ? 6 : 3); // __DATA is last in .o files and here in FLI if ( strcmp(segName, "__OBJC") == 0 ) return 4; - if ( strcmp(segName, "__OBJC2") == 0 ) + if ( strcmp(segName, "__IMPORT") == 0 ) return 5; if ( strcmp(segName, "__LINKEDIT") == 0 ) return INT_MAX; // linkedit segment should always sort last @@ -286,7 +288,7 @@ bool Section::Sorter::operator()(Section* left, Section* right) return left->fIndex < right->fIndex; } -void Section::assignIndexes() +void Section::assignIndexes(bool objfile) { //printf("unsorted sections:\n"); //for (std::vector::iterator it=fgSections.begin(); it != fgSections.end(); it++) { @@ -294,6 +296,7 @@ void Section::assignIndexes() //} // sort it + Section::fgMakingObjectFile = objfile; std::sort(fgSections.begin(), fgSections.end(), Section::Sorter()); // assign correct section ordering to each Section object @@ -793,8 +796,10 @@ void Linker::adjustScope() //fprintf(stderr, "demote %s to hidden\n", name); } else if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) { - // we do have an exported weak symbol, turn WEAK_DEFINES back on - fGlobalSymbolTable.setHasExternalWeakDefinitions(true); + if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn ) { + // we do have an exported weak symbol, turn WEAK_DEFINES back on + fGlobalSymbolTable.setHasExternalWeakDefinitions(true); + } } } else if ( scope == ObjectFile::Atom::scopeLinkageUnit ) { @@ -2152,7 +2157,7 @@ ObjectFile::Atom* Linker::findAtom(const Options::OrderedSymbol& orderedSymbol) void Linker::sortSections() { - Section::assignIndexes(); + Section::assignIndexes(fOptions.outputKind() == Options::kObjectFile); } @@ -4124,7 +4129,8 @@ bool Linker::SymbolTable::add(ObjectFile::Atom& newAtom) ++fRequireCount; // added a tentative definition means loadUndefines() needs to continue break; case ObjectFile::Atom::kWeakDefinition: - fHasExternalWeakDefinitions = true; + if ( newAtom.getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn ) + fHasExternalWeakDefinitions = true; break; case ObjectFile::Atom::kExternalDefinition: case ObjectFile::Atom::kExternalWeakDefinition: diff --git a/unit-tests/test-cases/relocs-asm/relocs-asm.s b/unit-tests/test-cases/relocs-asm/relocs-asm.s index 73c31ea..4d38f2d 100644 --- a/unit-tests/test-cases/relocs-asm/relocs-asm.s +++ b/unit-tests/test-cases/relocs-asm/relocs-asm.s @@ -30,31 +30,31 @@ .globl _test_loads _test_loads: @ PIC load of a - ldr r0, L6 + ldr r0, L100 L0: ldr r0, [pc, r0] @ PIC load of c - ldr r0, L6+4 + ldr r0, L100+4 L1: ldr r0, [pc, r0] @ sorta-absolute load of a - ldr r0, L6+8 + ldr r0, L100+8 ldr r0, [r0, #0] @ sorta-absolute load of c - ldr r0, L6+12 + ldr r0, L100+12 ldr r0, [r0, #0] @ sorta-absolute load of external - ldr r0, L6+16 + ldr r0, L100+16 ldr r0, [r0, #0] @ PIC load of a + addend ?? bx lr -L6: +L100: .long _a-(L0+8) .long _c-(L1+8) .long _a @@ -88,10 +88,12 @@ _test_branches: @ call external + addend bne _external+16 -_pointer_diffs: nop bl 1f 1: nop + + .text +_pointer_diffs: .long _foo-1b .long _foo+10-1b .long _test_branches-1b @@ -99,6 +101,98 @@ _pointer_diffs: .long (_test_branches - _test_loads) + -2097152 .long (_test_calls - _test_loads) + -2097152 + .text + .code 32 +_arm1: + bx lr +_arm2: + bx lr + .weak_definition _arm3 + .globl _arm3 + .private_extern _arm3 +_arm3: + bx lr + .weak_definition _arm4 + .globl _arm4 + .private_extern _arm4 +_arm4: + bx lr + + .code 16 + .thumb_func _thumb1 +_thumb1: + bx lr + .thumb_func _thumb2 +_thumb2: + bx lr + .weak_definition _thumb3 + .globl _thumb3 + .private_extern _thumb3 + .thumb_func _thumb3 +_thumb3: + bx lr + .weak_definition _thumb4 + .globl _thumb4 + .private_extern _thumb4 + .thumb_func _thumb4 +_thumb4: + bx lr + + .thumb_func _thumb_func_ref_test +_thumb_func_ref_test: + push {r7, lr} + add r7, sp, #0 + ldr r3, L6 +L2: add r3, pc + ldr r3, L7 +L3: add r3, pc + ldr r3, L8 +L4: add r3, pc + ldr r3, L9 +L5: add r3, pc + pop {r7, pc} + .align 2 +L6: .long _thumb1-(L2+4) +L7: .long _thumb2-(L3+4) +L7a:.long _thumb3-(L3+4) +L7b:.long _thumb4-(L3+4) +L8: .long _arm1-(L4+4) +L9: .long _arm2-(L5+4) +L9a:.long _arm3-(L5+4) +L9b:.long _arm4-(L5+4) + + .code 32 + .align 2 +_arm_func_ref_test: + push {r7, lr} + add r7, sp, #0 + ldr r3, L16 +L12:add r3, pc + ldr r3, L17 +L13:add r3, pc + ldr r3, L18 +L14:add r3, pc + ldr r3, L19 +L15:add r3, pc + pop {r7, pc} + .align 2 +L16: .long _thumb1-(L12+8) +L17: .long _thumb2-(L13+8) +L17a: .long _thumb3-(L3+8) +L17b: .long _thumb4-(L3+8) +L18: .long _arm1-(L14+8) +L19: .long _arm2-(L15+8) +L19a: .long _arm3-(L15+8) +L19b: .long _arm4-(L15+8) + + .section __DATA,__const +_myVTable: + .long _thumb1 + .long _thumb2 + .long _thumb3 + .long _arm1 + .long _arm2 + #endif #if __ppc__ || __ppc64__ @@ -410,6 +504,8 @@ Llocal2: .long _test_branches - . .long _test_branches - . + 8 .long _test_branches - . - 8 + .long 0 + .long 0 #if __ppc64__ .quad Llocal2-_test_branches #endif diff --git a/unit-tests/test-cases/tentative-to-real-r/Makefile b/unit-tests/test-cases/tentative-to-real-r/Makefile new file mode 100644 index 0000000..df0ae07 --- /dev/null +++ b/unit-tests/test-cases/tentative-to-real-r/Makefile @@ -0,0 +1,45 @@ +## +# Copyright (c) 2010 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +## +TESTROOT = ../.. +include ${TESTROOT}/include/common.makefile + + +# +# Test that references to commons survive -r -d +# + +run: all + +all: + ${CC} ${CCFLAGS} test.c -c -o test.${ARCH}.o + ${OBJECTDUMP} -no_content test.${ARCH}.o | grep -v kind: | grep -v section: > test.${ARCH}.o.dump + + ${LD} -arch ${ARCH} -r -d test.${ARCH}.o -o test-r-d.${ARCH}.o + ${OBJECTDUMP} -no_content test-r-d.${ARCH}.o | grep -v kind: | grep -v section: > test-r-d.${ARCH}.o.dump + + ${PASS_IFF} diff test.${ARCH}.o.dump test-r-d.${ARCH}.o.dump + + +clean: + rm -rf *.o *.dump + diff --git a/unit-tests/test-cases/tentative-to-real-r/test.c b/unit-tests/test-cases/tentative-to-real-r/test.c new file mode 100644 index 0000000..27d22e7 --- /dev/null +++ b/unit-tests/test-cases/tentative-to-real-r/test.c @@ -0,0 +1,13 @@ + +void foo() {} + +int a; +int b; +int c; + + + +int* pa = &a; +int* pb = &b; +int* pc = &c; + diff --git a/unit-tests/test-cases/weak-def-flag/Makefile b/unit-tests/test-cases/weak-def-flag/Makefile index 71d5db6..e813f49 100644 --- a/unit-tests/test-cases/weak-def-flag/Makefile +++ b/unit-tests/test-cases/weak-def-flag/Makefile @@ -1,5 +1,5 @@ ## -# Copyright (c) 2008 Apple Inc. All rights reserved. +# Copyright (c) 2008-2009 Apple Inc. All rights reserved. # # @APPLE_LICENSE_HEADER_START@ # @@ -40,7 +40,9 @@ all: otool -hv main | grep WEAK_DEFINES | ${FAIL_IF_STDIN} ${CC} ${CCFLAGS} main.c -o main -Wl,-exported_symbol,_my_weak otool -hv main | grep WEAK_DEFINES | ${FAIL_IF_EMPTY} + ${CC} ${CCFLAGS} main-strip-weak.c -o main-strip-weak + otool -hv main-strip-weak | grep WEAK_DEFINES | ${FAIL_IF_STDIN} ${PASS_IFF_GOOD_MACHO} main clean: - rm main + rm main main-strip-weak \ No newline at end of file diff --git a/unit-tests/test-cases/weak-def-flag/main-strip-weak.c b/unit-tests/test-cases/weak-def-flag/main-strip-weak.c new file mode 100644 index 0000000..cb40513 --- /dev/null +++ b/unit-tests/test-cases/weak-def-flag/main-strip-weak.c @@ -0,0 +1,16 @@ +#include + +// the 'l' prefix makes this an auto-strip symbol +void my_auto_strip_weak() __asm ( "lautostrip" ); + +void __attribute__((weak)) my_auto_strip_weak() +{ + +} + +int main() +{ + my_auto_strip_weak(); + return 0; +} + -- 2.45.2