MinGW GCC - undefined reference to `atexit' - c

I am trying to link a large project with GCC 4.8.1 from MinGW for a x86 target.
I am calling the linker like this
D:\MyGCCPath\gcc -L [LIBPATHS] -nostdlib -Wl,-Map,D:\PathToMapFile.map,--emit-relocs [OBJECTFILES AND LIBS] -lmsvcrt -lgcc -o D:\PathToMyOutputFile
With this call I get this linker rror:
libgcc.a(__main.o):(.text+0x5a): undefined reference to `atexit'
I tried different msvcr versions (100 and 90), but this was more a desperate attempt, since I am not very familiar with this problem. I am using the correct libraries provided by MinGW.
Is there any way I can fix this error?

You are linking with -nostdlib, and atexit() is a function from stdlib.h.
According to GCC Link Options:
-nostdlib
Do not use the standard system startup files or libraries when linking. No startup files and only the libraries you specify are passed to the linker, and options specifying linkage of the system libraries, such as -static-libgcc or -shared-libgcc, are ignored.

Libraries are checked in the order used on the command line so use -lgcc -lmsvcrt.

Related

RISC V linker cannot find -lgcc

I'm trying to compile C code for GCC, but the linker is unable to find libgcc.
I want to compile some simple tests for an RV32I core.
When I try to use the modulo operator, GCC generates a call to the soft implementation of
the mod instruction.
call __modsi3
But linking fails because I think im missing libgcc
test.c:(.text+0x34): undefined reference to `__modsi3'
This is my compilation command:
riscv64-unknown-elf-gcc -lm -lgcc -static -march=rv32i -mabi=ilp32 -nostartfiles -ffreestanding crt0.s -O0
These are my linker options:
-lgcc -b elf32-littleriscv -m elf32lriscv
If I try to use the -lgcc option on the linker, it will throw the following error:
riscv64-unknown-elf-ld: cannot find -lgcc
I also tried to provide directly the path of libgcc.a. But it didn't help.
I got the path of libgcc.a this way:
riscv64-unknown-elf-gcc -march=rv32i -print-libgcc-file-name
I added the path directly to my compilation command like so:
-L="/mnt/c/Users/camin/Documents/opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/libgcc.a"
Also, the way I compiled the toolchain might be the issue, I'm using the RISCV toolchain with multi-lib support
I followed the instructions from https://github.com/riscv/riscv-gnu-toolchain
with some slight modification (-j12)
./configure --prefix=/opt/riscv --enable-multilib
make -j12
This also installed the toolchain so I didn't had to make install
Thanks.
The problem comes from -L="/mnt/c/Users/camin/Documents/opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/libgcc.a" you must only give the path to the L option. Your option should be :-L="/mnt/c/Users/camin/Documents/opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0"
the enable-multilib is working well, it only provide libraries for set of archs. However be careful to give the path of the libgcc corresponding to your arch. When you enable multilib the default one will be a 64 bit versions. Normally for rv32i, the option you need is :-L="/mnt/c/Users/camin/Documents/opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/rv32i/ilp32".
If you don't give the good library you will probably get ABI is incompatible with that of the selected emulation error.
It would be easier to use the riscv64-unknown-elf-gcc driver to make the link because he knows all the options better. Normally it will find the necessary libraries (libgcc, libgloss ....) automatically for your arch.
This worked for me, had to manually add the path to the libgcc.a as an argument to elf-ld:
riscv32-unknown-elf-ld -o exampleProg2.elf -T bram.ld -m elf32lriscv -nostdlib --no-relax /(RVTOOLCHAIN_GCC_LIB_DIR)/libgcc.a
Just be careful of choosing the right libgcc.a, there may be multiple in your installation, depending of your multilib seutp.

Why does linking with `mingw32` solve this compilation problem with SDL2?

I'm learning development using SDL2 with C on Windows and Mingw.
I tried the following command to compile my program:
gcc -IC:C:/msys64_new/mingw64/include/SDL2 *.c -o game.exe -g -Wall -Wno-unused -LC:/msys64_new/mingw64/lib -lSDL2main -lSDL2
It gave the error: Undefined reference to WinMain
Then I read that I should add -lmingw32 to the command:
gcc -IC:C:/msys64_new/mingw64/include/SDL2 *.c -o game.exe -g -Wall -Wno-unused -LC:/msys64_new/mingw64/lib -lmingw32 -lSDL2main -lSDL2
And now it works! My questions are:
Why does this solve the problem? What does linking with libmingw32.a do that solves this?
How does gcc find libmingw32.a? I don't seem to have such a file in the folder directed by -LC:/msys64_new/mingw64/lib.
libmingw32 is a part of mingw implementation of C runtime library, including e.g. crt0 and thread-local storage, stuff happening before your main is called. If you ask gcc to inform you what it does under the hood via gcc -v the_rest_of_your_build_command you'll see that it have -lmingw32 anyway in its linking command; it is possible to drop CRT (and CRT0) but that's for another question (and you'll need special handling since ordinary C programs expect CRT to be present).
There are some predefined paths linker search for libraries in. Historically for unix-like systems there are /lib, /usr/lib and so on. As mingw is mostly just ported gcc toolchain it inherits the same paths, just with its installation directory prefix (e.g. c:\mingw-w64\x86_64-w64-mingw32\lib. Check outout of ld --verbose output, specifically SEARCH_DIR.
Now why you need to specify -lmingw32 even though it is there anyway - the only reason is how ld linker resolves dependencies - left to right rule, basically. If one static library depends on another, it needs to be specified first in libraries list (but can be specified multiple times, it will not produce a conflict). In your case, #include <SDL.h> redefines your main function to SDL_main; that way your program don't have defined entry point anymore, but libSDL2main.a have one - simple main or WinMain that does minimal preparation and calls your SDL_main. So, you need to link with -lSDL2main, but by default -lmingw32 is appended last (resulting in e.g. -lSDL2main -lSDL2 -lmingw32), and linker don't search for definition of WinMain in SDL2main, and there is no WinMain in your .os, hence linking error. If you add -lmingw32 -lSDL2main -lSDL2, you have correct dependency chain - CRT0 depends on WinMain which implemented in SDL2main which also depends on SDL2. Default parameters will still add -lmingw32 at the tail, so you'll implicitly have it twice, but as I've said before you're allowed to do so.

Can't link against WinPcap library wpcap.lib ("undefined reference to")

I am trying to build an example program which uses WinPcap-functions. I’m working under Windows 7 64 Bit edition with MinGW. I am able to compile the C-code to an object file, but I can’t link against wpcap.lib.
My linker call looks like this:
gcc -L ../../lib/x64 send_packet.o -lwpcap -o WinPcapTest.exe
With this call I get the following errors:
undefined reference to pcap_open
undefined reference to pcap_sendpacket
undefined reference to pcap_geterr
Obviously I am not linking against wpcap.lib, but I don’t know why. The library is definitely found. If I change the lib include path for example, I get this error:
cannot find -lwpcap
Why does the linker find the lib but does not link against it? Thanks for your help.
Try listing you libraries after binary definition. As far as I remember, with provided gcc command, ld would be symbol matching for pcap symbols between send_packet.o and libwpcap.lib but not with WinPcapTest.exe. I would suggest moving -lwpcap at the end:
gcc -I ..\..\..\Downloads\WpdPack_4_1_2\WpdPack\Include ..\send_packet.c -L ..\..\..\Downloads\WpdPack_4_1_2\WpdPack\Lib\x64 -O0 -g3 -Wall -o WinPcapTest.exe -lwpcap

What kinds of libraries not needed to be specified in GCC?

I was wondering what kinds of libraries used in code are not needed to specify to gcc command? Is /usr/lib/libc.a the only one?
What kinds of libraries are needed to specify to gcc?
Thanks and regards!
You can get an idea of what arguments gcc automatically passes to the linker by using the -dumpspecs switch. For example, on my Windows 7 setup with MinGW using:
gcc -dumpspecs | less
under libgcc section it shows:
*libgcc:
%{mthreads:-lmingwthrd} -lmingw32 %{shared-libgcc:-lgcc_s} -lgcc -lmoldname -lmingwex -lmsvcrt
which suggest those libraries are passed to the ld linker unless I explicitly forbid it with options like nodefaultlibs or nostdlib. Your gcc dumpspec will look different depending on the host-platform, OS and target it was configured to work with.
Edit: To help answer the questions in Tim's comment.
According to the gcc docs the meaning of the spec strings lib and libgcc are as follows:
lib Libraries to include on the command line to the linker
libgcc Decides which GCC support library to pass to the linker
As I understand it, both lib and libgcc are passed to the linker by default. This next part I'm not too sure about, so someone please correct if I'm wrong, if options like nodefaultlib get passed in then only the lib spec string will be applied but the libgcc won't.
I just checked the dumpspec for gcc 4.4.x on Ubuntu running under virtual-box and it appears the libc library gets included under the lib spec string.
*lib:
%{pthread:-lpthread} %{shared:-lc} %{!shared:%{mieee-fp:-lieee} %{profile:-lc_p}%{!profile:-lc}}
Hope that answers your question.

GCC -nostdlib fails with undefined reference to `__libc_csu_fini'

