Skip to content

Commit 63cdc78

Browse files
[SystemZ] Global Stackprotector and associated location section
This commit allows `-mstack-protector-guard=global` for `s390x`. It also adds a new arch-specific option `-mstack-protector-guard-record`, analogous to `-mrecord-mcount`, which will cause `clang` to emit a `__stack_protector_loc` section containing all the locations in the output binary that load the stack guard address, for the purposes of later rewriting of those loads by the kernel. This new option only works together with the `global` stack protector. In order to minimize exposure of the stack guard, both the storing of the stack guard onto the stack, and the later comparison of that value against the reference value, are handled via direct mem-to-mem instructions, those being `mvc` and `clc`. This is achieved by introducing two new pseudo instructions, `MOVE_STACK_GUARD` and `COMPARE_STACK_GUARD`, which are inserted by the DAGCombiner after SelectionDAG construction. These pseudos stick around throughout the entire backend pipeline, and are lowered only in the AsmPrinter. This commit also adds tests for both kinds of stack protectors (tls and global), for the proper insertion of the pseudos, the proper emission of the, `__stack_protector_loc` section, as well as the option compatibility checks for the new options.
1 parent 9be30e5 commit 63cdc78

File tree

18 files changed

+811
-91
lines changed

18 files changed

+811
-91
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ CODEGENOPT(InstrumentForProfiling , 1, 0, Benign) ///< Set when -pg is enabled.
157157
CODEGENOPT(CallFEntry , 1, 0, Benign) ///< Set when -mfentry is enabled.
158158
CODEGENOPT(MNopMCount , 1, 0, Benign) ///< Set when -mnop-mcount is enabled.
159159
CODEGENOPT(RecordMCount , 1, 0, Benign) ///< Set when -mrecord-mcount is enabled.
160+
CODEGENOPT(StackProtectorGuardRecord, 1, 0, Benign) ///< Set when -mstack-protector-guard-record is enabled.
160161
CODEGENOPT(PackedStack , 1, 0, Benign) ///< Set when -mpacked-stack is enabled.
161162
CODEGENOPT(LessPreciseFPMAD , 1, 0, Benign) ///< Enable less precise MAD instructions to
162163
///< be generated.

clang/include/clang/Options/Options.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5749,6 +5749,14 @@ def mstack_protector_guard_reg_EQ : Joined<["-"], "mstack-protector-guard-reg=">
57495749
Visibility<[ClangOption, CC1Option]>,
57505750
HelpText<"Use the given reg for addressing the stack-protector guard">,
57515751
MarshallingInfoString<CodeGenOpts<"StackProtectorGuardReg">>;
5752+
def mstackprotector_guard_record
5753+
: Flag<["-"], "mstack-protector-guard-record">,
5754+
HelpText<
5755+
"Generate a __stack_protector_loc section entry for each load of "
5756+
"the stackguard address.">,
5757+
Visibility<[ClangOption, CC1Option]>,
5758+
Group<m_Group>,
5759+
MarshallingInfoFlag<CodeGenOpts<"StackProtectorGuardRecord">>;
57525760
def mfentry : Flag<["-"], "mfentry">, HelpText<"Insert calls to fentry at function entry (x86/SystemZ only)">,
57535761
Visibility<[ClangOption, CC1Option]>, Group<m_Group>,
57545762
MarshallingInfoFlag<CodeGenOpts<"CallFEntry">>;

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,6 +1195,14 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
11951195
}
11961196
}
11971197

1198+
if (CGM.getCodeGenOpts().StackProtectorGuardRecord) {
1199+
if (CGM.getCodeGenOpts().StackProtectorGuard != "global")
1200+
CGM.getDiags().Report(diag::err_opt_not_valid_without_opt)
1201+
<< "-mstack-protector-guard-record"
1202+
<< "-mstack-protector-guard=global";
1203+
Fn->addFnAttr("mstackprotector-guard-record");
1204+
}
1205+
11981206
if (CGM.getCodeGenOpts().PackedStack) {
11991207
if (getContext().getTargetInfo().getTriple().getArch() !=
12001208
llvm::Triple::systemz)

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3438,22 +3438,24 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
34383438
}
34393439

