diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3161,10 +3161,13 @@ const std::string &TripleStr = EffectiveTriple.getTriple(); if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_EQ)) { StringRef Value = A->getValue(); - if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64()) + if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64() && + !EffectiveTriple.isARM() && !EffectiveTriple.isThumb()) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; - if (EffectiveTriple.isX86() && Value != "tls" && Value != "global") { + if ((EffectiveTriple.isX86() || EffectiveTriple.isARM() || + EffectiveTriple.isThumb()) && + Value != "tls" && Value != "global") { D.Diag(diag::err_drv_invalid_value_with_suggestion) << A->getOption().getName() << Value << "tls global"; return; @@ -3179,7 +3182,8 @@ if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_offset_EQ)) { StringRef Value = A->getValue(); - if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64()) + if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64() && + !EffectiveTriple.isARM() && !EffectiveTriple.isThumb()) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; int Offset; @@ -3187,6 +3191,12 @@ D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Value; return; } + if ((EffectiveTriple.isARM() || EffectiveTriple.isThumb()) && + (Offset < 0 || Offset > 0xfffff)) { + D.Diag(diag::err_drv_invalid_int_value) + << A->getOption().getName() << Value; + return; + } A->render(Args, CmdArgs); } diff --git a/clang/test/Driver/stack-protector-guard.c b/clang/test/Driver/stack-protector-guard.c --- a/clang/test/Driver/stack-protector-guard.c +++ b/clang/test/Driver/stack-protector-guard.c @@ -15,7 +15,7 @@ // RUN: FileCheck -check-prefix=CHECK-GS %s // Invalid arch -// RUN: not %clang -target arm-eabi-c -mstack-protector-guard=tls %s 2>&1 | \ +// RUN: not %clang -target powerpc64le-linux-gnu -mstack-protector-guard=tls %s 2>&1 | \ // RUN: FileCheck -check-prefix=INVALID-ARCH %s // INVALID-ARCH: unsupported option '-mstack-protector-guard=tls' for target @@ -23,7 +23,7 @@ // RUN: FileCheck -check-prefix=INVALID-ARCH2 %s // INVALID-ARCH2: unsupported option '-mstack-protector-guard-reg=fs' for target -// RUN: not %clang -target arm-linux-gnueabi -mstack-protector-guard-offset=10 %s 2>&1 | \ +// RUN: not %clang -target powerpc64le-linux-gnu -mstack-protector-guard-offset=10 %s 2>&1 | \ // RUN: FileCheck -check-prefix=INVALID-ARCH3 %s // INVALID-ARCH3: unsupported option '-mstack-protector-guard-offset=10' for target @@ -37,6 +37,14 @@ // CHECK-GS: "-cc1" {{.*}}"-mstack-protector-guard-reg=gs" // INVALID-REG: error: invalid value {{.*}} in 'mstack-protector-guard-reg=', expected one of: fs gs +// RUN: not %clang -target arm-eabi-c -mstack-protector-guard-offset=1048576 %s 2>&1 | \ +// RUN: FileCheck -check-prefix=INVALID-OFFSET %s +// INVALID-OFFSET: invalid integral value '1048576' in 'mstack-protector-guard-offset=' + +// RUN: not %clang -target arm-eabi-c -mstack-protector-guard=sysreg %s 2>&1 | \ +// RUN: FileCheck -check-prefix=INVALID-VALUE2 %s +// INVALID-VALUE2: error: invalid value 'sysreg' in 'mstack-protector-guard=', expected one of: tls global + // RUN: %clang -### -target x86_64-unknown-unknown -mstack-protector-guard-offset=30 %s 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-OFFSET %s diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp --- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp +++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -4891,40 +4891,67 @@ MachineBasicBlock &MBB = *MI->getParent(); DebugLoc DL = MI->getDebugLoc(); Register Reg = MI->getOperand(0).getReg(); - const GlobalValue *GV = - cast((*MI->memoperands_begin())->getValue()); - bool IsIndirect = Subtarget.isGVIndirectSymbol(GV); MachineInstrBuilder MIB; + unsigned int Offset = 0; - unsigned TargetFlags = ARMII::MO_NO_FLAG; - if (Subtarget.isTargetMachO()) { - TargetFlags |= ARMII::MO_NONLAZY; - } else if (Subtarget.isTargetCOFF()) { - if (GV->hasDLLImportStorageClass()) - TargetFlags |= ARMII::MO_DLLIMPORT; - else if (IsIndirect) - TargetFlags |= ARMII::MO_COFFSTUB; - } else if (Subtarget.isGVInGOT(GV)) { - TargetFlags |= ARMII::MO_GOT; - } + if (LoadImmOpc == ARM::MRC || LoadImmOpc == ARM::t2MRC) { + BuildMI(MBB, MI, DL, get(LoadImmOpc), Reg) + .addImm(15) + .addImm(0) + .addImm(13) + .addImm(0) + .addImm(3) + .add(predOps(ARMCC::AL)); - BuildMI(MBB, MI, DL, get(LoadImmOpc), Reg) - .addGlobalAddress(GV, 0, TargetFlags); + Module &M = *MBB.getParent()->getFunction().getParent(); + Offset = M.getStackProtectorGuardOffset(); + if (Offset & ~0xfffU) { + // The offset won't fit in the LDR's 12-bit immediate field, so emit an + // extra ADD to cover the delta. This gives us a guaranteed 8 additional + // bits, resulting in a range of 0 to +1 MiB for the guard offset. + unsigned AddOpc = (LoadImmOpc == ARM::MRC) ? ARM::ADDri : ARM::t2ADDri; + BuildMI(MBB, MI, DL, get(AddOpc), Reg) + .addReg(Reg, RegState::Kill) + .addImm(Offset & ~0xfffU) + .add(predOps(ARMCC::AL)) + .addReg(0); + Offset &= 0xfffU; + } + } else { + const GlobalValue *GV = + cast((*MI->memoperands_begin())->getValue()); + bool IsIndirect = Subtarget.isGVIndirectSymbol(GV); + + unsigned TargetFlags = ARMII::MO_NO_FLAG; + if (Subtarget.isTargetMachO()) { + TargetFlags |= ARMII::MO_NONLAZY; + } else if (Subtarget.isTargetCOFF()) { + if (GV->hasDLLImportStorageClass()) + TargetFlags |= ARMII::MO_DLLIMPORT; + else if (IsIndirect) + TargetFlags |= ARMII::MO_COFFSTUB; + } else if (Subtarget.isGVInGOT(GV)) { + TargetFlags |= ARMII::MO_GOT; + } - if (IsIndirect) { - MIB = BuildMI(MBB, MI, DL, get(LoadOpc), Reg); - MIB.addReg(Reg, RegState::Kill).addImm(0); - auto Flags = MachineMemOperand::MOLoad | - MachineMemOperand::MODereferenceable | - MachineMemOperand::MOInvariant; - MachineMemOperand *MMO = MBB.getParent()->getMachineMemOperand( - MachinePointerInfo::getGOT(*MBB.getParent()), Flags, 4, Align(4)); - MIB.addMemOperand(MMO).add(predOps(ARMCC::AL)); + BuildMI(MBB, MI, DL, get(LoadImmOpc), Reg) + .addGlobalAddress(GV, 0, TargetFlags); + + if (IsIndirect) { + MIB = BuildMI(MBB, MI, DL, get(LoadOpc), Reg); + MIB.addReg(Reg, RegState::Kill).addImm(0); + auto Flags = MachineMemOperand::MOLoad | + MachineMemOperand::MODereferenceable | + MachineMemOperand::MOInvariant; + MachineMemOperand *MMO = MBB.getParent()->getMachineMemOperand( + MachinePointerInfo::getGOT(*MBB.getParent()), Flags, 4, Align(4)); + MIB.addMemOperand(MMO).add(predOps(ARMCC::AL)); + } } MIB = BuildMI(MBB, MI, DL, get(LoadOpc), Reg); MIB.addReg(Reg, RegState::Kill) - .addImm(0) + .addImm(Offset) .cloneMemRefs(*MI) .add(predOps(ARMCC::AL)); } diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.cpp b/llvm/lib/Target/ARM/ARMInstrInfo.cpp --- a/llvm/lib/Target/ARM/ARMInstrInfo.cpp +++ b/llvm/lib/Target/ARM/ARMInstrInfo.cpp @@ -95,6 +95,13 @@ MachineFunction &MF = *MI->getParent()->getParent(); const ARMSubtarget &Subtarget = MF.getSubtarget(); const TargetMachine &TM = MF.getTarget(); + MachineBasicBlock &MBB = *MI->getParent(); + Module &M = *MBB.getParent()->getFunction().getParent(); + + if (M.getStackProtectorGuard() == "tls") { + expandLoadStackGuardBase(MI, ARM::MRC, ARM::LDRi12); + return; + } const GlobalValue *GV = cast((*MI->memoperands_begin())->getValue()); @@ -117,7 +124,6 @@ return; } - MachineBasicBlock &MBB = *MI->getParent(); DebugLoc DL = MI->getDebugLoc(); Register Reg = MI->getOperand(0).getReg(); MachineInstrBuilder MIB; diff --git a/llvm/lib/Target/ARM/Thumb2InstrInfo.cpp b/llvm/lib/Target/ARM/Thumb2InstrInfo.cpp --- a/llvm/lib/Target/ARM/Thumb2InstrInfo.cpp +++ b/llvm/lib/Target/ARM/Thumb2InstrInfo.cpp @@ -250,6 +250,14 @@ void Thumb2InstrInfo::expandLoadStackGuard( MachineBasicBlock::iterator MI) const { MachineFunction &MF = *MI->getParent()->getParent(); + MachineBasicBlock &MBB = *MI->getParent(); + Module &M = *MBB.getParent()->getFunction().getParent(); + + if (M.getStackProtectorGuard() == "tls") { + expandLoadStackGuardBase(MI, ARM::t2MRC, ARM::t2LDRi12); + return; + } + const GlobalValue *GV = cast((*MI->memoperands_begin())->getValue()); diff --git a/llvm/test/CodeGen/ARM/stack-guard-tls.ll b/llvm/test/CodeGen/ARM/stack-guard-tls.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/ARM/stack-guard-tls.ll @@ -0,0 +1,38 @@ +; RUN: split-file %s %t +; RUN: cat %t/main.ll %t/a.ll > %t/a2.ll +; RUN: cat %t/main.ll %t/b.ll > %t/b2.ll +; RUN: llc %t/a2.ll -mtriple=armv7-unknown-linux-gnueabihf -o - | \ +; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-SMALL %s +; RUN: llc %t/a2.ll -mtriple=thumbv7-unknown-linux-gnueabihf -o - | \ +; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-SMALL %s +; RUN: llc %t/b2.ll -mtriple=armv7-unknown-linux-gnueabihf -o - | \ +; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-LARGE %s +; RUN: llc %t/b2.ll -mtriple=thumbv7-unknown-linux-gnueabihf -o - | \ +; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-LARGE %s + +;--- main.ll +declare void @baz(i32*) + +define void @foo(i64 %t) sspstrong { + %vla = alloca i32, i64 %t, align 4 + call void @baz(i32* nonnull %vla) + ret void +} +!llvm.module.flags = !{!1, !2} +!1 = !{i32 2, !"stack-protector-guard", !"tls"} + +;--- a.ll +!2 = !{i32 2, !"stack-protector-guard-offset", i32 1296} + +;--- b.ll +!2 = !{i32 2, !"stack-protector-guard-offset", i32 4296} + +; CHECK: mrc p15, #0, [[REG1:r[0-9]+]], c13, c0, #3 +; CHECK-SMALL-NEXT: ldr{{(\.w)?}} [[REG1]], {{\[}}[[REG1]], #1296] +; CHECK-LARGE-NEXT: add{{(\.w)?}} [[REG1]], [[REG1]], #4096 +; CHECK-LARGE-NEXT: ldr{{(\.w)?}} [[REG1]], {{\[}}[[REG1]], #200] +; CHECK: bl baz +; CHECK: mrc p15, #0, [[REG2:r[0-9]+]], c13, c0, #3 +; CHECK-SMALL-NEXT: ldr{{(\.w)?}} [[REG2]], {{\[}}[[REG2]], #1296] +; CHECK-LARGE-NEXT: add{{(\.w)?}} [[REG2]], [[REG2]], #4096 +; CHECK-LARGE-NEXT: ldr{{(\.w)?}} [[REG2]], {{\[}}[[REG2]], #200]