I am compiling a c "hello world" program that juste include one simple function and a main function.
I am using GCC under Linux.
When I run readelf command on the binary, I can see symbol table and I can see function names in clear.
Is there a way to tell GCC (or the linker) to not generate this symbol table?
Is it possible to tell GCC to store only functions addresses, without storing function names in clear?
Use the -s option to strip the symbol table:
gcc -s -o hello hello.c
The utility strip discards symbols from object files.
Consider :
#include <stdio.h>
static void static_func(void)
{
puts(__FUNCTION__);
}
void func(void)
{
puts(__FUNCTION__);
}
int main(void)
{
static_func();
func();
return 0;
}
readelf produces on a fresh compiled binary :
Symbol table '.symtab' contains 71 entries:
Num: Value Size Type Bind Vis Ndx Name
....
37: 0000000000000000 0 FILE LOCAL DEFAULT ABS hide.c
38: 0000000000400526 17 FUNC LOCAL DEFAULT 14 static_func
....
61: 0000000000400537 17 FUNC GLOBAL DEFAULT 14 func
....
66: 0000000000400548 21 FUNC GLOBAL DEFAULT 14 main
....
And after stripping the binary the whole output is :
Symbol table '.dynsym' contains 4 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts#GLIBC_2.2.5 (2)
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main#GLIBC_2.2.5 (2)
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
Related
I'm trying to get the name of the called functions in a C program.
For exemple, this is my code:
void toto(void)
{
printf("toto\n");
}
void tutu(void)
{
printf("tutu\n");
}
void mdr(void)
{
printf("tutu\n");
printf("tutu\n");
printf("tutu\n");
printf("tutu\n");
}
int main(int ac, char **av)
{
toto();
tutu();
mdr();
}
I only wanna have on results : Main(), toto(), tutu() and mdr().
But the problem is, that when i'm using the Libelf, i retrieve some informations on the Symbol Table, but it gives me my functions called and more, like this example :
...
57: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main##GLIBC_
58: 0000000000401148 47 FUNC GLOBAL DEFAULT 13 mdr
59: 0000000000401126 17 FUNC GLOBAL DEFAULT 13 toto
60: 0000000000404020 0 NOTYPE GLOBAL DEFAULT 23 __data_start
61: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
62: 0000000000402008 0 OBJECT GLOBAL HIDDEN 15 __dso_handle
63: 0000000000401137 17 FUNC GLOBAL DEFAULT 13 tutu
64: 0000000000402000 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used
65: 00000000004011a0 101 FUNC GLOBAL DEFAULT 13 __libc_csu_init
66: 0000000000404028 0 NOTYPE GLOBAL DEFAULT 24 _end
67: 0000000000401070 5 FUNC GLOBAL HIDDEN 13 _dl_relocate_static_pie
68: 0000000000401040 47 FUNC GLOBAL DEFAULT 13 _start
69: 0000000000404024 0 NOTYPE GLOBAL DEFAULT 24 __bss_start
70: 0000000000401177 37 FUNC GLOBAL DEFAULT 13 main
71: 0000000000404028 0 OBJECT GLOBAL HIDDEN 23 __TMC_END__
72: 0000000000401000 0 FUNC GLOBAL HIDDEN 11 _init
So how can i only retrieve my called functions ? Thanks again for the help
I am trying to understand version script that is being used for resolving duplicate symbol problem.
I have created a main_demo.c file with the following content
#include<stdio.h>
extern void fun1_std(void);
extern void fun1_linux(void);
int main ()
{
fun1_linux(); //defined under libfun1_linux.c
fun1_std(); //defined under libfun2_std.c
return 0;
}
Content of libfun1_std.c
#include<stdio.h>
extern void fun (void);
void fun1_std()
{
fun();
}
Content of libfun1_linux.c
#include<stdio.h>
extern void fun (void);
void fun1_linux()
{
fun();
}
Now , I have created shared object for both the above files (which are calling fun()) named as libfun1_std.so and libfun1_linux.so respectively. The function "fun()" is defined under two shared objects that looks like the following:
//library name ==> libfun2_linux.so
#include <stdio.h>
void fun()
{
printf("In fun of libfun2_linux\n");
//Similarly libfun2_std.so is printing "In fun of libfun2_std"
}
My expectation is that symbol "fun" used in libfun1_linux.so is resolved by libfun2_linux.so and similarly "fun" used in libfun2_std.so is resolved by libfun2_std.so
As we can see if we create a executable/process by linking the main program with all the above shared libraries, process will get duplicate symbol in it's address space i.e, fun(). SO the output look like this:
In fun of libfun2_std
In fun of libfun2_std
To resolve this I have created a version script that will rename the symbol.
Content of version script:
LIBFUN2_STD_1.0 {
global: *; //i.e, every symbol is global
};
and compiled libfun2_std.so with this version script.
Let's see the symbol again:-
$ readelf -a libfun2_std.so | grep fun
13: 0000000000000735 18 FUNC GLOBAL DEFAULT 12 fun##LIBFUN2_STD_1.0
35: 0000000000000000 0 FILE LOCAL DEFAULT ABS libfun2_std.c
48: 0000000000000735 18 FUNC GLOBAL DEFAULT 12 fun
000000: Rev: 1 Flags: BASE Index: 1 Cnt: 1 Name: libfun2_std.so
Also the content of caller library
nm libfun1_std.so | grep fun
0000000000000705 T fun1_std
U fun##LIBFUN2_STD_1.0.
So now it seems that we have resolved the duplicate symbol. Let's create the main executable again
gcc -Wall -o main_demo main_demo.c -lfun1_std -lfun2_std -lfun1_linux -
lfun2_linux
But during execution I got the follwing result again:
In fun of libfun2_std
In fun of libfun2_std
Lets see the content of readelf for libfun2_linux.so
$ readelf -a libfun2_linux.so | grep fun
13: 00000000000006b5 18 FUNC GLOBAL DEFAULT 11 fun
34: 0000000000000000 0 FILE LOCAL DEFAULT ABS libfun2_linux.c
47: 00000000000006b5 18 FUNC GLOBAL DEFAULT 11 fun
Question:-
Why having version script for one library is not sufficient as now symbols are different? If we create two version script (one for libfun2_linux.so) it is working fine.
How version script works? (Read some links which explain that it works by creatig trees but didnot get it completely). Please suggest some link where it is clearly explained.
is vdso supported for a 32 bit application which is running on a 64 bit kernel with glibc version 2.15.? If yes, how do I make it work for 32 bit application running on 64 bit kernel.? Cause even though dlopen on "linux-vdso.so.1" is success, dlsym on "__vdso_gettimeofday" fails.
On the same system I able to do a dlopen on "linux-vdso.so.1" & dlsym on "__vdso_gettimeofday" from a application compiled for 64 bit.
On my 64-bit Linux 4.4.15, the 32-bit vdso has these symbols:
readelf -Ws vdso32
Symbol table '.dynsym' contains 9 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000ce0 9 FUNC GLOBAL DEFAULT 12 __kernel_sigreturn##LINUX_2.5
2: 00000d00 13 FUNC GLOBAL DEFAULT 12 __kernel_vsyscall##LINUX_2.5
3: 00000ad0 438 FUNC GLOBAL DEFAULT 12 __vdso_gettimeofday##LINUX_2.6
4: 00000c90 42 FUNC GLOBAL DEFAULT 12 __vdso_time##LINUX_2.6
5: 00000770 853 FUNC GLOBAL DEFAULT 12 __vdso_clock_gettime##LINUX_2.6
6: 00000cf0 8 FUNC GLOBAL DEFAULT 12 __kernel_rt_sigreturn##LINUX_2.5
7: 00000000 0 OBJECT GLOBAL DEFAULT ABS LINUX_2.5
8: 00000000 0 OBJECT GLOBAL DEFAULT ABS LINUX_2.6
This suggests that the __vdso_gettimeofday you are looking for has been added in kernel 2.6, and that your kernel version is older.
The test is on Ubuntu 12.04, 32-bit, with gcc 4.6.3.
Basically I am doing some binary manipulation work on ELF binaries, and what I have to do now is to assemble a assembly program and guarantee the libc symbols are loaded to a predefined address by me.
Let me elaborate it in an simple example.
Suppose in the original code, libc symbols stdout#GLIBC_2.0 is used.
#include <stdio.h>
int main() {
FILE* fout = stdout;
fprintf( fout, "hello\n" );
}
When I compile it and check the symbol address using these commands:
gcc main.c
readelf -s a.out | grep stdout
I got this:
0804a020 4 OBJECT GLOBAL DEFAULT 25 stdout#GLIBC_2.0 (2)
0804a020 4 OBJECT GLOBAL DEFAULT 25 stdout##GLIBC_2.0
and the .bss section is like this:
readelf -S a.out | grep bss
[25] .bss NOBITS 0804a020 001014 00000c 00 WA 0 0 32
Now what I am trying to do is to load the stdout symbol in a predefined address, so I did this:
echo "stdout = 0x804a024;" > symbolfile
gcc -Wl,--just-symbols=symbolfile main.c
Then when I check the .bss section and symbol stdout, I got this:
[25] .bss NOBITS 0804a014 001014 000008 00 WA 0 0 4
4: 0804a024 0 NOTYPE GLOBAL DEFAULT ABS stdout
49: 0804a024 0 NOTYPE GLOBAL DEFAULT ABS stdout
It seems that I didn't successfully load the symbol stdout##GLIBC_2.0, but just a wired stdout. (I tried to write stdout##GLIBC_2.0 in symbolfile, but it can't compile... )
It seems that as I didn't make it, the beginning address of .bss section has also changed, which makes the address of stdout symbol in a non-section area. During runtime, it throws a segmentation fault when loading from 0x804a024.
Could anyone help me on how to successfully load the library symbol at a predefined address? Thanks!
All the initialized global/static variables will go to initialized data section.
All the uninitialized global/static variables will go to uninitialed data section(BSS). The variables in BSS will get a value 0 during program load time.
If a global variable is explicitly initialized to zero (int myglobal = 0), where that variable will be stored?
Compiler is free to put such variable into bss as well as into data. For example, GCC has a special option controlling such behavior:
-fno-zero-initialized-in-bss
If the target supports a BSS section, GCC by default puts variables that are initialized to zero into BSS. This
can save space in the resulting code. This option turns off this
behavior because some programs explicitly rely on variables going to
the data section. E.g., so that the resulting executable can find the
beginning of that section and/or make assumptions based on that.
The default is -fzero-initialized-in-bss.
Tried with the following example (test.c file):
int put_me_somewhere = 0;
int main(int argc, char* argv[]) { return 0; }
Compiling with no options (implicitly -fzero-initialized-in-bss):
$ touch test.c && make test && objdump -x test | grep put_me_somewhere
cc test.c -o test
0000000000601028 g O .bss 0000000000000004 put_me_somewhere
Compiling with -fno-zero-initialized-in-bss option:
$ touch test.c && make test CFLAGS=-fno-zero-initialized-in-bss && objdump -x test | grep put_me_somewhere
cc -fno-zero-initialized-in-bss test.c -o test
0000000000601018 g O .data 0000000000000004 put_me_somewhere
It's easy enough to test for a specific compiler:
$ cat bss.c
int global_no_value;
int global_initialized = 0;
int main(int argc, char* argv[]) {
return 0;
}
$ make bss
cc bss.c -o bss
$ readelf -s bss | grep global_
32: 0000000000400420 0 FUNC LOCAL DEFAULT 13 __do_global_dtors_aux
40: 0000000000400570 0 FUNC LOCAL DEFAULT 13 __do_global_ctors_aux
55: 0000000000601028 4 OBJECT GLOBAL DEFAULT 25 global_initialized
60: 000000000060102c 4 OBJECT GLOBAL DEFAULT 25 global_no_value
We're looking for the location of 0000000000601028 and 000000000060102c:
$ readelf -S bss
There are 30 section headers, starting at offset 0x1170:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
...
[24] .data PROGBITS 0000000000601008 00001008
0000000000000010 0000000000000000 WA 0 0 8
[25] .bss NOBITS 0000000000601018 00001018
0000000000000018 0000000000000000 WA 0 0 8
It looks like both values are stored in the .bss section on my system: gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4).
The behavior is dependent upon the C implementation. It may end up in either .data or .bss, and to increase changes that it does not end up in .data taking redundant space up, it's better not to explicitly initialize it to 0, since it will be set to 0 anyway if the object is of static duration.