UnderstandingDSOLinkChange

From FedoraProject

(Difference between revisions)
Jump to: navigation, search
(Created page with '= Understanding the (Proposed) Change to DSO Linking= == Basics == The default behaviour for ld currently defaults to not linking objects that are listed as dependencies of a...')
 
(Understanding the (Proposed) Change to DSO Linking)
Line 1: Line 1:
 
= Understanding the (Proposed) Change to DSO Linking=  
 
= Understanding the (Proposed) Change to DSO Linking=  
 +
  
 
== Basics ==
 
== Basics ==
Line 7: Line 8:
  
 
== What's the difference? ==
 
== What's the difference? ==
 
The big difference is that with the proposed change in place, ld will no longer skip linking needed libraries by default. The current default behaviour will lead ld to skip linking with a library if it is listed as a needed by another library that the program uses. In abstract terms, if libA is needed by libB and your program requires both libA and libB, your program may only link to libB. Then if another version of libB comes out that does not list libA as a needed library, then a recompilation will mysteriously break.
 
 
A concrete example from Roland McGrath:
 
 
libxml2.so has:
 
 
  NEEDED            Shared library: [libdl.so.2]
 
  NEEDED            Shared library: [libz.so.1]
 
 
In this case, a program that links with libxml2 and uses dlopen may not link with libdl, and a program that links with libxml2 and uses gzopen may not link with libz. While these programs will work, they are at risk of failure if libxml2 is ever changed to omit the dependency on libdl/libz.
 
 
== What do I do? ==
 
 
Don't panic! Many packages will have no noticeable problems with the switch. Others may receive an error message telling them to add a DSO to their command line:
 
  
 
For example (courtesy Roland McGrath):
 
For example (courtesy Roland McGrath):
Line 42: Line 28:
  
  
<code>magilla 49 % gcc -g -fPIC -c foo1.c foo2.c foo3.c</code>
+
<code>gcc -g -fPIC -c foo1.c foo2.c foo3.c</code>
  
<code>magilla 50 % gcc -shared -o foo3.so foo3.o</code>
+
<code>gcc -shared -o foo3.so foo3.o</code>
  
<code>magilla 51 % gcc -shared -o foo2.so foo2.o foo3.so</code>
+
<code>gcc -shared -o foo2.so foo2.o foo3.so</code>
  
<code>magilla 52 % gcc -o foo1 foo1.o foo2.so -Wl,--rpath-link=</code>
 
  
 +
'''(This Succeeds)'''
  
Old result: Works. Note this could be dangerous if foo2.so is ever changed to not include foo3.so.
+
<code>gcc -o foo1 foo1.o foo2.so -Wl,--rpath-link=.</code>
  
  
 +
'''(This Fails)'''
  
New result:
+
<code>gcc -Wl,--no-add-needed -o foo1 foo1.o foo2.so -Wl,--rpath-link=.</code>
  
  /usr/bin/ld: foo1.o: undefined reference to symbol 'foo'
+
<code>/usr/bin/ld: : invalid DSO for symbol `foo' definition</code>
  /usr/bin/ld: note: 'foo' is defined in DSO ./foo3.so so try adding it to the linker command line
+
  
 +
<code>./foo3.so: could not read symbols: Bad value</code>
 +
 +
<code>collect2: ld returned 1 exit status</code>
 +
 +
<code>[Exit 1]</code>
 +
 +
 +
'''What it meant to say was:'''
 +
 +
<code>gcc -Wl,--no-add-needed -o foo1 foo1.o foo2.so -Wl,--rpath-link=. -B/tmp/</code>
 +
 +
<code>/tmp/ld: ./foo3.so: invalid DSO for symbol `foo' definition</code>
 +
 +
<code>./foo3.so: could not read symbols: Bad value</code>
 +
 +
<code>collect2: ld returned 1 exit status</code>
 +
 +
<code>[Exit 1]</code>
 +
 +
 +
So, the difference is whether you can refer to a symbol that's in a DSO
 +
that you didn't list explicitly in your link line, but that is a
 +
DT_NEEDED dependency of one of those (or recursively of those, I think).
 +
 +
I find that error message not very explanatory, but it's what it says.
 +
Giving a generic "undefined symbol" error (which usually comes with
 +
source line info for the reference) would be less strange but also
 +
perhaps too generic for this specially weird case.
 +
 +
 +
'''New result:'''
 +
 +
<code>gcc -o foo1 foo1.o foo2.so -Wl,--rpath-link=.</code>
 +
 +
<code>/usr/bin/ld: foo1.o: undefined reference to symbol 'foo'</code>
 +
 +
