Skip to content

Commit 7f6e331

Browse files
committed
Support #pragma clang section directives on MachO targets
rdar://59560986 Differential Revision: https://reviews.llvm.org/D97233
1 parent ceaedfb commit 7f6e331

File tree

13 files changed

+142
-81
lines changed

13 files changed

+142
-81
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3091,6 +3091,8 @@ def err_only_annotate_after_access_spec : Error<
30913091

30923092
def err_attribute_section_invalid_for_target : Error<
30933093
"argument to %select{'code_seg'|'section'}1 attribute is not valid for this target: %0">;
3094+
def err_pragma_section_invalid_for_target : Error<
3095+
"argument to #pragma section is not valid for this target: %0">;
30943096
def warn_attribute_section_drectve : Warning<
30953097
"#pragma %0(\".drectve\") has undefined behavior, "
30963098
"use #pragma comment(linker, ...) instead">, InGroup<MicrosoftDrectveSection>;

clang/include/clang/Basic/TargetInfo.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "llvm/ADT/Triple.h"
3333
#include "llvm/Frontend/OpenMP/OMPGridValues.h"
3434
#include "llvm/Support/DataTypes.h"
35+
#include "llvm/Support/Error.h"
3536
#include "llvm/Support/VersionTuple.h"
3637
#include <cassert>
3738
#include <string>
@@ -1115,15 +1116,15 @@ class TargetInfo : public virtual TransferrableTargetInfo,
11151116
/// checking on attribute((section("foo"))) specifiers.
11161117
///
11171118
/// In this case, "foo" is passed in to be checked. If the section
1118-
/// specifier is invalid, the backend should return a non-empty string
1119-
/// that indicates the problem.
1119+
/// specifier is invalid, the backend should return an Error that indicates
1120+
/// the problem.
11201121
///
11211122
/// This hook is a simple quality of implementation feature to catch errors
11221123
/// and give good diagnostics in cases when the assembler or code generator
11231124
/// would otherwise reject the section specifier.
11241125
///
1125-
virtual std::string isValidSectionSpecifier(StringRef SR) const {
1126-
return "";
1126+
virtual llvm::Error isValidSectionSpecifier(StringRef SR) const {
1127+
return llvm::Error::success();
11271128
}
11281129

11291130
/// Set forced language options.

clang/lib/Basic/Targets/OSTargets.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class LLVM_LIBRARY_VISIBILITY DarwinTargetInfo : public OSTargetInfo<Target> {
114114
this->MCountName = "\01mcount";
115115
}
116116

117-
std::string isValidSectionSpecifier(StringRef SR) const override {
117+
llvm::Error isValidSectionSpecifier(StringRef SR) const override {
118118
// Let MCSectionMachO validate this.
119119
StringRef Segment, Section;
120120
unsigned TAA, StubSize;

clang/lib/Sema/SemaAttr.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,14 @@ void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionA
301301
return;
302302
}
303303

304+
if (llvm::Error E =
305+
Context.getTargetInfo().isValidSectionSpecifier(SecName)) {
306+
Diag(PragmaLoc, diag::err_pragma_section_invalid_for_target)
307+
<< toString(std::move(E));
308+
CSec->Valid = false;
309+
return;
310+
}
311+
304312
if (UnifySection(SecName, SectionFlags, PragmaLoc))
305313
return;
306314

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "llvm/ADT/STLExtras.h"
4141
#include "llvm/ADT/StringExtras.h"
4242
#include "llvm/IR/Assumptions.h"
43+
#include "llvm/Support/Error.h"
4344
#include "llvm/Support/MathExtras.h"
4445
#include "llvm/Support/raw_ostream.h"
4546

@@ -3052,10 +3053,10 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, const AttributeCommonInfo &CI,
30523053
}
30533054

30543055
bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) {
3055-
std::string Error = Context.getTargetInfo().isValidSectionSpecifier(SecName);
3056-
if (!Error.empty()) {
3057-
Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error
3058-
<< 1 /*'section'*/;
3056+
if (llvm::Error E =
3057+
Context.getTargetInfo().isValidSectionSpecifier(SecName)) {
3058+
Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target)
3059+
<< toString(std::move(E)) << 1 /*'section'*/;
30593060
return false;
30603061
}
30613062
return true;
@@ -3073,10 +3074,9 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
30733074
return;
30743075

30753076
// If the target wants to validate the section specifier, make it happen.
3076-
std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(Str);
3077-
if (!Error.empty()) {
3077+
if (llvm::Error E = S.Context.getTargetInfo().isValidSectionSpecifier(Str)) {
30783078
S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target)
3079-
<< Error;
3079+
<< toString(std::move(E));
30803080
return;
30813081
}
30823082

@@ -3095,11 +3095,10 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
30953095
// `#pragma code_seg("segname")` uses checkSectionName() instead.
30963096
static bool checkCodeSegName(Sema &S, SourceLocation LiteralLoc,
30973097
StringRef CodeSegName) {
3098-
std::string Error =
3099-
S.Context.getTargetInfo().isValidSectionSpecifier(CodeSegName);
3100-
if (!Error.empty()) {
3098+
if (llvm::Error E =
3099+
S.Context.getTargetInfo().isValidSectionSpecifier(CodeSegName)) {
31013100
S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target)
3102-
<< Error << 0 /*'code-seg'*/;
3101+
<< toString(std::move(E)) << 0 /*'code-seg'*/;
31033102
return false;
31043103
}
31053104

clang/test/CodeGenCXX/clang-sections.cpp

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
// RUN: %clang_cc1 -emit-llvm -triple arm-none-eabi -o - %s | FileCheck %s
1+
// RUN: %clang_cc1 -emit-llvm -triple arm-none-eabi -o - %s | FileCheck %s --check-prefixes=CHECK,ELF
2+
// RUN: %clang_cc1 -emit-llvm -triple arm64-apple-ios -o - %s | FileCheck %s --check-prefixes=CHECK,MACHO
23
// Test that global variables, statics and functions are attached section-attributes
34
// as per '#pragma clang section' directives.
45

56
extern "C" {
67
// test with names for each section
8+
#ifdef __MACH__
9+
#pragma clang section bss = "__BSS,__mybss1" data = "__DATA,__mydata1" rodata = "__RODATA,__myrodata1"
10+
#pragma clang section text = "__TEXT,__mytext1"
11+
#else
712
#pragma clang section bss="my_bss.1" data="my_data.1" rodata="my_rodata.1"
813
#pragma clang section text="my_text.1"
14+
#endif
915
int a; // my_bss.1
1016
int b = 1; // my_data.1
1117
int c[4]; // my_bss.1
@@ -19,7 +25,11 @@ int foo(void) { // my_text.1
1925
static int g[2]; // my_bss.1
2026
#pragma clang section bss=""
2127
int h; // default - .bss
28+
#ifdef __MACH__
29+
#pragma clang section data = "" bss = "__BSS,__mybss2" text = "__TEXT,__mytext2"
30+
#else
2231
#pragma clang section data="" bss="my_bss.2" text="my_text.2"
32+
#endif
2333
int i = 0; // my_bss.2
2434
extern const int j;
2535
const int j = 4; // default - .rodata
@@ -29,7 +39,11 @@ int goo(void) { // my_text.2
2939
static int lstat_h; // my_bss.2
3040
return zoo(g, &lstat_h);
3141
}
42+
#ifdef __MACH__
43+
#pragma clang section rodata = "__RODATA,__myrodata2" data = "__DATA,__mydata2" relro = "__RELRO,__myrelro2"
44+
#else
3245
#pragma clang section rodata="my_rodata.2" data="my_data.2" relro="my_relro.2"
46+
#endif
3347
int l = 5; // my_data.2
3448
extern const int m;
3549
const int m = 6; // my_rodata.2
@@ -65,19 +79,26 @@ int hoo(void) {
6579
//CHECK: @n ={{.*}} global i32 0, align 4
6680
//CHECK: @o ={{.*}} global i32 6, align 4
6781
//CHECK: @p ={{.*}} constant i32 7, align 4
68-
//CHECK: @_ZL5fptrs = internal constant [2 x i32 ()*] [i32 ()* @foo, i32 ()* @goo], align 4 #3
82+
//CHECK: @_ZL5fptrs = internal constant [2 x i32 ()*] [i32 ()* @foo, i32 ()* @goo], align {{4|8}} #3
6983

7084
//CHECK: define{{.*}} i32 @foo() #5 {
7185
//CHECK: define{{.*}} i32 @goo() #6 {
7286
//CHECK: declare i32 @zoo(i32*, i32*) #7
7387
//CHECK: define{{.*}} i32 @hoo() #8 {
7488

75-
//CHECK: attributes #0 = { "bss-section"="my_bss.1" "data-section"="my_data.1" "rodata-section"="my_rodata.1" }
76-
//CHECK: attributes #1 = { "data-section"="my_data.1" "rodata-section"="my_rodata.1" }
77-
//CHECK: attributes #2 = { "bss-section"="my_bss.2" "rodata-section"="my_rodata.1" }
78-
//CHECK: attributes #3 = { "bss-section"="my_bss.2" "data-section"="my_data.2" "relro-section"="my_relro.2" "rodata-section"="my_rodata.2" }
79-
//CHECK: attributes #4 = { "relro-section"="my_relro.2" }
80-
//CHECK: attributes #5 = { {{.*"implicit-section-name"="my_text.1".*}} }
81-
//CHECK: attributes #6 = { {{.*"implicit-section-name"="my_text.2".*}} }
89+
//ELF: attributes #0 = { "bss-section"="my_bss.1" "data-section"="my_data.1" "rodata-section"="my_rodata.1" }
90+
//ELF: attributes #1 = { "data-section"="my_data.1" "rodata-section"="my_rodata.1" }
91+
//ELF: attributes #2 = { "bss-section"="my_bss.2" "rodata-section"="my_rodata.1" }
92+
//ELF: attributes #3 = { "bss-section"="my_bss.2" "data-section"="my_data.2" "relro-section"="my_relro.2" "rodata-section"="my_rodata.2" }
93+
//ELF: attributes #4 = { "relro-section"="my_relro.2" }
94+
//ELF: attributes #5 = { {{.*"implicit-section-name"="my_text.1".*}} }
95+
//ELF: attributes #6 = { {{.*"implicit-section-name"="my_text.2".*}} }
96+
//MACHO: attributes #0 = { "bss-section"="__BSS,__mybss1" "data-section"="__DATA,__mydata1" "rodata-section"="__RODATA,__myrodata1" }
97+
//MACHO: attributes #1 = { "data-section"="__DATA,__mydata1" "rodata-section"="__RODATA,__myrodata1" }
98+
//MACHO: attributes #2 = { "bss-section"="__BSS,__mybss2" "rodata-section"="__RODATA,__myrodata1" }
99+
//MACHO: attributes #3 = { "bss-section"="__BSS,__mybss2" "data-section"="__DATA,__mydata2" "relro-section"="__RELRO,__myrelro2" "rodata-section"="__RODATA,__myrodata2" }
100+
//MACHO: attributes #4 = { "relro-section"="__RELRO,__myrelro2" }
101+
//MACHO: attributes #5 = { {{.*"implicit-section-name"="__TEXT,__mytext1".*}} }
102+
//MACHO: attributes #6 = { {{.*"implicit-section-name"="__TEXT,__mytext2".*}} }
82103
//CHECK-NOT: attributes #7 = { {{.*"implicit-section-name".*}} }
83104
//CHECK-NOT: attributes #8 = { {{.*"implicit-section-name".*}} }
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple arm64-apple-ios
2+
3+
#pragma clang section bss = "" data = "" rodata = "" text = ""
4+
#pragma clang section bss = "" data = "" rodata = "" text = "__TEXT,__text"
5+
#pragma clang section bss = "" data = "" rodata = "" text = "badname" // expected-error {{argument to #pragma section is not valid for this target: mach-o section specifier requires a segment and section separated by a comma}}
6+
#pragma clang section bss = "" data = "" rodata = "" text = "__TEXT,__namethatiswaytoolong" // expected-error {{argument to #pragma section is not valid for this target: mach-o section specifier requires a section whose length is between 1 and 16 characters}}
7+
#pragma clang section
8+
9+
int a;

llvm/include/llvm/MC/MCSectionMachO.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,14 @@ class MCSectionMachO final : public MCSection {
5959
/// appear after a .section directive in a mach-o flavored .s file. If
6060
/// successful, this fills in the specified Out parameters and returns an
6161
/// empty string. When an invalid section specifier is present, this returns
62-
/// a string indicating the problem. If no TAA was parsed, TAA is not altered,
62+
/// an Error indicating the problem. If no TAA was parsed, TAA is not altered,
6363
/// and TAAWasSet becomes false.
64-
static std::string ParseSectionSpecifier(StringRef Spec, // In.
65-
StringRef &Segment, // Out.
66-
StringRef &Section, // Out.
67-
unsigned &TAA, // Out.
68-
bool &TAAParsed, // Out.
69-
unsigned &StubSize); // Out.
64+
static Error ParseSectionSpecifier(StringRef Spec, // In.
65+
StringRef &Segment, // Out.
66+
StringRef &Section, // Out.
67+
unsigned &TAA, // Out.
68+
bool &TAAParsed, // Out.
69+
unsigned &StubSize); // Out.
7070

7171
void PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
7272
raw_ostream &OS,

llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,13 +1129,12 @@ void TargetLoweringObjectFileMachO::emitModuleMetadata(MCStreamer &Streamer,
11291129
StringRef Segment, Section;
11301130
unsigned TAA = 0, StubSize = 0;
11311131
bool TAAParsed;
1132-
std::string ErrorCode =
1133-
MCSectionMachO::ParseSectionSpecifier(SectionVal, Segment, Section,
1134-
TAA, TAAParsed, StubSize);
1135-
if (!ErrorCode.empty())
1132+
if (Error E = MCSectionMachO::ParseSectionSpecifier(
1133+
SectionVal, Segment, Section, TAA, TAAParsed, StubSize)) {
11361134
// If invalid, report the error with report_fatal_error.
1137-
report_fatal_error("Invalid section specifier '" + Section + "': " +
1138-
ErrorCode + ".");
1135+
report_fatal_error("Invalid section specifier '" + Section +
1136+
"': " + toString(std::move(E)) + ".");
1137+
}
11391138

11401139
// Get the section.
11411140
MCSectionMachO *S = getContext().getMachOSection(
@@ -1159,21 +1158,27 @@ static void checkMachOComdat(const GlobalValue *GV) {
11591158

11601159
MCSection *TargetLoweringObjectFileMachO::getExplicitSectionGlobal(
11611160
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
1161+
1162+
StringRef SectionName = GO->getSection();
1163+
1164+
const Function *F = dyn_cast<Function>(GO);
1165+
if (F && F->hasFnAttribute("implicit-section-name")) {
1166+
SectionName = F->getFnAttribute("implicit-section-name").getValueAsString();
1167+
}
1168+
11621169
// Parse the section specifier and create it if valid.
11631170
StringRef Segment, Section;
11641171
unsigned TAA = 0, StubSize = 0;
11651172
bool TAAParsed;
11661173

11671174
checkMachOComdat(GO);
11681175

1169-
std::string ErrorCode =
1170-
MCSectionMachO::ParseSectionSpecifier(GO->getSection(), Segment, Section,
1171-
TAA, TAAParsed, StubSize);
1172-
if (!ErrorCode.empty()) {
1176+
if (Error E = MCSectionMachO::ParseSectionSpecifier(
1177+
SectionName, Segment, Section, TAA, TAAParsed, StubSize)) {
11731178
// If invalid, report the error with report_fatal_error.
11741179
report_fatal_error("Global variable '" + GO->getName() +
11751180
"' has an invalid section specifier '" +
1176-
GO->getSection() + "': " + ErrorCode + ".");
1181+
GO->getSection() + "': " + toString(std::move(E)) + ".");
11771182
}
11781183

11791184
// Get the section.

llvm/lib/MC/MCParser/DarwinAsmParser.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/MC/MCStreamer.h"
2424
#include "llvm/MC/MCSymbol.h"
2525
#include "llvm/MC/SectionKind.h"
26+
#include "llvm/Support/Error.h"
2627
#include "llvm/Support/FileSystem.h"
2728
#include "llvm/Support/MemoryBuffer.h"
2829
#include "llvm/Support/SMLoc.h"
@@ -689,12 +690,9 @@ bool DarwinAsmParser::parseDirectiveSection(StringRef, SMLoc) {
689690
unsigned StubSize;
690691
unsigned TAA;
691692
bool TAAParsed;
692-
std::string ErrorStr =
693-
MCSectionMachO::ParseSectionSpecifier(SectionSpec, Segment, Section,
694-
TAA, TAAParsed, StubSize);
695-
696-
if (!ErrorStr.empty())
697-
return Error(Loc, ErrorStr);
693+
if (class Error E = MCSectionMachO::ParseSectionSpecifier(
694+
SectionSpec, Segment, Section, TAA, TAAParsed, StubSize))
695+
return Error(Loc, toString(std::move(E)));
698696

699697
// Issue a warning if the target is not powerpc and Section is a *coal* section.
700698
Triple TT = getParser().getContext().getObjectFileInfo()->getTargetTriple();

0 commit comments

Comments
 (0)