Skip to content

Commit e0a372f

Browse files
[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
1 parent a69f9a8 commit e0a372f

File tree

3 files changed

+475
-3
lines changed

3 files changed

+475
-3
lines changed

llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
#undef R_PPC64_DTPREL16_HIGH
9898
#undef R_PPC64_DTPREL16_HIGHA
9999
#undef R_PPC64_REL24_NOTOC
100+
#undef R_PPC64_PCREL_OPT
100101
#undef R_PPC64_PCREL34
101102
#undef R_PPC64_GOT_PCREL34
102103
#undef R_PPC64_IRELATIVE
@@ -194,6 +195,7 @@ ELF_RELOC(R_PPC64_TPREL16_HIGHA, 113)
194195
ELF_RELOC(R_PPC64_DTPREL16_HIGH, 114)
195196
ELF_RELOC(R_PPC64_DTPREL16_HIGHA, 115)
196197
ELF_RELOC(R_PPC64_REL24_NOTOC, 116)
198+
ELF_RELOC(R_PPC64_PCREL_OPT, 123)
197199
ELF_RELOC(R_PPC64_PCREL34, 132)
198200
ELF_RELOC(R_PPC64_GOT_PCREL34, 133)
199201
ELF_RELOC(R_PPC64_IRELATIVE, 248)

llvm/lib/MC/MCObjectStreamer.cpp

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,68 @@ void MCObjectStreamer::emitGPRel64Value(const MCExpr *Value) {
665665
DF->getContents().resize(DF->getContents().size() + 8, 0);
666666
}
667667

668+
static Optional<std::pair<bool, std::string>>
669+
getOffsetAndDataFragment(const MCSymbol &Symbol, uint32_t &RelocOffset,
670+
MCDataFragment *&DF) {
671+
if (Symbol.isVariable()) {
672+
const MCExpr *SymbolExpr = Symbol.getVariableValue();
673+
MCValue OffsetVal;
674+
if(!SymbolExpr->evaluateAsRelocatable(OffsetVal, nullptr, nullptr))
675+
return std::make_pair(false,
676+
std::string("symbol in .reloc offset is not "
677+
"relocatable"));
678+
if (OffsetVal.isAbsolute()) {
679+
RelocOffset = OffsetVal.getConstant();
680+
MCFragment *Fragment = Symbol.getFragment();
681+
// FIXME Support symbols with no DF. For example:
682+
// .reloc .data, ENUM_VALUE, <some expr>
683+
if (!Fragment || Fragment->getKind() != MCFragment::FT_Data)
684+
return std::make_pair(false,
685+
std::string("symbol in offset has no data "
686+
"fragment"));
687+
DF = cast<MCDataFragment>(Fragment);
688+
return None;
689+
}
690+
691+
if (OffsetVal.getSymB())
692+
return std::make_pair(false,
693+
std::string(".reloc symbol offset is not "
694+
"representable"));
695+
696+
const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*OffsetVal.getSymA());
697+
if (!SRE.getSymbol().isDefined())
698+
return std::make_pair(false,
699+
std::string("symbol used in the .reloc offset is "
700+
"not defined"));
701+
702+
if (SRE.getSymbol().isVariable())
703+
return std::make_pair(false,
704+
std::string("symbol used in the .reloc offset is "
705+
"variable"));
706+
707+
MCFragment *Fragment = SRE.getSymbol().getFragment();
708+
// FIXME Support symbols with no DF. For example:
709+
// .reloc .data, ENUM_VALUE, <some expr>
710+
if (!Fragment || Fragment->getKind() != MCFragment::FT_Data)
711+
return std::make_pair(false,
712+
std::string("symbol in offset has no data "
713+
"fragment"));
714+
RelocOffset = SRE.getSymbol().getOffset() + OffsetVal.getConstant();
715+
DF = cast<MCDataFragment>(Fragment);
716+
} else {
717+
RelocOffset = Symbol.getOffset();
718+
MCFragment *Fragment = Symbol.getFragment();
719+
// FIXME Support symbols with no DF. For example:
720+
// .reloc .data, ENUM_VALUE, <some expr>
721+
if (!Fragment || Fragment->getKind() != MCFragment::FT_Data)
722+
return std::make_pair(false,
723+
std::string("symbol in offset has no data "
724+
"fragment"));
725+
DF = cast<MCDataFragment>(Fragment);
726+
}
727+
return None;
728+
}
729+
668730
Optional<std::pair<bool, std::string>>
669731
MCObjectStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
670732
const MCExpr *Expr, SMLoc Loc,
@@ -698,10 +760,17 @@ MCObjectStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
698760
std::string(".reloc offset is not representable"));
699761

700762
const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*OffsetVal.getSymA());
701-
if (SRE.getSymbol().isDefined()) {
702-
// FIXME SRE.getSymbol() may not be relative to DF.
763+
const MCSymbol &Symbol = SRE.getSymbol();
764+
if (Symbol.isDefined()) {
765+
uint32_t SymbolOffset = 0;
766+
Optional<std::pair<bool, std::string>> Error;
767+
Error = getOffsetAndDataFragment(Symbol, SymbolOffset, DF);
768+
769+
if (Error != None)
770+
return Error;
771+
703772
DF->getFixups().push_back(
704-
MCFixup::create(SRE.getSymbol().getOffset() + OffsetVal.getConstant(),
773+
MCFixup::create(SymbolOffset + OffsetVal.getConstant(),
705774
Expr, Kind, Loc));
706775
return None;
707776
}

0 commit comments

Comments
 (0)