我正在尝试使用gcc在Linux中将RR0D Rasta Ring 0 Debugger从32位模式转换为64位模式(长模式)。我熟悉x86 32位程序集(在MS-DOS环境中),但我是x86 64位程序集和Linux程序集编程的初学者。
这个项目是供生产使用的(我需要一个可用的非源调试器),但我也尝试学习如何进行32位到64位的转换。如果可能的话,我试图找到一种通用的方法来进行32位到64位的转换,可以使用正则表达式在任何32位程序上完成(这样它就可以自动化)。我知道没有通用的解决方案(64位代码可能占用比32位代码更多的空间等,并消耗更多的堆栈等),但即使在这种情况下,自动转换的代码也可作为起点。
这个想法是按原样保留8位和16位操作数,并用64位操作数替换32位操作数。如果用pushw %ax; pushw %bx; popl %ecx
替换pushw %ax; pushw %bx; popq %rcx
,这种方法自然会失败,但是行为良好的程序通常不会push
两个16位操作数,然后pop
一个32位操作数,还是他们?。
这些是到目前为止的转化次数:
修改修复:pusha
/ pushad
可以替换为连续的push
,因为{{1} } / pusha
命令在实际推送pushad
之前推送sp
/ esp
的值,而sp
的工作方式相同在286 +中的方式,但在8088/8086 The Assembly Language database中有所不同。这种差异不是问题(对于386+代码)。因此push sp
和pusha
可以用连续的pushad
命令替换。
替代方案与OpenSolaris' privregs.h
code类似。
编辑:修复:对所有命令使用64位内存寻址。
push
- > pusha
。
修改修复:有效的替代方案(使用push %ax; push %cx; push %dx; push %bx; push %sp; push %bp; push %si; push %di
),请注意x86处理器是little-endian:lea
- > 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
/ sp
的值但丢弃它(Intel instruction set - popa/popad) 。我们将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
- >
编辑修复:任何具有直接操作数的命令,在64位模式下不适合32位操作数大小,例如。 sahf
- > pushl $0xDEADBEEF
。
pushq %rax; pushq %rax; movq $0xDEADBEEF, %rax; movq %rax, 8(%rsp); popq %rax
:我认为在这种情况下,必须回溯源代码以查看最后ret
个ed操作数的大小,并相应地采取行动,例如。 push
- > pushl %eax; ret 4
。
修改:系统调用:pushq %rax; ret 8
- > int $0x80
(注意:32位系统调用可能有6个以上的参数,6个在寄存器中,其余的在堆栈中,64位系统调用可能永远不会超过6个参数)。
修改:还应该考虑哪些因素?将32位代码转换为64位代码(以长模式运行)需要进行哪些其他转换?