Skip to content

Commit 7c3fea7

Browse files
committed
[X86] Support customizing stack protector guard
Reviewed By: nickdesaulniers, MaskRay Differential Revision: https://reviews.llvm.org/D88631
1 parent 007ffdc commit 7c3fea7

File tree

14 files changed

+285
-8
lines changed

14 files changed

+285
-8
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,9 @@ ENUM_CODEGENOPT(DefaultTLSModel, TLSModel, 2, GeneralDynamicTLSModel)
356356
/// Bit size of immediate TLS offsets (0 == use the default).
357357
VALUE_CODEGENOPT(TLSSize, 8, 0)
358358

359+
/// The default stack protector guard offset to use.
360+
VALUE_CODEGENOPT(StackProtectorGuardOffset, 32, (unsigned)-1)
361+
359362
/// Number of path components to strip when emitting checks. (0 == full
360363
/// filename)
361364
VALUE_CODEGENOPT(EmitCheckPathComponentsToStrip, 32, 0)

clang/include/clang/Basic/CodeGenOptions.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,15 @@ class CodeGenOptions : public CodeGenOptionsBase {
327327
/// by sanitizer coverage pass.
328328
std::vector<std::string> SanitizeCoverageAllowlistFiles;
329329

330+
/// The guard style used for stack protector to get a initial value, this
331+
/// value usually be gotten from TLS or get from __stack_chk_guard, or some
332+
/// other styles we may implement in the future.
333+
std::string StackProtectorGuard;
334+
335+
/// The TLS base register when StackProtectorGuard is "tls".
336+
/// On x86 this can be "fs" or "gs".
337+
std::string StackProtectorGuardReg;
338+
330339
/// Path to blocklist file specifying which objects
331340
/// (files, functions) listed for instrumentation by sanitizer
332341
/// coverage pass should actually not be instrumented.

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ def err_drv_dllexport_inlines_and_fallback : Error<
213213

214214
def err_drv_invalid_value : Error<"invalid value '%1' in '%0'">;
215215
def err_drv_invalid_int_value : Error<"invalid integral value '%1' in '%0'">;
216+
def err_drv_invalid_value_with_suggestion : Error<"invalid value '%1' in '%0','%2'">;
216217
def err_drv_invalid_remap_file : Error<
217218
"invalid option '%0' not of the form <from-file>;<to-file>">;
218219
def err_drv_invalid_gcc_output_type : Error<

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2606,6 +2606,12 @@ def mrecip : Flag<["-"], "mrecip">, Group<m_Group>;
26062606
def mrecip_EQ : CommaJoined<["-"], "mrecip=">, Group<m_Group>, Flags<[CC1Option]>;
26072607
def mprefer_vector_width_EQ : Joined<["-"], "mprefer-vector-width=">, Group<m_Group>, Flags<[CC1Option]>,
26082608
HelpText<"Specifies preferred vector width for auto-vectorization. Defaults to 'none' which allows target specific decisions.">;
2609+
def mstack_protector_guard_EQ : Joined<["-"], "mstack-protector-guard=">, Group<m_Group>, Flags<[CC1Option]>,
2610+
HelpText<"Use the given guard (global, tls) for addressing the stack-protector guard">;
2611+
def mstack_protector_guard_offset_EQ : Joined<["-"], "mstack-protector-guard-offset=">, Group<m_Group>, Flags<[CC1Option]>,
2612+
HelpText<"Use the given offset for addressing the stack-protector guard">;
2613+
def mstack_protector_guard_reg_EQ : Joined<["-"], "mstack-protector-guard-reg=">, Group<m_Group>, Flags<[CC1Option]>,
2614+
HelpText<"Use the given reg for addressing the stack-protector guard">;
26092615
def mpie_copy_relocations : Flag<["-"], "mpie-copy-relocations">, Group<m_Group>,
26102616
Flags<[CC1Option]>,
26112617
HelpText<"Use copy relocations support for PIE builds">;

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,14 @@ static void initTargetOptions(DiagnosticsEngine &Diags,
521521
Options.UniqueSectionNames = CodeGenOpts.UniqueSectionNames;
522522
Options.UniqueBasicBlockSectionNames =
523523
CodeGenOpts.UniqueBasicBlockSectionNames;
524+
Options.StackProtectorGuard =
525+
llvm::StringSwitch<llvm::StackProtectorGuards>(CodeGenOpts
526+
.StackProtectorGuard)
527+
.Case("tls", llvm::StackProtectorGuards::TLS)
528+
.Case("global", llvm::StackProtectorGuards::Global)
529+
.Default(llvm::StackProtectorGuards::None);
530+
Options.StackProtectorGuardOffset = CodeGenOpts.StackProtectorGuardOffset;
531+
Options.StackProtectorGuardReg = CodeGenOpts.StackProtectorGuardReg;
524532
Options.TLSSize = CodeGenOpts.TLSSize;
525533
Options.EmulatedTLS = CodeGenOpts.EmulatedTLS;
526534
Options.ExplicitEmulatedTLS = CodeGenOpts.ExplicitEmulatedTLS;

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2984,8 +2984,9 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs,
29842984
Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer);
29852985
}
29862986

