#include "llvm/Support/LEB128.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/MC/MCSectionELF.h"
#include <tuple>
using namespace llvm;
return F->Offset;
}
-uint64_t MCAsmLayout::getSymbolOffset(const MCSymbolData *SD) const {
+// Simple getSymbolOffset helper for the non-varibale case.
+static bool getLabelOffset(const MCAsmLayout &Layout, const MCSymbolData &SD,
+ bool ReportError, uint64_t &Val) {
+ if (!SD.getFragment()) {
+ if (ReportError)
+ report_fatal_error("unable to evaluate offset to undefined symbol '" +
+ SD.getSymbol().getName() + "'");
+ return false;
+ }
+ Val = Layout.getFragmentOffset(SD.getFragment()) + SD.getOffset();
+ return true;
+}
+
+static bool getSymbolOffsetImpl(const MCAsmLayout &Layout,
+ const MCSymbolData *SD, bool ReportError,
+ uint64_t &Val) {
const MCSymbol &S = SD->getSymbol();
- // If this is a variable, then recursively evaluate now.
- if (S.isVariable()) {
- MCValue Target;
- if (!S.getVariableValue()->EvaluateAsRelocatable(Target, this))
- report_fatal_error("unable to evaluate offset for variable '" +
- S.getName() + "'");
+ if (!S.isVariable())
+ return getLabelOffset(Layout, *SD, ReportError, Val);
- // Verify that any used symbols are defined.
- if (Target.getSymA() && Target.getSymA()->getSymbol().isUndefined())
- report_fatal_error("unable to evaluate offset to undefined symbol '" +
- Target.getSymA()->getSymbol().getName() + "'");
- if (Target.getSymB() && Target.getSymB()->getSymbol().isUndefined())
- report_fatal_error("unable to evaluate offset to undefined symbol '" +
- Target.getSymB()->getSymbol().getName() + "'");
-
- uint64_t Offset = Target.getConstant();
- if (Target.getSymA())
- Offset += getSymbolOffset(&Assembler.getSymbolData(
- Target.getSymA()->getSymbol()));
- if (Target.getSymB())
- Offset -= getSymbolOffset(&Assembler.getSymbolData(
- Target.getSymB()->getSymbol()));
- return Offset;
+ // If SD is a variable, evaluate it.
+ MCValue Target;
+ if (!S.getVariableValue()->EvaluateAsValue(Target, &Layout, nullptr))
+ report_fatal_error("unable to evaluate offset for variable '" +
+ S.getName() + "'");
+
+ uint64_t Offset = Target.getConstant();
+
+ const MCAssembler &Asm = Layout.getAssembler();
+
+ const MCSymbolRefExpr *A = Target.getSymA();
+ if (A) {
+ uint64_t ValA;
+ if (!getLabelOffset(Layout, Asm.getSymbolData(A->getSymbol()), ReportError,
+ ValA))
+ return false;
+ Offset += ValA;
+ }
+
+ const MCSymbolRefExpr *B = Target.getSymB();
+ if (B) {
+ uint64_t ValB;
+ if (!getLabelOffset(Layout, Asm.getSymbolData(B->getSymbol()), ReportError,
+ ValB))
+ return false;
+ Offset -= ValB;
}
- assert(SD->getFragment() && "Invalid getOffset() on undefined symbol!");
- return getFragmentOffset(SD->getFragment()) + SD->getOffset();
+ Val = Offset;
+ return true;
+}
+
+bool MCAsmLayout::getSymbolOffset(const MCSymbolData *SD, uint64_t &Val) const {
+ return getSymbolOffsetImpl(*this, SD, false, Val);
+}
+
+uint64_t MCAsmLayout::getSymbolOffset(const MCSymbolData *SD) const {
+ uint64_t Val;
+ getSymbolOffsetImpl(*this, SD, true, Val);
+ return Val;
+}
+
+const MCSymbol *MCAsmLayout::getBaseSymbol(const MCSymbol &Symbol) const {
+ if (!Symbol.isVariable())
+ return &Symbol;
+
+ const MCExpr *Expr = Symbol.getVariableValue();
+ MCValue Value;
+ if (!Expr->EvaluateAsValue(Value, this, nullptr))
+ llvm_unreachable("Invalid Expression");
+
+ const MCSymbolRefExpr *RefB = Value.getSymB();
+ if (RefB)
+ Assembler.getContext().FatalError(
+ SMLoc(), Twine("symbol '") + RefB->getSymbol().getName() +
+ "' could not be evaluated in a subtraction expression");
+
+ const MCSymbolRefExpr *A = Value.getSymA();
+ if (!A)
+ return nullptr;
+
+ return &A->getSymbol();
}
uint64_t MCAsmLayout::getSectionAddressSize(const MCSectionData *SD) const {
if (!Symbol->isVariable())
return false;
- // FIXME: It looks like gas support some cases of the form "foo + 2". It
+ // FIXME: It looks like gas supports some cases of the form "foo + 2". It
// is not clear if that is a bug or a feature.
const MCExpr *Expr = Symbol->getVariableValue();
const MCSymbolRefExpr *Ref = dyn_cast<MCSymbolRefExpr>(Expr);
return SD->getFragment()->getAtom();
}
+// Try to fully compute Expr to an absolute value and if that fails produce
+// a relocatable expr.
+// FIXME: Should this be the behavior of EvaluateAsRelocatable itself?
+static bool evaluate(const MCExpr &Expr, const MCAsmLayout &Layout,
+ const MCFixup &Fixup, MCValue &Target) {
+ if (Expr.EvaluateAsValue(Target, &Layout, &Fixup)) {
+ if (Target.isAbsolute())
+ return true;
+ }
+ return Expr.EvaluateAsRelocatable(Target, &Layout, &Fixup);
+}
+
bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout,
const MCFixup &Fixup, const MCFragment *DF,
MCValue &Target, uint64_t &Value) const {
++stats::evaluateFixup;
- if (!Fixup.getValue()->EvaluateAsRelocatable(Target, &Layout))
+ // FIXME: This code has some duplication with RecordRelocation. We should
+ // probably merge the two into a single callback that tries to evaluate a
+ // fixup and records a relocation if one is needed.
+ const MCExpr *Expr = Fixup.getValue();
+ if (!evaluate(*Expr, Layout, Fixup, Target))
getContext().FatalError(Fixup.getLoc(), "expected relocatable expression");
bool IsPCRel = Backend.getFixupKindInfo(
assert(DF.fixup_begin() == DF.fixup_end() &&
"Cannot have fixups in virtual section!");
for (unsigned i = 0, e = DF.getContents().size(); i != e; ++i)
- assert(DF.getContents()[i] == 0 &&
- "Invalid data value for virtual section!");
+ if (DF.getContents()[i]) {
+ if (auto *ELFSec = dyn_cast<const MCSectionELF>(&SD->getSection()))
+ report_fatal_error("non-zero initializer found in section '" +
+ ELFSec->getSectionName() + "'");
+ else
+ report_fatal_error("non-zero initializer found in virtual section");
+ }
break;
}
case MCFragment::FT_Align:
}
bool MCAssembler::relaxLEB(MCAsmLayout &Layout, MCLEBFragment &LF) {
- int64_t Value = 0;
uint64_t OldSize = LF.getContents().size();
- bool IsAbs = LF.getValue().EvaluateAsAbsolute(Value, Layout);
- (void)IsAbs;
- assert(IsAbs);
+ int64_t Value = LF.getValue().evaluateKnownAbsolute(Layout);
SmallString<8> &Data = LF.getContents();
Data.clear();
raw_svector_ostream OSE(Data);
bool MCAssembler::relaxDwarfLineAddr(MCAsmLayout &Layout,
MCDwarfLineAddrFragment &DF) {
MCContext &Context = Layout.getAssembler().getContext();
- int64_t AddrDelta = 0;
uint64_t OldSize = DF.getContents().size();
- bool IsAbs = DF.getAddrDelta().EvaluateAsAbsolute(AddrDelta, Layout);
- (void)IsAbs;
- assert(IsAbs);
+ int64_t AddrDelta = DF.getAddrDelta().evaluateKnownAbsolute(Layout);
int64_t LineDelta;
LineDelta = DF.getLineDelta();
SmallString<8> &Data = DF.getContents();
bool MCAssembler::relaxDwarfCallFrameFragment(MCAsmLayout &Layout,
MCDwarfCallFrameFragment &DF) {
MCContext &Context = Layout.getAssembler().getContext();
- int64_t AddrDelta = 0;
uint64_t OldSize = DF.getContents().size();
- bool IsAbs = DF.getAddrDelta().EvaluateAsAbsolute(AddrDelta, Layout);
- (void)IsAbs;
- assert(IsAbs);
+ int64_t AddrDelta = DF.getAddrDelta().evaluateKnownAbsolute(Layout);
SmallString<8> &Data = DF.getContents();
Data.clear();
raw_svector_ostream OSE(Data);
OS << "]>";
}
-void MCSymbolData::dump() {
+void MCSymbolData::dump() const {
raw_ostream &OS = llvm::errs();
OS << "<MCSymbolData Symbol:" << getSymbol()