]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-26.0.80.tar.gz mac-os-x-1043 mac-os-x-1044ppc mac-os-x-1045ppc v26.0.80
authorApple <opensource@apple.com>
Thu, 26 May 2005 21:37:27 +0000 (21:37 +0000)
committerApple <opensource@apple.com>
Thu, 26 May 2005 21:37:27 +0000 (21:37 +0000)
ld64.xcode/project.pbxproj
src/MachOAbstraction.h
src/ObjectFile.h
src/Options.cpp
src/Options.h
src/Readers/ObjectFileArchiveMachO.cpp
src/Readers/ObjectFileDylibMachO.cpp
src/Readers/ObjectFileMachO.cpp
src/Writers/ExecutableFileMachO.cpp
src/ld.cpp

index ef5a16d0b220bb5fe8be515fc0dd9539f853c6d6..1831cbed073f3f9038a89e5b2039aaaa64decd33 100644 (file)
@@ -83,6 +83,8 @@
                                F97F5025070D0B6300B9FCD7,
                        );
                        buildRules = (
+                               F9E8D4BE07FCAF2A00FD5801,
+                               F9E8D4BD07FCAF2000FD5801,
                        );
                        buildSettings = {
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                        settings = {
                        };
                };
+               F9E8D4BD07FCAF2000FD5801 = {
+                       compilerSpec = com.apple.compilers.gcc.4_0;
+                       fileType = sourcecode.c;
+                       isEditable = 1;
+                       isa = PBXBuildRule;
+                       outputFiles = (
+                       );
+               };
+               F9E8D4BE07FCAF2A00FD5801 = {
+                       compilerSpec = com.apple.compilers.gcc.4_0;
+                       fileType = sourcecode.cpp;
+                       isEditable = 1;
+                       isa = PBXBuildRule;
+                       outputFiles = (
+                       );
+               };
        };
        rootObject = F9023C3006D5A227001BBF46;
 }
index 211a1891484aa956adaa146a7b8775c69b9ea18a..fe4b01ec444d89c34e7f07161f5cac949c02dc43 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
@@ -1041,22 +1042,46 @@ void macho_routines_command::set_cmdsize(uint32_t _value) {
 
 inline  __attribute__((always_inline))
 uint64_t macho_routines_command::init_address() const {
+#if defined(ARCH_PPC64)
        return ENDIAN_SWAP64(content.init_address);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       return ENDIAN_READ32(content.init_address);
+#else
+       #error unknown architecture
+#endif
 }
 
 inline  __attribute__((always_inline))
 void macho_routines_command::set_init_address(uint64_t _value) {
+#if defined(ARCH_PPC64)
        content.init_address = ENDIAN_SWAP64(_value);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       ENDIAN_WRITE32(content.init_address, _value);
+#else
+       #error unknown architecture
+#endif
 }
 
 inline  __attribute__((always_inline))
 uint64_t macho_routines_command::init_module() const {
+#if defined(ARCH_PPC64)
        return ENDIAN_SWAP64(content.init_module);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       return ENDIAN_READ32(content.init_module);
+#else
+       #error unknown architecture
+#endif
 }
 
 inline  __attribute__((always_inline))
 void macho_routines_command::set_init_module(uint64_t _value) {
+#if defined(ARCH_PPC64)
        content.init_module = ENDIAN_SWAP64(_value);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       ENDIAN_WRITE32(content.init_module, _value);
+#else
+       #error unknown architecture
+#endif
 }
 
 
@@ -1670,7 +1695,13 @@ uint64_t macho_nlist::n_value() const {
 
 inline  __attribute__((always_inline))
 void macho_nlist::set_n_value(uint64_t _value) {
+#if defined(ARCH_PPC64)
        content.n_value = ENDIAN_SWAP64(_value);
+#elif defined(ARCH_PPC) || defined(ARCH_I386)
+       ENDIAN_WRITE32(content.n_value, _value);
+#else
+       #error unknown architecture
+#endif
 }
 
 
@@ -1766,7 +1797,7 @@ void macho_relocation_info::set_r_pcrel(bool _value) {
        if ( _value )
                temp |= 0x00000080;
 #elif defined(ARCH_I386)
-       temp &= 0x7FFFFFFF;
+       temp &= 0xFEFFFFFF;
        if ( _value )
                temp |= 0x01000000;
 #else
@@ -1822,7 +1853,7 @@ void macho_relocation_info::set_r_extern(bool _value) {
        if ( _value )
                temp |= 0x00000010;
 #elif defined(ARCH_I386)
-       temp &= 0xEFFFFFFF;
+       temp &= 0xF7FFFFFF;
        if ( _value )
                temp |= 0x08000000;
 #else
index 5a80c26f352e7ea5da3a602eacd2bbca84a61cc8..255c028a7738005d52161056c79214a90655826f 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
@@ -81,6 +82,7 @@ public:
        
 protected:
                                                                                Reader() {}
+       virtual                                                         ~Reader() {}
 };
 
 class Segment
@@ -93,9 +95,11 @@ public:
        
        uint64_t                                        getBaseAddress() const { return fBaseAddress; }
        void                                            setBaseAddress(uint64_t addr) { fBaseAddress = addr; }
+       virtual bool                            hasFixedAddress() const { return false; }
 
 protected:
-               Segment() : fBaseAddress(0) {}
+                                                               Segment() : fBaseAddress(0) {}
+       virtual                                         ~Segment() {}
        uint64_t                                        fBaseAddress;
 };
 
@@ -120,6 +124,9 @@ class ContentWriter
 {
 public:
        virtual void    write(uint64_t atomOffset, const void* buffer, uint64_t size) = 0;
+protected:
+                                                               ContentWriter() {}
+       virtual                                         ~ContentWriter() {}
 };
 
 class Atom 
@@ -168,7 +175,8 @@ public:
                        unsigned int                                    setSortOrder(unsigned int order); // recursively sets follow-on atoms
 
 protected:
-               Atom() : fSegmentOffset(0), fSectionOffset(0), fSortOrder(0), fSection(NULL) {}
+                                                                                       Atom() : fSegmentOffset(0), fSectionOffset(0), fSortOrder(0), fSection(NULL) {}
+               virtual                                                         ~Atom() {}
                
                uint64_t                                                        fSegmentOffset;
                uint64_t                                                        fSectionOffset;
@@ -201,22 +209,28 @@ public:
                                ppcFixupAbsLow16, ppcFixupAbsLow14, ppcFixupAbsHigh16, ppcFixupAbsHigh16AddLow,
                                pointer32Difference, pointer64Difference, x86FixupBranch32 };
 
-       virtual bool                    isUnbound() const = 0;
+       virtual bool                    isTargetUnbound() const = 0;
+       virtual bool                    isFromTargetUnbound() const = 0;
+       virtual bool                    requiresRuntimeFixUp(bool slideable) const = 0;
        virtual bool                    isWeakReference() const = 0;
-       virtual bool                    requiresRuntimeFixUp() const = 0;
        virtual bool                    isLazyReference() const = 0;
        virtual Kind                    getKind() const = 0;
        virtual uint64_t                getFixUpOffset() const = 0;
        virtual const char*             getTargetName() const = 0;
        virtual Atom&                   getTarget() const = 0;
        virtual uint64_t                getTargetOffset() const = 0;
+       virtual bool                    hasFromTarget() const = 0;
        virtual Atom&                   getFromTarget() const = 0;
        virtual const char*             getFromTargetName() const = 0;
        virtual uint64_t                getFromTargetOffset() const = 0;
 
-       virtual void                    setTarget(Atom&) = 0;
+       virtual void                    setTarget(Atom&, uint64_t offset) = 0;
        virtual void                    setFromTarget(Atom&) = 0;
        virtual const char*             getDescription() const = 0;
+       
+protected:
+                                                       Reference() {}
+       virtual                                 ~Reference() {}
 };
 
 
index 6b913af5bb09980cac67b8dd7bfc58204bcbe907..6984e67ad27628635de0f0c3a3f0ce564e991cde 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
@@ -25,6 +26,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <vector>
 
 
 #include "Options.h"
@@ -52,7 +54,7 @@ Options::Options(int argc, const char* argv[])
        fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(false), fPICTreatment(kPICError),
        fWeakReferenceMismatchTreatment(kWeakReferenceMismatchError), 
        fUmbrellaName(NULL), fInitFunctionName(NULL), fZeroPageSize(0x1000), fStackSize(0), fStackAddr(0), fMinimumHeaderPad(0),
-       fCommonsMode(kCommonsIgnoreDylibs), fWarnCommons(false)
+       fCommonsMode(kCommonsIgnoreDylibs), fWarnCommons(false), fVerbose(false)
 {
        this->parsePreCommandLineEnvironmentSettings();
        this->parse(argc, argv);
@@ -251,7 +253,6 @@ bool Options::warnCommons()
        return fWarnCommons;
 }
 
-
 bool Options::shouldExport(const char* symbolName)
 {
        switch (fExportMode) {
@@ -364,21 +365,40 @@ Options::FileInfo Options::findFramework(const char* rootName)
        throwf("framework not found %s", rootName);
 }
 
-
-Options::FileInfo Options::makeFileInfo(const char* path)
+Options::FileInfo Options::findFile(const char* path)
 {
+       FileInfo result;
        struct stat statBuffer;
+       
+       // if absolute path and not a .o file, the use SDK prefix
+       if ( (path[0] == '/') && (strcmp(&path[strlen(path)-2], ".o") != 0) ) {
+               const int pathLen = strlen(path);
+               for (std::vector<const char*>::iterator it = fSDKPaths.begin(); it != fSDKPaths.end(); it++) {
+                       const char* sdkPathDir = *it;
+                       const int sdkPathDirLen = strlen(sdkPathDir);
+                       char possiblePath[sdkPathDirLen+pathLen+4];
+                       strcpy(possiblePath, sdkPathDir);
+                       if ( possiblePath[sdkPathDirLen-1] == '/' )
+                               possiblePath[sdkPathDirLen-1] = '\0';
+                       strcat(possiblePath, path);
+                       if ( stat(possiblePath, &statBuffer) == 0 ) {
+                               result.path = strdup(possiblePath);
+                               result.fileLen = statBuffer.st_size;
+                               return result;
+                       }
+               }
+       }
+       // try raw path
        if ( stat(path, &statBuffer) == 0 ) {
-               FileInfo result;
                result.path = strdup(path);
                result.fileLen = statBuffer.st_size;
                return result;
        }
-       else {
-               throwf("file not found: %s", path);
-       }
+       // not found
+       throwf("file not found: %s", path);
 }
 
+
 void Options::loadFileList(const char* fileOfPaths)
 {
        FILE* file = fopen(fileOfPaths, "r");
@@ -392,7 +412,7 @@ void Options::loadFileList(const char* fileOfPaths)
                if ( eol != NULL )
                        *eol = '\0';
                        
-               fInputFiles.push_back(makeFileInfo(path));
+               fInputFiles.push_back(findFile(path));
        }
        fclose(file);
 }
@@ -641,7 +661,7 @@ void Options::parse(int argc, const char* argv[])
                
                if ( arg[0] == '-' ) {
                        if ( (arg[1] == 'L') || (arg[1] == 'F') ) {
-                               // previously handled
+                               // previously handled by buildSearchPaths()
                        }
                        else if ( strcmp(arg, "-arch") == 0 ) {
                                parseArch(argv[++i]);
@@ -755,7 +775,7 @@ void Options::parse(int argc, const char* argv[])
                                 fForceSubtypeAll = true;
                        }
                        else if ( strcmp(arg, "-weak_library") == 0 ) {
-                               FileInfo info = makeFileInfo(argv[++i]);
+                               FileInfo info = findFile(argv[++i]);
                                info.options.fWeakImport = true;
                                fInputFiles.push_back(info);
                        }
@@ -930,13 +950,6 @@ void Options::parse(int argc, const char* argv[])
                                 // FIX FIX
                                 fprintf(stderr, "ld64: warning -dead_strip not yet supported for 64-bit code\n");
                        }
