David C. Rankin
2014-10-21 23:02:05 UTC
All, (ld linker gurus especially),
I am befuddled by the behavior of gcc/ld in compiling/linking a couple of
c/assembly files that I need help figuring out. The files are just a couple of
the example files which I'm building as a 32-bit elf file on x86_64. For some
reason when ld is called by gcc, the build fails. Calling ld standalone works
fine. I need to understand what default behavior of the gcc/collect2/ld call is
causing the problem and how I can fix it.
I also have one other question at the end concerning why '-dynamic-linker
/lib/ld-linux.so.2' is expressly required if it is the default, but that is
separate from this first issue.
For the first issue, the assembly/c files are all contained in:
[a whopping 3.7k total]
http://www.3111skyline.com/dl/bugs/openSuSE/131/pcasm.tar.bz2
I built the assembly files without issue using:
$ nasm -felf -D ELF_TYPE -o asm_io.o asm_io.asm
$ nasm -felf -o first.o first.asm
Compiling the c file to object and performing an independent link produces a
working executable (there is a 32/64 bit issue left, but irrelevant to this
discussion):
$ gcc -c -m32 -o main.o main.c
$ ld -dynamic-linker /lib/ld-linux.so.2 \
-o first first.o asm_io.o main.o \
-m elf_i386 -lc
Attempting to compile/link with gcc is where the problem arises. If I replace
the compile of main.c to object with a request that gcc perform the
compile/link, the build fails:
$ gcc -v -m32 -o first main.c first.o asm_io.o -Wl,-melf_i386
<snip>
x86_64-suse-linux/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
Now, the part I'm stumped with is why is the link failing? The full compiler
output is at:
[newlines provided for readability]
http://www.3111skyline.com/dl/bugs/openSuSE/131/pcasm/asm_io_main_build-alc.txt
Looking at the final collect2 output, you see:
COLLECT_GCC_OPTIONS='-v' '-m32' '-o' 'first' '-mtune=generic' '-march=i586'
/usr/lib64/gcc/x86_64-suse-linux/4.8/collect2 --build-id --eh-frame-hdr
-m elf_i386
-dynamic-linker /lib/ld-linux.so.2
-o first
<snip>
showing the '-dynamic-linker /lib/ld-linux.so.2' option is selected. So why does
the link fail? Looking further, I see what appears like the likely suspects, but
I am not familiar enough with the --as-needed --no-as-needed options to know if
this is in fact the cause:
<snip>
-melf_i386
-lgcc
--as-needed -lgcc_s
--no-as-needed -lc -lgcc
--as-needed -lgcc_s
--no-as-needed
<snip>
The manual says:
--as-needed
--no-as-needed
This option affects ELF DT_NEEDED tags for dynamic libraries mentioned on
the command line after the --as-needed option. Normally the linker will add a
DT_NEEDED tag for each dynamic library mentioned on the command line, regardless
of whether the library is actually needed or not. --as-needed causes a DT_NEEDED
tag to only be emitted for a library that at that point in the link satisfies a
non-weak undefined symbol reference from a regular object file or, if the
library is not found in the DT_NEEDED lists of other libraries, a non-weak
undefined symbol reference from another dynamic library. Object files or
libraries appearing on the command line after the library in question do not
affect whether the library is seen as needed. This is similar to the rules for
extraction of object files from archives. --no-as-needed restores the default
behaviour.
(https://sourceware.org/binutils/docs/ld/Options.html#Options)
This seems to indicate for -lgcc_s that a DT_NEEDED tag will only be emitted
if -lgcc_s satisfies:
(1.) a non-weak undefined symbol reference from a regular object file
or
(2.) a non-weak undefined symbol reference from another dynamic library
Since, libgcc_s is not needed, what is causing either of the criteria (1.) or
(2.) to be satisfied? Is it some default? More importantly, how to tell the
linker not to look for it? Is there some additional option I can pass or
rearrange the order of the gcc command that would help?
Lastly, if '-dynamic-linker /lib/ld-linux.so.2' is the default, then why must
it be expressly included with the standalone ld call in order to produce a
working executable? If it is omitted, the executable is produced, but inoperable
due to /usr/lib/libc.so.1 being used instead of /lib/ld-linux.so.2 in the
executable -- which I'm having difficulty understanding.
Specifically, if linked with:
$ ld -dynamic-linker /lib/ld-linux.so.2 \
-o first first.o asm_io.o main.o \
-m elf_i386 -lc
the executable works and contains the following explicit reference to
/lib/ld-linux.so.2:
$ hexdump -C -s 272 -n 32 first
00000110 01 00 00 00 2f 6c 69 62 2f 6c 64 2d 6c 69 6e 75 |..../lib/ld-linu|
00000120 78 2e 73 6f 2e 32 00 00 03 00 00 00 05 00 00 00 |x.so.2..........|
However if linked using the following:
$ ld -o first first.o asm_io.o main.o -m elf_i386 -lc
/usr/lib/libc.so.1 takes its place and the executable fails:
$ hexdump -C -s 272 -n 32 first.sav
00000110 01 00 00 00 2f 75 73 72 2f 6c 69 62 2f 6c 69 62 |..../usr/lib/lib|
00000120 63 2e 73 6f 2e 31 00 00 03 00 00 00 05 00 00 00 |c.so.1..........|
The files are identical in all other respects:
$ l first*
-rwxr-xr-x 1 david david 8030 Oct 21 03:15 first
-rwxr-xr-x 1 david david 8030 Oct 20 21:31 first.sav
But one runs, one doesn't:
$ ./first
Enter a number: 10
Enter another number: 14
Register Dump # 1
EAX = 00000018 EBX = 00000018 ECX = F7796132 EDX = F778B650
ESI = FFF7240C EDI = 08048290 EBP = FFF723FC ESP = FFF723DC
EIP = 080482C7 FLAGS = 0216 AF PF
Memory Dump # 2 Address = 0804A044
0804A040 72 3A 20 00 59 6F 75 20 65 6E 74 65 72 65 64 20 "r: ?You entered "
0804A050 00 20 61 6E 64 20 00 2C 20 74 68 65 20 73 75 6D "? and ?, the sum"
You entered 10 and 14, the sum of these is 24
$ ./first.sav
bash: ./first.sav: No such file or directory
Why does expressly including '-dynamic-linker /lib/ld-linux.so.2' make that
difference if it is the default?
I am befuddled by the behavior of gcc/ld in compiling/linking a couple of
c/assembly files that I need help figuring out. The files are just a couple of
the example files which I'm building as a 32-bit elf file on x86_64. For some
reason when ld is called by gcc, the build fails. Calling ld standalone works
fine. I need to understand what default behavior of the gcc/collect2/ld call is
causing the problem and how I can fix it.
I also have one other question at the end concerning why '-dynamic-linker
/lib/ld-linux.so.2' is expressly required if it is the default, but that is
separate from this first issue.
For the first issue, the assembly/c files are all contained in:
[a whopping 3.7k total]
http://www.3111skyline.com/dl/bugs/openSuSE/131/pcasm.tar.bz2
I built the assembly files without issue using:
$ nasm -felf -D ELF_TYPE -o asm_io.o asm_io.asm
$ nasm -felf -o first.o first.asm
Compiling the c file to object and performing an independent link produces a
working executable (there is a 32/64 bit issue left, but irrelevant to this
discussion):
$ gcc -c -m32 -o main.o main.c
$ ld -dynamic-linker /lib/ld-linux.so.2 \
-o first first.o asm_io.o main.o \
-m elf_i386 -lc
Attempting to compile/link with gcc is where the problem arises. If I replace
the compile of main.c to object with a request that gcc perform the
compile/link, the build fails:
$ gcc -v -m32 -o first main.c first.o asm_io.o -Wl,-melf_i386
<snip>
x86_64-suse-linux/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
Now, the part I'm stumped with is why is the link failing? The full compiler
output is at:
[newlines provided for readability]
http://www.3111skyline.com/dl/bugs/openSuSE/131/pcasm/asm_io_main_build-alc.txt
Looking at the final collect2 output, you see:
COLLECT_GCC_OPTIONS='-v' '-m32' '-o' 'first' '-mtune=generic' '-march=i586'
/usr/lib64/gcc/x86_64-suse-linux/4.8/collect2 --build-id --eh-frame-hdr
-m elf_i386
-dynamic-linker /lib/ld-linux.so.2
-o first
<snip>
showing the '-dynamic-linker /lib/ld-linux.so.2' option is selected. So why does
the link fail? Looking further, I see what appears like the likely suspects, but
I am not familiar enough with the --as-needed --no-as-needed options to know if
this is in fact the cause:
<snip>
-melf_i386
-lgcc
--as-needed -lgcc_s
--no-as-needed -lc -lgcc
--as-needed -lgcc_s
--no-as-needed
<snip>
The manual says:
--as-needed
--no-as-needed
This option affects ELF DT_NEEDED tags for dynamic libraries mentioned on
the command line after the --as-needed option. Normally the linker will add a
DT_NEEDED tag for each dynamic library mentioned on the command line, regardless
of whether the library is actually needed or not. --as-needed causes a DT_NEEDED
tag to only be emitted for a library that at that point in the link satisfies a
non-weak undefined symbol reference from a regular object file or, if the
library is not found in the DT_NEEDED lists of other libraries, a non-weak
undefined symbol reference from another dynamic library. Object files or
libraries appearing on the command line after the library in question do not
affect whether the library is seen as needed. This is similar to the rules for
extraction of object files from archives. --no-as-needed restores the default
behaviour.
(https://sourceware.org/binutils/docs/ld/Options.html#Options)
This seems to indicate for -lgcc_s that a DT_NEEDED tag will only be emitted
if -lgcc_s satisfies:
(1.) a non-weak undefined symbol reference from a regular object file
or
(2.) a non-weak undefined symbol reference from another dynamic library
Since, libgcc_s is not needed, what is causing either of the criteria (1.) or
(2.) to be satisfied? Is it some default? More importantly, how to tell the
linker not to look for it? Is there some additional option I can pass or
rearrange the order of the gcc command that would help?
Lastly, if '-dynamic-linker /lib/ld-linux.so.2' is the default, then why must
it be expressly included with the standalone ld call in order to produce a
working executable? If it is omitted, the executable is produced, but inoperable
due to /usr/lib/libc.so.1 being used instead of /lib/ld-linux.so.2 in the
executable -- which I'm having difficulty understanding.
Specifically, if linked with:
$ ld -dynamic-linker /lib/ld-linux.so.2 \
-o first first.o asm_io.o main.o \
-m elf_i386 -lc
the executable works and contains the following explicit reference to
/lib/ld-linux.so.2:
$ hexdump -C -s 272 -n 32 first
00000110 01 00 00 00 2f 6c 69 62 2f 6c 64 2d 6c 69 6e 75 |..../lib/ld-linu|
00000120 78 2e 73 6f 2e 32 00 00 03 00 00 00 05 00 00 00 |x.so.2..........|
However if linked using the following:
$ ld -o first first.o asm_io.o main.o -m elf_i386 -lc
/usr/lib/libc.so.1 takes its place and the executable fails:
$ hexdump -C -s 272 -n 32 first.sav
00000110 01 00 00 00 2f 75 73 72 2f 6c 69 62 2f 6c 69 62 |..../usr/lib/lib|
00000120 63 2e 73 6f 2e 31 00 00 03 00 00 00 05 00 00 00 |c.so.1..........|
The files are identical in all other respects:
$ l first*
-rwxr-xr-x 1 david david 8030 Oct 21 03:15 first
-rwxr-xr-x 1 david david 8030 Oct 20 21:31 first.sav
But one runs, one doesn't:
$ ./first
Enter a number: 10
Enter another number: 14
Register Dump # 1
EAX = 00000018 EBX = 00000018 ECX = F7796132 EDX = F778B650
ESI = FFF7240C EDI = 08048290 EBP = FFF723FC ESP = FFF723DC
EIP = 080482C7 FLAGS = 0216 AF PF
Memory Dump # 2 Address = 0804A044
0804A040 72 3A 20 00 59 6F 75 20 65 6E 74 65 72 65 64 20 "r: ?You entered "
0804A050 00 20 61 6E 64 20 00 2C 20 74 68 65 20 73 75 6D "? and ?, the sum"
You entered 10 and 14, the sum of these is 24
$ ./first.sav
bash: ./first.sav: No such file or directory
Why does expressly including '-dynamic-linker /lib/ld-linux.so.2' make that
difference if it is the default?
--
David C. Rankin, J.D.,P.E.
--
To unsubscribe, e-mail: opensuse+***@opensuse.org
To contact the owner, e-mail: opensuse+***@opensuse.org
David C. Rankin, J.D.,P.E.
--
To unsubscribe, e-mail: opensuse+***@opensuse.org
To contact the owner, e-mail: opensuse+***@opensuse.org