Discussion:
ld --as-needed -lgcc_s causing linker failure when called by gcc, OK standalone
David C. Rankin
2014-10-21 23:02:05 UTC
Permalink
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?
--
David C. Rankin, J.D.,P.E.
--
To unsubscribe, e-mail: opensuse+***@opensuse.org
To contact the owner, e-mail: opensuse+***@opensuse.org
arvidjaar
2014-10-22 07:46:09 UTC
Permalink
On Wed, Oct 22, 2014 at 3:02 AM, David C. Rankin
Post by David C. Rankin
$ 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
You need to install gcc-32bit
--
To unsubscribe, e-mail: opensuse+***@opensuse.org
To contact the owner, e-mail: opensuse+***@opensuse.org
David C. Rankin
2014-10-23 01:58:11 UTC
Permalink
Post by arvidjaar
On Wed, Oct 22, 2014 at 3:02 AM, David C. Rankin
Post by David C. Rankin
$ 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
You need to install gcc-32bit
Grr.. you mean multilib doesn't provide the needed 32-bit gcc requirements? I
looked at that and thought that multilib covered it. I'll install and give it a
go, but I still am unclear why it isn't covered by multilib. Oh well, learned
much more about the ABI that I had planned in this exercise...

I still do not understand why the independent link with ld:

$ ld -dynamic-linker /lib/ld-linux.so.2 \
-o first first.o asm_io.o main.o \
-m elf_i386 -lc

worked fine while the call from gcc failed?? If the missing gcc 32-bit is the
case -- then there must be a way to disable the gcc_s search from the command
line since it is not needed.

Any thought on why '-dynamic-linker /lib/ld-linux.so.2' is expressly required
when it is the default?

Thanks for your help.
--
David C. Rankin, J.D.,P.E.
--
To unsubscribe, e-mail: opensuse+***@opensuse.org
To contact the owner, e-mail: opensuse+***@opensuse.org
Andrei Borzenkov
2014-10-23 02:45:11 UTC
Permalink
В Wed, 22 Oct 2014 20:58:11 -0500
Post by David C. Rankin
Post by arvidjaar
On Wed, Oct 22, 2014 at 3:02 AM, David C. Rankin
Post by David C. Rankin
$ 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
You need to install gcc-32bit
Grr.. you mean multilib doesn't provide the needed 32-bit gcc requirements? I
looked at that and thought that multilib covered it. I'll install and give it a
go, but I still am unclear why it isn't covered by multilib. Oh well, learned
much more about the ABI that I had planned in this exercise...
Multilib allows you to concurrently install libraries for multiple
architectures. It does not say you must always have them for every
architecture.
Post by David C. Rankin
$ ld -dynamic-linker /lib/ld-linux.so.2 \
-o first first.o asm_io.o main.o \
-m elf_i386 -lc
worked fine while the call from gcc failed?? If the missing gcc 32-bit is the
case -- then there must be a way to disable the gcc_s search from the command
line since it is not needed.
gcc -nostdlib
Post by David C. Rankin
Any thought on why '-dynamic-linker /lib/ld-linux.so.2' is expressly required
when it is the default?
--
To unsubscribe, e-mail: opensuse+***@opensuse.org
To contact the owner, e-mail: opensuse+***@opensuse.org
David C. Rankin
2014-10-23 04:21:44 UTC
Permalink
Post by Andrei Borzenkov
Post by David C. Rankin
Grr.. you mean multilib doesn't provide the needed 32-bit gcc requirements? I
Post by David C. Rankin
looked at that and thought that multilib covered it. I'll install and give it a
go, but I still am unclear why it isn't covered by multilib. Oh well, learned
much more about the ABI that I had planned in this exercise...
Multilib allows you to concurrently install libraries for multiple
architectures. It does not say you must always have them for every
architecture.
Thank you Andrei and Arvidjaar,

The issue was gcc 32-bit. I thought I was covered having multilib +
libgcc_s1-32bit, but the full gcc 32-bit was needed.
--
David C. Rankin, J.D.,P.E.
--
To unsubscribe, e-mail: opensuse+***@opensuse.org
To contact the owner, e-mail: opensuse+***@opensuse.org
Andrei Borzenkov
2014-10-23 05:23:15 UTC
Permalink
On Thu, Oct 23, 2014 at 8:21 AM, David C. Rankin
Post by David C. Rankin
Post by Andrei Borzenkov
Post by David C. Rankin
Grr.. you mean multilib doesn't provide the needed 32-bit gcc requirements? I
Post by David C. Rankin
looked at that and thought that multilib covered it. I'll install and give it a
go, but I still am unclear why it isn't covered by multilib. Oh well, learned
much more about the ABI that I had planned in this exercise...
Multilib allows you to concurrently install libraries for multiple
architectures. It does not say you must always have them for every
architecture.
Thank you Andrei and Arvidjaar,
The issue was gcc 32-bit. I thought I was covered having multilib +
libgcc_s1-32bit, but the full gcc 32-bit was needed.
libgcc_s1 is run-time for the shared libgcc. You still need
development library. The same is true for any other library package;
just in this case it is part of gcc and not separate libgcc-devel.
--
To unsubscribe, e-mail: opensuse+***@opensuse.org
To contact the owner, e-mail: opensuse+***@opensuse.org
Loading...