从内存中注册的MOV无法与nasm中的BITS 32一起使用

时间:2019-02-03 18:51:56

标签: assembly x86 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]

当在程序集中指定 BITS 32 时,我似乎不明白为什么 nasm 使用RIP 相对寻址相对寻址(仅在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:

  • 在Linux中使用nasm和64位计算机。

  • 使用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

无效

2 个答案:

答案 0 :(得分:4)

nasm -f elf64 -F stabs -g sandbox.asm -o sandbox.o

这将始终生成64位ELF可执行文件,而不管您是否将32位代码放入其中。这导致反汇编程序将您的32位机器代码解码为好像是64位代码,因此产生了奇怪的结果。反汇编类似于原始代码的事实只是一个巧合,这是由于64位模式下的指令编码与32位等效项非常相似甚至相同(可能会更改默认寄存器大小)这一事实。

使用-f elf32获取32位ELF可执行文件。

答案 1 :(得分:4)

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指令就可以了。无论如何,如果使用-Fstabs,则-g是默认设置。 (我还没有全部阅读,但是https://www.ibm.com/developerworks/library/os-debugging/index.html掌握了一些有关STAB与DWARF的信息。)


在大多数情况下,BITS指令充其量是没有用的,而在最有害的情况下却是有害的。如果尝试构建32位,则不会出现诸如push ebx这样的有用错误,而无法编码代码存储到64位目标文件中,就可以进行此类操作。 (尽管它不会在这里保存您,因为所有这些代码都是以两种方式组装的。)

BITS唯一有用的时间是当您想使用nasm -fbin 并制作一个平面二进制文件时,您可以将其输入ndisasm或用作shellcode,或者定义ELF或dbA Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux)自己的其他任何元数据标头。 nasm没有提供用于更改BITS 16的{​​{1}}默认模式的命令行选项。

或者,如果您实际上想在文件中混合使用16、32和64位代码,这些文件以16位引导并切换到64位模式:这是{{1}的主要用例}。或在您的64位可执行文件中将某些-fbinBITS机器代码作为数据


请勿在文件顶部打BITS 32行作为样板,这没有帮助或好的做法。 BITS 16,如果您想描述此源文件中的内容以及如何构建/运行它。

您可以并且应该使用BITS 32 ,因此,如果您要构建64位代码,则将获得相对RIP的内存寻址方式;;; 32-bit x86 Linux code, NASM syntax之类的操作数(无GP寄存器的符号名)。比32位绝对寻址模式短一个字节,并且可以在PIE可执行文件中工作。

有趣的事实:32位模式有2种冗余方式来编码DEFAULT REL绝对寻址模式。 x86-64将较短的一个(无SIB字节)重新定位为相对RIP。 这就是为什么您的32位机器代码的64位反汇编具有[somedata],其中rel32是符号的绝对地址。