multi function symbols in ELF library file - linux

When i dump symbols in libmpich.a, i got this:
$ nm /usr/MPICH-install/lib/libmpich.a | grep PMPI_File_open
00000000 T PMPI_File_open
U PMPI_File_open
Can anyone explain this, thx.

Can anyone explain this
The libmpich.a contains at least two object files. One of these defines the function (T). The other one references it (U).
You can see this by running:
nm -A /usr/MPICH-install/lib/libmpich.a | grep PMPI_File_open

Related

why symbol exported from linux kernel cannot be used by module?

I define a variablity in kernel .c file,for example socket.c,and export it as follows:
int abcdefg;
EXPORT_SYMBOL(abcdefg);
Then compiles it with "sudo make bzImage" and reboot.But when I use it in my own module,when insmod the module ,it says "Unknown symbol in module".
So I go to see the symbol list. When use
cat /proc/kallsyms | grep "abcdefg"
there is nothing.
When use
nm vmlinux | grep "abcdefg"
there is c1d2b700 B abcdefg
How should I do to use the symbol in my own module?
https://i.stack.imgur.com/Zv5SM.png
It sounds like you're not actually running the new kernel. – Jonathon Reinhart
Yes,you are right! I forget to update the kernel with "make install". – jenny

error: undefined reference to.. long list while compiling GTK-3.12.2

