Index: cfe/trunk/docs/LanguageExtensions.rst =================================================================== --- cfe/trunk/docs/LanguageExtensions.rst +++ cfe/trunk/docs/LanguageExtensions.rst @@ -2521,3 +2521,45 @@ The attributes are applied to all matching declarations individually, even when the attribute is semantically incorrect. The attributes that aren't applied to any declaration are not verified semantically. + +Specifying section names for global objects (#pragma clang section) +=================================================================== + +The ``#pragma clang section`` directive provides a means to assign section-names +to global variables, functions and static variables. + +The section names can be specified as: + +.. code-block:: c++ + + #pragma clang section bss="myBSS" data="myData" rodata="myRodata" text="myText" + +The section names can be reverted back to default name by supplying an empty +string to the section kind, for example: + +.. code-block:: c++ + + #pragma clang section bss="" data="" text="" rodata="" + +The ``#pragma clang section`` directive obeys the following rules: + +* The pragma applies to all global variable, statics and function declarations + from the pragma to the end of the translation unit. + +* The pragma clang section is enabled automatically, without need of any flags. + +* This feature is only defined to work sensibly for ELF targets. + +* If section name is specified through _attribute_((section("myname"))), then + the attribute name gains precedence. + +* Global variables that are initialized to zero will be placed in the named + bss section, if one is present. + +* The ``#pragma clang section`` directive does not does try to infer section-kind + from the name. For example, naming a section "``.bss.mySec``" does NOT mean + it will be a bss section name. + +* The decision about which section-kind applies to each global is taken in the back-end. + Once the section-kind is known, appropriate section name, as specified by the user using + ``#pragma clang section`` directive, is applied to that global. Index: cfe/trunk/include/clang/Basic/Attr.td =================================================================== --- cfe/trunk/include/clang/Basic/Attr.td +++ cfe/trunk/include/clang/Basic/Attr.td @@ -1683,6 +1683,42 @@ let Documentation = [SectionDocs]; } +def PragmaClangBSSSection : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [StringArgument<"Name">]; + let Subjects = SubjectList<[GlobalVar], ErrorDiag, + "ExpectedFunctionMethodOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def PragmaClangDataSection : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [StringArgument<"Name">]; + let Subjects = SubjectList<[GlobalVar], ErrorDiag, + "ExpectedFunctionMethodOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def PragmaClangRodataSection : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [StringArgument<"Name">]; + let Subjects = SubjectList<[GlobalVar], ErrorDiag, + "ExpectedFunctionMethodOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def PragmaClangTextSection : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [StringArgument<"Name">]; + let Subjects = SubjectList<[Function], ErrorDiag, + "ExpectedFunctionMethodOrGlobalVar">; + let Documentation = [Undocumented]; +} + def Sentinel : InheritableAttr { let Spellings = [GCC<"sentinel">]; let Args = [DefaultIntArgument<"Sentinel", 0>, Index: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td @@ -887,9 +887,18 @@ "missing ')' after '#pragma %0' - ignoring">, InGroup; def warn_pragma_expected_identifier : Warning< "expected identifier in '#pragma %0' - ignored">, InGroup; + +// '#pragma clang section' related errors +def err_pragma_expected_clang_section_name : Error< + "expected one of [bss|data|rodata|text] section kind in '#pragma %0'">; +def err_pragma_clang_section_expected_equal : Error< + "expected '=' following '#pragma clang section %select{invalid|bss|data|rodata|text}0'">; +def err_pragma_clang_section_expected_name_or_clear : Error< + "expected section name or '\"\"' following '#pragma clang section %select{invalid|bss|data|rodata|text}0'">; def warn_pragma_expected_section_name : Warning< "expected a string literal for the section name in '#pragma %0' - ignored">, InGroup; + def warn_pragma_expected_section_push_pop_or_name : Warning< "expected push, pop or a string literal for the section name in '#pragma %0' - ignored">, InGroup; Index: cfe/trunk/include/clang/Parse/Parser.h =================================================================== --- cfe/trunk/include/clang/Parse/Parser.h +++ cfe/trunk/include/clang/Parse/Parser.h @@ -166,6 +166,7 @@ std::unique_ptr FPContractHandler; std::unique_ptr OpenCLExtensionHandler; std::unique_ptr OpenMPHandler; + std::unique_ptr PCSectionHandler; std::unique_ptr MSCommentHandler; std::unique_ptr MSDetectMismatchHandler; std::unique_ptr MSPointersToMembers; Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -336,6 +336,35 @@ /// \brief Source location for newly created implicit MSInheritanceAttrs SourceLocation ImplicitMSInheritanceAttrLoc; + /// \brief pragma clang section kind + enum PragmaClangSectionKind { + PCSK_Invalid = 0, + PCSK_BSS = 1, + PCSK_Data = 2, + PCSK_Rodata = 3, + PCSK_Text = 4 + }; + + enum PragmaClangSectionAction { + PCSA_Set = 0, + PCSA_Clear = 1 + }; + + struct PragmaClangSection { + std::string SectionName; + bool Valid = false; + SourceLocation PragmaLocation; + + void Act(SourceLocation PragmaLocation, + PragmaClangSectionAction Action, + StringLiteral* Name); + }; + + PragmaClangSection PragmaClangBSSSection; + PragmaClangSection PragmaClangDataSection; + PragmaClangSection PragmaClangRodataSection; + PragmaClangSection PragmaClangTextSection; + enum PragmaMsStackAction { PSK_Reset = 0x0, // #pragma () PSK_Set = 0x1, // #pragma (value) @@ -8117,6 +8146,11 @@ POAK_Reset // #pragma options align=reset }; + /// ActOnPragmaClangSection - Called on well formed \#pragma clang section + void ActOnPragmaClangSection(SourceLocation PragmaLoc, + PragmaClangSectionAction Action, + PragmaClangSectionKind SecKind, StringRef SecName); + /// ActOnPragmaOptionsAlign - Called on well formed \#pragma options align. void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, SourceLocation PragmaLoc); Index: cfe/trunk/lib/CodeGen/CGDecl.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGDecl.cpp +++ cfe/trunk/lib/CodeGen/CGDecl.cpp @@ -406,6 +406,13 @@ if (D.hasAttr()) CGM.AddGlobalAnnotations(&D, var); + if (auto *SA = D.getAttr()) + var->addAttribute("bss-section", SA->getName()); + if (auto *SA = D.getAttr()) + var->addAttribute("data-section", SA->getName()); + if (auto *SA = D.getAttr()) + var->addAttribute("rodata-section", SA->getName()); + if (const SectionAttr *SA = D.getAttr()) var->setSection(SA->getName()); Index: cfe/trunk/lib/CodeGen/CodeGenModule.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp @@ -1026,9 +1026,25 @@ llvm::GlobalObject *GO) { SetCommonAttributes(D, GO); - if (D) + if (D) { + if (auto *GV = dyn_cast(GO)) { + if (auto *SA = D->getAttr()) + GV->addAttribute("bss-section", SA->getName()); + if (auto *SA = D->getAttr()) + GV->addAttribute("data-section", SA->getName()); + if (auto *SA = D->getAttr()) + GV->addAttribute("rodata-section", SA->getName()); + } + + if (auto *F = dyn_cast(GO)) { + if (auto *SA = D->getAttr()) + if (!D->getAttr()) + F->addFnAttr("implicit-section-name", SA->getName()); + } + if (const SectionAttr *SA = D->getAttr()) GO->setSection(SA->getName()); + } getTargetCodeGenInfo().setTargetAttributes(D, GO, *this); } @@ -1127,6 +1143,10 @@ setLinkageAndVisibilityForGV(F, FD); + if (FD->getAttr()) { + F->addFnAttr("implicit-section-name"); + } + if (const SectionAttr *SA = FD->getAttr()) F->setSection(SA->getName()); @@ -2828,6 +2848,14 @@ if (D->hasAttr()) return true; + // A variable cannot be both common and exist in a section. + // We dont try to determine which is the right section in the front-end. + // If no specialized section name is applicable, it will resort to default. + if (D->hasAttr() || + D->hasAttr() || + D->hasAttr()) + return true; + // Thread local vars aren't considered common linkage. if (D->getTLSKind()) return true; Index: cfe/trunk/lib/Parse/ParsePragma.cpp =================================================================== --- cfe/trunk/lib/Parse/ParsePragma.cpp +++ cfe/trunk/lib/Parse/ParsePragma.cpp @@ -49,6 +49,15 @@ Token &FirstToken) override; }; +struct PragmaClangSectionHandler : public PragmaHandler { + explicit PragmaClangSectionHandler(Sema &S) + : PragmaHandler("section"), Actions(S) {} + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken) override; +private: + Sema &Actions; +}; + struct PragmaMSStructHandler : public PragmaHandler { explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {} void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, @@ -224,6 +233,9 @@ FPContractHandler.reset(new PragmaFPContractHandler()); PP.AddPragmaHandler("STDC", FPContractHandler.get()); + PCSectionHandler.reset(new PragmaClangSectionHandler(Actions)); + PP.AddPragmaHandler("clang", PCSectionHandler.get()); + if (getLangOpts().OpenCL) { OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler()); PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get()); @@ -323,6 +335,9 @@ MSCommentHandler.reset(); } + PP.RemovePragmaHandler("clang", PCSectionHandler.get()); + PCSectionHandler.reset(); + if (getLangOpts().MicrosoftExt) { PP.RemovePragmaHandler(MSDetectMismatchHandler.get()); MSDetectMismatchHandler.reset(); @@ -1614,6 +1629,51 @@ PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); } +// #pragma clang section bss="abc" data="" rodata="def" text="" +void PragmaClangSectionHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, Token &FirstToken) { + + Token Tok; + auto SecKind = Sema::PragmaClangSectionKind::PCSK_Invalid; + + PP.Lex(Tok); // eat 'section' + while (Tok.isNot(tok::eod)) { + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_expected_clang_section_name) << "clang section"; + return; + } + + const IdentifierInfo *SecType = Tok.getIdentifierInfo(); + if (SecType->isStr("bss")) + SecKind = Sema::PragmaClangSectionKind::PCSK_BSS; + else if (SecType->isStr("data")) + SecKind = Sema::PragmaClangSectionKind::PCSK_Data; + else if (SecType->isStr("rodata")) + SecKind = Sema::PragmaClangSectionKind::PCSK_Rodata; + else if (SecType->isStr("text")) + SecKind = Sema::PragmaClangSectionKind::PCSK_Text; + else { + PP.Diag(Tok.getLocation(), diag::err_pragma_expected_clang_section_name) << "clang section"; + return; + } + + PP.Lex(Tok); // eat ['bss'|'data'|'rodata'|'text'] + if (Tok.isNot(tok::equal)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_clang_section_expected_equal) << SecKind; + return; + } + + std::string SecName; + if (!PP.LexStringLiteral(Tok, SecName, "pragma clang section", false)) + return; + + Actions.ActOnPragmaClangSection(Tok.getLocation(), + (SecName.size()? Sema::PragmaClangSectionAction::PCSA_Set : + Sema::PragmaClangSectionAction::PCSA_Clear), + SecKind, SecName); + } +} + // #pragma 'align' '=' {'native','natural','mac68k','power','reset'} // #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'} static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok, Index: cfe/trunk/lib/Sema/SemaAttr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaAttr.cpp +++ cfe/trunk/lib/Sema/SemaAttr.cpp @@ -126,6 +126,36 @@ PackStack.Act(PragmaLoc, Action, StringRef(), Alignment); } +void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionAction Action, + PragmaClangSectionKind SecKind, StringRef SecName) { + PragmaClangSection *CSec; + switch (SecKind) { + case PragmaClangSectionKind::PCSK_BSS: + CSec = &PragmaClangBSSSection; + break; + case PragmaClangSectionKind::PCSK_Data: + CSec = &PragmaClangDataSection; + break; + case PragmaClangSectionKind::PCSK_Rodata: + CSec = &PragmaClangRodataSection; + break; + case PragmaClangSectionKind::PCSK_Text: + CSec = &PragmaClangTextSection; + break; + default: + llvm_unreachable("invalid clang section kind"); + } + + if (Action == PragmaClangSectionAction::PCSA_Clear) { + CSec->Valid = false; + return; + } + + CSec->Valid = true; + CSec->SectionName = SecName; + CSec->PragmaLocation = PragmaLoc; +} + void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, StringRef SlotLabel, Expr *alignment) { Expr *Alignment = static_cast(alignment); Index: cfe/trunk/lib/Sema/SemaDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -8651,6 +8651,14 @@ NewFD->setInvalidDecl(); } + // Apply an implicit SectionAttr if '#pragma clang section text' is active + if (PragmaClangTextSection.Valid && D.isFunctionDefinition() && + !NewFD->hasAttr()) { + NewFD->addAttr(PragmaClangTextSectionAttr::CreateImplicit(Context, + PragmaClangTextSection.SectionName, + PragmaClangTextSection.PragmaLocation)); + } + // Apply an implicit SectionAttr if #pragma code_seg is active. if (CodeSegStack.CurrentValue && D.isFunctionDefinition() && !NewFD->hasAttr()) { @@ -11175,6 +11183,23 @@ if (!VD) return; + // Apply an implicit SectionAttr if '#pragma clang section bss|data|rodata' is active + if (VD->hasGlobalStorage() && VD->isThisDeclarationADefinition() && + !inTemplateInstantiation() && !VD->hasAttr()) { + if (PragmaClangBSSSection.Valid) + VD->addAttr(PragmaClangBSSSectionAttr::CreateImplicit(Context, + PragmaClangBSSSection.SectionName, + PragmaClangBSSSection.PragmaLocation)); + if (PragmaClangDataSection.Valid) + VD->addAttr(PragmaClangDataSectionAttr::CreateImplicit(Context, + PragmaClangDataSection.SectionName, + PragmaClangDataSection.PragmaLocation)); + if (PragmaClangRodataSection.Valid) + VD->addAttr(PragmaClangRodataSectionAttr::CreateImplicit(Context, + PragmaClangRodataSection.SectionName, + PragmaClangRodataSection.PragmaLocation)); + } + if (auto *DD = dyn_cast(ThisDecl)) { for (auto *BD : DD->bindings()) { FinalizeDeclaration(BD); Index: cfe/trunk/test/CodeGenCXX/clang-sections-tentative.c =================================================================== --- cfe/trunk/test/CodeGenCXX/clang-sections-tentative.c +++ cfe/trunk/test/CodeGenCXX/clang-sections-tentative.c @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -x c -emit-llvm -triple arm-none-eabi -o - %s | FileCheck %s + +// Test that section attributes are attached to C tentative definitions as per +// '#pragma clang section' directives. + +#pragma clang section bss = ".bss.1" +int x; // bss.1 + +#pragma clang section bss = "" +int x; // stays in .bss.1 +int y; // not assigned a section attribute +int z; // not assigned a section attribute + +#pragma clang section bss = ".bss.2" +int x; // stays in .bss.1 +int y; // .bss.2 + +// Test the same for `const` declarations. +#pragma clang section rodata = ".rodata.1" +const int cx; // rodata.1 + +#pragma clang section rodata = "" +const int cx; // stays in .rodata.1 +const int cy; // not assigned a section attribute +const int cz; // not assigned a rodata section attribute + +#pragma clang section rodata = ".rodata.2" +const int cx; // stays in .rodata.1 +const int cy; // .rodata.2 + +// CHECK: @x = global i32 0, align 4 #0 +// CHECK: @y = global i32 0, align 4 #1 +// CHECK: @z = common global i32 0, align 4 +// CHECK: @cx = constant i32 0, align 4 #2 +// CHECK: @cy = constant i32 0, align 4 #3 +// CHECK: @cz = constant i32 0, align 4 #1 + +// CHECK: attributes #0 = { "bss-section"=".bss.1" } +// CHECK: attributes #1 = { "bss-section"=".bss.2" } +// CHECK: attributes #2 = { "bss-section"=".bss.2" "rodata-section"=".rodata.1" } +// CHECK: attributes #3 = { "bss-section"=".bss.2" "rodata-section"=".rodata.2" } Index: cfe/trunk/test/CodeGenCXX/clang-sections.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/clang-sections.cpp +++ cfe/trunk/test/CodeGenCXX/clang-sections.cpp @@ -0,0 +1,78 @@ +// RUN: %clang_cc1 -emit-llvm -triple arm-none-eabi -o - %s | FileCheck %s +// 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 +#pragma clang section bss="my_bss.1" data="my_data.1" rodata="my_rodata.1" +#pragma clang section text="my_text.1" +int a; // my_bss.1 +int b = 1; // my_data.1 +int c[4]; // my_bss.1 +short d[5] = {0}; // my_bss.1 +short e[6] = {0, 0, 1}; // my_data.1 +extern const int f; +const int f = 2; // my_rodata.1 +int foo(void) { // my_text.1 + return b; +} +static int g[2]; // my_bss.1 +#pragma clang section bss="" +int h; // default - .bss +#pragma clang section data="" bss="my_bss.2" text="my_text.2" +int i = 0; // my_bss.2 +extern const int j; +const int j = 4; // default - .rodata +int k; // my_bss.2 +extern int zoo(int *x, int *y); +int goo(void) { // my_text.2 + static int lstat_h; // my_bss.2 + return zoo(g, &lstat_h); +} +#pragma clang section rodata="my_rodata.2" data="my_data.2" +int l = 5; // my_data.2 +extern const int m; +const int m = 6; // my_rodata.2 +#pragma clang section rodata="" data="" bss="" text="" +int n; // default +int o = 6; // default +extern const int p; +const int p = 7; // default +int hoo(void) { + return b; +} +} +//CHECK: @a = global i32 0, align 4 #0 +//CHECK: @b = global i32 1, align 4 #0 +//CHECK: @c = global [4 x i32] zeroinitializer, align 4 #0 +//CHECK: @d = global [5 x i16] zeroinitializer, align 2 #0 +//CHECK: @e = global [6 x i16] [i16 0, i16 0, i16 1, i16 0, i16 0, i16 0], align 2 #0 +//CHECK: @f = constant i32 2, align 4 #0 + +//CHECK: @h = global i32 0, align 4 #1 +//CHECK: @i = global i32 0, align 4 #2 +//CHECK: @j = constant i32 4, align 4 #2 +//CHECK: @k = global i32 0, align 4 #2 +//CHECK: @_ZZ3gooE7lstat_h = internal global i32 0, align 4 #2 +//CHECK: @_ZL1g = internal global [2 x i32] zeroinitializer, align 4 #0 + +//CHECK: @l = global i32 5, align 4 #3 +//CHECK: @m = constant i32 6, align 4 #3 + +//CHECK: @n = global i32 0, align 4 +//CHECK: @o = global i32 6, align 4 +//CHECK: @p = constant i32 7, align 4 + +//CHECK: define i32 @foo() #4 { +//CHECK: define i32 @goo() #5 { +//CHECK: declare i32 @zoo(i32*, i32*) #6 +//CHECK: define i32 @hoo() #7 { + +//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" "rodata-section"="my_rodata.2" } +//CHECK: attributes #4 = { {{.*"implicit-section-name"="my_text.1".*}} } +//CHECK: attributes #5 = { {{.*"implicit-section-name"="my_text.2".*}} } +//CHECK-NOT: attributes #6 = { {{.*"implicit-section-name".*}} } +//CHECK-NOT: attributes #7 = { {{.*"implicit-section-name".*}} } Index: cfe/trunk/test/Sema/pragma-clang-section.c =================================================================== --- cfe/trunk/test/Sema/pragma-clang-section.c +++ cfe/trunk/test/Sema/pragma-clang-section.c @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -triple arm-none-eabi +#pragma clang section bss="mybss.1" data="mydata.1" rodata="myrodata.1" text="mytext.1" +#pragma clang section bss="" data="" rodata="" text="" +#pragma clang section + +#pragma clang section dss="mybss.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}} +#pragma clang section deta="mydata.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}} +#pragma clang section rodeta="rodata.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}} +#pragma clang section taxt="text.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}} + +#pragma clang section section bss="mybss.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}} + +#pragma clang section bss "mybss.2" // expected-error {{expected '=' following '#pragma clang section bss'}} +#pragma clang section data "mydata.2" // expected-error {{expected '=' following '#pragma clang section data'}} +#pragma clang section rodata "myrodata.2" // expected-error {{expected '=' following '#pragma clang section rodata'}} +#pragma clang section bss="" data="" rodata="" text="" more //expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}} +int a;