_dwarfDebugInfoSect(NULL), _dwarfDebugAbbrevSect(NULL),
_dwarfDebugLineSect(NULL), _dwarfDebugStringSect(NULL),
_objConstraint(ld::File::objcConstraintNone),
+ _swiftVersion(0),
_cpuSubType(0),
_canScatterAtoms(false) {}
virtual ~File();
virtual bool canScatterAtoms() const { return _canScatterAtoms; }
virtual const char* translationUnitSource() const;
virtual LinkerOptionsList* linkerOptions() const { return &_linkerOptions; }
+ virtual uint8_t swiftVersion() const { return _swiftVersion; }
const uint8_t* fileContent() { return _fileContent; }
private:
const uint8_t* _fileContent;
Section<A>** _sectionsArray;
uint8_t* _atomsArray;
+ uint8_t* _aliasAtomsArray;
uint32_t _sectionsArrayCount;
uint32_t _atomsArrayCount;
+ uint32_t _aliasAtomsArrayCount;
std::vector<ld::Fixup> _fixups;
std::vector<ld::Atom::UnwindInfo> _unwindInfos;
std::vector<ld::Atom::LineInfo> _lineInfos;
const macho_section<P>* _dwarfDebugLineSect;
const macho_section<P>* _dwarfDebugStringSect;
ld::File::ObjcConstraint _objConstraint;
+ uint8_t _swiftVersion;
uint32_t _cpuSubType;
bool _canScatterAtoms;
std::vector<std::vector<const char*> > _linkerOptions;
class Atom<A>* _beginAtoms;
class Atom<A>* _endAtoms;
bool _hasAliases;
+ std::set<const class Atom<A>*> _altEntries;
};
public:
CFISection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
: Section<A>(f, s) { }
- uint32_t cfiCount();
+ uint32_t cfiCount(Parser<A>& parser);
virtual ld::Atom::ContentType contentType() { return ld::Atom::typeCFI; }
virtual uint32_t computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFI_CU_InfoArrays&);
}
+class AliasAtom : public ld::Atom
+{
+public:
+ AliasAtom(const char* name, bool hidden, const ld::File* file, const char* aliasOfName) :
+ ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ (hidden ? ld::Atom::scopeLinkageUnit : ld::Atom::scopeGlobal),
+ ld::Atom::typeUnclassified, ld::Atom::symbolTableIn,
+ false, false, true, 0),
+ _file(file),
+ _name(name),
+ _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, ld::Fixup::bindingByNameUnbound, aliasOfName) { }
+
+ virtual const ld::File* file() const { return _file; }
+ virtual const char* translationUnitSource() const
+ { return NULL; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 0; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &((ld::Fixup*)&_fixup)[0]; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ static ld::Section _s_section;
+
+ const ld::File* _file;
+ const char* _name;
+ ld::Fixup _fixup;
+};
+
+ld::Section AliasAtom::_s_section("__LD", "__aliases", ld::Section::typeTempAlias, true);
+
+
template <typename A>
class Parser
{
static bool isThumbFromSymbol(const macho_nlist<P>& sym);
static bool weakImportFromSymbol(const macho_nlist<P>& sym);
static bool resolverFromSymbol(const macho_nlist<P>& sym);
+ static bool altEntryFromSymbol(const macho_nlist<P>& sym);
uint32_t symbolIndexFromIndirectSectionAddress(pint_t,const macho_section<P>*);
const macho_section<P>* firstMachOSection() { return _sectionsStart; }
const macho_section<P>* machOSectionFromSectionIndex(uint32_t index);
bool forceDwarfConversion() { return _forceDwarfConversion; }
bool verboseOptimizationHints() { return _verboseOptimizationHints; }
bool neverConvertDwarf() { return _neverConvertDwarf; }
-
+
macho_data_in_code_entry<P>* dataInCodeStart() { return _dataInCodeStart; }
macho_data_in_code_entry<P>* dataInCodeEnd() { return _dataInCodeEnd; }
const uint8_t* optimizationHintsStart() { return _lohStart; }
void parseDebugInfo();
void parseStabs();
+ void appendAliasAtoms(uint8_t* atomBuffer);
static bool isConstFunStabs(const char *stabStr);
bool read_comp_unit(const char ** name, const char ** comp_dir,
uint64_t *stmt_list);
- const char* getDwarfString(uint64_t form, const uint8_t* p);
+ pint_t realAddr(pint_t addr);
+ const char* getDwarfString(uint64_t form, const uint8_t*& p);
+ uint64_t getDwarfOffset(uint64_t form, const uint8_t*& di, bool dwarf64);
bool skip_form(const uint8_t ** offset, const uint8_t * end,
uint64_t form, uint8_t addr_size, bool dwarf64);
File<A>* _file;
const macho_nlist<P>* _symbols;
uint32_t _symbolCount;
+ uint32_t _indirectSymbolCount;
const char* _strings;
uint32_t _stringsSize;
const uint32_t* _indirectTable;
bool neverConvertDwarf, bool verboseOptimizationHints)
: _fileContent(fileContent), _fileLength(fileLength), _path(path), _modTime(modTime),
_ordinal(ordinal), _file(NULL),
- _symbols(NULL), _symbolCount(0), _strings(NULL), _stringsSize(0),
+ _symbols(NULL), _symbolCount(0), _indirectSymbolCount(0), _strings(NULL), _stringsSize(0),
_indirectTable(NULL), _indirectTableCount(0),
_undefinedStartIndex(0), _undefinedEndIndex(0),
_sectionsStart(NULL), _machOSectionsCount(0), _hasUUID(false),
return false;
}
+template <>
+typename arm::P::uint_t Parser<arm>::realAddr(typename arm::P::uint_t addr)
+{
+ return addr & (-2);
+}
+
+template <typename A>
+typename A::P::uint_t Parser<A>::realAddr(typename A::P::uint_t addr)
+{
+ return addr;
+}
+
#define STACK_ALLOC_IF_SMALL(_type, _name, _actual_count, _maxCount) \
_type* _name = NULL; \
uint32_t _name##_count = 1; \
// stack allocate (if not too large) array of CFI_Atom_Info
uint32_t countOfCFIs = 0;
if ( _EHFrameSection != NULL )
- countOfCFIs = _EHFrameSection->cfiCount();
+ countOfCFIs = _EHFrameSection->cfiCount(*this);
STACK_ALLOC_IF_SMALL(typename CFISection<A>::CFI_Atom_Info, cfiArray, countOfCFIs, 1024);
// stack allocate (if not too large) a copy of __eh_frame to apply relocations to
if ( cfiArray[i].isCIE )
continue;
if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS )
- cfiStartsArray[cfiStartsArrayCount++] = cfiArray[i].u.fdeInfo.function.targetAddress;
+ cfiStartsArray[cfiStartsArrayCount++] = realAddr(cfiArray[i].u.fdeInfo.function.targetAddress);
if ( cfiArray[i].u.fdeInfo.lsda.targetAddress != CFI_INVALID_ADDRESS )
cfiStartsArray[cfiStartsArrayCount++] = cfiArray[i].u.fdeInfo.lsda.targetAddress;
++countOfFDEs;
}
}
+ // process indirect symbols which become AliasAtoms
+ _file->_aliasAtomsArray = NULL;
+ _file->_aliasAtomsArrayCount = 0;
+ if ( _indirectSymbolCount != 0 ) {
+ _file->_aliasAtomsArrayCount = _indirectSymbolCount;
+ _file->_aliasAtomsArray = new uint8_t[_file->_aliasAtomsArrayCount*sizeof(AliasAtom)];
+ this->appendAliasAtoms(_file->_aliasAtomsArray);
+ }
+
+
// parse dwarf debug info to get line info
this->parseDebugInfo();
}
-
template <> uint8_t Parser<x86>::loadCommandSizeMask() { return 0x03; }
template <> uint8_t Parser<x86_64>::loadCommandSizeMask() { return 0x07; }
template <> uint8_t Parser<arm>::loadCommandSizeMask() { return 0x03; }
}
continue;
}
-
+ else if ( ((sym.n_type() & N_TYPE) == N_INDR) && ((sym.n_type() & N_EXT) != 0) ) {
+ _indirectSymbolCount++;
+ continue;
+ }
+
// count absolute symbols
if ( (sym.n_type() & N_TYPE) == N_ABS ) {
const char* absName = this->nameFromSymbol(sym);
}
}
+template <typename A>
+void Parser<A>::appendAliasAtoms(uint8_t* p)
+{
+ for (uint32_t i=0; i < this->_symbolCount; ++i) {
+ const macho_nlist<P>& sym = symbolFromIndex(i);
+ // ignore stabs
+ if ( (sym.n_type() & N_STAB) != 0 )
+ continue;
+
+ // only look at N_INDR symbols
+ if ( (sym.n_type() & N_TYPE) != N_INDR )
+ continue;
+
+ // skip non-external aliases
+ if ( (sym.n_type() & N_EXT) == 0 )
+ continue;
+
+ const char* symbolName = this->nameFromSymbol(sym);
+ const char* aliasOfName = &_strings[sym.n_value()];
+ bool isHiddenVisibility = (sym.n_type() & N_PEXT);
+ AliasAtom* allocatedSpace = (AliasAtom*)p;
+ new (allocatedSpace) AliasAtom(symbolName, isHiddenVisibility, _file, aliasOfName);
+ p += sizeof(AliasAtom);
+ }
+}
+
+
+
template <typename A>
int Parser<A>::sectionIndexSorter(void* extra, const void* l, const void* r)
{
_file->_objConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
else
_file->_objConstraint = ld::File::objcConstraintRetainRelease;
+ _file->_swiftVersion = ((flags >> 8) & 0xFF);
if ( sect->size() > 8 ) {
warning("section %s/%s has unexpectedly large size %llu in %s",
sect->segname(), Section<A>::makeSectionName(sect), sect->size(), _file->path());
return ( sym.n_desc() & N_SYMBOL_RESOLVER );
}
+template <typename A>
+bool Parser<A>::altEntryFromSymbol(const macho_nlist<P>& sym)
+{
+ return ( sym.n_desc() & N_ALT_ENTRY );
+}
+
/* Skip over a LEB128 value (signed or unsigned). */
static void
template <typename A>
-const char* Parser<A>::getDwarfString(uint64_t form, const uint8_t* p)
+const char* Parser<A>::getDwarfString(uint64_t form, const uint8_t*& di)
{
- if ( form == DW_FORM_string )
- return (const char*)p;
- else if ( form == DW_FORM_strp ) {
- uint32_t offset = E::get32(*((uint32_t*)p));
- const char* dwarfStrings = (char*)_file->fileContent() + _file->_dwarfDebugStringSect->offset();
- if ( offset > _file->_dwarfDebugStringSect->size() ) {
- warning("unknown dwarf DW_FORM_strp (offset=0x%08X) is too big in %s\n", offset, this->_path);
- return NULL;
- }
- return &dwarfStrings[offset];
+ uint32_t offset;
+ const char* dwarfStrings;
+ const char* result = NULL;
+ switch (form) {
+ case DW_FORM_string:
+ result = (const char*)di;
+ di += strlen(result) + 1;
+ break;
+ case DW_FORM_strp:
+ offset = E::get32(*((uint32_t*)di));
+ dwarfStrings = (char*)_file->fileContent() + _file->_dwarfDebugStringSect->offset();
+ if ( offset < _file->_dwarfDebugStringSect->size() )
+ result = &dwarfStrings[offset];
+ else
+ warning("dwarf DW_FORM_strp (offset=0x%08X) is too big in %s", offset, this->_path);
+ di += 4;
+ break;
+ default:
+ warning("unknown dwarf string encoding (form=%lld) in %s", form, this->_path);
+ break;
}
- warning("unknown dwarf string encoding (form=%lld) in %s\n", form, this->_path);
- return NULL;
+ return result;
+}
+
+template <typename A>
+uint64_t Parser<A>::getDwarfOffset(uint64_t form, const uint8_t*& di, bool dwarf64)
+{
+ if ( form == DW_FORM_sec_offset )
+ form = (dwarf64 ? DW_FORM_data8 : DW_FORM_data4);
+ uint64_t result = -1;
+ switch (form) {
+ case DW_FORM_data4:
+ result = A::P::E::get32(*(uint32_t*)di);
+ di += 4;
+ break;
+ case DW_FORM_data8:
+ result = A::P::E::get64(*(uint64_t*)di);
+ di += 8;
+ break;
+ default:
+ warning("unknown dwarf DW_FORM_ for DW_AT_stmt_list in %s", this->_path);
+ }
+ return result;
}
case N_LSYM:
case N_RSYM:
case N_PSYM:
+ case N_AST:
// not associated with an atom, just copy
stab.string = symString;
break;
return false;
else if (attr == 0)
return true;
-
if (form == DW_FORM_indirect)
form = read_uleb128 (&di, end);
- if (attr == DW_AT_name)
- *name = getDwarfString(form, di);
- else if (attr == DW_AT_comp_dir)
- *comp_dir = getDwarfString(form, di);
- else if (attr == DW_AT_stmt_list && form == DW_FORM_data4)
- *stmt_list = A::P::E::get32(*(uint32_t*)di);
- else if (attr == DW_AT_stmt_list && form == DW_FORM_data8)
- *stmt_list = A::P::E::get64(*(uint64_t*)di);
- if (! skip_form (&di, end, form, address_size, dwarf64))
- return false;
+ switch (attr) {
+ case DW_AT_name:
+ *name = getDwarfString(form, di);
+ break;
+ case DW_AT_comp_dir:
+ *comp_dir = getDwarfString(form, di);
+ break;
+ case DW_AT_stmt_list:
+ *stmt_list = getDwarfOffset(form, di, dwarf64);
+ break;
+ default:
+ if (! skip_form (&di, end, form, address_size, dwarf64))
+ return false;
+ }
}
}
return _dwarfTranslationUnitPath;
}
-
+
template <typename A>
bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
handler.doAtom(*((Atom<A>*)p));
p += sizeof(Atom<A>);
}
- return (_atomsArrayCount != 0);
+ p = _aliasAtomsArray;
+ for(int i=_aliasAtomsArrayCount; i > 0; --i) {
+ handler.doAtom(*((AliasAtom*)p));
+ p += sizeof(AliasAtom);
+ }
+
+ return (_atomsArrayCount != 0) || (_aliasAtomsArrayCount != 0);
}
template <typename A>
}
// arm does not have zero cost exceptions
-template <> uint32_t CFISection<arm>::cfiCount() { return 0; }
+template <>
+uint32_t CFISection<arm>::cfiCount(Parser<arm>& parser)
+{
+ return 0;
+}
template <typename A>
-uint32_t CFISection<A>::cfiCount()
+uint32_t CFISection<A>::cfiCount(Parser<A>& parser)
{
// create ObjectAddressSpace object for use by libunwind
OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset());
assert(count == 0);
}
+
+
+
template <>
void CFISection<arm64>::cfiParse(class Parser<arm64>& parser, uint8_t* buffer,
libunwind::CFI_Atom_Info<CFISection<arm64>::OAS>::CFI_Atom_Info cfiArray[],
}
}
-
-
#if SUPPORT_ARCH_arm64
template <>
void CFISection<arm64>::addCiePersonalityFixups(class Parser<arm64>& parser, const CFI_Atom_Info* cieInfo)
}
#endif
+
template <typename A>
void CFISection<A>::addCiePersonalityFixups(class Parser<A>& parser, const CFI_Atom_Info* cieInfo)
{
else {
const pint_t* content = (pint_t*)(this->file().fileContent() + this->_machOSection->offset() + reloc->r_address());
pint_t personalityAddr = *content;
- Section<x86_64>* personalitySection = parser.sectionForAddress(personalityAddr);
- assert((personalitySection->type() == ld::Section::typeCode) && "personality column in __compact_unwind section is not pointer to function");
+ assert((parser.sectionForAddress(personalityAddr)->type() == ld::Section::typeCode) && "personality column in __compact_unwind section is not pointer to function");
// atoms may not be constructed yet, so scan symbol table for labels
const char* name = parser.scanSymbolTableForAddress(personalityAddr);
return name;
}
#endif
+
template <typename A>
const char* CUSection<A>::personalityName(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
{
new (allocatedSpace) Atom<A>(*this, parser, *label, size, isAlias);
if ( isAlias )
this->_hasAliases = true;
+ if ( parser.altEntryFromSymbol(*label) )
+ this->_altEntries.insert(allocatedSpace);
}
else {
ld::Atom::SymbolTableInclusion inclusion = ld::Atom::symbolTableNotIn;
if ((instruction & 0xFE000000) == 0xFA000000)
displacement += ((instruction & 0x01000000) >> 23);
if ( reloc->r_extern() ) {
- target.addend = srcAddr + displacement;
+ dstAddr = srcAddr + displacement;
+ // <rdar://problem/16652542> support large .o files
+ if ( srcAddr > 0x2000000 ) {
+ dstAddr -= ((srcAddr + 0x1FFFFFF) & 0xFC000000);
+ }
+ target.addend = dstAddr;
if ( externSymbolIsThumbDef )
target.addend &= -2; // remove thumb bit
}
dstAddr &= 0xFFFFFFFC;
if ( reloc->r_extern() ) {
- target.addend = dstAddr;
+ // <rdar://problem/16652542> support large .o files
+ if ( srcAddr > 0x1000000 ) {
+ dstAddr -= ((srcAddr + 0xFFFFFF) & 0xFE000000);
+ }
+ target.addend = (int64_t)(int32_t)dstAddr;
}
else {
parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target);
}
}
}
+ if ( !this->_altEntries.empty() && !this->addFollowOnFixups() ) {
+ if ( _altEntries.count(_beginAtoms) != 0 )
+ warning("N_ALT_ENTRY bit set on first atom in section %s/%s", sect->segname(), Section<A>::makeSectionName(sect));
+
+ Atom<A>* end = &_endAtoms[-1];
+ for(Atom<A>* p = _beginAtoms; p < end; ++p) {
+ Atom<A>* nextAtom = &p[1];
+ if ( _altEntries.count(nextAtom) != 0 ) {
+ typename Parser<A>::SourceLocation src(p, 0);
+ parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, nextAtom);
+ typename Parser<A>::SourceLocation src2(nextAtom, 0);
+ parser.addFixup(src2, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinate, p);
+ }
+ }
+ }
// <rdar://problem/9218847> track data-in-code
if ( parser.hasDataInCodeLabels() && (this->type() == ld::Section::typeCode) ) {