diff --git a/clang/docs/ShadowCallStack.rst b/clang/docs/ShadowCallStack.rst index b1ab4c6e8b239..04c04d259d7dc 100644 --- a/clang/docs/ShadowCallStack.rst +++ b/clang/docs/ShadowCallStack.rst @@ -57,24 +57,27 @@ compiled application or the operating system. Integrating the runtime into the operating system should be preferred since otherwise all thread creation and destruction would need to be intercepted by the application. -The instrumentation makes use of the platform register ``x18``. On some -platforms, ``x18`` is reserved, and on others, it is designated as a scratch -register. This generally means that any code that may run on the same thread -as code compiled with ShadowCallStack must either target one of the platforms -whose ABI reserves ``x18`` (currently Android, Darwin, Fuchsia and Windows) -or be compiled with the flag ``-ffixed-x18``. If absolutely necessary, code -compiled without ``-ffixed-x18`` may be run on the same thread as code that -uses ShadowCallStack by saving the register value temporarily on the stack -(`example in Android`_) but this should be done with care since it risks -leaking the shadow call stack address. +The instrumentation makes use of the platform register ``x18`` on AArch64 and +``x3`` (``gp``) on RISC-V. For simplicity we will refer to this as the +``SCSReg``. On some platforms, ``SCSReg`` is reserved, and on others, it is +designated as a scratch register. This generally means that any code that may +run on the same thread as code compiled with ShadowCallStack must either target +one of the platforms whose ABI reserves ``SCSReg`` (currently Android, Darwin, +Fuchsia and Windows) or be compiled with a flag to reserve that register (e.g., +``-ffixed-x18``). If absolutely necessary, code compiled without reserving the +register may be run on the same thread as code that uses ShadowCallStack by +saving the register value temporarily on the stack (`example in Android`_) but +this should be done with care since it risks leaking the shadow call stack +address. .. _`example in Android`: https://android-review.googlesource.com/c/platform/frameworks/base/+/803717 -Because of the use of register ``x18``, the ShadowCallStack feature is -incompatible with any other feature that may use ``x18``. However, there -is no inherent reason why ShadowCallStack needs to use register ``x18`` -specifically; in principle, a platform could choose to reserve and use another -register for ShadowCallStack, but this would be incompatible with the AAPCS64. +Because it requires a dedicated register, the ShadowCallStack feature is +incompatible with any other feature that may use ``SCSReg``. However, there is +no inherent reason why ShadowCallStack needs to use a specific register; in +principle, a platform could choose to reserve and use another register for +ShadowCallStack, but this would be incompatible with the ABI standards +published in AAPCS64 and the RISC-V psABI. Special unwind information is required on functions that are compiled with ShadowCallStack and that may be unwound, i.e. functions compiled with @@ -91,7 +94,7 @@ ShadowCallStack is intended to be a stronger alternative to ``-fstack-protector``. It protects from non-linear overflows and arbitrary memory writes to the return address slot. -The instrumentation makes use of the ``x18`` register to reference the shadow +The instrumentation makes use of the ``SCSReg`` register to reference the shadow call stack, meaning that references to the shadow call stack do not have to be stored in memory. This makes it possible to implement a runtime that avoids exposing the address of the shadow call stack to attackers that can @@ -120,11 +123,11 @@ guard regions that can be allocated. The runtime will need the address of the shadow call stack in order to deallocate it when destroying the thread. If the entire program is compiled -with ``-ffixed-x18``, this is trivial: the address can be derived from the -value stored in ``x18`` (e.g. by masking out the lower bits). If a guard +with ``SCSReg`` reserved, this is trivial: the address can be derived from the +value stored in ``SCSReg`` (e.g. by masking out the lower bits). If a guard region is used, the address of the start of the guard region could then be stored at the start of the shadow call stack itself. But if it is possible -for code compiled without ``-ffixed-x18`` to run on a thread managed by the +for code compiled without reserving ``SCSReg`` to run on a thread managed by the runtime, which is the case on Android for example, the address must be stored somewhere else instead. On Android we store the address of the start of the guard region in TLS and deallocate the entire guard region including the @@ -133,7 +136,7 @@ the address of the start of the guard region is already somewhat guessable. One way in which the address of the shadow call stack could leak is in the ``jmp_buf`` data structure used by ``setjmp`` and ``longjmp``. The Android -runtime `avoids this`_ by only storing the low bits of ``x18`` in the +runtime `avoids this`_ by only storing the low bits of ``SCSReg`` in the ``jmp_buf``, which requires the address of the shadow call stack to be aligned to its size. @@ -146,9 +149,11 @@ protected from return address overwrites even without ShadowCallStack. Usage ===== -To enable ShadowCallStack, just pass the ``-fsanitize=shadow-call-stack`` -flag to both compile and link command lines. On aarch64, you also need to pass -``-ffixed-x18`` unless your target already reserves ``x18``. +To enable ShadowCallStack, just pass the ``-fsanitize=shadow-call-stack`` flag +to both compile and link command lines. On aarch64, you also need to pass +``-ffixed-x18`` unless your target already reserves ``x18``. On RISC-V, ``x3`` +(``gp``) is always reserved. It is, however, important to disable GP relaxation +in the linker. This can be done with the ``--no-relax-gp`` flag in GNU ld. Low-level API ------------- diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 299d4adf3333a..3f5b67e5f9b01 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -13,6 +13,7 @@ #include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Path.h" #include "llvm/Support/SpecialCaseList.h" @@ -543,11 +544,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto"; } - if ((Kinds & SanitizerKind::ShadowCallStack) && - ((TC.getTriple().isAArch64() && - !llvm::AArch64::isX18ReservedByDefault(TC.getTriple())) || - (TC.getTriple().isRISCV() && - !llvm::RISCV::isX18ReservedByDefault(TC.getTriple()))) && + if ((Kinds & SanitizerKind::ShadowCallStack) && TC.getTriple().isAArch64() && + !llvm::AArch64::isX18ReservedByDefault(TC.getTriple()) && !Args.hasArg(options::OPT_ffixed_x18) && DiagnoseErrors) { D.Diag(diag::err_drv_argument_only_allowed_with) << lastArgumentForMask(D, Args, Kinds & SanitizerKind::ShadowCallStack) diff --git a/clang/test/Driver/sanitizer-ld.c b/clang/test/Driver/sanitizer-ld.c index 0778a96ae2350..8192672b73fce 100644 --- a/clang/test/Driver/sanitizer-ld.c +++ b/clang/test/Driver/sanitizer-ld.c @@ -736,12 +736,12 @@ // RUN: %clang -fsanitize=shadow-call-stack -### %s 2>&1 \ // RUN: --target=riscv32-unknown-elf -fuse-ld=ld \ // RUN: | FileCheck --check-prefix=CHECK-SHADOWCALLSTACK-ELF-RISCV32 %s -// CHECK-SHADOWCALLSTACK-ELF-RISCV32: '-fsanitize=shadow-call-stack' only allowed with '-ffixed-x18' +// CHECK-SHADOWCALLSTACK-ELF-RISCV32-NOT: error: // RUN: %clang -fsanitize=shadow-call-stack -### %s 2>&1 \ // RUN: --target=riscv64-unknown-linux -fuse-ld=ld \ // RUN: | FileCheck --check-prefix=CHECK-SHADOWCALLSTACK-LINUX-RISCV64 %s -// CHECK-SHADOWCALLSTACK-LINUX-RISCV64: '-fsanitize=shadow-call-stack' only allowed with '-ffixed-x18' +// CHECK-SHADOWCALLSTACK-LINUX-RISCV64-NOT: error: // RUN: %clang -target riscv64-linux-android -fsanitize=shadow-call-stack %s -### 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECK-SHADOWCALLSTACK-ANDROID-RISCV64 diff --git a/compiler-rt/test/shadowcallstack/lit.cfg.py b/compiler-rt/test/shadowcallstack/lit.cfg.py index fc736af8c4fb4..062ce83ea15d7 100644 --- a/compiler-rt/test/shadowcallstack/lit.cfg.py +++ b/compiler-rt/test/shadowcallstack/lit.cfg.py @@ -19,5 +19,5 @@ scs_arch_cflags += ' -ffixed-x18 ' config.substitutions.append( ("%clang_scs ", config.clang + ' -O0 -fsanitize=shadow-call-stack ' + scs_arch_cflags + ' ') ) -if config.host_os not in ['Linux'] or config.target_arch not in ['aarch64']: +if config.host_os not in ['Linux'] or config.target_arch not in ['aarch64','riscv64']: config.unsupported = True diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst index 88d43a3befa5e..d747752c2a085 100644 --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -161,6 +161,11 @@ Changes to the RISC-V Backend * I, F, D, and A extension versions have been update to the 20191214 spec versions. New version I2.1, F2.2, D2.2, A2.1. This should not impact code generation. Immpacts versions accepted in ``-march`` and reported in ELF attributes. +* Changed the ShadowCallStack register from ``x18`` (``s2``) to ``x3`` + (``gp``). Note this breaks the existing non-standard ABI for ShadowCallStack + on RISC-V, but conforms with the new "platform register" defined in the + RISC-V psABI (for more details see the + `psABI discussion `_). Changes to the WebAssembly Backend ---------------------------------- diff --git a/llvm/include/llvm/TargetParser/RISCVTargetParser.h b/llvm/include/llvm/TargetParser/RISCVTargetParser.h index 6f6c89e80e4ec..993f653455a0d 100644 --- a/llvm/include/llvm/TargetParser/RISCVTargetParser.h +++ b/llvm/include/llvm/TargetParser/RISCVTargetParser.h @@ -40,8 +40,6 @@ StringRef getMArchFromMcpu(StringRef CPU); void fillValidCPUArchList(SmallVectorImpl &Values, bool IsRV64); void fillValidTuneCPUArchList(SmallVectorImpl &Values, bool IsRV64); -bool isX18ReservedByDefault(const Triple &TT); - } // namespace RISCV } // namespace llvm diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp index 38f75ad1f8c27..aa0664f6faae0 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp @@ -98,7 +98,7 @@ ABI getTargetABI(StringRef ABIName) { MCRegister getBPReg() { return RISCV::X9; } // Returns the register holding shadow call stack pointer. -MCRegister getSCSPReg() { return RISCV::X18; } +MCRegister getSCSPReg() { return RISCV::X3; } } // namespace RISCVABI diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp index 2bbb4109b6944..790b50d6163c4 100644 --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -27,8 +27,8 @@ using namespace llvm; -// For now we use x18, a.k.a s2, as pointer to shadow call stack. -// User should explicitly set -ffixed-x18 and not use x18 in their asm. +// For now we use x3, a.k.a gp, as pointer to shadow call stack. +// User should not use x3 in their asm. static void emitSCSPrologue(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const DebugLoc &DL) { @@ -48,27 +48,12 @@ static void emitSCSPrologue(MachineFunction &MF, MachineBasicBlock &MBB, Register SCSPReg = RISCVABI::getSCSPReg(); - auto &Ctx = MF.getFunction().getContext(); - if (!STI.isRegisterReservedByUser(SCSPReg)) { - Ctx.diagnose(DiagnosticInfoUnsupported{ - MF.getFunction(), "x18 not reserved by user for Shadow Call Stack."}); - return; - } - - const auto *RVFI = MF.getInfo(); - if (RVFI->useSaveRestoreLibCalls(MF)) { - Ctx.diagnose(DiagnosticInfoUnsupported{ - MF.getFunction(), - "Shadow Call Stack cannot be combined with Save/Restore LibCalls."}); - return; - } - const RISCVInstrInfo *TII = STI.getInstrInfo(); bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit); int64_t SlotSize = STI.getXLen() / 8; // Store return address to shadow call stack - // s[w|d] ra, 0(s2) - // addi s2, s2, [4|8] + // s[w|d] ra, 0(gp) + // addi gp, gp, [4|8] BuildMI(MBB, MI, DL, TII->get(IsRV64 ? RISCV::SD : RISCV::SW)) .addReg(RAReg) .addReg(SCSPReg) @@ -83,7 +68,7 @@ static void emitSCSPrologue(MachineFunction &MF, MachineBasicBlock &MBB, // Emit a CFI instruction that causes SlotSize to be subtracted from the value // of the shadow stack pointer when unwinding past this frame. char DwarfSCSReg = TRI->getDwarfRegNum(SCSPReg, /*IsEH*/ true); - assert(DwarfSCSReg < 32 && "SCS Register should be < 32 (X18)."); + assert(DwarfSCSReg < 32 && "SCS Register should be < 32 (X3)."); char Offset = static_cast(-SlotSize) & 0x7f; const char CFIInst[] = { @@ -118,27 +103,12 @@ static void emitSCSEpilogue(MachineFunction &MF, MachineBasicBlock &MBB, Register SCSPReg = RISCVABI::getSCSPReg(); - auto &Ctx = MF.getFunction().getContext(); - if (!STI.isRegisterReservedByUser(SCSPReg)) { - Ctx.diagnose(DiagnosticInfoUnsupported{ - MF.getFunction(), "x18 not reserved by user for Shadow Call Stack."}); - return; - } - - const auto *RVFI = MF.getInfo(); - if (RVFI->useSaveRestoreLibCalls(MF)) { - Ctx.diagnose(DiagnosticInfoUnsupported{ - MF.getFunction(), - "Shadow Call Stack cannot be combined with Save/Restore LibCalls."}); - return; - } - const RISCVInstrInfo *TII = STI.getInstrInfo(); bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit); int64_t SlotSize = STI.getXLen() / 8; // Load return address from shadow call stack - // l[w|d] ra, -[4|8](s2) - // addi s2, s2, -[4|8] + // l[w|d] ra, -[4|8](gp) + // addi gp, gp, -[4|8] BuildMI(MBB, MI, DL, TII->get(IsRV64 ? RISCV::LD : RISCV::LW)) .addReg(RAReg, RegState::Define) .addReg(SCSPReg) diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp index 9e2af55d2131b..f05753e61c363 100644 --- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp @@ -83,9 +83,6 @@ RISCVSubtarget::RISCVSubtarget(const Triple &TT, StringRef CPU, FrameLowering( initializeSubtargetDependencies(TT, CPU, TuneCPU, FS, ABIName)), InstrInfo(*this), RegInfo(getHwMode()), TLInfo(TM, *this) { - if (RISCV::isX18ReservedByDefault(TT)) - UserReservedRegister.set(RISCV::X18); - CallLoweringInfo.reset(new RISCVCallLowering(*getTargetLowering())); Legalizer.reset(new RISCVLegalizerInfo(*this)); diff --git a/llvm/lib/TargetParser/RISCVTargetParser.cpp b/llvm/lib/TargetParser/RISCVTargetParser.cpp index e3543b90e4d25..ac726cdbb797c 100644 --- a/llvm/lib/TargetParser/RISCVTargetParser.cpp +++ b/llvm/lib/TargetParser/RISCVTargetParser.cpp @@ -85,10 +85,5 @@ void fillValidTuneCPUArchList(SmallVectorImpl &Values, bool IsRV64) { #include "llvm/TargetParser/RISCVTargetParserDef.inc" } -bool isX18ReservedByDefault(const Triple &TT) { - // X18 is reserved for the ShadowCallStack ABI (even when not enabled). - return TT.isOSFuchsia() || TT.isAndroid(); -} - } // namespace RISCV } // namespace llvm diff --git a/llvm/test/CodeGen/RISCV/reserved-regs.ll b/llvm/test/CodeGen/RISCV/reserved-regs.ll index 68c6a6558eccc..045ffabf2ffc5 100644 --- a/llvm/test/CodeGen/RISCV/reserved-regs.ll +++ b/llvm/test/CodeGen/RISCV/reserved-regs.ll @@ -57,9 +57,6 @@ ; RUN: llc -mtriple=riscv32 -mattr=+reserve-x31 -verify-machineinstrs < %s | FileCheck %s -check-prefix=X31 ; RUN: llc -mtriple=riscv64 -mattr=+reserve-x31 -verify-machineinstrs < %s | FileCheck %s -check-prefix=X31 -; RUN: llc -mtriple=riscv64-fuchsia -verify-machineinstrs < %s | FileCheck %s -check-prefix=X18 -; RUN: llc -mtriple=riscv64-linux-android -verify-machineinstrs < %s | FileCheck %s -check-prefix=X18 - ; This program is free to use all registers, but needs a stack pointer for ; spill values, so do not test for reserving the stack pointer. diff --git a/llvm/test/CodeGen/RISCV/saverestore-scs.ll b/llvm/test/CodeGen/RISCV/saverestore-scs.ll new file mode 100644 index 0000000000000..6c3ee2c2f383f --- /dev/null +++ b/llvm/test/CodeGen/RISCV/saverestore-scs.ll @@ -0,0 +1,40 @@ +;; Check that shadow call stack doesn't interfere with save/restore + +; RUN: llc -mtriple=riscv32 < %s | FileCheck %s -check-prefix=RV32I +; RUN: llc -mtriple=riscv64 < %s | FileCheck %s -check-prefix=RV64I +; RUN: llc -mtriple=riscv32 -mattr=+save-restore < %s | FileCheck %s -check-prefix=RV32I-SR +; RUN: llc -mtriple=riscv64 -mattr=+save-restore < %s | FileCheck %s -check-prefix=RV64I-SR +; RUN: llc -mtriple=riscv32 -mattr=+f,+save-restore -target-abi=ilp32f < %s | FileCheck %s -check-prefix=RV32I-FP-SR +; RUN: llc -mtriple=riscv64 -mattr=+f,+d,+save-restore -target-abi=lp64d < %s | FileCheck %s -check-prefix=RV64I-FP-SR + +@var2 = global [30 x i32] zeroinitializer + +define void @callee_scs() nounwind shadowcallstack { +; RV32I-LABEL: callee_scs: +; RV32I-NOT: call t0, __riscv_save +; RV32I-NOT: tail __riscv_restore +; +; RV64I-LABEL: callee_scs: +; RV64I-NOT: call t0, __riscv_save +; RV64I-NOT: tail __riscv_restore +; +; RV32I-SR-LABEL: callee_scs: +; RV32I-SR: call t0, __riscv_save_12 +; RV32I-SR: tail __riscv_restore_12 +; +; RV64I-SR-LABEL: callee_scs: +; RV64I-SR: call t0, __riscv_save_12 +; RV64I-SR: tail __riscv_restore_12 +; +; RV32I-FP-SR-LABEL: callee_scs: +; RV32I-FP-SR: call t0, __riscv_save_12 +; RV32I-FP-SR: tail __riscv_restore_12 +; +; RV64I-FP-SR-LABEL: callee_scs: +; RV64I-FP-SR: call t0, __riscv_save_12 +; RV64I-FP-SR: tail __riscv_restore_12 + %val = load [30 x i32], ptr @var2 + store volatile [30 x i32] %val, ptr @var2 + ret void +} + diff --git a/llvm/test/CodeGen/RISCV/shadowcallstack.ll b/llvm/test/CodeGen/RISCV/shadowcallstack.ll index 4442372637f24..15c09f01c8d4d 100644 --- a/llvm/test/CodeGen/RISCV/shadowcallstack.ll +++ b/llvm/test/CodeGen/RISCV/shadowcallstack.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -mtriple=riscv32 -mattr=+reserve-x18 -verify-machineinstrs < %s \ +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ ; RUN: | FileCheck %s --check-prefix=RV32 -; RUN: llc -mtriple=riscv64 -mattr=+reserve-x18 -verify-machineinstrs < %s \ +; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ ; RUN: | FileCheck %s --check-prefix=RV64 define void @f1() shadowcallstack { @@ -34,9 +34,9 @@ declare i32 @bar() define i32 @f3() shadowcallstack { ; RV32-LABEL: f3: ; RV32: # %bb.0: -; RV32-NEXT: sw ra, 0(s2) -; RV32-NEXT: addi s2, s2, 4 -; RV32-NEXT: .cfi_escape 0x16, 0x12, 0x02, 0x82, 0x7c # +; RV32-NEXT: sw ra, 0(gp) +; RV32-NEXT: addi gp, gp, 4 +; RV32-NEXT: .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x7c # ; RV32-NEXT: addi sp, sp, -16 ; RV32-NEXT: .cfi_def_cfa_offset 16 ; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill @@ -44,16 +44,16 @@ define i32 @f3() shadowcallstack { ; RV32-NEXT: call bar@plt ; RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload ; RV32-NEXT: addi sp, sp, 16 -; RV32-NEXT: lw ra, -4(s2) -; RV32-NEXT: addi s2, s2, -4 -; RV32-NEXT: .cfi_restore s2 +; RV32-NEXT: lw ra, -4(gp) +; RV32-NEXT: addi gp, gp, -4 +; RV32-NEXT: .cfi_restore gp ; RV32-NEXT: ret ; ; RV64-LABEL: f3: ; RV64: # %bb.0: -; RV64-NEXT: sd ra, 0(s2) -; RV64-NEXT: addi s2, s2, 8 -; RV64-NEXT: .cfi_escape 0x16, 0x12, 0x02, 0x82, 0x78 # +; RV64-NEXT: sd ra, 0(gp) +; RV64-NEXT: addi gp, gp, 8 +; RV64-NEXT: .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x78 # ; RV64-NEXT: addi sp, sp, -16 ; RV64-NEXT: .cfi_def_cfa_offset 16 ; RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill @@ -61,9 +61,9 @@ define i32 @f3() shadowcallstack { ; RV64-NEXT: call bar@plt ; RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload ; RV64-NEXT: addi sp, sp, 16 -; RV64-NEXT: ld ra, -8(s2) -; RV64-NEXT: addi s2, s2, -8 -; RV64-NEXT: .cfi_restore s2 +; RV64-NEXT: ld ra, -8(gp) +; RV64-NEXT: addi gp, gp, -8 +; RV64-NEXT: .cfi_restore gp ; RV64-NEXT: ret %res = call i32 @bar() %res1 = add i32 %res, 1 @@ -73,72 +73,72 @@ define i32 @f3() shadowcallstack { define i32 @f4() shadowcallstack { ; RV32-LABEL: f4: ; RV32: # %bb.0: -; RV32-NEXT: sw ra, 0(s2) -; RV32-NEXT: addi s2, s2, 4 -; RV32-NEXT: .cfi_escape 0x16, 0x12, 0x02, 0x82, 0x7c # +; RV32-NEXT: sw ra, 0(gp) +; RV32-NEXT: addi gp, gp, 4 +; RV32-NEXT: .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x7c # ; RV32-NEXT: addi sp, sp, -16 ; RV32-NEXT: .cfi_def_cfa_offset 16 ; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill ; RV32-NEXT: sw s0, 8(sp) # 4-byte Folded Spill ; RV32-NEXT: sw s1, 4(sp) # 4-byte Folded Spill -; RV32-NEXT: sw s3, 0(sp) # 4-byte Folded Spill +; RV32-NEXT: sw s2, 0(sp) # 4-byte Folded Spill ; RV32-NEXT: .cfi_offset ra, -4 ; RV32-NEXT: .cfi_offset s0, -8 ; RV32-NEXT: .cfi_offset s1, -12 -; RV32-NEXT: .cfi_offset s3, -16 +; RV32-NEXT: .cfi_offset s2, -16 ; RV32-NEXT: call bar@plt ; RV32-NEXT: mv s0, a0 ; RV32-NEXT: call bar@plt ; RV32-NEXT: mv s1, a0 ; RV32-NEXT: call bar@plt -; RV32-NEXT: mv s3, a0 +; RV32-NEXT: mv s2, a0 ; RV32-NEXT: call bar@plt ; RV32-NEXT: add s0, s0, s1 -; RV32-NEXT: add a0, s3, a0 +; RV32-NEXT: add a0, s2, a0 ; RV32-NEXT: add a0, s0, a0 ; RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload ; RV32-NEXT: lw s0, 8(sp) # 4-byte Folded Reload ; RV32-NEXT: lw s1, 4(sp) # 4-byte Folded Reload -; RV32-NEXT: lw s3, 0(sp) # 4-byte Folded Reload +; RV32-NEXT: lw s2, 0(sp) # 4-byte Folded Reload ; RV32-NEXT: addi sp, sp, 16 -; RV32-NEXT: lw ra, -4(s2) -; RV32-NEXT: addi s2, s2, -4 -; RV32-NEXT: .cfi_restore s2 +; RV32-NEXT: lw ra, -4(gp) +; RV32-NEXT: addi gp, gp, -4 +; RV32-NEXT: .cfi_restore gp ; RV32-NEXT: ret ; ; RV64-LABEL: f4: ; RV64: # %bb.0: -; RV64-NEXT: sd ra, 0(s2) -; RV64-NEXT: addi s2, s2, 8 -; RV64-NEXT: .cfi_escape 0x16, 0x12, 0x02, 0x82, 0x78 # +; RV64-NEXT: sd ra, 0(gp) +; RV64-NEXT: addi gp, gp, 8 +; RV64-NEXT: .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x78 # ; RV64-NEXT: addi sp, sp, -32 ; RV64-NEXT: .cfi_def_cfa_offset 32 ; RV64-NEXT: sd ra, 24(sp) # 8-byte Folded Spill ; RV64-NEXT: sd s0, 16(sp) # 8-byte Folded Spill ; RV64-NEXT: sd s1, 8(sp) # 8-byte Folded Spill -; RV64-NEXT: sd s3, 0(sp) # 8-byte Folded Spill +; RV64-NEXT: sd s2, 0(sp) # 8-byte Folded Spill ; RV64-NEXT: .cfi_offset ra, -8 ; RV64-NEXT: .cfi_offset s0, -16 ; RV64-NEXT: .cfi_offset s1, -24 -; RV64-NEXT: .cfi_offset s3, -32 +; RV64-NEXT: .cfi_offset s2, -32 ; RV64-NEXT: call bar@plt ; RV64-NEXT: mv s0, a0 ; RV64-NEXT: call bar@plt ; RV64-NEXT: mv s1, a0 ; RV64-NEXT: call bar@plt -; RV64-NEXT: mv s3, a0 +; RV64-NEXT: mv s2, a0 ; RV64-NEXT: call bar@plt ; RV64-NEXT: add s0, s0, s1 -; RV64-NEXT: add a0, s3, a0 +; RV64-NEXT: add a0, s2, a0 ; RV64-NEXT: addw a0, s0, a0 ; RV64-NEXT: ld ra, 24(sp) # 8-byte Folded Reload ; RV64-NEXT: ld s0, 16(sp) # 8-byte Folded Reload ; RV64-NEXT: ld s1, 8(sp) # 8-byte Folded Reload -; RV64-NEXT: ld s3, 0(sp) # 8-byte Folded Reload +; RV64-NEXT: ld s2, 0(sp) # 8-byte Folded Reload ; RV64-NEXT: addi sp, sp, 32 -; RV64-NEXT: ld ra, -8(s2) -; RV64-NEXT: addi s2, s2, -8 -; RV64-NEXT: .cfi_restore s2 +; RV64-NEXT: ld ra, -8(gp) +; RV64-NEXT: addi gp, gp, -8 +; RV64-NEXT: .cfi_restore gp ; RV64-NEXT: ret %res1 = call i32 @bar() %res2 = call i32 @bar() @@ -153,28 +153,28 @@ define i32 @f4() shadowcallstack { define i32 @f5() shadowcallstack nounwind { ; RV32-LABEL: f5: ; RV32: # %bb.0: -; RV32-NEXT: sw ra, 0(s2) -; RV32-NEXT: addi s2, s2, 4 +; RV32-NEXT: sw ra, 0(gp) +; RV32-NEXT: addi gp, gp, 4 ; RV32-NEXT: addi sp, sp, -16 ; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill ; RV32-NEXT: call bar@plt ; RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload ; RV32-NEXT: addi sp, sp, 16 -; RV32-NEXT: lw ra, -4(s2) -; RV32-NEXT: addi s2, s2, -4 +; RV32-NEXT: lw ra, -4(gp) +; RV32-NEXT: addi gp, gp, -4 ; RV32-NEXT: ret ; ; RV64-LABEL: f5: ; RV64: # %bb.0: -; RV64-NEXT: sd ra, 0(s2) -; RV64-NEXT: addi s2, s2, 8 +; RV64-NEXT: sd ra, 0(gp) +; RV64-NEXT: addi gp, gp, 8 ; RV64-NEXT: addi sp, sp, -16 ; RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill ; RV64-NEXT: call bar@plt ; RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload ; RV64-NEXT: addi sp, sp, 16 -; RV64-NEXT: ld ra, -8(s2) -; RV64-NEXT: addi s2, s2, -8 +; RV64-NEXT: ld ra, -8(gp) +; RV64-NEXT: addi gp, gp, -8 ; RV64-NEXT: ret %res = call i32 @bar() %res1 = add i32 %res, 1