我最近开始学习从Windows移植到Linux。我一直在将程序从英特尔语法转换为AT& T语法,并将其从x32转换为x64。而且因为我对装配工具有足够的新意,特别是AT& T我在移植时遇到了一些麻烦。仅举几个:我故意不使用.intel_syntax
指令。
所以我不得不翻译这些命令:
RTLWriteIntegerBuffer: TIMES 3 DB 0x90,0x8D,0x40,0x00
接下来是:
LEA EDI,[OFFSET RTLWriteIntegerBuffer+ECX-1]
另一个:
LEA EBX,[EDX+'0']
还有一个:
ReadCharInited: DB 0
CMP BYTE PTR ReadCharInited,0
另一个问题是: AT& T语法与英特尔语法之间是否存在1:1映射?或者是否存在AT& T不支持的特定英特尔命令?
也许有人知道这样的功能:
HEAP_NO_SERIALIZE=1
HEAP_GENERATE_EXCEPTIONS=4
HEAP_ZERO_MEMORY=8
...
INVOKE HeapAlloc,EAX,HEAP_GENERATE_EXCEPTIONS+HEAP_ZERO_MEMORY+HEAP_CREATE_ALIGN_16,4194332
这个可能是特定于Borland Turbo Assembler的方式来致电kernel32.dll
' HeapAlloc
,但我不确定。 可以将其翻译为fallocate
系统调用吗?
提前致谢
答案 0 :(得分:4)
谈论" AT& T语法"与#34; Intel语法"相比,它通常仅指指令助记符与操作数排序和格式之间的差异。
因此,例如,这是AT& T语法中的指令:
movl $1, (%esi)
这是使用Intel语法的相同指令:
mov DWORD PTR [esi], 1
对于英特尔语法中可表示的每条指令,该指令的AT& T语法中都有等效表示。
由于没有AT& T汇编程序而且没有英特尔汇编程序,指令(指令以外的所有内容)都是另一回事。 GNU汇编程序(GAS)支持AT& T和Intel语法,但仅支持其自己的指令,这些指令是AT& T汇编程序使用的指令的扩展。 Microsoft的MASM仅支持Intel语法,但也只支持自己的指令,这些指令是原始Intel汇编程序的扩展。从一个汇编程序的指令到另一个汇编程序的指令并不总是直接等价的。在某些情况下,它们使用不同的目标文件格式这一事实可能会阻止在使用不同目标文件格式的不同汇编程序中找到实现指令功能的任何方法。 (或者甚至使用不同格式的相同汇编程序,如GNU汇编程序的情况。)
例如,这里有一些GAS指令:
.rept 3
.byte 0x90, 0x8D, 0x40, 0x00
.endr
以下是等效的MASM指令:
REPT 3
DB 90h, 8Dh, 40h, 00h
ENDM
但是没有MASM等同于以下GAS指令,因为它特定于ELF对象格式,MASM不支持:
.protected foo
另一方面,没有直接等同于以下MASM指令,因为GAS不支持任何复杂的高级语言指令:
INVOKE HeapAlloc,EAX,HEAP_GENERATE_EXCEPTIONS+HEAP_ZERO_MEMORY+HEAP_CREATE_ALIGN_16,4194332
要移植以前的ELF特定指令,您必须重新设计应用程序以处理Windows如何处理共享库。要移植后面的MASM特定指令,您必须创建自己的宏来完成确定如何正确传递所有参数的工作,或者只需手动写出此调用所需的所有汇编指令。到Linux x86-64 ABI。 (您还必须找到适当的Linux函数来调用并传递一组不同的参数,但这与转换指令本身是一个单独的问题。)
有些装配工试图与其他装配商兼容;例如,Borland的TASM尝试与MASM兼容,尽管它是MASM的旧版本。那么在TASM中工作的(在默认的MASM模式下)通常可以在MASM中工作,反之亦然。但是,许多汇编程序基本上使用自己的x86汇编语言版本。
例如,您在帖子中显示的代码似乎使用了两种不同的汇编语言版本,并且无法由任何单个汇编程序汇编。您的第一行代码使用TIMES
指令,但该指令仅受NASM支持,NASM不使用AT& T语法或Intel语法。它有自己的指令语法,尽管它与英特尔语法没有什么不同。它也有自己不兼容的指令集,不是基于任何特定的指令,比如你所展示的TIMES
指令。
其余代码似乎是MASM语法。除了第三行之外,它不会与NASM正确组装(第一行也不会与MASM正确组装)。我不确定是否会与TASM合并,因为在MASM 6中添加了INVOKE
指令。
请注意,鉴于代码的性质,使用汇编语言编写代码可能无法获得任何好处,而且将其翻译成C,C ++或其他您熟悉的语言可能会好得多。
答案 1 :(得分:2)
我对Windows不太熟悉,但无论如何,让我试着帮助你。
RTLWriteIntegerBuffer: TIMES 3 DB 0x90,0x8D,0x40,0x00
DB
指令转换为UNIX汇编程序中的.byte
,TIMES
支持gas {(.rept
}但我建议避免使用它,因为它不可移植到其他UNIX汇编程序。所以这个片段变成了
RTLWriteIntegerBuffer:
.byte 0x90,0x8d,0x40,0x00
.byte 0x90,0x8d,0x40,0x00
.byte 0x90,0x8d,0x40,0x00
LEA EDI,[OFFSET RTLWriteIntegerBuffer+ECX-1]
形式为[disp+base+index*scale]
的英特尔式内存操作数在AT& T语法中变为disp(base,index,scale)
。如果index
和scale
都为空,则可以改为编写disp(base)
,否则只需删除丢失的寄存器(但保留逗号)。你的指示变成了
lea RTLWriteIntegerBuffer-1(%ecx),%edi
注意交换的操作数。在AT& T语法中,除了一些浮点指令之外,所有双参数操作码都交换了操作数。
LEA EBX,[EDX+'0']
同样,这个变成了
lea '0'(%edx),%ebx
ReadCharInited: DB 0 CMP BYTE PTR ReadCharInited,0
这个变为
ReadCharInited: .byte 0
cmpb $0,ReadCharInited
请注意b
后缀,表示这是一个字节指令。其他后缀包括 word 的w
,双字的l
(长)四字的q
(仅限amd64)。 Immediates前缀为$
,内存操作数没有前缀。
另一个问题是:AT& T语法和英特尔语法之间是否存在1:1映射?或者是否存在AT& T不支持的特定Intel命令?
有关说明,通常有。解决这个问题的一种方法是用Intel语法编写指令,然后将其转储为AT& T语法(带objdump -d
),反之亦然(带objdump -d -Mintel
)。
对于伪指令(例如TIMES
或DB
),可能没有,因为UNIX汇编程序在概念上与例如不同。 MASM。
INVOKE HeapAlloc,EAX,HEAP_GENERATE_EXCEPTIONS+HEAP_ZERO_MEMORY+HEAP_CREATE_ALIGN_16,4194332
您可能希望只使用C标准库中的旧calloc
而不是此功能。如果您计划链接libc,那么这样的事情应该有用:
push $4194332
push $1
call calloc
add $8,%esp
请注意,虽然没有HeapDestroy
或类似,但如果您需要此功能,则需要编写自己的分配器。
答案 2 :(得分:2)
AT& T语法和英特尔语法之间是否存在1:1映射?或者是否存在AT& T不支持的特定Intel命令?
两种语法都可以表达每个x86指令的每种形式。任何有效的x86机器代码都可以反汇编为AT& T,MASM或NASM语法。
但是,存在一些差异,因此映射助记符并不完全是1:1。例如,在AT& T语法中,您必须使用movabs $0x123456789abcd, %rax
来获取使用64位立即的编码。
在NASM语法中,汇编程序会根据常量自动选择mov r64, imm64
编码与mov r/m32, imm32
或mov r/m64, sign-extended-imm32
编码。因此mov rax, 1
可能汇编为5字节mov r32, imm32
或7字节mov r/m64, imm32
(这就是为什么您应该始终写mov eax, 1
以确保获得较小的编码)。但是mov rax, 0x123456789abcd
将始终汇编为10字节mov r64, imm64
格式,而不必使用其他助记符。
见Intel's insn set ref for MOV。 (x86标记wiki中的其他链接。
此x86-64.org的what's new in x86-64的archive.org副本还涵盖了movabs与mov mnemonic问题以及其他内容。