Bug 118685 - FreeBSD static executables segfault due to libgcc missing crtbeginT.o
Summary: FreeBSD static executables segfault due to libgcc missing crtbeginT.o
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libgcc (show other bugs)
Version: 15.0
: P3 normal
Target Milestone: ---
Assignee: Gerald Pfeifer
URL: https://gcc.gnu.org/pipermail/gcc-pat...
Keywords: patch, wrong-code
Depends on:
Blocks:
 
Reported: 2025-01-28 13:45 UTC by Dimitry Andric
Modified: 2025-02-20 15:17 UTC (History)
7 users (show)

See Also:
Host:
Target: x86_64-portbld-freebsd
Build:
Known to work: 14.2.1, 15.0
Known to fail: 12.4.1, 13.3.1
Last reconfirmed: 2025-02-04 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dimitry Andric 2025-01-28 13:45:38 UTC
On one of the FreeBSD mailing lists, Steve Kargl reported an issue with statically linked executables segfaulting, if they were compiled with gcc 14 [1].

The segfaults were caused by a bad .dtors section in such executables, looking like:

Hex dump of section '.dtors':
  0x004efca8 ffffffff ffffffff                   ........

The function that walks over the dtors section is called __do_global_dtors_aux [2]. It skips over the first element, since it should always be -1, but it expects the array to be terminated by either a -1 or a 0 value. Because the section is too short, it overruns into whatever section follows, usually resulting in a segfault.

Further investigation shows that the cause for the strange .dtors section is that gcc with the -static option attempts to link crtbeginT.o and crtend.o:

$ gcc -v -static helloworld.c -o helloworld
...
/usr/local/libexec/gcc14/gcc/x86_64-portbld-freebsd15.0/14.2.0/collect2 \
  -plugin /usr/local/libexec/gcc14/gcc/x86_64-portbld-freebsd15.0/14.2.0/liblto_plugin.so \
  -plugin-opt=/usr/local/libexec/gcc14/gcc/x86_64-portbld-freebsd15.0/14.2.0/lto-wrapper \
  -plugin-opt=-fresolution=/tmp/ccRgJPpe.res \
  -plugin-opt=-pass-through=-lgcc \
  -plugin-opt=-pass-through=-lgcc_eh \
  -plugin-opt=-pass-through=-lc \
  -plugin-opt=-pass-through=-lgcc \
  -plugin-opt=-pass-through=-lgcc_eh \
  -m elf_x86_64_fbsd \
  -V \
  -Bstatic \
  -o helloworld \
  /usr/lib/crt1.o \
  /usr/lib/crti.o \
  /usr/local/lib/gcc14/gcc/x86_64-portbld-freebsd15.0/14.2.0/crtbeginT.o \
  -L/usr/local/lib/gcc14/gcc/x86_64-portbld-freebsd15.0/14.2.0 \
  -L/usr/local/lib/gcc14/gcc/x86_64-portbld-freebsd15.0/14.2.0/../../../../../x86_64-portbld-freebsd15.0/lib \
  -L/usr/local/lib/gcc14/gcc/x86_64-portbld-freebsd15.0/14.2.0/../../.. \
  /tmp/ccEhqbzH.o \
  -lgcc \
  -lgcc_eh \
  -lc \
  -lgcc \
  -lgcc_eh \
  /usr/local/lib/gcc14/gcc/x86_64-portbld-freebsd15.0/14.2.0/crtend.o \
  /usr/lib/crtn.o

Because the gcc port does not contain a crtbeginT.o file, it finds the corresponding file in /usr/lib instead, thus "mixing" the base system crtbeginT.o with the gcc-provided crtend.o.

The base system crtbeginT.o contains the first part of the .dtors section:

static crt_func __DTOR_LIST__[] __section(".dtors") __used = {
        (crt_func)-1
};

and normally the base system's crtend.o contains the last part:

