]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-97.2.tar.gz developer-tools-322 ios-32 v97.2
authorApple <opensource@apple.com>
Fri, 23 Jul 2010 22:13:49 +0000 (22:13 +0000)
committerApple <opensource@apple.com>
Fri, 23 Jul 2010 22:13:49 +0000 (22:13 +0000)
25 files changed:
ChangeLog
src/ld/LTOReader.hpp
src/ld/MachOReaderDylib.hpp
src/ld/MachOReaderRelocatable.hpp
src/ld/MachOWriterExecutable.hpp
src/ld/ObjectFile.h
src/ld/Options.cpp
src/ld/ld.cpp
src/other/ObjectDump.cpp
src/other/machochecker.cpp
unit-tests/test-cases/archive-basic/Makefile
unit-tests/test-cases/archive-duplicate/Makefile
unit-tests/test-cases/dead_strip-entry-archive/Makefile [new file with mode: 0644]
unit-tests/test-cases/dead_strip-entry-archive/bar.c [new file with mode: 0644]
unit-tests/test-cases/dead_strip-entry-archive/foo.c [new file with mode: 0644]
unit-tests/test-cases/empty-dylib/Makefile [new file with mode: 0644]
unit-tests/test-cases/empty-dylib/empty.c [new file with mode: 0644]
unit-tests/test-cases/empty-dylib/justdata.c [new file with mode: 0644]
unit-tests/test-cases/kext-basic/Makefile
unit-tests/test-cases/section-labels-zero-fill/Makefile [new file with mode: 0644]
unit-tests/test-cases/section-labels-zero-fill/both.c [new file with mode: 0644]
unit-tests/test-cases/section-labels-zero-fill/bss.c [new file with mode: 0644]
unit-tests/test-cases/section-labels-zero-fill/common.c [new file with mode: 0644]
unit-tests/test-cases/static-executable-weak-defines/Makefile [new file with mode: 0644]
unit-tests/test-cases/static-executable-weak-defines/test.c [new file with mode: 0644]

index 77b92561575419f9d04e81cb8ee787e5e30a7e17..ffe419096e330f8a24ef6b10d724e2b3a96870d0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,135 @@
 
+----- Tagged ld64-97.2
+
+2009-09-25     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7200658> 'unknown DWARF EH encoding' message logged to console with clang-50
+
+
+----- Tagged ld64-97.1
+
+2009-07-28     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7099040> make better no-PIC branch island to thumb1
+       * Add kBranchIslandNoPicToThumb1 as 8-byte no-PIC island
+
+
+2009-07-20     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7075703> section$start$__DATA$__bss can fail
+       * In SectionBoundaryAtom constructor make __bss and __common be zero-fill
+       * In AtomSorter, make sure end kSectionEnd sort after kTentativeDefinition
+       * unit-tests/test-cases/section-labels-zero-fill: add test cases
+
+
+----- Tagged ld64-97
+
+2009-07-13     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7049478> empty dylib should have subtype from command line
+       In Linker::writeOutput() for ARM, set initial fCurrentCpuConstraint to be command line subtype
+
+
+2009-07-09     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7043920> crash when using -dead_strip and LTO with unresolved intrinsic
+       * In Linker::optimize() after final deadStripResolve() call checkUndefines() one last time
+
+
+2009-07-09     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7043256> ld64 can not find a -e entry point from an archive
+       * src/ld/ld.cpp: add searchArchives parameter to entryPoint() for use by deadStripResolve()
+       * unit-tests/test-cases/dead_strip-entry-archive: added test case
+       
+
+2009-07-08     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/6702217> __objc_classrefs section could be coalesced
+       * In machoReader, chop up __objc_classrefs section into pointer size atoms
+       and make each weak and hidden with a name based on its target name. 
+       
+
+2009-06-26     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/6715874> "ld: symbol dyld_stub_binding_helper not defined" for xnu built with clang for x86_64
+       * Fix relocationNeededInFinalLinkedImage() to say weak-defs don't require indirection in static executables
+       * Added unit-tests/test-cases/static-executable-weak-defines
+
+
+2009-06-26     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7012016> Error msg for missing -init symbol is misleading/unclear
+       * In Linker::checkUndefines() check all ways that the command line could add an undefined
+         and then search for close matches/typos.
+
+
+2009-06-25     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/5725900> We need ld-symbol-moving-symbols for ARM/Embedded
+       * In mach_o::dylib::Reader::addSymbol() parse iPhoneOS version strings
+       * Update IPhoneVersionMin
+       
+
+2009-06-25     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/6933931> Linker makes subtype-zero file from empty subtype-nonzero file.
+       * In Linker::writeOutput() set inittal fCurrentCpuConstraint to be command line subtype
+       * Fix fArchitectureName to have arm sub-types
+
+
+2009-06-24     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/6955021> ld should do a better job of reporting attempts to link directories
+       * In Options::buildSearchPaths() sanity check -L and -F options
+       
+
+2009-06-24     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/6974647> better error message when libLTO.dylib not loadable
+       * in Linker::createReader() provide detail error messages
+
+
+----- Tagged ld64-96.10
+
+2009-08-31     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7182988> empty dylib has been __mh_dylib_header n_sect
+       * rework patch to use MinimalTextAtom to ensure there is always a __text section 
+       
+
+----- Tagged ld64-96.9
+
+2009-08-31     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7182988> empty dylib has been __mh_dylib_header n_sect
+       * suppress __mh_dylib_header from symbol table if there is no __text section
+       
+       Implicitly add dyld_stub_binder to libSystem.dylib so iPhone clients can build
+       against SnowLeopard libSystem.dylib.
+
+
+----- Tagged ld64-96.8
+
+2009-08-30     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7049478> SWB: gcc-5577.1 fails to build vecLib
+               
+
+----- Tagged ld64-96.7
+
+2009-08-29     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/6933931> Linker makes subtype-zero file from empty subtype-nonzero file.        
+
+       
+----- Tagged ld64-96.6
+
+2009-07-30     Nick Kledzik    <kledzik@apple.com>
+
+       <rdar://problem/7103437> ld: ldr 12-bit displacement out of range on SnowLeopard with gcc-5648
+       * in Section::Section() set fIndex to ensure __symbolstub1 sorts to end of __TEXT segment
+
 
 ----- Tagged ld64-96.5
 
index 0bd200ef4904babd464cfbd2140da8c81f2d8939..9d00b006f3986d8f78421f98259ffb48e94cd29b 100644 (file)
@@ -267,6 +267,7 @@ class Reader : public ObjectFile::Reader
 {
 public:
        static bool                                                                             validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture);
+       static const char*                                                              fileKind(const uint8_t* fileContent);
        static bool                                                                             loaded() { return (::lto_get_version() != NULL); }
                                                                                                        Reader(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                                const char* path, time_t modTime, 
@@ -358,6 +359,7 @@ Reader::Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path
                                kind = ObjectFile::Atom::kWeakDefinition;
                                break;
                        case LTO_SYMBOL_DEFINITION_UNDEFINED:
+                       case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
                                kind = ObjectFile::Atom::kExternalDefinition;
                                break;
                        default:
@@ -416,6 +418,25 @@ bool Reader::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type
        return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, tripletPrefixForArch(architecture));
 }
 
