在Intel Atom系统编译6502模拟器遇x86汇编错误及movw合法性疑问
为什么
movw di, [ebp+4]在你的编译环境下是非法指令? 你遇到的核心问题不是32/64位兼容性,而是汇编器语法风格不匹配——原来的代码是用NASM/YASM这类Intel风格汇编器的语法写的,但你用GCC内置的汇编器是GAS(采用AT&T语法),两者在指令格式、操作数顺序、符号表示上有本质区别。
逐个拆解你的错误:
错误:
movb ch, [ ebp+9]无效
在NASM(Intel语法)里,指令格式是mov 目的, 源,寄存器直接写名字,内存地址用[基址+偏移];但GAS(AT&T语法)正好反过来:- 操作数顺序是源在前,目的在后
- 寄存器名必须加
%前缀 - 内存地址格式是
偏移(%基址)
所以这条指令要改成:movb 9(%ebp), %ch(如果原意图是把内存[ebp+9]的字节加载到ch中)。
错误:
pushw 0xfffa无效
GAS里立即数必须加$前缀,32位模式下pushw是合法指令,所以要改成:pushw $0xfffa。
关于宏里的指令没报错的原因
那些宏定义里的指令没触发错误,大概率是因为编译过程在解析到宏实例化之前就因为前面的错误终止了,并不是它们本身合法。
两种解决思路:
思路1:改用NASM编译
直接用NASM来处理这个汇编文件,不用改代码:
- 把
.S后缀改成.asm - 用NASM生成32位目标文件:
nasm -f elf32 6502asm_x86.asm -o 6502asm_x86.o - 把生成的
.o文件和你的项目其他代码一起链接即可。
思路2:批量转成GAS(AT&T)语法
如果坚持用GCC的汇编器,需要把所有代码做以下调整:
- 反转所有指令的操作数顺序(NASM的
mov 目的, 源→ GAS的mov 源, 目的) - 所有寄存器名前加
%(比如di→%di,cl→%cl) - 所有立即数前加
$(比如0xfffa→$0xfffa) - 内存地址格式从
[基址+偏移]改成偏移(%基址),复杂寻址比如[ebx+esi*2+0x8]要改成0x8(%ebx, %esi, 2) - 保持指令后缀(
movb/movw/movl),GAS用这些后缀区分字节/字/双字操作,和NASM的mov byte ptr/mov word ptr作用一致。
举个例子,你提到的Intel格式MOV ECX, dword ptr table[RBX][RDI],对应的GAS语法是movl table(%rbx, %rdi, 4), %ecx(64位模式下)。
内容的提问来源于stack exchange,提问作者android.weasel
相关产品推荐
相关产品推荐

