Skip to content

[clang] Implement pragma clang section on COFF targets #112714

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5548,7 +5548,7 @@ The ``#pragma clang section`` directive obeys the following rules:

* The pragma clang section is enabled automatically, without need of any flags.

* This feature is only defined to work sensibly for ELF and Mach-O targets.
* This feature is only defined to work sensibly for ELF, Mach-O and COFF targets.

* If section name is specified through _attribute_((section("myname"))), then
the attribute name gains precedence.
Expand Down
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,8 @@ Windows Support
When `-fms-compatibility-version=18.00` or prior is set on the command line this Microsoft extension is still
allowed as VS2013 and prior allow it.

- Clang now supports the ``#pragma clang section`` directive for COFF targets.

LoongArch Support
^^^^^^^^^^^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions clang/test/Sema/pragma-clang-section.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple arm-none-eabi
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple arm64-windows-msvc
#pragma clang section bss = "mybss.1" data = "mydata.1" rodata = "myrodata.1" text = "mytext.1" // expected-note 2 {{#pragma entered here}}
#pragma clang section bss="" data="" rodata="" text=""
#pragma clang section
Expand Down
54 changes: 23 additions & 31 deletions llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -788,29 +788,35 @@ getGlobalObjectInfo(const GlobalObject *GO, const TargetMachine &TM) {
return {Group, IsComdat, Flags};
}

static MCSection *selectExplicitSectionGlobal(
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM,
MCContext &Ctx, Mangler &Mang, unsigned &NextUniqueID,
bool Retain, bool ForceUnique) {
StringRef SectionName = GO->getSection();

static StringRef handlePragmaClangSection(const GlobalObject *GO,
SectionKind Kind) {
// 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<GlobalVariable>(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("relro-section") && Kind.isReadOnlyWithRel()) {
SectionName = Attrs.getAttribute("relro-section").getValueAsString();
} else if (Attrs.hasAttribute("data-section") && Kind.isData()) {
SectionName = Attrs.getAttribute("data-section").getValueAsString();
}
if (Attrs.hasAttribute("bss-section") && Kind.isBSS())
return Attrs.getAttribute("bss-section").getValueAsString();
else if (Attrs.hasAttribute("rodata-section") && Kind.isReadOnly())
return Attrs.getAttribute("rodata-section").getValueAsString();
else if (Attrs.hasAttribute("relro-section") && Kind.isReadOnlyWithRel())
return Attrs.getAttribute("relro-section").getValueAsString();
else if (Attrs.hasAttribute("data-section") && Kind.isData())
return Attrs.getAttribute("data-section").getValueAsString();
}

return GO->getSection();
}

