2013-05-07 5 views

Antwort

7

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:

  1. qsort() in der C-Standardbibliothek Aufruf der benutzerdefinierten Vergleichsfunktion
  2. 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.

0

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.

+0

Und 'Schalter' und Funktion Zeiger Aufrufe. –