Issue |
79691
|
Summary |
Itanium ABI DSO ctor dtor codegen control
|
Labels |
new issue
|
Assignees |
|
Reporter |
Pawday
|
# Issue
I have an example of code with static object initialization
```c++
struct Init_t {
Init_t(int val);
~Init_t();
};
Init_t init_0(0);
```
using option ``-fno-register-global-dtors-with-atexit`` i want the clang compiler to not emit any calls to **__cxa_atexit** or **atexit**
I assume this option will disable the calls because compiler manual says:
```sh
clang --help | grep "atexit"
```
```txt
-fno-register-global-dtors-with-atexit
Don't use atexit to register global destructors
-fno-register-global-dtors-with-cxa-atexit
Don't use __cxa_atexit to register global destructors
-fno-use-cxa-atexit
Alias for -fno-register-global-dtors-with-cxa-atexit
-fregister-global-dtors-with-atexit
Use atexit or __cxa_atexit to register global destructors
```
However the command
```sh
clang -S -O3 -fPIC -fno-register-global-dtors-with-atexit DSO_Life.cc
```
where DSO_Life.cc contains:
```c++
struct Init_t {
Init_t(int val);
~Init_t();
};
Init_t init_0(0);
```
will generate x86_64 assembly code with call to **__cxa_atexit** anyway
```asm
_GLOBAL__sub_I_DSO_Life.cc: # @_GLOBAL__sub_I_DSO_Life.cc
.cfi_startproc
# %bb.0:
pushq %rbx
.cfi_def_cfa_offset 16
.cfi_offset %rbx, -16
movq init_0@GOTPCREL(%rip), %rbx
movq %rbx, %rdi
xorl %esi, %esi
callq _ZN6Init_tC1Ei@PLT
movq _ZN6Init_tD1Ev@GOTPCREL(%rip), %rdi
leaq __dso_handle(%rip), %rdx
movq %rbx, %rsi
popq %rbx
.cfi_def_cfa_offset 8
jmp __cxa_atexit@PLT # TAILCALL
```
LLVM IR also contains call to **__cxa_atexit**
```sh
clang -S -emit-llvm -O3 -fPIC -fno-register-global-dtors-with-atexit DSO_Life.cc
```
```llvm
; Function Attrs: nofree nounwind
declare i32 @__cxa_atexit(ptr, ptr, ptr) local_unnamed_addr #2
; Function Attrs: uwtable
define internal void @_GLOBAL__sub_I_DSO_Life.cc() #3 section ".text.startup" {
tail call void @_ZN6Init_tC1Ei(ptr noundef nonnull align 1 dereferenceable(1) @init_0, i32 noundef 0)
%1 = tail call i32 @__cxa_atexit(ptr nonnull @_ZN6Init_tD1Ev, ptr nonnull @init_0, ptr nonnull @__dso_handle) #4
ret void
}
```
# Related behavior
option ``-fno-use-cxa-atexit`` will replace call to **__cxa_atexit** with call to atexit
```sh
clang -S -emit-llvm -O3 -fPIC -fno-register-global-dtors-with-atexit DSO_Life.cc
```
Note: DSO_Life.cc changed to
```c++
struct Init_t {
Init_t(int val);
~Init_t();
};
Init_t init_0(0);
Init_t init_1(0);
Init_t init_2(0);
Init_t init_3(0);
Init_t init_4(0);
Init_t init_5(0);
Init_t init_6(0);
Init_t init_7(0);
```
```llvm
; Function Attrs: uwtable
define internal void @_GLOBAL__sub_I_DSO_Life.cc() #4 section ".text.startup" {
tail call void @Init_t::Init_t(int)(ptr noundef nonnull align 1 dereferenceable(1) @init_0, i32 noundef 0)
%1 = tail call i32 @atexit(ptr nonnull @__dtor_init_0) #3
tail call void @Init_t::Init_t(int)(ptr noundef nonnull align 1 dereferenceable(1) @init_1, i32 noundef 0)
%2 = tail call i32 @atexit(ptr nonnull @__dtor_init_1) #3
tail call void @Init_t::Init_t(int)(ptr noundef nonnull align 1 dereferenceable(1) @init_2, i32 noundef 0)
%3 = tail call i32 @atexit(ptr nonnull @__dtor_init_2) #3
tail call void @Init_t::Init_t(int)(ptr noundef nonnull align 1 dereferenceable(1) @init_3, i32 noundef 0)
%4 = tail call i32 @atexit(ptr nonnull @__dtor_init_3) #3
tail call void @Init_t::Init_t(int)(ptr noundef nonnull align 1 dereferenceable(1) @init_4, i32 noundef 0)
%5 = tail call i32 @atexit(ptr nonnull @__dtor_init_4) #3
tail call void @Init_t::Init_t(int)(ptr noundef nonnull align 1 dereferenceable(1) @init_5, i32 noundef 0)
%6 = tail call i32 @atexit(ptr nonnull @__dtor_init_5) #3
tail call void @Init_t::Init_t(int)(ptr noundef nonnull align 1 dereferenceable(1) @init_6, i32 noundef 0)
%7 = tail call i32 @atexit(ptr nonnull @__dtor_init_6) #3
tail call void @Init_t::Init_t(int)(ptr noundef nonnull align 1 dereferenceable(1) @init_7, i32 noundef 0)
%8 = tail call i32 @atexit(ptr nonnull @__dtor_init_7) #3
ret void
}
```
It also will extract dtor for each global object like that:
```llvm
; Function Attrs: nounwind uwtable
define internal void @__dtor_init_0() #2 section ".text.startup" {
tail call void @Init_t::~Init_t()(ptr @init_0)
ret void
}
; Function Attrs: nounwind uwtable
define internal void @__dtor_init_1() #2 section ".text.startup" {
tail call void @Init_t::~Init_t()(ptr @init_1)
ret void
}
; Function Attrs: nounwind uwtable
define internal void @__dtor_init_2() #2 section ".text.startup" {
tail call void @Init_t::~Init_t()(ptr @init_2)# Proposal
* remove mention of **_cxa_atexit** for ``-fregister-global-dtors-with-atexit`` and ``-fno-register-global-dtors-with-atexit`` options such that
```sh
clang --help | grep "atexit"
```
will produce
<pre>
-fno-register-global-dtors-with-atexit
Don't use atexit <del>or __cxa_atexit</del> to register global destructors
-fno-use-cxa-atexit Don't use __cxa_atexit <del>for calling</del> <ins>to register global</ins> destructors
-fregister-global-dtors-with-atexit
Use atexit <del>or __cxa_atexit</del> to register global destructors <ins>instead of __cxa_atexit</ins>
</pre>
* add ``-fno-register-global-dtors-with-cxa-atexit`` option as alias for existing ``-fno-use-cxa-atexit``
* add ``-fno-use-atexit`` option as alias for existing ``-fno-register-global-dtors-with-atexit``
* make codegen emit separated procedures for construct and destruct global objects in the translation unit if options
``-fno-use-atexit`` and ``-fno-use-cxa-atexit`` are specified
Final output for
```sh
clang --help | grep "atexit"
```
<pre>
-fno-register-global-dtors-with-atexit
Don't use atexit to register global destructors
-fno-register-global-dtors-with-cxa-atexit
Don't use __cxa_atexit to register global destructors
-fno-use-atexit
Alias for -fno-register-global-dtors-with-atexit
-fno-use-cxa-atexit
Alias for -fno-register-global-dtors-with-cxa-atexit
-fregister-global-dtors-with-atexit
Use atexit to register global destructors instead of __cxa_atexit
</pre>
ret void
}
; Function Attrs: nounwind uwtable
define internal void @__dtor_init_3() #2 section ".text.startup" {
tail call void @Init_t::~Init_t()(ptr @init_3)
ret void
}
; Function Attrs: nounwind uwtable
define internal void @__dtor_init_4() #2 section ".text.startup" {
tail call void @Init_t::~Init_t()(ptr @init_4)
ret void
}
; Function Attrs: nounwind uwtable
define internal void @__dtor_init_5() #2 section ".text.startup" {
tail call void @Init_t::~Init_t()(ptr @init_5)
ret void
}
```
(it can be usefull for reflection, i am gonna use that if it's legal)
# GCC behavior
Note: DSO_Life.cc changed to
```c++
struct Init_t {
Init_t(int val);
~Init_t();
};
Init_t init_0(0);
Init_t init_1(1);
```
GCC 13.2.1 also have option ``-fno-use-cxa-atexit``
Command:
```sh
gcc -S -O3 -fPIC -fno-use-cxa-atexit DSO_Life.cc
```
Because GCC does not have -fno-register-global-dtors-with-atexit option
it will produce construction and destruction symbols for all objects in the TU without the calls to runtime procedures
```asm
_GLOBAL__sub_I_DSO_Life.cc:
subq $8, %rsp
movq init_0@GOTPCREL(%rip), %rdi
xorl %esi, %esi
call Init_t::Init_t(int)@PLT ; ctor init_0
movq init_1@GOTPCREL(%rip), %rdi
movl $1, %esi
addq $8, %rsp
jmp Init_t::Init_t(int)@PLT ; ctor init_1
_GLOBAL__sub_D_DSO_Life.cc:
subq $8, %rsp
movq init_1@GOTPCREL(%rip), %rdi
call Init_t::~Init_t()@PLT ; dtor init_1
movq init_0@GOTPCREL(%rip), %rdi
addq $8, %rsp
jmp Init_t::~Init_t()@PLT ; dtor init_0
```
# Proposal
* remove mention of **_cxa_atexit** for ``-fregister-global-dtors-with-atexit`` and ``-fno-register-global-dtors-with-atexit`` options such that
```sh
clang --help | grep "atexit"
```
will produce
<pre>
-fno-register-global-dtors-with-atexit
Don't use atexit <del>or __cxa_atexit</del> to register global destructors
-fno-use-cxa-atexit Don't use __cxa_atexit <del>for calling</del> <ins>to register global</ins> destructors
-fregister-global-dtors-with-atexit
Use atexit <del>or __cxa_atexit</del> to register global destructors <ins>instead of __cxa_atexit</ins>
</pre>
* add ``-fno-register-global-dtors-with-cxa-atexit`` option as alias for existing ``-fno-use-cxa-atexit``
* add ``-fno-use-atexit`` option as alias for existing ``-fno-register-global-dtors-with-atexit``
* make codegen emit separated procedures for construct and destruct global objects in the translation unit if options
``-fno-use-atexit`` and ``-fno-use-cxa-atexit`` are specified
Final output for
```sh
clang --help | grep "atexit"
```
<pre>
-fno-register-global-dtors-with-atexit
Don't use atexit to register global destructors
-fno-register-global-dtors-with-cxa-atexit
Don't use __cxa_atexit to register global destructors
-fno-use-atexit
Alias for -fno-register-global-dtors-with-atexit
-fno-use-cxa-atexit
Alias for -fno-register-global-dtors-with-cxa-atexit
-fregister-global-dtors-with-atexit
Use atexit to register global destructors instead of __cxa_atexit
</pre>
# Thank You
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs