Ich bin mir nicht sicher, was eine gute Betreffzeile für diese Frage ist, aber hier gehen wir ...x86_64: Ist es möglich PLT/GOT Referenzen "in-line" zu ersetzen?
Um Codelokalität/Kompaktheit für einen kritischen Abschnitt des Codes zu erzwingen, suche ich nach einem Weg um eine Funktion in einer externen (dynamisch geladenen) Bibliothek durch einen "Sprungschlitz" (eine ELF R_X86_64_JUMP_SLOT
Verlagerung) direkt an der Aufrufstelle aufzurufen - was der Linker normalerweise in PLT/GOT eingibt, aber diese direkt an der Aufrufstelle inlined hat .
Wenn ich emulieren der Aufruf wie:
#include <stdio.h>
int main(int argc, char **argv)
{
asm ("push $1f\n\t"
"jmp *0f\n\t"
"0: .quad %P0\n"
"1:\n\t"
: : "i"(printf), "D"("Hello, World!\n"));
return 0;
}
den Platz für ein 64-Bit-Wort zu erhalten, wird der Anruf selbst funktioniert (bitte keine Kommentare zu dieser ist glücklicher Zufall, da dies bestimmte ABI Regeln bricht - das alles sind nicht Gegenstand dieser Frage ... und kann, für meinen Fall, auf andere Weise bearbeitet/angesprochen werden, versuche ich, dieses Beispiel kurz zu halten).
Es wird folgender Montage:
0000000000000000 <main>: 0: bf 00 00 00 00 mov $0x0,%edi 1: R_X86_64_32 .rodata.str1.1 5: 68 00 00 00 00 pushq $0x0 6: R_X86_64_32 .text+0x19 a: ff 24 25 00 00 00 00 jmpq *0x0 d: R_X86_64_32S .text+0x11 ... 11: R_X86_64_64 printf 19: 31 c0 xor %eax,%eax 1b: c3 retqaber (wegen
printf
als unmittelbare zu verwenden, schätze ich ...?) Die Zieladresse ist hier noch, dass der PLT Haken - die gleiche
R_X86_64_64
reloc. Verknüpfen der Objektdatei mit libc in einer tatsächlichen ausführbaren Datei ergibt:
0000000000400428 <[email protected]>: 400428: ff 25 92 04 10 00 jmpq *1049746(%rip) # 5008c0 <_GLOBAL_OFFSET_TABLE_+0x20> [ ... ] 0000000000400500 <main>: 400500: bf 0c 06 40 00 mov $0x40060c,%edi 400505: 68 19 05 40 00 pushq $0x400519 40050a: ff 24 25 11 05 40 00 jmpq *0x400511 400511: [ .quad 400428 ] 400519: 31 c0 xorl %eax, %eax 40051b: c3 retq [ ... ] DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE [ ... ] 00000000005008c0 R_X86_64_JUMP_SLOT printfI.e. Dies gibt immer noch die zweistufige Umleitung, die erste Übertragungsausführung an den PLT-Hook, und springt dann in den Bibliothekseinstiegspunkt.
Gibt es eine Möglichkeit, wie ich den Compiler/Assembler/Linker anweisen kann - in diesem Beispiel - "Inline" das Sprungschlitzziel unter der Adresse 0x400511
? I.e. Ersetze die "lokale" (aufgelöst zur Programmverbindungszeit durch ld
) R_X86_64_64
verlagern mit der "remote" (aufgelöst zur Programmladezeit durch ld.so
) R_X86_64_JUMP_SLOT
eins (und erzwinge nicht-Lazy-Load für diesen Abschnitt des Codes)? Vielleicht können Linker-Mapfiles dies ermöglichen - wenn ja, wie?
Edit:
Um dies deutlich zu machen, ist die Frage, wie dieses Ziel zu erreichen in einem dynamisch verknüpften ausführbaren/für eine externe Funktion, die in einer dynamischen Bibliothek nur verfügbar ist. Ja, es ist wahr statische Linken dies auf einfachere Art und Weise löst, aber:
- gibt es Systeme (wie Solaris), wo statische Bibliotheken werden in der Regel nicht vom Hersteller geliefert
- es Bibliotheken, die als nicht verfügbar sind entweder Sourcecode oder statische Versionen
Daher statisch Linke sind hier nicht hilfreich :(
Edit2:
ich gefunden habe, dass In einigen Architekturen (SPARC, bemerkenswerterweise, siehe section on SPARC relocations in the GNU as manual) ist GNU as in der Lage, bestimmte Arten von Verschiebungsreferenzen für den Linker direkt zu erzeugen, indem Modifikatoren verwendet werden. Mit dem zitierten SPARC würde man %gdop(symbolname)
verwenden, um den Assembler dazu zu bringen, Anweisungen an den Linker zu senden, in dem es heißt: "Lege diese Verlagerung genau hier an". Intels Assembler auf Itanium kennt die @fptr(symbol)
link-relocation operator für die gleiche Sache (siehe auch Abschnitt 4 in der Itanium psABI). Aber gibt es einen äquivalenten Mechanismus - etwas, um den Assembler anzuweisen, einen spezifischen Linker-Verschiebungstyp an einer bestimmten Position im Code zu emittieren - existiert für x86_64?
Ich habe auch gefunden, dass der GNU Assembler eine .reloc
Direktive hat, die angeblich für diesen Zweck verwendet werden soll; noch, wenn ich versuche:
#include <stdio.h>
int main(int argc, char **argv)
{
asm ("push %%rax\n\t"
"lea 1f(%%rip), %%rax\n\t"
"xchg %%rax, (%rsp)\n\t"
"jmp *0f\n\t"
".reloc 0f, R_X86_64_JUMP_SLOT, printf\n\t"
"0: .quad 0\n"
"1:\n\t"
: : "D"("Hello, World!\n"));
return 0;
}
ich einen Fehler von dem Linker erhalten (beachten Sie, dass 7 == R_X86_64_JUMP_SLOT
):
error: /tmp/cc6BUEZh.o: unexpected reloc 7 in object fileDer Assembler eine Objektdatei erzeugt, für die
readelf
sagt:
Relocation section '.rela.text.startup' at offset 0x5e8 contains 2 entries: Offset Info Type Symbol's Value Symbol's Name + Addend 0000000000000001 000000050000000a R_X86_64_32 0000000000000000 .rodata.str1.1 + 0 0000000000000017 0000000b00000007 R_X86_64_JUMP_SLOT 0000000000000000 printf + 0Das ist, was ich will - aber den Linker nimm es nicht.
Der Linker tut akzeptieren nur mit
R_X86_64_64
statt oben; Das erzeugt die gleiche Art von Binärdatei wie im ersten Fall ... Umleiten an
[email protected]
nicht die "aufgelöste" 1 ...
was ist mit Vorverbinden? http://en.wikipedia.org/wiki/Prelink – JohnTortugo
Siehe auch: [versucht PLT-Indirection für Anrufe zu vermeiden * innerhalb * einer einzigen gemeinsam genutzten Bibliothek] (http://stackoverflow.com/questions/36354247/how-do- i-force-gcc-zu-Anruf-eine-Funktion-direkt-im-Bild-Code). –