Skip to content

Commit 72f7990

Browse files
committed
[RISCV] Replace @plt/@gotpcrel in data directives with %pltpcrel %gotpcrel
clang -fexperimental-relative-c++-abi-vtables might generate `@plt` and `@gotpcrel` specifiers in data directives. The syntax is not used in humand-written assembly code, and is not supported by GNU assembler. Note: the `@plt` in `.word foo@plt` is different from the legacy `call func@plt` (where `@plt` is simply ignored). The `@plt` syntax was selected was simply due to a quirk of AsmParser: the syntax was supported by all targets until I updated it to be an opt-in feature in a067175 RISC-V favors the `%specifier(expr)` syntax following MIPS and Sparc, and we should follow this convention. This PR adds support for `.word %pltpcrel(foo+offset)` and `.word %gotpcrel(foo)`, and drops `@plt` and `@gotpcrel`. * MCValue::SymA can no longer have a SymbolVariant. Add an assert similar to that of AArch64ELFObjectWriter.cpp before https://reviews.llvm.org/D81446 (see my analysis at https://maskray.me/blog/2025-03-16-relocation-generation-in-assemblers if intrigued) * `jump foo@plt, x31` now has a different diagnostic. Pull Request: llvm#132569
1 parent 49ce038 commit 72f7990

31 files changed

+330
-183
lines changed

lld/test/ELF/riscv-reloc-plt32.s

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@
1818
.globl _start
1919
_start:
2020
.data
21-
.word foo@PLT - .
22-
.word foo@PLT - . + 1
23-
.word foo@PLT - . - 1
21+
.word %pltpcrel(foo)
22+
.word %pltpcrel(foo + 1)
23+
.word %pltpcrel(foo - 1)

lld/test/ELF/riscv-undefined-weak.s

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,4 @@ branch:
9797
# PC-NOT: .plt:
9898
# PLT: .plt:
9999

100-
.word target@plt - .
100+
.word %pltpcrel(target)

lld/test/ELF/riscv64-reloc-got32-pcrel.s

+8-8
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,16 @@ bar:
1212

1313
.globl _start
1414
_start: // PC = 0x33a8
15-
// bar@GOTPCREL = 0x2398 (got entry for `bar`) - 0x33a8 (.) = 0xf0efffff
16-
// bar@GOTPCREL+4 = 0x2398 (got entry for `bar`) - 0x33ac (.) + 4 = 0xf0efffff
17-
// bar@GOTPCREL-4 = 0x2398 (got entry for `bar`) - 0x33b0 (.) - 4 = 0xe4efffff
15+
// %gotpcrel(bar) = 0x2398 (got entry for `bar`) - 0x33a8 (.) = 0xf0efffff
16+
// %gotpcrel(bar+4) = 0x2398 (got entry for `bar`) - 0x33ac (.) + 4 = 0xf0efffff
17+
// %gotpcrel(bar-4) = 0x2398 (got entry for `bar`) - 0x33b0 (.) - 4 = 0xe4efffff
1818
// CHECK: Contents of section .data:
1919
// CHECK-NEXT: {{.*}} f0efffff f0efffff e4efffff
20-
.word bar@GOTPCREL
21-
.word bar@GOTPCREL+4
22-
.word bar@GOTPCREL-4
20+
.word %gotpcrel(bar)
21+
.word %gotpcrel(bar+4)
22+
.word %gotpcrel(bar-4)
2323

2424
// WARN: relocation R_RISCV_GOT32_PCREL out of range: {{.*}} is not in [-2147483648, 2147483647]; references 'baz'
2525
// WARN: relocation R_RISCV_GOT32_PCREL out of range: {{.*}} is not in [-2147483648, 2147483647]; references 'baz'
26-
.word baz@GOTPCREL+0xffffffff
27-
.word baz@GOTPCREL-0xffffffff
26+
.word %gotpcrel(baz+0xffffffff)
27+
.word %gotpcrel(baz-0xffffffff)

llvm/include/llvm/CodeGen/AsmPrinter.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,10 @@ class AsmPrinter : public MachineFunctionPass {
497497
unsigned MaxBytesToEmit = 0) const;
498498

