c++gcclinkercross-compiling

Linker not linking to basic libraries in cross compile


I've got an alpha cross compiler on an x86_64 host, that seems to build everything, but I can't get it to compile this simple test program:

#include <stdio.h>      /* puts */
#include <stdlib.h>     /* atexit */

void fnExit1 (void)
{
  puts ("Exit function 1.");
}

void fnExit2 (void)
{
  puts ("Exit function 2.");
}

int main ()
{
  atexit (fnExit1);
  atexit (fnExit2);
  puts ("Main function.");
  return 0;
}
>alpha-linux-gnu-gcc 1.cpp --sysroot=/opt
cc1plus: warning: '-fstack-protector' not supported for this target
/opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/bin/ld: /tmp/ccCNt1S8.o: in function `main':
(.text+0xb0): undefined reference to `atexit'
/opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/bin/ld: (.text+0xc8): undefined reference to `atexit'
collect2: error: ld returned 1 exit status

>alpha-linux-gnu-gcc 1.cpp --sysroot=/opt -lc -L/lib
cc1plus: warning: '-fstack-protector' not supported for this target
/opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/bin/ld: /tmp/ccAF0OeC.o: in function `main':
(.text+0xb0): undefined reference to `atexit'
/opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/bin/ld: (.text+0xc8): undefined reference to `atexit'
collect2: error: ld returned 1 exit status

