aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/MC/MCAssembler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/MC/MCAssembler.cpp')
-rw-r--r--contrib/llvm/lib/MC/MCAssembler.cpp220
1 files changed, 163 insertions, 57 deletions
diff --git a/contrib/llvm/lib/MC/MCAssembler.cpp b/contrib/llvm/lib/MC/MCAssembler.cpp
index 68111f187d38..a8aad7124bdb 100644
--- a/contrib/llvm/lib/MC/MCAssembler.cpp
+++ b/contrib/llvm/lib/MC/MCAssembler.cpp
@@ -7,7 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "assembler"
#include "llvm/MC/MCAssembler.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
@@ -28,9 +27,12 @@
#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;
+#define DEBUG_TYPE "assembler"
+
namespace {
namespace stats {
STATISTIC(EmittedFragments, "Number of emitted assembler fragments - total");
@@ -116,36 +118,89 @@ uint64_t MCAsmLayout::getFragmentOffset(const MCFragment *F) const {
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))
+ 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;
}
- assert(SD->getFragment() && "Invalid getOffset() on undefined symbol!");
- return getFragmentOffset(SD->getFragment()) + SD->getOffset();
+ const MCSymbolRefExpr *B = Target.getSymB();
+ if (B) {
+ uint64_t ValB;
+ if (!getLabelOffset(Layout, Asm.getSymbolData(B->getSymbol()), ReportError,
+ ValB))
+ return false;
+ Offset -= ValB;
+ }
+
+ 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))
+ 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 {
@@ -212,7 +267,7 @@ MCFragment::~MCFragment() {
}
MCFragment::MCFragment(FragmentType _Kind, MCSectionData *_Parent)
- : Kind(_Kind), Parent(_Parent), Atom(0), Offset(~UINT64_C(0))
+ : Kind(_Kind), Parent(_Parent), Atom(nullptr), Offset(~UINT64_C(0))
{
if (Parent)
Parent->getFragmentList().push_back(this);
@@ -230,7 +285,7 @@ MCEncodedFragmentWithFixups::~MCEncodedFragmentWithFixups() {
/* *** */
-MCSectionData::MCSectionData() : Section(0) {}
+MCSectionData::MCSectionData() : Section(nullptr) {}
MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A)
: Section(&_Section),
@@ -250,7 +305,7 @@ MCSectionData::getSubsectionInsertionPoint(unsigned Subsection) {
SmallVectorImpl<std::pair<unsigned, MCFragment *> >::iterator MI =
std::lower_bound(SubsectionFragmentMap.begin(), SubsectionFragmentMap.end(),
- std::make_pair(Subsection, (MCFragment *)0));
+ std::make_pair(Subsection, (MCFragment *)nullptr));
bool ExactMatch = false;
if (MI != SubsectionFragmentMap.end()) {
ExactMatch = MI->first == Subsection;
@@ -275,13 +330,13 @@ MCSectionData::getSubsectionInsertionPoint(unsigned Subsection) {
/* *** */
-MCSymbolData::MCSymbolData() : Symbol(0) {}
+MCSymbolData::MCSymbolData() : Symbol(nullptr) {}
MCSymbolData::MCSymbolData(const MCSymbol &_Symbol, MCFragment *_Fragment,
uint64_t _Offset, MCAssembler *A)
: Symbol(&_Symbol), Fragment(_Fragment), Offset(_Offset),
IsExternal(false), IsPrivateExtern(false),
- CommonSize(0), SymbolSize(0), CommonAlign(0),
+ CommonSize(0), SymbolSize(nullptr), CommonAlign(0),
Flags(0), Index(0)
{
if (A)
@@ -296,6 +351,7 @@ MCAssembler::MCAssembler(MCContext &Context_, MCAsmBackend &Backend_,
: Context(Context_), Backend(Backend_), Emitter(Emitter_), Writer(Writer_),
OS(OS_), BundleAlignSize(0), RelaxAll(false), NoExecStack(false),
SubsectionsViaSymbols(false), ELFHeaderEFlags(0) {
+ VersionMinInfo.Major = 0; // Major version == 0 for "none specified"
}
MCAssembler::~MCAssembler() {
@@ -318,6 +374,32 @@ void MCAssembler::reset() {
getBackend().reset();
getEmitter().reset();
getWriter().reset();
+ getLOHContainer().reset();
+}
+
+bool MCAssembler::isThumbFunc(const MCSymbol *Symbol) const {
+ if (ThumbFuncs.count(Symbol))
+ return true;
+
+ if (!Symbol->isVariable())
+ return false;
+
+ // 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);
+ if (!Ref)
+ return false;
+
+ if (Ref->getKind() != MCSymbolRefExpr::VK_None)
+ return false;
+
+ const MCSymbol &Sym = Ref->getSymbol();
+ if (!isThumbFunc(&Sym))
+ return false;
+
+ ThumbFuncs.insert(Symbol); // Cache it.
+ return true;
}
bool MCAssembler::isSymbolLinkerVisible(const MCSymbol &Symbol) const {
@@ -340,24 +422,39 @@ const MCSymbolData *MCAssembler::getAtom(const MCSymbolData *SD) const {
// Absolute and undefined symbols have no defining atom.
if (!SD->getFragment())
- return 0;
+ return nullptr;
// Non-linker visible symbols in sections which can't be atomized have no
// defining atom.
if (!getBackend().isSectionAtomizable(
SD->getFragment()->getParent()->getSection()))
- return 0;
+ return nullptr;
// Otherwise, return the atom for the containing fragment.
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,
+ MCValue &Target) {
+ if (Expr.EvaluateAsValue(Target, &Layout))
+ if (Target.isAbsolute())
+ return true;
+ return Expr.EvaluateAsRelocatable(Target, &Layout);
+}
+
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, Target))
getContext().FatalError(Fixup.getLoc(), "expected relocatable expression");
bool IsPCRel = Backend.getFixupKindInfo(
@@ -701,8 +798,13 @@ void MCAssembler::writeSectionData(const MCSectionData *SD,
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:
@@ -734,21 +836,23 @@ void MCAssembler::writeSectionData(const MCSectionData *SD,
Layout.getSectionAddressSize(SD));
}
-
-uint64_t MCAssembler::handleFixup(const MCAsmLayout &Layout,
- MCFragment &F,
- const MCFixup &Fixup) {
- // Evaluate the fixup.
- MCValue Target;
- uint64_t FixedValue;
- if (!evaluateFixup(Layout, Fixup, &F, Target, FixedValue)) {
- // The fixup was unresolved, we need a relocation. Inform the object
- // writer of the relocation, and give it an opportunity to adjust the
- // fixup value if need be.
- getWriter().RecordRelocation(*this, Layout, &F, Fixup, Target, FixedValue);
- }
- return FixedValue;
- }
+std::pair<uint64_t, bool> MCAssembler::handleFixup(const MCAsmLayout &Layout,
+ MCFragment &F,
+ const MCFixup &Fixup) {
+ // Evaluate the fixup.
+ MCValue Target;
+ uint64_t FixedValue;
+ bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags &
+ MCFixupKindInfo::FKF_IsPCRel;
+ if (!evaluateFixup(Layout, Fixup, &F, Target, FixedValue)) {
+ // The fixup was unresolved, we need a relocation. Inform the object
+ // writer of the relocation, and give it an opportunity to adjust the
+ // fixup value if need be.
+ getWriter().RecordRelocation(*this, Layout, &F, Fixup, Target, IsPCRel,
+ FixedValue);
+ }
+ return std::make_pair(FixedValue, IsPCRel);
+}
void MCAssembler::Finish() {
DEBUG_WITH_TYPE("mc-dump", {
@@ -811,9 +915,11 @@ void MCAssembler::Finish() {
for (MCEncodedFragmentWithFixups::fixup_iterator it3 = F->fixup_begin(),
ie3 = F->fixup_end(); it3 != ie3; ++it3) {
MCFixup &Fixup = *it3;
- uint64_t FixedValue = handleFixup(Layout, *F, Fixup);
+ uint64_t FixedValue;
+ bool IsPCRel;
+ std::tie(FixedValue, IsPCRel) = handleFixup(Layout, *F, Fixup);
getBackend().applyFixup(Fixup, F->getContents().data(),
- F->getContents().size(), FixedValue);
+ F->getContents().size(), FixedValue, IsPCRel);
}
}
}
@@ -875,7 +981,7 @@ bool MCAssembler::relaxInstruction(MCAsmLayout &Layout,
SmallVector<MCFixup, 4> Fixups;
SmallString<256> Code;
raw_svector_ostream VecOS(Code);
- getEmitter().EncodeInstruction(Relaxed, VecOS, Fixups);
+ getEmitter().EncodeInstruction(Relaxed, VecOS, Fixups, F.getSubtargetInfo());
VecOS.flush();
// Update the fragment.
@@ -942,7 +1048,7 @@ bool MCAssembler::layoutSectionOnce(MCAsmLayout &Layout, MCSectionData &SD) {
// remain NULL if none were relaxed.
// When a fragment is relaxed, all the fragments following it should get
// invalidated because their offset is going to change.
- MCFragment *FirstRelaxedFragment = NULL;
+ MCFragment *FirstRelaxedFragment = nullptr;
// Attempt to relax all the fragments in the section.
for (MCSectionData::iterator I = SD.begin(), IE = SD.end(); I != IE; ++I) {
@@ -1137,7 +1243,7 @@ void MCSectionData::dump() {
OS << "]>";
}
-void MCSymbolData::dump() {
+void MCSymbolData::dump() const {
raw_ostream &OS = llvm::errs();
OS << "<MCSymbolData Symbol:" << getSymbol()