static MCSection *selectExplicitSectionGlobal(const GlobalObject *GO,
SectionKind Kind,
const TargetMachine &TM,
MCContext &Ctx, Mangler &Mang,
unsigned &NextUniqueID,
bool Retain, bool ForceUnique) {
StringRef SectionName = handlePragmaClangSection(GO, Kind);

// Infer section flags from the section name if we can.
Kind = getELFKindForNamedSection(SectionName, Kind);

Expand Down Expand Up @@ -1291,21 +1297,7 @@ static void checkMachOComdat(const GlobalValue *GV) {
MCSection *TargetLoweringObjectFileMachO::getExplicitSectionGlobal(
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {

StringRef SectionName = GO->getSection();

const GlobalVariable *GV = dyn_cast<GlobalVariable>(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("relro-section") && Kind.isReadOnlyWithRel()) {
SectionName = Attrs.getAttribute("relro-section").getValueAsString();
} else if (Attrs.hasAttribute("data-section") && Kind.isData()) {
SectionName = Attrs.getAttribute("data-section").getValueAsString();
}
}
StringRef SectionName = handlePragmaClangSection(GO, Kind);

// Parse the section specifier and create it if valid.
StringRef Segment, Section;
Expand Down Expand Up @@ -1674,7 +1666,7 @@ static int getSelectionForCOFF(const GlobalValue *GV) {

MCSection *TargetLoweringObjectFileCOFF::getExplicitSectionGlobal(
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
StringRef Name = GO->getSection();
StringRef Name = handlePragmaClangSection(GO, Kind);
if (Name == getInstrProfSectionName(IPSK_covmap, Triple::COFF,
/*AddSegmentInfo=*/false) ||
Name == getInstrProfSectionName(IPSK_covfun, Triple::COFF,
Expand Down
146 changes: 146 additions & 0 deletions llvm/test/CodeGen/X86/clang-section-coff.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
;RUN: llc -mtriple=x86_64-windows-msvc %s -o - | FileCheck %s
;Test that global variables and functions are assigned to correct sections.

@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

declare i32 @zoo(ptr, ptr) #6

; Function Attrs: noinline nounwind
define i32 @hoo() #7 {
; CHECK-LABEL: hoo:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: movl b(%rip), %eax
; CHECK-NEXT: retq
entry:
%0 = load i32, ptr @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 #6 = { "correctly-rounded-divide-sqrt-fp-math"="false" "denormal-fp-math"="preserve-sign,preserve-sign" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="none" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #7 = { noinline nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "denormal-fp-math"="preserve-sign,preserve-sign" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="none" "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" "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_bss.1,"bw"
;CHECK: .globl a # @a
;CHECK: .p2align 2, 0x0
;CHECK: a:
;CHECK: .long 0 # 0x0

;CHECK: .section my_data.1,"dw"
;CHECK: .globl b # @b
;CHECK: .p2align 2, 0x0
;CHECK: b:
;CHECK: .long 1 # 0x1

;CHECK: .section my_bss.1,"bw"
;CHECK: .globl c # @c
;CHECK: .p2align 2, 0x0
;CHECK: c:
;CHECK: .zero 16
;CHECK: .globl d # @d
;CHECK: .p2align 1, 0x0
;CHECK: d:
;CHECK: .zero 10

;CHECK: .section my_data.1,"dw"
;CHECK: .globl e # @e
;CHECK: .p2align 1, 0x0
;CHECK: e:
;CHECK: .short 0 # 0x0
;CHECK: .short 0 # 0x0
;CHECK: .short 1 # 0x1
;CHECK: .short 0 # 0x0
;CHECK: .short 0 # 0x0
;CHECK: .short 0 # 0x0

;CHECK: .section my_rodata.1,"dr"
;CHECK: .globl f # @f
;CHECK: .p2align 2, 0x0
;CHECK: f:
;CHECK: .long 2 # 0x2
;CHECK: .bss
;CHECK: .globl h # @h
;CHECK: .p2align 2, 0x0
;CHECK: h:
;CHECK: .long 0 # 0x0

;CHECK: .section my_bss.2,"bw"
;CHECK: .globl i # @i
;CHECK: .p2align 2, 0x0
;CHECK: i:
;CHECK: .long 0 # 0x0

;CHECK: .section my_rodata.1,"dr"
;CHECK: .globl j # @j
;CHECK: .p2align 2, 0x0
;CHECK: j:
;CHECK: .long 4 # 0x4

;CHECK: .section my_bss.2,"bw"
;CHECK: .globl k # @k
;CHECK: .p2align 2, 0x0
;CHECK: k:
;CHECK: .long 0 # 0x0
;CHECK: .p2align 2, 0x0 # @_ZZ3gooE7lstat_h
;CHECK: _ZZ3gooE7lstat_h:
;CHECK: .long 0 # 0x0

;CHECK: .section my_bss.1,"bw"
;CHECK: .p2align 2, 0x0 # @_ZL1g
;CHECK: _ZL1g:
;CHECK: .zero 8

;CHECK: .section my_data.2,"dw"
;CHECK: .globl l # @l
;CHECK: .p2align 2, 0x0
;CHECK: l:
;CHECK: .long 5 # 0x5

;CHECK: .section my_rodata.2,"dr"
;CHECK: .globl m # @m
;CHECK: .p2align 2, 0x0
;CHECK: m:
;CHECK: .long 6 # 0x6
;CHECK: .bss
;CHECK: .globl n # @n
;CHECK: .p2align 2, 0x0
;CHECK: n:
;CHECK: .long 0 # 0x0
;CHECK: .data
;CHECK: .globl o # @o
;CHECK: .p2align 2, 0x0
;CHECK: o:
;CHECK: .long 6 # 0x6

;CHECK: .section .rdata,"dr"
;CHECK: .globl p # @p
;CHECK: .p2align 2, 0x0
;CHECK: p:
;CHECK: .long 7 # 0x7
Loading