-                       else if ( strcmp(arg, "-v") == 0 ) {
-                               extern const char ld64VersionString[];
-                               fprintf(stderr, "%s", ld64VersionString);
-                                // if only -v specified, exit cleanly
-                                if ( argc == 2 )
-                                       exit(0);
-                       }
                        else if ( strcmp(arg, "-w") == 0 ) {
                                // FIX FIX
                        }
@@ -1003,36 +1016,141 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-commons") == 0 ) {
                                fCommonsMode = parseCommonsTreatment(argv[++i]);
                        }
-                       
+                       else if ( strcmp(arg, "-v") == 0 ) {
+                               // previously handled by buildSearchPaths()
+                       }
+                       else if ( strcmp(arg, "-Z") == 0 ) {
+                               // previously handled by buildSearchPaths()
+                       }
+                       else if ( strcmp(arg, "-syslibroot") == 0 ) {
+                               ++i;
+                               // previously handled by buildSearchPaths()
+                       }
                        else {
                                fprintf(stderr, "unknown option: %s\n", arg);
                        }
                }
                else {
-                       fInputFiles.push_back(makeFileInfo(arg));
+                       fInputFiles.push_back(findFile(arg));
                }
        }
 }
 
+
+
+// 
+// -syslibroot <path> is used for SDK support.  
+// The rule is that all search paths (both explicit and default) are
+// checked to see if they exist in the SDK.  If so, that path is
+// replaced with the sdk prefixed path.  If not, that search path
+// is used as is.  If multiple -syslibroot options are specified
+// their directory structures are logically overlayed and files
+// from sdks specified earlier on the command line used before later ones.
+// 
 void Options::buildSearchPaths(int argc, const char* argv[])
 {
        bool addStandardLibraryDirectories = true;
-       // scan through argv looking for -L and -F options
+       std::vector<const char*> libraryPaths;
+       std::vector<const char*> frameworkPaths;
+       // 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') )
-                       fLibrarySearchPaths.push_back(&argv[i][2]);
+                       libraryPaths.push_back(&argv[i][2]);
                else if ( (argv[i][0] == '-') && (argv[i][1] == 'F') )
-                       fFrameworkSearchPaths.push_back(&argv[i][2]);
+                       frameworkPaths.push_back(&argv[i][2]);
                else if ( strcmp(argv[i], "-Z") == 0 )
                        addStandardLibraryDirectories = false;
+               else if ( strcmp(argv[i], "-v") == 0 ) {
+                       fVerbose = true;
+                       extern const char ld64VersionString[];
+                       fprintf(stderr, "%s", ld64VersionString);
+                        // if only -v specified, exit cleanly
+                        if ( argc == 2 )
+                               exit(0);
+               }
+               else if ( strcmp(argv[i], "-syslibroot") == 0 ) {
+                       const char* path = argv[++i];
+                       if ( path == NULL )
+                               throw "-syslibroot missing argument";
+                       fSDKPaths.push_back(path);
+               }
        }
        if ( addStandardLibraryDirectories ) {
-               fLibrarySearchPaths.push_back("/usr/lib");
-               fLibrarySearchPaths.push_back("/usr/local/lib");
+               libraryPaths.push_back("/usr/lib");
+               libraryPaths.push_back("/usr/local/lib");
                
-               fFrameworkSearchPaths.push_back("/Library/Frameworks/");
-               fFrameworkSearchPaths.push_back("/Network/Library/Frameworks/");
-               fFrameworkSearchPaths.push_back("/System/Library/Frameworks/");
+               frameworkPaths.push_back("/Library/Frameworks/");
+               frameworkPaths.push_back("/Network/Library/Frameworks/");
+               frameworkPaths.push_back("/System/Library/Frameworks/");
+       }
+       
+       // now merge sdk and library paths to make real search paths
+       for (std::vector<const char*>::iterator it = libraryPaths.begin(); it != libraryPaths.end(); it++) {
+               const char* libDir = *it;
+               bool sdkOverride = false;
+               if ( libDir[0] == '/' ) {
+                       char betterLibDir[PATH_MAX];
+                       if ( strstr(libDir, "/..") != NULL ) {
+                               if ( realpath(libDir, betterLibDir) != NULL )
+                                       libDir = betterLibDir;
+                       }
+                       const int libDirLen = strlen(libDir);
+                       for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) {
+                               const char* sdkDir = *sdkit;
+                               const int sdkDirLen = strlen(sdkDir);
+                               char newPath[libDirLen + sdkDirLen+4];
+                               strcpy(newPath, sdkDir);
+                               if ( newPath[sdkDirLen-1] == '/' )
+                                       newPath[sdkDirLen-1] = '\0';
+                               strcat(newPath, libDir);
+                               struct stat statBuffer;
+                               if ( stat(newPath, &statBuffer) == 0 ) {
+                                       fLibrarySearchPaths.push_back(strdup(newPath));
+                                       sdkOverride = true;
+                               }
+                       }
+               }
+               if ( !sdkOverride ) 
+                       fLibrarySearchPaths.push_back(libDir);
+       }
+       
+       // now merge sdk and framework paths to make real search paths
+       for (std::vector<const char*>::iterator it = frameworkPaths.begin(); it != frameworkPaths.end(); it++) {
+               const char* frameworkDir = *it;
+               bool sdkOverride = false;
+               if ( frameworkDir[0] == '/' ) {
+                       char betterFrameworkDir[PATH_MAX];
+                       if ( strstr(frameworkDir, "/..") != NULL ) {
+                               if ( realpath(frameworkDir, betterFrameworkDir) != NULL )
+                                       frameworkDir = betterFrameworkDir;
+                       }
+                       const int frameworkDirLen = strlen(frameworkDir);
+                       for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) {
+                               const char* sdkDir = *sdkit;
+                               const int sdkDirLen = strlen(sdkDir);
+                               char newPath[frameworkDirLen + sdkDirLen+4];
+                               strcpy(newPath, sdkDir);
+                               if ( newPath[sdkDirLen-1] == '/' )
+                                       newPath[sdkDirLen-1] = '\0';
+                               strcat(newPath, frameworkDir);
+                               struct stat statBuffer;
+                               if ( stat(newPath, &statBuffer) == 0 ) {
+                                       fFrameworkSearchPaths.push_back(strdup(newPath));
+                                       sdkOverride = true;
+                               }
+                       }
+               }
+               if ( !sdkOverride ) 
+                       fFrameworkSearchPaths.push_back(frameworkDir);
+       }
+       
+       if ( fVerbose ) {
+               fprintf(stderr,"Library search paths:\n");
+               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++)
+                       fprintf(stderr,"\t%s\n", *it);
+               fprintf(stderr,"Framework search paths:\n");
+               for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin(); it != fFrameworkSearchPaths.end(); it++)
+                       fprintf(stderr,"\t%s\n", *it);
        }
 }
 
@@ -1169,6 +1287,11 @@ void Options::checkIllegalOptionCombinations()
        // check -init is only used when building a dylib
        if ( (fInitFunctionName != NULL) && (fOutputKind != Options::kDynamicLibrary) )
                throw "-init can only be used with -dynamiclib";
+               
+       // make sure all required exported symbols exist
+       for (NameSet::iterator it=fExportSymbols.begin(); it != fExportSymbols.end(); it++)
+               fInitialUndefines.push_back(*it);
+               
 }
 
 
index 33d1137fef5a92c29dfeedbfaf4716e669017692..520b30428d2d6e0b66373a8972c689f2ff93fb3a 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
@@ -125,6 +126,7 @@ public:
        std::vector<SectionAlignment>&  sectionAlignments();
        CommonsMode                                     commonsMode();
        bool                                            warnCommons();
+       FileInfo                                        findFile(const char* path);
 
 private:
        class CStringEquals
@@ -143,7 +145,6 @@ private:
        void                                            parseArch(const char* architecture);
        FileInfo                                        findLibrary(const char* rootName);
        FileInfo                                        findFramework(const char* rootName);
-       FileInfo                                        makeFileInfo(const char* path);
        bool                                            checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result);
        uint32_t                                        parseVersionNumber(const char*);
        void                                            parseSectionOrderFile(const char* segment, const char* section, const char* path);
@@ -200,12 +201,14 @@ private:
        uint32_t                                                        fMinimumHeaderPad;
        CommonsMode                                                     fCommonsMode;
        bool                                                            fWarnCommons;
+       bool                                                            fVerbose;
        std::vector<const char*>                        fInitialUndefines;
        std::vector<ExtraSection>                       fExtraSections;
        std::vector<SectionAlignment>           fSectionAlignments;
        
        std::vector<const char*>                        fLibrarySearchPaths;
        std::vector<const char*>                        fFrameworkSearchPaths;
+       std::vector<const char*>                        fSDKPaths;
 
 };
 
index a6851a1d3e537a5ee83647d926c7fd3b6084670c..b01d8a0a170a07947bdd22311b5166e0190be567 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
@@ -71,6 +72,14 @@ private:
 
 std::vector<class ObjectFile::Atom*>           Reader::fgEmptyList;
 
