nasm 中的 MOV 以从内存中注册不使用 BITS 32
MOV to register from memory not working with BITS 32 in nasm
我刚开始使用 x86 汇编,正在尝试使用 MOV 指令进行一些基础操作。 (下面的代码)
BITS 32
SECTION .data
somedata: db "Hello world",10
SECTION .text
global _start
_start:
mov eax, somedata
mov al, [eax]
mov edx, [somedata]
我好像不明白为什么nasm使用RIP相对寻址,当指定BITS 32 在程序集中(我认为相对寻址仅在 64 位模式下)。此外,它在 32 位模式 中使用 RAX。如果我不指定任何东西,它似乎不使用相对寻址并使用EAX。
代码为 BITS 32
Disassembly of section .text:
00000000004000b0 <_start>:
4000b0: b8 c0 00 60 00 mov eax,0x6000c0
4000b5: 8a 00 mov al,BYTE PTR [rax]
4000b7: 8b 15 c0 00 60 00 mov edx,DWORD PTR [rip+0x6000c0] # a0017d <_end+0x4000ad>
代码没有 BITS 32
Disassembly of section .text:
00000000004000b0 <_start>:
4000b0: b8 c0 00 60 00 mov eax,0x6000c0
4000b5: 67 8a 00 mov al,BYTE PTR [eax]
4000b8: 8b 14 25 c0 00 60 00 mov edx,DWORD PTR ds:0x6000c0
我知道不是汇编,是我。我做错了什么?
PS:
使用 nasm,64 位计算机使用 linux。
使用nasm -f elf64 -F stabs -g sandbox.asm -o sandbox.o
组装
反汇编使用objdump -M intel -d sandbox
我还尝试了以下汇编器和链接器标志:
nasm -f elf32 -F stabs -g sandbox.asm -o sandbox.o
ld -oformat=elf32-i386 -o sandbox sandbox.o
但是说 ld: i386 architecture of input file `sandbox.o' is incompatible with i386:x86-64 output
是行不通的
nasm -f elf64 -F stabs -g sandbox.asm -o sandbox.o
这将始终生成 64 位 ELF 可执行文件,无论您将 32 位代码放入其中的事实如何。这会导致反汇编程序将您的 32 位机器代码解码为 64 位代码,因此会出现奇怪的结果。反汇编类似于原始代码的事实只是巧合,因为 64 位模式下的指令编码与 32 位等效指令非常相似甚至相同(可能更改默认寄存器大小)。
使用-f elf32
获取 32 位 ELF 可执行文件。
TL:DR:永远不要使用 BITS
指令,除非它是 必要的 。
BITS 指令不会更改 -felf64
或 -felf32
选择的输出文件类型。 (-felf
是 -felf32
的同义词,以防您在示例中看到它。)
为了生成 32 位静态可执行文件,我使用了一个 asm-link
shell 脚本,它最终是这样做的:
nasm -felf32 -g -Fdwarf foo.asm &&
ld -melf_i386 -o foo foo.o
stabs
调试格式已过时,但只要您的调试器支持它,将 asm 源代码行映射到 asm 指令可能没问题。无论如何,如果您使用 -g
,-Fstabs
是默认值。 (我还没有全部读完,但是 https://www.ibm.com/developerworks/library/os-debugging/index.html 有一些关于 STAB vs. DWARF 的信息。)
大多数时候,BITS 指令充其量是无用的,在最坏的情况下是有害的。 而不是像 push ebx
这样的有用错误,如果你尝试将 32 位代码构建到 64 位 object 文件中,它会让这样的事情发生。 (虽然它不会在这里拯救你,因为所有这些代码都是双向组装的。)
只有当你想使用 nasm -fbin
并制作一个可以提供给 ndisasm 或用作 shell编码,或者使用 db
(A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux) 自己定义 ELF 或任何其他元数据 headers。 nasm
不提供 command-line 选项来更改 -fbin
的 BITS 16
默认模式。
或者如果你真的想在一个以 16 位启动并切换到 64 位模式的文件中混合使用 16、32 和 64 位代码:这是主要的 use-case 对于 BITS
. 或在 64 位可执行文件中包含一些 BITS 32
或 BITS 16
机器代码 作为数据 。
不要在文件顶部添加 BITS 32
行作为样板文件的一部分,这没有帮助,也不是好的做法。 使用如下注释
;;; 32-bit x86 Linux code, NASM syntax
如果您想描述此源文件中的内容以及如何构建它/运行。
你可以并且应该使用DEFAULT REL
,所以如果你正在构建 64 位代码,你将获取内存操作数的 RIP-relative 寻址模式,例如 [somedata]
(没有 GP 寄存器的符号名称)。这比 32 位绝对寻址模式短一个字节,并且可以在 PIE 可执行文件中工作。
有趣的事实:32 位模式有 2 种冗余方式来编码 [disp32]
绝对寻址模式。 x86-64 将较短的一个(无 SIB 字节)重新用于 RIP-relative。 这就是为什么你的 32 位机器代码的 64 位反汇编具有 DWORD PTR [rip+0x6000c0]
,其中 rel32 是符号的绝对地址。
我刚开始使用 x86 汇编,正在尝试使用 MOV 指令进行一些基础操作。 (下面的代码)
BITS 32
SECTION .data
somedata: db "Hello world",10
SECTION .text
global _start
_start:
mov eax, somedata
mov al, [eax]
mov edx, [somedata]
我好像不明白为什么nasm使用RIP相对寻址,当指定BITS 32 在程序集中(我认为相对寻址仅在 64 位模式下)。此外,它在 32 位模式 中使用 RAX。如果我不指定任何东西,它似乎不使用相对寻址并使用EAX。
代码为 BITS 32
Disassembly of section .text:
00000000004000b0 <_start>:
4000b0: b8 c0 00 60 00 mov eax,0x6000c0
4000b5: 8a 00 mov al,BYTE PTR [rax]
4000b7: 8b 15 c0 00 60 00 mov edx,DWORD PTR [rip+0x6000c0] # a0017d <_end+0x4000ad>
代码没有 BITS 32
Disassembly of section .text:
00000000004000b0 <_start>:
4000b0: b8 c0 00 60 00 mov eax,0x6000c0
4000b5: 67 8a 00 mov al,BYTE PTR [eax]
4000b8: 8b 14 25 c0 00 60 00 mov edx,DWORD PTR ds:0x6000c0
我知道不是汇编,是我。我做错了什么?
PS:
使用 nasm,64 位计算机使用 linux。
使用
nasm -f elf64 -F stabs -g sandbox.asm -o sandbox.o
组装
反汇编使用
objdump -M intel -d sandbox
我还尝试了以下汇编器和链接器标志:
nasm -f elf32 -F stabs -g sandbox.asm -o sandbox.o
ld -oformat=elf32-i386 -o sandbox sandbox.o
但是说 ld: i386 architecture of input file `sandbox.o' is incompatible with i386:x86-64 output
nasm -f elf64 -F stabs -g sandbox.asm -o sandbox.o
这将始终生成 64 位 ELF 可执行文件,无论您将 32 位代码放入其中的事实如何。这会导致反汇编程序将您的 32 位机器代码解码为 64 位代码,因此会出现奇怪的结果。反汇编类似于原始代码的事实只是巧合,因为 64 位模式下的指令编码与 32 位等效指令非常相似甚至相同(可能更改默认寄存器大小)。
使用-f elf32
获取 32 位 ELF 可执行文件。
TL:DR:永远不要使用 BITS
指令,除非它是 必要的 。
BITS 指令不会更改 -felf64
或 -felf32
选择的输出文件类型。 (-felf
是 -felf32
的同义词,以防您在示例中看到它。)
为了生成 32 位静态可执行文件,我使用了一个 asm-link
shell 脚本,它最终是这样做的:
nasm -felf32 -g -Fdwarf foo.asm &&
ld -melf_i386 -o foo foo.o
stabs
调试格式已过时,但只要您的调试器支持它,将 asm 源代码行映射到 asm 指令可能没问题。无论如何,如果您使用 -g
,-Fstabs
是默认值。 (我还没有全部读完,但是 https://www.ibm.com/developerworks/library/os-debugging/index.html 有一些关于 STAB vs. DWARF 的信息。)
大多数时候,BITS 指令充其量是无用的,在最坏的情况下是有害的。 而不是像 push ebx
这样的有用错误,如果你尝试将 32 位代码构建到 64 位 object 文件中,它会让这样的事情发生。 (虽然它不会在这里拯救你,因为所有这些代码都是双向组装的。)
只有当你想使用 nasm -fbin
并制作一个可以提供给 ndisasm 或用作 shell编码,或者使用 db
(A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux) 自己定义 ELF 或任何其他元数据 headers。 nasm
不提供 command-line 选项来更改 -fbin
的 BITS 16
默认模式。
或者如果你真的想在一个以 16 位启动并切换到 64 位模式的文件中混合使用 16、32 和 64 位代码:这是主要的 use-case 对于 BITS
. 或在 64 位可执行文件中包含一些 BITS 32
或 BITS 16
机器代码 作为数据 。
不要在文件顶部添加 BITS 32
行作为样板文件的一部分,这没有帮助,也不是好的做法。 使用如下注释
;;; 32-bit x86 Linux code, NASM syntax
如果您想描述此源文件中的内容以及如何构建它/运行。
你可以并且应该使用DEFAULT REL
,所以如果你正在构建 64 位代码,你将获取内存操作数的 RIP-relative 寻址模式,例如 [somedata]
(没有 GP 寄存器的符号名称)。这比 32 位绝对寻址模式短一个字节,并且可以在 PIE 可执行文件中工作。
有趣的事实:32 位模式有 2 种冗余方式来编码 [disp32]
绝对寻址模式。 x86-64 将较短的一个(无 SIB 字节)重新用于 RIP-relative。 这就是为什么你的 32 位机器代码的 64 位反汇编具有 DWORD PTR [rip+0x6000c0]
,其中 rel32 是符号的绝对地址。