#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCMachOSymbolFlags.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MachO.h"
Kind == X86::reloc_riprel_4byte_movq_load;
}
+static bool doesSymbolRequireExternRelocation(MCSymbolData *SD) {
+ // Undefined symbols are always extern.
+ if (SD->Symbol->isUndefined())
+ return true;
+
+ // References to weak definitions require external relocation entries; the
+ // definition may not always be the one in the same object file.
+ if (SD->getFlags() & SF_WeakDefinition)
+ return true;
+
+ // Otherwise, we can use an internal relocation.
+ return false;
+}
+
namespace {
class MachObjectWriterImpl {
// Compute the symbol address.
if (Symbol.isDefined()) {
if (Symbol.isAbsolute()) {
- llvm_unreachable("FIXME: Not yet implemented!");
+ Address = cast<MCConstantExpr>(Symbol.getVariableValue())->getValue();
} else {
Address = Layout.getSymbolAddress(&Data);
}
unsigned Log2Size = Log2_32(Align);
assert((1U << Log2Size) == Align && "Invalid 'common' alignment!");
if (Log2Size > 15)
- llvm_report_error("invalid 'common' alignment '" +
+ report_fatal_error("invalid 'common' alignment '" +
Twine(Align) + "'");
// FIXME: Keep this mask with the SymbolFlags enumeration.
Flags = (Flags & 0xF0FF) | (Log2Size << 8);
unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind);
// See <reloc.h>.
- uint32_t Address = Layout.getFragmentOffset(Fragment) + Fixup.Offset;
+ uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.Offset;
+ uint32_t FixupAddress = Layout.getFragmentAddress(Fragment) + Fixup.Offset;
int64_t Value = 0;
unsigned Index = 0;
unsigned IsExtern = 0;
// actual expression addend without the PCrel bias. However, instructions
// with data following the relocation are not accomodated for (see comment
// below regarding SIGNED{1,2,4}), so it isn't exactly that either.
- Value += 1 << Log2Size;
+ Value += 1LL << Log2Size;
}
if (Target.isAbsolute()) { // constant
// Neither symbol can be modified.
if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None ||
Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None)
- llvm_report_error("unsupported relocation of modified symbol");
+ report_fatal_error("unsupported relocation of modified symbol");
// We don't support PCrel relocations of differences. Darwin 'as' doesn't
// implement most of these correctly.
if (IsPCRel)
- llvm_report_error("unsupported pc-relative relocation of difference");
+ report_fatal_error("unsupported pc-relative relocation of difference");
// We don't currently support any situation where one or both of the
// symbols would require a local relocation. This is almost certainly
// unused and may not be possible to encode correctly.
if (!A_Base || !B_Base)
- llvm_report_error("unsupported local relocations in difference");
+ report_fatal_error("unsupported local relocations in difference");
// Darwin 'as' doesn't emit correct relocations for this (it ends up with
// a single SIGNED relocation); reject it for now.
if (A_Base == B_Base)
- llvm_report_error("unsupported relocation with identical base");
+ report_fatal_error("unsupported relocation with identical base");
Value += Layout.getSymbolAddress(&A_SD) - Layout.getSymbolAddress(A_Base);
Value -= Layout.getSymbolAddress(&B_SD) - Layout.getSymbolAddress(B_Base);
Type = RIT_X86_64_Unsigned;
MachRelocationEntry MRE;
- MRE.Word0 = Address;
+ MRE.Word0 = FixupOffset;
MRE.Word1 = ((Index << 0) |
(IsPCRel << 24) |
(Log2Size << 25) |
MCSymbolData &SD = Asm.getSymbolData(*Symbol);
const MCSymbolData *Base = Asm.getAtom(Layout, &SD);
+ // Relocations inside debug sections always use local relocations when
+ // possible. This seems to be done because the debugger doesn't fully
+ // understand x86_64 relocation entries, and expects to find values that
+ // have already been fixed up.
+ if (Symbol->isInSection()) {
+ const MCSectionMachO &Section = static_cast<const MCSectionMachO&>(
+ Fragment->getParent()->getSection());
+ if (Section.hasAttribute(MCSectionMachO::S_ATTR_DEBUG))
+ Base = 0;
+ }
+
// x86_64 almost always uses external relocations, except when there is no
// symbol to use as a base address (a local symbol with no preceeding
// non-local symbol).
// Add the local offset, if needed.
if (Base != &SD)
Value += Layout.getSymbolAddress(&SD) - Layout.getSymbolAddress(Base);
- } else {
- // The index is the section ordinal.
- //
- // FIXME: O(N)
- Index = 1;
- MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end();
- for (; it != ie; ++it, ++Index)
- if (&*it == SD.getFragment()->getParent())
- break;
- assert(it != ie && "Unable to find section index!");
+ } else if (Symbol->isInSection()) {
+ // The index is the section ordinal (1-based).
+ Index = SD.getFragment()->getParent()->getOrdinal() + 1;
IsExtern = 0;
Value += Layout.getSymbolAddress(&SD);
if (IsPCRel)
- Value -= Address + (1 << Log2Size);
+ Value -= FixupAddress + (1 << Log2Size);
+ } else {
+ report_fatal_error("unsupported relocation of undefined symbol '" +
+ Symbol->getName() + "'");
}
MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind();
else
Type = RIT_X86_64_GOT;
} else if (Modifier != MCSymbolRefExpr::VK_None)
- llvm_report_error("unsupported symbol modifier in relocation");
+ report_fatal_error("unsupported symbol modifier in relocation");
else
Type = RIT_X86_64_Signed;
} else {
if (Modifier != MCSymbolRefExpr::VK_None)
- llvm_report_error("unsupported symbol modifier in branch "
+ report_fatal_error("unsupported symbol modifier in branch "
"relocation");
Type = RIT_X86_64_Branch;
// well based on the actual encoded instruction (the additional bias),
// but instead appear to just look at the final offset.
if (IsRIPRel) {
- switch (-(Target.getConstant() + (1 << Log2Size))) {
+ switch (-(Target.getConstant() + (1LL << Log2Size))) {
case 1: Type = RIT_X86_64_Signed1; break;
case 2: Type = RIT_X86_64_Signed2; break;
case 4: Type = RIT_X86_64_Signed4; break;
}
}
} else {
- if (Modifier == MCSymbolRefExpr::VK_GOT)
+ if (Modifier == MCSymbolRefExpr::VK_GOT) {
Type = RIT_X86_64_GOT;
- else if (Modifier != MCSymbolRefExpr::VK_None)
- llvm_report_error("unsupported symbol modifier in relocation");
+ } else if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) {
+ // GOTPCREL is allowed as a modifier on non-PCrel instructions, in
+ // which case all we do is set the PCrel bit in the relocation entry;
+ // this is used with exception handling, for example. The source is
+ // required to include any necessary offset directly.
+ Type = RIT_X86_64_GOT;
+ IsPCRel = 1;
+ } else if (Modifier != MCSymbolRefExpr::VK_None)
+ report_fatal_error("unsupported symbol modifier in relocation");
else
Type = RIT_X86_64_Unsigned;
}
// struct relocation_info (8 bytes)
MachRelocationEntry MRE;
- MRE.Word0 = Address;
+ MRE.Word0 = FixupOffset;
MRE.Word1 = ((Index << 0) |
(IsPCRel << 24) |
(Log2Size << 25) |
const MCFragment *Fragment,
const MCAsmFixup &Fixup, MCValue Target,
uint64_t &FixedValue) {
- uint32_t Address = Layout.getFragmentOffset(Fragment) + Fixup.Offset;
+ uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.Offset;
unsigned IsPCRel = isFixupKindPCRel(Fixup.Kind);
unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind);
unsigned Type = RIT_Vanilla;
MCSymbolData *A_SD = &Asm.getSymbolData(*A);
if (!A_SD->getFragment())
- llvm_report_error("symbol '" + A->getName() +
+ report_fatal_error("symbol '" + A->getName() +
"' can not be undefined in a subtraction expression");
uint32_t Value = Layout.getSymbolAddress(A_SD);
MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
if (!B_SD->getFragment())
- llvm_report_error("symbol '" + B->getSymbol().getName() +
+ report_fatal_error("symbol '" + B->getSymbol().getName() +
"' can not be undefined in a subtraction expression");
// Select the appropriate difference relocation type.
}
MachRelocationEntry MRE;
- MRE.Word0 = ((Address << 0) |
- (Type << 24) |
- (Log2Size << 28) |
- (IsPCRel << 30) |
+ MRE.Word0 = ((FixupOffset << 0) |
+ (Type << 24) |
+ (Log2Size << 28) |
+ (IsPCRel << 30) |
RF_Scattered);
MRE.Word1 = Value;
Relocations[Fragment->getParent()].push_back(MRE);
// If this is a difference or a defined symbol plus an offset, then we need
// a scattered relocation entry.
+ // Differences always require scattered relocations.
+ if (Target.getSymB())
+ return RecordScatteredRelocation(Asm, Layout, Fragment, Fixup,
+ Target, FixedValue);
+
+ // Get the symbol data, if any.
+ MCSymbolData *SD = 0;
+ if (Target.getSymA())
+ SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
+
+ // If this is an internal relocation with an offset, it also needs a
+ // scattered relocation entry.
uint32_t Offset = Target.getConstant();
if (IsPCRel)
Offset += 1 << Log2Size;
- if (Target.getSymB() ||
- (Target.getSymA() && !Target.getSymA()->getSymbol().isUndefined() &&
- Offset)) {
- RecordScatteredRelocation(Asm, Layout, Fragment, Fixup,Target,FixedValue);
- return;
- }
+ if (Offset && SD && !doesSymbolRequireExternRelocation(SD))
+ return RecordScatteredRelocation(Asm, Layout, Fragment, Fixup,
+ Target, FixedValue);
// See <reloc.h>.
- uint32_t Address = Layout.getFragmentOffset(Fragment) + Fixup.Offset;
+ uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.Offset;
uint32_t Value = 0;
unsigned Index = 0;
unsigned IsExtern = 0;
Type = RIT_Vanilla;
Value = 0;
} else {
- const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
- MCSymbolData *SD = &Asm.getSymbolData(*Symbol);
-
- if (Symbol->isUndefined()) {
+ // Check whether we need an external or internal relocation.
+ if (doesSymbolRequireExternRelocation(SD)) {
IsExtern = 1;
Index = SD->getIndex();
+ // For external relocations, make sure to offset the fixup value to
+ // compensate for the addend of the symbol address, if it was
+ // undefined. This occurs with weak definitions, for example.
+ if (!SD->Symbol->isUndefined())
+ FixedValue -= Layout.getSymbolAddress(SD);
Value = 0;
} else {
- // The index is the section ordinal.
- //
- // FIXME: O(N)
- Index = 1;
- MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end();
- for (; it != ie; ++it, ++Index)
- if (&*it == SD->getFragment()->getParent())
- break;
- assert(it != ie && "Unable to find section index!");
+ // The index is the section ordinal (1-based).
+ Index = SD->getFragment()->getParent()->getOrdinal() + 1;
Value = Layout.getSymbolAddress(SD);
}
// struct relocation_info (8 bytes)
MachRelocationEntry MRE;
- MRE.Word0 = Address;
+ MRE.Word0 = FixupOffset;
MRE.Word1 = ((Index << 0) |
(IsPCRel << 24) |
(Log2Size << 25) |