I provide the linker with my files: ld-2.7.so, libc-2.7.so and crt1.o but it fails to compile successfully. Is it possible to link to a different glibc from the default one ?
(Static compilation or installing a separate glibc is not an option.)
gcc -Wl,-dynamic-linker,ld-2.7.so,libc-2.7.so,crt1.o -nostdlib program.c
crt1.o: In function `_start':
(.text+0x12): undefined reference to `__libc_csu_fini'
crt1.o: In function `_start':
(.text+0x19): undefined reference to `__libc_csu_init'
/tmp/user/1000/ccauFlwt.o: In function `findsize':
program.c:(.text+0x21): undefined reference to `stat'
/tmp/user/1000/ccauFlwt.o: In function `findtime':
program.c:(.text+0x4c): undefined reference to `stat'
collect2: ld returned 1 exit status
I found out how to do it:
rpath specifies where the provided libraries are located. This folder should contain: libc.so.6, libdl.so.2, libgcc_s.so.1 and maybe more. Check with strace to find out which libraries your binary file uses.
ld.so is the provided linker
gcc -Xlinker -rpath=/default/path/to/libraries -Xlinker -I/default/path/to/libraries/ld.so program.c
As #onemasse said, you also need header files compatible with that version of libc. Between glibc versions things still work anyway though, but this can not relied upon.
Otherwise, I would suggest you use export LD_PRELOAD_PATH to wherever your other libc is before starting the new library.
But what you really is after, is to cross-compile in linux, for linux, but with another libc.
Have a look at crosstool.
If you want to link to another libc than the one provided by the system you also need to compile your program with header files compatible with that version of libc.
Also, I'm not familiar with the option "-dynamic-linker". It's not in the man page for gcc. I really can't work out what you're trying to do.
Maybe you should try this instead and work from there:
gcc -ldl program.c -o program
You normally don't have to explicitly link with "libc" or "crt1.o".

Resources