+const char* Reader::fileKind(const uint8_t* p)
+{
+       if ( (p[0] == 0xDE) && (p[1] == 0xC0) && (p[2] == 0x17) && (p[3] == 0x0B) ) {
+               uint32_t arch = LittleEndian::get32(*((uint32_t*)(&p[16])));
+               switch (arch) {
+                       case CPU_TYPE_POWERPC:
+                               return "ppc";
+                       case CPU_TYPE_I386:
+                               return "i386";
+                       case CPU_TYPE_X86_64:
+                               return "x86_64";
+                       case CPU_TYPE_ARM:
+                               return "arm";
+               }
+               return "unknown bitcode architecture";
+       }
+       return NULL;
+}
+
 bool Reader::optimize(const std::vector<ObjectFile::Atom *>& allAtoms, std::vector<ObjectFile::Atom*>& newAtoms, 
                                                        std::vector<const char*>& additionalUndefines, const std::set<ObjectFile::Atom*>& deadAtoms,
                                                        std::vector<ObjectFile::Atom*>& newlyDeadAtoms,
index 8aea6efd66f65541c27ed9b6126e3bf8c7605aee..1d8f89b127663e42ea8666fbd3c53012eb2432ac 100644 (file)
@@ -307,7 +307,8 @@ private:
        bool                                                                            fLazyLoaded;
        ObjectFile::Reader::ObjcConstraint                      fObjcContraint;
        std::vector<ObjectFile::Reader*>                        fReExportedChildren;
-       const ObjectFile::ReaderOptions::MacVersionMin  fDeploymentVersionMin;
+       const ObjectFile::ReaderOptions::MacVersionMin          fMacDeploymentVersionMin;
+       const ObjectFile::ReaderOptions::IPhoneVersionMin       fIPhoneDeploymentVersionMin;
        std::vector<class ObjectFile::Atom*>            fFlatImports;
 
        static bool                                                                     fgLogHashtable;
@@ -330,7 +331,8 @@ Reader<A>::Reader(const uint8_t* fileContent, uint64_t fileLength, const char* p
        fExplicitlyLinked(false), fImplicitlyLinked(false), fProvidedAtom(false), 
        fImplicitlyLinkPublicDylibs(options.fImplicitlyLinkPublicDylibs), fLazyLoaded(dylibOptions.fLazyLoad),
        fObjcContraint(ObjectFile::Reader::kObjcNone),
-       fDeploymentVersionMin(options.fMacVersionMin)
+       fMacDeploymentVersionMin(options.fMacVersionMin),
+       fIPhoneDeploymentVersionMin(options.fIPhoneVersionMin)
 {
        // sanity check
        if ( ! validFile(fileContent, dylibOptions.fBundleLoader) )
@@ -593,6 +595,13 @@ void Reader<x86>::addDyldFastStub()
        addSymbol("dyld_stub_binder", false);
 }
 
+// hack for bring up of iPhoneOS builds on SnowLeopard
+template <>
+void Reader<arm>::addDyldFastStub()
+{
+       addSymbol("dyld_stub_binder", false);
+}
+
 template <typename A>
 void Reader<A>::addDyldFastStub()
 {
@@ -610,53 +619,100 @@ void Reader<A>::addSymbol(const char* name, bool weakDef)
                const char* symAction = &name[4];
                const char* symCond = strchr(symAction, '$');
                if ( symCond != NULL ) {
-                       ObjectFile::ReaderOptions::MacVersionMin symVersionCondition = ObjectFile::ReaderOptions::kMinMacVersionUnset;
-                       if ( (strncmp(symCond, "$os10.", 6) == 0) && isdigit(symCond[6]) && (symCond[7] == '$') ) {
-                               switch ( symCond[6] - '0' ) {
-                                       case 0:
-                                       case 1:
-                                               symVersionCondition = ObjectFile::ReaderOptions::k10_1;
-                                               break;
-                                       case 2:
-                                               symVersionCondition = ObjectFile::ReaderOptions::k10_2;
-                                               break;
-                                       case 3:
-                                               symVersionCondition = ObjectFile::ReaderOptions::k10_3;
-                                               break;
-                                       case 4:
-                                               symVersionCondition = ObjectFile::ReaderOptions::k10_4;
-                                               break;
-                                       case 5:
-                                               symVersionCondition = ObjectFile::ReaderOptions::k10_5;
-                                               break;
-                                       case 6:
-                                               symVersionCondition = ObjectFile::ReaderOptions::k10_6;
-                                               break;
-                               }
-                               const char* symName = strchr(&symCond[1], '$');
-                               if ( symName != NULL ) {
-                                       ++symName;
-                                       if ( fDeploymentVersionMin == symVersionCondition ) {
-                                               if ( strncmp(symAction, "hide$", 5) == 0 ) {
-                                                       if ( fgLogHashtable ) fprintf(stderr, "  adding %s to ignore set for %s\n", symName, this->getPath());
-                                                       fIgnoreExports.insert(strdup(symName));
-                                                       return;
-                                               }
-                                               else if ( strncmp(symAction, "add$", 4) == 0 ) {
-                                                       this->addSymbol(symName, weakDef);
-                                                       return;
-                                               }
-                                               else {
-                                                       warning("bad symbol action: %s in dylib %s", name, this->getPath());
+                       if ( fMacDeploymentVersionMin != ObjectFile::ReaderOptions::kMinMacVersionUnset ) {
+                               ObjectFile::ReaderOptions::MacVersionMin symVersionCondition = ObjectFile::ReaderOptions::kMinMacVersionUnset;
+                               // ex:  $ld$add$os10.6$_foo
+                               if ( (strncmp(symCond, "$os10.", 6) == 0) && isdigit(symCond[6]) && (symCond[7] == '$') ) {
+                                       switch ( symCond[6] - '0' ) {
+                                               case 0:
+                                               case 1:
+                                                       symVersionCondition = ObjectFile::ReaderOptions::k10_1;
+                                                       break;
+                                               case 2:
+                                                       symVersionCondition = ObjectFile::ReaderOptions::k10_2;
+                                                       break;
+                                               case 3:
+                                                       symVersionCondition = ObjectFile::ReaderOptions::k10_3;
+                                                       break;
+                                               case 4:
+                                                       symVersionCondition = ObjectFile::ReaderOptions::k10_4;
+                                                       break;
+                                               case 5:
+                                                       symVersionCondition = ObjectFile::ReaderOptions::k10_5;
+                                                       break;
+                                               case 6:
+                                                       symVersionCondition = ObjectFile::ReaderOptions::k10_6;
+                                                       break;
+                                       }
+                                       const char* symName = strchr(&symCond[1], '$');
+                                       if ( symName != NULL ) {
+                                               ++symName;
+                                               if ( fMacDeploymentVersionMin == symVersionCondition ) {
+                                                       if ( strncmp(symAction, "hide$", 5) == 0 ) {
+                                                               if ( fgLogHashtable ) fprintf(stderr, "  adding %s to ignore set for %s\n", symName, this->getPath());
+                                                               fIgnoreExports.insert(strdup(symName));
+                                                               return;
+                                                       }
+                                                       else if ( strncmp(symAction, "add$", 4) == 0 ) {
+                                                               this->addSymbol(symName, weakDef);
+                                                               return;
+                                                       }
+                                                       else {
+                                                               warning("bad symbol action: %s in dylib %s", name, this->getPath());
+                                                       }
                                                }
                                        }
+                                       else {
+                                               warning("bad symbol name: %s in dylib %s", name, this->getPath());
+                                       }
                                }
                                else {
-                                       warning("bad symbol name: %s in dylib %s", name, this->getPath());
+                                       warning("bad symbol version: %s in dylib %s", name, this->getPath());
                                }
                        }
-                       else {
-                               warning("bad symbol version: %s in dylib %s", name, this->getPath());
+                       else if ( fIPhoneDeploymentVersionMin != ObjectFile::ReaderOptions::kMinIPhoneVersionUnset ) {
+                               ObjectFile::ReaderOptions::IPhoneVersionMin symVersionCondition = ObjectFile::ReaderOptions::kMinIPhoneVersionUnset;
+                               // ex:  $ld$add$os3.1$_foo
+                               if ( (strncmp(symCond, "$os", 3) == 0) && isdigit(symCond[3]) && (symCond[4] == '.') ) {
+                                       if ( (symCond[3] == '2') && (symCond[5] == '0') )
+                                               symVersionCondition = ObjectFile::ReaderOptions::k2_0;
+                                       else if ( (symCond[3] == '2') && (symCond[5] == '1') )
+                                               symVersionCondition = ObjectFile::ReaderOptions::k2_1;
+                                       else if ( (symCond[3] == '2') && (symCond[5] >= '2') )
+                                               symVersionCondition = ObjectFile::ReaderOptions::k2_2;
+                                       else if ( (symCond[3] == '3') && (symCond[5] == '0') )
+                                               symVersionCondition = ObjectFile::ReaderOptions::k3_0;
+                                       else if ( (symCond[3] == '3') && (symCond[5] == '1') )
+                                               symVersionCondition = ObjectFile::ReaderOptions::k3_1;
+                                       else if ( (symCond[3] == '3') && (symCond[5] >= '2') )
+                                               symVersionCondition = ObjectFile::ReaderOptions::k3_2;
+                                       else if ( (symCond[3] >= '4')  )
+                                               symVersionCondition = ObjectFile::ReaderOptions::k4_0;
+                                       const char* symName = strchr(&symCond[1], '$');
+                                       if ( symName != NULL ) {
+                                               ++symName;
+                                               if ( fIPhoneDeploymentVersionMin == symVersionCondition ) {
+                                                       if ( strncmp(symAction, "hide$", 5) == 0 ) {
+                                                               if ( fgLogHashtable ) fprintf(stderr, "  adding %s to ignore set for %s\n", symName, this->getPath());
+                                                               fIgnoreExports.insert(strdup(symName));
+                                                               return;
+                                                       }
+                                                       else if ( strncmp(symAction, "add$", 4) == 0 ) {
+                                                               this->addSymbol(symName, weakDef);
+                                                               return;
+                                                       }
+                                                       else {
+                                                               warning("bad symbol action: %s in dylib %s", name, this->getPath());
+                                                       }
+                                               }
+                                       }
+                                       else {
+                                               warning("bad symbol name: %s in dylib %s", name, this->getPath());
+                                       }
+                               }
+                               else {
+                                       warning("bad symbol version: %s in dylib %s, symCond=%s", name, this->getPath(), symCond);
+                               }
                        }
                }       
                else {
index e6a182c0aa056f0cb246d4d5c40d920eec970822..0792f51f9ccc4dce5efd95b6383cdbb2e0e4efb2 100644 (file)
@@ -1058,6 +1058,13 @@ AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* sectio
                                if ( !fOwner.fOptions.fNoEHLabels ) 
                                        fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
                        }
+                       else if ( (strncmp(fSection->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
+                               fSynthesizedName = "objc-class-pointer-name-PENDING";
+                               fScope = ObjectFile::Atom::scopeLinkageUnit;
+                               owner.fAtomsPendingAName.push_back(this);
+                               owner.fSectionsWithAtomsPendingAName.insert(fSection);
+                               fKind = ObjectFile::Atom::kWeakDefinition;
+                       }
                        else if ( section == owner.fUTF16Section ) {
                                if ( fOwner.fOptions.fForFinalLinkedImage ) {
                                        fDontDeadStrip = false;
@@ -1355,6 +1362,16 @@ void AnonymousAtom<A>::resolveName()
                if ( funcAtom != NULL )
                        asprintf((char**)&fSynthesizedName, "%s.lsda", funcAtom->getDisplayName());
        }
+       else if ( (strncmp(fSection->sectname(),  "__objc_classrefs", 16) == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
+               std::vector<ObjectFile::Reference*>& references = this->getReferences();
+               if ( references.size() != 1 )
+                       throwf("__objc_classrefs element missing reloc (count=%ld) for target class in %s", references.size(), fOwner.getPath());
+               const char* targetName = references[0]->getTargetName();
+               if ( strncmp(targetName, "_OBJC_CLASS_$_", 14) == 0 )
+                       asprintf((char**)&fSynthesizedName, "objc-class-ref-to-%s", &targetName[14]);
+               else
+                       asprintf((char**)&fSynthesizedName, "objc-class-ref-to-%s", targetName);
+       }
 }
 
 
@@ -1552,7 +1569,7 @@ public:
        virtual ObjectFile::Atom::Scope                         getScope() const                                { return ObjectFile::Atom::scopeLinkageUnit; }
        virtual ObjectFile::Atom::DefinitionKind        getDefinitionKind() const               { return ObjectFile::Atom::kWeakDefinition; }
        virtual ObjectFile::Atom::ContentType           getContentType() const                  { return fStart ? ObjectFile::Atom::kSectionStart : ObjectFile::Atom::kSectionEnd; }
-       virtual bool                                                            isZeroFill() const                              { return false; }
+       virtual bool                                                            isZeroFill() const                              { return fZeroFill; }
        virtual bool                                                            isThumb() const                                 { return false; }
        virtual SymbolTableInclusion                            getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
        virtual bool                                                            dontDeadStrip() const                   { return false; }
@@ -1609,6 +1626,7 @@ protected:
        const char*                                                                     fSectionName;
        const char*                                                                     fDisplayName;
        bool                                                                            fStart;
+       bool                                                                            fZeroFill;
        static std::vector<ObjectFile::Reference*>      fgNoReferences;
 };
 
@@ -1620,7 +1638,7 @@ std::vector<ObjectFile::Reference*> SectionBoundaryAtom<A>::fgNoReferences;
 //                     section$end$__DATA$__my
 template <typename A>
 SectionBoundaryAtom<A>::SectionBoundaryAtom(Reader<A>& owner, bool start, const char* symbolName, const char* segSectName)
- : fOwner(owner), fSymbolName(symbolName), fSectionName(NULL), fStart(start)
+ : fOwner(owner), fSymbolName(symbolName), fSectionName(NULL), fStart(start), fZeroFill(false)
 {
        const char* segSectDividor = strrchr(segSectName, '$');
        if ( segSectDividor == NULL )
@@ -1633,8 +1651,11 @@ SectionBoundaryAtom<A>::SectionBoundaryAtom(Reader<A>& owner, bool start, const
        strlcpy(segName, segSectName, segNameLen+1);
        if ( strcmp(segName, "__TEXT") == 0 )
                fSegment = new Segment("__TEXT", true, false, true);
-       else if ( strcmp(segName, "__DATA") == 0 ) 
+       else if ( strcmp(segName, "__DATA") == 0 ) {
                fSegment = new Segment("__DATA", true, true, false);
+               if ( (strcmp(fSectionName, "__bss") == 0) || (strcmp(fSectionName, "__common") == 0) )
+                       fZeroFill = true;
+       }       
        else 
                fSegment = new Segment(strdup(segName), true, true, false);
 
@@ -1801,6 +1822,7 @@ class Reader : public ObjectFile::Reader
 {
 public:
        static bool                                                                             validFile(const uint8_t* fileContent, bool subtypeMustMatch=false, cpu_subtype_t subtype=0);
+       static const char*                                                              fileKind(const uint8_t* fileContent);
                                                                                                        Reader(const uint8_t* fileContent, const char* path, time_t modTime, 
                                                                                                                const ObjectFile::ReaderOptions& options, uint32_t ordinalBase);
        virtual                                                                                 ~Reader() {}
@@ -2268,6 +2290,10 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
                                else if ((strcmp(sect->sectname(), "__cfstring") == 0) && (strcmp(sect->segname(), "__DATA") == 0)) {
                                        atomSize = 4 * sizeof(pint_t);
                                }
+                               // special case class reference sections
+                               else if ( (strncmp(sect->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0) ) {
+                                       atomSize = sizeof(pint_t);;
+                               }
                                break;
                }
                if ( atomSize != 0 ) {
@@ -3214,7 +3240,9 @@ typename A::P::uint_t ObjectFileAddressSpace<A>::getEncodedP(pint_t& addr, pint_
                        // do nothing
                        break;
                case DW_EH_PE_pcrel:
-                       result += startAddr;
+                       // <rdar://problem/7200658> pc-rel sdata4 should return zero if content is zero
+                       if ( (result != 0) || ((encoding & DW_EH_PE_indirect) != 0) )
+                               result += startAddr;
                        break;
                case DW_EH_PE_textrel:
                        throw "DW_EH_PE_textrel pointer encoding not supported";
@@ -4127,6 +4155,85 @@ bool Reader<arm>::validFile(const uint8_t* fileContent, bool subtypeMustMatch, c
        return true;
 }
 
+
+template <>
+const char* Reader<ppc>::fileKind(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return NULL;
+       if ( header->cputype() != CPU_TYPE_POWERPC )
+               return NULL;
+       switch ( header->cpusubtype() ) {
+               case CPU_SUBTYPE_POWERPC_750:
+                       return "ppc750";
+               case CPU_SUBTYPE_POWERPC_7400:
+                       return "ppc7400";
+               case CPU_SUBTYPE_POWERPC_7450:
+                       return "ppc7450";
+               case CPU_SUBTYPE_POWERPC_970:
+                       return "ppc970";
+               case CPU_SUBTYPE_POWERPC_ALL:
+                       return "ppc";
+       }
+       return "ppc???";
+}
+
+template <>
+const char* Reader<ppc64>::fileKind(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return NULL;
+       if ( header->cputype() != CPU_TYPE_POWERPC64 )
+               return NULL;
+       return "ppc64";
+}
+
+template <>
+const char* Reader<x86>::fileKind(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return NULL;
+       if ( header->cputype() != CPU_TYPE_I386 )
+               return NULL;
+       return "i386";
+}
+
+template <>
+const char* Reader<x86_64>::fileKind(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return NULL;
+       if ( header->cputype() != CPU_TYPE_X86_64 )
+               return NULL;
+       return "x86_64";
+}
+
+template <>
+const char* Reader<arm>::fileKind(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return NULL;
+       if ( header->cputype() != CPU_TYPE_ARM )
+               return NULL;
+       switch ( header->cpusubtype() ) {
+               case CPU_SUBTYPE_ARM_V4T:
+                       return "armv4t";
+               case CPU_SUBTYPE_ARM_V5TEJ:
+                       return "armv5";
+               case CPU_SUBTYPE_ARM_V6:
+                       return "armv6";
+               case CPU_SUBTYPE_ARM_V7:
+                       return "armv7";
+       }
+       return "arm???";
+}
+
+
 template <typename A>
 bool Reader<A>::isWeakImportSymbol(const macho_nlist<P>* sym)
 {
index 2ed0feb426215d6dfb0a0acddb17fe441c9e9165..95967330007943befbe6f986607b791d04d99cf3 100644 (file)
@@ -967,6 +967,23 @@ private:
        uint64_t                                                                fSize;
 };
 
+template <typename A>
+class MinimalTextAtom : public WriterAtom<A>
+{
+public:
+                                                                                       MinimalTextAtom(Writer<A>& writer)
+                                                                                                       : WriterAtom<A>(writer, headerSegment(writer)) {}
+       virtual const char*                                             getDisplayName() const  { return "minimal text"; }
+       virtual uint64_t                                                getSize() const                 { return 0; }
+       virtual const char*                                             getSectionName() const  { return "__text"; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const { }
+       virtual ObjectFile::Atom::SymbolTableInclusion  getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
+       
+private:
+       using WriterAtom<A>::fWriter;
+};
+
+
 template <typename A>
 class UnwindInfoAtom : public WriterAtom<A>
 {
@@ -1480,7 +1497,7 @@ public:
        uint64_t                                                                getFinalTargetAdress() const { return fFinalTarget.getAddress() + fFinalTargetOffset; }
 private:
        using WriterAtom<A>::fWriter;
-       enum IslandKind { kBranchIslandToARM, kBranchIslandToThumb2, kBranchIslandToThumb1 };
+       enum IslandKind { kBranchIslandToARM, kBranchIslandToThumb2, kBranchIslandToThumb1, kBranchIslandNoPicToThumb1 };
        const char*                                                             fName;
        ObjectFile::Atom&                                               fTarget;
        ObjectFile::Atom&                                               fFinalTarget;
@@ -2869,7 +2886,7 @@ Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile
          fLargestAtomSize(1), 
          fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false), 
          fCanScatter(false), fWritableSegmentPastFirst4GB(false), fNoReExportedDylibs(false), 
-         fBiggerThanTwoGigs(false), fSlideable(false), fHasThumbBranches(false),
+         fBiggerThanTwoGigs(false), fSlideable(false), fHasThumbBranches(false), 
          fFirstWritableSegment(NULL), fAnonNameIndex(1000)
 {
        switch ( fOptions.outputKind() ) {
@@ -2891,6 +2908,7 @@ Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile
                        if ( fOptions.hasCustomStack() )
                                fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
                        fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
+                       fWriterSynthesizedAtoms.push_back(new MinimalTextAtom<A>(*this));
                        if ( fOptions.needsUnwindInfoSection() )
                                fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
                        fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
@@ -2941,6 +2959,7 @@ Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile
                        if ( fOptions.sharedRegionEligible() )
                                fWriterSynthesizedAtoms.push_back(new SegmentSplitInfoLoadCommandsAtom<A>(*this));
                        fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
+                       fWriterSynthesizedAtoms.push_back(new MinimalTextAtom<A>(*this));
                        if ( fOptions.needsUnwindInfoSection() )
                                fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
                        fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
@@ -5273,7 +5292,10 @@ typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(cons
                        else
                                return kRelocNone;
                case ObjectFile::Atom::kWeakDefinition:
-                       // all calls to global weak definitions get indirected
+                       // in static executables, references to weak definitions are not indirected
+                       if ( fOptions.outputKind() == Options::kStaticExecutable)
+                               return kRelocNone;
+                       // in dynamic code, all calls to global weak definitions get indirected
                        if ( this->shouldExport(target) )
                                return kRelocExternal;
                        else if ( fSlideable )
@@ -10947,7 +10969,10 @@ BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int i
                        fIslandKind = kBranchIslandToThumb2;
                }
                else {
-                       fIslandKind = kBranchIslandToThumb1;
+                       if ( writer.fSlideable )
+                               fIslandKind = kBranchIslandToThumb1;
+                       else
+                               fIslandKind = kBranchIslandNoPicToThumb1;
                }
        }
        else {
@@ -11091,6 +11116,19 @@ void BranchIslandAtom<arm>::copyRawContent(uint8_t buffer[]) const
                        OSWriteLittleInt32(&buffer[12], 0, displacement);       //      .long target-this               
                        }
                        break;
+               case kBranchIslandNoPicToThumb1:
+                       {
+                       // There is no large displacement thumb1 branch instruction.
+                       // Instead use ARM instructions that can jump to thumb.
+                       // we use a 32-bit displacement, so we can directly jump to target which means no island hopping
+                       uint32_t targetAddr = getFinalTargetAdress();
+                       if ( fFinalTarget.isThumb() )
+                               targetAddr |= 1;
+                       if (log) fprintf(stderr, "%s: 2 ARM instruction jump to final target at 0x%08llX\n", fName, getFinalTargetAdress());
+                       OSWriteLittleInt32(&buffer[0], 0, 0xe51ff004);  //      ldr     pc, [pc, #-4]
+                       OSWriteLittleInt32(&buffer[4], 0, targetAddr);  //      .long target-this               
+                       }
+                       break;  
        };
 }
 
@@ -11116,6 +11154,8 @@ uint64_t BranchIslandAtom<arm>::getSize() const
                        return 16;
                case kBranchIslandToThumb2:
                        return 4;
+               case kBranchIslandNoPicToThumb1:
+                       return 8;
        };
        throw "internal error: no ARM branch island kind";
 }
index 7bba72ac4d3957f3019a325b7be9725ba340f004..e3ad601c4847d950b29b0ad3b0765c99b970eb4b 100644 (file)
@@ -77,7 +77,7 @@ public:
                                                                                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 IPhoneVersionMin { kMinIPhoneVersionUnset, k2_0, k3_0, k3_1 };
+       enum IPhoneVersionMin { kMinIPhoneVersionUnset, k2_0, k2_1, k2_2, k3_0, k3_1, k3_2, k4_0 };
 
        struct AliasPair {
                const char*                     realName;
index 6521abebcbf98a7aefe658b35303f0844417ab9e..f63a123351f966e163ee92b0e5b8f496726c8333 100644 (file)
@@ -1269,14 +1269,20 @@ void Options::setIPhoneVersionMin(const char* version)
        if ( ! isdigit(version[2]) )
                throw "-iphoneos_version_min argument is not a number";
 
-       if ( version[0] == '2' )
+                if ( (version[0] == '2') && (version[2] == '0') )
                fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_0;
+       else if ( (version[0] == '2') && (version[2] == '1') )
+               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_1;
+       else if ( (version[0] == '2') && (version[2] >= '2') )
+               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_2;
        else if ( (version[0] == '3') && (version[2] == '0') )
-               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_0;
-       else if ( (version[0] == '3') && (version[2] >= '1') )
+               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_0;
+       else if ( (version[0] == '3') && (version[2] == '1') )
                fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_1;
+       else if ( (version[0] == '3') && (version[2] >= '2') )
+               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_2;
        else if ( (version[0] >= '4')  )
-               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_1;
+               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k4_0;
        else {
                fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_0;
                warning("unknown option to -iphoneos_version_min, not 2.x, 3.x, or 4.x");
@@ -2537,10 +2543,36 @@ void Options::buildSearchPaths(int argc, const char* argv[])
        frameworkPaths.reserve(10);
        // scan through argv looking for -L, -F, -Z, and -syslibroot options
        for(int i=0; i < argc; ++i) {
-               if ( (argv[i][0] == '-') && (argv[i][1] == 'L') )
-                       libraryPaths.push_back(&argv[i][2]);
-               else if ( (argv[i][0] == '-') && (argv[i][1] == 'F') )
-                       frameworkPaths.push_back(&argv[i][2]);
+               if ( (argv[i][0] == '-') && (argv[i][1] == 'L') ) {
+                       const char* libSearchDir = &argv[i][2];
+                       if ( libSearchDir[0] == '\0' ) 
+                               throw "-L must be immediately followed by a directory path (no space)";
+                       struct stat statbuf;
+                       if ( stat(libSearchDir, &statbuf) == 0 ) {
+                               if ( statbuf.st_mode & S_IFDIR )
+                                       libraryPaths.push_back(libSearchDir);
+                               else
+                                       warning("path '%s' following -L not a directory", libSearchDir);
+                       }
+                       else {
+                               warning("directory '%s' following -L not found", libSearchDir);
+                       }
+               }
+               else if ( (argv[i][0] == '-') && (argv[i][1] == 'F') ) {
+                       const char* frameworkSearchDir = &argv[i][2];
+                       if ( frameworkSearchDir[0] == '\0' ) 
+                               throw "-F must be immediately followed by a directory path (no space)";
+                       struct stat statbuf;
+                       if ( stat(frameworkSearchDir, &statbuf) == 0 ) {
+                               if ( statbuf.st_mode & S_IFDIR )
+                                       frameworkPaths.push_back(frameworkSearchDir);
+                               else
+                                       warning("path '%s' following -F not a directory", frameworkSearchDir);
+                       }
+                       else {
+                               warning("directory '%s' following -F not found", frameworkSearchDir);
+                       }
+               }
                else if ( strcmp(argv[i], "-Z") == 0 )
                        addStandardLibraryDirectories = false;
                else if ( strcmp(argv[i], "-v") == 0 ) {
index f9d9ecbc626ef900d7c6b0b0424f9bbefbd0f0b0..6b6d1149d1ea7742ee2e9a69e371b9c5a4974e96 100644 (file)
@@ -143,15 +143,16 @@ Section::Section(const char* sectionName, const char* segmentName, bool zeroFill
                        this->fIndex = 11;
                else if ( strcmp(sectionName, "__symbol_stub1") == 0 ) 
                        this->fIndex = 11;
+               // sort fast arm stubs to end of __TEXT to be close to lazy pointers
+               else if ( strcmp(sectionName, "__symbolstub1") == 0 ) 
+                       this->fIndex = INT_MAX;  
                // sort unwind info to end of segment
                else if ( strcmp(sectionName, "__eh_frame") == 0 )
-                       this->fIndex = INT_MAX;
-               else if ( strcmp(sectionName, "__unwind_info") == 0 ) 
                        this->fIndex = INT_MAX-1;
-               else if ( strcmp(sectionName, "__gcc_except_tab") == 0 ) 
+               else if ( strcmp(sectionName, "__unwind_info") == 0 ) 
                        this->fIndex = INT_MAX-2;
-               else if ( strcmp(sectionName, "__symbolstub1") == 0 ) 
-                       this->fIndex = INT_MAX-3;  // sort to end of __TEXT to be close to lazy pointers
+               else if ( strcmp(sectionName, "__gcc_except_tab") == 0 ) 
+                       this->fIndex = INT_MAX-3;
        }
        else if ( strcmp(segmentName, "__DATA") == 0 ) {
                // sort arm lazy symbol pointers that must be at start of __DATA
@@ -332,6 +333,7 @@ private:
        };
 
        ObjectFile::Reader*     createReader(const Options::FileInfo&);
+       const char*                     fileArch(const void* p);
        void                            addAtom(ObjectFile::Atom& atom);
        void                            addAtoms(std::vector<class ObjectFile::Atom*>& atoms);
        void                            buildAtomList();
@@ -359,7 +361,7 @@ private:
        static const char*      truncateStabString(const char* str);
        void                            collectDebugInfo();
        void                            writeOutput();
-       ObjectFile::Atom*       entryPoint(bool orInit);
+       ObjectFile::Atom*       entryPoint(bool orInit, bool searchArchives=false);
        ObjectFile::Atom*       dyldClassicHelper();
        ObjectFile::Atom*       dyldCompressedHelper();
        ObjectFile::Atom*       dyldLazyLibraryHelper();
@@ -541,6 +543,22 @@ Linker::Linker(int argc, const char* argv[])
                        break;
                case CPU_TYPE_ARM:
                        fArchitectureName = "arm";
+                       if ( fOptions.preferSubArchitecture() ) {
+                               switch ( fOptions.subArchitecture() ) {
+                                       case CPU_SUBTYPE_ARM_V4T:
+                                               fArchitectureName = "armv4t";
+                                               break;
+                                       case CPU_SUBTYPE_ARM_V5TEJ:
+                                               fArchitectureName = "armv5";
+                                               break;
+                                       case CPU_SUBTYPE_ARM_V6:
+                                               fArchitectureName = "armv6";
+                                               break;
+                                       case CPU_SUBTYPE_ARM_V7:
+                                               fArchitectureName = "armv7";
+                                               break;
+                               }
+                       }
                        break;
                default:
                        fArchitectureName = "unknown architecture";
@@ -746,6 +764,7 @@ void Linker::optimize()
                        // LTO may optimize away some atoms, so dead stripping must be redone
                        fLiveAtoms.clear();
                        this->deadStripResolve();
+                       this->checkUndefines();
                }
                else {
                        // LTO may require new library symbols to be loaded, so redo
@@ -1218,10 +1237,44 @@ void Linker::checkUndefines()
                                        }
                                }
                                // scan command line options
-                               if  ( !foundAtomReference && fOptions.hasExportRestrictList() && fOptions.shouldExport(name) ) {
-                                       fprintf(stderr, "     -exported_symbols_list command line option\n");
+                               if  ( !foundAtomReference ) {
+                                       // might be from -init command line option
+                                       if ( (fOptions.initFunctionName() != NULL) && (strcmp(name, fOptions.initFunctionName()) == 0) ) {
+                                               fprintf(stderr, "     -init command line option\n");
+                                       }
+                                       // or might be from exported symbol option
+                                       else if ( fOptions.hasExportMaskList() && fOptions.shouldExport(name) ) {
+                                               fprintf(stderr, "     -exported_symbol[s_list] command line option\n");
+                                       }
+                                       else {
+                                               bool isInitialUndefine = false;
+                                               std::vector<const char*>& clundefs = fOptions.initialUndefines();
+                                               for (std::vector<const char*>::iterator uit = clundefs.begin(); uit != clundefs.end(); ++uit) {
+                                                       if ( strcmp(*uit, name) == 0 ) {
+                                                               isInitialUndefine = true;
+                                                               break;
+                                                       }
+                                               }
+                                               if ( isInitialUndefine )
+                                                       fprintf(stderr, "     -u command line option\n");
+                                       }
                                        ++unresolvableExportsCount;
                                }
+                               // be helpful and check for typos
+                               bool printedStart = false;
+                               for (SymbolTable::Mapper::iterator sit=fGlobalSymbolTable.begin(); sit != fGlobalSymbolTable.end(); ++sit) {
+                                       if ( (sit->second != NULL) && (strstr(sit->first, name) != NULL) ) {
+                                               if ( ! printedStart ) {
+                                                       fprintf(stderr, "     (maybe you meant: %s", sit->first);
+                                                       printedStart = true;
+                                               }
+                                               else {
+                                                       fprintf(stderr, ", %s ", sit->first);
+                                               }
+                                       }
+                               }
+                               if ( printedStart )
+                                       fprintf(stderr, ")\n");
                        }
                }
                if ( doError ) 
@@ -1593,7 +1646,7 @@ void Linker::moveToFrontOfSection(ObjectFile::Atom* atom)
 void Linker::deadStripResolve()
 {
        // add main() to live roots
-       ObjectFile::Atom* entryPoint = this->entryPoint(false);
+       ObjectFile::Atom* entryPoint = this->entryPoint(false, true);
        if ( entryPoint != NULL )
                fLiveRootAtoms.insert(entryPoint);
 
@@ -2460,7 +2513,7 @@ void Linker::writeDotOutput()
        }
 }
 
-ObjectFile::Atom* Linker::entryPoint(bool orInit)
+ObjectFile::Atom* Linker::entryPoint(bool orInit, bool searchArchives)
 {
        // if main executable, find entry point atom
        ObjectFile::Atom* entryPoint = NULL;
@@ -2470,6 +2523,11 @@ ObjectFile::Atom* Linker::entryPoint(bool orInit)
                case Options::kDyld:
                case Options::kPreload:
                        entryPoint = fGlobalSymbolTable.find(fOptions.entryName());
+                       if ( (entryPoint == NULL) && searchArchives ) {
+                               // <rdar://problem/7043256> ld64 can not find a -e entry point from an archive                          
+                               this->addJustInTimeAtoms(fOptions.entryName(), false, true, false);
+                               entryPoint = fGlobalSymbolTable.find(fOptions.entryName());
+                       }
                        if ( entryPoint == NULL ) {
                                throwf("could not find entry point \"%s\" (perhaps missing crt1.o)", fOptions.entryName());
                        }
@@ -3175,6 +3233,12 @@ void Linker::collectDebugInfo()
 
 void Linker::writeOutput()
 {
+       // <rdar://problem/6933931> ld -r of empty .o file should preserve sub-type
+       // <rdar://problem/7049478> empty dylib should have subtype from command line
+       if ( fOptions.preferSubArchitecture() && (fOptions.architecture() == CPU_TYPE_ARM) ) {
+               fCurrentCpuConstraint = (ObjectFile::Reader::CpuConstraint)fOptions.subArchitecture();
+       }
+
        if ( fOptions.forceCpuSubtypeAll() )
                fCurrentCpuConstraint = ObjectFile::Reader::kCpuAny;
 
@@ -3187,6 +3251,33 @@ void Linker::writeOutput()
                                                                                        fGlobalSymbolTable.hasExternalWeakDefinitions());
 }
 
+const char* Linker::fileArch(const void* p)
+{
+       const uint8_t* bytes = (uint8_t*)p;
+       const char* result;
+       result = mach_o::relocatable::Reader<ppc>::fileKind(bytes);
+       if ( result != NULL  )
+                return result;
+       result = mach_o::relocatable::Reader<ppc64>::fileKind(bytes);
+       if ( result != NULL  )
+                return result;
+       result = mach_o::relocatable::Reader<x86>::fileKind(bytes);
+       if ( result != NULL  )
+                return result;
+       result = mach_o::relocatable::Reader<x86_64>::fileKind(bytes);
+       if ( result != NULL  )
+                return result;
+       result = mach_o::relocatable::Reader<arm>::fileKind(bytes);
+       if ( result != NULL  )
+                return result;
+                
+       result = lto::Reader::fileKind(bytes);
+       if ( result != NULL  )
+                return result;
+       
+       return "unsupported file format";        
+}
+
 ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
 {
        // map in whole file
@@ -3203,8 +3294,10 @@ ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
 
        // if fat file, skip to architecture we want
        // Note: fat header is always big-endian
+       bool isFatFile = false;
        const fat_header* fh = (fat_header*)p;
        if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+               isFatFile = true;
                const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
                uint32_t sliceToUse;
                bool sliceFound = false;
@@ -3295,8 +3388,28 @@ ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
        if ( lto::Reader::validFile(p, len, fArchitecture) ) {
                return this->addObject(new lto::Reader(p, len, info.path, info.modTime, fOptions.readerOptions(), fArchitecture), info, len);
        }
-       else if ( !lto::Reader::loaded() && (p[0] == 'B') && (p[1] == 'C')  ) {
-               throw "could not process object file.  Looks like an llvm bitcode object file, but libLTO.dylib could not be loaded";
+       else if ( lto::Reader::fileKind((uint8_t*)p) != NULL ) {
+               if ( lto::Reader::loaded() ) {
+                       throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p), fArchitectureName);
+               }
+               else {
+                       const char* libLTO = "libLTO.dylib";
+                       char ldPath[PATH_MAX];
+                       char tmpPath[PATH_MAX];
+                       char libLTOPath[PATH_MAX];
+                       uint32_t bufSize = PATH_MAX;
+                       if ( _NSGetExecutablePath(ldPath, &bufSize) != -1 ) {
+                               if ( realpath(ldPath, tmpPath) != NULL ) {
+                                       char* lastSlash = strrchr(tmpPath, '/');
+                                       if ( lastSlash != NULL )
+                                               strcpy(lastSlash, "/../lib/libLTO.dylib");
+                                       libLTO = tmpPath;
+                                       if ( realpath(tmpPath, libLTOPath) != NULL ) 
+                                               libLTO = libLTOPath;
+                               }
+                       }
+                       throwf("could not process llvm bitcode object file, because %s could not be loaded", libLTO);
+               }
        }
 #endif
        // error handling
@@ -3304,7 +3417,10 @@ ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
                throwf("missing required architecture %s in file", fArchitectureName);
        }
        else {
-               throw "file is not of required architecture";
+               if ( isFatFile )
+                       throwf("file is universal but does not contain a(n) %s slice", fArchitectureName);
+               else
+                       throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p), fArchitectureName);
        }
 }
 
@@ -4107,6 +4223,12 @@ bool Linker::AtomSorter::operator()(const ObjectFile::Atom* left, const ObjectFi
                }
        }
 
+       // magic section$end symbol always sorts to the end of its section
+       if ( left->getContentType() == ObjectFile::Atom::kSectionEnd )
+               return false;
+       if ( right->getContentType() == ObjectFile::Atom::kSectionEnd )
+               return true;
+
        // the __common section can have real or tentative definitions
        // we want the real ones to sort before tentative ones
        bool leftIsTent  =  (left->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition);
@@ -4114,12 +4236,6 @@ bool Linker::AtomSorter::operator()(const ObjectFile::Atom* left, const ObjectFi
        if ( leftIsTent != rightIsTent )
                return rightIsTent; 
        
-       // magic section$end symbol always sorts to the end of its section
-       if ( left->getContentType() == ObjectFile::Atom::kSectionEnd )
-               return false;
-       if ( right->getContentType() == ObjectFile::Atom::kSectionEnd )
-               return true;
-
        // initializers are auto sorted to start of section
        if ( !fInitializerSet.empty() ) {
                bool leftFirst  = (fInitializerSet.count(left) != 0);
index c2ae578be739c6a5830d07cc37c74793ce81d1e6..25352b1b3b9cf066f8c184082bc6fbf0d22cf65a 100644 (file)
@@ -40,7 +40,8 @@ static bool                   sDumpContent= true;
 static bool                    sDumpStabs      = false;
 static bool                    sSort           = true;
 static bool                    sNMmode         = false;
-static cpu_type_t      sPreferredArch = CPU_TYPE_POWERPC64;
+static cpu_type_t              sPreferredArch = CPU_TYPE_I386;
+static cpu_subtype_t   sPreferredSubArch = 0xFFFFFFFF;
 static const char* sMatchName;
 static int sPrintRestrict;
 static int sPrintAlign;
@@ -405,8 +406,11 @@ static ObjectFile::Reader* createReader(const char* path, const ObjectFile::Read
                const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
                for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
                        if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) {
-                               p = p + OSSwapBigToHostInt32(archs[i].offset);
-                               mh = (struct mach_header*)p;
+                               if ( ((uint32_t)sPreferredSubArch == 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch == OSSwapBigToHostInt32(archs[i].cpusubtype)) ) {
+                                       p = p + OSSwapBigToHostInt32(archs[i].offset);
+                                       mh = (struct mach_header*)p;
+                                       break;
+                               }
                        }
                }
        }
@@ -480,8 +484,22 @@ int main(int argc, const char* argv[])
                                                sPreferredArch = CPU_TYPE_X86_64;
                                        else if ( strcmp(arch, "arm") == 0 )
                                                sPreferredArch = CPU_TYPE_ARM;
-                                       else if ( strcmp(arch, "armv6") == 0 )
+                                       else if ( strcmp(arch, "armv4t") == 0 ) {
+                                               sPreferredArch = CPU_TYPE_ARM;
+                                               sPreferredSubArch = CPU_SUBTYPE_ARM_V4T;
+                                       }
+                                       else if ( strcmp(arch, "armv5") == 0 ) {
+                                               sPreferredArch = CPU_TYPE_ARM;
+                                               sPreferredSubArch = CPU_SUBTYPE_ARM_V5TEJ;
+                                       }
+                                       else if ( strcmp(arch, "armv6") == 0 ) {
+                                               sPreferredArch = CPU_TYPE_ARM;
+                                               sPreferredSubArch = CPU_SUBTYPE_ARM_V6;
+                                       }
+                                       else if ( strcmp(arch, "armv7") == 0 ) {
                                                sPreferredArch = CPU_TYPE_ARM;
+                                               sPreferredSubArch = CPU_SUBTYPE_ARM_V7;
+                                       }
                                        else 
                                                throwf("unknown architecture %s", arch);
                                }
index cb4a7818f6700e3981974e88ca72d7c8f06654e1..68fdbb802009cf8319818e1cffdf4e380b79ff60 100644 (file)
@@ -106,6 +106,7 @@ private:
        bool                                                                            fWriteableSegmentWithAddrOver4G;
        const macho_segment_command<P>*                         fFirstSegment;
        const macho_segment_command<P>*                         fFirstWritableSegment;
+       uint32_t                                                                        fSectionCount;
 };
 
 
@@ -210,7 +211,7 @@ template <typename A>
 MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path)
  : fHeader(NULL), fLength(fileLength), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fDynamicSymbolTable(NULL), fIndirectTableCount(0),
  fLocalRelocations(NULL),  fLocalRelocationsCount(0),  fExternalRelocations(NULL),  fExternalRelocationsCount(0),
- fWriteableSegmentWithAddrOver4G(false), fFirstSegment(NULL), fFirstWritableSegment(NULL)
+ fWriteableSegmentWithAddrOver4G(false), fFirstSegment(NULL), fFirstWritableSegment(NULL), fSectionCount(0)
 {
        // sanity check
        if ( ! validFile(fileContent) )
@@ -387,6 +388,7 @@ void MachOChecker<A>::checkLoadCommands()
                                                throwf("section %s file offset not within segment", sect->sectname());
                                }       
                                checkSection(segCmd, sect);
+                               ++fSectionCount;
                        }
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
@@ -606,6 +608,15 @@ void MachOChecker<A>::checkSymbolTable()
                        if ( externalNames.find(symName) != externalNames.end() )
                                throwf("undefine with same name as external symbol: %s", symName);
                }
+               // verify all N_SECT values are valid
+               for(const macho_nlist<P>* p = fSymbols; p < &fSymbols[fSymbolCount]; ++p) {
+                       uint8_t type = p->n_type();
+                       if ( ((type & N_STAB) == 0) && ((type & N_TYPE) == N_SECT) ) {
+                               if ( p->n_sect() > fSectionCount ) {
+                                       throwf("symbol '%s' has n_sect=%d which is too large", &fStrings[p->n_strx()], p->n_sect());
+                               }
+                       }
+               }
        }
 }
 
index 39c0ef97da378cfaab3a36a135dcdb6f5938dc61..65c5f564805f1c6bae16fc679bf0ecaa0aa4143d 100644 (file)
@@ -39,7 +39,7 @@ all:
        ${CC} ${CCFLAGS} main.c -lfoobar-${ARCH} -L. -o main-${ARCH} 
        ${FAIL_IF_BAD_MACHO} main-${ARCH}
        nm main-${ARCH} | grep "_bar" | ${PASS_IFF_EMPTY}
-       ${CC} ${CCFLAGS} main.c -all_load -lfoobar-${ARCH} -L. -o main-${ARCH} 
+       ${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoobar-${ARCH}.a -o main-${ARCH} 
        ${FAIL_IF_BAD_MACHO} main-${ARCH}
 
 clean:
index 61f4bc71ebbdda60576ef1096364b54d5fe1881a..e339b180885661b743755afea1f0aa67e02c543a 100644 (file)
@@ -36,9 +36,9 @@ all:
        ${CC} ${CCFLAGS} foo.c -c -o foo-${ARCH}.o 
        ${CC} ${CCFLAGS} bar.c -c -o bar-${ARCH}.o 
        libtool -static foo-${ARCH}.o  bar-${ARCH}.o -o libfoobar-${ARCH}.a
-       ${CC} ${CCFLAGS} main.c -lfoobar-${ARCH} -lfoobar-${ARCH} -L. -o main-${ARCH} -all_load
+       ${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoobar-${ARCH}.a -lfoobar-${ARCH} -L. -o main-${ARCH} 
        ${FAIL_IF_BAD_MACHO} main-${ARCH}
-       ${CC} ${CCFLAGS} main.c ./libfoobar-${ARCH}.a ./libfoobar-${ARCH}.a -L. -o main-${ARCH} -all_load
+       ${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoobar-${ARCH}.a ./libfoobar-${ARCH}.a -L. -o main-${ARCH}
        ${PASS_IFF_GOOD_MACHO} main-${ARCH}
 
 clean:
diff --git a/unit-tests/test-cases/dead_strip-entry-archive/Makefile b/unit-tests/test-cases/dead_strip-entry-archive/Makefile
new file mode 100644 (file)
index 0000000..1317c48
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# Copyright (c) 2009 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
+
+#
+# <rdar://problem/7043256> ld64 can not find a -e entry point from an archive
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c -c -o foo.o
+       libtool -static foo.o -o libfoo.a
+       ${FAIL_IF_ERROR} ${CC} ${CCFLAGS}  bar.c -Os libfoo.a -dead_strip -o foo -Wl,-e,_foo 
+       ${PASS_IFF_GOOD_MACHO} foo
+
+clean:
+       rm -rf foo libfoo.a foo.o
+
diff --git a/unit-tests/test-cases/dead_strip-entry-archive/bar.c b/unit-tests/test-cases/dead_strip-entry-archive/bar.c
new file mode 100644 (file)
index 0000000..b348aa8
--- /dev/null
@@ -0,0 +1,4 @@
+
+void bar() {}
+
+
diff --git a/unit-tests/test-cases/dead_strip-entry-archive/foo.c b/unit-tests/test-cases/dead_strip-entry-archive/foo.c
new file mode 100644 (file)
index 0000000..95ec91c
--- /dev/null
@@ -0,0 +1,6 @@
+
+
+void foo() {}
+
+
+
diff --git a/unit-tests/test-cases/empty-dylib/Makefile b/unit-tests/test-cases/empty-dylib/Makefile
new file mode 100644 (file)
index 0000000..a12e7c1
--- /dev/null
@@ -0,0 +1,39 @@
+##
+# Copyright (c) 2009 Apple Computer, 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
+
+#
+# Check that the n_sect number for __mh_dylib_header is valid when there is no __text section
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -dynamiclib justdata.c -o libjustdata.dylib -Wl,-no_compact_unwind
+       ${PASS_IFF_GOOD_MACHO} libjustdata.dylib
+       ${CC} ${CCFLAGS} -dynamiclib empty.c -o libempty.dylib -Wl,-no_compact_unwind
+       ${PASS_IFF_GOOD_MACHO} libempty.dylib
+
+clean:
+       rm -rf libempty.dylib libjustdata.dylib
diff --git a/unit-tests/test-cases/empty-dylib/empty.c b/unit-tests/test-cases/empty-dylib/empty.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/unit-tests/test-cases/empty-dylib/justdata.c b/unit-tests/test-cases/empty-dylib/justdata.c
new file mode 100644 (file)
index 0000000..266e00d
--- /dev/null
@@ -0,0 +1 @@
+int data = 1;
index d233171a6b4087fee3e7d83c834f115b8ac4edac..4844cd77d45b4f8394b1878b339c957f6f195290 100644 (file)
@@ -18,7 +18,7 @@ run: all
 all:
        ${CC} ${CCFLAGS} -static -fno-common -mkernel -c mykext.c -o mykext.o
        ${CC} ${CCFLAGS} -static -fno-common -mkernel -c mykextinfo.c -o mykextinfo.o
-       ${CC} ${CCFLAGS} -Wl,-kext mykext.o mykextinfo.o -nostdlib -lkmodc++ -lkmod -lcc_kext -o mykext
+       unset LD_NO_CLASSIC_LINKER_STATIC && ${CC} ${CCFLAGS} -Wl,-kext mykext.o mykextinfo.o -nostdlib -lkmodc++ -lkmod -lcc_kext -o mykext -Wl,-w
        otool -hv mykext | grep ${FILE_TYPE} | ${FAIL_IF_EMPTY}
        nm -nm mykext | grep '(undefined) external _extern_global' | ${FAIL_IF_EMPTY}
        nm -nm mykext | grep '(__DATA,__data) external _my_global' | ${FAIL_IF_EMPTY}
diff --git a/unit-tests/test-cases/section-labels-zero-fill/Makefile b/unit-tests/test-cases/section-labels-zero-fill/Makefile
new file mode 100644 (file)
index 0000000..658a164
--- /dev/null
@@ -0,0 +1,46 @@
+##
+# Copyright (c) 2009 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
+
+#
+# Check that ld resolves the magic section start/end symbols.
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} common.c -o common
+       otool -lv common | grep -A8 __common | grep S_ZEROFILL | ${FAIL_IF_EMPTY}
+       ${FAIL_IF_BAD_MACHO} common
+       ${CC} ${CCFLAGS} bss.c -o bss
+       otool -lv bss | grep -A8 __bss | grep S_ZEROFILL | ${FAIL_IF_EMPTY}
+       ${FAIL_IF_BAD_MACHO} bss
+       ${CC} ${CCFLAGS} both.c -o both
+       otool -lv both | grep -A8 __common | grep S_ZEROFILL | ${FAIL_IF_EMPTY}
+       otool -lv both | grep -A8 __bss | grep S_ZEROFILL | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} both
+
+clean:
+       rm -f common bss both
+       
diff --git a/unit-tests/test-cases/section-labels-zero-fill/both.c b/unit-tests/test-cases/section-labels-zero-fill/both.c
new file mode 100644 (file)
index 0000000..fc1eabc
--- /dev/null
@@ -0,0 +1,43 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2009 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@
+ */
+#include <stdio.h>
+
+
+extern int  bss_start  __asm("section$start$__DATA$__bss");
+extern int  bss_end    __asm("section$end$__DATA$__bss");
+extern int  common_start  __asm("section$start$__DATA$__common");
+extern int  common_end    __asm("section$end$__DATA$__common");
+
+int mycommon[2];
+static int mybss[2];
+
+int main()
+{
+       mybss[0] = 0;
+       printf("bss start = %p\n", &bss_start);
+       printf("bss end = %p\n", &bss_end);
+       printf("common start = %p\n", &common_start);
+       printf("common end = %p\n", &common_end);
+       return 0;
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/section-labels-zero-fill/bss.c b/unit-tests/test-cases/section-labels-zero-fill/bss.c
new file mode 100644 (file)
index 0000000..d9b580b
--- /dev/null
@@ -0,0 +1,38 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2009 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@
+ */
+#include <stdio.h>
+
+
+extern int  bss_start  __asm("section$start$__DATA$__bss");
+extern int  bss_end    __asm("section$end$__DATA$__bss");
+
+static int mybss[2];
+
+int main()
+{
+       mybss[0] = 0;
+       printf("bss start = %p\n", &bss_start);
+       printf("bss end = %p\n", &bss_end);
+       return 0;
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/section-labels-zero-fill/common.c b/unit-tests/test-cases/section-labels-zero-fill/common.c
new file mode 100644 (file)
index 0000000..57a1270
--- /dev/null
@@ -0,0 +1,37 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2009 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@
+ */
+#include <stdio.h>
+
+
+extern int  common_start  __asm("section$start$__DATA$__common");
+extern int  common_end    __asm("section$end$__DATA$__common");
+
+int mycommon[2];
+
+int main()
+{
+       printf("common start = %p\n", &common_start);
+       printf("common end = %p\n", &common_end);
+       return 0;
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/static-executable-weak-defines/Makefile b/unit-tests/test-cases/static-executable-weak-defines/Makefile
new file mode 100644 (file)
index 0000000..05588b5
--- /dev/null
@@ -0,0 +1,35 @@
+##
+# Copyright (c) 2009 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 ld can link a static executable with a weak definition
+#
+
+all:
+       ${CC} ${CCFLAGS} test.c -static -o test -e _entry -nostdlib -Wl,-new_linker
+       ${PASS_IFF_GOOD_MACHO} test
+
+clean:
+       rm -rf test
diff --git a/unit-tests/test-cases/static-executable-weak-defines/test.c b/unit-tests/test-cases/static-executable-weak-defines/test.c
new file mode 100644 (file)
index 0000000..3e03861
--- /dev/null
@@ -0,0 +1,13 @@
+
+
+
+__attribute__((weak)) int foo()
+{
+       return 0;
+}
+
+
+int entry()
+{
+       return foo();
+}