Symbols in symtab reordered between module.kld and module.ko? - linker

I am comparing the readelf -s snapshot from module.kld and module.ko
for a module build in a cross compiler FreeBSD 10 environment,
Do the symbols in symtab get reordered between module.kld and
module.ko, as an example
readelf -s module.kld we pick 2 symbols
2651: 000b8230 74 FUNC GLOBAL DEFAULT 1 prison_equal_ip6
2652: 00030140 3318 FUNC GLOBAL DEFAULT 1 ip_output
Compare them with readelf -s from module.ko
2558: 0007a6d0 3318 FUNC GLOBAL DEFAULT 5 ip_output
2559: 001027c0 74 FUNC GLOBAL DEFAULT 5 prison_equal_ip6
So the symbol ip_output appears after prison_equal_ip6 in module.kld
but appears before it in module.ko. The problem is this is affecting
the DTrace FBT probing, running FBT probe of ip_output shows as having
arguments of prison_equal_ip6.
The way module.ko is being derived from module.kld is
ld -m elf_i386 -Bshareable --verbose -o module.ko.debug module.kld
How can I suppress this re-ordering?

Related

Why the sequence of the parameters passes to the `gcc` influence the output of `readelf -d` for the built shared library?

Given these:
bar.cpp:
int foo();
int bar()
{
return foo();
}
foo.cpp:
int foo()
{
return 42;
}
The libfoo.so is built by gcc for foo.cpp,i.e. gcc -shared -o libfoo.so -fPIC foo.c
As it's all known that readelf -d could be used to show the dependency of a specific shared library.
$ gcc -shared -o libbar2.so -fPIC bar.c -lfoo -L.
$ gcc -shared -o libbar.so -lfoo -L. -fPIC bar.c
$ readelf -d libbar2.so | grep -i needed
0x0000000000000001 (NEEDED) Shared library: [libfoo.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
$ readelf -d libbar.so | grep -i needed
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
Why the sequence of the parameters passes to the gcc influence the output of readelf -d for the built shared library?
All these tests are on Ubuntu16.04 with gcc 5.4.0.
Update:
$ ls -l libbar*
-rwxrwxr-x 1 joy joy 8000 Oct 4 23:16 libbar2.so
-rwxrwxr-x 1 joy joy 8000 Oct 4 23:16 libbar.so
$ sum -r libbar*
00265 8 libbar2.so
56181 8 libbar.so
The linking process is sequential and the order in which you specify the files is important. The file are treated in the order they are given. See this extract from the ld manual:
Some of the command-line options to ld may be specified at any point
in the command line. However, options which
refer to files, such as -l or -T, cause the file to be read at the point at which the option appears in the command
line, relative to the object files and other file options.
When you try to link a shared library into another one, the linker will lookup if there is any undefined reference that requires something from the library in all the files considered UP TO NOW(hence in your second example, there is no files prior to the libfoo library ) , and if there is none, the library is left aside, and the linking continue with the remaining files.
Here you also have a behaviour that may be surprising: it is possible (by default) to create shared libraries that still have undefined references (that means they are not self contained). That is what happen in your second example(libbar.so). If you want to avoid this behaviour to be sure you are not in this case you can add the -Wl,-no-undefined option (see https://stackoverflow.com/a/2356393/4871988).
If you add this option the second case will raise an error at link time.
EDIT: I found this other extract in the ld manual that explain this behaviour:
The linker will search an archive only once, at the location where it
is specified on the command line. If the
archive defines a symbol which was undefined in some object which appeared before the archive on the command
line, the linker will include the appropriate file(s) from the archive. However, an undefined symbol in an
object appearing later on the command line will not cause the linker to search the archive again.
See the -( option for a way to force the linker to search archives multiple times.
You may list the same archive multiple times on the command line.
This also applies to shared libraries

Output relocatable section data from linker script

Using commands like BYTE or LONG, it is possible to include explicit bytes of data in an output section from a linker script. The linked page also describes that those commands can be used to output the value of symbols.
I would have expected that if you perform partial linking (i.e., using the -r option of ld), relocation records would be emitted for the symbols that are outputted in this way. However, it seems that the linker just outputs the currently known value1 of the symbol.
Here is a MWE to clarify what I mean.
test.c:
int foo = 1, bar = 2;
test.ld:
SECTIONS {
.data : {
*(.data)
LONG(foo)
LONG(bar)
}
}
Then run the following:
$ gcc -c test.c
$ ld -T test.ld -r -o test.elf test.o
$ readelf -r test.elf
There are no relocations in this file.
$ readelf -x .data test.elf
Hex dump of section '.data':
0x00000000 01000000 02000000 00000000 04000000 ................
As you can see, no relocations are created and the values that are outputted are the currently known values of foo and bar.
Could this be a bug? If not, is there any way to force the linker to output relocation records for symbols added to an output section?
1 I'm not sure of this is the correct term. What I mean is the value that you see when you run readelf -s on the input object file.

"No symbol version section for versioned symbol"

I'm attempting to cross-compile my own shared library (libmystuff.so) against another shared library (libtheirstuff.so) that makes use of the libcurl shared library and am getting the following error:
libmystuff.so: No symbol version section for versioned symbol
'curl_global_init##CURL_OPENSSL_3'
Which is then followed by:
final link failed: Nonrepresentable section on output.
Going through the code that creates libtheirstuff, I can see that curl_global_init is the first reference to curl.
Doing ldd libtheirstuff.so on the target platform (arm5) shows that it can find all of the references.
What's going on here?
Edit: Here are the calls to gcc
arm-none-linux-gnueabi-gcc -fPIC -c mystuff_impl.c -o mystuff_impl.o -I/home/me/arm/include
arm-none-linux-gnueabi-gcc -shared -Wl,soname=libmystuff.so -o libmystuff.so.0.1 mystuff_impl.o -L/home/me/arm/lib -ltheirstuff
Linker was grabbing the wrong version.
This problem (No symbol version section for versioned symbol
'curl_global_init##CURL_OPENSSL_3') also appears when you are trying to compile a binary that will work on multiple Linux distributions. You can check for the problem like this:
$ objdump -x mybinary | grep curl_global_init
0... F *UND* 0... curl_global_init##CURL_OPENSSL_3
The solution in this case is to build on a machine where libcurl has been compiled with ./configure --disable-versioned-symbols. Binaries compiled this way will work elsewhere (including on systems which use versioned symbols). A portable binary should produce output like this (without any # signs):
$ objdump -x mybinary | grep curl_global_init
0... F *UND* 0... curl_global_init

gcc will not properly include math.h

Here is a minimal example outlining my problem
test.c:
#include <stdio.h>
#include <math.h>
main ()
{
fmod ( 3, 2 );
}
And here is the command I am issuing to compile test.c
gcc -lm test.c -o test
And here is the output I get when I issue the above command
/tmp/ccQmRk99.o: In function `main':
test.c:(.text+0x3e): undefined reference to `fmod'
collect2: ld returned 1 exit status
I get the same output if instead I use cc. I am using the following version of gcc
gcc-4.6.real (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1
Any ideas why my program won't compile?
The problem is coming from the linker, ld, rather than gcc (hence the exit status message). In general ld requires objects and libraries to be specified in the order user supplier, where user is an object that uses a library function and supplier is the object which provides it.
When your test.c is compiled to an object the compiler states that fmod is an undefined reference
$ gcc -c test.c
$ nm test.o
U fmod
0000000000000000 T main
(nm lists all the functions referred to by an object file)
The linker changes the undefined references to defined ones, looking up the references to see if they are supplied in other files.
$ gcc -lm test.o
$ nm a.out
0000000000600e30 d _DYNAMIC
0000000000600fe8 d _GLOBAL_OFFSET_TABLE_
00000000004006a8 R _IO_stdin_used
w _Jv_RegisterClasses
0000000000600e10 d __CTOR_END__
...
0000000000601018 D __dso_handle
w __gmon_start__
...
U __libc_start_main##GLIBC_2.2.5
0000000000601020 A _edata
0000000000601030 A _end
0000000000400698 T _fini
0000000000400448 T _init
0000000000400490 T _start
00000000004004bc t call_gmon_start
0000000000601020 b completed.7382
0000000000601010 W data_start
0000000000601028 b dtor_idx.7384
U fmod##GLIBC_2.2.5
0000000000400550 t frame_dummy
0000000000400574 T main
Most of these refer to libc functions that are run before and after main to set the environment up. You can see that fmod now points to glibc, where it will be resolved by the shared library system.
My system is set up to use shared libraries by default. If I instead force static linking I get the order dependency you see
$ gcc -static -lm test.o
test.o: In function `main':
test.c:(.text+0x40): undefined reference to `fmod'
collect2: ld returned 1 exit status
Putting -lm later in the linker command, after test.o, allows it to link successfully.
Checking the symbols fmod should now be resolved to an actual address, and indeed it is
$ gcc -static test.o -lm
$ nm a.out | grep fmod
0000000000400480 T __fmod
0000000000402b80 T __ieee754_fmod
0000000000400480 W fmod
From the gcc(1) manpage: "the placement of the -l option is significant."
Specifically:
-llibrary
-l library
Search the library named library when linking. (The second alternative with the library as a
separate argument is only for POSIX compliance and is not recommended.)
It makes a difference where in the command you write this option; the linker searches and processes
libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z
after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be
loaded.
The linker searches a standard list of directories for the library, which is actually a file named
liblibrary.a. The linker then uses this file as if it had been specified precisely by name.
The directories searched include several standard system directories plus any that you specify with
-L.
Normally the files found this way are library files---archive files whose members are object files.
The linker handles an archive file by scanning through it for members which define symbols that have
so far been referenced but not defined. But if the file that is found is an ordinary object file, it
is linked in the usual fashion. The only difference between using an -l option and specifying a file
name is that -l surrounds library with lib and .a and searches several directories.

From Static to dynamic linking on Solaris 10

Apparently Solaris 10 does not support static linking anymore. Therefore, I am wondering if anyone can assist me rewriting the makefile so that it supports dynamic linking. Essentially,
the following linker command gives me an error message that _memset is not found. Memset itself is in the standard library which should NOT be linked statically. Here is the linker command:
/usr/ccs/bin/ld -o q -e start_master -dn -z defs -M ../../../mapfile.q {list of object files}
Anyone an idea how I can get this running on Solaris 10 now?
Thanks!
What about
/usr/ccs/bin/ld -o q -e start_master -Bstatic -z defs -M ../../../mapfile.q {list of object files} -Bdynamic -lc

Resources