diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3091,6 +3091,8 @@ def err_attribute_section_invalid_for_target : Error< "argument to %select{'code_seg'|'section'}1 attribute is not valid for this target: %0">; +def err_pragma_section_invalid_for_target : Error< + "argument to #pragma section is not valid for this target: %0">; def warn_attribute_section_drectve : Warning< "#pragma %0(\".drectve\") has undefined behavior, " "use #pragma comment(linker, ...) instead">, InGroup; diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -32,6 +32,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/Frontend/OpenMP/OMPGridValues.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/Error.h" #include "llvm/Support/VersionTuple.h" #include #include @@ -1115,15 +1116,15 @@ /// checking on attribute((section("foo"))) specifiers. /// /// In this case, "foo" is passed in to be checked. If the section - /// specifier is invalid, the backend should return a non-empty string - /// that indicates the problem. + /// specifier is invalid, the backend should return an Error that indicates + /// the problem. /// /// This hook is a simple quality of implementation feature to catch errors /// and give good diagnostics in cases when the assembler or code generator /// would otherwise reject the section specifier. /// - virtual std::string isValidSectionSpecifier(StringRef SR) const { - return ""; + virtual llvm::Error isValidSectionSpecifier(StringRef SR) const { + return llvm::Error::success(); } /// Set forced language options. diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -114,7 +114,7 @@ this->MCountName = "\01mcount"; } - std::string isValidSectionSpecifier(StringRef SR) const override { + llvm::Error isValidSectionSpecifier(StringRef SR) const override { // Let MCSectionMachO validate this. StringRef Segment, Section; unsigned TAA, StubSize; diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -301,6 +301,14 @@ return; } + if (llvm::Error E = + Context.getTargetInfo().isValidSectionSpecifier(SecName)) { + Diag(PragmaLoc, diag::err_pragma_section_invalid_for_target) + << toString(std::move(E)); + CSec->Valid = false; + return; + } + if (UnifySection(SecName, SectionFlags, PragmaLoc)) return; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -40,6 +40,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/Assumptions.h" +#include "llvm/Support/Error.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" @@ -3052,10 +3053,10 @@ } bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) { - std::string Error = Context.getTargetInfo().isValidSectionSpecifier(SecName); - if (!Error.empty()) { - Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error - << 1 /*'section'*/; + if (llvm::Error E = + Context.getTargetInfo().isValidSectionSpecifier(SecName)) { + Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) + << toString(std::move(E)) << 1 /*'section'*/; return false; } return true; @@ -3073,10 +3074,9 @@ return; // If the target wants to validate the section specifier, make it happen. - std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(Str); - if (!Error.empty()) { + if (llvm::Error E = S.Context.getTargetInfo().isValidSectionSpecifier(Str)) { S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) - << Error; + << toString(std::move(E)); return; } @@ -3095,11 +3095,10 @@ // `#pragma code_seg("segname")` uses checkSectionName() instead. static bool checkCodeSegName(Sema &S, SourceLocation LiteralLoc, StringRef CodeSegName) { - std::string Error = - S.Context.getTargetInfo().isValidSectionSpecifier(CodeSegName); - if (!Error.empty()) { + if (llvm::Error E = + S.Context.getTargetInfo().isValidSectionSpecifier(CodeSegName)) { S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) - << Error << 0 /*'code-seg'*/; + << toString(std::move(E)) << 0 /*'code-seg'*/; return false; } diff --git a/clang/test/CodeGenCXX/clang-sections.cpp b/clang/test/CodeGenCXX/clang-sections.cpp --- a/clang/test/CodeGenCXX/clang-sections.cpp +++ b/clang/test/CodeGenCXX/clang-sections.cpp @@ -1,11 +1,17 @@ -// RUN: %clang_cc1 -emit-llvm -triple arm-none-eabi -o - %s | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -triple arm-none-eabi -o - %s | FileCheck %s --check-prefixes=CHECK,ELF +// RUN: %clang_cc1 -emit-llvm -triple arm64-apple-ios -o - %s | FileCheck %s --check-prefixes=CHECK,MACHO // Test that global variables, statics and functions are attached section-attributes // as per '#pragma clang section' directives. extern "C" { // test with names for each section +#ifdef __MACH__ +#pragma clang section bss = "__BSS,__mybss1" data = "__DATA,__mydata1" rodata = "__RODATA,__myrodata1" +#pragma clang section text = "__TEXT,__mytext1" +#else #pragma clang section bss="my_bss.1" data="my_data.1" rodata="my_rodata.1" #pragma clang section text="my_text.1" +#endif int a; // my_bss.1 int b = 1; // my_data.1 int c[4]; // my_bss.1 @@ -19,7 +25,11 @@ static int g[2]; // my_bss.1 #pragma clang section bss="" int h; // default - .bss +#ifdef __MACH__ +#pragma clang section data = "" bss = "__BSS,__mybss2" text = "__TEXT,__mytext2" +#else #pragma clang section data="" bss="my_bss.2" text="my_text.2" +#endif int i = 0; // my_bss.2 extern const int j; const int j = 4; // default - .rodata @@ -29,7 +39,11 @@ static int lstat_h; // my_bss.2 return zoo(g, &lstat_h); } +#ifdef __MACH__ +#pragma clang section rodata = "__RODATA,__myrodata2" data = "__DATA,__mydata2" relro = "__RELRO,__myrelro2" +#else #pragma clang section rodata="my_rodata.2" data="my_data.2" relro="my_relro.2" +#endif int l = 5; // my_data.2 extern const int m; const int m = 6; // my_rodata.2 @@ -65,19 +79,26 @@ //CHECK: @n ={{.*}} global i32 0, align 4 //CHECK: @o ={{.*}} global i32 6, align 4 //CHECK: @p ={{.*}} constant i32 7, align 4 -//CHECK: @_ZL5fptrs = internal constant [2 x i32 ()*] [i32 ()* @foo, i32 ()* @goo], align 4 #3 +//CHECK: @_ZL5fptrs = internal constant [2 x i32 ()*] [i32 ()* @foo, i32 ()* @goo], align {{4|8}} #3 //CHECK: define{{.*}} i32 @foo() #5 { //CHECK: define{{.*}} i32 @goo() #6 { //CHECK: declare i32 @zoo(i32*, i32*) #7 //CHECK: define{{.*}} i32 @hoo() #8 { -//CHECK: attributes #0 = { "bss-section"="my_bss.1" "data-section"="my_data.1" "rodata-section"="my_rodata.1" } -//CHECK: attributes #1 = { "data-section"="my_data.1" "rodata-section"="my_rodata.1" } -//CHECK: attributes #2 = { "bss-section"="my_bss.2" "rodata-section"="my_rodata.1" } -//CHECK: attributes #3 = { "bss-section"="my_bss.2" "data-section"="my_data.2" "relro-section"="my_relro.2" "rodata-section"="my_rodata.2" } -//CHECK: attributes #4 = { "relro-section"="my_relro.2" } -//CHECK: attributes #5 = { {{.*"implicit-section-name"="my_text.1".*}} } -//CHECK: attributes #6 = { {{.*"implicit-section-name"="my_text.2".*}} } +//ELF: attributes #0 = { "bss-section"="my_bss.1" "data-section"="my_data.1" "rodata-section"="my_rodata.1" } +//ELF: attributes #1 = { "data-section"="my_data.1" "rodata-section"="my_rodata.1" } +//ELF: attributes #2 = { "bss-section"="my_bss.2" "rodata-section"="my_rodata.1" } +//ELF: attributes #3 = { "bss-section"="my_bss.2" "data-section"="my_data.2" "relro-section"="my_relro.2" "rodata-section"="my_rodata.2" } +//ELF: attributes #4 = { "relro-section"="my_relro.2" } +//ELF: attributes #5 = { {{.*"implicit-section-name"="my_text.1".*}} } +//ELF: attributes #6 = { {{.*"implicit-section-name"="my_text.2".*}} } +//MACHO: attributes #0 = { "bss-section"="__BSS,__mybss1" "data-section"="__DATA,__mydata1" "rodata-section"="__RODATA,__myrodata1" } +//MACHO: attributes #1 = { "data-section"="__DATA,__mydata1" "rodata-section"="__RODATA,__myrodata1" } +//MACHO: attributes #2 = { "bss-section"="__BSS,__mybss2" "rodata-section"="__RODATA,__myrodata1" } +//MACHO: attributes #3 = { "bss-section"="__BSS,__mybss2" "data-section"="__DATA,__mydata2" "relro-section"="__RELRO,__myrelro2" "rodata-section"="__RODATA,__myrodata2" } +//MACHO: attributes #4 = { "relro-section"="__RELRO,__myrelro2" } +//MACHO: attributes #5 = { {{.*"implicit-section-name"="__TEXT,__mytext1".*}} } +//MACHO: attributes #6 = { {{.*"implicit-section-name"="__TEXT,__mytext2".*}} } //CHECK-NOT: attributes #7 = { {{.*"implicit-section-name".*}} } //CHECK-NOT: attributes #8 = { {{.*"implicit-section-name".*}} } diff --git a/clang/test/Sema/pragma-clang-section-macho.c b/clang/test/Sema/pragma-clang-section-macho.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/pragma-clang-section-macho.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -triple arm64-apple-ios + +#pragma clang section bss = "" data = "" rodata = "" text = "" +#pragma clang section bss = "" data = "" rodata = "" text = "__TEXT,__text" +#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}} +#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}} +#pragma clang section + +int a; diff --git a/llvm/include/llvm/MC/MCSectionMachO.h b/llvm/include/llvm/MC/MCSectionMachO.h --- a/llvm/include/llvm/MC/MCSectionMachO.h +++ b/llvm/include/llvm/MC/MCSectionMachO.h @@ -59,14 +59,14 @@ /// appear after a .section directive in a mach-o flavored .s file. If /// successful, this fills in the specified Out parameters and returns an /// empty string. When an invalid section specifier is present, this returns - /// a string indicating the problem. If no TAA was parsed, TAA is not altered, + /// an Error indicating the problem. If no TAA was parsed, TAA is not altered, /// and TAAWasSet becomes false. - static std::string ParseSectionSpecifier(StringRef Spec, // In. - StringRef &Segment, // Out. - StringRef &Section, // Out. - unsigned &TAA, // Out. - bool &TAAParsed, // Out. - unsigned &StubSize); // Out. + static Error ParseSectionSpecifier(StringRef Spec, // In. + StringRef &Segment, // Out. + StringRef &Section, // Out. + unsigned &TAA, // Out. + bool &TAAParsed, // Out. + unsigned &StubSize); // Out. void PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, raw_ostream &OS, diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -1129,13 +1129,12 @@ StringRef Segment, Section; unsigned TAA = 0, StubSize = 0; bool TAAParsed; - std::string ErrorCode = - MCSectionMachO::ParseSectionSpecifier(SectionVal, Segment, Section, - TAA, TAAParsed, StubSize); - if (!ErrorCode.empty()) + if (Error E = MCSectionMachO::ParseSectionSpecifier( + SectionVal, Segment, Section, TAA, TAAParsed, StubSize)) { // If invalid, report the error with report_fatal_error. - report_fatal_error("Invalid section specifier '" + Section + "': " + - ErrorCode + "."); + report_fatal_error("Invalid section specifier '" + Section + + "': " + toString(std::move(E)) + "."); + } // Get the section. MCSectionMachO *S = getContext().getMachOSection( @@ -1159,6 +1158,14 @@ MCSection *TargetLoweringObjectFileMachO::getExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { + + StringRef SectionName = GO->getSection(); + + const Function *F = dyn_cast(GO); + if (F && F->hasFnAttribute("implicit-section-name")) { + SectionName = F->getFnAttribute("implicit-section-name").getValueAsString(); + } + // Parse the section specifier and create it if valid. StringRef Segment, Section; unsigned TAA = 0, StubSize = 0; @@ -1166,14 +1173,12 @@ checkMachOComdat(GO); - std::string ErrorCode = - MCSectionMachO::ParseSectionSpecifier(GO->getSection(), Segment, Section, - TAA, TAAParsed, StubSize); - if (!ErrorCode.empty()) { + if (Error E = MCSectionMachO::ParseSectionSpecifier( + SectionName, Segment, Section, TAA, TAAParsed, StubSize)) { // If invalid, report the error with report_fatal_error. report_fatal_error("Global variable '" + GO->getName() + "' has an invalid section specifier '" + - GO->getSection() + "': " + ErrorCode + "."); + GO->getSection() + "': " + toString(std::move(E)) + "."); } // Get the section. diff --git a/llvm/lib/MC/MCParser/DarwinAsmParser.cpp b/llvm/lib/MC/MCParser/DarwinAsmParser.cpp --- a/llvm/lib/MC/MCParser/DarwinAsmParser.cpp +++ b/llvm/lib/MC/MCParser/DarwinAsmParser.cpp @@ -23,6 +23,7 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/SectionKind.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SMLoc.h" @@ -689,12 +690,9 @@ unsigned StubSize; unsigned TAA; bool TAAParsed; - std::string ErrorStr = - MCSectionMachO::ParseSectionSpecifier(SectionSpec, Segment, Section, - TAA, TAAParsed, StubSize); - - if (!ErrorStr.empty()) - return Error(Loc, ErrorStr); + if (class Error E = MCSectionMachO::ParseSectionSpecifier( + SectionSpec, Segment, Section, TAA, TAAParsed, StubSize)) + return Error(Loc, toString(std::move(E))); // Issue a warning if the target is not powerpc and Section is a *coal* section. Triple TT = getParser().getContext().getObjectFileInfo()->getTargetTriple(); diff --git a/llvm/lib/MC/MCSectionMachO.cpp b/llvm/lib/MC/MCSectionMachO.cpp --- a/llvm/lib/MC/MCSectionMachO.cpp +++ b/llvm/lib/MC/MCSectionMachO.cpp @@ -174,12 +174,12 @@ /// flavored .s file. If successful, this fills in the specified Out /// parameters and returns an empty string. When an invalid section /// specifier is present, this returns a string indicating the problem. -std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. - StringRef &Segment, // Out. - StringRef &Section, // Out. - unsigned &TAA, // Out. - bool &TAAParsed, // Out. - unsigned &StubSize) { // Out. +Error MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. + StringRef &Segment, // Out. + StringRef &Section, // Out. + unsigned &TAA, // Out. + bool &TAAParsed, // Out. + unsigned &StubSize) { // Out. TAAParsed = false; SmallVector SplitSpec; @@ -194,25 +194,23 @@ StringRef Attrs = GetEmptyOrTrim(3); StringRef StubSizeStr = GetEmptyOrTrim(4); - // Verify that the segment is present and not too long. - if (Segment.empty() || Segment.size() > 16) - return "mach-o section specifier requires a segment whose length is " - "between 1 and 16 characters"; - - // Verify that the section is present and not too long. + // Verify that the section is present. if (Section.empty()) - return "mach-o section specifier requires a segment and section " - "separated by a comma"; + return createStringError(inconvertibleErrorCode(), + "mach-o section specifier requires a segment " + "and section separated by a comma"); + // Verify that the section is not too long. if (Section.size() > 16) - return "mach-o section specifier requires a section whose length is " - "between 1 and 16 characters"; + return createStringError(inconvertibleErrorCode(), + "mach-o section specifier requires a section " + "whose length is between 1 and 16 characters"); // If there is no comma after the section, we're done. TAA = 0; StubSize = 0; if (SectionType.empty()) - return ""; + return Error::success(); // Figure out which section type it is. auto TypeDescriptor = @@ -223,7 +221,9 @@ // If we didn't find the section type, reject it. if (TypeDescriptor == std::end(SectionTypeDescriptors)) - return "mach-o section specifier uses an unknown section type"; + return createStringError(inconvertibleErrorCode(), + "mach-o section specifier uses an unknown " + "section type"); // Remember the TypeID. TAA = TypeDescriptor - std::begin(SectionTypeDescriptors); @@ -233,9 +233,10 @@ if (Attrs.empty()) { // S_SYMBOL_STUBS always require a symbol stub size specifier. if (TAA == MachO::S_SYMBOL_STUBS) - return "mach-o section specifier of type 'symbol_stubs' requires a size " - "specifier"; - return ""; + return createStringError(inconvertibleErrorCode(), + "mach-o section specifier of type " + "'symbol_stubs' requires a size specifier"); + return Error::success(); } // The attribute list is a '+' separated list of attributes. @@ -249,7 +250,9 @@ return SectionAttr.trim() == Descriptor.AssemblerName; }); if (AttrDescriptorI == std::end(SectionAttrDescriptors)) - return "mach-o section specifier has invalid attribute"; + return createStringError(inconvertibleErrorCode(), + "mach-o section specifier has invalid " + "attribute"); TAA |= AttrDescriptorI->AttrFlag; } @@ -258,19 +261,24 @@ if (StubSizeStr.empty()) { // S_SYMBOL_STUBS always require a symbol stub size specifier. if (TAA == MachO::S_SYMBOL_STUBS) - return "mach-o section specifier of type 'symbol_stubs' requires a size " - "specifier"; - return ""; + return createStringError(inconvertibleErrorCode(), + "mach-o section specifier of type " + "'symbol_stubs' requires a size specifier"); + return Error::success(); } // If we have a stub size spec, we must have a sectiontype of S_SYMBOL_STUBS. if ((TAA & MachO::SECTION_TYPE) != MachO::S_SYMBOL_STUBS) - return "mach-o section specifier cannot have a stub size specified because " - "it does not have type 'symbol_stubs'"; + return createStringError(inconvertibleErrorCode(), + "mach-o section specifier cannot have a stub " + "size specified because it does not have type " + "'symbol_stubs'"); // Convert the stub size from a string to an integer. if (StubSizeStr.getAsInteger(0, StubSize)) - return "mach-o section specifier has a malformed stub size"; + return createStringError(inconvertibleErrorCode(), + "mach-o section specifier has a malformed " + "stub size"); - return ""; + return Error::success(); } diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -1919,9 +1919,8 @@ StringRef ParsedSegment, ParsedSection; unsigned TAA = 0, StubSize = 0; bool TAAParsed; - std::string ErrorCode = MCSectionMachO::ParseSectionSpecifier( - Section, ParsedSegment, ParsedSection, TAA, TAAParsed, StubSize); - assert(ErrorCode.empty() && "Invalid section specifier."); + cantFail(MCSectionMachO::ParseSectionSpecifier( + Section, ParsedSegment, ParsedSection, TAA, TAAParsed, StubSize)); // Ignore the globals from the __OBJC section. The ObjC runtime assumes // those conform to /usr/lib/objc/runtime.h, so we can't add redzones to diff --git a/llvm/test/CodeGen/AArch64/clang-section-macho.ll b/llvm/test/CodeGen/AArch64/clang-section-macho.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/clang-section-macho.ll @@ -0,0 +1,11 @@ +;RUN: llc -mtriple=arm64-apple-ios %s -o - | FileCheck %s + +define dso_local void @foo() #0 { +entry: + ret void +} + +attributes #0 = { "implicit-section-name"="__TEXT,__mytext" } + +; CHECK: .section __TEXT,__mytext +; CHECK-NEXT: .globl _foo