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;
}
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
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
}
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
}
if ( _value )
temp |= 0x00000080;
#elif defined(ARCH_I386)
- temp &= 0x7FFFFFFF;
+ temp &= 0xFEFFFFFF;
if ( _value )
temp |= 0x01000000;
#else
if ( _value )
temp |= 0x00000010;
#elif defined(ARCH_I386)
- temp &= 0xEFFFFFFF;
+ temp &= 0xF7FFFFFF;
if ( _value )
temp |= 0x08000000;
#else
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
protected:
Reader() {}
+ virtual ~Reader() {}
};
class Segment
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;
};
{
public:
virtual void write(uint64_t atomOffset, const void* buffer, uint64_t size) = 0;
+protected:
+ ContentWriter() {}
+ virtual ~ContentWriter() {}
};
class Atom
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;
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() {}
};
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <vector>
#include "Options.h"
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);
return fWarnCommons;
}
-
bool Options::shouldExport(const char* symbolName)
{
switch (fExportMode) {
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");
if ( eol != NULL )
*eol = '\0';
- fInputFiles.push_back(makeFileInfo(path));
+ fInputFiles.push_back(findFile(path));
}
fclose(file);
}
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]);
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);
}
// 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
}
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);
}
}
// 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);
+
}
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
std::vector<SectionAlignment>& sectionAlignments();
CommonsMode commonsMode();
bool warnCommons();
+ FileInfo findFile(const char* path);
private:
class CStringEquals
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);
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;
};
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
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
{
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;
}
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];
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;
{
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;
}
{
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());
}
}
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());
}
}
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* @APPLE_LICENSE_HEADER_END@
*/
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- */
namespace ObjectFileMachO {
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;
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&);
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;
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));
}
}
}
+
}
// process stabs debugging info
{
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);
}
}
{
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;
// 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) {
return atom;
}
#endif
- return NULL;
+ throwf("address 0x%08X is not in any atom", offset);
}
uint32_t Reader::findAtomIndex(const Atom& atom)
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);
}
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;
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 ) {
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
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);
-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 = §ionsStart[fOwner.fSegment->nsects()];
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)
{
}
-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
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
return *fTarget;
}
-void Reference::setTarget(ObjectFile::Atom& target)
+void Reference::setTarget(ObjectFile::Atom& target, uint64_t offset)
{
fTarget = ⌖
+ fTargetOffset = offset;
}
return *fFromTarget;
}
+bool Reference::hasFromTarget() const
+{
+ return ( (fFromTarget != NULL) || (fFromTargetName != NULL) );
+}
+
const char* Reference::getFromTargetName() const
{
if ( fFromTargetName != NULL )
fFromTargetName = name;
}
+void Reference::setFromTargetOffset(uint64_t offset)
+{
+ fFromTargetOffset = offset;
+}
+
uint64_t Reference::getTargetOffset() const
{
return fTargetOffset;
// 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
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;
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
private:
void assignFileOffsets();
void partitionIntoSections();
+ bool addBranchIslands();
void adjustLoadCommandsAndPadding();
void createDynamicLinkerCommand();
void createDylibCommands();
uint64_t fFileSize;
uint64_t fBaseAddress;
uint64_t fSize;
+ bool fFixedAddress;
};
struct StabChunks {
ObjectFile::Atom* fAtom;
ObjectFile::Reader* fReader;
+ unsigned int fReaderOrder;
unsigned int fOrderInReader;
std::vector<ObjectFile::StabsInfo>* fStabs;
};
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;
};
-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
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
{
}
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';
}
// 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();
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;
}
// 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);
}
}
- // 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;
}
-
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());
throw "atom not found";
}
-
void Writer::buildFixups()
{
if ( fOptions.outputKind() == Options::kObjectFile )
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);
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);
}
}
}
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());
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();
::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());
}
}
}
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();
}
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();
}
+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=®ionsMap[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 = ®ionsIslands[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();
{
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;
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);
}
address += sectionOffset;
}
if ( fOptions.outputKind() == Options::kObjectFile ) {
-
//lastSeg->fBaseAddress = 0;
//lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
//lastSeg->fFileOffset = 0;
}
else {
lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
- lastSeg->fSize = address - lastSeg->fBaseAddress;
+ lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
}
}
// 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);
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];
{
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);
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);
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
};
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
+#include <errno.h>
#include <mach-o/loader.h>
#include <mach-o/fat.h>
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
{
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;
}
void Linker::link()
-{
+{
this->buildAtomList();
this->loadUndefines();
this->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() ) {
fGlobalSymbolTable.require(reference->getTargetName());
}
+ if ( reference->hasFromTarget() && reference->isFromTargetUnbound() )
+ fGlobalSymbolTable.require(reference->getFromTargetName());
}
// if in global namespace, add atom itself to symbol table
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");
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, '/');
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();
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";
}
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)
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 ) {
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() ) {
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:
else {
switch(target->getImportWeakness()) {
case ObjectFile::Atom::kWeakUnset:
- target->setImportWeakness(false);
- break;
+ target->setImportWeakness(false);
+ break;
case ObjectFile::Atom::kWeakImport:
mismatch = true;
break;
}
}
}
-
+}
+
+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);
}
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);
}
}
}
{
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());
+ //}
}
// 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:
}
}
break;
- default:
+ case Options::kObjectFile:
+ case Options::kDynamicBundle:
entryPoint = NULL;
+ break;
}
// tell writer about each segment's atoms
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
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:
// 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;
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) {
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());
}
}
}