static crt_func __DTOR_END__[] __section(".dtors") __used = {
        (crt_func)0
};

However, the gcc-provided crtend.o does _not_ contain any .dtors section, since gcc's configure script detects support for .preinit_array/.init_array/.fini_array, and thus defines HAVE_INITFINI_ARRAY_SUPPORT.

Therefore, the final .dtors section in a static executable only contains the first part, which results in the segfault.

Note that dynamic executables never see this issue, because then gcc will use its _own_ crtbeginS.o and crtendS.so: there will be no .ctors or .dtors sections in the executable, but .init and .fini sections.

As to fixing the problem, on the FreeBSD side we are going to implement seatbelts in the code that walks over the .ctors and .dtors tables, ensuring that they will not overrun the actual section boundaries. But this is really only a workaround.

On the gcc side, we would like to suggest adding crtbeginT.o to the libgcc-provided crt objects, so it will prefer that one over the base system's version. In that case, static executables will also end up without any .ctors/dtors sections, and segfaults will be avoided. (Alternatively, gcc could stop providing crt startup objects completely, and rely on the base system ones, but that is a lot more drastic.)

I will submit a patch to gcc-patches@ for this.

[1] https://lists.freebsd.org/archives/freebsd-hackers/2025-January/004236.html
[2] https://cgit.freebsd.org/src/tree/lib/csu/common/crtbegin.c#n69
Comment 2 kargls 2025-01-28 19:56:25 UTC
I can confirm that Dimitry's patch fixes gcc 15.0 (aka top-of-tree).