+#undef SwapArchToHostInt32
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+       #define SwapArchToHostInt32(value) OSSwapBigToHostInt32(value)
+#elif defined(ARCH_I386)
+       #define SwapArchToHostInt32(value) OSSwapLittleToHostInt32(value)
+#endif
+
+
 
 bool Reader::Entry::hasLongName() const
 {
@@ -130,7 +139,7 @@ uint32_t Reader::Entry::getContentSize() const
 const Reader::Entry*   Reader::Entry::getNext() const
 {
        const uint8_t* p = this->getContent() + getContentSize();
-       p = (const uint8_t*)(((uint32_t)p+3) & (-4));  // 4-byte align
+       p = (const uint8_t*)(((uintptr_t)p+3) & (-4));  // 4-byte align
        return (Reader::Entry*)p;
 }
 
@@ -156,7 +165,7 @@ Reader::Reader(const uint8_t fileContent[], uint64_t fileLength, const char* pat
                else
                        throw "archive has no table of contents";
                const uint8_t* contents = firstMember->getContent();
-               uint32_t ranlibArrayLen = OSReadBigInt32((void *) contents, 0);
+               uint32_t ranlibArrayLen = SwapArchToHostInt32(*((uint32_t*)contents));
                fTableOfContents = (const struct ranlib*)&contents[4];
                fTableOfContentCount = ranlibArrayLen / sizeof(struct ranlib);
                fStringPool = (const char*)&contents[ranlibArrayLen+8];
@@ -222,7 +231,7 @@ const struct ranlib* Reader::ranlibBinarySearch(const char* key)
        const struct ranlib* base = fTableOfContents;
        for (uint32_t n = fTableOfContentCount; n > 0; n /= 2) {
                const struct ranlib* pivot = &base[n/2];
-               const char* pivotStr = &fStringPool[OSSwapBigToHostInt32(pivot->ran_un.ran_strx)];
+               const char* pivotStr = &fStringPool[SwapArchToHostInt32(pivot->ran_un.ran_strx)];
                int cmp = strcmp(key, pivotStr);
                if ( cmp == 0 )
                        return pivot;
@@ -244,7 +253,7 @@ const struct ranlib* Reader::ranlibLinearSearch(const char* key)
 {
        for (uint32_t i = 0; i < fTableOfContentCount; ++i) {
                const struct ranlib* entry = &fTableOfContents[i];
-               const char* entryName = &fStringPool[OSSwapBigToHostInt32(entry->ran_un.ran_strx)];
+               const char* entryName = &fStringPool[SwapArchToHostInt32(entry->ran_un.ran_strx)];
                if ( strcmp(key, entryName) == 0 )
                        return entry;
        }
@@ -256,7 +265,7 @@ void Reader::dumpTableOfContents()
 {
        for (unsigned int i=0; i < fTableOfContentCount; ++i) {
                const struct ranlib* e = &fTableOfContents[i];
-               printf("%s in %s\n", &fStringPool[OSSwapBigToHostInt32(e->ran_un.ran_strx)], ((Entry*)&fFileContent[OSSwapBigToHostInt32(e->ran_off)])->getName());
+               printf("%s in %s\n", &fStringPool[SwapArchToHostInt32(e->ran_un.ran_strx)], ((Entry*)&fFileContent[SwapArchToHostInt32(e->ran_off)])->getName());
        }
 }
 
@@ -268,20 +277,20 @@ std::vector<class ObjectFile::Atom*>* Reader::getJustInTimeAtomsFor(const char*
        else {
                const struct ranlib* result = NULL;
                if ( fSorted ) {
-                       // do a binary search of table of contents lookig for requested symbol
+                       // do a binary search of table of contents looking for requested symbol
                        result = ranlibBinarySearch(name);
                }
                else {
-                       // do a linear search of table of contents lookig for requested symbol
+                       // do a linear search of table of contents looking for requested symbol
                        result = ranlibLinearSearch(name);
                }
                if ( result != NULL ) {
-                       const Entry* member = (Entry*)&fFileContent[OSSwapBigToHostInt32(result->ran_off)];
-                       //fprintf(stderr, "%s found in %s\n", name, member->getName());
+                       const Entry* member = (Entry*)&fFileContent[SwapArchToHostInt32(result->ran_off)];
                        if ( fInstantiatedEntries.count(member) == 0 ) {
                                // only return these atoms once
                                fInstantiatedEntries.insert(member);
                                ObjectFile::Reader* r = makeObjectReaderForMember(member);
+                               //fprintf(stderr, "%s found in %s\n", name, member->getName());
                                return new std::vector<class ObjectFile::Atom*>(r->getAtoms());
                        }
                }
index cadbef3bca400ac4560c4e78c8ffebc113f2edaa..fad4dcb845e85bce3e96d6974a6cdbad622c464e 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
index 5736d00552955ed05a3ecc66bf5557f3bd82ce68..154ff8b7f72264c5d44a0bcba574efdbafecb45b 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
@@ -20,7 +21,6 @@
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- */
 
 
 namespace ObjectFileMachO {
@@ -34,20 +34,23 @@ public:
        virtual                                 ~Reference();
        
        
-       virtual bool                    isUnbound() const;
+       virtual bool                    isTargetUnbound() const;
+       virtual bool                    isFromTargetUnbound() const;
        virtual bool                    isWeakReference() const;
-       virtual bool                    requiresRuntimeFixUp() const;
+       virtual bool                    requiresRuntimeFixUp(bool slideable) const;
        virtual bool                    isLazyReference() const;
        virtual Kind                    getKind() const;
        virtual uint64_t                getFixUpOffset() const;
        virtual const char*             getTargetName() const;
        virtual ObjectFile::Atom& getTarget() const;
        virtual uint64_t                getTargetOffset() const;
+       virtual bool                    hasFromTarget() const;
        virtual ObjectFile::Atom& getFromTarget() const;
        virtual const char*             getFromTargetName() const;
-       virtual void                    setTarget(ObjectFile::Atom&);
+       virtual void                    setTarget(ObjectFile::Atom&, uint64_t offset);
        virtual void                    setFromTarget(ObjectFile::Atom&);
        virtual void                    setFromTargetName(const char*);
+       virtual void                    setFromTargetOffset(uint64_t);
        virtual const char*             getDescription() const;
        virtual uint64_t                getFromTargetOffset() const;
        
@@ -165,7 +168,7 @@ protected:
                                                                                        Atom(Reader&, uint32_t offset);
        virtual                                                                 ~Atom();
        
-       const macho_section*                                    findSectionFromOffset(macho_uintptr_t offset);
+       const macho_section*                                    findSectionFromOffset(uint32_t offset);
        const macho_section*                                    getCommonsSection();
        void                                                                    setSize(macho_uintptr_t);
        void                                                                    setFollowOnAtom(Atom&);
@@ -205,7 +208,7 @@ Reader::Reader(const macho_header* header, const char* path, const ObjectFile::R
 
 Reader::Reader(const char* path)
  : fPath(NULL), fOptions(*(new ObjectFile::ReaderOptions())), fHeader(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL),
-       fNonAtomStabsStartIndex(0), fNonAtomStabsCount(0)
+       fIndirectTable(NULL), fNonAtomStabsStartIndex(0), fNonAtomStabsCount(0)
 {
        struct stat stat_buf;
        
@@ -340,7 +343,7 @@ void Reader::init(const macho_header* header, const char* path)
        
        for (std::set<uint32_t>::iterator it=cleavePoints.begin(); it != cleavePoints.end(); it++) {
                uint32_t cleavePoint = *it;
-               //printf("cleave offset 0x%08X\n", cleavePoint);
+               //printf("cleave offset 0x%08X, don't cleave=%d, isSymbol=%d\n", cleavePoint, dontCleavePoints.count(cleavePoint), symbolAtomOffsets.count(cleavePoint));
                // only create an atom if it is not a don't-cleave point and there is not already an atom at this offset
                if ( (dontCleavePoints.count(cleavePoint) == 0) && (symbolAtomOffsets.count(cleavePoint) == 0) )
                        fAtoms.push_back(new Atom(*this, cleavePoint));
@@ -394,6 +397,7 @@ void Reader::init(const macho_header* header, const char* path)
                                }
                        }
                }
+
        }
 
        // process stabs debugging info
@@ -688,27 +692,75 @@ void Reader::addRelocReference(const macho_section* sect, const macho_relocation
                                {
                                        srcAddr = sect->addr() + reloc->r_address();
                                        Atom* srcAtom = findAtomCoveringOffset(srcAddr);
-                                       // lazy pointers have references to dyld_stub_binding_helper which need to be ignored
-                                       if ( (srcAtom->fSection->flags() & SECTION_TYPE) != S_LAZY_SYMBOL_POINTERS ) {
-                                               uint32_t offsetInSrcAtom = srcAddr - srcAtom->fOffset;
-                                               macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
-                                               if ( reloc->r_extern() ) {
-                                                       const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
-                                                       uint8_t type = targetSymbol->n_type() & N_TYPE;
-                                                       if ( type == N_UNDF ) {
-                                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
-                                                               macho_uintptr_t addend = pointerValue;
+                                       uint32_t offsetInSrcAtom = srcAddr - srcAtom->fOffset;
+                                       macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
+                                       if ( reloc->r_extern() ) {
+                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
+                                               uint8_t type = targetSymbol->n_type() & N_TYPE;
+                                               if ( type == N_UNDF ) {
+                                                       const char* targetName = &fStrings[targetSymbol->n_strx()];
+                                                       macho_uintptr_t addend = pointerValue;
+                                                       // ppc lazy pointers have initial reference to dyld_stub_binding_helper
+                                                       if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
+                                                               std::vector<ObjectFile::Reference*>&  refs = srcAtom->getReferences();
+                                                               if ( refs.size() > 0 ) {
+                                                                       Reference* ref = (Reference*)refs[0];
+               #if defined(ARCH_PPC64)
+                                                                        // hack to work around bad crt1.o in Mac OS X 10.4
+                                                                       targetName = "dyld_stub_binding_helper";
+               #endif
+                                                                       ref->setFromTargetName(targetName);
+                                                               }
+                                                               else {
+                                                                       fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size());
+                                                               }
+                                                       } 
+               #if defined(ARCH_PPC64)
+                                                       // hack to work around bad crt1.o in Mac OS X 10.4
+                                                       else if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) {
+                                                               // ignore extra relocation
+                                                       }
+               #endif
+                                                       else {
                                                                srcAtom->addByNameReference(offsetInSrcAtom, Reference::pointer, targetName, addend, 0);
                                                        }
+                                               }
+                                               else {
+                                                       dstAddr = targetSymbol->n_value();
+                                                       Atom* dstAtom = findAtomCoveringOffset(dstAddr);
+                                                       macho_uintptr_t addend = pointerValue;
+                                                       // ppc lazy pointers have initial reference to dyld_stub_binding_helper
+                                                       if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
+                                                               std::vector<ObjectFile::Reference*>&  refs = srcAtom->getReferences();
+                                                               if ( refs.size() > 0 ) {
+                                                                       Reference* ref = (Reference*)refs[0];
+                                                                       ref->setFromTarget(*dstAtom);
+                                                                       ref->setFromTargetOffset(dstAddr - dstAtom->fOffset);
+                                                               }
+                                                               else {
+                                                                       fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size());
+                                                               }
+                                                       } 
                                                        else {
-                                                               dstAddr = targetSymbol->n_value();
-                                                               Atom* dstAtom = findAtomCoveringOffset(dstAddr);
-                                                               macho_uintptr_t addend = pointerValue;
                                                                srcAtom->addReference(offsetInSrcAtom, Reference::pointer, *dstAtom, addend, 0);
                                                        }
                                                }
+                                       }
+                                       else {
+                                               Atom* dstAtom = findAtomCoveringOffset(pointerValue);
+                                               // lazy pointers have references to dyld_stub_binding_helper which need to be ignored
+                                               if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
+                                                       std::vector<ObjectFile::Reference*>&  refs = srcAtom->getReferences();
+                                                       if ( refs.size() > 0 ) {
+                                                               Reference* ref = (Reference*)refs[0];
+                                                               ref->setFromTarget(*dstAtom);
+                                                               ref->setFromTargetOffset(pointerValue - dstAtom->fOffset);
+                                                       }
+                                                       else {
+                                                               fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size());
+                                                       }
+                                               }
                                                else {
-                                                       Atom* dstAtom = findAtomCoveringOffset(pointerValue);   
                                                        srcAtom->addReference(offsetInSrcAtom, Reference::pointer, *dstAtom, pointerValue-dstAtom->fOffset, 0);
                                                }
                                        }
@@ -723,39 +775,51 @@ void Reader::addRelocReference(const macho_section* sect, const macho_relocation
                                {
                                        srcAddr = sect->addr() + reloc->r_address();
                                        src = findAtomCoveringOffset(srcAddr);
-                                       // lazy pointers have references to dyld_stub_binding_helper which need to be ignored
-                                       if ( (src->fSection->flags() & SECTION_TYPE) != S_LAZY_SYMBOL_POINTERS ) {
-                                               if ( reloc->r_length() != 2 )
-                                                       throw "bad vanilla relocation length";
-                                               Reference::Kind kind;
-                                               macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
-                                               if ( reloc->r_pcrel() ) {
-                                                       kind = Reference::x86FixupBranch32;
-                                                       pointerValue += reloc->r_address() + sizeof(macho_uintptr_t);
+                                       if ( reloc->r_length() != 2 )
+                                               throw "bad vanilla relocation length";
+                                       Reference::Kind kind;
+                                       macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
+                                       if ( reloc->r_pcrel() ) {
+                                               kind = Reference::x86FixupBranch32;
+                                               pointerValue += srcAddr + sizeof(macho_uintptr_t);
+                                       }
+                                       else {
+                                               kind = Reference::pointer;
+                                       }
+                                       uint32_t offsetInSrcAtom = srcAddr - src->fOffset;
+                                       if ( reloc->r_extern() ) {
+                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
+                                               uint8_t type = targetSymbol->n_type() & N_TYPE;
+                                               if ( type == N_UNDF ) {
+                                                       const char* targetName = &fStrings[targetSymbol->n_strx()];
+                                                       macho_uintptr_t addend = pointerValue;
+                                                       src->addByNameReference(offsetInSrcAtom, kind, targetName, addend, 0);
                                                }
                                                else {
-                                                       kind = Reference::pointer;
+                                                       dstAddr = targetSymbol->n_value();
+                                                       dst = findAtomCoveringOffset(dstAddr);
+                                                       macho_uintptr_t addend = pointerValue - dstAddr;
+                                                       src->addReference(offsetInSrcAtom, kind, *dst, addend, 0);
                                                }
-                                               uint32_t offsetInSrcAtom = srcAddr - src->fOffset;
-                                               if ( reloc->r_extern() ) {
-                                                       const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
-                                                       uint8_t type = targetSymbol->n_type() & N_TYPE;
-                                                       if ( type == N_UNDF ) {
-                                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
-                                                               macho_uintptr_t addend = pointerValue;
-                                                               src->addByNameReference(offsetInSrcAtom, kind, targetName, addend, 0);
+                                       }
+                                       else {
+                                               dst = findAtomCoveringOffset(pointerValue);     
+                                               // lazy pointers have references to dyld_stub_binding_helper which need to be ignored
+                                               if ( (src->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
+                                                       std::vector<ObjectFile::Reference*>&  refs = src->getReferences();
+                                                       if ( refs.size() == 1 ) {
+                                                               Reference* ref = (Reference*)refs[0];
+                                                               ref->setFromTarget(*dst);
+                                                               ref->setFromTargetOffset(pointerValue - dst->fOffset);
                                                        }
                                                        else {
-                                                               dstAddr = targetSymbol->n_value();
-                                                               dst = findAtomCoveringOffset(dstAddr);
-                                                               macho_uintptr_t addend = pointerValue - dstAddr;
-                                                               src->addReference(offsetInSrcAtom, kind, *dst, addend, 0);
+                                                               fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", src->getDisplayName(), refs.size());
                                                        }
                                                }
-                                               else {
-                                                       dst = findAtomCoveringOffset(pointerValue);     
+                                               else if ( ((uint8_t*)fixUpPtr)[-1] == 0xE8 )  // special case call instruction
+                                                       this->addCallSiteReference(*src, offsetInSrcAtom, kind, *dst, 0, pointerValue - dst->fOffset);
+                                               else
                                                        src->addReference(offsetInSrcAtom, kind, *dst, 0, 0);
-                                               }
                                        }
                                }
                                break;
@@ -1005,6 +1069,10 @@ Atom* Reader::findAtomCoveringOffset(uint32_t offset)
                        // keep same base
                }
        }
+       // possible that last atom is zero length
+       Atom* lastAtom = fAtoms.back();
+       if ( (lastAtom->fOffset == offset) && (lastAtom->fSize == 0) )
+               return lastAtom;
 #else
        const uint32_t atomCount = fAtoms.size();
        for (uint32_t i=0; i < atomCount; ++i) {
@@ -1013,7 +1081,7 @@ Atom* Reader::findAtomCoveringOffset(uint32_t offset)
                        return atom;
        }
 #endif
-       return NULL;
+       throwf("address 0x%08X is not in any atom", offset);
 }
 
 uint32_t Reader::findAtomIndex(const Atom& atom)
@@ -1169,11 +1237,16 @@ void Reader::buildOffsetsSet(const macho_relocation_info* reloc, const macho_sec
                                        if  ( reloc->r_length() != 2 )
                                                throw "vanilla pointer relocation found that is not 4-bytes";
 #endif
-                                       //fprintf(stderr, "pcrel=%d, len=%d, extern=%d, type=%d\n", reloc->r_pcrel(), reloc->r_length(), reloc->r_extern(), reloc->r_type());
+                                       //fprintf(stderr, "addr=0x%08X, pcrel=%d, len=%d, extern=%d, type=%d\n", reloc->r_address(), reloc->r_pcrel(), reloc->r_length(), reloc->r_extern(), reloc->r_type());
                                        if ( !reloc->r_extern() ) {
                                                macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
+#if defined(ARCH_I386)
+                                       // i386 stubs have internal relocs that should not cause a cleave
+                                       if ( (sect->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS )
+                                               break;
+#endif
                                                if ( reloc->r_pcrel() )
-                                                       pointerValue += reloc->r_address() + sizeof(macho_uintptr_t);
+                                                       pointerValue += reloc->r_address() + sect->addr() + sizeof(macho_uintptr_t);
                                                // a pointer into code does not cleave the code (gcc always pointers to labels)
                                                insertOffsetIfNotText(cleavePoints, pointerValue);
                                        }
@@ -1407,7 +1480,6 @@ Atom::Atom(Reader& owner, const macho_nlist* symbol)
                                        Reference* ref = this->addByNameReference(0, Reference::pointer, name, 0, 0);
                                        if ( type == S_LAZY_SYMBOL_POINTERS ) {
                                                ref->setLazy(true);
-                                               ref->setFromTargetName("dyld_stub_binding_helper");
                                        }
                                }
                                break;
@@ -1465,7 +1537,6 @@ Atom::Atom(Reader& owner, uint32_t offset)
                                Reference* ref = this->addByNameReference(0, Reference::pointer, name, 0, 0);
                                if ( type == S_LAZY_SYMBOL_POINTERS ) {
                                        ref->setLazy(true);
-                                       ref->setFromTargetName("dyld_stub_binding_helper");
                                }
                                const macho_nlist* sym = &fOwner.fSymbols[symbolIndex];
                                if ( (sym->n_type() & N_TYPE) == N_UNDF ) {
@@ -1770,15 +1841,13 @@ void Atom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer
                        case Reference::pointer:
                                {
                                        //fprintf(stderr, "writeContent: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
-                                       if ( target.isImportProxy() ) {
-                                               if ( ref->isLazyReference() && finalLinkedImage ) {
-                                                       // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
-                                                       *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getFromTarget().getAddress());
-                                               }
-                                               else {
-                                                       // external realocation ==> pointer contains addend
-                                                       *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getTargetOffset());
-                                               }
+                                       if ( ref->isLazyReference() && finalLinkedImage ) {
+                                               // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
+                                               *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getFromTarget().getAddress());
+                                       }
+                                       else if ( target.isImportProxy() ) {
+                                               // external realocation ==> pointer contains addend
+                                               *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getTargetOffset());
                                        }
                                        else {
                                                // internal relocation
@@ -1806,8 +1875,8 @@ void Atom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer
                                        else {
                                                const int64_t bl_eightMegLimit = 0x00FFFFFF;
                                                if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
-                                                       //fprintf(stderr, "bl out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
-                                                       throw "bl out of range";
+                                                       //fprintf(stderr, "bl out of range (%lld max is +/-16M) from %s in %s to %s in %s\n", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
+                                                       throwf("bl out of range (%lld max is +/-16M) from %s in %s to %s in %s", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
                                                }
                                        }
                                        instruction = OSReadBigInt32(instructionPtr, 0);
@@ -1942,7 +2011,7 @@ void Atom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer
 
 
 
-const macho_section* Atom::findSectionFromOffset(macho_uintptr_t offset)
+const macho_section* Atom::findSectionFromOffset(uint32_t offset)
 {
        const macho_section* const sectionsStart = (const macho_section*)( (char*)fOwner.fSegment + sizeof(macho_segment_command) );
        const macho_section* const sectionsEnd   = &sectionsStart[fOwner.fSegment->nsects()];
@@ -1950,7 +2019,7 @@ const macho_section* Atom::findSectionFromOffset(macho_uintptr_t offset)
                if ( (s->addr() <= offset) && (offset < (s->addr()+s->size())) ) 
                        return s;
        }
-       throw "section not found";
+       throwf("address 0x%08X is not in any section", offset);
 }
 
 void Atom::setSize(macho_uintptr_t size)
@@ -2073,13 +2142,14 @@ Reference::~Reference()
 {
 }
 
-bool Reference::isUnbound() const
+bool Reference::isTargetUnbound() const
 {
-       if ( fTarget == NULL ) 
-               return true;
-       if ( (fFromTargetName!=NULL) && (fFromTarget==NULL) )
-               return true;
-       return false;
+       return ( fTarget == NULL );
+}
+
+bool Reference::isFromTargetUnbound() const
+{
+       return ( fFromTarget == NULL );
 }
 
 bool Reference::isWeakReference() const
@@ -2087,9 +2157,24 @@ bool Reference::isWeakReference() const
        return fWeak;
 }
 
-bool Reference::requiresRuntimeFixUp() const
+bool Reference::requiresRuntimeFixUp(bool slideable) const
 {
-       return ( fKind == Reference::pointer );
+       // This static linker only supports pure code (no code fixups are runtime)
+#if defined(ARCH_PPC) || defined(ARCH_PPC64)
+       // Only data can be fixed up, and the codegen assures only "pointers" need runtime fixups
+       return ( (fKind == Reference::pointer) && (fTarget->isImportProxy() || fTarget->isWeakDefinition() || slideable) );
+#elif defined(ARCH_I386)
+       // For i386, Reference::pointer is used for both data pointers and instructions with 32-bit absolute operands
+       if ( fKind == Reference::pointer ) {
+               if ( fTarget->isImportProxy() )
+                       return true;
+               else
+                       return slideable;
+       }
+       return false; 
+#else
+       #error
+#endif
 }
 
 bool Reference::isLazyReference() const
@@ -2119,9 +2204,10 @@ ObjectFile::Atom& Reference::getTarget() const
        return *fTarget;
 }
 
-void Reference::setTarget(ObjectFile::Atom& target)
+void Reference::setTarget(ObjectFile::Atom& target, uint64_t offset)
 {
        fTarget = &target;
+       fTargetOffset = offset;
 }
 
 
@@ -2130,6 +2216,11 @@ ObjectFile::Atom& Reference::getFromTarget() const
        return *fFromTarget;
 }
 
+bool Reference::hasFromTarget() const
+{
+       return ( (fFromTarget != NULL) || (fFromTargetName != NULL) );
+}
+
 const char* Reference::getFromTargetName() const
 {
        if ( fFromTargetName != NULL )
@@ -2147,6 +2238,11 @@ void Reference::setFromTargetName(const char* name)
        fFromTargetName = name;
 }
 
+void Reference::setFromTargetOffset(uint64_t offset)
+{
+       fFromTargetOffset = offset;
+}
+
 uint64_t Reference::getTargetOffset() const
 {
        return fTargetOffset;
@@ -2237,7 +2333,7 @@ const char* Reference::getDescription() const
                                // handled above
                                break;
                        case x86FixupBranch32:
-                               sprintf(temp, "offset 0x%04llX, call pc-rel fixup to ", this->getFixUpOffset());
+                               sprintf(temp, "offset 0x%04llX, pc-rel fixup to ", this->getFixUpOffset());
                                break;
                }
                // always quote by-name references
@@ -2256,8 +2352,15 @@ const char* Reference::getDescription() const
                        sprintf(&temp[strlen(temp)], " plus 0x%08llX", this->getTargetOffset());
                if ( (fKind==pointer) && fLazy ) {
                        strcat(temp, " initially bound to \"");
-                       strcat(temp, this->getFromTargetName());
-                       strcat(temp, "\"");
+                       if ( (fFromTarget != NULL) || (fFromTargetName != NULL) ) {
+                               strcat(temp, this->getFromTargetName());
+                               strcat(temp, "\"");
+                               if ( this->getFromTargetOffset() != 0 ) 
+                                       sprintf(&temp[strlen(temp)], " plus 0x%08llX", this->getFromTargetOffset());
+                       }
+                       else {
+                               strcat(temp, "\" << missing >>");
+                       }
                }
        }
        return temp;
index 5020cfeccf89060784ef2954a985f31aa98f5864..90a952799cbecb42824c5f4e0eed732cf2e6c00e 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
@@ -42,6 +43,7 @@ public:
 private:
        void                                            assignFileOffsets();
        void                                            partitionIntoSections();
+       bool                                            addBranchIslands();
        void                                            adjustLoadCommandsAndPadding();
        void                                            createDynamicLinkerCommand();
        void                                            createDylibCommands();
@@ -98,6 +100,7 @@ private:
                uint64_t                                                        fFileSize;
                uint64_t                                                        fBaseAddress;
                uint64_t                                                        fSize;
+               bool                                                            fFixedAddress;
        };
 
        
@@ -115,6 +118,7 @@ private:
        struct StabChunks {
                ObjectFile::Atom*                                       fAtom;
                ObjectFile::Reader*                                     fReader;
+               unsigned int                                            fReaderOrder;
                unsigned int                                            fOrderInReader;
                std::vector<ObjectFile::StabsInfo>*     fStabs;
        };
@@ -222,17 +226,19 @@ protected:
        class Segment : public ObjectFile::Segment
        {
        public:
-                                                                       Segment(const char* name, bool readable, bool writable, bool executable)
-                                                                                                : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable) {}
+                                                                       Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
+                                                                                                : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
                virtual const char*                     getName() const                                 { return fName; }
                virtual bool                            isContentReadable() const               { return fReadable; }
                virtual bool                            isContentWritable() const               { return fWritable; }
                virtual bool                            isContentExecutable() const             { return fExecutable; }
+               virtual bool                            hasFixedAddress() const                 { return fFixedAddress; }
        private:
                const char*                                     fName;
                const bool                                      fReadable;
                const bool                                      fWritable;
                const bool                                      fExecutable;
+               const bool                                      fFixedAddress;
        };
        
        static std::vector<ObjectFile::Reference*>      fgEmptyReferenceList;
@@ -247,10 +253,10 @@ protected:
 };
 
 