34403440
const std::string &TripleStr = EffectiveTriple.getTriple();
3441+
StringRef GuardValue;
34413442
if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_EQ)) {
3442-
StringRef Value = A->getValue();
3443+
GuardValue = A->getValue();
34433444
if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64() &&
34443445
!EffectiveTriple.isARM() && !EffectiveTriple.isThumb() &&
3445-
!EffectiveTriple.isRISCV() && !EffectiveTriple.isPPC())
3446+
!EffectiveTriple.isRISCV() && !EffectiveTriple.isPPC() &&
3447+
!EffectiveTriple.isSystemZ())
34463448
D.Diag(diag::err_drv_unsupported_opt_for_target)
34473449
<< A->getAsString(Args) << TripleStr;
34483450
if ((EffectiveTriple.isX86() || EffectiveTriple.isARM() ||
3449-
EffectiveTriple.isThumb()) &&
3450-
Value != "tls" && Value != "global") {
3451+
EffectiveTriple.isThumb() || EffectiveTriple.isSystemZ()) &&
3452+
GuardValue != "tls" && GuardValue != "global") {
34513453
D.Diag(diag::err_drv_invalid_value_with_suggestion)
3452-
<< A->getOption().getName() << Value << "tls global";
3454+
<< A->getOption().getName() << GuardValue << "tls global";
34533455
return;
34543456
}
34553457
if ((EffectiveTriple.isARM() || EffectiveTriple.isThumb()) &&
3456-
Value == "tls") {
3458+
GuardValue == "tls") {
34573459
if (!Args.hasArg(options::OPT_mstack_protector_guard_offset_EQ)) {
34583460
D.Diag(diag::err_drv_ssp_missing_offset_argument)
34593461
<< A->getAsString(Args);
@@ -3477,18 +3479,19 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
34773479
CmdArgs.push_back("-target-feature");
34783480
CmdArgs.push_back("+read-tp-tpidruro");
34793481
}
3480-
if (EffectiveTriple.isAArch64() && Value != "sysreg" && Value != "global") {
3482+
if (EffectiveTriple.isAArch64() && GuardValue != "sysreg" &&
3483+
GuardValue != "global") {
34813484
D.Diag(diag::err_drv_invalid_value_with_suggestion)
3482-
<< A->getOption().getName() << Value << "sysreg global";
3485+
<< A->getOption().getName() << GuardValue << "sysreg global";
34833486
return;
34843487
}
34853488
if (EffectiveTriple.isRISCV() || EffectiveTriple.isPPC()) {
3486-
if (Value != "tls" && Value != "global") {
3489+
if (GuardValue != "tls" && GuardValue != "global") {
34873490
D.Diag(diag::err_drv_invalid_value_with_suggestion)
3488-
<< A->getOption().getName() << Value << "tls global";
3491+
<< A->getOption().getName() << GuardValue << "tls global";
34893492
return;
34903493
}
3491-
if (Value == "tls") {
3494+
if (GuardValue == "tls") {
34923495
if (!Args.hasArg(options::OPT_mstack_protector_guard_offset_EQ)) {
34933496
D.Diag(diag::err_drv_ssp_missing_offset_argument)
34943497
<< A->getAsString(Args);
@@ -3562,6 +3565,21 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
35623565
}
35633566
A->render(Args, CmdArgs);
35643567
}
3568+
3569+
if (Arg *A = Args.getLastArg(options::OPT_mstackprotector_guard_record)) {
3570+
if (!EffectiveTriple.isSystemZ()) {
3571+
D.Diag(diag::err_drv_unsupported_opt_for_target)
3572+
<< A->getAsString(Args) << TripleStr;
3573+
return;
3574+
}
3575+
if (GuardValue != "global") {
3576+
D.Diag(diag::err_drv_argument_only_allowed_with)
3577+
<< "-mstack-protector-guard-record"
3578+
<< "-mstack-protector-guard=global";
3579+
return;
3580+
}
3581+
A->render(Args, CmdArgs);
3582+
}
35653583
}
35663584

35673585
static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clang_cc1 -S -mllvm -stop-after=systemz-isel -stack-protector 1 -triple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-PSEUDOS %s
2+
// RUN: not %clang_cc1 -S -stack-protector 1 -mstack-protector-guard-record -triple=s390x-ibm-linux < %s -o - 2>&1 | FileCheck -check-prefix=CHECK-OPTS %s
3+
// CHECK-PSEUDOS: bb.0.entry:
4+
// CHECK-PSEUDOS: %3:addr64bit = LOAD_STACK_GUARD_ADDRESS
5+
// CHECK-PSEUDOS: MOVE_STACK_GUARD %stack.0.StackGuardSlot, 0, %3
6+
// CHECK-PSEUDOS: COMPARE_STACK_GUARD %stack.0.StackGuardSlot, 0, %3, implicit-def $cc
7+
8+
extern char *strcpy (char * D, const char * S);
9+
int main(int argc, char *argv[])
10+
{
11+
char Buffer[8] = {0};
12+
strcpy(Buffer, argv[1]);
13+
return 0;
14+
}
15+
16+
// CHECK-OPTS: error: option '-mstack-protector-guard-record' cannot be specified without '-mstack-protector-guard=global'

clang/test/Driver/stack-protector-guard.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,21 @@
155155

156156
// CHECK-TLS-POWERPC32: "-cc1" {{.*}}"-mstack-protector-guard=tls" "-mstack-protector-guard-offset=24" "-mstack-protector-guard-reg=r2"
157157
// INVALID-REG-POWERPC32: error: invalid value 'r3' in 'mstack-protector-guard-reg=', expected one of: r2
158+
159+
// RUN: %clang -### -target systemz-unknown-elf -mstack-protector-guard=tls %s 2>&1 | \
160+
// RUN: FileCheck -check-prefix=CHECK_TLS_SYSTEMZ %s
161+
// CHECK_TLS_SYSTEMZ: "-cc1" {{.*}}"-mstack-protector-guard=tls"
162+
163+
// RUN: %clang -### -target systemz-unknown-elf -mstack-protector-guard=global %s 2>&1 | \
164+
// RUN: FileCheck -check-prefix=CHECK_GLOBAL_SYSTEMZ %s
165+
// CHECK_GLOBAL_SYSTEMZ: "-cc1" {{.*}}"-mstack-protector-guard=global"
166+
167+
// RUN: %clang -### -target systemz-unknown-elf -mstack-protector-guard=global \
168+
// RUN: -mstack-protector-guard-record %s 2>&1 | \
169+
// RUN: FileCheck -check-prefix=CHECK_GLOBAL_RECORD_SYSTEMZ %s
170+
// CHECK_GLOBAL_RECORD_SYSTEMZ: "-cc1" {{.*}}"-mstack-protector-guard=global" "-mstack-protector-guard-record"
171+
172+
// RUN: not %clang -target systemz-unknown-elf -mstack-protector-guard=tls \
173+
// RUN: -mstack-protector-guard-record %s 2>&1 | \
174+
// RUN: FileCheck -check-prefix=INVALID_TLS_RECORD_SYSTEMZ %s
175+
// INVALID_TLS_RECORD_SYSTEMZ: error: invalid argument '-mstack-protector-guard-record' only allowed with '-mstack-protector-guard=global'

llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
#include "llvm/BinaryFormat/GOFF.h"
2525
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
2626
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
27+
#include "llvm/IR/GlobalVariable.h"
2728
#include "llvm/IR/Mangler.h"
2829
#include "llvm/IR/Module.h"
2930
#include "llvm/MC/MCExpr.h"
31+
#include "llvm/MC/MCInst.h"
3032
#include "llvm/MC/MCInstBuilder.h"
3133
#include "llvm/MC/MCSectionELF.h"
3234
#include "llvm/MC/MCStreamer.h"
@@ -213,6 +215,16 @@ SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MachineOperand MO) {
213215
return insert(Sym, ADAslotType);
214216
}
215217

218+
namespace {
219+
unsigned long getStackGuardOffset(const MachineBasicBlock *MBB) {
220+
// In the TLS (default) case, AddrReg will contain the thread pointer, so we
221+
// need to add 40 bytes to get the actual address of the stack guard.
222+
StringRef GuardType =
223+
MBB->getParent()->getFunction().getParent()->getStackProtectorGuard();
224+
return (GuardType == "global") ? 0 : 40;
225+
}
226+
} // namespace
227+
216228
void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
217229
SystemZ_MC::verifyInstructionPredicates(MI->getOpcode(),
218230
getSubtargetInfo().getFeatureBits());
@@ -740,13 +752,128 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
740752
case SystemZ::EH_SjLj_Setup:
741753
return;
742754

755+
case SystemZ::LOAD_STACK_GUARD: {
756+
// If requested, record address of stack guard address load
757+
if (MF->getFunction().hasFnAttribute("mstackprotector-guard-record"))
758+
emitStackProtectorLocEntry();
759+
Register AddrReg = emitLoadStackGuardAddress(MI);
760+
LoweredMI = MCInstBuilder(SystemZ::LG)
761+
.addReg(AddrReg)
762+
.addImm(getStackGuardOffset(MI->getParent()))
763+
.addReg(0);
764+
} break;
765+
766+
case SystemZ::LOAD_STACK_GUARD_ADDRESS:
767+
// If requested, record address of stack guard address load
768+
if (MF->getFunction().hasFnAttribute("mstackprotector-guard-record"))
769+
emitStackProtectorLocEntry();
770+
emitLoadStackGuardAddress(MI);
771+
return;
772+
773+
case SystemZ::COMPARE_STACK_GUARD:
774+
LoweredMI = MCInstBuilder(SystemZ::CLC)
775+
.addReg(MI->getOperand(0).getReg())
776+
.addImm(MI->getOperand(1).getImm())
777+
.addImm(8)
778+
.addReg(MI->getOperand(2).getReg())
779+
.addImm(getStackGuardOffset(MI->getParent()));
780+
break;
781+
782+
case SystemZ::MOVE_STACK_GUARD:
783+
LoweredMI = MCInstBuilder(SystemZ::MVC)
784+
.addReg(MI->getOperand(0).getReg())
785+
.addImm(MI->getOperand(1).getImm())
786+
.addImm(8)
787+
.addReg(MI->getOperand(2).getReg())
788+
.addImm(getStackGuardOffset(MI->getParent()));
789+
break;
790+
743791
default:
744792
Lower.lower(MI, LoweredMI);
745793
break;
746794
}
747795
EmitToStreamer(*OutStreamer, LoweredMI);
748796
}
749797

798+
void SystemZAsmPrinter::emitStackProtectorLocEntry() {
799+
MCSymbol *Sym = OutContext.createTempSymbol();
800+
OutStreamer->pushSection();
801+
OutStreamer->switchSection(OutContext.getELFSection(
802+
"__stack_protector_loc", ELF::SHT_PROGBITS, ELF::SHF_ALLOC));
803+
OutStreamer->emitSymbolValue(Sym, getDataLayout().getPointerSize());
804+
OutStreamer->popSection();
805+
OutStreamer->emitLabel(Sym);
806+
}
807+
808+
// Emit the stack guard address load, depending on guard type.
809+
// Return the register the stack guard address was loaded into.
810+
Register SystemZAsmPrinter::emitLoadStackGuardAddress(const MachineInstr *MI) {
811+
const MachineBasicBlock *MBB = MI->getParent();
812+
const MachineFunction &MF = *MBB->getParent();
813+
const Register AddrReg = MI->getOperand(0).getReg();
814+
const MCRegisterInfo &MRI = *TM.getMCRegisterInfo();
815+
const Register Reg32 = MRI.getSubReg(AddrReg, SystemZ::subreg_l32);
816+
817+
const Module *M = MF.getFunction().getParent();
818+
StringRef GuardType = M->getStackProtectorGuard();
819+
820+
if (GuardType.empty() || (GuardType == "tls")) {
821+
// EAR can only load the low subregister so use a shift for %a0 to produce
822+
// the GR containing %a0 and %a1.
823+
824+
// ear <reg>, %a0
825+
MCInst EAR1 = MCInstBuilder(SystemZ::EAR)
826+
.addReg(Reg32)
827+
.addReg(SystemZ::A0)
828+
.addReg(AddrReg);
829+
830+
// sllg <reg>, <reg>, 32
831+
MCInst SLLG = MCInstBuilder(SystemZ::SLLG)
832+
.addReg(AddrReg)
833+
.addReg(AddrReg)
834+
.addReg(0)
835+
.addImm(32);
836+
837+
// ear <reg>, %a1
838+
MCInst EAR2 = MCInstBuilder(SystemZ::EAR)
839+
.addReg(Reg32)
840+
.addReg(SystemZ::A1)
841+
.addReg(AddrReg);
842+
843+
EmitToStreamer(*OutStreamer, EAR1);
844+
EmitToStreamer(*OutStreamer, SLLG);
845+
EmitToStreamer(*OutStreamer, EAR2);
846+
} else if (GuardType == "global") {
847+
// Obtain the global value.
848+
const auto *GV = M->getGlobalVariable(
849+
"__stack_chk_guard", PointerType::getUnqual(M->getContext()));
850+
assert(GV &&
851+
"could not create reference to global variable __stack_chk_guard");
852+
auto *Sym = TM.getSymbol(GV);
853+
// Ref->
854+
// Emit the address load.
855+
MCInst Load;
856+
if (M->getPICLevel() == PICLevel::NotPIC) {
857+
Load = MCInstBuilder(SystemZ::LARL)
858+
.addReg(AddrReg)
859+
.addExpr(MCSymbolRefExpr::create(Sym, OutContext));
860+
} else {
861+
Load =
862+
MCInstBuilder(SystemZ::LGRL)
863+
.addReg(AddrReg)
864+
.addExpr(MCSymbolRefExpr::create(Sym, SystemZ::S_GOT, OutContext))
865+
.addExpr(getGlobalOffsetTable(OutContext));
866+
}
867+
EmitToStreamer(*OutStreamer, Load);
868+
} else {
869+
llvm_unreachable(
870+
(Twine("Unknown stack protector type \"") + GuardType + "\"")
871+
.str()
872+
.c_str());
873+
}
874+
return AddrReg;
875+
}
876+
750877
// Emit the largest nop instruction smaller than or equal to NumBytes
751878
// bytes. Return the size of nop emitted.
752879
static unsigned EmitNop(MCContext &OutContext, MCStreamer &OutStreamer,

llvm/lib/Target/SystemZ/SystemZAsmPrinter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
139139
void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI,
140140
SystemZMCInstLower &Lower);
141141
void LowerPATCHABLE_RET(const MachineInstr &MI, SystemZMCInstLower &Lower);
142+
Register emitLoadStackGuardAddress(const MachineInstr *MI);
143+
void emitStackProtectorLocEntry();
142144
void emitAttributes(Module &M);
143145
};
144146
} // end namespace llvm

llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include "SystemZTargetMachine.h"
1413
#include "SystemZISelLowering.h"
14+
#include "SystemZTargetMachine.h"
1515
#include "llvm/Analysis/AliasAnalysis.h"
1616
#include "llvm/CodeGen/SelectionDAGISel.h"
17+
#include "llvm/IR/Module.h"
1718
#include "llvm/Support/Debug.h"
1819
#include "llvm/Support/KnownBits.h"
1920
#include "llvm/Support/raw_ostream.h"
@@ -369,7 +370,11 @@ class SystemZDAGToDAGISel : public SelectionDAGISel {
369370
if (F.hasFnAttribute("mrecord-mcount"))
370371
report_fatal_error("mrecord-mcount only supported with fentry-call");
371372
}
372-
373+
if (F.getParent()->getStackProtectorGuard() != "global") {
374+
if (F.hasFnAttribute("mstack-protector-guard-record"))
375+
report_fatal_error("mstack-protector-guard-record only supported with "
376+
"mstack-protector-guard=global");
377+
}
373378
Subtarget = &MF.getSubtarget<SystemZSubtarget>();
374379
return SelectionDAGISel::runOnMachineFunction(MF);
375380
}

0 commit comments

Comments
 (0)