Mit Blick auf die Ausgabe von objdump -d ELFfile
konnte ich nicht zwischen direkten und indirekten Jumps/Anrufe unterscheiden. Irgendwelche Vorschläge?direkte und indirekte Aufrufe/Sprünge in der Ausgabe von objdump
Antwort
Indirekte Anrufe und Sprünge haben ein *
nach der Anweisung und vor der Position wie in callq *%r13
und jmpq *0x204d8a(%rip)
.
Ich zeige es Ihnen zwei echte Beispiele aus meiner x86-64 Linux-Rechner:
- qsort() in der C-Standardbibliothek Aufruf der benutzerdefinierten Vergleichsfunktion
- Ein dynamisch ausführbaren calling verknüpft strcmp()
Die qsort() Implementierung in GLIBC ruft tatsächlich eine unterschiedliche Reihenfolge ein Algorithmen abhängig von der Eingabegröße. Eine solche Implementierung ist msort_with_tmp() in /lib64/libc.so.6:
0000003cbde37d70 <msort_with_tmp.part.0>:
<...>
3cbde37dd6: 4c 8b 68 10 mov 0x10(%rax),%r13
<...>
3cbde37e2f: 41 ff d5 callq *%r13
Der Codeausschnitt oben bewegt die Adresse der Vergleichsfunktion in R13 und schließlich macht einen indirekten Aufruf.
Für eine dynamisch verknüpfte ausführbare Aufruf strcmp(), werde ich /bin/true als Beispiel verwenden. Alle Anrufe zu strcmp() im Hauptprogramm wird in einen Aufruf der PLT-Stub übersetzt, strcmp @ plt:
$ gdb /bin/true
(gdb) disassemble '[email protected]'
0x401350 <+0>: ff 25 8a 4d 20 00 jmpq *0x204d8a(%rip) # 0x6060e0 <[email protected]>
0x401356 <+6>: 68 19 00 00 00 pushq $0x19
0x40135b <+11>: e9 50 fe ff ff jmpq 0x4011b0
In der ersten Anweisung, 0x204d8a (% rip) verwendet RIP relative Adressierung zu lokalisieren [email protected].
Wenn wir versuchen, zu prüfen, welchen Wert [email protected] zur Laufzeit gilt:
(gdb) break *0x401350
(gdb) run --XXX
Breakpoint 1, 0x0000000000401350 in [email protected]()
(gdb) p/a '[email protected]'
$1 = 0x3cbdf2fbe0 <__strcmp_sse42>
(gdb) break *0x3cbdf2fbe0
Breakpoint 2 at 0x3cbdf2fbe0: file ../sysdeps/x86_64/multiarch/strcmp-sse42.S, line 128.
(gdb) continue
Continuing.
Breakpoint 2, __strcmp_sse42()
at ../sysdeps/x86_64/multiarch/strcmp-sse42.S:128
128 mov %esi, %ecx
Wir sehen, dass [email protected] Punkte __strcmp_sse42() in /usr /lib64/libc.so.6.
Damit ist die erste indirekte Sprung trafen wir uns, jmpq * 0x204d8a (% rip) in strcmp @ plt, landet Springen zu __strcmp_sse42(). Dies ist der STT_GNU_IFUNC Mechanismus in Aktion. Es verwendet den dynamischen Linker, um die am besten geeignete strcmp() Variante zur Laufzeit basierend auf CPU-Fähigkeiten zu finden.
Auf x86-64 CPUs sind die Aufruf- und Sprungbefehle implizit% rip relativ.
So sind die relevanten Modi sind:
jmpq $6 # Direct, relative: Jump to %rip+0x6
jmpq *$6 # Direct, absolute: Jump to 0x6
jmpq %r13 # Indirect, relative: Jump to %rip+%r13
jmpq *%r13 # Indirect, absolute: Jump to %r13. Aka "movq %r13, %rip"
Und dann die doppelt indirekte Modi:
jmpq 0x20(%r13) # Jump to %rip + *(%r13 + 0x20).
jmpq *0x20(%r13) # Jump to *(%r13 + 0x20)
Der letzte ist Adressierungsart sehr häufig in C gesehen ++ Demontage als
callq *0x20(%r13)
Dabei enthält% r13 die Adresse einer vtable. Es sieht also den Eintrag in der Vtable bei Offset 0x20 nach und ruft dann die Funktion auf, auf die der Eintrag zeigt. Es ist immer absoluter Modus (d. H. Nicht% relative Rip), da die vtable von mehreren Call-Sites verwendet wird, so dass% rip relativ keinen Sinn ergibt.
Und 'Schalter' und Funktion Zeiger Aufrufe. –
http://stackoverflow.com/questions/9223756/what-does-anasterisk-before-an-address-mean-in-x86-64-att-assembly –