This is likely going to need a global maintainer to approval the patch.
I'm not sure if there is an active FreeBSD maintainer, so will need
someone to commit the patch as well.
Comment 3 Eric Gallager 2025-01-29 11:34:29 UTC
(In reply to kargls from comment #2)
> I can confirm that Dimitry's patch fixes gcc 15.0 (aka top-of-tree).
> 
> This is likely going to need a global maintainer to approval the patch.
> I'm not sure if there is an active FreeBSD maintainer, so will need
> someone to commit the patch as well.

Gerald Pfeifer sometimes commits FreeBSD-related patches; maybe he could do so here as well?
Comment 4 Gerald Pfeifer 2025-02-04 03:52:04 UTC
Note that with @Andreas Tobler we have a formal GCC on FreeBSD maintainer
who I am looping in, though I understand he hasn't had much time as of 
lately.

So unless I hear otherwise, and given dim@'s expertise and track record,
I plan to commit this to head and the last release branch at least.

Should this go back to all active release branches?
Comment 5 kargls 2025-02-04 04:50:24 UTC
On 2/3/25 19:52, gerald at pfeifer dot com wrote:
> 
> --- Comment #4 from Gerald Pfeifer <gerald at pfeifer dot com> ---
> Note that with @Andreas Tobler we have a formal GCC on FreeBSD maintainer
> who I am looping in, though I understand he hasn't had much time as of
> lately.
> 
> So unless I hear otherwise, and given dim@'s expertise and track record,
> I plan to commit this to head and the last release branch at least.
> 
> Should this go back to all active release branches?
> 

I know the patch fixes head and 14 branch.  I haven't
tested any older branches.
Comment 6 Lorenzo Salvadore 2025-02-04 07:51:13 UTC
I have tested latest GCC 12 and GCC 13 snapshots: they are affected by this bug too.
Comment 7 GCC Commits 2025-02-08 16:37:06 UTC
The trunk branch has been updated by Gerald Pfeifer <gerald@gcc.gnu.org>:

https://gcc.gnu.org/g:06e5b0b4a244090abfea333d91fc5963292cb41d

commit r15-7444-g06e5b0b4a244090abfea333d91fc5963292cb41d
Author: Dimitry Andric <dimitry@andric.com>
Date:   Tue Jan 28 18:36:16 2025 +0100

    libgcc: On FreeBSD use GCC's crt objects for static linking
    
    Add crtbeginT.o to extra_parts on FreeBSD. This ensures we use GCC's
    crt objects for static linking. Otherwise it could mix crtbeginT.o
    from the base system with libgcc's crtend.o, possibly leading to
    segfaults.
    
    libgcc:
            PR target/118685
            * config.host (*-*-freebsd*): Add crtbeginT.o to extra_parts.
    
    Signed-off-by: Dimitry Andric <dimitry@andric.com>
Comment 8 Gerald Pfeifer 2025-02-08 16:45:29 UTC
I'll look into pushing this to older release branches as well.

Thank you for the diagnosis and pach, Dim!
Comment 9 GCC Commits 2025-02-09 11:24:49 UTC
The releases/gcc-14 branch has been updated by Gerald Pfeifer <gerald@gcc.gnu.org>:

https://gcc.gnu.org/g:796849274c155d6f3430d94500cfa3c11fb59a1d

commit r14-11282-g796849274c155d6f3430d94500cfa3c11fb59a1d
Author: Dimitry Andric <dimitry@andric.com>
Date:   Tue Jan 28 18:36:16 2025 +0100

    libgcc: On FreeBSD use GCC's crt objects for static linking
    
    Add crtbeginT.o to extra_parts on FreeBSD. This ensures we use GCC's
    crt objects for static linking. Otherwise it could mix crtbeginT.o
    from the base system with libgcc's crtend.o, possibly leading to
    segfaults.
    
    libgcc:
            PR target/118685
            * config.host (*-*-freebsd*): Add crtbeginT.o to extra_parts.
    
    Signed-off-by: Dimitry Andric <dimitry@andric.com>
Comment 10 GCC Commits 2025-02-17 08:40:00 UTC
The releases/gcc-13 branch has been updated by Gerald Pfeifer <gerald@gcc.gnu.org>:

https://gcc.gnu.org/g:4f3a1ef6a8f32e4583d4c67fc452db9aa7fccb68

commit r13-9379-g4f3a1ef6a8f32e4583d4c67fc452db9aa7fccb68
Author: Dimitry Andric <dimitry@andric.com>
Date:   Tue Jan 28 18:36:16 2025 +0100

    libgcc: On FreeBSD use GCC's crt objects for static linking
    
    Add crtbeginT.o to extra_parts on FreeBSD. This ensures we use GCC's
    crt objects for static linking. Otherwise it could mix crtbeginT.o
    from the base system with libgcc's crtend.o, possibly leading to
    segfaults.
    
    libgcc:
            PR target/118685
            * config.host (*-*-freebsd*): Add crtbeginT.o to extra_parts.
    
    Signed-off-by: Dimitry Andric <dimitry@andric.com>
Comment 11 GCC Commits 2025-02-20 15:11:02 UTC
The releases/gcc-12 branch has been updated by Gerald Pfeifer <gerald@gcc.gnu.org>:

https://gcc.gnu.org/g:23541b23deb5504c6d3c0a3e96a0858e10c3c627

commit r12-10960-g23541b23deb5504c6d3c0a3e96a0858e10c3c627
Author: Dimitry Andric <dimitry@andric.com>
Date:   Tue Jan 28 18:36:16 2025 +0100

    libgcc: On FreeBSD use GCC's crt objects for static linking
    
    Add crtbeginT.o to extra_parts on FreeBSD. This ensures we use GCC's
    crt objects for static linking. Otherwise it could mix crtbeginT.o
    from the base system with libgcc's crtend.o, possibly leading to
    segfaults.
    
    libgcc:
            PR target/118685
            * config.host (*-*-freebsd*): Add crtbeginT.o to extra_parts.
    
    Signed-off-by: Dimitry Andric <dimitry@andric.com>
Comment 12 Gerald Pfeifer 2025-02-20 15:17:06 UTC
All active release branches are now covered in addition to trunk,
so closing this.

Thank you for the report and patch, Dim!