在x64操作系统上运行x86汇编代码是否可行?

11

最近我决定尝试基本的x86汇编语言,以便更容易调试程序等等。所以我开始(大约一周前)学习x86汇编语言。在此期间,我升级了计算机到8GB内存,因此我的x86 Windows XP安装浪费了所有内存,现在我正在运行一个x64 Windows 7副本,所以问题是:

在x64操作系统上能否使用x86汇编?它会在仿真器中正常运行吗?还是应该学习x64汇编语言?


我想在这个问题上免费提供一些意见(似乎很相关且不会打扰):在世界上有许多x86-32的资源。在汇编级别上,32/64之间似乎没有太大的区别。考虑到32位材料的丰富性,是否值得挖掘64位资源并真正集中精力学习64位(假设一个人想要学习64位),或者,由于(至少看起来)重要的概念都在32位中,只有像64位寄存器这样的东西真正重要,因此仅限于32位对于仅进行casua的限制是可以接受的。 - Kevin Won
不是太多。但是如果你使用编译器,情况就会发生改变。调用约定和ABI不同,X86_64上强制使用的SSE2意味着它实际被使用。而像PIC之类的东西也相当不同。尽管如此,这些差异仍然是可控的。 - Marco van de Voort
Marco,我不太确定我是否理解正确:你是说你认为64位与32位之间的概念差异如此微不足道,以至于学习汇编语言的人可以安全地忽略它们,只需专注于32位而无需担心在转向64位时需要重新学习“旧”方式吗? - Kevin Won
你其实不需要“重新学习”什么。学习栈参数(传统的32位)和寄存器参数(64位)的调用约定都是有意义的,而64位的调用约定在使用寄存器不足时确实必须使用栈参数,例如对于具有超过6个整数参数的函数。先学习32位并不是一个坏主意;在那里有些事情更简单。(但在现代调用约定中保持16字节的堆栈对齐比64位中的8字节推送更丑陋,因为它以4字节为单位。) - Peter Cordes
3个回答

19

在x64操作系统上是否可以使用x86汇编语言工作?它在模拟器中能正常运行吗?

是的,可以并且可以正常运行。指令集体系结构始终向后兼容。

x86-64寄存器:

alt text
(来源:usenix.org)

例如: 您可以看到,rax是新的64位通用寄存器,但您仍然可以使用eax,因为它对应于rax的低32位。

还是我应该学习x64汇编语言?

x86-32架构是x86-64的子集。就像您先学习x86,然后再去了解x86-64汇编语言中的新内容。 一旦您学会了x86汇编语言,那么这将是一个有用的资源:http://www.cs.cmu.edu/~fp/courses/15213-s06/misc/asm64-handout.pdf


rax 中的 r 代表什么?我知道 e 代表扩展。 - kizzx2
1
@kizzx2:r 代表寄存器。 e 代表扩展。如果你去其他的 ISAs,你会发现像 r1、r2、r3 这样的寄存器名称。 - claws
1
视觉效果总是能让答案更好。 - Mert Akcakaya
很好的回答,附有易懂的图表。 - weefwefwqg3
x86 ISA总是向后兼容,因为这是它的关键特点/卖点(以及快速x86-64 CPU的存在也使其继续存在)。一些AArch64芯片已经放弃了对ARM32模式的支持。因此,通常情况下指令集架构并不总是向后兼容。MIPS64r6甚至重新组织了一些现有模式中的操作码,因此它是一种单独的不兼容CPU,只能与早期MIPS在asm源级别兼容。 - Peter Cordes

14

是的,当然可以。大多数程序仍然是32位的,并且在64位Windows系统上运行良好。这些程序是机器语言编写的,具有与汇编语言一一对应的映射关系(并且可以轻松地反汇编为x86汇编代码)。


谢谢,有了这个,我现在可以无后顾之忧地继续进行了。 - user252778

2

如果编译选项为:

Linux 明确实现了 32 位支持。

请注意保留 HTML 标签。

CONFIG_IA32_EMULATION=y

已设置。

大多数合理的发行版都会这样做,包括Ubuntu 14.04。

32位模拟当然是可能的,因为x86-64处理器设计成向后兼容32位可执行文件,通过32位模拟模式,内核知道如何使用。

另一件你需要担心的事情是库:要编译32位程序,你需要32位库。在Ubuntu 14.04 AMD64上:

sudo apt-get install gcc-multilib

然后我们可以轻松地通过一个hello world来测试它:
#include <stdio.h>
#include <stdlib.h>

int main() {
    puts("hello world");
    return EXIT_SUCCESS;
}

并且:

gcc -m32 hello_world.c
./a.out

打印出:

hello world

并且:

file a.out

确认它是32位的:

ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=358f7969deeb2f24a8dd932a0d296887af4eae30, not stripped

Windows Subsystem for Linux并不会这样做;Windows内核中的仿真层表现得像CONFIG_IA32_EMULATION=n的Linux。它无法运行32位二进制文件或64位代码中的32位int 0x80系统调用(首先没有人应该这样做,但新手编写的汇编代码有时会这样做)。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接