+----- Tagged ld64-97.2
+
+2009-09-25 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7200658> 'unknown DWARF EH encoding' message logged to console with clang-50
+
+
+----- Tagged ld64-97.1
+
+2009-07-28 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7099040> make better no-PIC branch island to thumb1
+ * Add kBranchIslandNoPicToThumb1 as 8-byte no-PIC island
+
+
+2009-07-20 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7075703> section$start$__DATA$__bss can fail
+ * In SectionBoundaryAtom constructor make __bss and __common be zero-fill
+ * In AtomSorter, make sure end kSectionEnd sort after kTentativeDefinition
+ * unit-tests/test-cases/section-labels-zero-fill: add test cases
+
+
+----- Tagged ld64-97
+
+2009-07-13 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7049478> empty dylib should have subtype from command line
+ In Linker::writeOutput() for ARM, set initial fCurrentCpuConstraint to be command line subtype
+
+
+2009-07-09 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7043920> crash when using -dead_strip and LTO with unresolved intrinsic
+ * In Linker::optimize() after final deadStripResolve() call checkUndefines() one last time
+
+
+2009-07-09 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7043256> ld64 can not find a -e entry point from an archive
+ * src/ld/ld.cpp: add searchArchives parameter to entryPoint() for use by deadStripResolve()
+ * unit-tests/test-cases/dead_strip-entry-archive: added test case
+
+
+2009-07-08 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/6702217> __objc_classrefs section could be coalesced
+ * In machoReader, chop up __objc_classrefs section into pointer size atoms
+ and make each weak and hidden with a name based on its target name.
+
+
+2009-06-26 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/6715874> "ld: symbol dyld_stub_binding_helper not defined" for xnu built with clang for x86_64
+ * Fix relocationNeededInFinalLinkedImage() to say weak-defs don't require indirection in static executables
+ * Added unit-tests/test-cases/static-executable-weak-defines
+
+
+2009-06-26 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7012016> Error msg for missing -init symbol is misleading/unclear
+ * In Linker::checkUndefines() check all ways that the command line could add an undefined
+ and then search for close matches/typos.
+
+
+2009-06-25 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/5725900> We need ld-symbol-moving-symbols for ARM/Embedded
+ * In mach_o::dylib::Reader::addSymbol() parse iPhoneOS version strings
+ * Update IPhoneVersionMin
+
+
+2009-06-25 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/6933931> Linker makes subtype-zero file from empty subtype-nonzero file.
+ * In Linker::writeOutput() set inittal fCurrentCpuConstraint to be command line subtype
+ * Fix fArchitectureName to have arm sub-types
+
+
+2009-06-24 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/6955021> ld should do a better job of reporting attempts to link directories
+ * In Options::buildSearchPaths() sanity check -L and -F options
+
+
+2009-06-24 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/6974647> better error message when libLTO.dylib not loadable
+ * in Linker::createReader() provide detail error messages
+
+
+----- Tagged ld64-96.10
+
+2009-08-31 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7182988> empty dylib has been __mh_dylib_header n_sect
+ * rework patch to use MinimalTextAtom to ensure there is always a __text section
+
+
+----- Tagged ld64-96.9
+
+2009-08-31 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7182988> empty dylib has been __mh_dylib_header n_sect
+ * suppress __mh_dylib_header from symbol table if there is no __text section
+
+ Implicitly add dyld_stub_binder to libSystem.dylib so iPhone clients can build
+ against SnowLeopard libSystem.dylib.
+
+
+----- Tagged ld64-96.8
+
+2009-08-30 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7049478> SWB: gcc-5577.1 fails to build vecLib
+
+
+----- Tagged ld64-96.7
+
+2009-08-29 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/6933931> Linker makes subtype-zero file from empty subtype-nonzero file.
+
+
+----- Tagged ld64-96.6
+
+2009-07-30 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7103437> ld: ldr 12-bit displacement out of range on SnowLeopard with gcc-5648
+ * in Section::Section() set fIndex to ensure __symbolstub1 sorts to end of __TEXT segment
+
----- Tagged ld64-96.5
{
public:
static bool validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture);
+ static const char* fileKind(const uint8_t* fileContent);
static bool loaded() { return (::lto_get_version() != NULL); }
Reader(const uint8_t* fileContent, uint64_t fileLength,
const char* path, time_t modTime,
kind = ObjectFile::Atom::kWeakDefinition;
break;
case LTO_SYMBOL_DEFINITION_UNDEFINED:
+ case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
kind = ObjectFile::Atom::kExternalDefinition;
break;
default:
return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, tripletPrefixForArch(architecture));
}
+const char* Reader::fileKind(const uint8_t* p)
+{
+ if ( (p[0] == 0xDE) && (p[1] == 0xC0) && (p[2] == 0x17) && (p[3] == 0x0B) ) {
+ uint32_t arch = LittleEndian::get32(*((uint32_t*)(&p[16])));
+ switch (arch) {
+ case CPU_TYPE_POWERPC:
+ return "ppc";
+ case CPU_TYPE_I386:
+ return "i386";
+ case CPU_TYPE_X86_64:
+ return "x86_64";
+ case CPU_TYPE_ARM:
+ return "arm";
+ }
+ return "unknown bitcode architecture";
+ }
+ return NULL;
+}
+
bool Reader::optimize(const std::vector<ObjectFile::Atom *>& allAtoms, std::vector<ObjectFile::Atom*>& newAtoms,
std::vector<const char*>& additionalUndefines, const std::set<ObjectFile::Atom*>& deadAtoms,
std::vector<ObjectFile::Atom*>& newlyDeadAtoms,
bool fLazyLoaded;
ObjectFile::Reader::ObjcConstraint fObjcContraint;
std::vector<ObjectFile::Reader*> fReExportedChildren;
- const ObjectFile::ReaderOptions::MacVersionMin fDeploymentVersionMin;
+ const ObjectFile::ReaderOptions::MacVersionMin fMacDeploymentVersionMin;
+ const ObjectFile::ReaderOptions::IPhoneVersionMin fIPhoneDeploymentVersionMin;
std::vector<class ObjectFile::Atom*> fFlatImports;
static bool fgLogHashtable;
fExplicitlyLinked(false), fImplicitlyLinked(false), fProvidedAtom(false),
fImplicitlyLinkPublicDylibs(options.fImplicitlyLinkPublicDylibs), fLazyLoaded(dylibOptions.fLazyLoad),
fObjcContraint(ObjectFile::Reader::kObjcNone),
- fDeploymentVersionMin(options.fMacVersionMin)
+ fMacDeploymentVersionMin(options.fMacVersionMin),
+ fIPhoneDeploymentVersionMin(options.fIPhoneVersionMin)
{
// sanity check
if ( ! validFile(fileContent, dylibOptions.fBundleLoader) )
addSymbol("dyld_stub_binder", false);
}
+// hack for bring up of iPhoneOS builds on SnowLeopard
+template <>
+void Reader<arm>::addDyldFastStub()
+{
+ addSymbol("dyld_stub_binder", false);
+}
+
template <typename A>
void Reader<A>::addDyldFastStub()
{
const char* symAction = &name[4];
const char* symCond = strchr(symAction, '$');
if ( symCond != NULL ) {
- ObjectFile::ReaderOptions::MacVersionMin symVersionCondition = ObjectFile::ReaderOptions::kMinMacVersionUnset;
- if ( (strncmp(symCond, "$os10.", 6) == 0) && isdigit(symCond[6]) && (symCond[7] == '$') ) {
- switch ( symCond[6] - '0' ) {
- case 0:
- case 1:
- symVersionCondition = ObjectFile::ReaderOptions::k10_1;
- break;
- case 2:
- symVersionCondition = ObjectFile::ReaderOptions::k10_2;
- break;
- case 3:
- symVersionCondition = ObjectFile::ReaderOptions::k10_3;
- break;
- case 4:
- symVersionCondition = ObjectFile::ReaderOptions::k10_4;
- break;
- case 5:
- symVersionCondition = ObjectFile::ReaderOptions::k10_5;
- break;
- case 6:
- symVersionCondition = ObjectFile::ReaderOptions::k10_6;
- break;
- }
- const char* symName = strchr(&symCond[1], '$');
- if ( symName != NULL ) {
- ++symName;
- if ( fDeploymentVersionMin == symVersionCondition ) {
- if ( strncmp(symAction, "hide$", 5) == 0 ) {
- if ( fgLogHashtable ) fprintf(stderr, " adding %s to ignore set for %s\n", symName, this->getPath());
- fIgnoreExports.insert(strdup(symName));
- return;
- }
- else if ( strncmp(symAction, "add$", 4) == 0 ) {
- this->addSymbol(symName, weakDef);
- return;
- }
- else {
- warning("bad symbol action: %s in dylib %s", name, this->getPath());
+ if ( fMacDeploymentVersionMin != ObjectFile::ReaderOptions::kMinMacVersionUnset ) {
+ ObjectFile::ReaderOptions::MacVersionMin symVersionCondition = ObjectFile::ReaderOptions::kMinMacVersionUnset;
+ // ex: $ld$add$os10.6$_foo
+ if ( (strncmp(symCond, "$os10.", 6) == 0) && isdigit(symCond[6]) && (symCond[7] == '$') ) {
+ switch ( symCond[6] - '0' ) {
+ case 0:
+ case 1:
+ symVersionCondition = ObjectFile::ReaderOptions::k10_1;
+ break;
+ case 2:
+ symVersionCondition = ObjectFile::ReaderOptions::k10_2;
+ break;
+ case 3:
+ symVersionCondition = ObjectFile::ReaderOptions::k10_3;
+ break;
+ case 4:
+ symVersionCondition = ObjectFile::ReaderOptions::k10_4;
+ break;
+ case 5:
+ symVersionCondition = ObjectFile::ReaderOptions::k10_5;
+ break;
+ case 6:
+ symVersionCondition = ObjectFile::ReaderOptions::k10_6;
+ break;
+ }
+ const char* symName = strchr(&symCond[1], '$');
+ if ( symName != NULL ) {
+ ++symName;
+ if ( fMacDeploymentVersionMin == symVersionCondition ) {
+ if ( strncmp(symAction, "hide$", 5) == 0 ) {
+ if ( fgLogHashtable ) fprintf(stderr, " adding %s to ignore set for %s\n", symName, this->getPath());
+ fIgnoreExports.insert(strdup(symName));
+ return;
+ }
+ else if ( strncmp(symAction, "add$", 4) == 0 ) {
+ this->addSymbol(symName, weakDef);
+ return;
+ }
+ else {
+ warning("bad symbol action: %s in dylib %s", name, this->getPath());
+ }
}
}
+ else {
+ warning("bad symbol name: %s in dylib %s", name, this->getPath());
+ }
}
else {
- warning("bad symbol name: %s in dylib %s", name, this->getPath());
+ warning("bad symbol version: %s in dylib %s", name, this->getPath());
}
}
- else {
- warning("bad symbol version: %s in dylib %s", name, this->getPath());
+ else if ( fIPhoneDeploymentVersionMin != ObjectFile::ReaderOptions::kMinIPhoneVersionUnset ) {
+ ObjectFile::ReaderOptions::IPhoneVersionMin symVersionCondition = ObjectFile::ReaderOptions::kMinIPhoneVersionUnset;
+ // ex: $ld$add$os3.1$_foo
+ if ( (strncmp(symCond, "$os", 3) == 0) && isdigit(symCond[3]) && (symCond[4] == '.') ) {
+ if ( (symCond[3] == '2') && (symCond[5] == '0') )
+ symVersionCondition = ObjectFile::ReaderOptions::k2_0;
+ else if ( (symCond[3] == '2') && (symCond[5] == '1') )
+ symVersionCondition = ObjectFile::ReaderOptions::k2_1;
+ else if ( (symCond[3] == '2') && (symCond[5] >= '2') )
+ symVersionCondition = ObjectFile::ReaderOptions::k2_2;
+ else if ( (symCond[3] == '3') && (symCond[5] == '0') )
+ symVersionCondition = ObjectFile::ReaderOptions::k3_0;
+ else if ( (symCond[3] == '3') && (symCond[5] == '1') )
+ symVersionCondition = ObjectFile::ReaderOptions::k3_1;
+ else if ( (symCond[3] == '3') && (symCond[5] >= '2') )
+ symVersionCondition = ObjectFile::ReaderOptions::k3_2;
+ else if ( (symCond[3] >= '4') )
+ symVersionCondition = ObjectFile::ReaderOptions::k4_0;
+ const char* symName = strchr(&symCond[1], '$');
+ if ( symName != NULL ) {
+ ++symName;
+ if ( fIPhoneDeploymentVersionMin == symVersionCondition ) {
+ if ( strncmp(symAction, "hide$", 5) == 0 ) {
+ if ( fgLogHashtable ) fprintf(stderr, " adding %s to ignore set for %s\n", symName, this->getPath());
+ fIgnoreExports.insert(strdup(symName));
+ return;
+ }
+ else if ( strncmp(symAction, "add$", 4) == 0 ) {
+ this->addSymbol(symName, weakDef);
+ return;
+ }
+ else {
+ warning("bad symbol action: %s in dylib %s", name, this->getPath());
+ }
+ }
+ }
+ else {
+ warning("bad symbol name: %s in dylib %s", name, this->getPath());
+ }
+ }
+ else {
+ warning("bad symbol version: %s in dylib %s, symCond=%s", name, this->getPath(), symCond);
+ }
}
}
else {
if ( !fOwner.fOptions.fNoEHLabels )
fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
}
+ else if ( (strncmp(fSection->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
+ fSynthesizedName = "objc-class-pointer-name-PENDING";
+ fScope = ObjectFile::Atom::scopeLinkageUnit;
+ owner.fAtomsPendingAName.push_back(this);
+ owner.fSectionsWithAtomsPendingAName.insert(fSection);
+ fKind = ObjectFile::Atom::kWeakDefinition;
+ }
else if ( section == owner.fUTF16Section ) {
if ( fOwner.fOptions.fForFinalLinkedImage ) {
fDontDeadStrip = false;
if ( funcAtom != NULL )
asprintf((char**)&fSynthesizedName, "%s.lsda", funcAtom->getDisplayName());
}
+ else if ( (strncmp(fSection->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
+ std::vector<ObjectFile::Reference*>& references = this->getReferences();
+ if ( references.size() != 1 )
+ throwf("__objc_classrefs element missing reloc (count=%ld) for target class in %s", references.size(), fOwner.getPath());
+ const char* targetName = references[0]->getTargetName();
+ if ( strncmp(targetName, "_OBJC_CLASS_$_", 14) == 0 )
+ asprintf((char**)&fSynthesizedName, "objc-class-ref-to-%s", &targetName[14]);
+ else
+ asprintf((char**)&fSynthesizedName, "objc-class-ref-to-%s", targetName);
+ }
}
virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kWeakDefinition; }
virtual ObjectFile::Atom::ContentType getContentType() const { return fStart ? ObjectFile::Atom::kSectionStart : ObjectFile::Atom::kSectionEnd; }
- virtual bool isZeroFill() const { return false; }
+ virtual bool isZeroFill() const { return fZeroFill; }
virtual bool isThumb() const { return false; }
virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
virtual bool dontDeadStrip() const { return false; }
const char* fSectionName;
const char* fDisplayName;
bool fStart;
+ bool fZeroFill;
static std::vector<ObjectFile::Reference*> fgNoReferences;
};
// section$end$__DATA$__my
template <typename A>
SectionBoundaryAtom<A>::SectionBoundaryAtom(Reader<A>& owner, bool start, const char* symbolName, const char* segSectName)
- : fOwner(owner), fSymbolName(symbolName), fSectionName(NULL), fStart(start)
+ : fOwner(owner), fSymbolName(symbolName), fSectionName(NULL), fStart(start), fZeroFill(false)
{
const char* segSectDividor = strrchr(segSectName, '$');
if ( segSectDividor == NULL )
strlcpy(segName, segSectName, segNameLen+1);
if ( strcmp(segName, "__TEXT") == 0 )
fSegment = new Segment("__TEXT", true, false, true);
- else if ( strcmp(segName, "__DATA") == 0 )
+ else if ( strcmp(segName, "__DATA") == 0 ) {
fSegment = new Segment("__DATA", true, true, false);
+ if ( (strcmp(fSectionName, "__bss") == 0) || (strcmp(fSectionName, "__common") == 0) )
+ fZeroFill = true;
+ }
else
fSegment = new Segment(strdup(segName), true, true, false);
{
public:
static bool validFile(const uint8_t* fileContent, bool subtypeMustMatch=false, cpu_subtype_t subtype=0);
+ static const char* fileKind(const uint8_t* fileContent);
Reader(const uint8_t* fileContent, const char* path, time_t modTime,
const ObjectFile::ReaderOptions& options, uint32_t ordinalBase);
virtual ~Reader() {}
else if ((strcmp(sect->sectname(), "__cfstring") == 0) && (strcmp(sect->segname(), "__DATA") == 0)) {
atomSize = 4 * sizeof(pint_t);
}
+ // special case class reference sections
+ else if ( (strncmp(sect->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0) ) {
+ atomSize = sizeof(pint_t);;
+ }
break;
}
if ( atomSize != 0 ) {
// do nothing
break;
case DW_EH_PE_pcrel:
- result += startAddr;
+ // <rdar://problem/7200658> pc-rel sdata4 should return zero if content is zero
+ if ( (result != 0) || ((encoding & DW_EH_PE_indirect) != 0) )
+ result += startAddr;
break;
case DW_EH_PE_textrel:
throw "DW_EH_PE_textrel pointer encoding not supported";
return true;
}
+
+template <>
+const char* Reader<ppc>::fileKind(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return NULL;
+ if ( header->cputype() != CPU_TYPE_POWERPC )
+ return NULL;
+ switch ( header->cpusubtype() ) {
+ case CPU_SUBTYPE_POWERPC_750:
+ return "ppc750";
+ case CPU_SUBTYPE_POWERPC_7400:
+ return "ppc7400";
+ case CPU_SUBTYPE_POWERPC_7450:
+ return "ppc7450";
+ case CPU_SUBTYPE_POWERPC_970:
+ return "ppc970";
+ case CPU_SUBTYPE_POWERPC_ALL:
+ return "ppc";
+ }
+ return "ppc???";
+}
+
+template <>
+const char* Reader<ppc64>::fileKind(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return NULL;
+ if ( header->cputype() != CPU_TYPE_POWERPC64 )
+ return NULL;
+ return "ppc64";
+}
+
+template <>
+const char* Reader<x86>::fileKind(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return NULL;
+ if ( header->cputype() != CPU_TYPE_I386 )
+ return NULL;
+ return "i386";
+}
+
+template <>
+const char* Reader<x86_64>::fileKind(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return NULL;
+ if ( header->cputype() != CPU_TYPE_X86_64 )
+ return NULL;
+ return "x86_64";
+}
+
+template <>
+const char* Reader<arm>::fileKind(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return NULL;
+ if ( header->cputype() != CPU_TYPE_ARM )
+ return NULL;
+ switch ( header->cpusubtype() ) {
+ case CPU_SUBTYPE_ARM_V4T:
+ return "armv4t";
+ case CPU_SUBTYPE_ARM_V5TEJ:
+ return "armv5";
+ case CPU_SUBTYPE_ARM_V6:
+ return "armv6";
+ case CPU_SUBTYPE_ARM_V7:
+ return "armv7";
+ }
+ return "arm???";
+}
+
+
template <typename A>
bool Reader<A>::isWeakImportSymbol(const macho_nlist<P>* sym)
{
uint64_t fSize;
};
+template <typename A>
+class MinimalTextAtom : public WriterAtom<A>
+{
+public:
+ MinimalTextAtom(Writer<A>& writer)
+ : WriterAtom<A>(writer, headerSegment(writer)) {}
+ virtual const char* getDisplayName() const { return "minimal text"; }
+ virtual uint64_t getSize() const { return 0; }
+ virtual const char* getSectionName() const { return "__text"; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
+
+private:
+ using WriterAtom<A>::fWriter;
+};
+
+
template <typename A>
class UnwindInfoAtom : public WriterAtom<A>
{
uint64_t getFinalTargetAdress() const { return fFinalTarget.getAddress() + fFinalTargetOffset; }
private:
using WriterAtom<A>::fWriter;
- enum IslandKind { kBranchIslandToARM, kBranchIslandToThumb2, kBranchIslandToThumb1 };
+ enum IslandKind { kBranchIslandToARM, kBranchIslandToThumb2, kBranchIslandToThumb1, kBranchIslandNoPicToThumb1 };
const char* fName;
ObjectFile::Atom& fTarget;
ObjectFile::Atom& fFinalTarget;
fLargestAtomSize(1),
fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
fCanScatter(false), fWritableSegmentPastFirst4GB(false), fNoReExportedDylibs(false),
- fBiggerThanTwoGigs(false), fSlideable(false), fHasThumbBranches(false),
+ fBiggerThanTwoGigs(false), fSlideable(false), fHasThumbBranches(false),
fFirstWritableSegment(NULL), fAnonNameIndex(1000)
{
switch ( fOptions.outputKind() ) {
if ( fOptions.hasCustomStack() )
fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new MinimalTextAtom<A>(*this));
if ( fOptions.needsUnwindInfoSection() )
fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
if ( fOptions.sharedRegionEligible() )
fWriterSynthesizedAtoms.push_back(new SegmentSplitInfoLoadCommandsAtom<A>(*this));
fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new MinimalTextAtom<A>(*this));
if ( fOptions.needsUnwindInfoSection() )
fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
else
return kRelocNone;
case ObjectFile::Atom::kWeakDefinition:
- // all calls to global weak definitions get indirected
+ // in static executables, references to weak definitions are not indirected
+ if ( fOptions.outputKind() == Options::kStaticExecutable)
+ return kRelocNone;
+ // in dynamic code, all calls to global weak definitions get indirected
if ( this->shouldExport(target) )
return kRelocExternal;
else if ( fSlideable )
fIslandKind = kBranchIslandToThumb2;
}
else {
- fIslandKind = kBranchIslandToThumb1;
+ if ( writer.fSlideable )
+ fIslandKind = kBranchIslandToThumb1;
+ else
+ fIslandKind = kBranchIslandNoPicToThumb1;
}
}
else {
OSWriteLittleInt32(&buffer[12], 0, displacement); // .long target-this
}
break;
+ case kBranchIslandNoPicToThumb1:
+ {
+ // There is no large displacement thumb1 branch instruction.
+ // Instead use ARM instructions that can jump to thumb.
+ // we use a 32-bit displacement, so we can directly jump to target which means no island hopping
+ uint32_t targetAddr = getFinalTargetAdress();
+ if ( fFinalTarget.isThumb() )
+ targetAddr |= 1;
+ if (log) fprintf(stderr, "%s: 2 ARM instruction jump to final target at 0x%08llX\n", fName, getFinalTargetAdress());
+ OSWriteLittleInt32(&buffer[0], 0, 0xe51ff004); // ldr pc, [pc, #-4]
+ OSWriteLittleInt32(&buffer[4], 0, targetAddr); // .long target-this
+ }
+ break;
};
}
return 16;
case kBranchIslandToThumb2:
return 4;
+ case kBranchIslandNoPicToThumb1:
+ return 8;
};
throw "internal error: no ARM branch island kind";
}
fTraceOutputFile(NULL), fMacVersionMin(kMinMacVersionUnset), fIPhoneVersionMin(kMinIPhoneVersionUnset) {}
enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
enum MacVersionMin { kMinMacVersionUnset, k10_1, k10_2, k10_3, k10_4, k10_5, k10_6 };
- enum IPhoneVersionMin { kMinIPhoneVersionUnset, k2_0, k3_0, k3_1 };
+ enum IPhoneVersionMin { kMinIPhoneVersionUnset, k2_0, k2_1, k2_2, k3_0, k3_1, k3_2, k4_0 };
struct AliasPair {
const char* realName;
if ( ! isdigit(version[2]) )
throw "-iphoneos_version_min argument is not a number";
- if ( version[0] == '2' )
+ if ( (version[0] == '2') && (version[2] == '0') )
fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_0;
+ else if ( (version[0] == '2') && (version[2] == '1') )
+ fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_1;
+ else if ( (version[0] == '2') && (version[2] >= '2') )
+ fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_2;
else if ( (version[0] == '3') && (version[2] == '0') )
- fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_0;
- else if ( (version[0] == '3') && (version[2] >= '1') )
+ fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_0;
+ else if ( (version[0] == '3') && (version[2] == '1') )
fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_1;
+ else if ( (version[0] == '3') && (version[2] >= '2') )
+ fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_2;
else if ( (version[0] >= '4') )
- fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_1;
+ fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k4_0;
else {
fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_0;
warning("unknown option to -iphoneos_version_min, not 2.x, 3.x, or 4.x");
frameworkPaths.reserve(10);
// scan through argv looking for -L, -F, -Z, and -syslibroot options
for(int i=0; i < argc; ++i) {
- if ( (argv[i][0] == '-') && (argv[i][1] == 'L') )
- libraryPaths.push_back(&argv[i][2]);
- else if ( (argv[i][0] == '-') && (argv[i][1] == 'F') )
- frameworkPaths.push_back(&argv[i][2]);
+ if ( (argv[i][0] == '-') && (argv[i][1] == 'L') ) {
+ const char* libSearchDir = &argv[i][2];
+ if ( libSearchDir[0] == '\0' )
+ throw "-L must be immediately followed by a directory path (no space)";
+ struct stat statbuf;
+ if ( stat(libSearchDir, &statbuf) == 0 ) {
+ if ( statbuf.st_mode & S_IFDIR )
+ libraryPaths.push_back(libSearchDir);
+ else
+ warning("path '%s' following -L not a directory", libSearchDir);
+ }
+ else {
+ warning("directory '%s' following -L not found", libSearchDir);
+ }
+ }
+ else if ( (argv[i][0] == '-') && (argv[i][1] == 'F') ) {
+ const char* frameworkSearchDir = &argv[i][2];
+ if ( frameworkSearchDir[0] == '\0' )
+ throw "-F must be immediately followed by a directory path (no space)";
+ struct stat statbuf;
+ if ( stat(frameworkSearchDir, &statbuf) == 0 ) {
+ if ( statbuf.st_mode & S_IFDIR )
+ frameworkPaths.push_back(frameworkSearchDir);
+ else
+ warning("path '%s' following -F not a directory", frameworkSearchDir);
+ }
+ else {
+ warning("directory '%s' following -F not found", frameworkSearchDir);
+ }
+ }
else if ( strcmp(argv[i], "-Z") == 0 )
addStandardLibraryDirectories = false;
else if ( strcmp(argv[i], "-v") == 0 ) {
this->fIndex = 11;
else if ( strcmp(sectionName, "__symbol_stub1") == 0 )
this->fIndex = 11;
+ // sort fast arm stubs to end of __TEXT to be close to lazy pointers
+ else if ( strcmp(sectionName, "__symbolstub1") == 0 )
+ this->fIndex = INT_MAX;
// sort unwind info to end of segment
else if ( strcmp(sectionName, "__eh_frame") == 0 )
- this->fIndex = INT_MAX;
- else if ( strcmp(sectionName, "__unwind_info") == 0 )
this->fIndex = INT_MAX-1;
- else if ( strcmp(sectionName, "__gcc_except_tab") == 0 )
+ else if ( strcmp(sectionName, "__unwind_info") == 0 )
this->fIndex = INT_MAX-2;
- else if ( strcmp(sectionName, "__symbolstub1") == 0 )
- this->fIndex = INT_MAX-3; // sort to end of __TEXT to be close to lazy pointers
+ else if ( strcmp(sectionName, "__gcc_except_tab") == 0 )
+ this->fIndex = INT_MAX-3;
}
else if ( strcmp(segmentName, "__DATA") == 0 ) {
// sort arm lazy symbol pointers that must be at start of __DATA
};
ObjectFile::Reader* createReader(const Options::FileInfo&);
+ const char* fileArch(const void* p);
void addAtom(ObjectFile::Atom& atom);
void addAtoms(std::vector<class ObjectFile::Atom*>& atoms);
void buildAtomList();
static const char* truncateStabString(const char* str);
void collectDebugInfo();
void writeOutput();
- ObjectFile::Atom* entryPoint(bool orInit);
+ ObjectFile::Atom* entryPoint(bool orInit, bool searchArchives=false);
ObjectFile::Atom* dyldClassicHelper();
ObjectFile::Atom* dyldCompressedHelper();
ObjectFile::Atom* dyldLazyLibraryHelper();
break;
case CPU_TYPE_ARM:
fArchitectureName = "arm";
+ if ( fOptions.preferSubArchitecture() ) {
+ switch ( fOptions.subArchitecture() ) {
+ case CPU_SUBTYPE_ARM_V4T:
+ fArchitectureName = "armv4t";
+ break;
+ case CPU_SUBTYPE_ARM_V5TEJ:
+ fArchitectureName = "armv5";
+ break;
+ case CPU_SUBTYPE_ARM_V6:
+ fArchitectureName = "armv6";
+ break;
+ case CPU_SUBTYPE_ARM_V7:
+ fArchitectureName = "armv7";
+ break;
+ }
+ }
break;
default:
fArchitectureName = "unknown architecture";
// LTO may optimize away some atoms, so dead stripping must be redone
fLiveAtoms.clear();
this->deadStripResolve();
+ this->checkUndefines();
}
else {
// LTO may require new library symbols to be loaded, so redo
}
}
// scan command line options
- if ( !foundAtomReference && fOptions.hasExportRestrictList() && fOptions.shouldExport(name) ) {
- fprintf(stderr, " -exported_symbols_list command line option\n");
+ if ( !foundAtomReference ) {
+ // might be from -init command line option
+ if ( (fOptions.initFunctionName() != NULL) && (strcmp(name, fOptions.initFunctionName()) == 0) ) {
+ fprintf(stderr, " -init command line option\n");
+ }
+ // or might be from exported symbol option
+ else if ( fOptions.hasExportMaskList() && fOptions.shouldExport(name) ) {
+ fprintf(stderr, " -exported_symbol[s_list] command line option\n");
+ }
+ else {
+ bool isInitialUndefine = false;
+ std::vector<const char*>& clundefs = fOptions.initialUndefines();
+ for (std::vector<const char*>::iterator uit = clundefs.begin(); uit != clundefs.end(); ++uit) {
+ if ( strcmp(*uit, name) == 0 ) {
+ isInitialUndefine = true;
+ break;
+ }
+ }
+ if ( isInitialUndefine )
+ fprintf(stderr, " -u command line option\n");
+ }
++unresolvableExportsCount;
}
+ // be helpful and check for typos
+ bool printedStart = false;
+ for (SymbolTable::Mapper::iterator sit=fGlobalSymbolTable.begin(); sit != fGlobalSymbolTable.end(); ++sit) {
+ if ( (sit->second != NULL) && (strstr(sit->first, name) != NULL) ) {
+ if ( ! printedStart ) {
+ fprintf(stderr, " (maybe you meant: %s", sit->first);
+ printedStart = true;
+ }
+ else {
+ fprintf(stderr, ", %s ", sit->first);
+ }
+ }
+ }
+ if ( printedStart )
+ fprintf(stderr, ")\n");
}
}
if ( doError )
void Linker::deadStripResolve()
{
// add main() to live roots
- ObjectFile::Atom* entryPoint = this->entryPoint(false);
+ ObjectFile::Atom* entryPoint = this->entryPoint(false, true);
if ( entryPoint != NULL )
fLiveRootAtoms.insert(entryPoint);
}
}
-ObjectFile::Atom* Linker::entryPoint(bool orInit)
+ObjectFile::Atom* Linker::entryPoint(bool orInit, bool searchArchives)
{
// if main executable, find entry point atom
ObjectFile::Atom* entryPoint = NULL;
case Options::kDyld:
case Options::kPreload:
entryPoint = fGlobalSymbolTable.find(fOptions.entryName());
+ if ( (entryPoint == NULL) && searchArchives ) {
+ // <rdar://problem/7043256> ld64 can not find a -e entry point from an archive
+ this->addJustInTimeAtoms(fOptions.entryName(), false, true, false);
+ entryPoint = fGlobalSymbolTable.find(fOptions.entryName());
+ }
if ( entryPoint == NULL ) {
throwf("could not find entry point \"%s\" (perhaps missing crt1.o)", fOptions.entryName());
}
void Linker::writeOutput()
{
+ // <rdar://problem/6933931> ld -r of empty .o file should preserve sub-type
+ // <rdar://problem/7049478> empty dylib should have subtype from command line
+ if ( fOptions.preferSubArchitecture() && (fOptions.architecture() == CPU_TYPE_ARM) ) {
+ fCurrentCpuConstraint = (ObjectFile::Reader::CpuConstraint)fOptions.subArchitecture();
+ }
+
if ( fOptions.forceCpuSubtypeAll() )
fCurrentCpuConstraint = ObjectFile::Reader::kCpuAny;
fGlobalSymbolTable.hasExternalWeakDefinitions());
}
+const char* Linker::fileArch(const void* p)
+{
+ const uint8_t* bytes = (uint8_t*)p;
+ const char* result;
+ result = mach_o::relocatable::Reader<ppc>::fileKind(bytes);
+ if ( result != NULL )
+ return result;
+ result = mach_o::relocatable::Reader<ppc64>::fileKind(bytes);
+ if ( result != NULL )
+ return result;
+ result = mach_o::relocatable::Reader<x86>::fileKind(bytes);
+ if ( result != NULL )
+ return result;
+ result = mach_o::relocatable::Reader<x86_64>::fileKind(bytes);
+ if ( result != NULL )
+ return result;
+ result = mach_o::relocatable::Reader<arm>::fileKind(bytes);
+ if ( result != NULL )
+ return result;
+
+ result = lto::Reader::fileKind(bytes);
+ if ( result != NULL )
+ return result;
+
+ return "unsupported file format";
+}
+
ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
{
// map in whole file
// if fat file, skip to architecture we want
// Note: fat header is always big-endian
+ bool isFatFile = false;
const fat_header* fh = (fat_header*)p;
if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+ isFatFile = true;
const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
uint32_t sliceToUse;
bool sliceFound = false;
if ( lto::Reader::validFile(p, len, fArchitecture) ) {
return this->addObject(new lto::Reader(p, len, info.path, info.modTime, fOptions.readerOptions(), fArchitecture), info, len);
}
- else if ( !lto::Reader::loaded() && (p[0] == 'B') && (p[1] == 'C') ) {
- throw "could not process object file. Looks like an llvm bitcode object file, but libLTO.dylib could not be loaded";
+ else if ( lto::Reader::fileKind((uint8_t*)p) != NULL ) {
+ if ( lto::Reader::loaded() ) {
+ throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p), fArchitectureName);
+ }
+ else {
+ const char* libLTO = "libLTO.dylib";
+ char ldPath[PATH_MAX];
+ char tmpPath[PATH_MAX];
+ char libLTOPath[PATH_MAX];
+ uint32_t bufSize = PATH_MAX;
+ if ( _NSGetExecutablePath(ldPath, &bufSize) != -1 ) {
+ if ( realpath(ldPath, tmpPath) != NULL ) {
+ char* lastSlash = strrchr(tmpPath, '/');
+ if ( lastSlash != NULL )
+ strcpy(lastSlash, "/../lib/libLTO.dylib");
+ libLTO = tmpPath;
+ if ( realpath(tmpPath, libLTOPath) != NULL )
+ libLTO = libLTOPath;
+ }
+ }
+ throwf("could not process llvm bitcode object file, because %s could not be loaded", libLTO);
+ }
}
#endif
// error handling
throwf("missing required architecture %s in file", fArchitectureName);
}
else {
- throw "file is not of required architecture";
+ if ( isFatFile )
+ throwf("file is universal but does not contain a(n) %s slice", fArchitectureName);
+ else
+ throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p), fArchitectureName);
}
}
}
}
+ // magic section$end symbol always sorts to the end of its section
+ if ( left->getContentType() == ObjectFile::Atom::kSectionEnd )
+ return false;
+ if ( right->getContentType() == ObjectFile::Atom::kSectionEnd )
+ return true;
+
// the __common section can have real or tentative definitions
// we want the real ones to sort before tentative ones
bool leftIsTent = (left->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition);
if ( leftIsTent != rightIsTent )
return rightIsTent;
- // magic section$end symbol always sorts to the end of its section
- if ( left->getContentType() == ObjectFile::Atom::kSectionEnd )
- return false;
- if ( right->getContentType() == ObjectFile::Atom::kSectionEnd )
- return true;
-
// initializers are auto sorted to start of section
if ( !fInitializerSet.empty() ) {
bool leftFirst = (fInitializerSet.count(left) != 0);
static bool sDumpStabs = false;
static bool sSort = true;
static bool sNMmode = false;
-static cpu_type_t sPreferredArch = CPU_TYPE_POWERPC64;
+static cpu_type_t sPreferredArch = CPU_TYPE_I386;
+static cpu_subtype_t sPreferredSubArch = 0xFFFFFFFF;
static const char* sMatchName;
static int sPrintRestrict;
static int sPrintAlign;
const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) {
- p = p + OSSwapBigToHostInt32(archs[i].offset);
- mh = (struct mach_header*)p;
+ if ( ((uint32_t)sPreferredSubArch == 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch == OSSwapBigToHostInt32(archs[i].cpusubtype)) ) {
+ p = p + OSSwapBigToHostInt32(archs[i].offset);
+ mh = (struct mach_header*)p;
+ break;
+ }
}
}
}
sPreferredArch = CPU_TYPE_X86_64;
else if ( strcmp(arch, "arm") == 0 )
sPreferredArch = CPU_TYPE_ARM;
- else if ( strcmp(arch, "armv6") == 0 )
+ else if ( strcmp(arch, "armv4t") == 0 ) {
+ sPreferredArch = CPU_TYPE_ARM;
+ sPreferredSubArch = CPU_SUBTYPE_ARM_V4T;
+ }
+ else if ( strcmp(arch, "armv5") == 0 ) {
+ sPreferredArch = CPU_TYPE_ARM;
+ sPreferredSubArch = CPU_SUBTYPE_ARM_V5TEJ;
+ }
+ else if ( strcmp(arch, "armv6") == 0 ) {
+ sPreferredArch = CPU_TYPE_ARM;
+ sPreferredSubArch = CPU_SUBTYPE_ARM_V6;
+ }
+ else if ( strcmp(arch, "armv7") == 0 ) {
sPreferredArch = CPU_TYPE_ARM;
+ sPreferredSubArch = CPU_SUBTYPE_ARM_V7;
+ }
else
throwf("unknown architecture %s", arch);
}
bool fWriteableSegmentWithAddrOver4G;
const macho_segment_command<P>* fFirstSegment;
const macho_segment_command<P>* fFirstWritableSegment;
+ uint32_t fSectionCount;
};
MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path)
: fHeader(NULL), fLength(fileLength), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fDynamicSymbolTable(NULL), fIndirectTableCount(0),
fLocalRelocations(NULL), fLocalRelocationsCount(0), fExternalRelocations(NULL), fExternalRelocationsCount(0),
- fWriteableSegmentWithAddrOver4G(false), fFirstSegment(NULL), fFirstWritableSegment(NULL)
+ fWriteableSegmentWithAddrOver4G(false), fFirstSegment(NULL), fFirstWritableSegment(NULL), fSectionCount(0)
{
// sanity check
if ( ! validFile(fileContent) )
throwf("section %s file offset not within segment", sect->sectname());
}
checkSection(segCmd, sect);
+ ++fSectionCount;
}
}
cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
if ( externalNames.find(symName) != externalNames.end() )
throwf("undefine with same name as external symbol: %s", symName);
}
+ // verify all N_SECT values are valid
+ for(const macho_nlist<P>* p = fSymbols; p < &fSymbols[fSymbolCount]; ++p) {
+ uint8_t type = p->n_type();
+ if ( ((type & N_STAB) == 0) && ((type & N_TYPE) == N_SECT) ) {
+ if ( p->n_sect() > fSectionCount ) {
+ throwf("symbol '%s' has n_sect=%d which is too large", &fStrings[p->n_strx()], p->n_sect());
+ }
+ }
+ }
}
}
${CC} ${CCFLAGS} main.c -lfoobar-${ARCH} -L. -o main-${ARCH}
${FAIL_IF_BAD_MACHO} main-${ARCH}
nm main-${ARCH} | grep "_bar" | ${PASS_IFF_EMPTY}
- ${CC} ${CCFLAGS} main.c -all_load -lfoobar-${ARCH} -L. -o main-${ARCH}
+ ${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoobar-${ARCH}.a -o main-${ARCH}
${FAIL_IF_BAD_MACHO} main-${ARCH}
clean:
${CC} ${CCFLAGS} foo.c -c -o foo-${ARCH}.o
${CC} ${CCFLAGS} bar.c -c -o bar-${ARCH}.o
libtool -static foo-${ARCH}.o bar-${ARCH}.o -o libfoobar-${ARCH}.a
- ${CC} ${CCFLAGS} main.c -lfoobar-${ARCH} -lfoobar-${ARCH} -L. -o main-${ARCH} -all_load
+ ${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoobar-${ARCH}.a -lfoobar-${ARCH} -L. -o main-${ARCH}
${FAIL_IF_BAD_MACHO} main-${ARCH}
- ${CC} ${CCFLAGS} main.c ./libfoobar-${ARCH}.a ./libfoobar-${ARCH}.a -L. -o main-${ARCH} -all_load
+ ${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoobar-${ARCH}.a ./libfoobar-${ARCH}.a -L. -o main-${ARCH}
${PASS_IFF_GOOD_MACHO} main-${ARCH}
clean:
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/7043256> ld64 can not find a -e entry point from an archive
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ libtool -static foo.o -o libfoo.a
+ ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} bar.c -Os libfoo.a -dead_strip -o foo -Wl,-e,_foo
+ ${PASS_IFF_GOOD_MACHO} foo
+
+clean:
+ rm -rf foo libfoo.a foo.o
+
--- /dev/null
+
+void bar() {}
+
+
--- /dev/null
+
+
+void foo() {}
+
+
+
--- /dev/null
+##
+# Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that the n_sect number for __mh_dylib_header is valid when there is no __text section
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib justdata.c -o libjustdata.dylib -Wl,-no_compact_unwind
+ ${PASS_IFF_GOOD_MACHO} libjustdata.dylib
+ ${CC} ${CCFLAGS} -dynamiclib empty.c -o libempty.dylib -Wl,-no_compact_unwind
+ ${PASS_IFF_GOOD_MACHO} libempty.dylib
+
+clean:
+ rm -rf libempty.dylib libjustdata.dylib
--- /dev/null
+int data = 1;
all:
${CC} ${CCFLAGS} -static -fno-common -mkernel -c mykext.c -o mykext.o
${CC} ${CCFLAGS} -static -fno-common -mkernel -c mykextinfo.c -o mykextinfo.o
- ${CC} ${CCFLAGS} -Wl,-kext mykext.o mykextinfo.o -nostdlib -lkmodc++ -lkmod -lcc_kext -o mykext
+ unset LD_NO_CLASSIC_LINKER_STATIC && ${CC} ${CCFLAGS} -Wl,-kext mykext.o mykextinfo.o -nostdlib -lkmodc++ -lkmod -lcc_kext -o mykext -Wl,-w
otool -hv mykext | grep ${FILE_TYPE} | ${FAIL_IF_EMPTY}
nm -nm mykext | grep '(undefined) external _extern_global' | ${FAIL_IF_EMPTY}
nm -nm mykext | grep '(__DATA,__data) external _my_global' | ${FAIL_IF_EMPTY}
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that ld resolves the magic section start/end symbols.
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} common.c -o common
+ otool -lv common | grep -A8 __common | grep S_ZEROFILL | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_BAD_MACHO} common
+ ${CC} ${CCFLAGS} bss.c -o bss
+ otool -lv bss | grep -A8 __bss | grep S_ZEROFILL | ${FAIL_IF_EMPTY}
+ ${FAIL_IF_BAD_MACHO} bss
+ ${CC} ${CCFLAGS} both.c -o both
+ otool -lv both | grep -A8 __common | grep S_ZEROFILL | ${FAIL_IF_EMPTY}
+ otool -lv both | grep -A8 __bss | grep S_ZEROFILL | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} both
+
+clean:
+ rm -f common bss both
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+
+extern int bss_start __asm("section$start$__DATA$__bss");
+extern int bss_end __asm("section$end$__DATA$__bss");
+extern int common_start __asm("section$start$__DATA$__common");
+extern int common_end __asm("section$end$__DATA$__common");
+
+int mycommon[2];
+static int mybss[2];
+
+int main()
+{
+ mybss[0] = 0;
+ printf("bss start = %p\n", &bss_start);
+ printf("bss end = %p\n", &bss_end);
+ printf("common start = %p\n", &common_start);
+ printf("common end = %p\n", &common_end);
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+
+extern int bss_start __asm("section$start$__DATA$__bss");
+extern int bss_end __asm("section$end$__DATA$__bss");
+
+static int mybss[2];
+
+int main()
+{
+ mybss[0] = 0;
+ printf("bss start = %p\n", &bss_start);
+ printf("bss end = %p\n", &bss_end);
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+
+extern int common_start __asm("section$start$__DATA$__common");
+extern int common_end __asm("section$end$__DATA$__common");
+
+int mycommon[2];
+
+int main()
+{
+ printf("common start = %p\n", &common_start);
+ printf("common end = %p\n", &common_end);
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that ld can link a static executable with a weak definition
+#
+
+all:
+ ${CC} ${CCFLAGS} test.c -static -o test -e _entry -nostdlib -Wl,-new_linker
+ ${PASS_IFF_GOOD_MACHO} test
+
+clean:
+ rm -rf test
--- /dev/null
+
+
+
+__attribute__((weak)) int foo()
+{
+ return 0;
+}
+
+
+int entry()
+{
+ return foo();
+}