-WriterAtom::Segment                                            WriterAtom::fgPageZeroSegment("__PAGEZERO", false, false, false);
-WriterAtom::Segment                                            WriterAtom::fgTextSegment("__TEXT", true, false, true);
-WriterAtom::Segment                                            WriterAtom::fgLinkEditSegment("__LINKEDIT", true, false, false);
-WriterAtom::Segment                                            WriterAtom::fgStackSegment("__UNIXSTACK", true, true, false);
+WriterAtom::Segment                                            WriterAtom::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
+WriterAtom::Segment                                            WriterAtom::fgTextSegment("__TEXT", true, false, true, false);
+WriterAtom::Segment                                            WriterAtom::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
+WriterAtom::Segment                                            WriterAtom::fgStackSegment("__UNIXSTACK", true, true, false, true);
 std::vector<ObjectFile::Reference*>            WriterAtom::fgEmptyReferenceList;
 
 class PageZeroAtom : public WriterAtom 
@@ -535,7 +541,22 @@ private:
        WeakImportSetting                                               fWeakImportSetting;
 };
 
-
+#if defined(ARCH_PPC) || defined(ARCH_PPC64) 
+class BranchIslandAtom : public WriterAtom 
+{
+public:
+                                                                                       BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset);
+       virtual const char*                                             getName() const                         { return fName; }
+       virtual Scope                                                   getScope() const                        { return ObjectFile::Atom::scopeLinkageUnit; }
+       virtual uint64_t                                                getSize() const                         { return 4; }
+       virtual const char*                                             getSectionName() const          { return "__text"; }
+       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
+private:
+       const char*                                                             fName;
+       ObjectFile::Atom&                                               fTarget;
+       uint32_t                                                                fTargetOffset;
+};
+#endif
 
 struct ExportSorter
 {
@@ -560,7 +581,7 @@ Writer::SectionInfo::SectionInfo()
 }
        
 Writer::SegmentInfo::SegmentInfo()
- : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0), fBaseAddress(0), fSize(0)
+ : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0), fBaseAddress(0), fSize(0), fFixedAddress(false)
 {
        fName[0] = '\0';
 }
@@ -806,6 +827,10 @@ void Writer::write(std::vector<class ObjectFile::Atom*>& atoms, class ObjectFile
        // assign each section a file offset
        assignFileOffsets();
        
+       // if need to add branch islands, reassign file offsets
+       if ( addBranchIslands() )
+               assignFileOffsets();
+
        // build symbol table and relocations
        buildLinkEdit();
        
@@ -1004,7 +1029,7 @@ void Writer::collectExportedAndImportedAndLocalAtoms()
 bool Writer::stabChunkCompare(const struct StabChunks& lhs, const struct StabChunks& rhs)
 {
        if ( lhs.fReader != rhs.fReader ) {
-               return lhs.fReader < rhs.fReader;
+               return lhs.fReaderOrder < rhs.fReaderOrder;
        }
        return lhs.fOrderInReader < rhs.fOrderInReader;
 }
@@ -1015,28 +1040,39 @@ unsigned int Writer::collectStabs()
        
        // collect all stabs chunks
        std::set<ObjectFile::Reader*> seenReaders;
+       std::map<ObjectFile::Reader*, unsigned int> readerOrdinals;
        const int atomCount = fAllAtoms->size();
        for (int i=0; i < atomCount; ++i) {
                ObjectFile::Atom* atom = (*fAllAtoms)[i];
                ObjectFile::Reader* atomsReader = atom->getFile();
-               if ( (atomsReader != NULL) && (seenReaders.count(atomsReader) == 0) ) {
-                       seenReaders.insert(atomsReader);
-                       std::vector<ObjectFile::StabsInfo>* readerStabs = atomsReader->getStabsDebugInfo();
-                       if ( readerStabs != NULL ) {
-                               StabChunks chunk;
-                               chunk.fAtom                             = NULL;
-                               chunk.fReader                   = atomsReader;
-                               chunk.fOrderInReader    = 0;
-                               chunk.fStabs                    = readerStabs;
-                               fStabChunks.push_back(chunk);
-                               count += readerStabs->size() + 1; // extra one is for trailing N_SO
+               unsigned int readerOrder = 0;
+               if ( atomsReader != NULL ) {
+                       std::map<ObjectFile::Reader*, unsigned int>::iterator pos = readerOrdinals.find(atomsReader);
+                       if ( pos == readerOrdinals.end() ) {
+                               readerOrder = readerOrdinals.size();
+                               readerOrdinals[atomsReader] = readerOrder;
+                               std::vector<ObjectFile::StabsInfo>* readerStabs = atomsReader->getStabsDebugInfo();
+                               if ( readerStabs != NULL ) {
+                                       StabChunks chunk;
+                                       chunk.fAtom                             = NULL;
+                                       chunk.fReader                   = atomsReader;
+                                       chunk.fReaderOrder              = readerOrder;
+                                       chunk.fOrderInReader    = 0;
+                                       chunk.fStabs                    = readerStabs;
+                                       fStabChunks.push_back(chunk);
+                                       count += readerStabs->size() + 1; // extra one is for trailing N_SO
+                               }
                        }
-               }               
+                       else {
+                               readerOrder = pos->second;
+                       }
+               }
                std::vector<ObjectFile::StabsInfo>* atomStabs = atom->getStabsDebugInfo();
                if ( atomStabs != NULL ) {
                        StabChunks chunk;
                        chunk.fAtom                             = atom;
                        chunk.fReader                   = atomsReader;
+                       chunk.fReaderOrder              = readerOrder;
                        chunk.fOrderInReader    = atom->getSortOrder();
                        chunk.fStabs                    = atomStabs;
                        fStabChunks.push_back(chunk);
@@ -1044,9 +1080,18 @@ unsigned int Writer::collectStabs()
                }
        }
        
-       // sort by order in original .o file
+       // sort stabs: group by .o file 
        std::sort(fStabChunks.begin(), fStabChunks.end(), stabChunkCompare);
        
+       //fprintf(stderr, "Sorted stabs:\n");
+       //for (std::vector<StabChunks>::iterator it=fStabChunks.begin(); it != fStabChunks.end(); it++) {
+       //      ObjectFile::Atom* atom = (*it).fAtom;
+       //      if ( atom != NULL )
+       //              fprintf(stderr, "\t%s\n", (*it).fAtom->getDisplayName());
+       //      else
+       //              fprintf(stderr, "\t%s\n", (*it).fReader->getPath());
+       //}
+       
        return count;
 }
 
@@ -1103,28 +1148,30 @@ void Writer::addStabs(uint32_t startIndex, uint32_t count)
 
 
 
-
 uint32_t Writer::symbolIndex(ObjectFile::Atom& atom)
 {
        // search imports
-       const int importCount = fImportedAtoms.size();
-       for (int i=0; i < importCount; ++i) {
-               if ( &atom == fImportedAtoms[i] )
+       int i = 0;
+       for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
+               if ( &atom == *it )
                        return i + fSymbolTableImportStartIndex;
+               ++i;
        }
        
        // search locals
-       const int localCount = fLocalSymbolAtoms.size();
-       for (int i=0; i < localCount; ++i) {
-               if ( &atom == fLocalSymbolAtoms[i] )
+       i = 0;
+       for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
+               if ( &atom == *it )
                        return i + fSymbolTableLocalStartIndex;
+               ++i;
        }
        
        // search exports
-       const int exportCount = fExportedAtoms.size();
-       for (int i=0; i < exportCount; ++i) {
-               if ( &atom == fExportedAtoms[i] )
+       i = 0;
+       for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
+               if ( &atom == *it )
                        return i + fSymbolTableExportStartIndex;
+               ++i;
        }
        
        fprintf(stderr, "symbolIndex(%s)\n", atom.getDisplayName());
@@ -1132,7 +1179,6 @@ uint32_t Writer::symbolIndex(ObjectFile::Atom& atom)
        throw "atom not found";
 }
 
-
 void Writer::buildFixups()
 {
        if ( fOptions.outputKind() == Options::kObjectFile )
@@ -1438,7 +1484,6 @@ void Writer::buildObjectFileFixups()
                                        const int refCount = refs.size();
                                        for (int l=0; l < refCount; ++l) {
                                                ObjectFile::Reference* ref = refs[l];
-                                               relocIndex += this->addRelocs(atom, ref);
                                                if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
                                                        uint32_t offsetInSection = atom->getSectionOffset();
                                                        uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t);    
@@ -1447,6 +1492,36 @@ void Writer::buildObjectFileFixups()
                                                        IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
                                                        //printf("fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
                                                        fIndirectSymbolTable.push_back(entry);
+                                                       if ( curSection->fAllLazyPointers ) {
+                                                               ObjectFile::Atom& target = ref->getTarget();
+                                                               ObjectFile::Atom& fromTarget = ref->getFromTarget();
+                                                               if ( &fromTarget == NULL ) {
+                                                                       fprintf(stderr, "lazy pointer %s missing initial binding\n", atom->getDisplayName());
+                                                               }
+                                                               else {
+                                                                       bool isExtern = target.isImportProxy();
+                                                                       uint32_t symbolIndex = 0;
+                                                                       if ( isExtern ) 
+                                                                               symbolIndex = this->symbolIndex(target);
+                                                                       uint32_t sectionNum = target.getSection()->getIndex();
+                                                                       uint32_t address = atom->getSectionOffset();
+                                                                       macho_relocation_info reloc1;
+                                                                       reloc1.set_r_address(address);
+                                                                       if ( isExtern )
+                                                                               reloc1.set_r_symbolnum(symbolIndex);
+                                                                       else
+                                                                               reloc1.set_r_symbolnum(sectionNum);
+                                                                       reloc1.set_r_pcrel(false);
+                                                                       reloc1.set_r_length(macho_relocation_info::pointer_length); 
+                                                                       reloc1.set_r_extern(isExtern);
+                                                                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                                                                       fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
+                                                                       ++relocIndex;
+                                                               }
+                                                       }
+                                               }
+                                               else {
+                                                       relocIndex += this->addRelocs(atom, ref);
                                                }
                                        }
                                }
