aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/MC/MCObjectStreamer.cpp
diff options
context:
space:
mode:
authorStefan Pintilie <stefanp@ca.ibm.com>2020-07-21 12:54:48 -0500
committerStefan Pintilie <stefanp@ca.ibm.com>2020-07-22 04:25:54 -0500
commite0a372ff10c8cc076cfd44e540629b7d09000d5e (patch)
treededa4ded1f8f3a785e15f72b12b5d924e67c21ac /llvm/lib/MC/MCObjectStreamer.cpp
parenta69f9a8584f2a090b5fe6235a112f9b68c324863 (diff)
downloadllvm-e0a372ff10c8cc076cfd44e540629b7d09000d5e.zip
llvm-e0a372ff10c8cc076cfd44e540629b7d09000d5e.tar.gz
llvm-e0a372ff10c8cc076cfd44e540629b7d09000d5e.tar.bz2
[PowerPC] Extend .reloc directive on PowerPC
When the compiler generates a GOT indirect load it must generate two loads. One that loads the address of the element from the GOT and a second to load the actual element based on the address just loaded from the GOT. However, the linker can optimize these two loads into one load if it knows that it is safe to do so. The compiler can tell the linker that the optimization is safe by using the R_PPC64_PCREL_OPT relocation. This patch extends the .reloc directive to allow the following setup pld 3, vec@got@pcrel(0), 1 .Lpcrel1=.-8 ... More instructions possible here ... .reloc .Lpcrel1,R_PPC64_PCREL_OPT,.-.Lpcrel1 lwa 3, 4(3) Reviewers: nemanjai, lei, hfinkel, sfertile, efriedma, tstellar, grosbach, MaskRay Reviewed By: nemanjai, MaskRay Differential Revision: https://reviews.llvm.org/D79625
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;
}