Jak przekonwertować 32-bitowy zestaw inline gcc Linuksa na kod 64-bitowy? [Zamknięte]
Próbuję się przekonwertowaćDebuger RR0D Rasta Ring 0 z trybu 32-bitowego do trybu 64-bitowego (tryb długi) w systemie Linux, przy użyciu gcc. Jestem zaznajomiony z 32-bitowym zestawem x86 (w środowisku MS-DOS), ale jestem początkującym w 64-bitowym zespole x86 i ogólnie w programowaniu montażu Linuksa.
Ten projekt jest przeznaczony do użytku produkcyjnego (potrzebuję działającego debugera bez źródła), ale próbuję również nauczyć się, jak wykonać konwersję 32-bitową na 64-bitową. Jeśli to możliwe, staram się znaleźć uniwersalny sposób na konwersję 32-bitową na 64-bitową, która mogłaby być wykonana w dowolnym 32-bitowym programie z użyciem wyrażeń regularnych (aby można było zautomatyzować). Wiem, że nie istnieje żadne ogólne rozwiązanie (kod 64-bitowy może zająć więcej miejsca niż kod 32-bitowy itp. I zużywać więcej stosu itp.), Ale nawet w takim przypadku automatycznie skonwertowany kod posłużyłby za punkt wyjścia.
Pomysł polegałby na zachowaniu 8-bitowych i 16-bitowych operandów jako takich i zastąpieniu 32-bitowych argumentów operandami 64-bitowymi. Takie podejście naturalnie zawiedzie, jeślipushw %ax; pushw %bx; popl %ecx
jest zastąpiony przezpushw %ax; pushw %bx; popq %rcx
, ale dobrze zachowane programy zazwyczaj tego nie robiąpush
dwa 16-bitowe operandy, a następniepop
jeden 32-bitowy operand, czy oni?
Oto dotychczasowe konwersje:
Edytować: Naprawić:pusha
/ pushad
mogą być zastąpione przez kolejnepush
'es, bopusha
/ pushad
polecenia przesuwają wartośćsp
/ esp
przed rzeczywisty nacisksp
, ipush sp
działa w ten sam sposób w 286+, ale inaczej w 8088/8086Baza danych języka montażu. Ta różnica nie stanowi tutaj problemu (dla kodu 386+).pusha
ipushad
można zatem zastąpić kolejnympush
polecenia.
Alternatywą jest podobnie jak wOpenSolaris ”privregs.h
kod.
Edytować: Poprawka: użyj 64-bitowego adresowania pamięci dla wszystkich poleceń.
pusha
->push %ax; push %cx; push %dx; push %bx; push %sp; push %bp; push %si; push %di
.
Edytować: Poprawka: prawidłowa alternatywa (użycielea
), zauważ, że procesory x86 są little-endian:pusha
->movq %rax, -8(%rsp); lea -8(%rsp), %rax; mov %ax, -10(%rsp); movq -8(%rsp), %rax; movw %cx, -4(%rsp); movw %dx, -6(%rsp); movw %bx, -8(%rsp); movw %bp, -12(%rsp); movw %si, -14(%rsp); movw %di, -16(%rsp); lea -16(%rsp), %rsp
.
pushad
->push %rax; push %rcx; push %rdx; push %rbx; push %rsp; push %rbp; push %rsi; push %rdi
.
Edytować: Poprawka: poprawna alternatywa (użycielea
):pushad
->movq %rax, -8(%rsp); movq %rcx, -16(%rsp); movq %rdx, -24(%rsp); movq %rbx, -32(%rsp); lea -32(%rsp), %rax; movq %rax, -40(%rsp); movq -8(%rsp), %rax; movq %rbp, -48(%rsp); movq %rsi, -56(%rsp); movq %rdi, -64(%rsp); lea -64(%rsp), %rsp
.
Edytować: Naprawić:popa
ipopad
pop wartośćsp
/ esp
ale odrzuć to (Zestaw instrukcji Intela - popa / popad). Chodźmypop
to dobx
/ rbx
.
popa
->popw %di; popw %si; popw %bp; popw %bx; popw %bx; popw %dx; popw %cx; popw %ax
.
popad
->popq %rdi; popq %rsi; popq %rbp; popq %rbx; popq %rbx; popq %rdx; popq %rcx; popq %rax
.
pushfd
->pushfq
.
popfd
->popfq
.
Edytować: push
rejestrów segmentowych, np.pushw %ds
->pushw %ax; pushw %ax; movw %ds, %ax; movw %ax, 2(%rsp); popw %ax
.
Edytować: pop
rejestrów segmentowych, np.popw %ds
->pushw %ax; movw 2(%rsp), %ax; movw %ax, %ds; popw %ax
.
Edytować: inc %reg16
->add $1, %reg16
, np.inc %ax
->add $1, %ax
.
Edytować: dec %reg16
->sub $1, %reg16
, np.dec %ax
->sub $1, %ax
.
Edytować: inc %reg32
->add $1, %reg64
, np.inc %eax
->add $1, %rax
.
Edytować: dec %reg32
->sub $1, %reg64
, np.dec %eax
->sub $1, %rax
.
Edytować: aaa
->?
Edytować: aad
->?
Edytować: aam
->?
Edytować: aas
->?
Edytować: arpl
->?
Edytować: bound
->?
Edytować: daa
->?
Edytować: das
->?
Edytować: lahf
->?
Edytować: sahf
->?
Edytować Poprawka: dowolne polecenie z bezpośrednim operandem, które nie pasuje do 32-bitowego rozmiaru operandu w trybie 64-bitowym, np.pushl $0xDEADBEEF
->pushq %rax; pushq %rax; movq $0xDEADBEEF, %rax; movq %rax, 8(%rsp); popq %rax
.
ret
z bezpośrednim operandem: myślę, że w tym przypadku kod źródłowy musi zostać cofnięty, aby zobaczyć rozmiary ostatniegopush
ed operandów i działaj odpowiednio, np.pushl %eax; ret 4
->pushq %rax; ret 8
.
Edytować:: wezwania:int $0x80
->pushq %rdi; movq %rbp, %r9; movq %rdi, %r8; movq %rbx, %rdi; xchgq %rcx, %rsi; -- replace %rax value using a substitution list --; syscall; popq %rdi; xchgq %rcx, %rsi
(Uwaga: 32-bitowe wywołania systemowe mogą mieć więcej niż 6 parametrów, 6 w rejestrach, a reszta w stosie, 64-bitowe wywołania systemowe nigdy nie mogą mieć więcej niż 6 parametrów).
Edytować: Co jeszcze należy wziąć pod uwagę? Jakie inne konwersje byłyby potrzebne do konwersji kodu 32-bitowego na kod 64-bitowy (do uruchomienia w trybie długim)?