+----- Tagged ld64-97.14
+
+2010-04-20 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7712869> if last section is zero-fill don't add size to filesize total in -r mode
+
+----- Tagged ld64-97.13
+
+2010-03-17 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7824112> Support for iPhoneSimulator with OBJC 2.0 ABI
+
+
+----- Tagged ld64-97.12
+
+2010-03-17 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7712869> if last section is zero-fill don't add size to filesize total in -r mode
+
+----- Tagged ld64-97.11
+
+2010-01-26 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7622634> Libc-624.1 causes latent ld bug
+ * build linker -no_pie
+
+
+----- Tagged ld64-97.10
+
+2010-01-26 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7556912> LC_SEGMENT command 0 filesize field greater than vmsize field
+ * Move __DATA to end in -r mode
+
+
+2010-01-26 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7516793> symboled __ustring strings of just 0x0000 mis-parsed
+ * Parse __ustring section based on content - not just labels
+
+
+----- Tagged ld64-97.9
+
+2010-01-14 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7532743> LC_SEGMENT command 0 filesize field greater than vmsize field
+ * for i386 -r mode sort __IMPORT segment before __DATA segment
+
+
+2010-01-11 Nick Kledzik <kledzik@apple.com>
+
+ * fix ARM -r -d references to tentative definitions
+
+----- Tagged ld64-97.8
+
+2009-12-08 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7455147> many mach-o images in Barolo have MH_WEAK_DEFINES bit incorrectly set
+ * don't let auto-strip weak symbols set MH_WEAK_DEFINES
+
+
+----- Tagged ld64-97.7
+
+2009-11-30 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7429384> llvmgcc now puts const short arrays in __ustring section, linker does not handle that
+ * Only auto-coalesce UTF16 strings that are labeled with "___utf16_string*"
+
+
+----- Tagged ld64-97.6
+
+2009-11-06 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7332627> make -pie default for x86_64 for 10.7 and later
+
+
+2009-10-28 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7331635> Add a -no_pie flag
+ * support -no_pie and LD_NO_PIE
+
+
+----- Tagged ld64-97.5
+
+2009-10-27 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7341117> crash when __ustring section has zero length string
+ * stop trying to suppress tailing 0x0000 from synthesized string used to coalese utf16 strings
+
+
+----- Tagged ld64-97.4
+
+2009-10-21 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7320293> missing thumb bit when thumb function takes address of itself
+ * move toao.atom == srcao.atom test to after fromao.atom == srcao.atom test
+
+
+----- Tagged ld64-97.3
+
+2009-10-06 Nick Kledzik <kledzik@apple.com>
+
+ * Add missing LittleEndian::set32() in arm::kPointerDiff
+
+2009-10-05 Nick Kledzik <kledzik@apple.com>
+
+ <rdar://problem/7268427> ARM: handle pointer-diff to weak thumb that is overridden by non-weak ARM
+ * When parsing ARM relocations, if target is a thumb function, remove one from addend
+ * When writing out content for arm::kPointerDiff, add one if target is thumb
+ * When writing ARM_RELOC_SECTDIFF, use target offsets if they fit in function
+
+
----- Tagged ld64-97.2
2009-09-25 Nick Kledzik <kledzik@apple.com>
.Ss Options when creating a main executable
.Bl -tag
.It Fl pie
-This makes a special kind of main executable that is position independent (PIE). On Mac OS X 10.5, the OS
-will load a PIE at a random address each time it is executed. You cannot create a PIE from .o files compiled
+This makes a special kind of main executable that is position independent (PIE). On Mac OS X 10.5 and later, the OS
+the OS will load a PIE at a random address each time it is executed. You cannot create a PIE from .o files compiled
with -mdynamic-no-pic. That means the codegen is less optimal, but the address randomization adds some
-security.
+security. When targeting Mac OS X 10.7 or later PIE is the default for x86_64 main executables.
+.It Fl no_pie
+Do not make a position independent executable (PIE). This is the default, except for x86_64 for 10.7 or later.
.It Fl pagezero_size Ar size
By default the linker creates an unreadable segment starting at address zero named __PAGEZERO. Its existence
will cause a bus error if a NULL pointer is dereferenced. The argument
INSTALL_PATH = /usr/bin;
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
OTHER_LDFLAGS = (
+ "-Wl,-no_pie",
"@$(DERIVED_FILE_DIR)/linker_opts",
"-Wl,-exported_symbol,__mh_execute_header",
);
char* s = &name[13];
const uint16_t* words = (uint16_t*)((char*)(owner.fHeader) + section->offset() + addr - section->addr());
unsigned int wordCount = size/2;
- // note, the compiler sometimes puts trailing zeros on the end of the data
- if ( E::get32(words[wordCount-1]) == 0 )
- --wordCount;
bool needSeperator = false;
for(unsigned int i=0; i < wordCount; ++i) {
if ( needSeperator )
}
}
}
- else if ( (strcmp(sect->sectname(), "__ustring") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) ) {
- // if there is a __ustring section parse it into AnonymousAtoms based on labels
+ else if ( (strcmp(sect->sectname(), "__ustring") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) && (sect->size() != 0) ) {
+ // if there is a __ustring section parse it into atoms
fUTF16Section = sect;
+ // first find all cleave points
+ const uint16_t* words = (uint16_t*)((char*)(fHeader) + fUTF16Section->offset());
+ unsigned int wordCount = fUTF16Section->size()/2;
std::vector<pint_t> utf16Addreses;
+ bool inString = false;
+ for (unsigned int i=0; i < wordCount; ++i) {
+ if ( inString ) {
+ if ( words[i] == 0x0000 ) {
+ inString = false;
+ }
+ }
+ else {
+ if ( words[i] == 0x0000 ) {
+ // skip over zero padding
+ }
+ else {
+ inString = true;
+ utf16Addreses.push_back(fUTF16Section->addr() + i*2);
+ }
+ }
+ }
+ utf16Addreses.push_back(fUTF16Section->addr() + sect->size());
+ // build map of symbols
+ std::map<pint_t, const macho_nlist<P>* > symbolMap;
for (int i=fSymbolCount-1; i >= 0 ; --i) {
const macho_nlist<P>& sym = fSymbols[i];
if ( (sym.n_type() & N_STAB) == 0 ) {
uint8_t type = (sym.n_type() & N_TYPE);
if ( type == N_SECT ) {
if ( &fSectionsStart[sym.n_sect()-1] == fUTF16Section ) {
- utf16Addreses.push_back(sym.n_value());
+ // rdar://problem/7429384 don't coalesce UTF16 strings unless label starts with ___utf16_string
+ if ( strncmp(&fStrings[sym.n_strx()], "___utf16_string", 15) != 0 ) {
+ symbolMap[sym.n_value()] = &sym;
+ // <rdar://problem/7516793> if this symbol is a string of just 0x0000, it may not be in utf16Addreses
+ if ( words[(sym.n_value() - sect->addr())/2] == 0x0000 ) {
+ for(typename std::vector<pint_t>::iterator sit=utf16Addreses.begin(); sit != utf16Addreses.end(); ++sit) {
+ if ( *sit == sym.n_value() ) {
+ // already in utf16Addreses
+ break;
+ }
+ if ( *sit > sym.n_value() ) {
+ // need to insert
+ utf16Addreses.insert(sit, sym.n_value());
+ break;
+ }
+ }
+ }
+ }
}
}
}
}
- utf16Addreses.push_back(fUTF16Section->addr()+fUTF16Section->size());
- std::sort(utf16Addreses.begin(), utf16Addreses.end());
+ // make atom for each string
for(int i=utf16Addreses.size()-2; i >=0 ; --i) {
pint_t size = utf16Addreses[i+1] - utf16Addreses[i];
- AnonymousAtom<A>* strAtom = new AnonymousAtom<A>(*this, fUTF16Section, utf16Addreses[i], size);
- fAtoms.push_back(strAtom);
- fAddrToAtom[utf16Addreses[i]] = strAtom;
+ typename std::map<pint_t, const macho_nlist<P>* >::iterator pos = symbolMap.find(utf16Addreses[i]);
+ if ( pos == symbolMap.end() ) {
+ AnonymousAtom<A>* strAtom = new AnonymousAtom<A>(*this, fUTF16Section, utf16Addreses[i], size);
+ fAtoms.push_back(strAtom);
+ fAddrToAtom[utf16Addreses[i]] = strAtom;
+ }
+ else {
+ SymbolAtom<A>* newAtom = new SymbolAtom<A>(*this, pos->second, fUTF16Section);
+ fAtoms.push_back(newAtom);
+ fAddrToAtom[utf16Addreses[i]] = newAtom;
+ newAtom->setSize(size);
+ }
}
}
}
if ( weakImport )
kind = arm::kPointerWeakImport;
if ( reloc->r_extern() ) {
+ const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
+ if ( (targetSymbol->n_desc() & N_ARM_THUMB_DEF) && (pointerValue == 1) )
+ pointerValue = 0;
makeByNameReference(kind, srcAddr, targetName, pointerValue);
}
else {
else {
const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
+ int32_t addend;
srcAddr = sect->addr() + sreloc->r_address();
dstAddr = sreloc->r_value();
uint32_t betterDstAddr;
AtomAndOffset toao = findAtomAndOffset(dstAddr);
// check for addend encoded in the section content
pointerValue = LittleEndian::get32(*fixUpPtr);
+ addend = pointerValue - (dstAddr - nextRelocValue);
+ if ( toao.atom->isThumb() && (addend & 1) )
+ addend &= -2; // remove thumb bit
if ( (dstAddr - nextRelocValue) != pointerValue ) {
- if ( toao.atom == srcao.atom )
- toao.offset += (pointerValue + nextRelocValue) - dstAddr;
- else if ( fromao.atom == srcao.atom )
- toao.offset += (pointerValue + nextRelocValue) - dstAddr;
+ if ( fromao.atom == srcao.atom ) {
+ if ( ((const macho_section<P>*)(((BaseAtom*)(srcao.atom))->getSectionRecord()))->flags() & S_ATTR_PURE_INSTRUCTIONS ) {
+ int pcBaseOffset = srcao.atom->isThumb() ? 4 : 8;
+ if ( addend == -pcBaseOffset ) {
+ fromao.offset -= addend;
+ }
+ else {
+ toao.offset += addend;
+ }
+ }
+ else {
+ toao.offset += addend;
+ }
+ }
+ else if ( toao.atom == srcao.atom )
+ toao.offset += addend;
else
- fromao.offset += (dstAddr - pointerValue) - nextRelocValue;
+ fromao.offset -= addend;
}
new Reference<arm>(arm::kPointerDiff, srcao, fromao, toao);
}
{
public:
ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcContraint,
- bool objcReplacementClasses);
+ bool objcReplacementClasses, bool abi2override);
virtual const char* getName() const { return "objc$info"; }
virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
virtual uint64_t getSize() const { return 8; }
virtual const char* getSectionName() const;
virtual void copyRawContent(uint8_t buffer[]) const;
private:
- Segment& getInfoSegment() const;
+ Segment& getInfoSegment(bool abi2override) const;
+ bool fAbi2override;
uint32_t fContent[2];
};
template <typename A>
ObjectFile::Atom& Writer<A>::makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses)
{
- return *(new ObjCInfoAtom<A>(*this, objcContraint, objcReplacementClasses));
+
+ return *(new ObjCInfoAtom<A>(*this, objcContraint, objcReplacementClasses, fOptions.objCABIVersion2POverride()));
}
template <typename A>
else
sreloc1->set_r_type(ARM_RELOC_SECTDIFF);
sreloc1->set_r_address(address);
- sreloc1->set_r_value(target.getAddress());
+ if ( ref->getTargetOffset() >= target.getSize() )
+ sreloc1->set_r_value(target.getAddress());
+ else
+ sreloc1->set_r_value(target.getAddress()+ref->getTargetOffset());
sreloc2->set_r_scattered(true);
sreloc2->set_r_pcrel(false);
sreloc2->set_r_length(2);
sreloc2->set_r_type(ARM_RELOC_PAIR);
sreloc2->set_r_address(0);
- if ( &ref->getFromTarget() == atom )
- sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
+ if ( &ref->getFromTarget() == atom ) {
+ unsigned int pcBaseOffset = atom->isThumb() ? 4 : 8;
+ if ( (ref->getFromTargetOffset() > pcBaseOffset) && (strncmp(atom->getSectionName(), "__text", 6) == 0) ) {
+ sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset()-pcBaseOffset);
+ }
+ else
+ sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
+ }
else
sreloc2->set_r_value(ref->getFromTarget().getAddress());
fSectionRelocs.push_back(reloc2);
uint32_t firstDisp;
uint32_t nextDisp;
uint32_t opcode = 0;
+ int32_t diff;
bool relocateableExternal = false;
bool is_bl;
bool is_blx;
}
break;
case arm::kPointerDiff:
- LittleEndian::set32(*fixUp,
- (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
+ diff = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
+ if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
+ diff |= 1;
+ LittleEndian::set32(*fixUp, diff);
break;
case arm::kReadOnlyPointer:
if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
uint32_t firstDisp;
uint32_t nextDisp;
uint32_t opcode = 0;
+ int32_t diff;
bool relocateableExternal = false;
bool is_bl;
bool is_blx;
case arm::kPointer:
case arm::kReadOnlyPointer:
case arm::kPointerWeakImport:
- {
if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
// indirect symbol table has INDIRECT_SYMBOL_LOCAL, so we must put address in content
if ( this->indirectSymbolInRelocatableIsLocal(ref) )
}
}
else {
- // internal relocation
- if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
- // pointer contains target address
- if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
+ // internal relocation => pointer contains target address
+ if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
targetAddr |= 1;
- LittleEndian::set32(*fixUp, targetAddr);
- }
- else {
- // pointer contains addend
- LittleEndian::set32(*fixUp, ref->getTargetOffset());
- }
- }
+ LittleEndian::set32(*fixUp, targetAddr);
}
break;
case arm::kPointerDiff:
- LittleEndian::set32(*fixUp,
- (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
+ diff = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
+ if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
+ diff |= 1;
+ LittleEndian::set32(*fixUp, diff);
break;
case arm::kDtraceProbeSite:
case arm::kDtraceIsEnabledSite:
cmd->set_vmaddr(sectInfo->getBaseAddress());
cmd->set_fileoff(sectInfo->fFileOffset);
}
- cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
+ // <rdar://problem/7712869> if last section is zero-fill don't add size to filesize total
+ if ( !sectInfo->fAllZeroFill ) {
+ cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
+ }
cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
}
sect->set_sectname(sectInfo->fSectionName);
template <typename A>
-ObjCInfoAtom<A>::ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, bool objcReplacementClasses)
- : WriterAtom<A>(writer, getInfoSegment())
+ObjCInfoAtom<A>::ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcConstraint,
+ bool objcReplacementClasses, bool abi2override)
+ : WriterAtom<A>(writer, getInfoSegment(abi2override)), fAbi2override(abi2override)
{
fContent[0] = 0;
uint32_t value = 0;
// objc info section is in a different segment and section for 32 vs 64 bit runtimes
template <> const char* ObjCInfoAtom<ppc>::getSectionName() const { return "__image_info"; }
-template <> const char* ObjCInfoAtom<x86>::getSectionName() const { return "__image_info"; }
+template <> const char* ObjCInfoAtom<x86>::getSectionName() const { return fAbi2override ? "__objc_imageinfo" : "__image_info"; }
template <> const char* ObjCInfoAtom<arm>::getSectionName() const { return "__objc_imageinfo"; }
template <> const char* ObjCInfoAtom<ppc64>::getSectionName() const { return "__objc_imageinfo"; }
template <> const char* ObjCInfoAtom<x86_64>::getSectionName() const { return "__objc_imageinfo"; }
-template <> Segment& ObjCInfoAtom<ppc>::getInfoSegment() const { return Segment::fgObjCSegment; }
-template <> Segment& ObjCInfoAtom<x86>::getInfoSegment() const { return Segment::fgObjCSegment; }
-template <> Segment& ObjCInfoAtom<ppc64>::getInfoSegment() const { return Segment::fgDataSegment; }
-template <> Segment& ObjCInfoAtom<x86_64>::getInfoSegment() const { return Segment::fgDataSegment; }
-template <> Segment& ObjCInfoAtom<arm>::getInfoSegment() const { return Segment::fgDataSegment; }
+template <> Segment& ObjCInfoAtom<ppc>::getInfoSegment(bool abi2override) const { return Segment::fgObjCSegment; }
+template <> Segment& ObjCInfoAtom<x86>::getInfoSegment(bool abi2override) const { return abi2override ? Segment::fgDataSegment : Segment::fgObjCSegment; }
+template <> Segment& ObjCInfoAtom<ppc64>::getInfoSegment(bool abi2override) const { return Segment::fgDataSegment; }
+template <> Segment& ObjCInfoAtom<x86_64>::getInfoSegment(bool abi2override) const { return Segment::fgDataSegment; }
+template <> Segment& ObjCInfoAtom<arm>::getInfoSegment(bool abi2override) const { return Segment::fgDataSegment; }
fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false),
fTraceOutputFile(NULL), fMacVersionMin(kMinMacVersionUnset), fIPhoneVersionMin(kMinIPhoneVersionUnset) {}
enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
- enum MacVersionMin { kMinMacVersionUnset, k10_1, k10_2, k10_3, k10_4, k10_5, k10_6 };
+ enum MacVersionMin { kMinMacVersionUnset, k10_1, k10_2, k10_3, k10_4, k10_5, k10_6, k10_7 };
enum IPhoneVersionMin { kMinIPhoneVersionUnset, k2_0, k2_1, k2_2, k3_0, k3_1, k3_2, k4_0 };
struct AliasPair {
fVerbose(false), fKeepRelocations(false), fWarnStabs(false),
fTraceDylibSearching(false), fPause(false), fStatistics(false), fPrintOptions(false),
fSharedRegionEligible(false), fPrintOrderFileStatistics(false),
- fReadOnlyx86Stubs(false), fPositionIndependentExecutable(false), fMaxMinimumHeaderPad(false),
+ fReadOnlyx86Stubs(false), fPositionIndependentExecutable(false),
+ fDisablePositionIndependentExecutable(false), fMaxMinimumHeaderPad(false),
fDeadStripDylibs(false), fAllowTextRelocs(false), fWarnTextRelocs(false),
fUsingLazyDylibLinking(false), fEncryptable(true),
fOrderData(true), fMarkDeadStrippableDylib(false),
fMakeClassicDyldInfo(true), fMakeCompressedDyldInfo(true), fAllowCpuSubtypeMismatches(false),
- fUseSimplifiedDylibReExports(false), fSaveTempFiles(false)
+ fUseSimplifiedDylibReExports(false), fObjCABIVersion2POverride(false), fSaveTempFiles(false)
{
this->checkForClassic(argc, argv);
this->parsePreCommandLineEnvironmentSettings();
case 6:
fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_6;
break;
+ case 7:
+ fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_7;
+ break;
default:
- fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_6;
+ fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_7;
break;
}
}
else if ( strcmp(arg, "-pie") == 0 ) {
fPositionIndependentExecutable = true;
}
+ else if ( strcmp(arg, "-no_pie") == 0 ) {
+ fDisablePositionIndependentExecutable = true;
+ }
else if ( strncmp(arg, "-reexport-l", 11) == 0 ) {
FileInfo info = findLibrary(&arg[11], true);
info.options.fReExport = true;
else if ( strcmp(arg, "-no_zero_fill_sections") == 0 ) {
fReaderOptions.fOptimizeZeroFill = false;
}
+ else if ( strcmp(arg, "-objc_abi_version") == 0 ) {
+ const char* version = argv[++i];
+ if ( version == NULL )
+ throw "-objc_abi_version missing version number";
+ if ( strcmp(version, "2") == 0 )
+ fObjCABIVersion2POverride = true;
+ else
+ warning("ignoring unrecognized argument (%s) to -objc_abi_version", version);
+ }
else {
throwf("unknown option: %s", arg);
}
fMakeCompressedDyldInfo = false;
fMakeClassicDyldInfo = true;
}
+ // temporary until projects adopt -no_pie
+ if ( getenv("LD_NO_PIE") != NULL ) {
+ warning("LD_NO_PIE being used to disble building a position independent executable");
+ fDisablePositionIndependentExecutable = true;
+ }
sWarningsSideFilePath = getenv("LD_WARN_FILE");
}
// Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB
if ( minOS(ObjectFile::ReaderOptions::k10_5, ObjectFile::ReaderOptions::k2_0) )
fUseSimplifiedDylibReExports = true;
+
+ // x86_64 for MacOSX 10.7 defaults to PIE
+ if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind == kDynamicExecutable)
+ && (fReaderOptions.fMacVersionMin >= ObjectFile::ReaderOptions::k10_7) ) {
+ fPositionIndependentExecutable = true;
+ }
}
void Options::checkIllegalOptionCombinations()
if ( strncmp(name, ".objc_class_name_", 17) == 0 ) {
// rdar://problem/4718189 map ObjC class names to new runtime names
switch (fArchitecture) {
+ case CPU_TYPE_I386:
+ // i386 only uses new symbols when using objc2 ABI
+ if ( !fObjCABIVersion2POverride )
+ break;
+ // when using objc2 ABI to same as archs below
case CPU_TYPE_POWERPC64:
case CPU_TYPE_X86_64:
case CPU_TYPE_ARM:
if ( fPositionIndependentExecutable ) {
switch ( fOutputKind ) {
case Options::kDynamicExecutable:
+ // -no_pie anywhere on command line disable PIE
+ if ( fDisablePositionIndependentExecutable )
+ fPositionIndependentExecutable = false;
+ break;
case Options::kPreload:
break;
case Options::kDynamicLibrary:
bool markAutoDeadStripDylib() { return fMarkDeadStrippableDylib; }
bool removeEHLabels() { return fReaderOptions.fNoEHLabels; }
bool useSimplifiedDylibReExports() { return fUseSimplifiedDylibReExports; }
+ bool objCABIVersion2POverride() { return fObjCABIVersion2POverride; }
private:
class CStringEquals
bool fPrintOrderFileStatistics;
bool fReadOnlyx86Stubs;
bool fPositionIndependentExecutable;
+ bool fDisablePositionIndependentExecutable;
bool fMaxMinimumHeaderPad;
bool fDeadStripDylibs;
bool fAllowTextRelocs;
bool fNoEHLabels;
bool fAllowCpuSubtypeMismatches;
bool fUseSimplifiedDylibReExports;
+ bool fObjCABIVersion2POverride;
std::vector<const char*> fInitialUndefines;
NameSet fAllowedUndefined;
NameSet fWhyLive;
{
public:
static Section* find(const char* sectionName, const char* segmentName, bool zeroFill, bool untrustedZeroFill, bool createIfNeeded=true);
- static void assignIndexes();
+ static void assignIndexes(bool objfile);
const char* getName() { return fSectionName; }
private:
Section(const char* sectionName, const char* segmentName, bool zeroFill, bool untrustedZeroFill);
static NameToSection fgMapping;
static std::vector<Section*> fgSections;
static NameToOrdinal fgSegmentDiscoverOrder;
+ static bool fgMakingObjectFile;
};
Section::NameToSection Section::fgMapping;
std::vector<Section*> Section::fgSections;
Section::NameToOrdinal Section::fgSegmentDiscoverOrder;
+bool Section::fgMakingObjectFile;
Section::Section(const char* sectionName, const char* segmentName, bool zeroFill, bool untrustedZeroFill)
: fZeroFill(zeroFill), fUntrustedZeroFill(untrustedZeroFill)
if ( strcmp(segName, "__TEXT") == 0 )
return 2;
if ( strcmp(segName, "__DATA") == 0 )
- return 3;
+ return (fgMakingObjectFile ? 6 : 3); // __DATA is last in .o files and here in FLI
if ( strcmp(segName, "__OBJC") == 0 )
return 4;
- if ( strcmp(segName, "__OBJC2") == 0 )
+ if ( strcmp(segName, "__IMPORT") == 0 )
return 5;
if ( strcmp(segName, "__LINKEDIT") == 0 )
return INT_MAX; // linkedit segment should always sort last
return left->fIndex < right->fIndex;
}
-void Section::assignIndexes()
+void Section::assignIndexes(bool objfile)
{
//printf("unsorted sections:\n");
//for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
//}
// sort it
+ Section::fgMakingObjectFile = objfile;
std::sort(fgSections.begin(), fgSections.end(), Section::Sorter());
// assign correct section ordering to each Section object
//fprintf(stderr, "demote %s to hidden\n", name);
}
else if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
- // we do have an exported weak symbol, turn WEAK_DEFINES back on
- fGlobalSymbolTable.setHasExternalWeakDefinitions(true);
+ if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn ) {
+ // we do have an exported weak symbol, turn WEAK_DEFINES back on
+ fGlobalSymbolTable.setHasExternalWeakDefinitions(true);
+ }
}
}
else if ( scope == ObjectFile::Atom::scopeLinkageUnit ) {
void Linker::sortSections()
{
- Section::assignIndexes();
+ Section::assignIndexes(fOptions.outputKind() == Options::kObjectFile);
}
++fRequireCount; // added a tentative definition means loadUndefines() needs to continue
break;
case ObjectFile::Atom::kWeakDefinition:
- fHasExternalWeakDefinitions = true;
+ if ( newAtom.getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn )
+ fHasExternalWeakDefinitions = true;
break;
case ObjectFile::Atom::kExternalDefinition:
case ObjectFile::Atom::kExternalWeakDefinition:
.globl _test_loads
_test_loads:
@ PIC load of a
- ldr r0, L6
+ ldr r0, L100
L0:
ldr r0, [pc, r0]
@ PIC load of c
- ldr r0, L6+4
+ ldr r0, L100+4
L1:
ldr r0, [pc, r0]
@ sorta-absolute load of a
- ldr r0, L6+8
+ ldr r0, L100+8
ldr r0, [r0, #0]
@ sorta-absolute load of c
- ldr r0, L6+12
+ ldr r0, L100+12
ldr r0, [r0, #0]
@ sorta-absolute load of external
- ldr r0, L6+16
+ ldr r0, L100+16
ldr r0, [r0, #0]
@ PIC load of a + addend ??
bx lr
-L6:
+L100:
.long _a-(L0+8)
.long _c-(L1+8)
.long _a
@ call external + addend
bne _external+16
-_pointer_diffs:
nop
bl 1f
1: nop
+
+ .text
+_pointer_diffs:
.long _foo-1b
.long _foo+10-1b
.long _test_branches-1b
.long (_test_branches - _test_loads) + -2097152
.long (_test_calls - _test_loads) + -2097152
+ .text
+ .code 32
+_arm1:
+ bx lr
+_arm2:
+ bx lr
+ .weak_definition _arm3
+ .globl _arm3
+ .private_extern _arm3
+_arm3:
+ bx lr
+ .weak_definition _arm4
+ .globl _arm4
+ .private_extern _arm4
+_arm4:
+ bx lr
+
+ .code 16
+ .thumb_func _thumb1
+_thumb1:
+ bx lr
+ .thumb_func _thumb2
+_thumb2:
+ bx lr
+ .weak_definition _thumb3
+ .globl _thumb3
+ .private_extern _thumb3
+ .thumb_func _thumb3
+_thumb3:
+ bx lr
+ .weak_definition _thumb4
+ .globl _thumb4
+ .private_extern _thumb4
+ .thumb_func _thumb4
+_thumb4:
+ bx lr
+
+ .thumb_func _thumb_func_ref_test
+_thumb_func_ref_test:
+ push {r7, lr}
+ add r7, sp, #0
+ ldr r3, L6
+L2: add r3, pc
+ ldr r3, L7
+L3: add r3, pc
+ ldr r3, L8
+L4: add r3, pc
+ ldr r3, L9
+L5: add r3, pc
+ pop {r7, pc}
+ .align 2
+L6: .long _thumb1-(L2+4)
+L7: .long _thumb2-(L3+4)
+L7a:.long _thumb3-(L3+4)
+L7b:.long _thumb4-(L3+4)
+L8: .long _arm1-(L4+4)
+L9: .long _arm2-(L5+4)
+L9a:.long _arm3-(L5+4)
+L9b:.long _arm4-(L5+4)
+
+ .code 32
+ .align 2
+_arm_func_ref_test:
+ push {r7, lr}
+ add r7, sp, #0
+ ldr r3, L16
+L12:add r3, pc
+ ldr r3, L17
+L13:add r3, pc
+ ldr r3, L18
+L14:add r3, pc
+ ldr r3, L19
+L15:add r3, pc
+ pop {r7, pc}
+ .align 2
+L16: .long _thumb1-(L12+8)
+L17: .long _thumb2-(L13+8)
+L17a: .long _thumb3-(L3+8)
+L17b: .long _thumb4-(L3+8)
+L18: .long _arm1-(L14+8)
+L19: .long _arm2-(L15+8)
+L19a: .long _arm3-(L15+8)
+L19b: .long _arm4-(L15+8)
+
+ .section __DATA,__const
+_myVTable:
+ .long _thumb1
+ .long _thumb2
+ .long _thumb3
+ .long _arm1
+ .long _arm2
+
#endif
#if __ppc__ || __ppc64__
.long _test_branches - .
.long _test_branches - . + 8
.long _test_branches - . - 8
+ .long 0
+ .long 0
#if __ppc64__
.quad Llocal2-_test_branches
#endif
--- /dev/null
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Test that references to commons survive -r -d
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} test.c -c -o test.${ARCH}.o
+ ${OBJECTDUMP} -no_content test.${ARCH}.o | grep -v kind: | grep -v section: > test.${ARCH}.o.dump
+
+ ${LD} -arch ${ARCH} -r -d test.${ARCH}.o -o test-r-d.${ARCH}.o
+ ${OBJECTDUMP} -no_content test-r-d.${ARCH}.o | grep -v kind: | grep -v section: > test-r-d.${ARCH}.o.dump
+
+ ${PASS_IFF} diff test.${ARCH}.o.dump test-r-d.${ARCH}.o.dump
+
+
+clean:
+ rm -rf *.o *.dump
+
--- /dev/null
+
+void foo() {}
+
+int a;
+int b;
+int c;
+
+
+
+int* pa = &a;
+int* pb = &b;
+int* pc = &c;
+
##
-# Copyright (c) 2008 Apple Inc. All rights reserved.
+# Copyright (c) 2008-2009 Apple Inc. All rights reserved.
#
# @APPLE_LICENSE_HEADER_START@
#
otool -hv main | grep WEAK_DEFINES | ${FAIL_IF_STDIN}
${CC} ${CCFLAGS} main.c -o main -Wl,-exported_symbol,_my_weak
otool -hv main | grep WEAK_DEFINES | ${FAIL_IF_EMPTY}
+ ${CC} ${CCFLAGS} main-strip-weak.c -o main-strip-weak
+ otool -hv main-strip-weak | grep WEAK_DEFINES | ${FAIL_IF_STDIN}
${PASS_IFF_GOOD_MACHO} main
clean:
- rm main
+ rm main main-strip-weak
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+
+// the 'l' prefix makes this an auto-strip symbol
+void my_auto_strip_weak() __asm ( "lautostrip" );
+
+void __attribute__((weak)) my_auto_strip_weak()
+{
+
+}
+
+int main()
+{
+ my_auto_strip_weak();
+ return 0;
+}
+