499499
/// Lower the specified LLVM Constant to an MCExpr.
500-
virtual const MCExpr *lowerConstant(const Constant *CV);
500+
/// When BaseCV is present, we are lowering the element at BaseCV plus Offset.
501+
virtual const MCExpr *lowerConstant(const Constant *CV,
502+
const Constant *BaseCV = nullptr,
503+
uint64_t Offset = 0);
501504

502505
/// Print a general LLVM constant to the .s file.
503506
/// On AIX, when an alias refers to a sub-element of a global variable, the

llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h

+15-12
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile {
4040
uint8_t PLTRelativeSpecifier = 0;
4141

4242
public:
43-
TargetLoweringObjectFileELF();
4443
~TargetLoweringObjectFileELF() override = default;
4544

4645
void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
@@ -112,11 +111,22 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile {
112111
MCSection *getStaticDtorSection(unsigned Priority,
113112
const MCSymbol *KeySym) const override;
114113

114+
virtual const MCExpr *createTargetMCExpr(const MCExpr *Expr,
115+
uint8_t Specifier) const {
116+
return nullptr;
117+
}
118+
const MCExpr *
119+
lowerSymbolDifference(const MCSymbol *LHS, const MCSymbol *RHS,
120+
int64_t Addend,
121+
std::optional<int64_t> PCRelativeOffset) const;
115122
const MCExpr *lowerRelativeReference(const GlobalValue *LHS,
116-
const GlobalValue *RHS,
123+
const GlobalValue *RHS, int64_t Addend,
124+
std::optional<int64_t> PCRelativeOffset,
117125
const TargetMachine &TM) const override;
118126

119-
const MCExpr *lowerDSOLocalEquivalent(const DSOLocalEquivalent *Equiv,
127+
const MCExpr *lowerDSOLocalEquivalent(const MCSymbol *LHS,
128+
const MCSymbol *RHS, int64_t Addend,
129+
std::optional<int64_t> PCRelativeOffset,
120130
const TargetMachine &TM) const override;
121131

122132
MCSection *getSectionForCommandLines() const override;
@@ -206,7 +216,8 @@ class TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile {
206216
const MCSymbol *KeySym) const override;
207217

208218
const MCExpr *lowerRelativeReference(const GlobalValue *LHS,
209-
const GlobalValue *RHS,
219+
const GlobalValue *RHS, int64_t Addend,
220+
std::optional<int64_t> PCRelativeOffset,
210221
const TargetMachine &TM) const override;
211222

212223
/// Given a mergeable constant with the specified size and relocation
@@ -240,10 +251,6 @@ class TargetLoweringObjectFileWasm : public TargetLoweringObjectFile {
240251
const MCSymbol *KeySym) const override;
241252
MCSection *getStaticDtorSection(unsigned Priority,
242253
const MCSymbol *KeySym) const override;
243-
244-
const MCExpr *lowerRelativeReference(const GlobalValue *LHS,
245-
const GlobalValue *RHS,
246-
const TargetMachine &TM) const override;
247254
};
248255

249256
class TargetLoweringObjectFileXCOFF : public TargetLoweringObjectFile {
@@ -269,10 +276,6 @@ class TargetLoweringObjectFileXCOFF : public TargetLoweringObjectFile {
269276
MCSection *getStaticDtorSection(unsigned Priority,
270277
const MCSymbol *KeySym) const override;
271278

272-
const MCExpr *lowerRelativeReference(const GlobalValue *LHS,
273-
const GlobalValue *RHS,
274-
const TargetMachine &TM) const override;
275-
276279
MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
277280
const TargetMachine &TM) const override;
278281

llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h

+6
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,12 @@ class MCTargetAsmParser : public MCAsmParserExtension {
396396
virtual bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) {
397397
return getParser().parsePrimaryExpr(Res, EndLoc, nullptr);
398398
}
399+
// Parse an expression in a data directive, possibly with a relocation
400+
// specifier.
401+
virtual bool parseDataExpr(const MCExpr *&Res) {
402+
SMLoc EndLoc;
403+
return getParser().parseExpression(Res, EndLoc);
404+
}
399405

400406
virtual bool parseRegister(MCRegister &Reg, SMLoc &StartLoc,
401407
SMLoc &EndLoc) = 0;

llvm/include/llvm/Target/TargetLoweringObjectFile.h

+10-11
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class TargetLoweringObjectFile : public MCObjectFileInfo {
5151
bool SupportIndirectSymViaGOTPCRel = false;
5252
bool SupportGOTPCRelWithOffset = true;
5353
bool SupportDebugThreadLocalLocation = true;
54-
bool SupportDSOLocalEquivalentLowering = false;
54+
uint32_t PLTPCRelativeSpecifier = 0;
5555

5656
/// PersonalityEncoding, LSDAEncoding, TTypeEncoding - Some encoding values
5757
/// for EH.
@@ -196,20 +196,19 @@ class TargetLoweringObjectFile : public MCObjectFileInfo {
196196
/// emitting the address in debug info.
197197
virtual const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const;
198198

199-
virtual const MCExpr *lowerRelativeReference(const GlobalValue *LHS,
200-
const GlobalValue *RHS,
201-
const TargetMachine &TM) const {
199+
virtual const MCExpr *lowerRelativeReference(
200+
const GlobalValue *LHS, const GlobalValue *RHS, int64_t Addend,
201+
std::optional<int64_t> PCRelativeOffset, const TargetMachine &TM) const {
202202
return nullptr;
203203
}
204204

205-
/// Target supports a native lowering of a dso_local_equivalent constant
206-
/// without needing to replace it with equivalent IR.
207-
bool supportDSOLocalEquivalentLowering() const {
208-
return SupportDSOLocalEquivalentLowering;
209-
}
205+
/// Target supports a PC-relative relocation that references the PLT of a
206+
/// function.
207+
bool hasPLTPCRelative() const { return PLTPCRelativeSpecifier; }
210208

211-
virtual const MCExpr *lowerDSOLocalEquivalent(const DSOLocalEquivalent *Equiv,
212-
const TargetMachine &TM) const {
209+
virtual const MCExpr *lowerDSOLocalEquivalent(
210+
const MCSymbol *LHS, const MCSymbol *RHS, int64_t Addend,
211+
std::optional<int64_t> PCRelativeOffset, const TargetMachine &TM) const {
213212
return nullptr;
214213
}
215214

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

+39-27
Original file line numberDiff line numberDiff line change
@@ -3363,7 +3363,9 @@ void AsmPrinter::emitAlignment(Align Alignment, const GlobalObject *GV,
33633363
// Constant emission.
33643364
//===----------------------------------------------------------------------===//
33653365

3366-
const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) {
3366+
const MCExpr *AsmPrinter::lowerConstant(const Constant *CV,
3367+
const Constant *BaseCV,
3368+
uint64_t Offset) {
33673369
MCContext &Ctx = OutContext;
33683370

33693371
if (CV->isNullValue() || isa<UndefValue>(CV))
@@ -3382,7 +3384,8 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) {
33823384
return lowerBlockAddressConstant(*BA);
33833385

33843386
if (const auto *Equiv = dyn_cast<DSOLocalEquivalent>(CV))
3385-
return getObjFileLowering().lowerDSOLocalEquivalent(Equiv, TM);
3387+
return getObjFileLowering().lowerDSOLocalEquivalent(
3388+
getSymbol(Equiv->getGlobalValue()), nullptr, 0, std::nullopt, TM);
33863389

33873390
if (const NoCFIValue *NC = dyn_cast<NoCFIValue>(CV))
33883391
return MCSymbolRefExpr::create(getSymbol(NC->getGlobalValue()), Ctx);
@@ -3428,7 +3431,7 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) {
34283431
// is reasonable to treat their delta as a 32-bit value.
34293432
[[fallthrough]];
34303433
case Instruction::BitCast:
3431-
return lowerConstant(CE->getOperand(0));
3434+
return lowerConstant(CE->getOperand(0), BaseCV, Offset);
34323435

34333436
case Instruction::IntToPtr: {
34343437
const DataLayout &DL = getDataLayout();
@@ -3467,33 +3470,42 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) {
34673470
}
34683471

34693472
case Instruction::Sub: {
3470-
GlobalValue *LHSGV;
3471-
APInt LHSOffset;
3473+
GlobalValue *LHSGV, *RHSGV;
3474+
APInt LHSOffset, RHSOffset;
34723475
DSOLocalEquivalent *DSOEquiv;
34733476
if (IsConstantOffsetFromGlobal(CE->getOperand(0), LHSGV, LHSOffset,
3474-
getDataLayout(), &DSOEquiv)) {
3475-
GlobalValue *RHSGV;
3476-
APInt RHSOffset;
3477-
if (IsConstantOffsetFromGlobal(CE->getOperand(1), RHSGV, RHSOffset,
3478-
getDataLayout())) {
3479-
const MCExpr *RelocExpr =
3480-
getObjFileLowering().lowerRelativeReference(LHSGV, RHSGV, TM);
3481-
if (!RelocExpr) {
3482-
const MCExpr *LHSExpr =
3483-
MCSymbolRefExpr::create(getSymbol(LHSGV), Ctx);
3484-
if (DSOEquiv &&
3485-
getObjFileLowering().supportDSOLocalEquivalentLowering())
3486-
LHSExpr =
3487-
getObjFileLowering().lowerDSOLocalEquivalent(DSOEquiv, TM);
3488-
RelocExpr = MCBinaryExpr::createSub(
3489-
LHSExpr, MCSymbolRefExpr::create(getSymbol(RHSGV), Ctx), Ctx);
3490-
}
3491-
int64_t Addend = (LHSOffset - RHSOffset).getSExtValue();
3477+
getDataLayout(), &DSOEquiv) &&
3478+
IsConstantOffsetFromGlobal(CE->getOperand(1), RHSGV, RHSOffset,
3479+
getDataLayout())) {
3480+
auto *LHSSym = getSymbol(LHSGV);
3481+
auto *RHSSym = getSymbol(RHSGV);
3482+
int64_t Addend = (LHSOffset - RHSOffset).getSExtValue();
3483+
std::optional<int64_t> PCRelativeOffset;
3484+
if (getObjFileLowering().hasPLTPCRelative() && RHSGV == BaseCV)
3485+
PCRelativeOffset = Offset;
3486+
3487+
// Try the generic symbol difference first.
3488+
const MCExpr *Res = getObjFileLowering().lowerRelativeReference(
3489+
LHSGV, RHSGV, Addend, PCRelativeOffset, TM);
3490+
3491+
// (ELF-specific) If the generic symbol difference does not apply, and
3492+
// LHS is a dso_local_equivalent of a dso_preemptable function,
3493+
// reference the PLT entry instead.
3494+
if (DSOEquiv && TM.getTargetTriple().isOSBinFormatELF() &&
3495+
!(LHSGV->isDSOLocal() || LHSGV->isImplicitDSOLocal()))
3496+
Res = getObjFileLowering().lowerDSOLocalEquivalent(
3497+
LHSSym, RHSSym, Addend, PCRelativeOffset, TM);
3498+
3499+
// Otherwise, return LHS-RHS+Addend.
3500+
if (!Res) {
3501+
Res =
3502+
MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHSSym, Ctx),
3503+
MCSymbolRefExpr::create(RHSSym, Ctx), Ctx);
34923504
if (Addend != 0)
3493-
RelocExpr = MCBinaryExpr::createAdd(
3494-
RelocExpr, MCConstantExpr::create(Addend, Ctx), Ctx);
3495-
return RelocExpr;
3505+
Res = MCBinaryExpr::createAdd(
3506+
Res, MCConstantExpr::create(Addend, Ctx), Ctx);
34963507
}
3508+
return Res;
34973509
}
34983510

34993511
const MCExpr *LHS = lowerConstant(CE->getOperand(0));
@@ -4023,7 +4035,7 @@ static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *CV,
40234035

40244036
// Otherwise, it must be a ConstantExpr. Lower it to an MCExpr, then emit it
40254037
// thread the streamer with EmitValue.
4026-
const MCExpr *ME = AP.lowerConstant(CV);
4038+
const MCExpr *ME = AP.lowerConstant(CV, BaseCV, Offset);
40274039

40284040
// Since lowerConstant already folded and got rid of all IR pointer and
40294041
// integer casts, detect GOT equivalent accesses by looking into the MCExpr

0 commit comments

Comments
 (0)