从 Windows 移植到 Linux。汇编命令翻译
Porting from Windows to Linux. Assembler command translation
我最近开始学习从 Windows 到 Linux 的移植。我一直在将程序从 Intel 语法翻译成 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 语法和 Intel 语法之间是否有 1:1 映射? 或者是否存在 AT&T 不支持的特定 Intel 命令?
也许有人知道这样的函数:
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
系统调用吗?
提前致谢
我对Windows不是很熟悉,但无论如何让我试着帮助你。
RTLWriteIntegerBuffer: TIMES 3 DB 0x90,0x8D,0x40,0x00
DB
指令在 UNIX 汇编程序中转换为 .byte
,gas 支持 TIMES
(如 .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 [=17=],ReadCharInited
注意 b
后缀表明这是一个字节指令。其他后缀包括 w
for word,l
for doubleword (long) 和 q
for quadword(仅限 amd64)。立即数以 $
为前缀,内存操作数不带前缀。
Another question is: Is there 1:1 mapping between AT&T syntax and Intel syntax? Or are there specific Intel commands that are not supported in AT&T?
说明一般都有。解决这个问题的一种方法是用 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
而不是此函数。如果你打算 link 反对 libc:
push 94332
push
call calloc
add ,%esp
请注意,虽然没有 HeapDestroy
或类似的东西,但如果您需要此功能,则需要编写自己的分配器。
当谈论"AT&T syntax"与"Intel syntax"时,通常只是指指令助记符和操作数顺序和格式之间的区别。
因此,例如,这是 AT&T 语法中的指令:
movl , (%esi)
这是使用 Intel 语法的相同指令:
mov DWORD PTR [esi], 1
对于 Intel 语法中可表示的每条指令,该指令在 AT&T 语法中都有等效的表示。
由于不再有 AT&T assembler 和 Intel assembler,指令(指令以外的所有内容)都是另一回事。 GNU assembler (GAS) 支持 AT&T 和 Intel 语法,但只支持它自己的指令,这些指令是 AT&T assembler 使用的指令的扩展。 Microsoft 的 MASM 只支持 Intel 语法,但也只支持它自己的指令,这是对原始 Intel assembler's 的扩展。一个 assembler 的指令并不总是直接等同于另一个 assembler 的指令。在某些情况下,它们使用不同的目标文件格式这一事实可能会阻止找到任何方法来使用不同的目标文件格式在不同的 assembler 中实现指令的功能。 (甚至相同的 assembler 使用不同的格式,就像 GNU assembler 的情况一样。)
例如,这里有一些 GAS 指令:
.rept 3
.byte 0x90, 0x8D, 0x40, 0x00
.endr
下面是等效的 MASM 指令:
REPT 3
DB 90h, 8Dh, 40h, 00h
ENDM
但是没有与以下 GAS 指令等效的 MASM,因为它特定于 MASM 不支持的 ELF 对象格式:
.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 函数来调用和传递一组不同的参数,但这是与翻译指令本身不同的问题。)
一些 assemblers 试图与其他 assemblers 兼容;例如 Borland 的 TASM 试图与 MASM 兼容,尽管它是 MASM 的旧版本。因此,在 TASM(在其默认的 MASM 模式下)中起作用的东西通常在 MASM 中起作用,反之亦然。然而,许多 assemble 作者基本上使用他们自己的 x86 汇编语言版本。
例如,您在 post 中显示的代码似乎使用了两种不同的汇编语言版本,并且不能由任何一个 assembler assembled .您的第一行代码使用 TIMES
指令,但此指令仅受 NASM 支持,它既不使用 AT&T 语法也不使用 Intel 语法。它有自己的指令语法,尽管它与 Intel 语法没有太大区别。它也有自己的一组不兼容的指令,不基于任何特定的东西,就像你展示的 TIMES
指令。
您的其余代码似乎采用 MASM 语法。除了第三行,它不会 assemble 使用 NASM 正确(第一行 assemble 使用 MASM 也不会正确)。我不确定 TASM 是否会 assemble,因为在 MASM 6 中添加了 INVOKE
指令。
请注意,鉴于您的代码的性质,用汇编语言编写它可能没有任何好处,您最好将其翻译成 C、C++ 或您更熟悉的其他语言。
Is there 1:1 mapping between AT&T syntax and Intel syntax? Or are there specific Intel commands that are not supported in AT&T?
两种语法都可以表达每条x86指令的每一种形式。任何有效的 x86 机器代码都可以 disassembled 到 AT&T、MASM 或 NASM 语法中。
虽然存在一些差异,因此映射助记符并不完全 1:1。例如,在 AT&T 语法中,您必须使用 movabs [=10=]x123456789abcd, %rax
来获取使用 64 位立即数的编码。
在 NASM 语法中,assembler 会根据常量自动选择 mov r64, imm64
编码与 mov r/m32, imm32
或 mov r/m64, sign-extended-imm32
编码。所以 mov rax, 1
可能 assemble 到 5 字节 mov r32, imm32
或 7 字节 mov r/m64, imm32
(这就是为什么你应该总是写 mov eax, 1
以确保你得到较小的编码)。但是 mov rax, 0x123456789abcd
将始终 assemble 为 10 字节的 mov r64, imm64
形式,而无需使用不同的助记符。
请参阅 Intel's insn set ref for MOV. (Other links in the x86 标签 wiki)。
x86-64.org 的 what's new in x86-64 的 archive.org 副本还涵盖了 movabs 与 mov 助记符问题以及其他内容。
我最近开始学习从 Windows 到 Linux 的移植。我一直在将程序从 Intel 语法翻译成 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 语法和 Intel 语法之间是否有 1:1 映射? 或者是否存在 AT&T 不支持的特定 Intel 命令?
也许有人知道这样的函数:
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
系统调用吗?
提前致谢
我对Windows不是很熟悉,但无论如何让我试着帮助你。
RTLWriteIntegerBuffer: TIMES 3 DB 0x90,0x8D,0x40,0x00
DB
指令在 UNIX 汇编程序中转换为 .byte
,gas 支持 TIMES
(如 .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 [=17=],ReadCharInited
注意 b
后缀表明这是一个字节指令。其他后缀包括 w
for word,l
for doubleword (long) 和 q
for quadword(仅限 amd64)。立即数以 $
为前缀,内存操作数不带前缀。
Another question is: Is there 1:1 mapping between AT&T syntax and Intel syntax? Or are there specific Intel commands that are not supported in AT&T?
说明一般都有。解决这个问题的一种方法是用 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
而不是此函数。如果你打算 link 反对 libc:
push 94332
push
call calloc
add ,%esp
请注意,虽然没有 HeapDestroy
或类似的东西,但如果您需要此功能,则需要编写自己的分配器。
当谈论"AT&T syntax"与"Intel syntax"时,通常只是指指令助记符和操作数顺序和格式之间的区别。
因此,例如,这是 AT&T 语法中的指令:
movl , (%esi)
这是使用 Intel 语法的相同指令:
mov DWORD PTR [esi], 1
对于 Intel 语法中可表示的每条指令,该指令在 AT&T 语法中都有等效的表示。
由于不再有 AT&T assembler 和 Intel assembler,指令(指令以外的所有内容)都是另一回事。 GNU assembler (GAS) 支持 AT&T 和 Intel 语法,但只支持它自己的指令,这些指令是 AT&T assembler 使用的指令的扩展。 Microsoft 的 MASM 只支持 Intel 语法,但也只支持它自己的指令,这是对原始 Intel assembler's 的扩展。一个 assembler 的指令并不总是直接等同于另一个 assembler 的指令。在某些情况下,它们使用不同的目标文件格式这一事实可能会阻止找到任何方法来使用不同的目标文件格式在不同的 assembler 中实现指令的功能。 (甚至相同的 assembler 使用不同的格式,就像 GNU assembler 的情况一样。)
例如,这里有一些 GAS 指令:
.rept 3
.byte 0x90, 0x8D, 0x40, 0x00
.endr
下面是等效的 MASM 指令:
REPT 3
DB 90h, 8Dh, 40h, 00h
ENDM
但是没有与以下 GAS 指令等效的 MASM,因为它特定于 MASM 不支持的 ELF 对象格式:
.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 函数来调用和传递一组不同的参数,但这是与翻译指令本身不同的问题。)
一些 assemblers 试图与其他 assemblers 兼容;例如 Borland 的 TASM 试图与 MASM 兼容,尽管它是 MASM 的旧版本。因此,在 TASM(在其默认的 MASM 模式下)中起作用的东西通常在 MASM 中起作用,反之亦然。然而,许多 assemble 作者基本上使用他们自己的 x86 汇编语言版本。
例如,您在 post 中显示的代码似乎使用了两种不同的汇编语言版本,并且不能由任何一个 assembler assembled .您的第一行代码使用 TIMES
指令,但此指令仅受 NASM 支持,它既不使用 AT&T 语法也不使用 Intel 语法。它有自己的指令语法,尽管它与 Intel 语法没有太大区别。它也有自己的一组不兼容的指令,不基于任何特定的东西,就像你展示的 TIMES
指令。
您的其余代码似乎采用 MASM 语法。除了第三行,它不会 assemble 使用 NASM 正确(第一行 assemble 使用 MASM 也不会正确)。我不确定 TASM 是否会 assemble,因为在 MASM 6 中添加了 INVOKE
指令。
请注意,鉴于您的代码的性质,用汇编语言编写它可能没有任何好处,您最好将其翻译成 C、C++ 或您更熟悉的其他语言。
Is there 1:1 mapping between AT&T syntax and Intel syntax? Or are there specific Intel commands that are not supported in AT&T?
两种语法都可以表达每条x86指令的每一种形式。任何有效的 x86 机器代码都可以 disassembled 到 AT&T、MASM 或 NASM 语法中。
虽然存在一些差异,因此映射助记符并不完全 1:1。例如,在 AT&T 语法中,您必须使用 movabs [=10=]x123456789abcd, %rax
来获取使用 64 位立即数的编码。
在 NASM 语法中,assembler 会根据常量自动选择 mov r64, imm64
编码与 mov r/m32, imm32
或 mov r/m64, sign-extended-imm32
编码。所以 mov rax, 1
可能 assemble 到 5 字节 mov r32, imm32
或 7 字节 mov r/m64, imm32
(这就是为什么你应该总是写 mov eax, 1
以确保你得到较小的编码)。但是 mov rax, 0x123456789abcd
将始终 assemble 为 10 字节的 mov r64, imm64
形式,而无需使用不同的助记符。
请参阅 Intel's insn set ref for MOV. (Other links in the x86 标签 wiki)。
x86-64.org 的 what's new in x86-64 的 archive.org 副本还涵盖了 movabs 与 mov 助记符问题以及其他内容。