<code>/usr/bin/ld: note: 'foo' is defined in DSO ./foo3.so so try adding it to the linker command line</code>
 +
 +
 +
The big difference is that with the proposed change in place, ld will no longer skip linking needed libraries by default. The current default behaviour will lead ld to skip linking with a library if it is listed as a needed by another library that the program uses. In abstract terms, if libA is needed by libB and your program requires both libA and libB, your program may only link to libB. Then if another version of libB comes out that does not list libA as a needed library, then a recompilation will mysteriously break.
 +
 +
A concrete example from Roland McGrath:
 +
 +
libxml2.so has:
 +
 +
  NEEDED            Shared library: [libdl.so.2]
 +
  NEEDED            Shared library: [libz.so.1]
 +
 +
In this case, a program that links with libxml2 and uses dlopen may not link with libdl, and a program that links with libxml2 and uses gzopen may not link with libz. While these programs will work, they are at risk of failure if libxml2 is ever changed to omit the dependency on libdl/libz.
 +
 +
== What do I do? ==
  
The error message will prompt you to explicitly link to the DSO that you need. Adding ./foo3.so will get rid of the error:
+
The error message will prompt you to explicitly link to the DSO that you need. From the foo example, adding foo3.so will get rid of the error:
  
 
<code>gcc -o foo1 foo1.o foo2.so foo3.so -Wl,--rpath-link=.</code>
 
<code>gcc -o foo1 foo1.o foo2.so foo3.so -Wl,--rpath-link=.</code>

Revision as of 19:16, 26 November 2009

Contents

Understanding the (Proposed) Change to DSO Linking

Basics

The default behaviour for ld currently defaults to not linking objects that are listed as dependencies of another linked object. This is dangerous if the other object is ever changed to occlude the object on which your program depended, causing your program to break without any change to your code.

What's the difference?

For example (courtesy Roland McGrath):

 ==> foo1.c <==
 #include <stdio.h>
 extern int foo ();
 int
 main ()
 {
   printf ("%d\n", foo ());
 }
 ==> foo2.c <==
 extern int foo ();
 int bar () { return foo (); }
 ==> foo3.c <==
 int foo () { return 0; }


gcc -g -fPIC -c foo1.c foo2.c foo3.c

gcc -shared -o foo3.so foo3.o

gcc -shared -o foo2.so foo2.o foo3.so


(This Succeeds)

gcc -o foo1 foo1.o foo2.so -Wl,--rpath-link=.


(This Fails)

gcc -Wl,--no-add-needed -o foo1 foo1.o foo2.so -Wl,--rpath-link=.

/usr/bin/ld: �: invalid DSO for symbol `foo' definition

./foo3.so: could not read symbols: Bad value

collect2: ld returned 1 exit status

[Exit 1]


What it meant to say was:

gcc -Wl,--no-add-needed -o foo1 foo1.o foo2.so -Wl,--rpath-link=. -B/tmp/

/tmp/ld: ./foo3.so: invalid DSO for symbol `foo' definition

./foo3.so: could not read symbols: Bad value

collect2: ld returned 1 exit status

[Exit 1]


So, the difference is whether you can refer to a symbol that's in a DSO that you didn't list explicitly in your link line, but that is a DT_NEEDED dependency of one of those (or recursively of those, I think).

I find that error message not very explanatory, but it's what it says. Giving a generic "undefined symbol" error (which usually comes with source line info for the reference) would be less strange but also perhaps too generic for this specially weird case.


New result:

gcc -o foo1 foo1.o foo2.so -Wl,--rpath-link=.

/usr/bin/ld: foo1.o: undefined reference to symbol 'foo'

/usr/bin/ld: note: 'foo' is defined in DSO ./foo3.so so try adding it to the linker command line


The big difference is that with the proposed change in place, ld will no longer skip linking needed libraries by default. The current default behaviour will lead ld to skip linking with a library if it is listed as a needed by another library that the program uses. In abstract terms, if libA is needed by libB and your program requires both libA and libB, your program may only link to libB. Then if another version of libB comes out that does not list libA as a needed library, then a recompilation will mysteriously break.

A concrete example from Roland McGrath:

libxml2.so has:

 NEEDED            Shared library: [libdl.so.2]
 NEEDED            Shared library: [libz.so.1]

In this case, a program that links with libxml2 and uses dlopen may not link with libdl, and a program that links with libxml2 and uses gzopen may not link with libz. While these programs will work, they are at risk of failure if libxml2 is ever changed to omit the dependency on libdl/libz.

What do I do?

The error message will prompt you to explicitly link to the DSO that you need. From the foo example, adding foo3.so will get rid of the error:

gcc -o foo1 foo1.o foo2.so foo3.so -Wl,--rpath-link=.