@@ -1490,47 +1565,46 @@ void Writer::buildExecutableFixups()
                                        std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
                                        const int refCount = refs.size();
                                        //printf("atom %s has %d references\n", atom->getDisplayName(), refCount);
-                                                                       
                                        for (int l=0; l < refCount; ++l) {
                                                ObjectFile::Reference* ref = refs[l];
-                                               // only care about references that need dyld fixups
-                                               if ( ref->requiresRuntimeFixUp() ) {
+                                               if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
+                                                       // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
+                                                       if ( atom->getSize() != sizeof(macho_uintptr_t) ) {
+                                                               printf("wrong size pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
+                                                       }
+                                                       uint32_t offsetInSection = atom->getSectionOffset();
+                                                       uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t);    
+                                                       uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
+                                                       //fprintf(stderr,"indirect pointer atom %p %s section offset = %d\n", atom, atom->getDisplayName(), offsetInSection);
+                                                       if ( ref->getTarget().isImportProxy() 
+                                                         || ref->getTarget().isWeakDefinition() 
+                                                         || (fOptions.interposable() && fOptions.shouldExport(ref->getTarget().getName()))
+                                                         || (fOptions.nameSpace() == Options::kFlatNameSpace) 
+                                                         || (fOptions.nameSpace() == Options::kForceFlatNameSpace) ) {
+                                                               undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
+                                                       }
+                                                       uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
+                                                       IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
+                                                       //fprintf(stderr,"fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
+                                                       fIndirectSymbolTable.push_back(entry);
+                                                       if ( slideable && curSection->fAllLazyPointers ) {
+                                                               // if this is a dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
+                                                               macho_relocation_info pblaReloc;
+                                                               SectionInfo* sectInfo = (SectionInfo*)ref->getFromTarget().getSection();
+                                                               uint32_t sectionNum = sectInfo->getIndex();
+                                                               pblaReloc.set_r_address(atom->getAddress()-fOptions.baseAddress());
+                                                               pblaReloc.set_r_symbolnum(sectionNum); 
+                                                               pblaReloc.set_r_pcrel(false);
+                                                               pblaReloc.set_r_length(macho_relocation_info::pointer_length); 
+                                                               pblaReloc.set_r_extern(false);
+                                                               pblaReloc.set_r_type(GENERIC_RELOC_VANILLA);
+                                                               fInternalRelocs.push_back(pblaReloc);
+                                                       }
+                                               }
+                                               else if ( ref->requiresRuntimeFixUp(slideable) ) {
                                                        if ( ! atom->getSegment().isContentWritable() )
                                                                throwf("relocations in read-only segments not supported. %s in %s reference to %s", atom->getDisplayName(), atom->getFile()->getPath(), ref->getTarget().getDisplayName());
-                                                       if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
-                                                               // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
-                                                               if ( atom->getSize() != sizeof(macho_uintptr_t) ) {
-                                                                       printf("oversize pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
-                                                               }
-                                                               uint32_t offsetInSection = atom->getSectionOffset();
-                                                               uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t);    
-                                                               uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
-                                                               //printf("indirect pointer atom %s section offset = %d\n", atom->getDisplayName(), offsetInSection);
-                                                               if ( ref->getTarget().isImportProxy() 
-                                                                 || ref->getTarget().isWeakDefinition() 
-                                                                 || (fOptions.interposable() && fOptions.shouldExport(ref->getTarget().getName()))
-                                                                 || (fOptions.nameSpace() == Options::kFlatNameSpace) 
-                                                                 || (fOptions.nameSpace() == Options::kForceFlatNameSpace) ) {
-                                                                       undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
-                                                               }
-                                                               uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
-                                                               IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
-                                                               //printf("fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
-                                                               fIndirectSymbolTable.push_back(entry);
-                                                               if ( slideable && curSection->fAllLazyPointers ) {
-                                                                       // if this is a dylib/bundle, need PBLAPTR internal relocation to fix up binding handler if image slides
-                                                                       macho_relocation_info pblaReloc;
-                                                                       macho_scattered_relocation_info* pblaSReloc = (macho_scattered_relocation_info*)&pblaReloc;
-                                                                       pblaSReloc->set_r_scattered(true);
-                                                                       pblaSReloc->set_r_pcrel(false);
-                                                                       pblaSReloc->set_r_length(macho_relocation_info::pointer_length); 
-                                                                       pblaSReloc->set_r_type(PPC_RELOC_PB_LA_PTR);
-                                                                       pblaSReloc->set_r_address(atom->getAddress()-fOptions.baseAddress());
-                                                                       pblaSReloc->set_r_value(ref->getFromTarget().getAddress()); // helper is stored in "from" address
-                                                                       fInternalRelocs.push_back(pblaReloc);
-                                                               }
-                                                       }
-                                                       else if ( ref->getTarget().isImportProxy() ) {
+                                                       if ( ref->getTarget().isImportProxy() ) {
                                                                // if import is to antoher dylib, this is encoded as an external relocation
                                                                macho_relocation_info externalReloc;
                                                                externalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
@@ -1541,7 +1615,7 @@ void Writer::buildExecutableFixups()
                                                                externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
                                                                fExternalRelocs.push_back(externalReloc);
                                                        }
-                                                       else if ( slideable ) {
+                                                       else {
                                                                // if this is a dylib/bundle, need fix-up encoded as an internal relocation
                                                                macho_relocation_info internalReloc;
                                                                SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
@@ -1613,10 +1687,10 @@ void Writer::writeAtoms()
                                                                ::pwrite(fFileDescriptor, &x86Nop, 1, p);
                        #endif
                                                }
+                                               end = offset+atom->getSize();
+                                               //fprintf(stderr, "writing 0x%08X -> 0x%08X, atom %s\n", offset, end, atom->getDisplayName());
                                                ContentWriter writer(fFileDescriptor, offset);
                                                atom->writeContent(requireAllFixUps, writer);
-                                               end = offset+atom->getSize();
-                                               //printf("wrote 0x%08X -> 0x%08X, atom %s\n", offset, end, atom->getDisplayName());
                                        }
                                }
                        }
@@ -1672,6 +1746,7 @@ void Writer::partitionIntoSections()
                                        else
                                                currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
                                        currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
+                                       currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
                                        this->fSegmentInfos.push_back(currentSegmentInfo);
                                }
                                currentSectionInfo = new SectionInfo();
@@ -1696,6 +1771,8 @@ void Writer::partitionIntoSections()
                        }
                        if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
                                currentSectionInfo->fAllLazyPointers = true;
+                       if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
+                               currentSectionInfo->fAllLazyPointers = true;
                        if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
                                currentSectionInfo->fAllNonLazyPointers = true;
                        curSection = atom->getSection();
@@ -1721,6 +1798,135 @@ void Writer::partitionIntoSections()
 }
 
 
+struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
+class TargetAndOffsetComparor
+{
+public:
+       bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const 
+       { 
+               if ( left.atom != right.atom )
+                       return ( left.atom < right.atom );
+               return ( left.offset < right.offset );
+       }
+};
+
+//
+// PowerPC can do PC relative branches as far as +/-16MB.
+// If a branch target is >16MB then we insert one or more
+// "branch islands" between the branch and its target that
+// allows island hoping to the target.
+//
+// Branch Island Algorithm
+//
+// If the __TEXT segment < 16MB, then no branch islands needed
+// Otherwise, every 15MB into the __TEXT segment is region is  
+// added which can contain branch islands.  Every out of range
+// bl instruction is checked.  If it crosses a region, an island
+// is added to that region with the same target and the bl is 
+// adjusted to target the island instead.  
+//
+// In theory, if too many islands are added to one region, it
+// could grow the __TEXT enough that other previously in-range
+// bl branches could be pushed out of range.  We reduce the  
+// probability this could happen by placing the ranges every
+// 15MB which means the region would have to be 1MB (256K islands)
+// before any branches could be pushed out of range.
+//
+bool Writer::addBranchIslands()
+{
+       bool result = false;
+#if defined(ARCH_PPC) || defined(ARCH_PPC64) 
+       // Can only possibly need branch islands if __TEXT segment > 16M
+       if ( fLoadCommandsSegment->fSize > 16000000 ) {
+               const uint32_t kBetweenRegions = 15000000; // place regions of islands every 15MB in __text section
+               SectionInfo* textSection = NULL;
+               for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
+                       if ( strcmp((*it)->fSectionName, "__text") == 0 )
+                               textSection = *it;
+               }
+               const int kIslandRegionsCount = textSection->fSize / kBetweenRegions; 
+               typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
+               AtomToIsland regionsMap[kIslandRegionsCount];
+               std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
+               unsigned int islandCount = 0;
+               
+               // create islands for branch references that are out of range
+               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
+                       ObjectFile::Atom* atom = *it;
+                       std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
+                       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
+                               ObjectFile::Reference* ref = *rit;
+                               if ( ref->getKind() == ObjectFile::Reference::ppcFixupBranch24 ) {
+                                       ObjectFile::Atom& target = ref->getTarget();
+                                       int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
+                                       int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
+                                       int64_t displacement = dstAddr - srcAddr;
+                                       const int64_t kFifteenMegLimit = kBetweenRegions;
+                                       if ( (displacement > kFifteenMegLimit) || (displacement < (-kFifteenMegLimit)) ) {
+                                               for (int i=0; i < kIslandRegionsCount; ++i) {
+                                                       AtomToIsland* region=&regionsMap[i];
+                                                       int64_t islandRegionAddr = kBetweenRegions * (i+1);
+                                                       if ( ((srcAddr < islandRegionAddr) && (dstAddr > islandRegionAddr)) 
+                                                          ||((dstAddr < islandRegionAddr) && (srcAddr > islandRegionAddr)) ) {
+                                                               TargetAndOffset islandTarget = { &target, ref->getTargetOffset() };
+                                                               AtomToIsland::iterator pos = region->find(islandTarget);
+                                                               if ( pos == region->end() ) {
+                                                                       BranchIslandAtom* island = new BranchIslandAtom(*this, target.getDisplayName(), i, target, ref->getTargetOffset());
+                                                                       (*region)[islandTarget] = island;
+                                                                       regionsIslands[i].push_back(island);
+                                                                       ++islandCount;
+                                                                       ref->setTarget(*island, 0);
+                                                               }
+                                                               else {
+                                                                       ref->setTarget(*(pos->second), 0);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+               
+               // insert islands into __text section and adjust section offsets
+               if ( islandCount > 0 ) {
+                       std::vector<ObjectFile::Atom*> newAtomList;
+                       newAtomList.reserve(textSection->fAtoms.size()+islandCount);
+                       uint64_t islandRegionAddr = kBetweenRegions;
+                       int regionIndex = 0;
+                       uint64_t sectionOffset = 0;
+                       for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
+                               ObjectFile::Atom* atom = *it;
+                               newAtomList.push_back(atom);
+                               if ( atom->getAddress() > islandRegionAddr ) {
+                                       std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
+                                       for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
+                                               ObjectFile::Atom* islandAtom = *rit;
+                                               newAtomList.push_back(islandAtom);
+                                               islandAtom->setSection(textSection);
+                                               uint64_t alignment = 1 << (islandAtom->getAlignment());
+                                               sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
+                                               islandAtom->setSectionOffset(sectionOffset);
+                                               sectionOffset += islandAtom->getSize();
+                                       }
+                                       ++regionIndex;
+                                       islandRegionAddr += kBetweenRegions;
+                               }
+                               uint64_t alignment = 1 << (atom->getAlignment());
+                               sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
+                               atom->setSectionOffset(sectionOffset);
+                               sectionOffset += atom->getSize();
+                       }
+                       textSection->fAtoms = newAtomList;
+                       textSection->fSize = sectionOffset;
+                       result = true;
+               }
+               
+       }
+#endif
+       return result;
+}
+
+
 void Writer::adjustLoadCommandsAndPadding()
 {
        fSegmentCommands->computeSize();
@@ -1787,20 +1993,26 @@ void Writer::assignFileOffsets()
 {
        bool haveFixedSegments = false;
        uint64_t fileOffset = 0;
-       uint64_t nextContiguousAddress = fOptions.baseAddress();
+       uint64_t nextContiguousAddress = 0;
+       bool baseAddressUsed = false; 
        std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
        const int segCount = segmentInfos.size();
        for(int i=0; i < segCount; ++i) {
                SegmentInfo* curSegment = segmentInfos[i];
                fileOffset = (fileOffset+4095) & (-4096);
                curSegment->fFileOffset = fileOffset;
-               if ( curSegment->fBaseAddress == 0 ) {
-                       // segment has uses next address
-                       curSegment->fBaseAddress = nextContiguousAddress;
+               if ( curSegment->fFixedAddress ) {
+                       // segment has fixed address already set
+                       haveFixedSegments = true;
                }
                else {
-                       // segment has fixed address
-                       haveFixedSegments = true;
+                       // segment uses next address
+                       if ( !baseAddressUsed ) {
+                               baseAddressUsed = true;
+                               if ( fOptions.baseAddress() != 0 ) 
+                                       nextContiguousAddress = fOptions.baseAddress();
+                       }
+                       curSegment->fBaseAddress = nextContiguousAddress;
                }
                uint64_t address = curSegment->fBaseAddress;
                std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
@@ -1821,6 +2033,9 @@ void Writer::assignFileOffsets()
                                fileOffset += curSection->fSize;
                        }
                }
+               // page align segment size
+               curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096);
+               curSegment->fSize         = (curSegment->fSize+4095) & (-4096);
                if ( curSegment->fBaseAddress == nextContiguousAddress )
                        nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
        }
@@ -1881,7 +2096,6 @@ void Writer::adjustLinkEditSections()
                address += sectionOffset;
        }
        if ( fOptions.outputKind() == Options::kObjectFile ) {
-               
                //lastSeg->fBaseAddress = 0;
                //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
                //lastSeg->fFileOffset = 0;
@@ -1889,7 +2103,7 @@ void Writer::adjustLinkEditSections()
        }
        else {
                lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
-               lastSeg->fSize = address - lastSeg->fBaseAddress;
+               lastSeg->fSize     = (address - lastSeg->fBaseAddress+4095) & (-4096);
        }
 }
 
