diff --git a/lld/test/ELF/aarch64-reloc-gotpcrel32.s b/lld/test/ELF/aarch64-reloc-gotpcrel32.s index 4d007776a86a7..35dfe756f4b24 100644 --- a/lld/test/ELF/aarch64-reloc-gotpcrel32.s +++ b/lld/test/ELF/aarch64-reloc-gotpcrel32.s @@ -17,11 +17,11 @@ _start: // PC = 0x303a0 // bar@GOTPCREL-4 = 0x20390 (got entry for `bar`) - 0x303a8 (.) - 4 = 0xe4fffeff // CHECK: Contents of section .data: // CHECK-NEXT: {{.*}} f0fffeff f0fffeff e4fffeff - .word bar@GOTPCREL - .word bar@GOTPCREL+4 - .word bar@GOTPCREL-4 + .word %gotpcrel(bar) + .word %gotpcrel(bar+4) + .word %gotpcrel(bar-4) // WARN: relocation R_AARCH64_GOTPCREL32 out of range: {{.*}} is not in [-2147483648, 2147483647]; references 'baz' // WARN: relocation R_AARCH64_GOTPCREL32 out of range: {{.*}} is not in [-2147483648, 2147483647]; references 'baz' - .word baz@GOTPCREL+0xffffffff - .word baz@GOTPCREL-0xffffffff + .word %gotpcrel(baz+0xffffffff) + .word %gotpcrel(baz-0xffffffff) diff --git a/lld/test/ELF/aarch64-reloc-plt32.s b/lld/test/ELF/aarch64-reloc-plt32.s index 8a3b989a909b8..cd442e76fcf3d 100644 --- a/lld/test/ELF/aarch64-reloc-plt32.s +++ b/lld/test/ELF/aarch64-reloc-plt32.s @@ -32,6 +32,6 @@ .globl _start _start: .data - .word foo@PLT - . + 2149589079 - .word foo@PLT - . - 2145378212 - .word foo@PLT - . + .word %pltpcrel(foo + 2149589079) + .word %pltpcrel(foo - 2145378212) + .word %pltpcrel(foo) diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 3641e22e6f76a..88ccc043d8b89 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -181,6 +181,7 @@ class AArch64AsmParser : public MCTargetAsmParser { bool showMatchError(SMLoc Loc, unsigned ErrCode, uint64_t ErrorInfo, OperandVector &Operands); + bool parseExprWithSpecifier(const MCExpr *&Res, SMLoc &E); bool parseDataExpr(const MCExpr *&Res) override; bool parseAuthExpr(const MCExpr *&Res, SMLoc &EndLoc); @@ -8190,8 +8191,31 @@ bool AArch64AsmParser::parseDirectiveAeabiAArch64Attr(SMLoc L) { return false; } +bool AArch64AsmParser::parseExprWithSpecifier(const MCExpr *&Res, SMLoc &E) { + SMLoc Loc = getLoc(); + if (getLexer().getKind() != AsmToken::Identifier) + return TokError("expected '%' relocation specifier"); + StringRef Identifier = getParser().getTok().getIdentifier(); + auto Spec = AArch64::parsePercentSpecifierName(Identifier); + if (!Spec) + return TokError("invalid relocation specifier"); + + getParser().Lex(); // Eat the identifier + if (parseToken(AsmToken::LParen, "expected '('")) + return true; + + const MCExpr *SubExpr; + if (getParser().parseParenExpression(SubExpr, E)) + return true; + + Res = MCSpecifierExpr::create(SubExpr, Spec, getContext(), Loc); + return false; +} + bool AArch64AsmParser::parseDataExpr(const MCExpr *&Res) { SMLoc EndLoc; + if (parseOptionalToken(AsmToken::Percent)) + return parseExprWithSpecifier(Res, EndLoc); if (getParser().parseExpression(Res)) return true; diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp index a388216a95098..5add98dcab931 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp @@ -104,6 +104,18 @@ unsigned AArch64ELFObjectWriter::getRelocType(const MCFixup &Fixup, break; } + switch (RefKind) { + case AArch64::S_GOTPCREL: + case AArch64::S_PLT: + if (Kind == FK_Data_4) + break; + reportError(Fixup.getLoc(), AArch64::getSpecifierName(RefKind) + + " can only be used in a .word directive"); + return ELF::R_RISCV_NONE; + default: + break; + } + // Extract the relocation type from the fixup kind, after applying STT_TLS as // needed. if (mc::isRelocation(Fixup.getKind())) @@ -117,8 +129,7 @@ unsigned AArch64ELFObjectWriter::getRelocType(const MCFixup &Fixup, case FK_Data_2: return R_CLS(PREL16); case FK_Data_4: { - return Target.getSpecifier() == AArch64::S_PLT ? R_CLS(PLT32) - : R_CLS(PREL32); + return R_CLS(PREL32); } case FK_Data_8: if (IsILP32) { @@ -220,9 +231,13 @@ unsigned AArch64ELFObjectWriter::getRelocType(const MCFixup &Fixup, case FK_Data_2: return R_CLS(ABS16); case FK_Data_4: - return (!IsILP32 && Target.getSpecifier() == AArch64::S_GOTPCREL) - ? ELF::R_AARCH64_GOTPCREL32 - : R_CLS(ABS32); + if (!IsILP32) { + if (Target.getSpecifier() == AArch64::S_GOTPCREL) + return ELF::R_AARCH64_GOTPCREL32; + if (Target.getSpecifier() == AArch64::S_PLT) + return ELF::R_AARCH64_PLT32; + } + return R_CLS(ABS32); case FK_Data_8: { if (IsILP32) { reportError( diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp index 2b5cf3484ffc1..a06ae8eb8c3cb 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp @@ -113,12 +113,22 @@ StringRef AArch64::getSpecifierName(AArch64::Specifier S) { case AArch64::S_GOT_AUTH: return ":got_auth:"; case AArch64::S_GOT_AUTH_PAGE: return ":got_auth:"; case AArch64::S_GOT_AUTH_LO12: return ":got_auth_lo12:"; + + case AArch64::S_GOTPCREL: return "%gotpcrel"; + case AArch64::S_PLT: return "%pltpcrel"; default: llvm_unreachable("Invalid relocation specifier"); } // clang-format on } +AArch64::Specifier AArch64::parsePercentSpecifierName(StringRef name) { + return StringSwitch(name) + .Case("pltpcrel", AArch64::S_PLT) + .Case("gotpcrel", AArch64::S_GOTPCREL) + .Default(0); +} + static bool evaluate(const MCSpecifierExpr &Expr, MCValue &Res, const MCAssembler *Asm) { if (!Expr.getSubExpr()->evaluateAsRelocatable(Res, Asm)) @@ -232,8 +242,13 @@ void AArch64MCAsmInfoELF::printSpecifierExpr( raw_ostream &OS, const MCSpecifierExpr &Expr) const { if (auto *AE = dyn_cast(&Expr)) return AE->print(OS, this); - OS << AArch64::getSpecifierName(Expr.getSpecifier()); + auto Str = AArch64::getSpecifierName(Expr.getSpecifier()); + OS << Str; + if (!Str.empty() && Str[0] == '%') + OS << ')'; printExpr(OS, *Expr.getSubExpr()); + if (!Str.empty() && Str[0] == '%') + OS << ')'; } bool AArch64MCAsmInfoELF::evaluateAsRelocatableImpl( diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h index 0dfa61b1dc60e..971ba58497f96 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h @@ -183,6 +183,8 @@ enum { /// (e.g. ":got:", ":lo12:"). StringRef getSpecifierName(Specifier S); +Specifier parsePercentSpecifierName(StringRef); + inline Specifier getSymbolLoc(Specifier S) { return static_cast(S & AArch64::S_SymLocBits); } diff --git a/llvm/test/MC/AArch64/data-directive-specifier.s b/llvm/test/MC/AArch64/data-directive-specifier.s index 2cb7eb3a3ca81..a790bb57b9bd5 100644 --- a/llvm/test/MC/AArch64/data-directive-specifier.s +++ b/llvm/test/MC/AArch64/data-directive-specifier.s @@ -1,6 +1,6 @@ # RUN: llvm-mc -triple=aarch64 -filetype=obj %s | llvm-readobj -r - | FileCheck %s -# RUN: not llvm-mc -triple=aarch64 %s --defsym ERR=1 -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error: -# RUN: not llvm-mc -triple=aarch64 -filetype=obj %s --defsym OBJERR=1 -o /dev/null 2>&1 | FileCheck %s --check-prefix=OBJERR --implicit-check-not=error: +# RUN: not llvm-mc -triple=aarch64 %s --defsym ERR0=1 -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR0 --implicit-check-not=error: +# RUN: not llvm-mc -triple=aarch64 -filetype=obj %s --defsym ERR=1 -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error: .globl g g: @@ -8,47 +8,51 @@ l: # CHECK: Section ({{.*}}) .rela.data { # CHECK-NEXT: 0x0 R_AARCH64_PLT32 l 0x0 -# CHECK-NEXT: 0x4 R_AARCH64_PLT32 l 0x4 -# CHECK-NEXT: 0x8 R_AARCH64_PLT32 extern 0x4 -# CHECK-NEXT: 0xC R_AARCH64_PLT32 g 0x8 -# CHECK-NEXT: 0x10 R_AARCH64_PLT32 g 0x18 +# CHECK-NEXT: 0x4 R_AARCH64_PLT32 extern 0x4 +# CHECK-NEXT: 0x8 R_AARCH64_PLT32 g 0x8 # CHECK-NEXT: } .data -.word l@plt - . -.word l@plt - .data - -.word extern@plt - . + 4 -.word g@plt - . + 8 -.word g@plt - .data + 8 +.word %pltpcrel(l) +.word %pltpcrel(extern + 4), %pltpcrel(g + 8) # CHECK: Section ({{.*}}) .rela.data1 { # CHECK-NEXT: 0x0 R_AARCH64_GOTPCREL32 data1 0x0 # CHECK-NEXT: 0x4 R_AARCH64_GOTPCREL32 extern 0x4 -# CHECK-NEXT: 0x8 R_AARCH64_GOTPCREL32 extern 0xFFFFFFFFFFFFFFFB +# CHECK-NEXT: 0x8 R_AARCH64_GOTPCREL32 extern 0xFFFFFFFFFFFFFFFB # CHECK-NEXT: } .section .data1,"aw" data1: -.word data1@GOTPCREL -.word extern@gotpcrel+4 -.word extern@GOTPCREL-5 +.word %gotpcrel(data1) +.word %gotpcrel(extern+4), %gotpcrel(extern-5) -## Test parse-time errors -.ifdef ERR -# ERR: [[#@LINE+1]]:9: error: @ specifier only allowed after a symbol -.quad 3@plt - . +.ifdef ERR0 +# ERR0: [[#@LINE+1]]:8: error: invalid relocation specifier +.word %xxx(l) + +# ERR0: [[#@LINE+1]]:17: error: expected '(' +.word %pltpcrel l -# ERR: [[#@LINE+1]]:9: error: expected ')' -.quad (l@plt - .) +# ERR0: [[#@LINE+2]]:14: error: unknown token in expression +# ERR0: [[#@LINE+1]]:14: error: invalid operand +ldr w0, [x1, %pltpcrel(g)] .endif -.ifdef OBJERR -.quad g@plt - . +.ifdef ERR +# ERR: [[#@LINE+1]]:8: error: %pltpcrel can only be used in a .word directive +.quad %pltpcrel(g) + +# ERR: [[#@LINE+1]]:8: error: expected relocatable expression +.word %pltpcrel(g-.) + +# ERR: [[#@LINE+1]]:8: error: expected relocatable expression +.word %pltpcrel(extern - und) -.word extern@gotpcrel - . +# ERR: [[#@LINE+1]]:8: error: %gotpcrel can only be used in a .word directive +.quad %gotpcrel(g) -# OBJERR: [[#@LINE+1]]:7: error: symbol 'und' can not be undefined in a subtraction expression -.word extern@plt - und +# ERR: [[#@LINE+1]]:8: error: expected relocatable expression +.word %gotpcrel(extern - .) -# OBJERR: [[#@LINE+1]]:7: error: symbol 'und' can not be undefined in a subtraction expression -.word extern@gotpcrel - und +# ERR: [[#@LINE+1]]:8: error: expected relocatable expression +.word %gotpcrel(extern - und) .endif