https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118685

            Bug ID: 118685
           Summary: FreeBSD static executables segfault due to libgcc
                    missing crtbeginT.o
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libgcc
          Assignee: unassigned at gcc dot gnu.org
          Reporter: dimitry at andric dot com
  Target Milestone: ---

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

Reply via email to