Skip to content

Commit 12f7ba1

Browse files
Yassine Missoumsivadeilra
authored andcommitted
Implementation of flag /cbstring
1 parent 3e8908c commit 12f7ba1

File tree

8 files changed

+153
-6
lines changed

8 files changed

+153
-6
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ CODEGENOPT(HotPatch, 1, 0, Benign) ///< Supports the Microsoft /HOTPATCH flag an
148148
///< generates a 'patchable-function' attribute.
149149

150150
CODEGENOPT(TlsGuards , 1, 1, Benign) ///< Controls emission of tls guards via -fms-tls-guards
151+
CODEGENOPT(CBString, 1, 0, Benign) ///< Place string literals in .text section (Microsoft /cbstring flag)
151152
CODEGENOPT(JMCInstrument, 1, 0, Benign) ///< Set when -fjmc is enabled.
152153
CODEGENOPT(InstrumentForProfiling , 1, 0, Benign) ///< Set when -pg is enabled.
153154
CODEGENOPT(CallFEntry , 1, 0, Benign) ///< Set when -mfentry is enabled.

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3878,6 +3878,10 @@ def fms_hotpatch : Flag<["-"], "fms-hotpatch">, Group<f_Group>,
38783878
Visibility<[ClangOption, CC1Option, CLOption]>,
38793879
HelpText<"Ensure that all functions can be hotpatched at runtime">,
38803880
MarshallingInfoFlag<CodeGenOpts<"HotPatch">>;
3881+
def fms_cbstring : Flag<["-"], "fms-cbstring">, Group<f_Group>,
3882+
Visibility<[ClangOption, CC1Option, CLOption]>,
3883+
HelpText<"Place string literals in .text section">,
3884+
MarshallingInfoFlag<CodeGenOpts<"CBString">>;
38813885

38823886
// See llvm/lib/CodeGen/WindowsSecureHotPatching.cpp
38833887
def fms_secure_hotpatch_functions_file
@@ -9062,6 +9066,8 @@ def _SLASH_QIntel_jcc_erratum : CLFlag<"QIntel-jcc-erratum">,
90629066
Alias<mbranches_within_32B_boundaries>;
90639067
def _SLASH_arm64EC : CLFlag<"arm64EC">,
90649068
HelpText<"Set build target to arm64ec">;
9069+
def _SLASH_cbstring : CLFlag<"cbstring">, Alias<fms_cbstring>,
9070+
HelpText<"Place string literals in .text section">;
90659071
def : CLFlag<"Qgather-">, Alias<mno_gather>,
90669072
HelpText<"Disable generation of gather instructions in auto-vectorization(x86 only)">;
90679073
def : CLFlag<"Qscatter-">, Alias<mno_scatter>,

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3416,7 +3416,7 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
34163416
}
34173417

34183418
LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) {
3419-
return MakeAddrLValue(CGM.GetAddrOfConstantStringFromLiteral(E),
3419+
return MakeAddrLValue(CGM.GetAddrOfConstantStringFromLiteral(E, ".str", CurFn),
34203420
E->getType(), AlignmentSource::Decl);
34213421
}
34223422

@@ -3448,7 +3448,7 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
34483448
return MakeAddrLValue(C, E->getType(), AlignmentSource::Decl);
34493449
}
34503450
}
3451-
auto C = CGM.GetAddrOfConstantStringFromLiteral(SL, GVName);
3451+
auto C = CGM.GetAddrOfConstantStringFromLiteral(SL, GVName, CurFn);
34523452
return MakeAddrLValue(C, E->getType(), AlignmentSource::Decl);
34533453
}
34543454

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6819,7 +6819,7 @@ CodeGenModule::GetConstantArrayFromStringLiteral(const StringLiteral *E) {
68196819
static llvm::GlobalVariable *
68206820
GenerateStringLiteral(llvm::Constant *C, llvm::GlobalValue::LinkageTypes LT,
68216821
CodeGenModule &CGM, StringRef GlobalName,
6822-
CharUnits Alignment) {
6822+
CharUnits Alignment, llvm::Function *CurrentFunc = nullptr) {
68236823
unsigned AddrSpace = CGM.getContext().getTargetAddressSpace(
68246824
CGM.GetGlobalConstantAddressSpace());
68256825

@@ -6836,14 +6836,31 @@ GenerateStringLiteral(llvm::Constant *C, llvm::GlobalValue::LinkageTypes LT,
68366836
}
68376837
CGM.setDSOLocal(GV);
68386838

6839+
// If /cbstring flag is enabled, place function-local string literals in code
6840+
// sections following MSVC behavior:
6841+
// - Function strings without custom section → .text$s
6842+
// - Function strings with custom section → <section>$s
6843+
// - Global strings → default section (like MSVC's CONST)
6844+
if (CGM.getCodeGenOpts().CBString && CurrentFunc) {
6845+
if (CurrentFunc->hasSection()) {
6846+
// Function has a custom section, append $s to it
6847+
GV->setSection((Twine(CurrentFunc->getSection()) + "$s").str());
6848+
} else {
6849+
// Function has no custom section, use .text$s
6850+
GV->setSection(".text$s");
6851+
}
6852+
}
6853+
// Note: Global strings (CurrentFunc == nullptr) keep default section behavior
6854+
68396855
return GV;
68406856
}
68416857

68426858
/// GetAddrOfConstantStringFromLiteral - Return a pointer to a
68436859
/// constant array for the given string literal.
68446860
ConstantAddress
68456861
CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
6846-
StringRef Name) {
6862+
StringRef Name,
6863+
llvm::Function *CurrentFunc) {
68476864
CharUnits Alignment =
68486865
getContext().getAlignOfGlobalVarInChars(S->getType(), /*VD=*/nullptr);
68496866

@@ -6877,7 +6894,7 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
68776894
GlobalVariableName = Name;
68786895
}
68796896

