[mach-o] add initial support for modes in arm code.

This patch just supports marking ranges that are thumb code (vs arm code).
Future patches will mark data and jump table ranges. The ranges are encoded
as References with offsetInAtom being the start of the range and the target
being the same atom.

llvm-svn: 213712
This commit is contained in:
Nick Kledzik 2014-07-23 00:51:37 +00:00
parent 16d99f93a8
commit 7e9808f7de
6 changed files with 103 additions and 7 deletions

View File

@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "MachONormalizedFile.h"
#include "Atoms.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/Reference.h"
@ -136,6 +137,11 @@ public:
FindAddressForAtom,
normalized::Relocations&) = 0;
/// Add arch-specific References.
virtual void addAdditionalReferences(MachODefinedAtom &atom) { }
/// Only relevant for 32-bit arm archs.
virtual bool isThumbFunction(const DefinedAtom &atom) { return false; }
struct ReferenceInfo {
Reference::KindArch arch;

View File

@ -69,6 +69,9 @@ public:
FindAddressForAtom,
normalized::Relocations &) override;
void addAdditionalReferences(MachODefinedAtom &atom) override;
bool isThumbFunction(const DefinedAtom &atom) override;
private:
static const Registry::KindStrings _sKindStrings[];
@ -77,6 +80,9 @@ private:
enum : Reference::KindValue {
invalid, /// for error condition
modeThumbCode, /// Content starting at this offset is thumb.
modeArmCode, /// Content starting at this offset is arm.
// Kinds found in mach-o .o files:
thumb_b22, /// ex: bl _foo
thumb_movw, /// ex: movw r1, :lower16:_foo
@ -115,12 +121,12 @@ private:
void applyFixupFinal(const Reference &ref, uint8_t *location,
uint64_t fixupAddress, uint64_t targetAddress,
uint64_t inAtomAddress);
uint64_t inAtomAddress, bool &thumbMode);
void applyFixupRelocatable(const Reference &ref, uint8_t *location,
uint64_t fixupAddress,
uint64_t targetAddress,
uint64_t inAtomAddress);
uint64_t inAtomAddress, bool &thumbMode);
const bool _swap;
};
@ -135,6 +141,8 @@ ArchHandler_arm::ArchHandler_arm() :
ArchHandler_arm::~ArchHandler_arm() { }
const Registry::KindStrings ArchHandler_arm::_sKindStrings[] = {
LLD_KIND_STRING_ENTRY(modeThumbCode),
LLD_KIND_STRING_ENTRY(modeArmCode),
LLD_KIND_STRING_ENTRY(thumb_b22),
LLD_KIND_STRING_ENTRY(thumb_movw),
LLD_KIND_STRING_ENTRY(thumb_movt),
@ -712,7 +720,8 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *location,
uint64_t fixupAddress,
uint64_t targetAddress,
uint64_t inAtomAddress) {
uint64_t inAtomAddress,
bool &thumbMode) {
if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
return;
assert(ref.kindArch() == Reference::KindArch::ARM);
@ -720,43 +729,59 @@ void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *location,
int32_t displacement;
uint16_t value16;
switch (ref.kindValue()) {
case modeThumbCode:
thumbMode = true;
break;
case modeArmCode:
thumbMode = false;
break;
case thumb_b22:
assert(thumbMode);
displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
write32(*loc32, _swap, setDisplacementInThumbBranch(*loc32, displacement));
break;
case thumb_movw:
assert(thumbMode);
value16 = (targetAddress + ref.addend()) & 0xFFFF;
write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
break;
case thumb_movt:
assert(thumbMode);
value16 = (targetAddress + ref.addend()) >> 16;
write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
break;
case thumb_movw_funcRel:
assert(thumbMode);
value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
break;
case thumb_movt_funcRel:
assert(thumbMode);
value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
break;
case arm_b24:
assert(!thumbMode);
displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
*loc32 = setDisplacementInArmBranch(*loc32, displacement);
break;
case arm_movw:
assert(!thumbMode);
value16 = (targetAddress + ref.addend()) & 0xFFFF;
write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
break;
case arm_movt:
assert(!thumbMode);
value16 = (targetAddress + ref.addend()) >> 16;
write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
break;
case arm_movw_funcRel:
assert(!thumbMode);
value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
break;
case arm_movt_funcRel:
assert(!thumbMode);
value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
break;
@ -783,6 +808,7 @@ void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom,
// Copy raw bytes.
memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
// Apply fix-ups.
bool thumbMode = false;
for (const Reference *ref : atom) {
uint32_t offset = ref->offsetInAtom();
const Atom *target = ref->target();
@ -794,11 +820,11 @@ void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom,
if (relocatable) {
applyFixupRelocatable(*ref, &atomContentBuffer[offset],
fixupAddress, targetAddress,
atomAddress);
atomAddress, thumbMode);
} else {
applyFixupFinal(*ref, &atomContentBuffer[offset],
fixupAddress, targetAddress,
atomAddress);
atomAddress, thumbMode);
}
}
}
@ -829,13 +855,21 @@ void ArchHandler_arm::applyFixupRelocatable(const Reference &ref,
uint8_t *location,
uint64_t fixupAddress,
uint64_t targetAddress,
uint64_t inAtomAddress) {
uint64_t inAtomAddress,
bool &thumbMode) {
bool useExternalReloc = useExternalRelocationTo(*ref.target());
int32_t *loc32 = reinterpret_cast<int32_t *>(location);
int32_t displacement;
uint16_t value16;
switch (ref.kindValue()) {
case modeThumbCode:
thumbMode = true;
break;
case modeArmCode:
thumbMode = false;
break;
case thumb_b22:
assert(thumbMode);
if (useExternalReloc)
displacement = (ref.addend() - (fixupAddress + 4));
else
@ -843,6 +877,7 @@ void ArchHandler_arm::applyFixupRelocatable(const Reference &ref,
write32(*loc32, _swap, setDisplacementInThumbBranch(*loc32, displacement));
break;
case thumb_movw:
assert(thumbMode);
if (useExternalReloc)
value16 = ref.addend() & 0xFFFF;
else
@ -850,6 +885,7 @@ void ArchHandler_arm::applyFixupRelocatable(const Reference &ref,
write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
break;
case thumb_movt:
assert(thumbMode);
if (useExternalReloc)
value16 = ref.addend() >> 16;
else
@ -857,14 +893,17 @@ void ArchHandler_arm::applyFixupRelocatable(const Reference &ref,
write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
break;
case thumb_movw_funcRel:
assert(thumbMode);
value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
break;
case thumb_movt_funcRel:
assert(thumbMode);
value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
break;
case arm_b24:
assert(!thumbMode);
if (useExternalReloc)
displacement = (ref.addend() - (fixupAddress + 8));
else
@ -872,6 +911,7 @@ void ArchHandler_arm::applyFixupRelocatable(const Reference &ref,
write32(*loc32, _swap, setDisplacementInArmBranch(*loc32, displacement));
break;
case arm_movw:
assert(!thumbMode);
if (useExternalReloc)
value16 = ref.addend() & 0xFFFF;
else
@ -879,6 +919,7 @@ void ArchHandler_arm::applyFixupRelocatable(const Reference &ref,
write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
break;
case arm_movt:
assert(!thumbMode);
if (useExternalReloc)
value16 = ref.addend() >> 16;
else
@ -886,10 +927,12 @@ void ArchHandler_arm::applyFixupRelocatable(const Reference &ref,
write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
break;
case arm_movw_funcRel:
assert(!thumbMode);
value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
break;
case arm_movt_funcRel:
assert(!thumbMode);
value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
break;
@ -926,6 +969,10 @@ void ArchHandler_arm::appendSectionRelocations(
uint32_t fromAtomAddress;
uint16_t other16;
switch (ref.kindValue()) {
case modeThumbCode:
case modeArmCode:
// Do nothing.
break;
case thumb_b22:
if (useExternalReloc) {
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
@ -1115,6 +1162,25 @@ void ArchHandler_arm::appendSectionRelocations(
}
}
void ArchHandler_arm::addAdditionalReferences(MachODefinedAtom &atom) {
if (atom.isThumb()) {
atom.addReference(0, modeThumbCode, &atom, 0, Reference::KindArch::ARM);
}
}
bool ArchHandler_arm::isThumbFunction(const DefinedAtom &atom) {
for (const Reference *ref : atom) {
if (ref->offsetInAtom() != 0)
return false;
if (ref->kindNamespace() != Reference::KindNamespace::mach_o)
continue;
assert(ref->kindArch() == Reference::KindArch::ARM);
if (ref->kindValue() == modeThumbCode)
return true;
}
return false;
}
std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() {
return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm());
}

View File

@ -139,6 +139,16 @@ public:
return pos->second;
}
typedef std::function<void (MachODefinedAtom* atom)> DefinedAtomVisitor;
void eachDefinedAtom(DefinedAtomVisitor vistor) {
for (auto &sectAndAtoms : _sectionAtoms) {
for (auto &offAndAtom : sectAndAtoms.second) {
vistor(offAndAtom.atom);
}
}
}
llvm::BumpPtrAllocator &allocator() { return _allocator; }
private:

View File

@ -617,6 +617,8 @@ uint16_t Util::descBits(const DefinedAtom* atom) {
}
if (atom->contentType() == lld::DefinedAtom::typeResolver)
desc |= N_SYMBOL_RESOLVER;
if (_archHandler.isThumbFunction(*atom))
desc |= N_ARM_THUMB_DEF;
return desc;
}
@ -656,7 +658,7 @@ void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) {
sym.type = N_SECT;
sym.scope = scopeBits(atom);
sym.sect = sect->finalSectionIndex;
sym.desc = 0;
sym.desc = descBits(atom);
sym.value = _atomToAddress[atom];
_atomToSymbolIndex[atom] = file.localSymbols.size();
file.localSymbols.push_back(sym);

View File

@ -562,6 +562,7 @@ std::error_code convertRelocs(const Section &section,
handler.kindArch());
}
}
return std::error_code();
}
@ -606,6 +607,11 @@ normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
return ec;
}
// Add additional arch-specific References
file->eachDefinedAtom([&](MachODefinedAtom* atom) -> void {
handler->addAdditionalReferences(*atom);
});
// Sort references in each atom to their canonical order.
for (const DefinedAtom* defAtom : file->defined()) {
reinterpret_cast<const SimpleDefinedAtom*>(defAtom)->sortReferences();

View File

@ -570,6 +570,8 @@ undefined-symbols:
# CHECK: addend: 4
# CHECK: - name: _foo_thumb
# CHECK: references:
# CHECK: - kind: modeThumbCode
# CHECK: offset: 0
# CHECK: - kind: thumb_b22
# CHECK: offset: 0
# CHECK: target: _x
@ -652,8 +654,12 @@ undefined-symbols:
# CHECK: addend: 8
# CHECK: - name: _t1
# CHECK: content: [ C0, 46 ]
# CHECK: references:
# CHECK: - kind: modeThumbCode
# CHECK: offset: 0
# CHECK: - name: _foo_arm
# CHECK: references:
# CHECK-NOT: - kind: modeThumbCode
# CHECK: - kind: arm_b24
# CHECK: offset: 0
# CHECK: target: _x