#include <unistd.h>
#include <vector>
+#include <unordered_map>
#include "Options.h"
#include "ld.hpp"
// overrides of ld::Atom
virtual ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual uint64_t objectAddress() const { return 0; }
virtual void encode() = 0;
uint32_t currentOffset();
private:
- class CStringEquals
- {
- public:
- bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
- };
enum { kBufferSize = 0x01000000 };
- typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
+ typedef std::unordered_map<const char*, int32_t, CStringHash, CStringEquals> StringToOffset;
const uint32_t _pointerSize;
std::vector<char*> _fullBuffers;
uint32_t stringOffsetForStab(const ld::relocatable::File::Stab& stab, StringPoolAtom* pool);
uint64_t valueForStab(const ld::relocatable::File::Stab& stab);
uint8_t sectionIndexForStab(const ld::relocatable::File::Stab& stab);
-
+ bool isAltEntry(const ld::Atom* atom);
mutable std::vector<macho_nlist<P> > _globals;
mutable std::vector<macho_nlist<P> > _locals;
uint32_t _stabsIndexEnd;
static ld::Section _s_section;
+ static int _s_anonNameIndex;
+
};
template <typename A>
ld::Section SymbolTableAtom<A>::_s_section("__LINKEDIT", "__symbol_table", ld::Section::typeLinkEdit, true);
+template <typename A>
+int SymbolTableAtom<A>::_s_anonNameIndex = 1;
+
+template <typename A>
+bool SymbolTableAtom<A>::isAltEntry(const ld::Atom* atom)
+{
+ // alt entries have a group subordinate reference to the previous atom
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ if ( fit->kind == ld::Fixup::kindNoneGroupSubordinate ) {
+ if ( fit->binding == Fixup::bindingDirectlyBound ) {
+ const Atom* prevAtom = fit->u.target;
+ assert(prevAtom != NULL);
+ for (ld::Fixup::iterator fit2 = prevAtom->fixupsBegin(); fit2 != prevAtom->fixupsEnd(); ++fit2) {
+ if ( fit2->kind == ld::Fixup::kindNoneFollowOn ) {
+ if ( fit2->binding == Fixup::bindingDirectlyBound ) {
+ if ( fit2->u.target == atom )
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
template <typename A>
bool SymbolTableAtom<A>::addLocal(const ld::Atom* atom, StringPoolAtom* pool)
{
macho_nlist<P> entry;
- static int s_anonNameIndex = 1;
assert(atom->symbolTableInclusion() != ld::Atom::symbolTableNotIn);
// set n_strx
if ( atom->combine() == ld::Atom::combineByNameAndContent ) {
// don't use 'l' labels for x86_64 strings
// <rdar://problem/6605499> x86_64 obj-c runtime confused when static lib is stripped
- sprintf(anonName, "LC%u", s_anonNameIndex++);
+ sprintf(anonName, "LC%u", _s_anonNameIndex++);
symbolName = anonName;
}
}
}
else if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel ) {
// make auto-strip anonymous name for symbol
- sprintf(anonName, "l%03u", s_anonNameIndex++);
+ sprintf(anonName, "l%03u", _s_anonNameIndex++);
symbolName = anonName;
}
}
desc |= N_WEAK_DEF;
if ( atom->isThumb() )
desc |= N_ARM_THUMB_DEF;
+ if ( (this->_options.outputKind() == Options::kObjectFile) && this->_state.allObjectFilesScatterable && isAltEntry(atom) )
+ desc |= N_ALT_ENTRY;
entry.set_n_desc(desc);
// set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
macho_nlist<P> entry;
// set n_strx
- entry.set_n_strx(pool->add(atom->name()));
+ const char* symbolName = atom->name();
+ char anonName[32];
+ if ( this->_options.outputKind() == Options::kObjectFile ) {
+ if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel ) {
+ // make auto-strip anonymous name for symbol
+ sprintf(anonName, "l%03u", _s_anonNameIndex++);
+ symbolName = anonName;
+ }
+ }
+ entry.set_n_strx(pool->add(symbolName));
// set n_type
if ( atom->definition() == ld::Atom::definitionAbsolute ) {
entry.set_n_type(N_EXT | N_SECT | N_PEXT);
}
else if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)
- && (atom->section().type() == ld::Section::typeMachHeader) ) {
- // the __mh_execute_header is historical magic and must be an absolute symbol
+ && (atom->section().type() == ld::Section::typeMachHeader)
+ && !_options.positionIndependentExecutable() ) {
+ // the __mh_execute_header is historical magic in non-pie executabls and must be an absolute symbol
entry.set_n_type(N_EXT | N_ABS);
}
}
desc |= N_SYMBOL_RESOLVER;
if ( atom->dontDeadStrip() && (this->_options.outputKind() == Options::kObjectFile) )
desc |= N_NO_DEAD_STRIP;
+ if ( (this->_options.outputKind() == Options::kObjectFile) && this->_state.allObjectFilesScatterable && isAltEntry(atom) )
+ desc |= N_ALT_ENTRY;
if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) ) {
desc |= N_WEAK_DEF;
// <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
// set n_type
if ( this->_options.outputKind() == Options::kObjectFile ) {
- if ( (atom->scope() == ld::Atom::scopeLinkageUnit)
+ if ( atom->section().type() == ld::Section::typeTempAlias ) {
+ if ( atom->scope() == ld::Atom::scopeLinkageUnit )
+ entry.set_n_type(N_INDR | N_EXT | N_PEXT);
+ else
+ entry.set_n_type(N_INDR | N_EXT);
+ }
+ else if ( (atom->scope() == ld::Atom::scopeLinkageUnit)
&& (atom->definition() == ld::Atom::definitionTentative) )
entry.set_n_type(N_UNDF | N_EXT | N_PEXT);
else
// set n_value, zero for import proxy and size for tentative definition
if ( atom->definition() == ld::Atom::definitionTentative )
entry.set_n_value(atom->size());
- else
+ else if ( atom->section().type() != ld::Section::typeTempAlias )
entry.set_n_value(0);
+ else {
+ assert(atom->fixupsBegin() != atom->fixupsEnd());
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ assert(fit->kind == ld::Fixup::kindNoneFollowOn);
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingByNameUnbound:
+ entry.set_n_value(pool->add(fit->u.name));
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ entry.set_n_value(pool->add((_state.indirectBindingTable[fit->u.bindingIndex])->name()));
+ break;
+ default:
+ assert(0 && "internal error: unexpected alias binding");
+ }
+ }
+ }
// add to array
_imports.push_back(entry);
return ( (_stabsIndexStart != _stabsIndexEnd) || (_stabsStringsOffsetStart != _stabsStringsOffsetEnd) );
}
+
template <typename A>
void SymbolTableAtom<A>::encode()
{
// make nlist entries for all local symbols
std::vector<const ld::Atom*>& localAtoms = this->_writer._localAtoms;
+ std::vector<const ld::Atom*>& globalAtoms = this->_writer._exportedAtoms;
_locals.reserve(localAtoms.size()+this->_state.stabs.size());
this->_writer._localSymbolsStartIndex = 0;
// make nlist entries for all debug notes
// make nlist entries for all global symbols
- std::vector<const ld::Atom*>& globalAtoms = this->_writer._exportedAtoms;
_globals.reserve(globalAtoms.size());
this->_writer._globalSymbolsStartIndex = symbolIndex;
for (std::vector<const ld::Atom*>::const_iterator it=globalAtoms.begin(); it != globalAtoms.end(); ++it) {
// for kext bundles the reloc base address starts at __TEXT segment
return _options.baseAddress();
}
- // for all other kinds, the x86_64 reloc base address starts at __DATA segment
+ // for all other kinds, the x86_64 reloc base address starts at first writable segment (usually __DATA)
for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
ld::Internal::FinalSection* sect = *sit;
- if ( strcmp(sect->segmentName(), "__DATA") == 0 )
+ if ( !sect->isSectionHidden() && _options.initialSegProtection(sect->segmentName()) & VM_PROT_WRITE )
return sect->address;
}
- throw "__DATA segment not found";
+ throw "writable (__DATA) segment not found";
}
template <typename A>
// for x86_64 the reloc base address starts at __DATA segment
for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
ld::Internal::FinalSection* sect = *sit;
- if ( strcmp(sect->segmentName(), "__DATA") == 0 )
+ if ( !sect->isSectionHidden() && _options.initialSegProtection(sect->segmentName()) & VM_PROT_WRITE )
return sect->address;
}
- throw "__DATA segment not found";
+ throw "writable (__DATA) segment not found";
}
template <typename A>
return (_pointerLocations.size() + _callSiteLocations.size()) * sizeof(macho_relocation_info<P>);
}
+#if SUPPORT_ARCH_arm64
+template <> uint32_t ExternalRelocationsAtom<arm64>::pointerReloc() { return ARM64_RELOC_UNSIGNED; }
+#endif
+#if SUPPORT_ARCH_arm_any
template <> uint32_t ExternalRelocationsAtom<arm>::pointerReloc() { return ARM_RELOC_VANILLA; }
+#endif
template <> uint32_t ExternalRelocationsAtom<x86>::pointerReloc() { return GENERIC_RELOC_VANILLA; }
template <> uint32_t ExternalRelocationsAtom<x86_64>::pointerReloc() { return X86_64_RELOC_UNSIGNED; }
template <> uint32_t ExternalRelocationsAtom<x86_64>::callReloc() { return X86_64_RELOC_BRANCH; }
template <> uint32_t ExternalRelocationsAtom<x86>::callReloc() { return GENERIC_RELOC_VANILLA; }
+#if SUPPORT_ARCH_arm64
+template <> uint32_t ExternalRelocationsAtom<arm64>::callReloc() { return ARM64_RELOC_BRANCH26; }
+#endif
+
template <typename A>
uint32_t ExternalRelocationsAtom<A>::callReloc()
{
relocs.push_back(reloc1);
}
break;
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(X86_64_RELOC_TLV);
+ relocs.push_back(reloc1);
+ break;
default:
assert(0 && "need to handle -r reloc");
}
template <>
-void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection* sect,
+void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection* sect,
const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
{
macho_relocation_info<P> reloc1;
fromExternal = entry.fromTargetUsesExternalReloc;
fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
}
-
-
+
switch ( entry.kind ) {
case ld::Fixup::kindStoreX86PCRel32:
case ld::Fixup::kindStoreX86BranchPCRel32:
}
else {
// regular pointer
- if ( !external && (entry.toAddend != 0) ) {
- // use scattered reloc is target offset is non-zero
+ if ( !external && (entry.toAddend != 0) && (entry.toTarget->symbolTableInclusion() != ld::Atom::symbolTableNotIn) ) {
+ // use scattered reloc if target offset is non-zero into named atom (5658046)
sreloc1->set_r_scattered(true);
sreloc1->set_r_pcrel(false);
sreloc1->set_r_length(2);
relocs.push_back(reloc1);
}
break;
+ case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreX86Abs32TLVLoad:
+ case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(entry.kind == ld::Fixup::kindStoreX86PCRel32TLVLoad);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(GENERIC_RLEOC_TLV);
+ relocs.push_back(reloc1);
+ break;
default:
assert(0 && "need to handle -r reloc");
}
+
+#if SUPPORT_ARCH_arm_any
template <>
void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection* sect,
const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
}
}
+#endif
+#if SUPPORT_ARCH_arm64
+template <>
+void SectionRelocationsAtom<arm64>::encodeSectionReloc(ld::Internal::FinalSection* sect,
+ const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+ macho_relocation_info<P> reloc1;
+ macho_relocation_info<P> reloc2;
+ uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+ bool external = entry.toTargetUsesExternalReloc;
+ uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+ bool fromExternal = false;
+ uint32_t fromSymbolNum = 0;
+ if ( entry.fromTarget != NULL ) {
+ fromExternal = entry.fromTargetUsesExternalReloc;
+ fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
+ }
+
+
+ switch ( entry.kind ) {
+ case ld::Fixup::kindStoreARM64Branch26:
+ if ( entry.toAddend != 0 ) {
+ assert(entry.toAddend < 0x400000);
+ reloc2.set_r_address(address);
+ reloc2.set_r_symbolnum(entry.toAddend);
+ reloc2.set_r_pcrel(false);
+ reloc2.set_r_length(2);
+ reloc2.set_r_extern(false);
+ reloc2.set_r_type(ARM64_RELOC_ADDEND);
+ relocs.push_back(reloc2);
+ }
+ // fall into next case
+ case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+ case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+ case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_BRANCH26);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreARM64Page21:
+ if ( entry.toAddend != 0 ) {
+ assert(entry.toAddend < 0x400000);
+ reloc2.set_r_address(address);
+ reloc2.set_r_symbolnum(entry.toAddend);
+ reloc2.set_r_pcrel(false);
+ reloc2.set_r_length(2);
+ reloc2.set_r_extern(false);
+ reloc2.set_r_type(ARM64_RELOC_ADDEND);
+ relocs.push_back(reloc2);
+ }
+ // fall into next case
+ case ld::Fixup::kindStoreTargetAddressARM64Page21:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_PAGE21);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreARM64PageOff12:
+ if ( entry.toAddend != 0 ) {
+ assert(entry.toAddend < 0x400000);
+ reloc2.set_r_address(address);
+ reloc2.set_r_symbolnum(entry.toAddend);
+ reloc2.set_r_pcrel(false);
+ reloc2.set_r_length(2);
+ reloc2.set_r_extern(false);
+ reloc2.set_r_type(ARM64_RELOC_ADDEND);
+ relocs.push_back(reloc2);
+ }
+ // fall into next case
+ case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_PAGEOFF12);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreARM64GOTLoadPage21:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_GOT_LOAD_PAGE21);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+ case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_GOT_LOAD_PAGEOFF12);
+ relocs.push_back(reloc1);
+ break;
+
+
+ case ld::Fixup::kindStoreLittleEndian64:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+ if ( entry.fromTarget != NULL ) {
+ // this is a pointer-diff
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(3);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_UNSIGNED);
+ reloc2.set_r_address(address);
+ reloc2.set_r_symbolnum(fromSymbolNum);
+ reloc2.set_r_pcrel(false);
+ reloc2.set_r_length(3);
+ reloc2.set_r_extern(fromExternal);
+ reloc2.set_r_type(ARM64_RELOC_SUBTRACTOR);
+ relocs.push_back(reloc2);
+ relocs.push_back(reloc1);
+ }
+ else {
+ // regular pointer
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(3);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_UNSIGNED);
+ relocs.push_back(reloc1);
+ }
+ break;
+
+ case ld::Fixup::kindStoreLittleEndian32:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ if ( entry.fromTarget != NULL ) {
+ // this is a pointer-diff
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_UNSIGNED);
+ reloc2.set_r_address(address);
+ reloc2.set_r_symbolnum(fromSymbolNum);
+ reloc2.set_r_pcrel(false);
+ reloc2.set_r_length(2);
+ reloc2.set_r_extern(fromExternal);
+ reloc2.set_r_type(ARM64_RELOC_SUBTRACTOR);
+ relocs.push_back(reloc2);
+ relocs.push_back(reloc1);
+ }
+ else {
+ // regular pointer
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_UNSIGNED);
+ relocs.push_back(reloc1);
+ }
+ break;
+
+ case ld::Fixup::kindStoreARM64PointerToGOT:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(3);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_POINTER_TO_GOT);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreARM64PCRelToGOT:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_POINTER_TO_GOT);
+ relocs.push_back(reloc1);
+ break;
+
+ default:
+ assert(0 && "need to handle arm64 -r reloc");
+
+ }
+
+}
+#endif // SUPPORT_ARCH_arm64
template <typename A>
template <typename A>
void IndirectSymbolTableAtom<A>::encode()
{
- // static executables should not have an indirect symbol table
- if ( this->_options.outputKind() == Options::kStaticExecutable )
+ // static executables should not have an indirect symbol table, unless PIE
+ if ( (this->_options.outputKind() == Options::kStaticExecutable) && !_options.positionIndependentExecutable() )
return;
// x86_64 kext bundles should not have an indirect symbol table
if ( (this->_options.outputKind() == Options::kKextBundle) && kextBundlesDontHaveIndirectSymbolTable() )
return;
+ // slidable static executables (-static -pie) should not have an indirect symbol table
+ if ( (this->_options.outputKind() == Options::kStaticExecutable) && this->_options.positionIndependentExecutable() )
+ return;
+
// find all special sections that need a range of the indirect symbol table section
for (std::vector<ld::Internal::FinalSection*>::iterator sit = this->_state.sections.begin(); sit != this->_state.sections.end(); ++sit) {
ld::Internal::FinalSection* sect = *sit;