diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -3445,14 +3445,14 @@ .. code-block:: c++ - #pragma clang section bss="myBSS" data="myData" rodata="myRodata" text="myText" + #pragma clang section bss="myBSS" data="myData" rodata="myRodata" relro="myRelro" 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="" + #pragma clang section bss="" data="" text="" rodata="" relro="" The ``#pragma clang section`` directive obeys the following rules: diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2020,6 +2020,14 @@ let Documentation = [Undocumented]; } +def PragmaClangRelroSection : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [StringArgument<"Name">]; + let Subjects = SubjectList<[GlobalVar], ErrorDiag>; + let Documentation = [Undocumented]; +} + def PragmaClangTextSection : InheritableAttr { // This attribute has no spellings as it is only ever created implicitly. let Spellings = []; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -976,9 +976,9 @@ // '#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'">; + "expected one of [bss|data|rodata|text|relro] 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'">; + "expected '=' following '#pragma clang section %select{invalid|bss|data|rodata|text|relro}0'">; def warn_pragma_expected_section_name : Warning< "expected a string literal for the section name in '#pragma %0' - ignored">, InGroup; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -418,7 +418,8 @@ PCSK_BSS = 1, PCSK_Data = 2, PCSK_Rodata = 3, - PCSK_Text = 4 + PCSK_Text = 4, + PCSK_Relro = 5 }; enum PragmaClangSectionAction { @@ -439,6 +440,7 @@ PragmaClangSection PragmaClangBSSSection; PragmaClangSection PragmaClangDataSection; PragmaClangSection PragmaClangRodataSection; + PragmaClangSection PragmaClangRelroSection; PragmaClangSection PragmaClangTextSection; enum PragmaMsStackAction { diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -419,6 +419,8 @@ var->addAttribute("data-section", SA->getName()); if (auto *SA = D.getAttr()) var->addAttribute("rodata-section", SA->getName()); + if (auto *SA = D.getAttr()) + var->addAttribute("relro-section", SA->getName()); if (const SectionAttr *SA = D.getAttr()) var->setSection(SA->getName()); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1717,6 +1717,8 @@ GV->addAttribute("data-section", SA->getName()); if (auto *SA = D->getAttr()) GV->addAttribute("rodata-section", SA->getName()); + if (auto *SA = D->getAttr()) + GV->addAttribute("relro-section", SA->getName()); } if (auto *F = dyn_cast(GO)) { @@ -4118,6 +4120,7 @@ // If no specialized section name is applicable, it will resort to default. if (D->hasAttr() || D->hasAttr() || + D->hasAttr() || D->hasAttr()) return true; diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -1790,7 +1790,7 @@ /*IsReinject=*/false); } -// #pragma clang section bss="abc" data="" rodata="def" text="" +// #pragma clang section bss="abc" data="" rodata="def" text="" relro="" void PragmaClangSectionHandler::HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) { @@ -1812,6 +1812,8 @@ SecKind = Sema::PragmaClangSectionKind::PCSK_Data; else if (SecType->isStr("rodata")) SecKind = Sema::PragmaClangSectionKind::PCSK_Rodata; + else if (SecType->isStr("relro")) + SecKind = Sema::PragmaClangSectionKind::PCSK_Relro; else if (SecType->isStr("text")) SecKind = Sema::PragmaClangSectionKind::PCSK_Text; else { 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 @@ -266,6 +266,9 @@ case PragmaClangSectionKind::PCSK_Rodata: CSec = &PragmaClangRodataSection; break; + case PragmaClangSectionKind::PCSK_Relro: + CSec = &PragmaClangRelroSection; + break; case PragmaClangSectionKind::PCSK_Text: CSec = &PragmaClangTextSection; break; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12657,6 +12657,11 @@ Context, PragmaClangRodataSection.SectionName, PragmaClangRodataSection.PragmaLocation, AttributeCommonInfo::AS_Pragma)); + if (PragmaClangRelroSection.Valid) + VD->addAttr(PragmaClangRelroSectionAttr::CreateImplicit( + Context, PragmaClangRelroSection.SectionName, + PragmaClangRelroSection.PragmaLocation, + AttributeCommonInfo::AS_Pragma)); } if (auto *DD = dyn_cast(ThisDecl)) { 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 @@ -29,17 +29,20 @@ static int lstat_h; // my_bss.2 return zoo(g, &lstat_h); } -#pragma clang section rodata="my_rodata.2" data="my_data.2" +#pragma clang section rodata="my_rodata.2" data="my_data.2" relro="my_relro.2" int l = 5; // my_data.2 extern const int m; const int m = 6; // my_rodata.2 + +typedef int (*fptr_t)(void); +const fptr_t fptrs[2] = {&foo, &goo}; #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; + return b + fptrs[f](); } } //CHECK: @a = global i32 0, align 4 #0 @@ -62,17 +65,19 @@ //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: define i32 @foo() #4 { -//CHECK: define i32 @goo() #5 { -//CHECK: declare i32 @zoo(i32*, i32*) #6 -//CHECK: define i32 @hoo() #7 { +//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" "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: 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".*}} } //CHECK-NOT: attributes #7 = { {{.*"implicit-section-name".*}} } +//CHECK-NOT: attributes #8 = { {{.*"implicit-section-name".*}} } diff --git a/clang/test/Sema/pragma-clang-section.c b/clang/test/Sema/pragma-clang-section.c --- a/clang/test/Sema/pragma-clang-section.c +++ b/clang/test/Sema/pragma-clang-section.c @@ -3,15 +3,17 @@ #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 dss="mybss.2" // expected-error {{expected one of [bss|data|rodata|text|relro] section kind in '#pragma clang section'}} +#pragma clang section deta="mydata.2" // expected-error {{expected one of [bss|data|rodata|text|relro] section kind in '#pragma clang section'}} +#pragma clang section rodeta="rodata.2" // expected-error {{expected one of [bss|data|rodata|text|relro] section kind in '#pragma clang section'}} +#pragma clang section taxt="text.2" // expected-error {{expected one of [bss|data|rodata|text|relro] 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 section bss="mybss.2" // expected-error {{expected one of [bss|data|rodata|text|relro] 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'}} +#pragma clang section text "text.2" // expected-error {{expected '=' following '#pragma clang section text'}} +#pragma clang section relro "relro.2" // expected-error {{expected '=' following '#pragma clang section relro'}} +#pragma clang section bss="" data="" rodata="" text="" more //expected-error {{expected one of [bss|data|rodata|text|relro] section kind in '#pragma clang section'}} int a; diff --git a/llvm/include/llvm/IR/GlobalVariable.h b/llvm/include/llvm/IR/GlobalVariable.h --- a/llvm/include/llvm/IR/GlobalVariable.h +++ b/llvm/include/llvm/IR/GlobalVariable.h @@ -243,6 +243,7 @@ bool hasImplicitSection() const { return getAttributes().hasAttribute("bss-section") || getAttributes().hasAttribute("data-section") || + getAttributes().hasAttribute("relro-section") || getAttributes().hasAttribute("rodata-section"); } 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 @@ -568,6 +568,8 @@ SectionName = Attrs.getAttribute("bss-section").getValueAsString(); } else if (Attrs.hasAttribute("rodata-section") && Kind.isReadOnly()) { SectionName = Attrs.getAttribute("rodata-section").getValueAsString(); + } else if (Attrs.hasAttribute("relro-section") && Kind.isReadOnlyWithRel()) { + SectionName = Attrs.getAttribute("relro-section").getValueAsString(); } else if (Attrs.hasAttribute("data-section") && Kind.isData()) { SectionName = Attrs.getAttribute("data-section").getValueAsString(); } diff --git a/llvm/lib/Target/TargetLoweringObjectFile.cpp b/llvm/lib/Target/TargetLoweringObjectFile.cpp --- a/llvm/lib/Target/TargetLoweringObjectFile.cpp +++ b/llvm/lib/Target/TargetLoweringObjectFile.cpp @@ -253,6 +253,7 @@ auto Attrs = GVar->getAttributes(); if ((Attrs.hasAttribute("bss-section") && Kind.isBSS()) || (Attrs.hasAttribute("data-section") && Kind.isData()) || + (Attrs.hasAttribute("relro-section") && Kind.isReadOnlyWithRel()) || (Attrs.hasAttribute("rodata-section") && Kind.isReadOnly())) { return getExplicitSectionGlobal(GO, Kind, TM); } diff --git a/llvm/test/MC/ELF/section-relro.ll b/llvm/test/MC/ELF/section-relro.ll new file mode 100644 --- /dev/null +++ b/llvm/test/MC/ELF/section-relro.ll @@ -0,0 +1,65 @@ +; Tests that data and relro are correctly placed in sections +; specified by "#pragma clang section" +; RUN: llc -filetype=obj -mtriple x86_64-unknown-linux %s -o - | llvm-readobj -S -t | FileCheck %s + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux" + +@funcs_relro = hidden constant [2 x i32 ()*] [i32 ()* bitcast (i32 (...)* @func1 to i32 ()*), i32 ()* bitcast (i32 (...)* @func2 to i32 ()*)], align 16 #0 +@var_data = hidden global i32 33, align 4 #0 + +declare i32 @func1(...) +declare i32 @func2(...) + +; Function Attrs: noinline nounwind optnone sspstrong uwtable +define hidden i32 @foo(i32 %i) { +entry: + %i.addr = alloca i32, align 4 + store i32 %i, i32* %i.addr, align 4 + %0 = load i32, i32* %i.addr, align 4 + %idxprom = sext i32 %0 to i64 + %arrayidx = getelementptr inbounds [2 x i32 ()*], [2 x i32 ()*]* @funcs_relro, i64 0, i64 %idxprom + %1 = load i32 ()*, i32 ()** %arrayidx, align 8 + %call = call i32 %1() + %2 = load i32, i32* @var_data, align 4 + %add = add nsw i32 %call, %2 + ret i32 %add +} + +attributes #0 = { "data-section"=".my_data" "relro-section"=".my_relro" "rodata-section"=".my_rodata" } + +; CHECK: Section { +; CHECK: Index: +; CHECK: Name: .my_rodata +; CHECK: Type: SHT_PROGBITS (0x1) +; CHECK: Flags [ (0x2) +; CHECK: SHF_ALLOC (0x2) +; CHECK: ] +; CHECK: Size: 16 +; CHECK: } +; CHECK: Section { +; CHECK: Index: +; CHECK: Name: .my_data +; CHECK: Type: SHT_PROGBITS (0x1) +; CHECK: Flags [ (0x3) +; CHECK: SHF_ALLOC (0x2) +; CHECK: SHF_WRITE (0x1) +; CHECK: ] +; CHECK: Size: 4 +; CHECK: } +; CHECK: Symbol { +; CHECK: Name: funcs_relro +; CHECK: Value: 0x0 +; CHECK: Size: 16 +; CHECK: Binding: Global (0x1) +; CHECK: Type: Object (0x1) +; CHECK: Section: .my_rodata +; CHECK: } +; CHECK: Symbol { +; CHECK: Name: var_data +; CHECK: Value: 0x0 +; CHECK: Size: 4 +; CHECK: Binding: Global (0x1) +; CHECK: Type: Object (0x1) +; CHECK: Section: .my_data +; CHECK: }