2987-
static void RenderSSPOptions(const ToolChain &TC, const ArgList &Args,
2988-
ArgStringList &CmdArgs, bool KernelOrKext) {
2987+
static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
2988+
const ArgList &Args, ArgStringList &CmdArgs,
2989+
bool KernelOrKext) {
29892990
const llvm::Triple &EffectiveTriple = TC.getEffectiveTriple();
29902991

29912992
// NVPTX doesn't support stack protectors; from the compiler's perspective, it
@@ -3030,6 +3031,50 @@ static void RenderSSPOptions(const ToolChain &TC, const ArgList &Args,
30303031
A->claim();
30313032
}
30323033
}
3034+
3035+
// First support "tls" and "global" for X86 target.
3036+
// TODO: Support "sysreg" for AArch64.
3037+
const std::string &TripleStr = EffectiveTriple.getTriple();
3038+
if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_EQ)) {
3039+
StringRef Value = A->getValue();
3040+
if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64())
3041+
D.Diag(diag::err_drv_unsupported_opt_for_target)
3042+
<< A->getAsString(Args) << TripleStr;
3043+
if (Value != "tls" && Value != "global") {
3044+
D.Diag(diag::err_drv_invalid_value_with_suggestion)
3045+
<< A->getOption().getName() << Value
3046+
<< "valid arguments to '-mstack-protector-guard=' are:tls global";
3047+
return;
3048+
}
3049+
A->render(Args, CmdArgs);
3050+
}
3051+
3052+
if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_offset_EQ)) {
3053+
StringRef Value = A->getValue();
3054+
if (!EffectiveTriple.isX86())
3055+
D.Diag(diag::err_drv_unsupported_opt_for_target)
3056+
<< A->getAsString(Args) << TripleStr;
3057+
unsigned Offset;
3058+
if (Value.getAsInteger(10, Offset)) {
3059+
D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Value;
3060+
return;
3061+
}
3062+
A->render(Args, CmdArgs);
3063+
}
3064+
3065+
if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_reg_EQ)) {
3066+
StringRef Value = A->getValue();
3067+
if (!EffectiveTriple.isX86())
3068+
D.Diag(diag::err_drv_unsupported_opt_for_target)
3069+
<< A->getAsString(Args) << TripleStr;
3070+
if (EffectiveTriple.isX86() && (Value != "fs" && Value != "gs")) {
3071+
D.Diag(diag::err_drv_invalid_value_with_suggestion)
3072+
<< A->getOption().getName() << Value
3073+
<< "for X86, valid arguments to '-mstack-protector-guard-reg=' are:fs gs";
3074+
return;
3075+
}
3076+
A->render(Args, CmdArgs);
3077+
}
30333078
}
30343079

30353080
static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args,
@@ -5467,7 +5512,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
54675512
options::OPT_mno_speculative_load_hardening, false))
54685513
CmdArgs.push_back(Args.MakeArgString("-mspeculative-load-hardening"));
54695514

