Linuxでr0DRastaRing 0 Debuggerを32ビットモードから64ビットモード(ロングモード)にgccを使用して変換しようとしています。私はx8632ビットアセンブリ(MS-DOS環境)に精通していますが、x8664ビットアセンブリおよび一般的なLinuxアセンブリプログラミングの初心者です。
このプロジェクトは本番用です(動作する非ソースデバッガーが必要です)が、32ビットから64ビットへの変換方法も学習しようとしています。可能であれば、正規表現を使用して任意の32ビットプログラムで実行できる(自動化できるように)32ビットから64ビットへの変換を実行するための普遍的な方法を見つけようとしています。一般的な解決策は存在しないことを認識しています(64ビットコードは32ビットコードなどよりも多くのスペースを取り、スタックを消費する可能性があります)が、その場合でも、自動的に変換されたコードが出発点として機能します。
アイデアは、8ビットと16ビットのオペランドをそのままにして、32ビットのオペランドを64ビットのオペランドに置き換えることです。pushw %ax; pushw %bx; popl %ecx
このアプローチは、に置き換えると当然失敗しますpushw %ax; pushw %bx; popq %rcx
が、正常に動作するプログラムは通常、push
2つの16ビットオペランドとpop
1つの32ビットオペランドを使用しません。
これまでの変換は次のとおりです。
編集:修正:pusha
/コマンドは/の値を実際のプッシュの前にプッシュするため、 /は連続する'esに置き換えることがpushad
でき、286 +でも同じように機能しますが、8088/8086アセンブリ言語データベースでは動作が異なります。この違いはここでは問題になりません(386以上のコードの場合)。したがって、連続したコマンドに置き換えることができます。push
pusha
pushad
sp
esp
sp
push sp
pusha
pushad
push
別の方法は、 OpenSolarisのprivregs.h
コードと同様です。
編集:修正:すべてのコマンドに64ビットのメモリアドレス指定を使用します。
pusha
->push %ax; push %cx; push %dx; push %bx; push %sp; push %bp; push %si; push %di
。編集:修正:有効な代替手段(を使用
lea
)。x86プロセッサはリトルエンディアンであることに注意してください: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
。編集:修正:有効な代替手段(を使用
lea
):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
。編集:修正:/の値
popa
をpopad
ポップしますが、それを破棄します(Intel命令セット-popa / popad)。/に入れましょう。sp
esp
pop
bx
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
。編集:
push
セグメントレジスタの、例えば。pushw %ds
->pushw %ax; pushw %ax; movw %ds, %ax; movw %ax, 2(%rsp); popw %ax
。編集:
pop
セグメントレジスタの、例えば。popw %ds
->pushw %ax; movw 2(%rsp), %ax; movw %ax, %ds; popw %ax
。編集:
inc %reg16
->add $1, %reg16
、例えば。inc %ax
->add $1, %ax
。編集:
dec %reg16
->sub $1, %reg16
、例えば。dec %ax
->sub $1, %ax
。編集:
inc %reg32
->add $1, %reg64
、例えば。inc %eax
->add $1, %rax
。編集:
dec %reg32
->sub $1, %reg64
、例えば。dec %eax
->sub $1, %rax
。編集:
aaa
->?編集:
aad
->?編集:
aam
->?編集:
aas
->?編集:
arpl
->?編集:
bound
->?編集:
daa
->?編集:
das
->?編集:
lahf
->?編集:
sahf
->?編集修正:64ビットモードの32ビットオペランドサイズに適合しない直接オペランドを持つコマンド。
pushl $0xDEADBEEF
->pushq %rax; pushq %rax; movq $0xDEADBEEF, %rax; movq %rax, 8(%rsp); popq %rax
。ret
push
即値オペランドの場合:この場合、最後に編集されたオペランドのサイズを確認するためにソースコードをバックトレースし、それに応じて動作する必要があると思います。pushl %eax; ret 4
->pushq %rax; ret 8
。編集:: syscalls:
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
(注:32ビットのsyscallには6つを超えるパラメーターがあり、6つはレジスターにあり、残りはスタックにあります。64ビットのsyscallsには6つを超えるパラメーターがない場合があります)。
編集:他に何を考慮に入れるべきですか?32ビットコードを64ビットコードに変換する(ロングモードで実行する)には、他にどのような変換が必要ですか?