On Debian bullseye (testing), with these xz/lzma-related packages installed:
ii liblzma-dev:amd64 5.2.4-1+b1 amd64
ii liblzma5:amd64 5.2.4-1+b1 amd64
ii lzma-dev 9.22-2.1 all
Clang generates a working ./a.out without issue:
$>gunzip < /usr/share/doc/liblzma-dev/examples/02_decompress.c.gz | sed -s 's/extern int/int' | clang -std=c18 -Wall -Wextra -x c -llzma -
However, attempting to use gcc fails:
$>gunzip < /usr/share/doc/liblzma-dev/examples/02_decompress.c.gz | sed -s 's/extern int/int' | gcc -std=c18 -Wall -Wextra -x c -llzma -
/usr/bin/ld: /tmp/ccl8uTG0.o: in function `init_decoder':
:(.text+0x20): undefined reference to `lzma_stream_decoder'
/usr/bin/ld: /tmp/ccl8uTG0.o: in function `decompress':
:(.text+0x1e1): undefined reference to `lzma_code'
/usr/bin/ld: /tmp/ccl8uTG0.o: in fuction `main':
:(.text+0x4e4): undefined reference to `lzma_end'
collect2: error: ld returned 1 exit status
g++ --version reports 9.3.0-3
clang++ --version reports 9.0.1-10
(Those compilers are both installed via apt-get.)
/etc/ld.so.conf.d/x86_64-linux-gnu.conf contains
# Multiarch support
/usr/local/lib/x86_64-linux-gnu
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
I have checked that /usr/lib/x86_64-linux-gnu/liblzma.so.5.2.4 (and its .so.5 and .so symlinks, and the associated .a file too) exist.
Furthermore, the output of readelf --symbols /usr/lib/x86_64-linux-gnu/liblzma.so.5.2.4 | grep 'lzma_[sec]' shows that those three symbols exist (along with many others):
67: 000000000000c720 106 FUNC GLOBAL DEFAULT 13 lzma_stream_decoder##XZ_5.0
108: 00000000000039d0 701 FUNC GLOBAL DEFAULT 13 lzma_code##XZ_5.0
117: 0000000000003c90 65 FUNC GLOBAL DEFAULT 13 lzma_end##XZ_5.0
What am I doing wrong?
Clang puts the -llzma outside the --as-needed area of the linker command line:
[…] -L/usr/lib -llzma /tmp/--e00a22.o -lgcc --as-needed -lgcc_s […]
GCC puts it after --as-needed:
[…] --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 […]
-llzma /tmp/ccAZHRvb.o -lgcc --push-state
As a result, the linker notices that -llzma is not needed at that point in the command line and drops it. Linking is order-sensitive.
You can fix this by using - -llzma instead of -llzma -, as HolyBlackCat suggested.
Related
This question already has an answer here:
32-bit absolute addresses no longer allowed in x86-64 Linux?
(1 answer)
Closed last month.
I'm a student currently taking a computer structures course and I have an assignement for writing in aseembly and C. I've found an issue I don't quite understand. We were given a makefile for running the program, and when connecting to our school's servers it works as intended. The issue arises when trying to use the same makefile on my personal machine. One of the assembly files (and likely more as I continue working) utilizes a .rodata section. Attempting to use the makefile as it was given results in the following error:
gcc -g -o a.out main.o run_main.o func_select.o pstring.o
/usr/bin/ld: func_select.o: relocation R_X86_64_32S against `.rodata' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status
make: *** [makefile:2: a.out] Error 1
attempting to add one of the following
-fpie -fPIE or -no-pie
in between
-o
and a.out
results in the following error
gcc -g -o -fPIE a.out main.o run_main.o func_select.o pstring.o
/usr/bin/ld: cannot find a.out: No such file or directory
collect2: error: ld returned 1 exit status
make: *** [makefile:2: a.out] Error 1
I'm sorry if this is considered a silly question however I can't figuere it out.
The expectation was for the makefile to create all of the .o files and a.out, however the a.out file never works.
In addition writing the following: gcc -g -fPIE -o a.out main.o run_main.o func_select.o pstring.o still creates an error, specifically
gcc -g -fPIE -o a.out main.o run_main.o func_select.o pstring.o
/usr/bin/ld: func_select.o: relocation R_X86_64_32S against `.rodata' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status
make: *** [makefile:2: a.out] Error 1
As per man gcc:
gcc [-c|-S|-E] [-std=standard]
[-g] [-pg] [-Olevel]
[-Wwarn...] [-Wpedantic]
[-Idir...] [-Ldir...]
[-Dmacro[=defn]...] [-Umacro]
[-foption...] [-mmachine-option...]
[-o outfile] [#file] infile...
-o requires outfile parameter. This should work:
gcc -g -fPIE -o a.out main.o run_main.o func_select.o pstring.o
I'm trying to get my head around how the linking process works when producing an executable. To do that I'm reading Ian Taylor's blog series about it, but a lot of it is beyond me at the moment - so I'd like to see how it works in practice.
At the moment I produce some object files and link them via gcc with:
gcc -m32 -o test.o -c test.c
gcc -m32 -o main.o -c main.c
gcc -m32 -o test main.o test.o
How do I replicate the gcc -m32 -o test main.o test.o stage using ld?
I've tried a very naive: ld -A i386 ./test.o ./main.o
But that returns me these errors:
ld: i386 architecture of input file `./test.o' is incompatible with i386:x86-64 output
ld: i386 architecture of input file `./main.o' is incompatible with i386:x86-64 output
ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
./test.o: In function `print_hello':
test.c:(.text+0xd): undefined reference to `_GLOBAL_OFFSET_TABLE_'
test.c:(.text+0x1e): undefined reference to `puts'
./main.o: In function `main':
main.c:(.text+0x15): undefined reference to `_GLOBAL_OFFSET_TABLE_
I'm most confused by _start and _GLOBAL_OFFSET_TABLE_ being missing - what additional info does gcc give to ld to add them?
Here are the files:
main.c
#include "test.h"
void main()
{
print_hello();
}
test.h
void print_hello();
test.c
#include <stdio.h>
void print_hello()
{
puts("Hello, world");
}
#sam : I am not the best people to answer your question because I am a beginner in compilation. I know how to compile programs but I do not really understand all the details (https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools)
So, I decided this year to try to understand how compilation works and I tried to do, more or less, the same things as you tried a few days ago. As nobody has answered, I am going to expose what I have done but I hope an expert will supplement my answer.
Short answer : It is recommended to not use ld directly but to use gcc directly instead. Nevertheless, it is, as you write, interesting to know how the linking process works. This command works on my computer :
ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc.so /usr/lib/crti.o /usr/lib/crtn.o
Very Long answer :
How did I find the command above ?
As n.m suggested, run gcc with -v option.
gcc -v -m32 -o test main.o test.o
... /usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 ... (many
options and parameters)....
If you run ld with these options and parameters (copy and paste), it should work.
Try your command with -m elf_i386 (cf. collect2 parameters)
ld -m elf_i386 test.o main.o
ld: warning: cannot find entry symbol _start; ....
Look for symbol _start in object files used in the full ld command.
readelf -s /usr/lib/crt1.o (or objdump -t)
Symbol table '.symtab' contains 18 entries: Num: Value Size
Type Bind Vis Ndx Name... 11: 00000000 0 FUNC
GLOBAL DEFAULT 2 _start
Add this object to your ld command :ld -m elf_i386 test.o main.o /usr/lib/crt1.o
... undefined reference to `__libc_csu_fini'...
Look for this new reference in object files. It is not so obvious to know which library/object files are used because of -L, -l options and some .so include other libraries. For example, cat /usr/lib/libc.so. But, ld with --trace option helps. Try this commandld --trace ... (collect2 parameters)At the end, you should findld -m elf_i386 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc_nonshared.a /lib/libc.so.6 /usr/lib/crti.oor shorter (cf. cat /usr/lib/libc.so) ld -m elf_i386 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc.so /usr/lib/crti.o
It compiles but it does not run (Try to run ./test). It needs the right -dynamic-linker option because it is a dynamically linked ELF executable. (cf collect2 parameters to find it) ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc.so /usr/lib/crti.o But, it does not run (Segmentation fault (core dumped)) because you need the epilogue of the _init and _fini functions (https://gcc.gnu.org/onlinedocs/gccint/Initialization.html). Add the ctrn.o object. ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o test test.o main.o /usr/lib/crt1.o /usr/lib/libc.so /usr/lib/crti.o /usr/lib/crtn.o./test
Hello, world
I'm able to compile and run my application in C on CentOS with the following parameters:
gcc test.c -o test -lpcap -lssl -lcrypto -L /usr/local/lib -L /usr/local/opt/openssl/lib/ -lhiredis
But I need to run the application on a machine where I cannot compile, nor download ex. hiredis.
So I need to compile everything together on my own CentOS - which does match in setup.
I've read about the static flag, but when doing so I get the following errors:
gcc -static test.c -o test -lpcap -lssl -lcrypto -L /usr/local/lib -L /usr/local/opt/openssl/lib/ -lhiredis
/usr/bin/ld: cannot find -lpcap
/usr/bin/ld: cannot find -lssl
/usr/bin/ld: cannot find -lcrypto
/usr/local/lib/libhiredis.a(net.o): In function `_redisContextConnectTcp':
/home/alfredballe/hiredis/net.c:399: warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
collect2: error: ld returned 1 exit status
What am I doing wrong?
I've downloaded and compiled: http://leenissen.dk/fann/wp/
cmake version 2.8.11.2
gcc (Ubuntu/Linaro 4.8.1-10ubuntu8) 4.8.1
Command used to compile:
cmake -D CMAKE_INSTALL_PREFIX:PATH=/usr .
Installation:
sudo make && sudo make install
Then I go to examples/ directory inside fann project and try to compile examples by running:
make all
I'm getting an error:
gcc -O3 xor_train.c -o xor_train -lfann -lm
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib/libfann.so: undefined reference to `sin'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib/libfann.so: undefined reference to `exp'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib/libfann.so: undefined reference to `cos'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib/libfann.so: undefined reference to `log'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib/libfann.so: undefined reference to `pow'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib/libfann.so: undefined reference to `sqrt'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib/libfann.so: undefined reference to `floor'
collect2: error: ld returned 1 exit status
make: *** [xor_train] Error 1
Update:
I've followed an instruction given by a library
I've checked on another machine and provided instruction works as intended so I guess my environment is in a some way misconfigured.
Some more info about shared library dependencies:
ldd /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib/libfann.so
linux-vdso.so.1 => (0x00007fff3abfe000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6f3997c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6f39f84000)
As suggested by #michael-burr compiled with -Wl,-v
/usr/bin/ld --sysroot=/ \
--build-id --eh-frame-hdr -m elf_x86_64 \
--hash-style=gnu --as-needed \
-dynamic-linker /lib64/ld-linux-x86-64.so.2 \
-z relro -o xor_train \
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o \
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crti.o \
/usr/lib/gcc/x86_64-linux-gnu/4.8/crtbegin.o \
-L/usr/lib/gcc/x86_64-linux-gnu/4.8 \
-L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu \
-L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib \
-L/lib/x86_64-linux-gnu \
-L/lib/../lib -L/usr/lib/x86_64-linux-gnu \
-L/usr/lib/../lib \
-L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../.. \
-v /tmp/cc0AHZgU.o -lfann -lm -lgcc --as-needed -lgcc_s --no-as-needed \
-lc -lgcc --as-needed -lgcc_s --no-as-needed \
/usr/lib/gcc/x86_64-linux-gnu/4.8/crtend.o \
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crtn.o
GNU ld (GNU Binutils for Ubuntu) 2.23.52.20130913
Root cause: missing dependencies in FANN library (Will send a patch to author). Such a dependency is called "inter library dependency".
It may happen that one build a shared library A and doesn't have correct dependencies set (let's say B).
In such a case a shared library A will be build without any error msg as it's not required to provide implementation during compiling.
The problem will appear as a lack of library B when one try to create an executable file which depends on A.
In this specific case a solution is to modify a CMake configuration file according to CMake manual
Example changeline:
TARGET_LINK_LIBRARIES(fann m)
It looks like you're compiling your own program as 64-bit, but the FANN library is 32-bit. You might need to specify an architecture for FANN when you compile, which might mean modifying GCC flags in the makefile, unless there are autoconf settings to do it for you. Assuming that you want 64-bit FANN.
Alternatively, you could specify 32-bit architecture when you compile your own code.
Consider the hello world C program:
hello.c:
#include "stdio.h"
int main()
{
printf("Hello, World!\n");
}
If I call:
$ gcc -c hello.c -o hello.o
It will produce an ELF Relocatable File hello.o
If I then call:
$ gcc hello.o -o hello [1]
It will link hello.o with ld and produce an ELF Executable File hello
However if I call ld directly [2] instead of [1]:
$ ld hello.o -o hello [2]
I get these errors:
/usr/bin/ld.bfd.real: warning: cannot find entry symbol _start
test.c:(.text+0xa): undefined reference to `puts'
gcc must be passing other options to ld (to link the C library for example).
Is there anyway to determine exactly what the command-line gcc is passing through to ld in command [1] ?
Yes, you can use gcc -v hello.o -o hello to get the link line. For your example on my ubuntu machine, I get this link line (edited to be multiline for readability):
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/collect2
--build-id
--eh-frame-hdr
-m elf_x86_64
--hash-style=gnu
-dynamic-linker
/lib64/ld-linux-x86-64.so.2
-o hello
-z relro
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crt1.o
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crti.o
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtbegin.o
-L/usr/lib/gcc/x86_64-linux-gnu/4.4.5
-L/usr/lib/gcc/x86_64-linux-gnu/4.4.5
-L/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib
-L/lib/../lib
-L/usr/lib/../lib
-L/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../.. -L/usr/lib/x86_64-linux-gnu
hello.o
-lgcc
--as-needed -lgcc_s --no-as-needed
-lc
-lgcc
--as-needed -lgcc_s --no-as-needed
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtend.o
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crtn.o
Note that collect2 is just an alias for ld.
For oneline lovers:
echo "int main(void) {}" | gcc -o /dev/null -v -x c - &> /dev/stdout| grep collect | tr -s " " "\012"
Replace -x c with -x c++ to get c++ flags.
Can be used also with clang, but in such case you should grep for /usr/bin/ld