Getting 100+ errors like this:
./.libs/libgtk-3.so: undefined reference to `g_drive_can_start_degraded'
I've provided all the linker flags like -lglib-2.0 -lfreetype etc. still I'm getting those errors any help?
The first step is often Google. Search for g_drive_can_start_degraded to find out in which library/project it might be. The first link returns GDrive from GIO: https://developer.gnome.org/gio/stable/GDrive.html
Further down, it says glib: gio/gdrive.c
So it seems that this function is part of glib. Let's find this library:
find /usr/lib* -name "libglib*.so*"
If that doesn't show up any hits, try also the usual places like /lib* or /usr/local/lib*.
For me, it gives this list:
/usr/lib/cli/glib-sharp-2.0/libglibsharpglue-2.so
/usr/lib/vmware-installer/2.1.0/lib/lib/libglib-2.0.so.0
/usr/lib/vmware-installer/2.1.0/lib/lib/libglib-2.0.so.0/libglib-2.0.so.0
/usr/lib/vmware/lib/libglib-2.0.so.0
/usr/lib/vmware/lib/libglib-2.0.so.0/libglib-2.0.so.0
/usr/lib/vmware/lib/libglibmm-2.4.so.1
/usr/lib/vmware/lib/libglibmm-2.4.so.1/libglibmm-2.4.so.1
/usr/lib/vmware/lib/libglibmm_generate_extra_defs-2.4.so.1
/usr/lib/vmware/lib/libglibmm_generate_extra_defs-2.4.so.1/libglibmm_generate_extra_defs-2.4.so.1
/usr/lib/x86_64-linux-gnu/libglibmm-2.4.so.1.3.0
/usr/lib/x86_64-linux-gnu/libglibmm_generate_extra_defs-2.4.so.1.3.0
/usr/lib/x86_64-linux-gnu/libglib-2.0.so
/usr/lib/x86_64-linux-gnu/libglibmm-2.4.so.1
/usr/lib/x86_64-linux-gnu/libglibmm_generate_extra_defs-2.4.so.1
/usr/lib/x86_64-linux-gnu/libglib-2.0.so looks like the most promising candidate. Let's see what's inside:
objdump --dynamic-syms /usr/lib/x86_64-linux-gnu/libglib-2.0.so | grep g_drive_can_start_degraded
which returns nothing. Maybe I have the wrong version of glib (2.x instead of 3.x)?
But further investigation shows that I also have /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0:
> objdump --dynamic-syms /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0 | grep g_drive_can_start_de
000000000003f080 g DF .text 0000000000000078 Base g_drive_can_start_degraded
Seems like you're missing -lgio-2.0 somewhere.
If the library didn't define the symbol but would need it, the output would look like this:
0000000000000000 DF *UND* 0000000000000000 g_setenv
Note the address is 0 and the segment is *UND* instead of .text.
Note: The order of libraries that you pass to the linker is important! The linker will search each library only once.

linux kallsyms R symbol not showing

I wan't to find the kernel address of system call table.
I usually do this by grepping sys_call
but in one system, I can see the address
but in other, it doesn't show the entry.
root#ubuntu:~# cat /proc/kallsyms | grep sys_call
ffffffff8122aa90 t proc_sys_call_handler
ffffffff81726432 t ret_from_sys_call
ffffffff81726644 T int_ret_from_sys_call
ffffffff81728146 t sysexit_from_sys_call
ffffffff81728386 t sysretl_from_sys_call
ffffffff8172858e t ia32_ret_from_sys_call
**ffffffff81801400 R sys_call_table**
ffffffff81809cc0 R ia32_sys_call_table
root#ubuntu:~#
no system call table... why not showing the R type symbol??
/ $ cat /proc/kallsyms | grep sys_call
ffffffff8119c230 t proc_sys_call_handler
ffffffff817a1a57 t ret_from_sys_call
ffffffff817a1c50 T int_ret_from_sys_call
ffffffff817a2cb8 t sysexit_from_sys_call
ffffffff817a2ed8 t sysretl_from_sys_call
ffffffff817a30be t ia32_ret_from_sys_call
/ $
/ $
in what case does this could happen?
some advice would be nice
thank you
You should look into the version of the kernel in both cases, check with uname -r.
This was initially exported in the earlier versions of the kernel 2.4.x. This initially had "EXPORT_SYMBOL(sys_call_table);" line from linux/kernel/ksyms.c for
sys_call_table from being exported properly and later was made static and removed IMU.
Now this has been exported again in of some of latest kernels (in some version > 3.3.x). I would recommend digging into the LXR to check out the details.
You need to check whether your current kernel is compiled with the option CONFIG_KALLSYMS_ALL=y

Linux: update embedded resource from executable

I have an executable in which I embed a binary file resource using the objcopy method
objcopy --input binary --output elf32-i386 --binary-architecture i386 data.txt data.o
link to data.o and use
extern char _binary_data_txt_start
extern char _binary_data_txt_end
Is it possible now to update this data inside the executable? The updated data can have the same exact size, I just need to change some of the bits.
In windows PE files this is very simple to do using UpdateResource()
Nothing special and nothing hard at all. I'll give you correct sequence below, but first let me to correct slightly your embedding method. Lets not use objcopy explicitly, lets use GNU LD instead to got correct entry inside ELF file.
Lets begin. This is test-emb.c file:
#include <stdio.h>
extern unsigned char data[] asm("_binary_data_txt_start");
int
main (void)
{
fprintf(stderr, "%u, %u, %u\n", data[0] - '0', data[1] - '0', data[2] - '0');
return 0;
}
This is resource called data.txt
12345678
This is another resource called newdata.txt
98765432
Now compile and link:
$ gcc test-emb.c -c -m32
$ gcc -o test-emb test-emb.o -Wl,--format=binary -Wl,data.txt -Wl,--format=default -m32
Try:
$ ./test-emb
1, 2, 3
Now start dancing. Step one: determine logical and physical address of data section:
$ readelf -S test-emb | grep "\.data" | awk '{print $4}'
080496b8
$ readelf -S test-emb | grep "\.data" | awk '{print $5}'
0006b8
Step two: start and size fo binary data:
$ readelf -s test-emb | grep _binary_data_txt_start | awk '{print $2}'
080496c0
$readelf -s test-emb | grep _binary_data_txt_size | awk '{print $2}'
00000009
Step three: doing math. We do need: find offset of binary data in data, and convert it to physical starting point:
$ echo $((0x080496c0 - 0x080496b8))
8
echo $((0x0006b8 + 8))
1728
Step four: actual replacement (count value is binary data size, taht is 9):
cat newdata.txt | dd of=test-emb bs=1 seek=1728 count=9 conv=notrunc
Now check again:
$ ./test-emb
9, 8, 7
Everything works. You may easily fold this method into script, not harder in use, that UpdateResource under Windows, but I want to give you understanding of how things are going on.
Is it possible now to update this data inside the executable? The updated data can have the same exact size, I just need to change some of the bits.
Sure: just do it:
int main()
{
unsigned char *cp = (unsigned char*) _binary_data_txt_start
cp[0] = 'a'; // change first byte to 0x41
cp[42] += 3; // increment 43rd byte by 3
}
Note: if your _binary_data_txt_start ended up in .rodata, you may have to mprotect the pages on which it resides with PROT_READ|PROT_WRITE first.
Note: if you want the updated data to persist for the next execution of the binary, then harper's answer is correct: just use fopen, seek to correct place in the file, and write the data there.
That leaves the final question: how to find the correct place. If that is your question, see libelf documentation.
When you want to update the date in the binary you will just open the file with a mean you prefer like fopen iostream or what ever.
You can also modify the data when you executable is running. Tho modify the resource in process memory you must be sure that it is in a writable section. Verify this in your MAP file.
You can control the section with --rename-section argument of the objcopy command:
objcopy -I binary -O elf32-i386 --rename-section .rodata=.data data.txt data.o
When you really want to change the content of your elf-file before it is loaded as process than you will have to read the elf header to locate the resource data. It's easier to find the data.txt when you place it in section with a name of its own using --rename-section.
Edit:
The elf file format is too complex to decribe it in just an Stackoverflow answer. You find the basic description and links to the necessary specification here at the Wiki page.
But the easiest way to modify the linker output file is to generate a new version of data.txt and run the linker.

What is a reliable way to determine which shared library will be loaded across linux platforms?

I need to find out which library will be loaded given in the information returned from /sbin/ldconfig. I came up with the following:
#!/bin/bash
echo $(dirname $(/sbin/ldconfig -p | awk "/$1/ {print \$4}" | head -n 1))
Running this results with:
$ whichlib libGL.so
/usr/X11R6/lib
This a two part question:
Will this produce a reliable result across platform?
Is there a slicker way to parse the output of ldconfig?
Thanks,
Paul
There're several ways the library is loaded by executeable:
1.
Using $LD_LIBRARY_PATH
Using ld cache
Libary with full path compiled into binary (-rpath gcc flag)
You're using option 2, while option 1 and 3 are not considered.
Depending on what exactly you're doing you may want to run ldd directly on the executable you're planning to run rather than the general case ldconfig.
Since you asked, you could write your script like this:
dirname "$(/sbin/ldconfig -p | awk "\$1 == "$1" {print \$4; exit}")"
It's a little more precise and has one less pipe. Also echo $(cmd) is redundant; you can just write cmd.

Resources