symboles de débogage gcc (- drapeau g) vs option de linker-rdynamic
glibc fournit backtrace()
et backtrace_symbols()
pour obtenir la trace de la pile d'exécution d'un programme. Mais pour que cela fonctionne, le programme doit être construit avec linker -rdynamic
drapeau.
Quelle est la différence entre -g
drapeau passé à gcc vs linker -rdynamic
drapeau ? Pour un exemple de code, je me suis lu pour comparer les sorties. -rdynamic
semble produire plus d'infos sous Symbol table '.dynsym'
mais je ne suis pas tout à fait sûr de ce qu'est l'info supplémentaire.
même si je strip
un programme binaire en utilisant -rdynamic
,backtrace_symbols()
continuer à travailler.
Quand strip
supprime tous les symboles du binaire pourquoi laisse-t-il ce qui a été ajouté par le -rdynamic
drapeau ?
modifier: questions de suivi basées sur la réponse de Mat ci-dessous..
Pour le même exemple de code que vous avez pris c'est la différence que je vois avec -g
& -rdynamic
sans aucune 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
-g
il y a plus d'articles, plus d'entrées dans .symtab
tableau .dynsym
reste le même..
[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
-rdynamic
pas de sections de débogage supplémentaires,.symtab entrées sont 70 (de même que la vanille gcc invocation), mais plus .dynsym
entrées..
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
Maintenant, ce sont les questions que j'ai..
dans gdb vous pouvez faire bt pour obtenir le bactrace. Si cela fonctionne avec juste
-g
pourquoi avons-nous besoin d'-rdynamic
pour que backtrace_symbols fonctionne ?Comparaison de la ajouts
.symtab
-g
& ajouts.dynsym
-rdynamic
ils ne sont pas exactement les mêmes.. Ne soit un fournir de meilleures informations de débogage par rapport à l'autre ? FWIW, la taille de la sortie produite est comme ceci: avec -g > avec -rdynamic > ni avec l'optionQuelle est exactement l'utilisation de .dynsym ? Est-ce que tous les symboles exportés par ce binaire ? Dans ce cas, pourquoi est-foo .dynsym parce que nous ne compilons pas le code bibliothèque.
si je lie mon code en utilisant toutes les bibliothèques statiques alors-rdynamic n'est pas nécessaire pour que backtrace_symbols fonctionne ?
1 réponses
selon les docs:
Ceci indique au linker d'ajouter tous les symboles, pas seulement ceux utilisés, à la table de symboles dynamiques.
ce ne sont pas des symboles de débogage, ce sont des symboles de linker dynamique. Ceux-ci ne sont pas enlevés par strip
puisqu'il briserait (dans la plupart des cas) l'exécutable - ils sont utilisés par le linker d'exécution pour faire l'étape finale du lien de votre exécutable.
Exemple:
$ cat t.c
void foo() {}
int main() { foo(); return 0; }
Compiler et lier sans -rdynamic
(et pas des optimisations, évidemment)
$ 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
donc l'exécutable a un .symtab
avec tout. Mais remarquez que .dynsym
ne mentionne pas foo
- c'est l'essentiel. Ce n'est pas de suffisamment d'informations pour backtrace_symbols
au travail. Il s'appuie sur les informations présentes dans cette section pour faire correspondre les adresses de code avec les noms de fonction.
Maintenant compiler -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
Même chose pour les symboles .symtab
, mais maintenant foo
a un symbole dans la section de symbole dynamique (et un tas d'autres symboles y apparaissent aussi maintenant). Cela rend backtrace_symbols
work-it dispose maintenant de suffisamment d'informations (dans la plupart des cas) pour cartographier les adresses de code avec les noms de fonction.
Bande:
$ 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
$
Aucun .symtab
est parti, mais la table de symboles dynamique est toujours là, et l'exécutable s'exécute. Donc backtrace_symbols
fonctionne toujours trop.
la Bande de la dynamique de la table des symboles:
$ 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
... et vous obtenez une fracture de l'exécutable.
Une lecture intéressante pour ce qu' .symtab
et .dynsym
sont utilisés, c'est ici: à l'Intérieur de l'ELFE Tables de symboles. Une des choses à noter est que .symtab
n'est pas nécessaire à l'exécution, il est donc rejeté par le chargeur. Cette section ne reste pas dans la mémoire du processus. .dynsym
, par contre, nécessaire à l'exécution, il est donc conservé dans l'image process. Il est donc disponible pour des choses comme backtrace_symbols
pour recueillir des informations sur l' processus actuel de l'intérieur de lui-même.
Donc en bref:
- symboles dynamiques ne sont pas supprimés par
strip
puisque cela rendrait l'exécutable Non-chargeable backtrace_symbols
nécessite des symboles dynamiques pour comprendre quel code appartient à quelle fonctionbacktrace_symbols
n'utilise pas de symboles de débogage
D'où le comportement que vous avez remarqué.
Pour votre questions:
gdb
est un débogueur. Il utilise les informations de débogage dans l'exécutable et les bibliothèques pour afficher les informations pertinentes. C'est beaucoup plus complexe quebacktrace_symbols
, et inspecte les fichiers sur votre disque dur en plus du live processus.backtrace_symbols
ne fonctionne pas, il est entièrement en cours de traitement-de sorte qu'il ne peut pas accéder aux sections qui ne sont pas chargées dans l'image exécutable. Les sections de débogage ne sont pas chargées dans l'image d'exécution, donc elle ne peut pas utiliser ils..dynsym
n'est pas une section débogage. C'est une section utilisée par le dynamic linker..symbtab
n'est pas non plus une section de débogage, mais elle peut être utilisée par les débogueurs qui ont accès aux fichiers exécutables (et à la bibliothèque).-rdynamic
ne pas générer des sections de débogage, seulement cette table étendue de symboles dynamiques. La croissance exécutable de-rdynamic
dépend entièrement du nombre de symboles dans cet exécutable (et des considérations d'alignement/remplissage). Il devrait être beaucoup moins que-g
.- sauf pour les binaires statiquement liés, les exécutables ont besoin de dépendances externes résolues au moment du chargement. Comme lier
printf
et quelques procédures de démarrage d'application de la bibliothèque C. Ces symboles externes doivent être indiqués quelque part dans l'exécutable: c'est ce que.dynsym
est utilisé pour, et c'est pourquoi le fichier exe a une.dynsym
même si vous ne spécifiez pas-rdynamic
. Lorsque vous ne spécifiez, le linker ajoute d'autres symboles qui ne sont pas nécessaires pour le processus de travail, mais peut être utilisé par des choses commebacktrace_symbols
. backtrace_symbols
ne résoudra aucun nom de fonction si vous faites un lien statique. Même si vous spécifiez-rdynamic
, le.dynsym
la section ne sera pas émise à l'exécutable. Aucune table de symboles n'est chargée dans l'image exécutable, doncbacktrace_symbols
impossible de cartographier les adresses des codes aux symboles.