11

我正在尝试使用 gcc 在 Linux中将 RR0D Rasta Ring 0 调试器从 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的 'es,因为pusha/pushad命令在实际推送之前sp推送/的值,并且在 286+ 中的工作方式相同,但在 8088/8086 The Assembly Language database中的工作方式不同。这种差异在这里不是问题(对于 386+ 代码)。因此可以用连续的命令代替。esp sppush sppushapushadpush

另一种方法与OpenSolaris 的privregs.h代码类似。

编辑:修复:对所有命令使用 64 位内存寻址。

  1. pusha-> push %ax; push %cx; push %dx; push %bx; push %sp; push %bp; push %si; push %di

    编辑:修复:一个有效的替代方案(使用lea),请注意 x86 处理器是 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

  2. 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

    编辑:修复:popapopad弹出sp/的值esp但将其丢弃(英特尔指令集 - popa/popad)。让我们pop进入bx/ rbx

  3. popa-> popw %di; popw %si; popw %bp; popw %bx; popw %bx; popw %dx; popw %cx; popw %ax

  4. popad-> popq %rdi; popq %rsi; popq %rbp; popq %rbx; popq %rbx; popq %rdx; popq %rcx; popq %rax

  5. pushfd-> pushfq

  6. popfd-> popfq

  7. 编辑: push段寄存器,例如。pushw %ds-> pushw %ax; pushw %ax; movw %ds, %ax; movw %ax, 2(%rsp); popw %ax

  8. 编辑: pop段寄存器,例如。popw %ds-> pushw %ax; movw 2(%rsp), %ax; movw %ax, %ds; popw %ax

  9. 编辑: inc %reg16 -> add $1, %reg16,例如。inc %ax-> add $1, %ax

  10. 编辑: dec %reg16 -> sub $1, %reg16,例如。dec %ax-> sub $1, %ax

  11. 编辑: inc %reg32 -> add $1, %reg64,例如。inc %eax-> add $1, %rax

  12. 编辑: dec %reg32 -> sub $1, %reg64,例如。dec %eax-> sub $1, %rax

  13. 编辑: aaa ->?

  14. 编辑: aad ->?

  15. 编辑: aam ->?

  16. 编辑: aas ->?

  17. 编辑: arpl ->?

  18. 编辑: bound ->?

  19. 编辑: daa ->?

  20. 编辑: das ->?

  21. 编辑: lahf ->?

  22. 编辑: sahf ->?

  23. 编辑修复:任何带有直接操作数的命令在 64 位模式下不适合 32 位操作数大小,例如。pushl $0xDEADBEEF-> pushq %rax; pushq %rax; movq $0xDEADBEEF, %rax; movq %rax, 8(%rsp); popq %rax

  24. ret使用立即操作数:我认为在这种情况下,必须回溯源代码以查看 last pushed 操作数的大小,并采取相应的行动,例如。pushl %eax; ret 4-> pushq %rax; ret 8

  25. 编辑::系统调用: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 位系统调用可能有超过 6 个参数,6 个在寄存器中,其余在堆栈中,64 位系统调用可能永远不会有超过 6 个参数)。

编辑:还应该考虑什么?将 32 位代码转换为 64 位代码(以长模式运行)还需要哪些其他转换?

4

0 回答 0