@@ -2033,7 +2247,13 @@ void MachHeaderAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWrit
        // fill out mach_header
        mh.set_magic(macho_header::magic_value);
        mh.set_cputype(fWriter.fOptions.architecture());
-       mh.set_cpusubtype(0);
+#if defined(ARCH_PPC) || defined(ARCH_PPC64) 
+       mh.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
+#elif defined(ARCH_I386)
+       mh.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
+#else
+       #error unknown architecture
+#endif
        mh.set_filetype(fileType);
        mh.set_ncmds(commandsCount);            
        mh.set_sizeofcmds(commandsSize);        
@@ -2141,6 +2361,9 @@ void SegmentLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::Co
                                else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
                                        sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
                                }
+                               else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
+                                       sect->set_flags(S_COALESCED);
+                               }
                        }
                }
                p = &p[macho_segment_command::size + sectionsEmitted*macho_section::content_size];
@@ -2210,6 +2433,7 @@ void DyldLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::Conte
 {
        uint64_t size = this->getSize();
        uint8_t buffer[size];
+       bzero(buffer, size);
        macho_dylinker_command* cmd = (macho_dylinker_command*)buffer;
        if ( fWriter.fOptions.outputKind() == Options::kDyld )
                cmd->set_cmd(LC_ID_DYLINKER);
@@ -2484,7 +2708,7 @@ void IndirectTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::
                        ENDIAN_WRITE32(indirectTable[entry.indirectIndex], entry.symbolIndex);
                }
                else {
-                       throw "malformed indirect table";
+                       throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, entry.indirectIndex);
                }
        }
        writer.write(0, buffer, size);
@@ -2546,6 +2770,35 @@ int32_t StringsLinkEditAtom::emptyString()
         return 1;
 }
 
+#if defined(ARCH_PPC) || defined(ARCH_PPC64) 
+BranchIslandAtom::BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset) 
+ : WriterAtom(writer, fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
+{
+       char* buf = new char[strlen(name)+32];
+       if ( targetOffset == 0 ) {
+               if ( islandRegion == 0 )
+                       sprintf(buf, "%s$island", name);
+               else
+                       sprintf(buf, "%s$island_%d", name, islandRegion);
+       }
+       else {
+               sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
+       }
+       fName = buf;
+}
+
+
+void BranchIslandAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
+{
+       int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
+       uint8_t instruction[4];
+       int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
+       OSWriteBigInt32(&instruction, 0, branchInstruction);                    
+       writer.write(0, &instruction, 4);
+}
+
+
+#endif
 
 
 };
index 7b05e321a289b830cb34f7eeece4aed5a506eab0..3b6805946e9c1fc9061e809bb97369965179de4c 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
@@ -25,6 +26,7 @@
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <fcntl.h>
+#include <errno.h>
 #include <mach-o/loader.h>
 #include <mach-o/fat.h>
 
@@ -283,21 +285,13 @@ private:
        void                            writeOutput();
        
        void                            resolve(ObjectFile::Reference* reference);
+       void                            resolveFrom(ObjectFile::Reference* reference);
        void                            addJustInTimeAtoms(const char* name);
        
        void                            addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info);
        void                            addIndirectLibraries(ObjectFile::Reader* reader);
        bool                            haveIndirectLibrary(const char* path, ObjectFile::Reader* reader);
        bool                            haveDirectLibrary(const char* path);
-
-       struct SegmentAndItsAtoms
-       {
-               class Segment*                                          fSegment;
-               uint64_t                                                        fSegmentSize;
-               uint64_t                                                        fSegmentBaseAddress;
-               std::vector<class ObjectFile::Atom*>    fAtoms;
-       };
-       
        
        class SymbolTable
        {
@@ -338,7 +332,6 @@ private:
        std::vector<ExecutableFile::DyLibUsed>                          fDynamicLibraries;
        std::list<IndirectLibrary>                                                      fIndirectDynamicLibraries;
        std::vector<class ObjectFile::Atom*>                            fAllAtoms;
-       std::vector< SegmentAndItsAtoms >                                       fAllAtomsBySegment;
        std::set<class ObjectFile::Atom*>                                       fDeadAtoms;
        SectionOrder                                                                            fSectionOrder;
        unsigned int                                                                            fNextSortOrder;
@@ -363,7 +356,7 @@ void Linker::setOutputFile(ExecutableFile::Writer* writer)
 }
 
 void Linker::link()
-{              
+{      
        this->buildAtomList();
        this->loadUndefines();
        this->resolveReferences();
@@ -382,9 +375,11 @@ inline void Linker::addAtom(ObjectFile::Atom& atom)
        std::vector<class ObjectFile::Reference*>& references = atom.getReferences();
        for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
                ObjectFile::Reference* reference = *it;
-               if ( reference->isUnbound() ) {
+               if ( reference->isTargetUnbound() ) {
                        fGlobalSymbolTable.require(reference->getTargetName());
                }
+               if ( reference->hasFromTarget() && reference->isFromTargetUnbound() )
+                       fGlobalSymbolTable.require(reference->getFromTargetName());
        }
        
        // if in global namespace, add atom itself to symbol table
@@ -479,6 +474,7 @@ void Linker::loadUndefines()
                std::vector<const char*> unresolvableUndefines;
                fGlobalSymbolTable.getNeededNames(false, unresolvableUndefines);
                const int unresolvableCount = unresolvableUndefines.size();
+               int unresolvableExportsCount  = 0;
                if ( unresolvableCount != 0 ) {
                        if ( doPrint ) {
                                fprintf(stderr, "can't resolve symbols:\n");
@@ -494,12 +490,14 @@ void Linker::loadUndefines()
                                        strcat(nonLazyName, "$non_lazy_ptr");
                                        ObjectFile::Atom* lastStubAtomWithUnresolved = NULL;
                                        ObjectFile::Atom* lastNonLazyAtomWithUnresolved = NULL;
+                                       // scan all atoms for references
+                                       bool foundAtomReference = false;
                                        for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
                                                ObjectFile::Atom* atom = *it;
                                                std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
                                                for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
                                                        ObjectFile::Reference* reference = *rit;
-                                                       if ( reference->isUnbound() ) {
+                                                       if ( reference->isTargetUnbound() ) {
                                                                if ( (atom != lastStubAtomWithUnresolved) && (strcmp(reference->getTargetName(), stubName) == 0) ) {
                                                                        const char* path = atom->getFile()->getPath();
                                                                        const char* shortPath = strrchr(path, '/');
@@ -509,6 +507,7 @@ void Linker::loadUndefines()
                                                                                shortPath = &shortPath[1];
                                                                        fprintf(stderr, "      %s in %s\n", atom->getDisplayName(), shortPath);
                                                                        lastStubAtomWithUnresolved = atom;
+                                                                       foundAtomReference = true;
                                                                }
                                                                else if ( (atom != lastNonLazyAtomWithUnresolved) && (strcmp(reference->getTargetName(), nonLazyName) == 0) ) {
                                                                        const char* path = atom->getFile()->getPath();
@@ -519,13 +518,43 @@ void Linker::loadUndefines()
                                                                                shortPath = &shortPath[1];
                                                                        fprintf(stderr, "      %s in %s\n", atom->getDisplayName(), shortPath);
                                                                        lastNonLazyAtomWithUnresolved = atom;
+                                                                       foundAtomReference = true;
+                                                               }
+                                                       }
+                                                       if ( reference->hasFromTarget() && reference->isFromTargetUnbound() ) {
+                                                               if ( (atom != lastStubAtomWithUnresolved) && (strcmp(reference->getFromTargetName(), stubName) == 0) ) {
+                                                                       const char* path = atom->getFile()->getPath();
+                                                                       const char* shortPath = strrchr(path, '/');
+                                                                       if ( shortPath == NULL )
+                                                                               shortPath = path;
+                                                                       else
+                                                                               shortPath = &shortPath[1];
+                                                                       fprintf(stderr, "      %s in %s\n", atom->getDisplayName(), shortPath);
+                                                                       lastStubAtomWithUnresolved = atom;
+                                                                       foundAtomReference = true;
+                                                               }
+                                                               else if ( (atom != lastNonLazyAtomWithUnresolved) && (strcmp(reference->getFromTargetName(), nonLazyName) == 0) ) {
+                                                                       const char* path = atom->getFile()->getPath();
+                                                                       const char* shortPath = strrchr(path, '/');
+                                                                       if ( shortPath == NULL )
+                                                                               shortPath = path;
+                                                                       else
+                                                                               shortPath = &shortPath[1];
+                                                                       fprintf(stderr, "      %s in %s\n", atom->getDisplayName(), shortPath);
+                                                                       lastNonLazyAtomWithUnresolved = atom;
+                                                                       foundAtomReference = true;
                                                                }
                                                        }
                                                }
                                        }
+                                       // scan command line options
+                                       if  ( !foundAtomReference && fOptions.hasExportRestrictList() && fOptions.shouldExport(name) ) {
+                                               fprintf(stderr, "     -exported_symbols_list command line option\n");
+                                               ++unresolvableExportsCount;
+                                       }
                                }
                        }
-                       if ( doError )
+                       if ( doError && (unresolvableCount > unresolvableExportsCount) ) // last check should be removed.  It exists so broken projects still build
                                throw "symbol(s) not found";
                }
                