5470-
RenderSSPOptions(TC, Args, CmdArgs, KernelOrKext);
5515+
RenderSSPOptions(D, TC, Args, CmdArgs, KernelOrKext);
54715516
RenderSCPOptions(TC, Args, CmdArgs);
54725517
RenderTrivialAutoVarInitOptions(D, TC, Args, CmdArgs);
54735518

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,21 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
12541254
}
12551255
Opts.SSPBufferSize =
12561256
getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags);
1257+
1258+
Opts.StackProtectorGuard =
1259+
std::string(Args.getLastArgValue(OPT_mstack_protector_guard_EQ));
1260+
1261+
if (Arg *A = Args.getLastArg(OPT_mstack_protector_guard_offset_EQ)) {
1262+
StringRef Val = A->getValue();
1263+
unsigned Offset = Opts.StackProtectorGuardOffset;
1264+
Val.getAsInteger(10, Offset);
1265+
Opts.StackProtectorGuardOffset = Offset;
1266+
}
1267+
1268+
Opts.StackProtectorGuardReg =
1269+
std::string(Args.getLastArgValue(OPT_mstack_protector_guard_reg_EQ,
1270+
"none"));
1271+
12571272
Opts.StackRealignment = Args.hasArg(OPT_mstackrealign);
12581273
if (Arg *A = Args.getLastArg(OPT_mstack_alignment)) {
12591274
StringRef Val = A->getValue();
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %clang -### -target x86_64-unknown-unknown -mstack-protector-guard=tls %s 2>&1 | \
2+
// RUN: FileCheck -check-prefix=CHECK-TLS %s
3+
// RUN: %clang -### -target x86_64-unknown-unknown -mstack-protector-guard=global %s 2>&1 | \
4+
// RUN: FileCheck -check-prefix=CHECK-GLOBAL %s
5+
// RUN: %clang -### -target x86_64-unknown-unknown -mstack-protector-guard=local %s 2>&1 | \
6+
// RUN: FileCheck -check-prefix=INVALID-VALUE %s
7+
8+
// CHECK-TLS: "-cc1" {{.*}}"-mstack-protector-guard=tls"
9+
// CHECK-GLOBAL: "-cc1" {{.*}}"-mstack-protector-guard=global"
10+
// INVALID-VALUE: error: invalid value 'local' in 'mstack-protector-guard=','valid arguments to '-mstack-protector-guard=' are:tls global'
11+
12+
// RUN: %clang -### -target x86_64-unknown-unknown -mstack-protector-guard-reg=fs %s 2>&1 | \
13+
// RUN: FileCheck -check-prefix=CHECK-FS %s
14+
// RUN: %clang -### -target x86_64-unknown-unknown -mstack-protector-guard-reg=gs %s 2>&1 | \
15+
// RUN: FileCheck -check-prefix=CHECK-GS %s
16+
17+
// Invalid arch
18+
// RUN: not %clang -target arm-eabi-c -mstack-protector-guard=tls %s 2>&1 | \
19+
// RUN: FileCheck -check-prefix=INVALID-ARCH %s
20+
// INVALID-ARCH: unsupported option '-mstack-protector-guard=tls' for target
21+
22+
// RUN: not %clang -target powerpc64le-linux-gnu -mstack-protector-guard-reg=fs %s 2>&1 | \
23+
// RUN: FileCheck -check-prefix=INVALID-ARCH2 %s
24+
// INVALID-ARCH2: unsupported option '-mstack-protector-guard-reg=fs' for target
25+
26+
// RUN: not %clang -target aarch64-linux-gnu -mstack-protector-guard-offset=10 %s 2>&1 | \
27+
// RUN: FileCheck -check-prefix=INVALID-ARCH3 %s
28+
// INVALID-ARCH3: unsupported option '-mstack-protector-guard-offset=10' for target
29+
30+
// Invalid option value
31+
// RUN: not %clang -target x86_64-unknown-unknown -c -mstack-protector-guard-reg=cs %s 2>&1 | \
32+
// RUN: FileCheck -check-prefix=INVALID-REG %s
33+
// RUN: not %clang -target x86_64-unknown-unknown -c -mstack-protector-guard-reg=ds %s 2>&1 | \
34+
// RUN: FileCheck -check-prefix=INVALID-REG %s
35+
36+
// CHECK-FS: "-cc1" {{.*}}"-mstack-protector-guard-reg=fs"
37+
// CHECK-GS: "-cc1" {{.*}}"-mstack-protector-guard-reg=gs"
38+
// INVALID-REG: error: invalid value {{.*}} in 'mstack-protector-guard-reg=','for X86, valid arguments to '-mstack-protector-guard-reg=' are:fs gs'
39+
40+
// RUN: %clang -### -target x86_64-unknown-unknown -mstack-protector-guard-offset=30 %s 2>&1 | \
41+
// RUN: FileCheck -check-prefix=CHECK-OFFSET %s
42+
43+
// CHECK-OFFSET: "-cc1" {{.*}}"-mstack-protector-guard-offset=30"

llvm/include/llvm/CodeGen/CommandFlags.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ bool getIgnoreXCOFFVisibility();
9999

100100
std::string getBBSections();
101101

102+
std::string getStackProtectorGuard();
103+
unsigned getStackProtectorGuardOffset();
104+
std::string getStackProtectorGuardReg();
105+
102106
unsigned getTLSSize();
103107

104108
bool getEmulatedTLS();
@@ -135,6 +139,9 @@ struct RegisterCodeGenFlags {
135139

136140
llvm::BasicBlockSection getBBSectionsMode(llvm::TargetOptions &Options);
137141

142+
llvm::StackProtectorGuards
143+
getStackProtectorGuardMode(llvm::TargetOptions &Options);
144+
138145
/// Common utility function tightly tied to the options listed here. Initializes
139146
/// a TargetOptions object with CodeGen flags and returns it.
140147
/// \p TheTriple is used to determine the default value for options if

llvm/include/llvm/Target/TargetOptions.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ namespace llvm {
7373
None // Do not use Basic Block Sections.
7474
};
7575

76+
enum class StackProtectorGuards {
77+
None,
78+
TLS,
79+
Global
80+
};
81+
7682
enum class EABI {
7783
Unknown,
7884
Default, // Default means not specified
@@ -307,6 +313,16 @@ namespace llvm {
307313
/// Emit XRay Function Index section
308314
unsigned XRayOmitFunctionIndex : 1;
309315

316+
/// Stack protector guard offset to use.
317+
unsigned StackProtectorGuardOffset : 32;
318+
319+
/// Stack protector guard mode to use, e.g. tls, global.
320+
StackProtectorGuards StackProtectorGuard =
321+
StackProtectorGuards::None;
322+
323+
/// Stack protector guard reg to use, e.g. usually fs or gs in X86.
324+
std::string StackProtectorGuardReg = "None";
325+
310326
/// FloatABIType - This setting is set by -float-abi=xxx option is specfied
311327
/// on the command line. This setting may either be Default, Soft, or Hard.
312328
/// Default selects the target's default behavior. Soft selects the ABI for

llvm/lib/CodeGen/CommandFlags.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ CGOPT_EXP(bool, DataSections)
7676
CGOPT_EXP(bool, FunctionSections)
7777
CGOPT(bool, IgnoreXCOFFVisibility)
7878
CGOPT(std::string, BBSections)
79+
CGOPT(std::string, StackProtectorGuard)
80+
CGOPT(unsigned, StackProtectorGuardOffset)
81+
CGOPT(std::string, StackProtectorGuardReg)
7982
CGOPT(unsigned, TLSSize)
8083
CGOPT(bool, EmulatedTLS)
8184
CGOPT(bool, UniqueSectionNames)
@@ -348,6 +351,21 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
348351
cl::init("none"));
349352
CGBINDOPT(BBSections);
350353

354+
static cl::opt<std::string> StackProtectorGuard(
355+
"stack-protector-guard", cl::desc("Stack protector guard mode"),
356+
cl::init("none"));
357+
CGBINDOPT(StackProtectorGuard);
358+
359+
static cl::opt<std::string> StackProtectorGuardReg(
360+
"stack-protector-guard-reg", cl::desc("Stack protector guard register"),
361+
cl::init("none"));
362+
CGBINDOPT(StackProtectorGuardReg);
363+
364+
static cl::opt<unsigned> StackProtectorGuardOffset(
365+
"stack-protector-guard-offset", cl::desc("Stack protector guard offset"),
366+
cl::init((unsigned)-1));
367+
CGBINDOPT(StackProtectorGuardOffset);
368+
351369
static cl::opt<unsigned> TLSSize(
352370
"tls-size", cl::desc("Bit size of immediate TLS offsets"), cl::init(0));
353371
CGBINDOPT(TLSSize);
@@ -459,6 +477,24 @@ codegen::getBBSectionsMode(llvm::TargetOptions &Options) {
459477
}
460478
}
461479

480+
llvm::StackProtectorGuards
481+
codegen::getStackProtectorGuardMode(llvm::TargetOptions &Options) {
482+
if (getStackProtectorGuard() == "tls")
483+
return StackProtectorGuards::TLS;
484+
if (getStackProtectorGuard() == "global")
485+
return StackProtectorGuards::Global;
486+
if (getStackProtectorGuard() != "none") {
487+
ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
488+
MemoryBuffer::getFile(getStackProtectorGuard());
489+
if (!MBOrErr)
490+
errs() << "error illegal stack protector guard mode: "
491+
<< MBOrErr.getError().message() << "\n";
492+
else
493+
Options.BBSectionsFuncListBuf = std::move(*MBOrErr);
494+
}
495+
return StackProtectorGuards::None;
496+
}
497+
462498
// Common utility function tightly tied to the options listed here. Initializes
463499
// a TargetOptions object with CodeGen flags and returns it.
464500
TargetOptions
@@ -493,6 +529,9 @@ codegen::InitTargetOptionsFromCodeGenFlags(const Triple &TheTriple) {
493529
Options.BBSections = getBBSectionsMode(Options);
494530
Options.UniqueSectionNames = getUniqueSectionNames();
495531
Options.UniqueBasicBlockSectionNames = getUniqueBasicBlockSectionNames();
532+
Options.StackProtectorGuard = getStackProtectorGuardMode(Options);
533+
Options.StackProtectorGuardOffset = getStackProtectorGuardOffset();
534+
Options.StackProtectorGuardReg = getStackProtectorGuardReg();
496535
Options.TLSSize = getTLSSize();
497536
Options.EmulatedTLS = getEmulatedTLS();
498537
Options.ExplicitEmulatedTLS = EmulatedTLSView->getNumOccurrences() > 0;

llvm/lib/CodeGen/StackProtector.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,10 @@ bool StackProtector::RequiresStackProtector() {
381381
static Value *getStackGuard(const TargetLoweringBase *TLI, Module *M,
382382
IRBuilder<> &B,
383383
bool *SupportsSelectionDAGSP = nullptr) {
384-
if (Value *Guard = TLI->getIRStackGuard(B))
384+
Value *Guard = TLI->getIRStackGuard(B);
385+
auto GuardMode = TLI->getTargetMachine().Options.StackProtectorGuard;
386+
if ((GuardMode == llvm::StackProtectorGuards::TLS ||
387+
GuardMode == llvm::StackProtectorGuards::None) && Guard)
385388
return B.CreateLoad(B.getInt8PtrTy(), Guard, true, "StackGuard");
386389

387390
// Use SelectionDAG SSP handling, since there isn't an IR guard.

llvm/lib/Target/X86/X86ISelLowering.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2469,13 +2469,23 @@ Value *X86TargetLowering::getIRStackGuard(IRBuilder<> &IRB) const {
24692469
// <zircon/tls.h> defines ZX_TLS_STACK_GUARD_OFFSET with this value.
24702470
return SegmentOffset(IRB, 0x10, getAddressSpace());
24712471
} else {
2472+
unsigned AddressSpace = getAddressSpace();
2473+
// Specially, some users may customize the base reg and offset.
2474+
unsigned Offset = getTargetMachine().Options.StackProtectorGuardOffset;
2475+
// If we don't set -stack-protector-guard-offset value:
24722476
// %fs:0x28, unless we're using a Kernel code model, in which case
24732477
// it's %gs:0x28. gs:0x14 on i386.
2474-
unsigned Offset = (Subtarget.is64Bit()) ? 0x28 : 0x14;
2475-
return SegmentOffset(IRB, Offset, getAddressSpace());
2478+
if (Offset == (unsigned)-1)
2479+
Offset = (Subtarget.is64Bit()) ? 0x28 : 0x14;
2480+
2481+
auto GuardReg = getTargetMachine().Options.StackProtectorGuardReg;
2482+
if (GuardReg == "fs")
2483+
AddressSpace = X86AS::FS;
2484+
else if (GuardReg == "gs")
2485+
AddressSpace = X86AS::GS;
2486+
return SegmentOffset(IRB, Offset, AddressSpace);
24762487
}
24772488
}
2478-
24792489
return TargetLowering::getIRStackGuard(IRB);
24802490
}
24812491

@@ -2497,8 +2507,13 @@ void X86TargetLowering::insertSSPDeclarations(Module &M) const {
24972507
}
24982508
return;
24992509
}
2510+
2511+
auto GuardMode = getTargetMachine().Options.StackProtectorGuard;
2512+
25002513
// glibc, bionic, and Fuchsia have a special slot for the stack guard.
2501-
if (hasStackGuardSlotTLS(Subtarget.getTargetTriple()))
2514+
if ((GuardMode == llvm::StackProtectorGuards::TLS ||
2515+
GuardMode == llvm::StackProtectorGuards::None)
2516+
&& hasStackGuardSlotTLS(Subtarget.getTargetTriple()))
25022517
return;
25032518
TargetLowering::insertSSPDeclarations(M);
25042519
}

0 commit comments

Comments
 (0)