<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/79691>79691</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Itanium ABI DSO ctor dtor codegen control
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          Pawday
      </td>
    </tr>
</table>

<pre>
    # 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


</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsW1tv2zoS_jXKy8CBRfn64AfHSboBsqdF27PA7otASyObpxSpJSnH2Yf97QuSki05ru24OfHiIEEQuxxe5htyLpxhqdZsIRAnQf8m6N9e0dIspZp8oU8pfb6ay_R5EpAIHrQuMejeBt3pAyzpCoEKwDXNC44gM0hkivDEzBK0oYYlIOd_YGKACWYY5ew_1DAp_ATV30HX_yYBubG_rlUbVSYGHgQzsYFgWDVXDQEZMWFgRXlAxkFUEwHgv5sOTUowvN1-98z7iS1bcTcgo26re81Sc0SpmViALCz_4MmdTMiOwgXTBlVnweWc8k5qpNIdK4IONbhmxvcFBk9UGDBLhIRTsYBE5gXjqMBIENIA5swAFc-QUM61bQ3INCDTOE7WNK7mci0gVUVrtrbgAdW6zBHMkuma6SfGOaRM0zlHz4dbaI4JLTVu-cmpKCkHTZ91EE337pVe-gaPpNNZIi8gGM5gobCAgJCaMXJAoptGszbVDp4o0c127_-5lSIgQwMWlR9hpVlPC35aSNEfMqn0iasna3oGB839O40Pz0ipsbEiVLQpZ1RDJtXrue1kvyzZ37cSler1yPYeg7_JJ1xZNVi6M5hTkR4-bd-g8zmCTvblYXbigYHbb5_jR5bhdZLs5eRpiQqbvSCRwlAmGhrwKjsFcEFT5RR9gQIVNQjr0SAe9KxBwHzOnxsm2ur_QTtDxfMTfd6rs1TnviX-9Pj5ZvoYx7qcxw9xU9LRFKzPCHrdA52qycfXScZibagyhZJ1sx1N-vP5dbdhicZFqZf_DrrjgPTVfN2eIcUsTjIayyzTaCActMlVczWSzKDT6JHLlZ22knSv--nz9y-zr3ePbov6ihVW8mQGO-tWw7Zz2m8p29DXUnFPR80quv1W0-022Anif_028Js9C-9Y0Ot-efy-u8i2z214tzrCY4MHjtQNj1Mt4yUVKce9I46ganBdyOLEPRhtqH_khWOicdAcSndMvk8fHmfTx8cDB_vx8R9_h4evQLmWGw09eoxP8WDfoGP9b4fzVf725mWn0S5SNUU3cF-KxPnnqTHK2hsQMlOIIGQpnlhtDVNMOFUILCJOo1owR4VRdo-aH2PgMqE8LoWgOaYxTVMbNkSkxdNeBsonY4OEeuGMCQQmDCpBOawkS4_otDNpdq0INPq5A0KuDa7NtVPxsggIaZpLQxn3G7mZvq0NDqITSYoZCClEyTlQzhYCQkhRYYYKRYKOcTIKHQe9bm02Z05w9XhnQ6ulA9IPIYhuGzz8VMabhVsMOlX0Ym922C69O7KlhU5QvZobhcaJYOsNDhwoEsFX5NRgCnNc0hWzgWGjw8totR1UVKGp8xcKC04TPO4UWq6jGTZcXsN-kwbt-W058iUVC0zByPNvHe_lzZvE8BCRHCJGh4i9Q8T-IeLgEHH4IjB5Azv4Zmaod74ZqrY1mgbRtHkGnNO8gE36qTWKrdLE9dTe-l4AVngEFjkfVnhBWOQIrOh8WOSCsKIjsHrnw4ouCKt3BFb_fFi9C8LqH4E1OB9W_4KwBkdgDc-HNbggrOERWKPzYQ13Yb0manww_v7koj5cG0UTA3Zul1VCmizr_E2Vu-XsB4JZUuMu9OddaPxN5kSP3nZltRMnb-PE24GaF3PDJ4-PifRPgRm-K8zwUjDJu8IkrimCL0oWUlPevjpNQWEuVwg5CseHzOo7z4srj1WM-hJ1ar6fivScMoG_smnQZbL0SnfC3eq8_LszAIWSaZlgvd-zQmEQ3dXCf1U-fk_aPYhmKfIgutvJFgfRLCD3nvQLOfGDqfbN2nb37AFiYtFaN4hmLsF795IB389T9xYK3jKT_gZC2mJhQhukqT3NL-fyXTZ7HZD75nZvNYOmp57dF7mEKuVAtXWTVaUCcM20YWJxLBPR5mC3d2udvQvtW-dExdsundMf6JLkCxS-KKexoMplWQolE0xLhX69RIoqZWC1vd6PtvvUwISrbRhFheau_gmlYAZYVmt7U0n3w92xJnvTOFQh6AITljFMW1vq_t4za5ZlaYrSWO7_DJOya0A-6nlt23VuLW-njvfT6uBPf_5vyoZH7NjPzNdBk_XOUUz0rlFMdKlgrfeuMHtbmO-Ksv-uKPsnbOaOXSUjZiChAuZozU9mr4NWjxVm3LPr7plAc1hIIaizUTZwtP7F2uuhBo4Ln7Fu-fkIPs1mm8LBXzmPHh4tmVtJhNE1uQ795dg9bTqtfNKcZla9XzjybGaRJHueMeyY9NNKHjfV6x0LIJWo3VMix_2JlRUP0k_GDDQvBdv4xkVajRDH_ls_53PJvVOxurAT7nz_3VWKZGkab42s9S-FYTk2Qqm9ojrtfUE9dKzLua9G90abWnWxob6msP_Kwn3QHR_KIFXl7egGrH-rj-s-vsLT-crlyvPVC_dwRdP0gCh8Cf61LId79uL21_fiFZj3yLptKrZsp7tsn38CXivL4yx1D0XPH8mKj2TFR7LiI1nxkaz4SFZ8JCv-mskK99RxScUP-Kcsm4SrdBKl42hMr3ASDruDqD8cDIdXywkmg0E0wqzbTyjpp8PREIf9PiVR1BuN5sn8ik1Il_S6IRmGJOxFw2vsDaM0ouk4TGk0DknQ62JOGb_mfJVfS7W4YlqXOBmOB-PwitM5cu3-4wchAp_AEa3u9G-v1MSO6czLhQ56Xc600dtZDDMcJw-GClbmML15sJcWHza6iKc2TIkURkl-VSo-WRpTuFfV5D4g9wtmluX8OpF5QO5dGdF_dAolrUGyfsByowNy77j9XwAAAP__H2tX9A">