>grep atexit /opt/lib/*so
grep: /opt/lib/libc-2.41.so: binary file matches
grep: /opt/lib/libc.so: binary file matches

nm info against glibc in sysroot:

>alpha-linux-gnu-nm  /opt/lib/libc-2.41.so |grep atexit
000000000005ac80 t __GI___cxa_atexit
000000000005ac80 T __cxa_atexit
000000000005b240 T __cxa_thread_atexit_impl
00000000001d5d10 t __dyn_atexit
000000000005ab00 t __internal_atexit
00000000001d5d10 T atexit@GLIBC_2.0

Cross compiler info from build

>alpha-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=alpha-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/opt/tools/bin/../libexec/gcc/alpha-linux-gnu/14.2.0/lto-wrapper
Target: alpha-linux-gnu
Configured with: ../gcc-14.2.0/configure --target=alpha-linux-gnu --prefix=/opt//tools --with-glibc-version=2.41 --with-sysroot=/opt/ --with-newlib --without-headers --enable-default-pie --enable-default-ssp --disable-nls --disable-shared --disable-multilib --disable-threads --disable-libatomic --disable-libgomp --disable-libquadmath --disable-libssp --disable-libvtv --disable-libstdcxx --enable-languages=c,c++
Thread model: single
Supported LTO compression algorithms: zlib zstd
gcc version 14.2.0 (GCC)

Verbose compile with the cross-compiler, as requested:

# alpha-linux-gnu-gcc -v 1.cpp --sysroot=/opt
Using built-in specs.
COLLECT_GCC=alpha-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/opt/tools/bin/../libexec/gcc/alpha-linux-gnu/14.2.0/lto-wrapper
Target: alpha-linux-gnu
Configured with: ../gcc-14.2.0/configure --target=alpha-linux-gnu --prefix=/opt//tools --with-glibc-version=2.41 --with-sysroot=/opt/ --with-newlib --without-headers --enable-default-pie --enable-default-ssp --disable-nls --disable-shared --disable-multilib --disable-threads --disable-libatomic --disable-libgomp --disable-libquadmath --disable-libssp --disable-libvtv --disable-libstdcxx --enable-languages=c,c++
Thread model: single
Supported LTO compression algorithms: zlib zstd
gcc version 14.2.0 (GCC)
COLLECT_GCC_OPTIONS='-v' '--sysroot=/opt' '-dumpdir' 'a-'
 /opt/tools/bin/../libexec/gcc/alpha-linux-gnu/14.2.0/cc1plus -quiet -v -iprefix /opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/ -isysroot /opt 1.cpp -quiet -dumpdir a- -dumpbase 1.cpp -dumpbase-ext .cpp -version -o /tmp/ccLFcKBK.s
GNU C++17 (GCC) version 14.2.0 (alpha-linux-gnu)
        compiled by GNU C version 14.2.0, GMP version 6.3.0, MPFR version 4.2.2, MPC version 1.3.1, isl version isl-0.27-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring duplicate directory "/opt/tools/bin/../lib/gcc/../../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/include/c++/14.2.0"
ignoring duplicate directory "/opt/tools/bin/../lib/gcc/../../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/include/c++/14.2.0/alpha-linux-gnu"
ignoring duplicate directory "/opt/tools/bin/../lib/gcc/../../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/include/c++/14.2.0/backward"
ignoring duplicate directory "/opt/tools/bin/../lib/gcc/../../lib/gcc/alpha-linux-gnu/14.2.0/include"
ignoring duplicate directory "/opt/tools/bin/../lib/gcc/../../lib/gcc/alpha-linux-gnu/14.2.0/include-fixed"
ignoring duplicate directory "/opt/tools/bin/../lib/gcc/../../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/include/c++/14.2.0
 /opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/include/c++/14.2.0/alpha-linux-gnu
 /opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/include/c++/14.2.0/backward
 /opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/include
 /opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/include-fixed
 /opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/include
 /opt/usr/local/include
 /opt/usr/include
End of search list.
cc1plus: warning: '-fstack-protector' not supported for this target
Compiler executable checksum: 1f850107005d162dc105cc0cda692399
COLLECT_GCC_OPTIONS='-v' '--sysroot=/opt' '-dumpdir' 'a-'
 /opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/bin/as -v -o /tmp/ccrw7cHl.o /tmp/ccLFcKBK.s
GNU assembler version 2.44 (alpha-linux-gnu) using BFD version (GNU Binutils) 2.44
COMPILER_PATH=/opt/tools/bin/../libexec/gcc/alpha-linux-gnu/14.2.0/:/opt/tools/bin/../libexec/gcc/:/opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/bin/
LIBRARY_PATH=/opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/:/opt/tools/bin/../lib/gcc/:/opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/lib/:/opt/lib/:/opt/usr/lib/
COLLECT_GCC_OPTIONS='-v' '--sysroot=/opt' '-dumpdir' 'a.'
 /opt/tools/bin/../libexec/gcc/alpha-linux-gnu/14.2.0/collect2 -plugin /opt/tools/bin/../libexec/gcc/alpha-linux-gnu/14.2.0/liblto_plugin.so -plugin-opt=/opt/tools/bin/../libexec/gcc/alpha-linux-gnu/14.2.0/lto-wrapper -plugin-opt=-fresolution=/tmp/cc3JrLwT.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc --sysroot=/opt --eh-frame-hdr -m elf64alpha -O1 -dynamic-linker /lib/ld-linux.so.2 -pie /opt/usr/lib/crt1.o /opt/usr/lib/crti.o /opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/crtbegin.o -L/opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0 -L/opt/tools/bin/../lib/gcc -L/opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/lib -L/opt/lib -L/opt/usr/lib /tmp/ccrw7cHl.o -lgcc -lc -lgcc /opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/crtend.o /opt/usr/lib/crtn.o
/opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/bin/ld: /tmp/ccrw7cHl.o: in function `main':
(.text+0xb0): undefined reference to `atexit'
/opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/bin/ld: (.text+0xc8): undefined reference to `atexit'
collect2: error: ld returned 1 exit status

################################################################################################################################################

I took the LD_LIBRARY list and took a look, and no, all I have are the cross compiled root (/opt):

# for x in `echo "/opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/:/opt/tools/bin/../lib/gcc/:/opt/tools/bin/../lib/gcc/alpha-linux-gnu/14.2.0/../../../../alpha-linux-gnu/lib/:/opt/lib/:/opt/usr/lib/" |tr ":" "\n"` ; do ls -al $x/libc* 2>/dev/null; done
-rwxr-xr-x 1 root root 12206288 May 20 13:42 /opt/lib//libc-2.41.so*
lrwxrwxrwx 1 root root       12 May 20 14:06 /opt/lib//libc.so -> libc-2.41.so*
lrwxrwxrwx 1 root root       12 May 20 13:16 /opt/lib//libc.so.6 -> libc-2.41.so*
lrwxrwxrwx 1 root root       12 May 20 14:06 /opt/lib//libc.so.6.1 -> libc-2.41.so*
lrwxrwxrwx 1 root root       17 May 20 13:16 /opt/lib//libcrypt.so.1 -> libcrypt1-2.41.so*
lrwxrwxrwx 1 root root       17 May 20 13:16 /opt/lib//libcrypt.so.2 -> libcrypt2-2.41.so*
-rwxr-xr-x 1 root root   410744 May 20 13:44 /opt/lib//libcrypt1-2.41.so*
-rwxr-xr-x 1 root root   409464 May 20 13:44 /opt/lib//libcrypt2-2.41.so*
-rw-r--r-- 1 root root 30198284 May 20 12:53 /opt/usr/lib//libc.a
lrwxrwxrwx 1 root root       11 May 20 16:18 /opt/usr/lib//libc.so -> libc.so.6.1*
-rwxr-xr-x 1 root root 12206288 May 20 12:53 /opt/usr/lib//libc.so.6.1*
-rw-r--r-- 1 root root      249 May 20 12:53 /opt/usr/lib//libc.so.hold
lrwxrwxrwx 1 root root       22 May 20 13:16 /opt/usr/lib//libc_malloc_debug.so -> libc_malloc_debug.so.0*
-rwxr-xr-x 1 root root   251808 May 20 12:53 /opt/usr/lib//libc_malloc_debug.so.0*
-rw-r--r-- 1 root root    18962 May 20 12:53 /opt/usr/lib//libc_nonshared.a
-rw-r--r-- 1 root root 30477670 May 20 12:53 /opt/usr/lib//libc_p.a
-rw-r--r-- 1 root root   362888 May 20 12:57 /opt/usr/lib//libcrypt.a
lrwxrwxrwx 1 root root       23 May 20 13:16 /opt/usr/lib//libcrypt.so -> ../../lib/libcrypt.so.2*
lrwxrwxrwx 1 root root       21 May 19 16:39 /opt/usr/lib//libctf-nobfd.so -> libctf-nobfd.so.0.0.0*
lrwxrwxrwx 1 root root       21 May 19 16:39 /opt/usr/lib//libctf-nobfd.so.0 -> libctf-nobfd.so.0.0.0*
-rwxr-xr-x 1 root root  1616752 May 19 16:39 /opt/usr/lib//libctf-nobfd.so.0.0.0*
lrwxrwxrwx 1 root root       15 May 19 16:39 /opt/usr/lib//libctf.so -> libctf.so.0.0.0*
lrwxrwxrwx 1 root root       15 May 19 16:39 /opt/usr/lib//libctf.so.0 -> libctf.so.0.0.0*
-rwxr-xr-x 1 root root  1465552 May 19 16:39 /opt/usr/lib//libctf.so.0.0.0*

Solution

  • Your program:

    $ cat 1.cpp
    #include <stdio.h>      /* puts */
    #include <stdlib.h>     /* atexit */
    
    void fnExit1 (void)
    {
      puts ("Exit function 1.");
    }
    
    void fnExit2 (void)
    {
      puts ("Exit function 2.");
    }
    
    int main ()
    {
      atexit (fnExit1);
      atexit (fnExit2);
      puts ("Main function.");
      return 0;
    }
    

    links successfully for me on:

    $ lsb_release -a
    No LSB modules are available.
    Distributor ID: Ubuntu
    Description:    Ubuntu 24.04.2 LTS
    Release:    24.04
    Codename:   noble
    

    if I do:

    $ sudo apt install gcc-alpha-linux-gnu g++-alpha-linux-gnu 
    ...[cut]...
    $ alpha-linux-gnu-gcc 1.cpp
    $ file a.out
    a.out: ELF 64-bit LSB executable, Alpha (unofficial), version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=685ad826db93d1c5393d323e944517eb433b566b, for GNU/Linux 3.2.0, not stripped
    

    I installed g++-alpha-linux-gnu even though I'm just running alpha-linux-gnu-gcc because for your example you compile C source in a file 1.cpp that the frontend will identify as C++ source and for which it will invoke the C++ compiler, cc1plus, as your verbose build log shows. Happily the GNU Standard C header files that you #include are equipped with conditional extern C declarations, so this does not cause me any undefined reference linkage failure, and isn't the cause of yours.

    We can see where atexit is successfully resolved by repeating the linkage to request that information:

    $ alpha-linux-gnu-gcc 1.cpp -Wl,-trace-symbol=atexit
    /usr/lib/gcc-cross/alpha-linux-gnu/13/../../../../alpha-linux-gnu/bin/ld: /tmp/ccaDrpG3.o: reference to atexit
    /usr/lib/gcc-cross/alpha-linux-gnu/13/../../../../alpha-linux-gnu/bin/ld: /usr/alpha-linux-gnu/lib/libc_nonshared.a(atexit.oS): definition of atexit
    

    The definition comes from archive member /usr/alpha-linux-gnu/lib/libc_nonshared.a(atexit.oS). Modulo the <prefix>/<target> = /usr/alpha-linux-gnu, this is normal.


    This will lead us to see how your cross installation is broken

    We can see from your verbose build log that -lc_nonshared is not present. Take my word that it isn't in mine either. So how does my linkage succeed?

    It succeeds because -lc is present, and -lc is resolved to my:

    /usr/alpha-linux-gnu/lib/libc.so
    

    which is not actually a shared library but is:

    $ file /usr/alpha-linux-gnu/lib/libc.so
    /usr/alpha-linux-gnu/lib/libc.so: ASCII text
    
    $ cat /usr/alpha-linux-gnu/lib/libc.so
    /* GNU ld script
       Use the shared library, but some functions are only in
       the static library, so try that secondarily.  */
    OUTPUT_FORMAT(elf64-alpha)
    GROUP ( /usr/alpha-linux-gnu/lib/libc.so.6.1 /usr/alpha-linux-gnu/lib/libc_nonshared.a  AS_NEEDED ( /usr/alpha-linux-gnu/lib/ld-linux.so.2 ) )
    

    an incremental linker script, which pulls in both the real GLIBC shared library:

    /usr/alpha-linux-gnu/lib/libc.so.6.1
    

    plus:

    /usr/alpha-linux-gnu/lib/libc_nonshared.a
    

    in which atexit is defined.

    Again, this is normal. If you want to understand the motivation of these shenanigans, see What is the purpose of libc_nonshared.a?

    But it is not so in your case. We can see from the listing of your /opt/usr/lib that:

    lrwxrwxrwx 1 root root       11 May 20 16:18 /opt/usr/lib//libc.so -> libc.so.6.1*
    

    libc.so is simply a symlink to libc.so.6.1.

    And libc.so.6.1 does not resolve your reference to atexit.

    Why not?

    That reference:

    $ alpha-linux-gnu-gcc -c 1.cpp
    $ readelf -sW 1.o | grep atexit
        12: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND atexit
        
    

    is an unversioned external reference. Your libc.so.6.1 defines:

    $ readelf -sW /usr/alpha-linux-gnu/lib/libc.so.6.1 | grep atexit
       466: 00000000001924d0    56 FUNC    GLOBAL DEFAULT [STD GPLOAD]    12 atexit@GLIBC_2.0
      1114: 000000000004a960   344 FUNC    GLOBAL DEFAULT [STD GPLOAD]    12 __cxa_thread_atexit_impl@@GLIBC_2.18
      1823: 000000000004a680    28 FUNC    GLOBAL DEFAULT [STD GPLOAD]    12 __cxa_atexit@@GLIBC_2.1.3
      
    

    only the versioned atexit@GLIBC_2.0. And this is not a default version - which would be atexit@@GLIBC_2.0, with double @ - so it will only, by intent, resolve references to atexit@GLIBC_2.0, not references to unversioned atexit. To resolve unversioned atexit, trusting the linker to find the right definition, you are supposed to link libc_unshared.a, which you don't, because your libc.so is not the band-aid linker script that it ought to be.


    Fixes?

    If you can, get rid of your existing alpha-linux-gnu-(gcc|g++) cross installation and replace it with your package-manager's, which should work.

    If you can't get rid of it then as root replace your libc.so symlink with an incremental linker script as per my /usr/alpha-linux-gnu/lib/libc.so above, with the paths corrected for your installation. But in that case I wouldn't be suprised if other problems surface.