6880-
auto GV = GenerateStringLiteral(C, LT, *this, GlobalVariableName, Alignment);
6897+
auto GV = GenerateStringLiteral(C, LT, *this, GlobalVariableName, Alignment, CurrentFunc);
68816898

68826899
CGDebugInfo *DI = getModuleDebugInfo();
68836900
if (DI && getCodeGenOpts().hasReducedDebugInfo())

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1174,7 +1174,8 @@ class CodeGenModule : public CodeGenTypeCache {
11741174
/// Return a pointer to a constant array for the given string literal.
11751175
ConstantAddress
11761176
GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
1177-
StringRef Name = ".str");
1177+
StringRef Name = ".str",
1178+
llvm::Function *CurrentFunc = nullptr);
11781179

11791180
/// Return a pointer to a constant array for the given ObjCEncodeExpr node.
11801181
ConstantAddress

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6782,6 +6782,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
67826782
}
67836783

67846784
Args.AddLastArg(CmdArgs, options::OPT_fms_hotpatch);
6785+
Args.AddLastArg(CmdArgs, options::OPT_fms_cbstring);
67856786

67866787
if (Args.hasArg(options::OPT_fms_secure_hotpatch_functions_file))
67876788
Args.AddLastArg(CmdArgs, options::OPT_fms_secure_hotpatch_functions_file);

