This is first step in reworking how mach-o relocations are processed.
The existing KindHandler is going to become a delgate/helper object for
processing architecture specific references. The KindHandler knows how
to convert mach-o relocations into References and back, as well, as fixing
up the content the relocation is on.
One of the messy things about mach-o relocations is that they sometime
come in pairs, but the pairs still convert to one lld::Reference. So, the
conversion has to detect pairs (arch specific) and change the stride.
llvm-svn: 211921
}
ArrayRef<uint8_t> rawContent() const override {
- // Zerofill atoms have a content pointer which is null.
- assert(_content.data() != nullptr);
+ // Note: Zerofill atoms have a content pointer which is null.
return _content;
}
+ void addReference(uint32_t offsetInAtom, uint16_t relocType,
+ const Atom *target, Reference::Addend addend,
+ Reference::KindArch arch = Reference::KindArch::x86_64,
+ Reference::KindNamespace ns = Reference::KindNamespace::mach_o) {
+ SimpleDefinedAtom::addReference(ns, arch, relocType, offsetInAtom, target, addend);
+ }
+
private:
const StringRef _name;
const ArrayRef<uint8_t> _content;
#ifndef LLD_READER_WRITER_MACHO_FILE_H
#define LLD_READER_WRITER_MACHO_FILE_H
+#include "llvm/ADT/StringMap.h"
+
#include "Atoms.h"
#include "lld/Core/Simple.h"
namespace lld {
namespace mach_o {
+using lld::mach_o::normalized::Section;
+
class MachOFile : public SimpleFile {
public:
MachOFile(StringRef path) : SimpleFile(path) {}
void addDefinedAtom(StringRef name, Atom::Scope scope,
DefinedAtom::ContentType type, DefinedAtom::Merge merge,
- ArrayRef<uint8_t> content, bool copyRefs) {
+ uint64_t sectionOffset, uint64_t contentSize,
+ bool copyRefs, const Section *inSection) {
+ assert(sectionOffset+contentSize <= inSection->content.size());
+ ArrayRef<uint8_t> content = inSection->content.slice(sectionOffset,
+ contentSize);
if (copyRefs) {
// Make a copy of the atom's name and content that is owned by this file.
name = name.copy(_allocator);
new (_allocator) MachODefinedAtom(*this, name, scope, type, merge,
content);
addAtom(*atom);
+ _sectionAtoms[inSection].push_back({sectionOffset, atom});
}
void addDefinedAtomInCustomSection(StringRef name, Atom::Scope scope,
DefinedAtom::ContentType type, DefinedAtom::Merge merge,
- ArrayRef<uint8_t> content, StringRef sectionName,
- bool copyRefs) {
- if (copyRefs) {
+ uint64_t sectionOffset, uint64_t contentSize,
+ StringRef sectionName, bool copyRefs,
+ const Section *inSection) {
+ assert(sectionOffset+contentSize <= inSection->content.size());
+ ArrayRef<uint8_t> content = inSection->content.slice(sectionOffset,
+ contentSize);
+ if (copyRefs) {
// Make a copy of the atom's name and content that is owned by this file.
name = name.copy(_allocator);
content = content.copy(_allocator);
new (_allocator) MachODefinedCustomSectionAtom(*this, name, scope, type,
merge, content, sectionName);
addAtom(*atom);
+ _sectionAtoms[inSection].push_back({sectionOffset, atom});
}
- void addZeroFillDefinedAtom(StringRef name, Atom::Scope scope, uint64_t size,
- bool copyRefs) {
+ void addZeroFillDefinedAtom(StringRef name, Atom::Scope scope,
+ uint64_t sectionOffset, uint64_t size,
+ bool copyRefs, const Section *inSection) {
if (copyRefs) {
// Make a copy of the atom's name and content that is owned by this file.
name = name.copy(_allocator);
MachODefinedAtom *atom =
new (_allocator) MachODefinedAtom(*this, name, scope, size);
addAtom(*atom);
+ _sectionAtoms[inSection].push_back({sectionOffset, atom});
}
void addUndefinedAtom(StringRef name, bool copyRefs) {
SimpleUndefinedAtom *atom =
new (_allocator) SimpleUndefinedAtom(*this, name);
addAtom(*atom);
+ _undefAtoms[name] = atom;
}
void addTentativeDefAtom(StringRef name, Atom::Scope scope, uint64_t size,
MachOTentativeDefAtom *atom =
new (_allocator) MachOTentativeDefAtom(*this, name, scope, size, align);
addAtom(*atom);
+ _undefAtoms[name] = atom;
}
-
-
+
+ /// Search this file for an the atom from 'section' that covers
+ /// 'offsetInSect'. Returns nullptr is no atom found.
+ MachODefinedAtom *findAtomCoveringAddress(const Section §ion,
+ uint64_t offsetInSect,
+ uint32_t *foundOffsetAtom=nullptr) {
+ auto pos = _sectionAtoms.find(§ion);
+ if (pos == _sectionAtoms.end())
+ return nullptr;
+ auto vec = pos->second;
+ assert(offsetInSect < section.content.size());
+ // Vector of atoms for section are already sorted, so do binary search.
+ auto atomPos = std::lower_bound(vec.begin(), vec.end(), offsetInSect,
+ [offsetInSect](const SectionOffsetAndAtom &ao,
+ uint64_t targetAddr) -> bool {
+ // Each atom has a start offset of its slice of the
+ // section's content. This compare function must return true
+ // iff the atom's range is before the offset being searched for.
+ uint64_t atomsEndOffset = ao.offset+ao.atom->rawContent().size();
+ return (atomsEndOffset <= offsetInSect);
+ });
+ if (atomPos == vec.end())
+ return nullptr;
+ if (foundOffsetAtom)
+ *foundOffsetAtom = offsetInSect - atomPos->offset;
+ return atomPos->atom;
+ }
+
+ /// Searches this file for an UndefinedAtom named 'name'. Returns
+ /// nullptr is no such atom found.
+ const lld::Atom *findUndefAtom(StringRef name) {
+ auto pos = _undefAtoms.find(name);
+ if (pos == _undefAtoms.end())
+ return nullptr;
+ return pos->second;
+ }
+
private:
- llvm::BumpPtrAllocator _allocator;
+ struct SectionOffsetAndAtom { uint64_t offset; MachODefinedAtom *atom; };
+ typedef llvm::DenseMap<const normalized::Section *,
+ std::vector<SectionOffsetAndAtom>> SectionToAtoms;
+ typedef llvm::StringMap<const lld::Atom *> NameToAtom;
+
+ llvm::BumpPtrAllocator _allocator;
+ SectionToAtoms _sectionAtoms;
+ NameToAtom _undefAtoms;
};
+
+
} // end namespace mach_o
} // end namespace lld
sout.value = sin->n_value;
if (sout.type == N_UNDF)
f->undefinedSymbols.push_back(sout);
- else if (sout.scope == (SymbolScope)N_EXT)
+ else if (sin->n_type & N_EXT)
f->globalSymbols.push_back(sout);
else
f->localSymbols.push_back(sout);
}
void Util::appendSection(SectionInfo *si, NormalizedFile &file) {
+ const bool rMode = (_context.outputMachOType() == llvm::MachO::MH_OBJECT);
// Add new empty section to end of file.sections.
Section temp;
file.sections.push_back(std::move(temp));
if ( ref->target() != nullptr )
targetAddress = _atomToAddress[ref->target()];
uint64_t fixupAddress = _atomToAddress[ai.atom] + offset;
- _context.kindHandler().applyFixup(
+ if ( rMode ) {
+ // FIXME: Need a handler method to update content for .o file
+ // output and any needed section relocations.
+ } else {
+ _context.kindHandler().applyFixup(
ref->kindNamespace(), ref->kindArch(), ref->kindValue(),
ref->addend(), &atomContent[offset], fixupAddress, targetAddress);
+ }
}
}
}
#include "MachONormalizedFileBinaryUtils.h"
#include "File.h"
#include "Atoms.h"
+#include "ReferenceKinds.h"
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
#include "llvm/Support/MachO.h"
+#include "llvm/Support/Format.h"
using namespace llvm::MachO;
using namespace lld::mach_o::normalized;
ENTRY("", "", S_CSTRING_LITERALS, typeCString),
ENTRY("__TEXT", "__ustring", S_REGULAR, typeUTF16String),
ENTRY("__TEXT", "__const", S_REGULAR, typeConstant),
+ ENTRY("__TEXT", "__const_coal", S_COALESCED, typeConstant),
ENTRY("__TEXT", "__eh_frame", S_COALESCED, typeCFI),
ENTRY("__TEXT", "__literal4", S_4BYTE_LITERALS, typeLiteral4),
ENTRY("__TEXT", "__literal8", S_8BYTE_LITERALS, typeLiteral8),
ENTRY("__TEXT", "__literal16", S_16BYTE_LITERALS, typeLiteral16),
ENTRY("__TEXT", "__gcc_except_tab", S_REGULAR, typeLSDA),
ENTRY("__DATA", "__data", S_REGULAR, typeData),
+ ENTRY("__DATA", "__datacoal_nt", S_COALESCED, typeData),
ENTRY("__DATA", "__const", S_REGULAR, typeConstData),
ENTRY("__DATA", "__cfstring", S_REGULAR, typeCFString),
ENTRY("__DATA", "__mod_init_func", S_MOD_INIT_FUNC_POINTERS,
atomizeUTF8,
atomizeUTF16,
atomizeCFI,
- atomizeCU
+ atomizeCU,
+ atomizeCFString
};
/// Returns info on how to atomize a section of the specified ContentType.
atomizeFixedSize),
ENTRY(typeLiteral16, 16, scopeLinkageUnit, mergeByContent,
atomizeFixedSize),
- ENTRY(typeCFString, 16, scopeLinkageUnit, mergeByContent,
- atomizeFixedSize),
+ ENTRY(typeCFString, 4, scopeLinkageUnit, mergeByContent,
+ atomizeCFString),
ENTRY(typeInitializerPtr, 4, scopeTranslationUnit, mergeNo,
atomizePointerSize),
ENTRY(typeTerminatorPtr, 4, scopeTranslationUnit, mergeNo,
// Mach-O symbol table does have size in it. Instead the size is the
// difference between this and the next symbol.
uint64_t size = nextSymbolAddr - symbolAddr;
+ uint64_t offset = symbolAddr - section.address;
if (section.type == llvm::MachO::S_ZEROFILL) {
- file.addZeroFillDefinedAtom(symbolName, symbolScope, size, copyRefs);
+ file.addZeroFillDefinedAtom(symbolName, symbolScope, offset, size, copyRefs,
+ §ion);
} else {
- uint64_t offset = symbolAddr - section.address;
- ArrayRef<uint8_t> atomContent = section.content.slice(offset, size);
- DefinedAtom::Merge merge = (symbolDescFlags & N_WEAK_DEF)
+ DefinedAtom::Merge merge = (symbolDescFlags & N_WEAK_DEF)
? DefinedAtom::mergeAsWeak : DefinedAtom::mergeNo;
if (atomType == DefinedAtom::typeUnknown) {
// Mach-O needs a segment and section name. Concatentate those two
std::string segSectName = section.segmentName.str()
+ "/" + section.sectionName.str();
file.addDefinedAtomInCustomSection(symbolName, symbolScope, atomType,
- merge, atomContent, segSectName, true);
+ merge, offset, size, segSectName, true,
+ §ion);
} else {
- if ((atomType == lld::DefinedAtom::typeCode) &&
+ if ((atomType == lld::DefinedAtom::typeCode) &&
(symbolDescFlags & N_SYMBOL_RESOLVER)) {
- atomType = lld::DefinedAtom::typeResolver;
+ atomType = lld::DefinedAtom::typeResolver;
}
file.addDefinedAtom(symbolName, symbolScope, atomType, merge,
- atomContent, copyRefs);
+ offset, size, copyRefs, §ion);
}
}
}
// Sort symbols.
std::sort(symbols.begin(), symbols.end(),
[](const Symbol *lhs, const Symbol *rhs) -> bool {
+ if (lhs == rhs)
+ return false;
// First by address.
- if (lhs->value != rhs->value)
- return lhs->value < rhs->value;
- // If same address, one is an alias. Sort by scope.
+ uint64_t lhsAddr = lhs->value;
+ uint64_t rhsAddr = rhs->value;
+ if (lhsAddr != rhsAddr)
+ return lhsAddr < rhsAddr;
+ // If same address, one is an alias so sort by scope.
Atom::Scope lScope = atomScope(lhs->scope);
Atom::Scope rScope = atomScope(rhs->scope);
if (lScope != rScope)
// Debug logging of symbols.
//for (const Symbol *sym : symbols)
- // llvm::errs() << "sym: " << sym->value << ", " << sym->name << "\n";
+ // llvm::errs() << " sym: "
+ // << llvm::format("0x%08llx ", (uint64_t)sym->value)
+ // << ", " << sym->name << "\n";
// If section has no symbols and no content, there are no atoms.
if (symbols.empty() && section.content.empty())
return std::error_code();
- uint64_t anonAtomEnd = symbols.empty()
- ? section.address + section.content.size()
- : (uint64_t)symbols.front()->value;
- if (anonAtomEnd != section.address) {
+ if (symbols.empty()) {
+ // Section has no symbols, put all content in one anoymous atom.
+ atomFromSymbol(atomType, section, file, section.address, StringRef(),
+ 0, Atom::scopeTranslationUnit,
+ section.address + section.content.size(), copyRefs);
+ }
+ else if (symbols.front()->value != section.address) {
// Section has anonymous content before first symbol.
- atomFromSymbol(atomType, section, file, section.address, StringRef(), 0,
- Atom::scopeTranslationUnit, anonAtomEnd, copyRefs);
+ atomFromSymbol(atomType, section, file, section.address, StringRef(),
+ 0, Atom::scopeTranslationUnit, symbols.front()->value,
+ copyRefs);
}
const Symbol *lastSym = nullptr;
break;
case atomizePointerSize:
// Break section up into atoms each the size of a pointer.
- size = is64 ? 8 : 4;;
+ size = is64 ? 8 : 4;
break;
case atomizeUTF8:
// Break section up into zero terminated c-strings.
// Break section up into compact unwind entries.
size = is64 ? 32 : 20;
break;
+ case atomizeCFString:
+ // Break section up into compact unwind entries.
+ size = is64 ? 32 : 16;
+ break;
case atomizeAtSymbols:
break;
}
+ " is malformed. The last atom is "
"not zero terminated.");
}
- ArrayRef<uint8_t> byteContent = section.content.slice(offset, size);
- file.addDefinedAtom(StringRef(), scope, atomType, merge, byteContent,
- copyRefs);
+ file.addDefinedAtom(StringRef(), scope, atomType, merge, offset, size,
+ copyRefs, §ion);
offset += size;
}
}
return std::error_code();
}
+// Walks all relocations for a section in a normalized .o file and
+// creates corresponding lld::Reference objects.
+std::error_code convertRelocs(const Section §ion,
+ const NormalizedFile &normalizedFile,
+ MachOFile &file,
+ KindHandler &handler) {
+ // Utility function for KindHandler to find atom by its address.
+ auto atomByAddr = [&] (uint32_t sectIndex, uint64_t addr,
+ const lld::Atom **atom, Reference::Addend *addend)
+ -> std::error_code {
+ if (sectIndex > normalizedFile.sections.size())
+ return make_dynamic_error_code(Twine("out of range section "
+ "index (") + Twine(sectIndex) + ")");
+ const Section § = normalizedFile.sections[sectIndex-1];
+ uint32_t offsetInTarget;
+ uint64_t offsetInSect = addr - sect.address;
+ *atom = file.findAtomCoveringAddress(sect, offsetInSect, &offsetInTarget);
+ *addend = offsetInTarget;
+ return std::error_code();
+ };
+
+ // Utility function for KindHandler to find atom by its symbol index.
+ auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result)
+ -> std::error_code {
+ // Find symbol from index.
+ const Symbol *sym = nullptr;
+ uint32_t numLocal = normalizedFile.localSymbols.size();
+ uint32_t numGlobal = normalizedFile.globalSymbols.size();
+ uint32_t numUndef = normalizedFile.undefinedSymbols.size();
+ if (symbolIndex < numLocal) {
+ sym = &normalizedFile.localSymbols[symbolIndex];
+ } else if (symbolIndex < numLocal+numGlobal) {
+ sym = &normalizedFile.globalSymbols[symbolIndex-numLocal];
+ } else if (symbolIndex < numLocal+numGlobal+numUndef) {
+ sym = &normalizedFile.undefinedSymbols[symbolIndex-numLocal-numGlobal];
+ } else {
+ return make_dynamic_error_code(Twine("symbol index (")
+ + Twine(symbolIndex) + ") out of range");
+ }
+ // Find atom from symbol.
+ if ((sym->type & N_TYPE) == N_SECT) {
+ if (sym->sect > normalizedFile.sections.size())
+ return make_dynamic_error_code(Twine("symbol section index (")
+ + Twine(sym->sect) + ") out of range ");
+ const Section &symSection = normalizedFile.sections[sym->sect-1];
+ uint64_t targetOffsetInSect = sym->value - symSection.address;
+ MachODefinedAtom *target = file.findAtomCoveringAddress(symSection,
+ targetOffsetInSect);
+ if (target) {
+ *result = target;
+ return std::error_code();
+ }
+ return make_dynamic_error_code(Twine("no atom found for defined symbol"));
+ } else if ((sym->type & N_TYPE) == N_UNDF) {
+ const lld::Atom *target = file.findUndefAtom(sym->name);
+ if (target) {
+ *result = target;
+ return std::error_code();
+ }
+ return make_dynamic_error_code(Twine("no undefined atom found for sym"));
+ } else {
+ // Search undefs
+ return make_dynamic_error_code(Twine("no atom found for symbol"));
+ }
+ };
+
+ const bool swap = !MachOLinkingContext::isHostEndian(normalizedFile.arch);
+ // Use old-school iterator so that paired relocations can be grouped.
+ for (auto it=section.relocations.begin(), e=section.relocations.end();
+ it != e; ++it) {
+ const Relocation &reloc = *it;
+ // Find atom this relocation is in.
+ if (reloc.offset > section.content.size())
+ return make_dynamic_error_code(Twine("r_address (") + Twine(reloc.offset)
+ + ") is larger than section size ("
+ + Twine(section.content.size()) + ")");
+ uint32_t offsetInAtom;
+ MachODefinedAtom *inAtom = file.findAtomCoveringAddress(section,
+ reloc.offset,
+ &offsetInAtom);
+ if (!inAtom)
+ return make_dynamic_error_code(Twine("no atom at r_address"));
+ uint64_t fixupAddress = section.address + reloc.offset;
+
+ const lld::Atom *target = nullptr;
+ Reference::Addend addend = 0;
+ Reference::KindValue kind;
+ std::error_code relocErr;
+ if (handler.isPairedReloc(reloc)) {
+ // Handle paired relocations together.
+ relocErr = handler.getPairReferenceInfo(reloc, *++it, inAtom,
+ offsetInAtom, fixupAddress, swap,
+ atomByAddr, atomBySymbol, &kind,
+ &target, &addend);
+ }
+ else {
+ // Use KindHandler to convert relocation record into information
+ // needed to instantiate an lld::Reference object.
+ relocErr = handler.getReferenceInfo(reloc, inAtom, offsetInAtom,
+ fixupAddress,swap, atomByAddr,
+ atomBySymbol, &kind, &target, &addend);
+ }
+ if (relocErr) {
+ return make_dynamic_error_code(
+ Twine("bad relocation (") + relocErr.message()
+ + ") in section "
+ + section.segmentName + "/" + section.sectionName
+ + " (r_address=" + Twine::utohexstr(reloc.offset)
+ + ", r_type=" + Twine(reloc.type)
+ + ", r_extern=" + Twine(reloc.isExtern)
+ + ", r_length=" + Twine(reloc.length)
+ + ", r_pcrel=" + Twine(reloc.pcRel)
+ + (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol))
+ : (Twine(", r_scattered=1, r_value=")
+ + Twine(reloc.value)))
+ + ")" );
+ } else {
+ // Instantiate an lld::Reference object and add to its atom.
+ inAtom->addReference(offsetInAtom, kind, target, addend);
+ }
+ }
+ return std::error_code();
+}
+
+bool isDebugInfoSection(const Section §ion) {
+ if ((section.attributes & S_ATTR_DEBUG) == 0)
+ return false;
+ return section.segmentName.equals("__DWARF");
+}
+
+/// Converts normalized mach-o file into an lld::File and lld::Atoms.
ErrorOr<std::unique_ptr<lld::File>>
normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
bool copyRefs) {
std::unique_ptr<MachOFile> file(new MachOFile(path));
// Create atoms from each section.
for (auto § : normalizedFile.sections) {
+ if (isDebugInfoSection(sect))
+ continue;
DefinedAtom::ContentType atomType = atomTypeFromSection(sect);
if (std::error_code ec =
processSection(atomType, sect, normalizedFile, *file, copyRefs))
}
}
+ // TEMP BEGIN: until all KindHandlers switched to new interface.
+ if (normalizedFile.arch != lld::MachOLinkingContext::arch_x86_64)
+ return std::unique_ptr<File>(std::move(file));
+ // TEMP END
+
+ // Convert mach-o relocations to References
+ std::unique_ptr<mach_o::KindHandler> handler
+ = KindHandler::create(normalizedFile.arch);
+ for (auto § : normalizedFile.sections) {
+ if (isDebugInfoSection(sect))
+ continue;
+ if (std::error_code ec = convertRelocs(sect, normalizedFile, *file, *handler))
+ return ec;
+ }
+
+ // Sort references in each atom to their canonical order.
+ for (const DefinedAtom* defAtom : file->defined()) {
+ reinterpret_cast<const SimpleDefinedAtom*>(defAtom)->sortReferences();
+ }
+
return std::unique_ptr<File>(std::move(file));
}
#include "ReferenceKinds.h"
-
+#include "MachONormalizedFileBinaryUtils.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
namespace lld {
namespace mach_o {
}
}
+KindHandler::RelocPattern KindHandler::relocPattern(const Relocation &reloc) {
+ assert((reloc.type & 0xFFF0) == 0);
+ uint16_t result = reloc.type;
+ if (reloc.scattered)
+ result |= rScattered;
+ if (reloc.pcRel)
+ result |= rPcRel;
+ if (reloc.isExtern)
+ result |= rExtern;
+ switch(reloc.length) {
+ case 0:
+ break;
+ case 1:
+ result |= rLength2;
+ break;
+ case 2:
+ result |= rLength4;
+ break;
+ case 3:
+ result |= rLength8;
+ break;
+ default:
+ llvm_unreachable("bad r_length");
+ }
+ return result;
+}
+
+bool KindHandler::isPairedReloc(const Relocation &reloc) {
+ llvm_unreachable("abstract");
+}
+
+std::error_code
+KindHandler::getReferenceInfo(const Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ llvm_unreachable("abstract");
+}
+
+std::error_code
+KindHandler::getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ llvm_unreachable("abstract");
+}
+
//===----------------------------------------------------------------------===//
// KindHandler_x86_64
//===----------------------------------------------------------------------===//
}
const Registry::KindStrings KindHandler_x86_64::kindStrings[] = {
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_UNSIGNED),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_BRANCH),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED_1),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED_2),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED_4),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_GOT_LOAD),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_GOT),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_TLV),
- LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_GOT_LOAD_NOW_LEA),
- LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_TLV_NOW_LEA),
- LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_LAZY_TARGET),
- LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_LAZY_IMMEDIATE),
+ LLD_KIND_STRING_ENTRY(invalid),
+ LLD_KIND_STRING_ENTRY(branch32),
+ LLD_KIND_STRING_ENTRY(ripRel32),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus1),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus2),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus4),
+ LLD_KIND_STRING_ENTRY(ripRel32Anon),
+ LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
+ LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea),
+ LLD_KIND_STRING_ENTRY(ripRel32Got),
+ LLD_KIND_STRING_ENTRY(lazyPointer),
+ LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+ LLD_KIND_STRING_ENTRY(pointer64),
+ LLD_KIND_STRING_ENTRY(pointer64Anon),
+ LLD_KIND_STRING_ENTRY(delta32),
+ LLD_KIND_STRING_ENTRY(delta64),
+ LLD_KIND_STRING_ENTRY(delta32Anon),
+ LLD_KIND_STRING_ENTRY(delta64Anon),
LLD_KIND_STRING_END
};
-
+
bool KindHandler_x86_64::isCallSite(const Reference &ref) {
- return (ref.kindValue() == X86_64_RELOC_BRANCH);
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ return (ref.kindValue() == branch32);
}
bool KindHandler_x86_64::isPointer(const Reference &ref) {
- return (ref.kindValue() == X86_64_RELOC_UNSIGNED);
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ return (ref.kindValue() == pointer64);
}
bool KindHandler_x86_64::isLazyImmediate(const Reference &ref) {
- return (ref.kindValue() == LLD_X86_64_RELOC_LAZY_IMMEDIATE);
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ return (ref.kindValue() == lazyImmediateLocation);
}
bool KindHandler_x86_64::isLazyTarget(const Reference &ref) {
- return (ref.kindValue() == LLD_X86_64_RELOC_LAZY_TARGET);
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ return (ref.kindValue() == lazyPointer);
+}
+
+bool KindHandler_x86_64::isPairedReloc(const Relocation &reloc) {
+ return (reloc.type == X86_64_RELOC_SUBTRACTOR);
+}
+
+static int32_t readS32(bool swap, const uint8_t *addr) {
+ return read32(swap, *reinterpret_cast<const uint32_t*>(addr));
}
+static int64_t readS64(bool swap, const uint8_t *addr) {
+ return read64(swap, *reinterpret_cast<const uint64_t*>(addr));
+}
+
+Reference::KindValue
+KindHandler_x86_64::kindFromReloc(const Relocation &reloc) {
+ switch(relocPattern(reloc)) {
+ case X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4:
+ return branch32;
+ case X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4:
+ return ripRel32;
+ case X86_64_RELOC_SIGNED | rPcRel | rLength4:
+ return ripRel32Anon;
+ case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4:
+ return ripRel32Minus1;
+ case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4:
+ return ripRel32Minus2;
+ case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4:
+ return ripRel32Minus4;
+ case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4:
+ return ripRel32GotLoad;
+ case X86_64_RELOC_GOT | rPcRel | rExtern | rLength4:
+ return ripRel32Got;
+ case X86_64_RELOC_UNSIGNED | rExtern | rLength8:
+ return pointer64;
+ case X86_64_RELOC_UNSIGNED | rLength8:
+ return pointer64Anon;
+ default:
+ return invalid;
+ }
+
+}
+
+
+std::error_code
+KindHandler_x86_64::getReferenceInfo(const Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ typedef std::error_code E;
+ *kind = kindFromReloc(reloc);
+ if (*kind == invalid)
+ return make_dynamic_error_code(Twine("unknown type"));
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ uint64_t targetAddress;
+ switch (*kind) {
+ case branch32:
+ case ripRel32:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent);
+ return std::error_code();
+ case ripRel32Minus1:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent) + 1;
+ return std::error_code();
+ case ripRel32Minus2:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent) + 2;
+ return std::error_code();
+ case ripRel32Minus4:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent) + 4;
+ return std::error_code();
+ case ripRel32Anon:
+ targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ripRel32GotLoad:
+ case ripRel32Got:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return std::error_code();
+ case pointer64:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS64(swap, fixupContent);
+ return std::error_code();
+ case pointer64Anon:
+ targetAddress = readS64(swap, fixupContent);
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ default:
+ llvm_unreachable("bad reloc kind");
+ }
+}
+
+
+Reference::KindValue
+KindHandler_x86_64::kindFromRelocPair(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2) {
+ switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+ X86_64_RELOC_UNSIGNED | rExtern | rLength8):
+ return delta64;
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+ X86_64_RELOC_UNSIGNED | rExtern | rLength4):
+ return delta32;
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+ X86_64_RELOC_UNSIGNED | rLength8):
+ return delta64Anon;
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+ X86_64_RELOC_UNSIGNED | rLength4):
+ return delta32Anon;
+ default:
+ llvm_unreachable("bad reloc pairs");
+ }
+}
+
+
+std::error_code
+KindHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ *kind = kindFromRelocPair(reloc1, reloc2);
+ if (*kind == invalid)
+ return make_dynamic_error_code(Twine("unknown pair"));
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ typedef std::error_code E;
+ uint64_t targetAddress;
+ const lld::Atom *fromTarget;
+ if (E ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
+ return ec;
+ if (fromTarget != inAtom)
+ return make_dynamic_error_code(Twine("pointer diff not in base atom"));
+ switch (*kind) {
+ case delta64:
+ if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = readS64(swap, fixupContent) + offsetInAtom;
+ return std::error_code();
+ case delta32:
+ if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent) + offsetInAtom;
+ return std::error_code();
+ case delta64Anon:
+ targetAddress = offsetInAtom + readS64(swap, fixupContent);
+ return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+ case delta32Anon:
+ targetAddress = offsetInAtom + readS32(swap, fixupContent);
+ return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+ default:
+ llvm_unreachable("bad reloc pair kind");
+ }
+}
+
+
+
void KindHandler_x86_64::applyFixup(Reference::KindNamespace ns,
Reference::KindArch arch,
Reference::KindValue kindValue,
int32_t *loc32 = reinterpret_cast<int32_t*>(location);
uint64_t* loc64 = reinterpret_cast<uint64_t*>(location);
switch (kindValue) {
- case X86_64_RELOC_BRANCH:
- case X86_64_RELOC_SIGNED:
- case X86_64_RELOC_GOT_LOAD:
- case X86_64_RELOC_GOT:
- case X86_64_RELOC_TLV:
- *loc32 = (targetAddress - (fixupAddress+4)) + addend;
- break;
- case X86_64_RELOC_UNSIGNED:
- *loc64 = targetAddress + addend;
- break;
- case X86_64_RELOC_SIGNED_1:
- *loc32 = (targetAddress - (fixupAddress+5)) + addend;
- break;
- case X86_64_RELOC_SIGNED_2:
- *loc32 = (targetAddress - (fixupAddress+6)) + addend;
- break;
- case X86_64_RELOC_SIGNED_4:
- *loc32 = (targetAddress - (fixupAddress+8)) + addend;
- break;
- case LLD_X86_64_RELOC_SIGNED_32:
- *loc32 = (targetAddress - fixupAddress) + addend;
- break;
- case LLD_X86_64_RELOC_GOT_LOAD_NOW_LEA:
- case LLD_X86_64_RELOC_TLV_NOW_LEA:
- // Change MOVQ to LEA
- assert(location[-2] == 0x8B);
- location[-2] = 0x8D;
- *loc32 = (targetAddress - (fixupAddress+4)) + addend;
- break;
- case LLD_X86_64_RELOC_LAZY_TARGET:
- case LLD_X86_64_RELOC_LAZY_IMMEDIATE:
- // do nothing
- break;
+ case branch32:
+ case ripRel32:
+ case ripRel32Got:
+ case ripRel32GotLoad:
+ *loc32 = (targetAddress - (fixupAddress+4)) + addend;
+ break;
+ case pointer64:
+ case pointer64Anon:
+ *loc64 = targetAddress + addend;
+ break;
+ case ripRel32Minus1:
+ *loc32 = (targetAddress - (fixupAddress+5)) + addend;
+ break;
+ case ripRel32Minus2:
+ *loc32 = (targetAddress - (fixupAddress+6)) + addend;
+ break;
+ case ripRel32Minus4:
+ *loc32 = (targetAddress - (fixupAddress+8)) + addend;
+ break;
+ case delta32:
+ case delta32Anon:
+ *loc32 = (targetAddress - fixupAddress) + addend;
+ break;
+ case delta64:
+ case delta64Anon:
+ *loc64 = (targetAddress - fixupAddress) + addend;
+ break;
+ case ripRel32GotLoadNowLea:
+ // Change MOVQ to LEA
+ assert(location[-2] == 0x8B);
+ location[-2] = 0x8D;
+ *loc32 = (targetAddress - (fixupAddress+4)) + addend;
+ break;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ // do nothing
+ break;
default:
llvm_unreachable("invalid x86_64 Reference Kind");
break;
//===----------------------------------------------------------------------===//
+#include "MachONormalizedFile.h"
+
#include "lld/Core/LLVM.h"
#include "lld/Core/Reference.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
namespace lld {
namespace mach_o {
+
// Additional Reference Kind values used internally.
enum {
- LLD_X86_64_RELOC_GOT_LOAD_NOW_LEA = 100,
- LLD_X86_64_RELOC_TLV_NOW_LEA = 101,
- LLD_X86_64_RELOC_LAZY_TARGET = 102,
- LLD_X86_64_RELOC_LAZY_IMMEDIATE = 103,
- LLD_X86_64_RELOC_SIGNED_32 = 104,
-};
-enum {
LLD_X86_RELOC_BRANCH32 = 100, // CALL or JMP 32-bit pc-rel
LLD_X86_RELOC_ABS32 = 101, // 32-bit absolute addr in instruction
LLD_X86_RELOC_FUNC_REL32 = 102, // 32-bit target from start of func
virtual bool isPointer(const Reference &) = 0;
virtual bool isLazyImmediate(const Reference &) = 0;
virtual bool isLazyTarget(const Reference &) = 0;
+
+ /// Returns true if the specified relocation is paired to the next relocation.
+ virtual bool isPairedReloc(const normalized::Relocation &);
+
+ /// Prototype for a helper function. Given a sectionIndex and address,
+ /// finds the atom and offset with that atom of that address.
+ typedef std::function<std::error_code (uint32_t sectionIndex, uint64_t addr,
+ const lld::Atom **, Reference::Addend *)>
+ FindAtomBySectionAndAddress;
+
+ /// Prototype for a helper function. Given a symbolIndex, finds the atom
+ /// representing that symbol.
+ typedef std::function<std::error_code (uint32_t symbolIndex,
+ const lld::Atom**)> FindAtomBySymbolIndex;
+
+ /// Analyzes a relocation from a .o file and returns the info
+ /// (kind, target, addend) needed to instantiate a Reference.
+ /// Two helper functions are passed as parameters to find the target atom
+ /// given a symbol index or address.
+ virtual std::error_code
+ getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend);
+
+ /// Analyzes a pair of relocations from a .o file and returns the info
+ /// (kind, target, addend) needed to instantiate a Reference.
+ /// Two helper functions are passed as parameters to find the target atom
+ /// given a symbol index or address.
+ virtual std::error_code
+ getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend);
+
+ /// Fixup an atom when generating a final linked binary.
virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
Reference::KindValue kindValue, uint64_t addend,
uint8_t *location, uint64_t fixupAddress,
protected:
KindHandler();
+
+ // Handy way to pack mach-o r_type and other bit fields into one 16-bit value.
+ typedef uint16_t RelocPattern;
+ enum {
+ rScattered = 0x8000,
+ rPcRel = 0x4000,
+ rExtern = 0x2000,
+ rLength1 = 0x0000,
+ rLength2 = 0x0100,
+ rLength4 = 0x0200,
+ rLength8 = 0x0300
+ };
+ static RelocPattern relocPattern(const normalized::Relocation &reloc);
+
};
bool isPointer(const Reference &) override;
bool isLazyImmediate(const Reference &) override;
bool isLazyTarget(const Reference &) override;
+ bool isPairedReloc(const normalized::Relocation &) override;
+ std::error_code getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+ std::error_code
+ getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+
virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
Reference::KindValue kindValue, uint64_t addend,
uint8_t *location, uint64_t fixupAddress,
uint64_t targetAddress) override;
+
+private:
+ friend class X86_64LazyPointerAtom;
+ friend class X86_64StubHelperAtom;
+ friend class X86_64StubAtom;
+ friend class X86_64StubHelperCommonAtom;
+ friend class X86_64NonLazyPointerAtom;
+
+ enum : Reference::KindValue {
+ invalid, /// for error condition
+
+ // Kinds found in mach-o .o files:
+ branch32, /// ex: call _foo
+ ripRel32, /// ex: movq _foo(%rip), %rax
+ ripRel32Minus1, /// ex: movb $0x12, _foo(%rip)
+ ripRel32Minus2, /// ex: movw $0x1234, _foo(%rip)
+ ripRel32Minus4, /// ex: movl $0x12345678, _foo(%rip)
+ ripRel32Anon, /// ex: movq L1(%rip), %rax
+ ripRel32GotLoad, /// ex: movq _foo@GOTPCREL(%rip), %rax
+ ripRel32Got, /// ex: pushq _foo@GOTPCREL(%rip)
+ pointer64, /// ex: .quad _foo
+ pointer64Anon, /// ex: .quad L1
+ delta64, /// ex: .quad _foo - .
+ delta32, /// ex: .long _foo - .
+ delta64Anon, /// ex: .quad L1 - .
+ delta32Anon, /// ex: .long L1 - .
+
+ // Kinds introduced by Passes:
+ ripRel32GotLoadNowLea, /// Target of GOT load is in linkage unit so
+ /// "movq _foo@GOTPCREL(%rip), %rax" can be changed
+ /// to "leaq _foo(%rip), %rax
+ lazyPointer, /// Location contains a lazy pointer.
+ lazyImmediateLocation, /// Location contains immediate value used in stub.
+ };
+
+ Reference::KindValue kindFromReloc(const normalized::Relocation &reloc);
+ Reference::KindValue kindFromRelocPair(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2);
+
+
};
class KindHandler_x86 : public KindHandler {
X86_64StubAtom(const File &file, const Atom &lazyPointer)
: SimpleDefinedAtom(file) {
this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86_64, X86_64_RELOC_SIGNED, 2,
+ Reference::KindArch::x86_64,
+ KindHandler_x86_64::ripRel32, 2,
&lazyPointer, 0);
}
const Atom &binder)
: SimpleDefinedAtom(file) {
this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86_64, X86_64_RELOC_SIGNED, 3,
- &cache, 0);
+ Reference::KindArch::x86_64,
+ KindHandler_x86_64::ripRel32, 3, &cache, 0);
this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86_64, X86_64_RELOC_SIGNED, 11,
- &binder, 0);
+ Reference::KindArch::x86_64,
+ KindHandler_x86_64::ripRel32, 11, &binder, 0);
}
ContentType contentType() const override {
: SimpleDefinedAtom(file) {
this->addReference(Reference::KindNamespace::mach_o,
Reference::KindArch::x86_64,
- LLD_X86_64_RELOC_LAZY_IMMEDIATE, 1, this, 0);
+ KindHandler_x86_64::lazyImmediateLocation, 1, this, 0);
this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86_64, X86_64_RELOC_SIGNED, 6,
+ Reference::KindArch::x86_64,
+ KindHandler_x86_64::ripRel32, 6,
&helperCommon, 0);
}
const Atom &shlib)
: SimpleDefinedAtom(file) {
this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86_64, X86_64_RELOC_UNSIGNED, 0,
- &helper, 0);
+ Reference::KindArch::x86_64,
+ KindHandler_x86_64::pointer64, 0, &helper, 0);
this->addReference(Reference::KindNamespace::mach_o,
Reference::KindArch::x86_64,
- LLD_X86_64_RELOC_LAZY_TARGET, 0, &shlib, 0);
+ KindHandler_x86_64::lazyPointer, 0, &shlib, 0);
}
ContentType contentType() const override {
X86_64NonLazyPointerAtom(const File &file, const Atom &shlib)
: SimpleDefinedAtom(file) {
this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86_64, X86_64_RELOC_UNSIGNED, 0,
- &shlib, 0);
+ Reference::KindArch::x86_64,
+ KindHandler_x86_64::pointer64, 0, &shlib, 0);
}
ContentType contentType() const override {
31, C0, 5D, C3 ]
references:
- offset: 7
- kind: X86_64_RELOC_SIGNED
+ kind: ripRel32
target: LC1
- offset: 12
- kind: X86_64_RELOC_BRANCH
+ kind: branch32
target: _printf
- ref-name: LC1
00, 00, 00, 31, C0, 5D, C3 ]
references:
- offset: 7
- kind: X86_64_RELOC_BRANCH
+ kind: branch32
target: _foo
undefined-atoms:
value: 0x0000000000000000
...
-# CHECK: defined-atoms:
-# CHECK: - scope: hidden
+# CHECK:defined-atoms:
+# CHECK: - ref-name: L000
+# CHECK: scope: hidden
# CHECK: type: c-string
# CHECK: content: [ 68, 65, 6C, 6C, 6F, 00 ]
# CHECK: merge: by-content
-# CHECK: - scope: hidden
+# CHECK: - ref-name: L001
+# CHECK: scope: hidden
# CHECK: type: c-string
# CHECK: content: [ 74, 68, 65, 72, 65, 00 ]
# CHECK: merge: by-content
# CHECK: - scope: hidden
# CHECK: type: cfstring
# CHECK: merge: by-content
+# CHECK: references:
+# CHECK: - kind: pointer64
+# CHECK: offset: 0
+# CHECK: target: ___CFConstantStringClassReference
+# CHECK: - kind: pointer64
+# CHECK: offset: 16
+# CHECK: target: L000
# CHECK: - scope: hidden
# CHECK: type: cfstring
# CHECK: merge: by-content
-# CHECK:undefined-atoms:
+# CHECK: references:
+# CHECK: - kind: pointer64
+# CHECK: offset: 0
+# CHECK: target: ___CFConstantStringClassReference
+# CHECK: - kind: pointer64
+# CHECK: offset: 16
+# CHECK: target: L001
+# CHECK:undefined-atoms:
# CHECK: - name: ___CFConstantStringClassReference
+
--- /dev/null
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of x86_64 data relocations.
+#
+#_foo:
+# ret
+#
+#_bar:
+# ret
+#
+# .section __DATA,__custom
+#L1:
+# .quad 0
+#
+# .data
+#_d:
+# .quad _foo
+# .quad _foo+4
+# .quad _foo - .
+# .quad L1
+# .quad L1 + 2
+# .quad _foo - .
+# .quad _foo + 4 - .
+# .quad L1 - .
+# .long _foo - .
+# .long _foo + 4 - .
+# .long L1 - .
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xC3, 0xC3 ]
+ - segment: __DATA
+ section: __custom
+ type: S_REGULAR
+ attributes: [ ]
+ address: 0x0000000000000002
+ content: [ 0x00, 0x00, 0x00, 0x00 ]
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000008
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xD2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xC8, 0xFF, 0xFF, 0xFF, 0xC8, 0xFF, 0xFF, 0xFF,
+ 0xC2, 0xFF, 0xFF, 0xFF ]
+ relocations:
+ - offset: 0x00000040
+ type: X86_64_RELOC_SUBTRACTOR
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000040
+ type: X86_64_RELOC_UNSIGNED
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 2
+ - offset: 0x0000003C
+ type: X86_64_RELOC_SUBTRACTOR
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x0000003C
+ type: X86_64_RELOC_UNSIGNED
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 0
+ - offset: 0x00000038
+ type: X86_64_RELOC_SUBTRACTOR
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000038
+ type: X86_64_RELOC_UNSIGNED
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 0
+ - offset: 0x00000030
+ type: X86_64_RELOC_SUBTRACTOR
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000030
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 2
+ - offset: 0x00000028
+ type: X86_64_RELOC_SUBTRACTOR
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000028
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 0
+ - offset: 0x00000020
+ type: X86_64_RELOC_SUBTRACTOR
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000020
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 0
+ - offset: 0x00000018
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 2
+ - offset: 0x00000010
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 2
+ - offset: 0x00000008
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 0
+ - offset: 0x00000000
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 0
+local-symbols:
+ - name: _foo
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000000
+ - name: _bar
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000001
+ - name: _d
+ type: N_SECT
+ sect: 3
+ value: 0x0000000000000008
+...
+
+
+# CHECK: defined-atoms:
+# CHECK: - name: _d
+# CHECK: type: data
+# CHECK: references:
+# CHECK: - kind: pointer64
+# CHECK: offset: 0
+# CHECK: target: _foo
+# CHECK: - kind: pointer64
+# CHECK: offset: 8
+# CHECK: target: _foo
+# CHECK: addend: 4
+# CHECK: - kind: pointer64Anon
+# CHECK: offset: 16
+# CHECK: target: L003
+# CHECK: - kind: pointer64Anon
+# CHECK: offset: 24
+# CHECK: target: L003
+# CHECK: addend: 2
+# CHECK: - kind: delta64
+# CHECK: offset: 32
+# CHECK: target: _foo
+# CHECK: - kind: delta64
+# CHECK: offset: 40
+# CHECK: target: _foo
+# CHECK: addend: 4
+# CHECK: - kind: delta64Anon
+# CHECK: offset: 48
+# CHECK: target: L003
+# CHECK: - kind: delta32
+# CHECK: offset: 56
+# CHECK: target: _foo
+# CHECK: - kind: delta32
+# CHECK: offset: 60
+# CHECK: target: _foo
+# CHECK: addend: 4
+# CHECK: - kind: delta32Anon
+# CHECK: offset: 64
+# CHECK: target: L003
+# CHECK: - name: _foo
+# CHECK: content: [ C3 ]
+# CHECK: - name: _bar
+# CHECK: content: [ C3 ]
+# CHECK: - ref-name: L003
+# CHECK: type: unknown
+# CHECK: content: [ 00, 00, 00, 00 ]
+# CHECK: section-choice: custom-required
+# CHECK: section-name: __DATA/__custom
length: 3
pc-rel: false
extern: true
- symbol: 1
+ symbol: 0
- offset: 0x00000008
type: X86_64_RELOC_UNSIGNED
length: 3
pc-rel: false
extern: true
- symbol: 2
+ symbol: 1
- segment: __DATA
section: __mod_term_func
type: S_MOD_TERM_FUNC_POINTERS
length: 3
pc-rel: false
extern: true
- symbol: 3
+ symbol: 2
global-symbols:
- name: _init
type: N_SECT
# CHECK: - type: initializer-pointer
# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
# CHECK: dead-strip: never
+# CHECK: references:
+# CHECK: - kind: pointer64
+# CHECK: offset: 0
+# CHECK: target: _init
# CHECK: - type: initializer-pointer
# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
# CHECK: dead-strip: never
+# CHECK: references:
+# CHECK: - kind: pointer64
+# CHECK: offset: 0
+# CHECK: target: _init2
# CHECK: - type: terminator-pointer
# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
# CHECK: dead-strip: never
+# CHECK: references:
+# CHECK: - kind: pointer64
+# CHECK: offset: 0
+# CHECK: target: _term
# CHECK: - name: _init
# CHECK: scope: global
# CHECK: content: [ 55, 48, 89, E5, 5D, C3 ]
--- /dev/null
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of x86_64 text relocations.
+#
+#_test:
+# call _foo
+# call _foo+4
+# movq _foo@GOTPCREL(%rip), %rax
+# pushq _foo@GOTPCREL(%rip)
+# movl _foo(%rip), %eax
+# movl _foo+4(%rip), %eax
+# movb $0x12, _foo(%rip)
+# movw $0x1234, _foo(%rip)
+# movl $0x12345678, _foo(%rip)
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x04, 0x00,
+ 0x00, 0x00, 0x48, 0x8B, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0xFF, 0x35, 0x00, 0x00, 0x00, 0x00, 0x8B,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x05, 0x04,
+ 0x00, 0x00, 0x00, 0xC6, 0x05, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0x12, 0x66, 0xC7, 0x05, 0xFE, 0xFF, 0xFF,
+ 0xFF, 0x34, 0x12, 0xC7, 0x05, 0xFC, 0xFF, 0xFF,
+ 0xFF, 0x78, 0x56, 0x34, 0x12 ]
+ relocations:
+ - offset: 0x00000035
+ type: X86_64_RELOC_SIGNED_4
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x0000002D
+ type: X86_64_RELOC_SIGNED_2
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000025
+ type: X86_64_RELOC_SIGNED_1
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x0000001F
+ type: X86_64_RELOC_SIGNED
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000019
+ type: X86_64_RELOC_SIGNED
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000013
+ type: X86_64_RELOC_GOT
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x0000000D
+ type: X86_64_RELOC_GOT_LOAD
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000006
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000001
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+local-symbols:
+ - name: _test
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _foo
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+...
+# CHECK: defined-atoms:
+# CHECK: - name: _test
+# CHECK: references:
+# CHECK: - kind: branch32
+# CHECK: offset: 1
+# CHECK: target: _foo
+# CHECK: - kind: branch32
+# CHECK: offset: 6
+# CHECK: target: _foo
+# CHECK: addend: 4
+# CHECK: - kind: ripRel32GotLoad
+# CHECK: offset: 13
+# CHECK: target: _foo
+# CHECK: - kind: ripRel32Got
+# CHECK: offset: 19
+# CHECK: target: _foo
+# CHECK: - kind: ripRel32
+# CHECK: offset: 25
+# CHECK: target: _foo
+# CHECK: - kind: ripRel32
+# CHECK: offset: 31
+# CHECK: target: _foo
+# CHECK: addend: 4
+# CHECK: - kind: ripRel32Minus1
+# CHECK: offset: 37
+# CHECK: target: _foo
+# CHECK-NOT: addend:
+# CHECK: - kind: ripRel32Minus2
+# CHECK: offset: 45
+# CHECK: target: _foo
+# CHECK-NOT: addend:
+# CHECK: - kind: ripRel32Minus4
+# CHECK: offset: 53
+# CHECK: target: _foo
+# CHECK-NOT: addend:
+