So weit ich weiß, sind .dynsym und .dynstr im Prinzip das gleiche wie .symtab und .strtab, enthalten aber speziell die Symbole, die zum dynamischen Linken relevant sind, d.h. die exportierten Symbole. Der Vorteil einer solchen Trennung ist, dass man beim Relozieren / dynamischen Linken nur diese exportierten Symbole nach einem Treffer durchsuchen muss und sie damit von den lokalen Symbolen getrennt hat.
Hier ein Auszug aus meinem Quelltext am Beispiel der IA32-Architektur:
http://sourceforge.net/p/xenos/code/HEAD/tree/trunk/kernel/arch/x86/ia32/I386TaskManager.cpp#l236In .rel.dyn des Executables findest du eine Liste mit Relokationen, d.h. Stellen im Programmtext, an denen eine Adresse aus der Symboltabelle eingesetzt werden muss. Jede davon zeigt auf ein Symbol aus einer Symboltabelle (die findest du aus dem Link-Feld der Relationstabelle) mit weiteren Infos. Die werden hier ab Zeile 238 gesucht und es wird geprüft, ob es sich um eine Relokationstabelle handelt, und ob auf eine dynamische Symboltabelle verwiesen wird. In 240-242 werden dann die Links zur Relationstabelle, Symboltabelle und Stringtabelle geholt - letztere findest du aus dem Link-Feld der Symboltabelle. Ab 244 wird dann die Relokationstabelle durchsucht. Es wird überprüft, um was für einen Relokationstyp es sich handelt (in diesem Fall ist nur R_386_JMP_SLOT von Bedeutung) und der Index in die Symboltabelle abgefragt. Ab 252 werden dann die exportieren Symbole der Bibliothek (in meinem Beispiel ist das der Kernel, bzw. dessen Low-Level-API, der diese Symbole exportiert) durchsucht und in 254 auf Treffer überprüft. In 256 wird schließlich der gefundene Wert an die Stelle gesetzt, auf die in der Relokation verwiesen wird - die dortige Formel hängt davon ab, welcher Relokationstyp vorliegt, in dem Fall eben R_386_JMP_SLOT.
Bei x86_64 sieht das so ähnlich aus:
http://sourceforge.net/p/xenos/code/HEAD/tree/trunk/kernel/arch/x86/amd64/X86_64TaskManager.cpp#l228