aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/MC/MCObjectStreamer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/MC/MCObjectStreamer.cpp')
-rw-r--r--llvm/lib/MC/MCObjectStreamer.cpp75
1 files changed, 72 insertions, 3 deletions
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
index e39c4a0..78ee215 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -665,6 +665,68 @@ void MCObjectStreamer::emitGPRel64Value(const MCExpr *Value) {
DF->getContents().resize(DF->getContents().size() + 8, 0);
}
+static Optional<std::pair<bool, std::string>>
+getOffsetAndDataFragment(const MCSymbol &Symbol, uint32_t &RelocOffset,
+ MCDataFragment *&DF) {
+ if (Symbol.isVariable()) {
+ const MCExpr *SymbolExpr = Symbol.getVariableValue();
+ MCValue OffsetVal;
+ if(!SymbolExpr->evaluateAsRelocatable(OffsetVal, nullptr, nullptr))
+ return std::make_pair(false,
+ std::string("symbol in .reloc offset is not "
+ "relocatable"));
+ if (OffsetVal.isAbsolute()) {
+ RelocOffset = OffsetVal.getConstant();
+ MCFragment *Fragment = Symbol.getFragment();
+ // FIXME Support symbols with no DF. For example:
+ // .reloc .data, ENUM_VALUE, <some expr>
+ if (!Fragment || Fragment->getKind() != MCFragment::FT_Data)
+ return std::make_pair(false,
+ std::string("symbol in offset has no data "
+ "fragment"));
+ DF = cast<MCDataFragment>(Fragment);
+ return None;
+ }
+
+ if (OffsetVal.getSymB())
+ return std::make_pair(false,
+ std::string(".reloc symbol offset is not "
+ "representable"));
+
+ const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*OffsetVal.getSymA());
+ if (!SRE.getSymbol().isDefined())
+ return std::make_pair(false,
+ std::string("symbol used in the .reloc offset is "
+ "not defined"));
+
+ if (SRE.getSymbol().isVariable())
+ return std::make_pair(false,
+ std::string("symbol used in the .reloc offset is "
+ "variable"));
+
+ MCFragment *Fragment = SRE.getSymbol().getFragment();
+ // FIXME Support symbols with no DF. For example:
+ // .reloc .data, ENUM_VALUE, <some expr>
+ if (!Fragment || Fragment->getKind() != MCFragment::FT_Data)
+ return std::make_pair(false,
+ std::string("symbol in offset has no data "
+ "fragment"));
+ RelocOffset = SRE.getSymbol().getOffset() + OffsetVal.getConstant();
+ DF = cast<MCDataFragment>(Fragment);
+ } else {
+ RelocOffset = Symbol.getOffset();
+ MCFragment *Fragment = Symbol.getFragment();
+ // FIXME Support symbols with no DF. For example:
+ // .reloc .data, ENUM_VALUE, <some expr>
+ if (!Fragment || Fragment->getKind() != MCFragment::FT_Data)
+ return std::make_pair(false,
+ std::string("symbol in offset has no data "
+ "fragment"));
+ DF = cast<MCDataFragment>(Fragment);
+ }
+ return None;
+}
+
Optional<std::pair<bool, std::string>>
MCObjectStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
const MCExpr *Expr, SMLoc Loc,
@@ -698,10 +760,17 @@ MCObjectStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
std::string(".reloc offset is not representable"));
const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*OffsetVal.getSymA());
- if (SRE.getSymbol().isDefined()) {
- // FIXME SRE.getSymbol() may not be relative to DF.
+ const MCSymbol &Symbol = SRE.getSymbol();
+ if (Symbol.isDefined()) {
+ uint32_t SymbolOffset = 0;
+ Optional<std::pair<bool, std::string>> Error;
+ Error = getOffsetAndDataFragment(Symbol, SymbolOffset, DF);
+
+ if (Error != None)
+ return Error;
+
DF->getFixups().push_back(
- MCFixup::create(SRE.getSymbol().getOffset() + OffsetVal.getConstant(),
+ MCFixup::create(SymbolOffset + OffsetVal.getConstant(),
Expr, Kind, Loc));
return None;
}