0x00000000004004b6 <main+30>: callq 0x400398 <printf@plt>
Weiß jemand Bescheid?
AKTUALISIEREN
Warum disas printf
geben mir zwei unterschiedliche Ergebnisse?
(gdb) disas printf
Dump of assembler code for function printf@plt:
0x0000000000400398 <printf@plt+0>: jmpq *0x2004c2(%rip) # 0x600860 <_GLOBAL_OFFSET_TABLE_+24>
0x000000000040039e <printf@plt+6>: pushq $0x0
0x00000000004003a3 <printf@plt+11>: jmpq 0x400388
(gdb) disas printf
Dump of assembler code for function printf:
0x00000037aa44d360 <printf+0>: sub $0xd8,%rsp
0x00000037aa44d367 <printf+7>: mov %rdx,0x30(%rsp)
0x00000037aa44d36c <printf+12>: movzbl %al,%edx
0x00000037aa44d36f <printf+15>: mov %rsi,0x28(%rsp)
0x00000037aa44d374 <printf+20>: lea 0x0(,%rdx,4),%rax
0x00000037aa44d37c <printf+28>: lea 0x3f(%rip),%rdx # 0x37aa44d3c2 <printf+98>
objdump
Ich stelle mir vor?Antworten:
Auf diese Weise können Codekorrekturen durchgeführt werden (Anpassen von Adressen basierend auf dem Speicherort des Codes im virtuellen Speicher, die je nach Prozess unterschiedlich sein können), ohne dass für jeden Prozess eine separate Kopie des Codes verwaltet werden muss. Das PLT ist die Prozedurverknüpfungstabelle , eine der Strukturen, die das dynamische Laden und Verknüpfen einfacher macht.
printf@plt
ist eigentlich ein kleiner Stub, der (irgendwann) die eigentlicheprintf
Funktion aufruft und Dinge auf dem Weg modifiziert, um nachfolgende Aufrufe schneller zu machen.Die reale
printf
Funktion kann an einer beliebigen Stelle in einem bestimmten Prozess (virtueller Adressraum) abgebildet werden, ebenso wie der Code, der versucht, sie aufzurufen.Um eine ordnungsgemäße gemeinsame Nutzung von Code für aufrufenden Code (linke Seite unten) und aufgerufenen Code (rechte Seite unten) zu ermöglichen, möchten Sie keine Korrekturen direkt auf den aufrufenden Code anwenden, da dies die Position des aufrufenden Codes einschränkt andere Prozesse.
Es handelt sich also
PLT
um einen kleineren prozessspezifischen Bereich mit einer zur Laufzeit zuverlässig berechneten Adresse, der nicht von Prozessen gemeinsam genutzt wird. Daher kann jeder Prozess ihn beliebig ändern, ohne dass dies nachteilige Auswirkungen hat.Untersuchen Sie das folgende Diagramm, das sowohl Ihren Code als auch den Bibliothekscode zeigt, der verschiedenen virtuellen Adressen in zwei verschiedenen Prozessen zugeordnet ist,
ProcA
undProcB
:Dieses spezielle Beispiel zeigt einen einfachen Fall, in dem das PLT einem festen Ort zugeordnet ist. In Ihrem Szenario befindet es sich relativ zum aktuellen Programmzähler, wie aus Ihrer relativen Suche nach Programmzählern hervorgeht:
Ich habe gerade eine feste Adressierung verwendet, um das Beispiel einfacher zu halten.
Die ursprüngliche Art und Weise , in dem Code geteilt wurde gemeint , sie hatten an dem zu ladende gleicht jeden Prozess in jedem virtuellen Adressraum Speicherplatz , die es verwendete. Entweder das oder es konnte nicht freigegeben werden, da das Korrigieren der einzelnen freigegebenen Kopie für einen Prozess andere Prozesse, bei denen sie einem anderen Speicherort zugeordnet wurden, vollständig überfüllte.
Durch die Verwendung von positionsunabhängigem Code zusammen mit dem PLT und einer globalen Offset-Tabelle (GOT) ist der erste Aufruf einer Funktion
printf@plt
(im PLT) eine mehrstufige Operation, in der die folgenden Aktionen ausgeführt werden:printf@plt
den PLT an.printf
und nicht an den PLT-Setup-Code gerichtet werden.printf
Code an der richtigen Adresse für diesen Vorgang aufgerufen.Bei nachfolgenden Aufrufen wird der mehrstufige Ansatz vereinfacht, da der GOT-Zeiger geändert wurde:
printf@plt
den PLT an.printf
.Ein guter Artikel kann gefunden werden hier , die beschreibt , wie
glibc
zur Laufzeit geladen wird.quelle
disas printf
geben mir zwei unterschiedliche Ergebnisse?r
break
Ich bin mir nicht sicher, aber wahrscheinlich macht das, was Sie gesehen haben, Sinn. Wenn Sie den Befehl disas zum ersten Mal ausführen, wird printf noch nicht aufgerufen, sodass es nicht aufgelöst wird. Sobald Ihr Programm die printf-Methode aufruft, wenn das GOT zum ersten Mal aktualisiert wird, wird das printf aufgelöst und das GOT zeigt auf die eigentliche Funktion. Daher zeigt der nächste Aufruf des Befehls disas die tatsächliche printf-Assembly.
quelle