Skip to content

Commit

Permalink
Add support for #pragma clang section
Browse files Browse the repository at this point in the history
This patch provides a means to specify section-names for global variables, 
functions and static variables, using #pragma directives. 
This feature is only defined to work sensibly for ELF targets.
One can specify section names as:
#pragma clang section bss="myBSS" data="myData" rodata="myRodata" text="myText"
One can "unspecify" a section name with empty string e.g.
#pragma clang section bss="" data="" text="" rodata=""

Reviewers: Roger Ferrer, Jonathan Roelofs, Reid Kleckner
Differential Revision: https://reviews.llvm.org/D33412

llvm-svn: 304705
  • Loading branch information
javedabsar committed Jun 5, 2017
1 parent b16d146 commit 2a67c9e
Show file tree
Hide file tree
Showing 13 changed files with 409 additions and 1 deletion.
42 changes: 42 additions & 0 deletions clang/docs/LanguageExtensions.rst
Expand Up @@ -2521,3 +2521,45 @@ whether or not an attribute is supported by the pragma by referring to the
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.
36 changes: 36 additions & 0 deletions clang/include/clang/Basic/Attr.td
Expand Up @@ -1683,6 +1683,42 @@ def Section : InheritableAttr {
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>,
Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Expand Up @@ -887,9 +887,18 @@ def warn_pragma_expected_rparen : Warning<
"missing ')' after '#pragma %0' - ignoring">, InGroup<IgnoredPragmas>;
def warn_pragma_expected_identifier : Warning<
"expected identifier in '#pragma %0' - ignored">, InGroup<IgnoredPragmas>;

// '#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<IgnoredPragmas>;

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<IgnoredPragmas>;
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Parse/Parser.h
Expand Up @@ -166,6 +166,7 @@ class Parser : public CodeCompletionHandler {
std::unique_ptr<PragmaHandler> FPContractHandler;
std::unique_ptr<PragmaHandler> OpenCLExtensionHandler;
std::unique_ptr<PragmaHandler> OpenMPHandler;
std::unique_ptr<PragmaHandler> PCSectionHandler;
std::unique_ptr<PragmaHandler> MSCommentHandler;
std::unique_ptr<PragmaHandler> MSDetectMismatchHandler;
std::unique_ptr<PragmaHandler> MSPointersToMembers;
Expand Down
34 changes: 34 additions & 0 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -336,6 +336,35 @@ class Sema {
/// \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)
Expand Down Expand Up @@ -8117,6 +8146,11 @@ class Sema {
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);
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/CodeGen/CGDecl.cpp
Expand Up @@ -406,6 +406,13 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
if (D.hasAttr<AnnotateAttr>())
CGM.AddGlobalAnnotations(&D, var);

if (auto *SA = D.getAttr<PragmaClangBSSSectionAttr>())
var->addAttribute("bss-section", SA->getName());
if (auto *SA = D.getAttr<PragmaClangDataSectionAttr>())
var->addAttribute("data-section", SA->getName());
if (auto *SA = D.getAttr<PragmaClangRodataSectionAttr>())
var->addAttribute("rodata-section", SA->getName());

if (const SectionAttr *SA = D.getAttr<SectionAttr>())
var->setSection(SA->getName());

Expand Down
30 changes: 29 additions & 1 deletion clang/lib/CodeGen/CodeGenModule.cpp
Expand Up @@ -1026,9 +1026,25 @@ void CodeGenModule::setNonAliasAttributes(const Decl *D,
llvm::GlobalObject *GO) {
SetCommonAttributes(D, GO);

if (D)
if (D) {
if (auto *GV = dyn_cast<llvm::GlobalVariable>(GO)) {
if (auto *SA = D->getAttr<PragmaClangBSSSectionAttr>())
GV->addAttribute("bss-section", SA->getName());
if (auto *SA = D->getAttr<PragmaClangDataSectionAttr>())
GV->addAttribute("data-section", SA->getName());
if (auto *SA = D->getAttr<PragmaClangRodataSectionAttr>())
GV->addAttribute("rodata-section", SA->getName());
}

if (auto *F = dyn_cast<llvm::Function>(GO)) {
if (auto *SA = D->getAttr<PragmaClangTextSectionAttr>())
if (!D->getAttr<SectionAttr>())
F->addFnAttr("implicit-section-name", SA->getName());
}

if (const SectionAttr *SA = D->getAttr<SectionAttr>())
GO->setSection(SA->getName());
}

getTargetCodeGenInfo().setTargetAttributes(D, GO, *this);
}
Expand Down Expand Up @@ -1127,6 +1143,10 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,

setLinkageAndVisibilityForGV(F, FD);

if (FD->getAttr<PragmaClangTextSectionAttr>()) {
F->addFnAttr("implicit-section-name");
}

if (const SectionAttr *SA = FD->getAttr<SectionAttr>())
F->setSection(SA->getName());

Expand Down Expand Up @@ -2828,6 +2848,14 @@ static bool isVarDeclStrongDefinition(const ASTContext &Context,
if (D->hasAttr<SectionAttr>())
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<PragmaClangBSSSectionAttr>() ||
D->hasAttr<PragmaClangDataSectionAttr>() ||
D->hasAttr<PragmaClangRodataSectionAttr>())
return true;

// Thread local vars aren't considered common linkage.
if (D->getTLSKind())
return true;
Expand Down
60 changes: 60 additions & 0 deletions clang/lib/Parse/ParsePragma.cpp
Expand Up @@ -49,6 +49,15 @@ struct PragmaPackHandler : public PragmaHandler {
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,
Expand Down Expand Up @@ -224,6 +233,9 @@ void Parser::initializePragmaHandlers() {
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());
Expand Down Expand Up @@ -323,6 +335,9 @@ void Parser::resetPragmaHandlers() {
MSCommentHandler.reset();
}

PP.RemovePragmaHandler("clang", PCSectionHandler.get());
PCSectionHandler.reset();

if (getLangOpts().MicrosoftExt) {
PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
MSDetectMismatchHandler.reset();
Expand Down Expand Up @@ -1614,6 +1629,51 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP,
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,
Expand Down
30 changes: 30 additions & 0 deletions clang/lib/Sema/SemaAttr.cpp
Expand Up @@ -126,6 +126,36 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
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<Expr *>(alignment);
Expand Down
25 changes: 25 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Expand Up @@ -8651,6 +8651,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setInvalidDecl();
}

// Apply an implicit SectionAttr if '#pragma clang section text' is active
if (PragmaClangTextSection.Valid && D.isFunctionDefinition() &&
!NewFD->hasAttr<SectionAttr>()) {
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<SectionAttr>()) {
Expand Down Expand Up @@ -11175,6 +11183,23 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) {
if (!VD)
return;

// Apply an implicit SectionAttr if '#pragma clang section bss|data|rodata' is active
if (VD->hasGlobalStorage() && VD->isThisDeclarationADefinition() &&
!inTemplateInstantiation() && !VD->hasAttr<SectionAttr>()) {
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<DecompositionDecl>(ThisDecl)) {
for (auto *BD : DD->bindings()) {
FinalizeDeclaration(BD);
Expand Down

0 comments on commit 2a67c9e

Please sign in to comment.