@@ -541,40 +570,52 @@ void Linker::loadUndefines()
 
 void Linker::addJustInTimeAtoms(const char* name)
 {
-       // give writer a crack at it
-       ObjectFile::Atom* atom = fOutputFile->getUndefinedProxyAtom(name);
-       if ( atom != NULL ) {
-               this->addAtom(*atom);
+       // when creating final linked image, write gets first chance
+       if ( fOptions.outputKind() != Options::kObjectFile ) {
+               ObjectFile::Atom* atom = fOutputFile->getUndefinedProxyAtom(name);
+               if ( atom != NULL ) {
+                       this->addAtom(*atom);\
+                       return;
+               }
        }
-       else {
-               // give direct readers a chance
-               const int readerCount = fInputFiles.size();
-               for (int i=0; i < readerCount; ++i) {
-                       // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
-                       // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
-                       std::vector<class ObjectFile::Atom*>* atoms = fInputFiles[i]->getJustInTimeAtomsFor(name);
+       
+       // give direct readers a chance
+       const int readerCount = fInputFiles.size();
+       for (int i=0; i < readerCount; ++i) {
+               // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
+               // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
+               std::vector<class ObjectFile::Atom*>* atoms = fInputFiles[i]->getJustInTimeAtomsFor(name);
+               if ( atoms != NULL ) {
+                       this->addAtoms(*atoms);
+                       delete atoms;
+                       return;  // found a definition, no need to search anymore
+                       //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file #%d\n", name, i);
+               }
+       }
+       
+       // give indirect readers a chance
+       for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
+               ObjectFile::Reader* reader = it->reader;
+               if ( reader != NULL ) {
+                       std::vector<class ObjectFile::Atom*>* atoms = reader->getJustInTimeAtomsFor(name);
                        if ( atoms != NULL ) {
                                this->addAtoms(*atoms);
                                delete atoms;
-                               return;  // found a definition, no need to search anymore
+                               break;
                                //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file #%d\n", name, i);
                        }
                }
-               
-               // give indirect readers a chance
-               for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
-                       ObjectFile::Reader* reader = it->reader;
-                       if ( reader != NULL ) {
-                               std::vector<class ObjectFile::Atom*>* atoms = reader->getJustInTimeAtomsFor(name);
-                               if ( atoms != NULL ) {
-                                       this->addAtoms(*atoms);
-                                       delete atoms;
-                                       break;
-                                       //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file #%d\n", name, i);
-                               }
-                       }
+       }
+       
+       // when creating .o file, writer goes last (this is so any static archives will be searched above)
+       if ( fOptions.outputKind() == Options::kObjectFile ) {
+               ObjectFile::Atom* atom = fOutputFile->getUndefinedProxyAtom(name);
+               if ( atom != NULL ) {
+                       this->addAtom(*atom);
+                       return;
                }
        }
+
 }
 
 void Linker::resolve(ObjectFile::Reference* reference)
@@ -592,7 +633,7 @@ void Linker::resolve(ObjectFile::Reference* reference)
                        target = fGlobalSymbolTable.find(nonStubTarget);        
                        // also need indirection to all exported weak symbols for C++ support
                        if ( (target != NULL) && !target->isImportProxy() && (!target->isWeakDefinition() || (target->getScope() != ObjectFile::Atom::scopeGlobal)) ) {
-                               reference->setTarget(*target);
+                               reference->setTarget(*target, reference->getTargetOffset());
                                // mark stub as no longer being needed
                                ObjectFile::Atom* stub = fGlobalSymbolTable.find(targetName);
                                if ( stub != NULL ) {
@@ -614,7 +655,7 @@ void Linker::resolve(ObjectFile::Reference* reference)
        if ( target == NULL ) {
                fprintf(stderr, "can't resolve: %s\n", targetName);
        }
-       reference->setTarget(*target);
+       reference->setTarget(*target, reference->getTargetOffset());
        
        // handle weak-imports
        if ( target->isImportProxy() ) {
@@ -622,8 +663,8 @@ void Linker::resolve(ObjectFile::Reference* reference)
                if ( reference->isWeakReference() ) {
                        switch(target->getImportWeakness()) {
                                case ObjectFile::Atom::kWeakUnset:
-                                       target->setImportWeakness(true);
-                    break;     
+                                       target->setImportWeakness(true);        
+                                       break;
                                case ObjectFile::Atom::kWeakImport:
                                        break;
                                case ObjectFile::Atom::kNonWeakImport:
@@ -634,8 +675,8 @@ void Linker::resolve(ObjectFile::Reference* reference)
                else {
                        switch(target->getImportWeakness()) {
                                case ObjectFile::Atom::kWeakUnset:
-                                       target->setImportWeakness(false);       
-                    break;     
+                                       target->setImportWeakness(false);
+                                       break;  
                                case ObjectFile::Atom::kWeakImport:
                                        mismatch = true;
                                        break;
@@ -656,16 +697,17 @@ void Linker::resolve(ObjectFile::Reference* reference)
                        }
                }
        }
-       
+}
+
+void Linker::resolveFrom(ObjectFile::Reference* reference)
+{      
        // handle references that have two (from and to) targets
-       if ( reference->isUnbound() ) {
-               const char* fromTargetName = reference->getFromTargetName();
-               ObjectFile::Atom* fromTarget = fGlobalSymbolTable.find(fromTargetName);
-               if ( target == NULL ) {
-                       fprintf(stderr, "can't resolve: %s\n", fromTargetName);
-               }
-               reference->setFromTarget(*fromTarget);
+       const char* fromTargetName = reference->getFromTargetName();
+       ObjectFile::Atom* fromTarget = fGlobalSymbolTable.find(fromTargetName);
+       if ( fromTarget == NULL ) {
+               fprintf(stderr, "can't resolve: %s\n", fromTargetName);
        }
+       reference->setFromTarget(*fromTarget);
 }
 
 
@@ -677,9 +719,10 @@ void Linker::resolveReferences()
                std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
                for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
                        ObjectFile::Reference* reference = *it;
-                       if ( reference->isUnbound() ) {
+                       if ( reference->isTargetUnbound() ) 
                                this->resolve(reference);
-                       }
+                       if ( reference->hasFromTarget() && reference->isFromTargetUnbound() ) 
+                               this->resolveFrom(reference);
                }
        }
 }
@@ -715,6 +758,10 @@ void Linker::sortAtoms()
 {
        Section::assignIndexes();
        std::sort(fAllAtoms.begin(), fAllAtoms.end(), Linker::AtomSorter());
+       //fprintf(stderr, "Sorted atoms:\n");
+       //for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
+       //      fprintf(stderr, "\t%s\n", (*it)->getDisplayName());
+       //}
 }
 
 
@@ -722,16 +769,12 @@ void Linker::sortAtoms()
 // make sure given addresses are within reach of branches, etc
 void Linker::tweakLayout()
 {
-       
-
-
 }
 
-
 void Linker::writeOutput()
 {
        // if main executable, find entry point atom
-       ObjectFile::Atom* entryPoint;
+       ObjectFile::Atom* entryPoint = NULL;
        switch ( fOptions.outputKind() ) {
                case Options::kDynamicExecutable:
                case Options::kStaticExecutable:
@@ -749,8 +792,10 @@ void Linker::writeOutput()
                                }
                        }
                        break;
-               default:
+               case Options::kObjectFile:
+               case Options::kDynamicBundle:
                        entryPoint = NULL;
+                       break;
        }
        
        // tell writer about each segment's atoms
@@ -766,12 +811,13 @@ ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
        uint64_t len = info.fileLen;
        int fd = ::open(info.path, O_RDONLY, 0);
        if ( fd == -1 )
-               throw "can't open file";
+               throwf("can't open file, errno=%d", errno);
        if ( info.fileLen < 20 )
                throw "file too small";
-       char* p = (char*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE, fd, 0);
+               
+       char* p = (char*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
        if ( p == (char*)(-1) )
-               throw "can't map file";
+               throwf("can't map file, errno=%d", errno);
        ::close(fd);
        
        // if fat file, skip to architecture we want
@@ -855,7 +901,7 @@ ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
                                        throw "wrong architecture in object file";
                        }
                }
-               else if ( fileType == MH_DYLIB ) {
+               else if ( (fileType == MH_DYLIB) || (fileType == MH_DYLIB_STUB) ) {
                        ObjectFile::Reader* dylibReader = NULL;
                        switch ( cpuType ) {
                                case CPU_TYPE_POWERPC:
@@ -925,18 +971,11 @@ void Linker::createReaders()
                        // with flat namespace, blindly load all indirect libraries
                        // the indirect list will grow as indirect libraries are loaded
                        for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
-                               struct stat statBuffer;
-                               if ( stat(it->path, &statBuffer) == 0 ) {
-                                       Options::FileInfo info;
-                                       info.path = it->path;
-                                       info.fileLen = statBuffer.st_size;
-                                       info.options.fWeakImport = false;
-                                       info.options.fReExport = false;
-                                       info.options.fInstallPathOverride = NULL;
-                                       it->reader = this->createReader(info);
+                               try {
+                                       it->reader = this->createReader(fOptions.findFile(it->path));
                                }
-                               else {
-                                       fprintf(stderr, "ld64 warning: indirect library not found: %s\n", it->path);
+                               catch (const char* msg) {
+                                       fprintf(stderr, "ld64 warning: indirect library %s could not be loaded: %s\n", it->path, msg);
                                }
                        }
                        break;
@@ -951,17 +990,7 @@ void Linker::createReaders()
                                        for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
                                                if ( it->reader == NULL ) {
                                                        try {
-                                                               struct stat statBuffer;
-                                                               if ( stat(it->path, &statBuffer) != 0 ) 
-                                                                       throw "file not found";
-                                                                       
-                                                               Options::FileInfo info;
-                                                               info.path = it->path;
-                                                               info.fileLen = statBuffer.st_size;
-                                                               info.options.fWeakImport = false;
-                                                               info.options.fReExport = false;
-                                                               info.options.fInstallPathOverride = NULL;
-                                                               it->reader = this->createReader(info);
+                                                               it->reader = this->createReader(fOptions.findFile(it->path));
                                                                indirectAdded = true;
                                                        }
                                                        catch (const char* msg) {
@@ -996,7 +1025,7 @@ void Linker::createReaders()
                        dylibInfo.directReader = it->reExportParent;
                        fDynamicLibraries.push_back(dylibInfo);
                        if ( fOptions.readerOptions().fTraceIndirectDylibs )
-                               printf("[Logging for Build & Integration] Used indirect dynamic library: %s\n", it->path);
+                               printf("[Logging for Build & Integration] Used indirect dynamic library: %s\n", it->reader->getPath());
                }
        }
 }