gcc debug symbols (-g flag) vs linker's -rdynamic option
2013-04-24 17:17
405 查看
glibc provides backtrace()and backtrace_symbols()to get the stack trace of a running program. But for this to work the program has to be built with linker's -rdynamicflag. What is the difference between -gflag passed to gcc vs linker's -rdynamicflag ? For a sample code I did readelf to compare the outputs. -rdynamicseems to produce more info under Symbol table '.dynsym'But I am not quite sure what the additional info is. Even if I stripa program binary built using -rdynamic, backtrace_symbols()continue to work. When stripremoves all the symbols from the binary why is it leaving behind whatever was added by the -rdynamicflag ? Edit: Follow-up questions based on Mat's response below.. For the same sample code you took this is the difference I see with -g& -rdynamic without any option.. Symbol table '.dynsym' contains 4 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 218 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) 2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ Symbol table '.symtab' contains 70 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000400200 0 SECTION LOCAL DEFAULT 1 2: 000000000040021c 0 SECTION LOCAL DEFAULT 2 with -gthere are more sections, more entries in .symtabtable but .dynsymremains the same.. [26] .debug_aranges PROGBITS 0000000000000000 0000095c 0000000000000030 0000000000000000 0 0 1 [27] .debug_pubnames PROGBITS 0000000000000000 0000098c 0000000000000023 0000000000000000 0 0 1 [28] .debug_info PROGBITS 0000000000000000 000009af 00000000000000a9 0000000000000000 0 0 1 [29] .debug_abbrev PROGBITS 0000000000000000 00000a58 0000000000000047 0000000000000000 0 0 1 [30] .debug_line PROGBITS 0000000000000000 00000a9f 0000000000000038 0000000000000000 0 0 1 [31] .debug_frame PROGBITS 0000000000000000 00000ad8 0000000000000058 0000000000000000 0 0 8 [32] .debug_loc PROGBITS 0000000000000000 00000b30 0000000000000098 0000000000000000 0 0 1 Symbol table '.dynsym' contains 4 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 218 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) 2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ Symbol table '.symtab' contains 77 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000400200 0 SECTION LOCAL DEFAULT 1 with -rdynamicno additional debug sections, .symtab entries are 70 (same as vanilla gcc invocation), but more .dynsymentries.. Symbol table '.dynsym' contains 19 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 218 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) 2: 00000000005008e8 0 OBJECT GLOBAL DEFAULT ABS _DYNAMIC 3: 0000000000400750 57 FUNC GLOBAL DEFAULT 12 __libc_csu_fini 4: 00000000004005e0 0 FUNC GLOBAL DEFAULT 10 _init 5: 0000000000400620 0 FUNC GLOBAL DEFAULT 12 _start 6: 00000000004006f0 86 FUNC GLOBAL DEFAULT 12 __libc_csu_init 7: 0000000000500ab8 0 NOTYPE GLOBAL DEFAULT ABS __bss_start 8: 00000000004006de 16 FUNC GLOBAL DEFAULT 12 main 9: 0000000000500aa0 0 NOTYPE WEAK DEFAULT 23 data_start 10: 00000000004007c8 0 FUNC GLOBAL DEFAULT 13 _fini 11: 00000000004006d8 6 FUNC GLOBAL DEFAULT 12 foo 12: 0000000000500ab8 0 NOTYPE GLOBAL DEFAULT ABS _edata 13: 0000000000500a80 0 OBJECT GLOBAL DEFAULT ABS _GLOBAL_OFFSET_TABLE_ 14: 0000000000500ac0 0 NOTYPE GLOBAL DEFAULT ABS _end 15: 00000000004007d8 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used 16: 0000000000500aa0 0 NOTYPE GLOBAL DEFAULT 23 __data_start 17: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 18: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ Symbol table '.symtab' contains 70 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000400200 0 SECTION LOCAL DEFAULT 1 2: 000000000040021c 0 SECTION LOCAL DEFAULT 2 Now these are the questions I have.. In gdb you can do bt to get the bactrace. If that works with just -gwhy do we need -rdynamicfor backtrace_symbols to work ? Comparing the additions to .symtabwith -g& additions to .dynsymwith -rdynamicthey are not exactly the same.. Does either one provide better debugging info compared to the other ? FWIW, size of the output produced is like this: with -g > with -rdynamic > with neither option What exactly is the usage of .dynsym ? Is it all the symbols exported by this binary ? In that case why is foo going into .dynsym because we are not compiling the code as a library. If I like my code against all static libraries then -rdynamic is not needed for backtrace_symbols to work ? c linux gcc linker shared-libraries
| |||
|
1 Answer
activeoldestvotesup vote13down voteaccepted | According to the docs: This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table. Those are not debug symbols, they are dynamic linker symbols. Those are not removed by stripsince it would (in most cases) break the executable - they are used by the runtime linker to do the final link stage of your executable. Example: $ cat t.c void foo() {} int main() { foo(); return 0; } Compile and link without -rdynamic(and no optimizations, obviously) $ gcc -O0 -o t t.c $ readelf -s t Symbol table '.dynsym' contains 3 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) 2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ Symbol table '.symtab' contains 50 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000400270 0 SECTION LOCAL DEFAULT 1 .... 27: 0000000000000000 0 FILE LOCAL DEFAULT ABS t.c 28: 0000000000600e14 0 NOTYPE LOCAL DEFAULT 18 __init_array_end 29: 0000000000600e40 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC So the executable has a .symtabwith everything. But notice that .dynsymdoesn't mention fooat all - it has the bare essentials in there. This is not enough information for backtrace_symbolsto work. It relies on the information present in that section to match code addresses with function names. Now compile with -rdynamic: $ gcc -O0 -o t t.c -rdynamic $ readelf -s t Symbol table '.dynsym' contains 17 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) 2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 4: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS _edata 5: 0000000000601008 0 NOTYPE GLOBAL DEFAULT 24 __data_start 6: 0000000000400734 6 FUNC GLOBAL DEFAULT 13 foo 7: 0000000000601028 0 NOTYPE GLOBAL DEFAULT ABS _end 8: 0000000000601008 0 NOTYPE WEAK DEFAULT 24 data_start 9: 0000000000400838 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used 10: 0000000000400750 136 FUNC GLOBAL DEFAULT 13 __libc_csu_init 11: 0000000000400650 0 FUNC GLOBAL DEFAULT 13 _start 12: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS __bss_start 13: 000000000040073a 16 FUNC GLOBAL DEFAULT 13 main 14: 0000000000400618 0 FUNC GLOBAL DEFAULT 11 _init 15: 00000000004007e0 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini 16: 0000000000400828 0 FUNC GLOBAL DEFAULT 14 _fini Symbol table '.symtab' contains 50 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000400270 0 SECTION LOCAL DEFAULT 1 .... 27: 0000000000000000 0 FILE LOCAL DEFAULT ABS t.c 28: 0000000000600e14 0 NOTYPE LOCAL DEFAULT 18 __init_array_end 29: 0000000000600e40 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC Same thing for symbols in .symtab, but now foohas a symbol in the dynamic symbol section (and a bunch of other symbols appear there now too). This makes backtrace_symbolswork - it now has enough information (in most cases) to map code addresses with function names. Strip that: $ strip --strip-all t $ readelf -s t Symbol table '.dynsym' contains 17 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) 2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 4: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS _edata 5: 0000000000601008 0 NOTYPE GLOBAL DEFAULT 24 __data_start 6: 0000000000400734 6 FUNC GLOBAL DEFAULT 13 foo 7: 0000000000601028 0 NOTYPE GLOBAL DEFAULT ABS _end 8: 0000000000601008 0 NOTYPE WEAK DEFAULT 24 data_start 9: 0000000000400838 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used 10: 0000000000400750 136 FUNC GLOBAL DEFAULT 13 __libc_csu_init 11: 0000000000400650 0 FUNC GLOBAL DEFAULT 13 _start 12: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS __bss_start 13: 000000000040073a 16 FUNC GLOBAL DEFAULT 13 main 14: 0000000000400618 0 FUNC GLOBAL DEFAULT 11 _init 15: 00000000004007e0 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini 16: 0000000000400828 0 FUNC GLOBAL DEFAULT 14 _fini $ ./t $ No .symtabis gone, but the dynamic symbol table is still there, and the executable runs. So backtrace_symbolsstill works too. Strip the dynamic symbol table: $ strip -R .dynsym t $ ./t ./t: relocation error: ./t: symbol , version GLIBC_2.2.5 not defined in file libc.so.6 with link time reference ... and you get a broken executable. An interesting read for what .symtaband .dynsymare used for is here: Inside ELF Symbol Tables. One of the things to note is that .symtabis not needed at runtime, so it is discarded by the loader. That section does not remain in the process's memory. .dynsym, on the otherhand, is needed at runtime, so it is kept in the process image. So it is available for things like backtrace_symbolsto gather information about the current process from within itself. So in short: dynamic symbols are not stripped by stripsince that would render the executable non-loadable backtrace_symbolsneeds dynamic symbols to figure out what code belongs which function backtrace_symbolsdoes not use debugging symbols Hence the behavior you noticed. For your specific questions: gdbis a debugger. It uses debug information in the executable and libraries to display relevant information. It is much more complex than backtrace_symbols, and inspects the actual files on your drive in addition to the live process. backtrace_symbolsdoes not, it is entirely in-process - so it cannot access sections that are not loaded into the executable image. Debug sections are not loaded into the runtime image, so it can't use them. .dynsymis not a debugging section. It is a section used by the dynamic linker. .symbtabisn't a debugging section either, but it can be used by debugger that have access to the executable (and library) files. -rdynamicdoes not generate debug sections, only that extended dynamic symbol table. The executable growth from -rdynamicdepends entirely on the number of symbols in that executable (and alignment/padding considerations). It should be considerably less than -g. Except for statically linked binaries, executables need external dependencies resolved at load time. Like linking printfand some application startup procedures from the C library. These external symbols must be indicated somewhere in the executable: this is what .dynsymis used for, and this is why the exe has a .dynsymeven if you don't specify -rdynamic. When you do specify it, the linker adds other symbols that are not necessary for the process to work, but can be used by things like backtrace_symbols. backtrace_symbolswill not resolve any function names if you statically link. Even if you specify -rdynamic, the .dynsymsection will not be emitted to the executable. No symbol tables gets loaded into the executable image, so backtrace_symbolscannot map code adresses to symbols. |
相关文章推荐
- g++: error: unrecognized option '--no-undefined' gcc、g++版本过高问题
- VS编译警告 : LINK : warning LNK4076: invalid incremental status file './Debug/.ilk'; linking nonincr
- iOS "directory not found for option '-L/Users/.../Pods/build/Debug-iphoneos"解决方式
- CodeBlock编辑器GCC环境下,编译报错:Execution of 'mingw32-g++.exe -o bin\Debug\test.exe obj\Debug\main.o' in 'C
- vs 错误1------"无法启动程序'...debug/abc.exe',系统找不到指定文件"的问题!
- 用gcc编译.cpp文件可能出现"undefined reference to `__gxx_personality_v0'"问题的解决
- tcc88xx/android配置linux内核(make tcc88xx_defconfig)时gcc:error trying to exec 'cc1':execvp:No such file or directory
- gcc undefined reference to '__stack_chk_fail'【操作系统开发编译中遇到的问题】
- GCC's bacl-end & assemble emission (41)
- 消除directory not found for option '-F'/'-L' 警告
- Error:Execution failed for task ':app:transformNative_libsWithStripDebugSymbolForDebug'. > java.lang.NullPointerExcep
- codeblocks gcc error: 'for' loop initial declarations are only allowed in C99 mode|
- Nios II编译出错:make: *** No rule to make target `e:/nios ', needed by `/cygdrive/e/nios/Debug/system_de
- myEclipse debug android 'hello world'
- [Android Studio][NDK]Execution failed for task ':app:compileDebugNdk'. Error Code:2
- Error:Execution failed for task ':app:compileDebugNdk' 解决方法
- GCC's bacl-end & assemble emission (16)
- PHP Warning: PHP Startup: Unable to load dynamic library './php_mysql.dll' - /xd5/xd2/xb2/xbb/xb5/xbd/xd6/xb8/xb6/xa8/xb5/xc4/x
- proguard.ParseException: Unknown option '-keepdirectories' in line 57 of file
- iOS开发——warning: directory not found for option ' '