clang/test/CodeGen/ms-cbstring.c

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Comprehensive test for -fms-cbstring flag functionality
2+
// RUN: %clang_cc1 -emit-llvm -fms-cbstring -fms-extensions %s -o - | FileCheck --check-prefixes=CBSTRING,CHECK %s
3+
// RUN: %clang_cc1 -emit-llvm -fms-extensions %s -o - | FileCheck --check-prefixes=NORMAL,CHECK %s
4+
5+
// Function declarations to avoid needing system headers
6+
int printf(const char* format, ...);
7+
8+
// Helper function declaration
9+
int uses_string(const char*);
10+
11+
// Global scope strings
12+
const char *global_str = "global_test";
13+
static const char *static_global_str = "static_global_test";
14+
15+
// String arrays
16+
const char *array[] = {"array_element1", "array_element2"};
17+
18+
// Function in default text section
19+
void test_function() {
20+
const char *local_str = "local_test";
21+
static const char *static_local_str = "static_local_test";
22+
23+
// Concatenated strings
24+
const char *concat = "concat_" "string_test";
25+
26+
// Use strings to prevent optimization
27+
printf("%s %s %s\n", local_str, static_local_str, concat);
28+
}
29+
30+
// Function with custom code segment
31+
void __declspec(code_seg("other_seg")) in_other_seg(void)
32+
{
33+
uses_string("test_in_other_seg");
34+
}
35+
36+
int main() {
37+
const char *main_str = "main_function_test";
38+
static const char *static_main_str = "static_main_test";
39+
40+
// Use all strings to ensure they appear in IR
41+
printf("%s %s %s %s %s\n", global_str, static_global_str, array[0], array[1], main_str);
42+
printf("%s\n", static_main_str);
43+
test_function();
44+
in_other_seg();
45+
46+
return 0;
47+
}
48+
49+
// Check string constants in order they appear in IR:
50+
// Note: With -fms-cbstring, function strings get section attributes but remain comdats for proper deduplication
51+
// Note: Global strings keep default section behavior (like MSVC's CONST segment)
52+
53+
// Global strings - should keep default section behavior (not go to .text$s)
54+
// NORMAL: constant {{.*}} c"global_test\00"{{.*}}comdat
55+
// CBSTRING: constant {{.*}} c"global_test\00"
56+
// CBSTRING-NOT: section
57+
// CBSTRING-SAME: comdat
58+
59+
// Array elements (global scope) - should keep default section behavior
60+
// NORMAL: constant {{.*}} c"array_element1\00"{{.*}}comdat
61+
// CBSTRING: constant {{.*}} c"array_element1\00"
62+
// CBSTRING-NOT: section
63+
// CBSTRING-SAME: comdat
64+
// NORMAL: constant {{.*}} c"array_element2\00"{{.*}}comdat
65+
// CBSTRING: constant {{.*}} c"array_element2\00"
66+
// CBSTRING-NOT: section
67+
// CBSTRING-SAME: comdat
68+
69+
// Function local strings go to .text$s
70+
// CHECK: constant {{.*}} c"local_test\00"
71+
// CBSTRING-SAME: section ".text$s"
72+
// NORMAL-NOT: section
73+
// CHECK-SAME: comdat
74+
75+
// Static local strings keep default section behavior (like MSVC)
76+
// CHECK: constant {{.*}} c"static_local_test\00"
77+
// CBSTRING-NOT: section
78+
// NORMAL-NOT: section
79+
// CHECK-SAME: comdat
80+
81+
// Concatenated strings in functions go to .text$s
82+
// CHECK: constant {{.*}} c"concat_string_test\00"
83+
// CBSTRING-SAME: section ".text$s"
84+
// NORMAL-NOT: section
85+
// CHECK-SAME: comdat
86+
87+
// Printf format strings also go to .text$s when used in functions
88+
// CBSTRING: section ".text$s"{{.*}}comdat
89+
90+
// Strings in function with custom code segment go to other_seg$s
91+
// CHECK: constant {{.*}} c"test_in_other_seg\00"
92+
// CBSTRING-SAME: section "other_seg$s"
93+
// NORMAL-NOT: section
94+
// CHECK-SAME: comdat
95+
96+
// Main function strings go to .text$s
97+
// CHECK: constant {{.*}} c"main_function_test\00"
98+
// CBSTRING-SAME: section ".text$s"
99+
// NORMAL-NOT: section
100+
// CHECK-SAME: comdat
101+
102+
// Static main function strings keep default section behavior
103+
// NORMAL: constant {{.*}} c"static_main_test\00"{{.*}}comdat
104+
// CBSTRING: constant {{.*}} c"static_main_test\00"
105+
// CBSTRING-NOT: section
106+
// CBSTRING-SAME: comdat
107+
108+
// Static global strings keep default section behavior
109+
// NORMAL: constant {{.*}} c"static_global_test\00"{{.*}}comdat
110+
// CBSTRING: constant {{.*}} c"static_global_test\00"
111+
// CBSTRING-NOT: section
112+
// CBSTRING-SAME: comdat
113+
114+
// Check that functions are defined
115+
// CHECK: define dso_local void @test_function()
116+
// CHECK: define dso_local void @in_other_seg()
117+
// CHECK: define dso_local i32 @main()

clang/test/Driver/cl-options.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@
198198
// Ox: -O3
199199
// Ox: -mframe-pointer=none
200200

201+
// RUN: %clang_cl /cbstring --target=i686-pc-windows-msvc -### -- %s 2>&1 | FileCheck -check-prefix=cbstring %s
202+
// RUN: %clang_cl /cbstring --target=x86_64-pc-windows-msvc -### -- %s 2>&1 | FileCheck -check-prefix=cbstring %s
203+
// cbstring: -fms-cbstring
204+
201205
// RUN: %clang_cl --target=i686-pc-win32 /O2sy- -### -- %s 2>&1 | FileCheck -check-prefix=PR24003 %s
202206
// PR24003: -Os
203207
// PR24003: -mframe-pointer=all

0 commit comments

Comments
 (0)