Nie jestem pewien, co jest dobrym tematem dla tego pytania, ale tutaj ...x86_64: Czy możliwe jest "zastępowanie w linii" referencji PLT/GOT?
W celu wymuszenia lokalizacji kodu/zwartości dla krytycznego fragmentu kodu, szukam sposobu wywoływanie funkcji w zewnętrznej (dynamicznie ładowanej) bibliotece przez "slot skoku" (przeniesienie ELF R_X86_64_JUMP_SLOT
) bezpośrednio na stronę wywołania - co linker zwykle umieszcza w PLT/GOT, ale ma te umieszczone bezpośrednio na stronie połączenia .
Gdybym emulować wywołanie jak:
#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;
}
uzyskać przestrzeń dla słowa 64-bitowego, sama rozmowa działa (proszę, bez komentarzy na temat tej istoty szczęśliwym zbiegiem okoliczności, ponieważ łamie pewne zasady ABI - wszystko to nie są przedmiotem niniejszej pytanie ... i, w moim przypadku, można pracować nad innymi adresami, staram się zachować ten krótki przykład).
Tworzy następujący zestaw:
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 retqAle (z powodu korzystania
printf
jako natychmiastowe, chyba ...?) Adres docelowy jest tu nadal, że haka PLT - ten sam
R_X86_64_64
reloc. Łączenie pliku obiektu z libc do rzeczywistego pliku wykonywalnego daje w wyniku:
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 printf, tj. nadal daje to dwukierunkowe przekierowanie, pierwsze wykonanie transferu do haka PLT, a następnie przeskoczenie do punktu wejścia biblioteki.
Czy istnieje sposób, w jaki mogę polecić kompilatorowi/assemblerowi/łącznikowi do - w tym przykładzie - "inline" docelowego gniazda skoku pod adresem 0x400511
? To znaczy. zastąpić "lokalny" (rozwiązany w czasie połączenia programu przez ld
) R_X86_64_64
przenieść z "zdalnego" (rozwiązany w czasie ładowania programu przez ld.so
) R_X86_64_JUMP_SLOT
jeden (i wymusić non-lazy-load dla tej sekcji kodu)? Może pliki map linkerów mogą to umożliwić - jeśli tak, to w jaki sposób?
Edit:
Aby to jasne, pytanie o to, jak to osiągnąć w dynamicznie połączonej wykonywalnego/do zewnętrznej funkcji, która jest dostępna tylko w dynamicznej biblioteki. Tak, to prawda statyczne powiązanie rozwiązuje to w prostszy sposób, ale:
- istnieją systemy (jak Solaris) gdzie biblioteki statyczne nie są zazwyczaj dostarczane przez sprzedawcę
- istnieją biblioteki, które nie są dostępne albo sourcecode lub wersje statyczne
Stąd statyczne powiązanie nie jest pomocne tutaj :(
Edit2:
Odkryłam, że w niektórych architekturach (SPARC, zauważalnie, patrz section on SPARC relocations in the GNU as manual), GNU as jest w stanie utworzyć pewne typy odwołań relokacji dla łącznika w miejscu przy użyciu modyfikatorów . Cytowany SPARC użyje %gdop(symbolname)
, aby zmusić asembler do wysłania instrukcji do linkera z napisem "stwórz tutaj relokację". Asembler Intela na Itanium zna @fptr(symbol)
link-relocation operator dla tego samego rodzaju rzeczy (patrz także sekcja 4 w Itanium psABI). Ale czy mechanizm równoważny - coś, co nakazuje asemblerowi emitowanie określonego typu relokacji linkera na określonej pozycji w kodzie - istnieje dla x86_64?
Odkryłem również, że asembler GNU ma dyrektywę .reloc
, która podobno ma być używana do tego celu; Nadal, jeśli spróbuję:
#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;
}
pojawia się błąd z łącznikiem (zauważ, że 7 == R_X86_64_JUMP_SLOT
):
error: /tmp/cc6BUEZh.o: unexpected reloc 7 in object fileAssembler tworzy plik obiektu, dla którego
readelf
mówi:
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 + 0To jest to, co chcę - ale linker nie bierze tego.
Łącznik ma zaakceptować tylko za pomocą
R_X86_64_64
zamiast powyżej; w ten sposób tworzy się ten sam rodzaj binarny jak w pierwszym przypadku ... przekierowanie do
[email protected]
nie "rozwiązane" ...
co z prelinkowaniem? http://en.wikipedia.org/wiki/Prelink – JohnTortugo
Zobacz też: [próbuje uniknąć indeksu PLT dla połączeń * w * jednej wspólnej bibliotece] (http://stackoverflow.com/questions/36354247/how-do- i-force-gcc-to-call-a-function-bezpośrednio-w-pic-code). –