Index: include/llvm/IR/GlobalVariable.h =================================================================== --- include/llvm/IR/GlobalVariable.h +++ include/llvm/IR/GlobalVariable.h @@ -235,6 +235,13 @@ Attrs = A; } + /// Check if section name is present + bool hasImplicitSection() const { + return getAttributes().hasAttribute("bss-section") || + getAttributes().hasAttribute("data-section") || + getAttributes().hasAttribute("rodata-section"); + } + // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Value *V) { return V->getValueID() == Value::GlobalVariableVal; Index: lib/CodeGen/GlobalMerge.cpp =================================================================== --- lib/CodeGen/GlobalMerge.cpp +++ lib/CodeGen/GlobalMerge.cpp @@ -556,7 +556,8 @@ // Grab all non-const globals. for (auto &GV : M.globals()) { // Merge is safe for "normal" internal or external globals only - if (GV.isDeclaration() || GV.isThreadLocal() || GV.hasSection()) + if (GV.isDeclaration() || GV.isThreadLocal() || + GV.hasSection() || GV.hasImplicitSection()) continue; if (!(MergeExternalGlobals && GV.hasExternalLinkage()) && Index: lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -248,6 +248,25 @@ const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { StringRef SectionName = GO->getSection(); + // Check if '#pragma clang section' name is applicable. + // Note that pragma directive overrides -ffunction-section, -fdata-section + // and so section name is exactly as user specified and not uniqued. + const GlobalVariable *GV = dyn_cast(GO); + if (GV && GV->hasImplicitSection()) { + auto Attrs = GV->getAttributes(); + if (Attrs.hasAttribute("bss-section") && Kind.isBSS()) { + SectionName = Attrs.getAttribute("bss-section").getValueAsString(); + } else if (Attrs.hasAttribute("rodata-section") && Kind.isReadOnly()) { + SectionName = Attrs.getAttribute("rodata-section").getValueAsString(); + } else if (Attrs.hasAttribute("data-section") && Kind.isData()) { + SectionName = Attrs.getAttribute("data-section").getValueAsString(); + } + } + const Function *F = dyn_cast(GO); + if (F && F->hasFnAttribute("implicit-section-name")) { + SectionName = F->getFnAttribute("implicit-section-name").getValueAsString(); + } + // Infer section flags from the section name if we can. Kind = getELFKindForNamedSection(SectionName, Kind); Index: lib/Target/TargetLoweringObjectFile.cpp =================================================================== --- lib/Target/TargetLoweringObjectFile.cpp +++ lib/Target/TargetLoweringObjectFile.cpp @@ -240,6 +240,20 @@ if (GO->hasSection()) return getExplicitSectionGlobal(GO, Kind, TM); + if (auto *GVar = dyn_cast(GO)) { + auto Attrs = GVar->getAttributes(); + if ((Attrs.hasAttribute("bss-section") && Kind.isBSS()) || + (Attrs.hasAttribute("data-section") && Kind.isData()) || + (Attrs.hasAttribute("rodata-section") && Kind.isReadOnly())) { + return getExplicitSectionGlobal(GO, Kind, TM); + } + } + + if (auto *F = dyn_cast(GO)) { + if (F->hasFnAttribute("implicit-section-name")) + return getExplicitSectionGlobal(GO, Kind, TM); + } + // Use default section depending on the 'type' of global return SelectSectionForGlobal(GO, Kind, TM); } Index: test/CodeGen/ARM/clang-section.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/clang-section.ll @@ -0,0 +1,140 @@ +;RUN: llc -mtriple=armv7-eabi %s -o - | FileCheck %s +;Test that global variables and functions are assigned to correct sections. + +target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" +target triple = "armv7-arm-none-eabi" + +@a = global i32 0, align 4 #0 +@b = global i32 1, align 4 #0 +@c = global [4 x i32] zeroinitializer, align 4 #0 +@d = global [5 x i16] zeroinitializer, align 2 #0 +@e = global [6 x i16] [i16 0, i16 0, i16 1, i16 0, i16 0, i16 0], align 2 #0 +@f = constant i32 2, align 4 #0 +@h = global i32 0, align 4 #1 +@i = global i32 0, align 4 #2 +@j = constant i32 4, align 4 #2 +@k = global i32 0, align 4 #2 +@_ZZ3gooE7lstat_h = internal global i32 0, align 4 #2 +@_ZL1g = internal global [2 x i32] zeroinitializer, align 4 #0 +@l = global i32 5, align 4 #3 +@m = constant i32 6, align 4 #3 +@n = global i32 0, align 4 +@o = global i32 6, align 4 +@p = constant i32 7, align 4 + +; Function Attrs: noinline nounwind +define i32 @foo() #4 { +entry: + %0 = load i32, i32* @b, align 4 + ret i32 %0 +} + +; Function Attrs: noinline +define i32 @goo() #5 { +entry: + %call = call i32 @zoo(i32* getelementptr inbounds ([2 x i32], [2 x i32]* @_ZL1g, i32 0, i32 0), i32* @_ZZ3gooE7lstat_h) + ret i32 %call +} + +declare i32 @zoo(i32*, i32*) #6 + +; Function Attrs: noinline nounwind +define i32 @hoo() #7 { +entry: + %0 = load i32, i32* @b, align 4 + ret i32 %0 +} + +attributes #0 = { "bss-section"="my_bss.1" "data-section"="my_data.1" "rodata-section"="my_rodata.1" } +attributes #1 = { "data-section"="my_data.1" "rodata-section"="my_rodata.1" } +attributes #2 = { "bss-section"="my_bss.2" "rodata-section"="my_rodata.1" } +attributes #3 = { "bss-section"="my_bss.2" "data-section"="my_data.2" "rodata-section"="my_rodata.2" } +attributes #4 = { noinline nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "denormal-fp-math"="preserve-sign" "disable-tail-calls"="false" "implicit-section-name"="my_text.1" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="true" "no-jump-tables"="false" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a9" "target-features"="+dsp,+fp16,+neon,+vfp3" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #5 = { noinline "correctly-rounded-divide-sqrt-fp-math"="false" "denormal-fp-math"="preserve-sign" "disable-tail-calls"="false" "implicit-section-name"="my_text.2" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="true" "no-jump-tables"="false" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a9" "target-features"="+dsp,+fp16,+neon,+vfp3" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #6 = { "correctly-rounded-divide-sqrt-fp-math"="false" "denormal-fp-math"="preserve-sign" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a9" "target-features"="+dsp,+fp16,+neon,+vfp3" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #7 = { noinline nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "denormal-fp-math"="preserve-sign" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="true" "no-jump-tables"="false" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a9" "target-features"="+dsp,+fp16,+neon,+vfp3" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.module.flags = !{!0, !1, !2, !3} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 1, !"static_rwdata", i32 1} +!2 = !{i32 1, !"enumsize_buildattr", i32 2} +!3 = !{i32 1, !"armlib_unavailable", i32 0} + +;CHECK: .section my_text.1,"ax",%progbits +;CHECK: .type foo,%function +;CHECK: foo: + +;CHECK: .section my_text.2,"ax",%progbits +;CHECK: .type goo,%function +;CHECK: goo: + +;CHECK: .text +;CHECK: .type hoo,%function +;CHECK: hoo: + +;CHECK: .type a,%object +;CHECK: .section my_bss.1,"aw",%nobits +;CHECK: a: + +;CHECK: .type b,%object +;CHECK: .section my_data.1,"aw",%progbits +;CHECK: b: + +;CHECK: .type c,%object +;CHECK: .section my_bss.1,"aw",%nobits +;CHECK: c: + +;CHECK: .type d,%object +;CHECK: d: + +;CHECK: .type e,%object +;CHECK: .section my_data.1,"aw",%progbits +;CHECK: e: + +;CHECK: .type f,%object +;CHECK: .section my_rodata.1,"a",%progbits +;CHECK: f: + +;CHECK: .type h,%object +;CHECK: .bss +;CHECK: h: + +;CHECK: .type i,%object +;CHECK: .section my_bss.2,"aw",%nobits +;CHECK: i: + +;CHECK: .type j,%object +;CHECK: .section my_rodata.1,"a",%progbits +;CHECK: j: + +;CHECK: .type k,%object +;CHECK: .section my_bss.2,"aw",%nobits +;CHECK: k: + +;CHECK: .type _ZZ3gooE7lstat_h,%object @ @_ZZ3gooE7lstat_h +;CHECK: _ZZ3gooE7lstat_h: + +;CHECK: .type _ZL1g,%object +;CHECK: .section my_bss.1,"aw",%nobits +;CHECK: _ZL1g: + +;CHECK: .type l,%object +;CHECK: .section my_data.2,"aw",%progbits +;CHECK: l: + +;CHECK: .type m,%object +;CHECK: .section my_rodata.2,"a",%progbits +;CHECK: m: + +;CHECK: .type n,%object +;CHECK: .bss +;CHECK: n: + +;CHECK: .type o,%object +;CHECK: .data +;CHECK: o: + +;CHECK: .type p,%object +;CHECK: .section .rodata,"a",%progbits +;CHECK: p: Index: test/MC/ELF/clang-section.s =================================================================== --- /dev/null +++ test/MC/ELF/clang-section.s @@ -0,0 +1,399 @@ +// RUN: llvm-mc -filetype=obj -triple arm-eabi %s -o - | llvm-readobj -s -t | FileCheck %s +// Test that global variables and functions are assigned correct section. + .text + .syntax unified + .eabi_attribute 67, "2.09" @ Tag_conformance + .eabi_attribute 6, 1 @ Tag_CPU_arch + .eabi_attribute 8, 1 @ Tag_ARM_ISA_use + .eabi_attribute 17, 1 @ Tag_ABI_PCS_GOT_use + .eabi_attribute 20, 1 @ Tag_ABI_FP_denormal + .eabi_attribute 21, 1 @ Tag_ABI_FP_exceptions + .eabi_attribute 23, 3 @ Tag_ABI_FP_number_model + .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access + .eabi_attribute 24, 1 @ Tag_ABI_align_needed + .eabi_attribute 25, 1 @ Tag_ABI_align_preserved + .eabi_attribute 38, 1 @ Tag_ABI_FP_16bit_format + .eabi_attribute 18, 4 @ Tag_ABI_PCS_wchar_t + .eabi_attribute 26, 2 @ Tag_ABI_enum_size + .eabi_attribute 14, 0 @ Tag_ABI_PCS_R9_use + .section my_text.1,"ax",%progbits + .globl foo + .p2align 2 + .type foo,%function + .code 32 @ @foo +foo: + .fnstart +@ BB#0: @ %entry + ldr r0, .LCPI0_0 + ldr r0, [r0] + mov pc, lr + .p2align 2 +@ BB#1: +.LCPI0_0: + .long b +.Lfunc_end0: + .size foo, .Lfunc_end0-foo + .cantunwind + .fnend + + .section my_text.2,"ax",%progbits + .globl goo + .p2align 2 + .type goo,%function + .code 32 @ @goo +goo: + .fnstart +@ BB#0: @ %entry + .save {r11, lr} + push {r11, lr} + ldr r0, .LCPI1_0 + ldr r1, .LCPI1_1 + bl zoo + pop {r11, lr} + mov pc, lr + .p2align 2 +@ BB#1: +.LCPI1_0: + .long _ZL1g +.LCPI1_1: + .long _ZZ3gooE7lstat_h +.Lfunc_end1: + .size goo, .Lfunc_end1-goo + .cantunwind + .fnend + + .text + .globl hoo + .p2align 2 + .type hoo,%function + .code 32 @ @hoo +hoo: + .fnstart +@ BB#0: @ %entry + ldr r0, .LCPI2_0 + ldr r0, [r0] + mov pc, lr + .p2align 2 +@ BB#1: +.LCPI2_0: + .long b +.Lfunc_end2: + .size hoo, .Lfunc_end2-hoo + .cantunwind + .fnend + + .type a,%object @ @a + .section my_bss.1,"aw",%nobits + .globl a + .p2align 2 +a: + .long 0 @ 0x0 + .size a, 4 + + .type b,%object @ @b + .section my_data.1,"aw",%progbits + .globl b + .p2align 2 +b: + .long 1 @ 0x1 + .size b, 4 + + .type c,%object @ @c + .section my_bss.1,"aw",%nobits + .globl c + .p2align 2 +c: + .zero 16 + .size c, 16 + + .type d,%object @ @d + .globl d + .p2align 1 +d: + .zero 10 + .size d, 10 + + .type e,%object @ @e + .section my_data.1,"aw",%progbits + .globl e + .p2align 1 +e: + .short 0 @ 0x0 + .short 0 @ 0x0 + .short 1 @ 0x1 + .short 0 @ 0x0 + .short 0 @ 0x0 + .short 0 @ 0x0 + .size e, 12 + + .type f,%object @ @f + .section my_rodata.1,"a",%progbits + .globl f + .p2align 2 +f: + .long 2 @ 0x2 + .size f, 4 + + .type h,%object @ @h + .bss + .globl h + .p2align 2 +h: + .long 0 @ 0x0 + .size h, 4 + + .type i,%object @ @i + .section my_bss.2,"aw",%nobits + .globl i + .p2align 2 +i: + .long 0 @ 0x0 + .size i, 4 + + .type j,%object @ @j + .section my_rodata.1,"a",%progbits + .globl j + .p2align 2 +j: + .long 4 @ 0x4 + .size j, 4 + + .type k,%object @ @k + .section my_bss.2,"aw",%nobits + .globl k + .p2align 2 +k: + .long 0 @ 0x0 + .size k, 4 + + .type _ZZ3gooE7lstat_h,%object @ @_ZZ3gooE7lstat_h + .p2align 2 +_ZZ3gooE7lstat_h: + .long 0 @ 0x0 + .size _ZZ3gooE7lstat_h, 4 + + .type _ZL1g,%object @ @_ZL1g + .section my_bss.1,"aw",%nobits + .p2align 2 +_ZL1g: + .zero 8 + .size _ZL1g, 8 + + .type l,%object @ @l + .section my_data.2,"aw",%progbits + .globl l + .p2align 2 +l: + .long 5 @ 0x5 + .size l, 4 + + .type m,%object @ @m + .section my_rodata.2,"a",%progbits + .globl m + .p2align 2 +m: + .long 6 @ 0x6 + .size m, 4 + + .type n,%object @ @n + .bss + .globl n + .p2align 2 +n: + .long 0 @ 0x0 + .size n, 4 + + .type o,%object @ @o + .data + .globl o + .p2align 2 +o: + .long 6 @ 0x6 + .size o, 4 + + .type p,%object @ @p + .section .rodata,"a",%progbits + .globl p + .p2align 2 +p: + .long 7 @ 0x7 + .size p, 4 + + + .ident "clang version 5.0.0 (http://llvm.org/git/clang.git 254242a3ad440307fb451093a429c71ea9a8c888) (http://llvm.org/git/llvm.git 3c8daefbe3d1672ac1dae775b211f881f0063038)" + .section ".note.GNU-stack","",%progbits + .eabi_attribute 30, 1 @ Tag_ABI_optimization_goals + +//CHECK: Section { +//CHECK: Name: .text +//CHECK: Type: SHT_PROGBITS (0x1) +//CHECK: Flags [ (0x6) +//CHECK: SHF_ALLOC (0x2) +//CHECK: SHF_EXECINSTR (0x4) +//CHECK: ] +//CHECK: } +//CHECK: Section { +//CHECK: Name: my_text.1 +//CHECK: Type: SHT_PROGBITS (0x1) +//CHECK: Flags [ (0x6) +//CHECK: SHF_ALLOC (0x2) +//CHECK: SHF_EXECINSTR (0x4) +//CHECK: ] +//CHECK: } +//CHECK: Section { +//CHECK: Name: my_text.2 +//CHECK: Type: SHT_PROGBITS (0x1) +//CHECK: Flags [ (0x6) +//CHECK: SHF_ALLOC (0x2) +//CHECK: SHF_EXECINSTR (0x4) +//CHECK: ] +//CHECK: } +//CHECK: Section { +//CHECK: Name: my_bss.1 +//CHECK: Type: SHT_NOBITS (0x8) +//CHECK: Flags [ (0x3) +//CHECK: SHF_ALLOC (0x2) +//CHECK: SHF_WRITE (0x1) +//CHECK: ] +//CHECK: } +//CHECK: Section { +//CHECK: Name: my_data.1 +//CHECK: Type: SHT_PROGBITS (0x1) +//CHECK: Flags [ (0x3) +//CHECK: SHF_ALLOC (0x2) +//CHECK: SHF_WRITE (0x1) +//CHECK: ] +//CHECK: } +//CHECK: Section { +//CHECK: Name: my_rodata.1 +//CHECK: Type: SHT_PROGBITS (0x1) +//CHECK: Flags [ (0x2) +//CHECK: SHF_ALLOC (0x2) +//CHECK: ] +//CHECK: } +//CHECK: Section { +//CHECK: Name: .bss +//CHECK: Type: SHT_NOBITS (0x8) +//CHECK: Flags [ (0x3) +//CHECK: SHF_ALLOC (0x2) +//CHECK: SHF_WRITE (0x1) +//CHECK: ] +//CHECK: } +//CHECK: Section { +//CHECK: Name: my_bss.2 +//CHECK: Type: SHT_NOBITS (0x8) +//CHECK: Flags [ (0x3) +//CHECK: SHF_ALLOC (0x2) +//CHECK: SHF_WRITE (0x1) +//CHECK: ] +//CHECK: } +//CHECK: Section { +//CHECK: Name: my_data.2 +//CHECK: Type: SHT_PROGBITS (0x1) +//CHECK: Flags [ (0x3) +//CHECK: SHF_ALLOC (0x2) +//CHECK: SHF_WRITE (0x1) +//CHECK: ] +//CHECK: } +//CHECK: Section { +//CHECK: Name: my_rodata.2 +//CHECK: Type: SHT_PROGBITS (0x1) +//CHECK: Flags [ (0x2) +//CHECK: SHF_ALLOC (0x2) +//CHECK: ] +//CHECK: } +//CHECK: Section { +//CHECK: Name: .data +//CHECK: Type: SHT_PROGBITS (0x1) +//CHECK: Flags [ (0x3) +//CHECK: SHF_ALLOC (0x2) +//CHECK: SHF_WRITE (0x1) +//CHECK: ] +//CHECK: } +//CHECK: Section { +//CHECK: Name: .rodata +//CHECK: Type: SHT_PROGBITS (0x1) +//CHECK: Flags [ (0x2) +//CHECK: SHF_ALLOC (0x2) +//CHECK: ] +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: _ZL1g +//CHECK: Section: my_bss.1 (0xE) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: _ZZ3gooE7lstat_h +//CHECK: Section: my_bss.2 (0x12) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: a +//CHECK: Section: my_bss.1 (0xE) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: b +//CHECK: Section: my_data.1 (0xF) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: c +//CHECK: Section: my_bss.1 (0xE) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: d +//CHECK: Section: my_bss.1 (0xE) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: e +//CHECK: Section: my_data.1 (0xF) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: f +//CHECK: Section: my_rodata.1 (0x10) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: foo +//CHECK: Section: my_text.1 (0x4) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: goo +//CHECK: Section: my_text.2 (0x8) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: h +//CHECK: Section: .bss (0x11) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: hoo +//CHECK: Section: .text (0x2) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: i +//CHECK: Section: my_bss.2 (0x12) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: j +//CHECK: Section: my_rodata.1 (0x10) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: k +//CHECK: Section: my_bss.2 (0x12) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: l +//CHECK: Section: my_data.2 (0x13) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: m +//CHECK: Section: my_rodata.2 (0x14) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: n +//CHECK: Section: .bss (0x11) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: o +//CHECK: Section: .data (0x15) +//CHECK: } +//CHECK: Symbol { +//CHECK: Name: p +//CHECK: Section: .rodata (0x16) +//CHECK: }