32位程序的汇编指令长度

时间:2020-02-06 17:57:54

标签: assembly x86 disassembly machine-code

我构建了一个简单的程序,并使用file命令检查程序是否为32位格式。 反过来,我使用objdump来反汇编程序,发现某些汇编指令长度大于4字节。

我希望程序是32位格式。因此,这些汇编指令的长度不应大于4字节。 显然,我错了。您能告诉我为什么有6字节或7字节的汇编指令吗?谢谢。

$ file a.out
a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=09aa196a671a6e169f09984360133ad9488f7e53, not stripped
$ objdump -d a.out
a.out:     file format elf32-i386

Disassembly of section .init:

 080482a8 <_init>:
 80482a8:       53                      push   %ebx
 80482a9:       83 ec 08                sub    $0x8,%esp
 80482ac:       e8 8f 00 00 00          call   8048340 <__x86.get_pc_thunk.bx>
 80482b1:       81 c3 4f 1d 00 00       add    $0x1d4f,%ebx
 80482b7:       8b 83 fc ff ff ff       mov    -0x4(%ebx),%eax
 80482bd:       85 c0                   test   %eax,%eax
 80482bf:       74 05                   je     80482c6 <_init+0x1e>
 80482c1:       e8 3a 00 00 00          call   8048300 <__libc_start_main@plt+0x10>
 80482c6:       83 c4 08                add    $0x8,%esp
 80482c9:       5b                      pop    %ebx
 80482ca:       c3                      ret

2 个答案:

答案 0 :(得分:4)

为什么?一个明显的原因是,一条指令可以 include 一个32位立即数,例如mov $address, %register。这样call rel32可以从当前地址到达任何32位地址。

这些指令需要空间来存放操作码(1个字节),有时还需要一个ModR / M字节来指定哪些寄存器/存储器是操作数。

如果一条指令限制为4个字节,则需要多条指令才能将静态地址放入寄存器,并且您不能将其中一个用作存储器直接寻址模式。 RISC ISA通常需要2条指令来构造寄存器中的任意32位常量(包括地址),例如MIPS lui $t0, high_half / ori $t0, $t0, low_half


x86是可变长度的CISC;常用指令简短,但是可以使用更长的指令,而不是强迫您使用单独的指令在寄存器中构造地址或常量。

例如您可以执行movl $123456, some_static_variable并获得包含以下组件的指令编码:

mov_opcode (1B)   Mod/RM (1B)    disp32 absolute address (4B)    imm32=123456 (4B)

总共10个字节,包括两个4字节值。 (在Intel的指令集参考手册(x86 SDM的第2卷)中,这是mov r/m32, imm32 form of MOV,具有[disp32]寻址模式。)

您可以使用前缀使其更长,例如用于线程本地存储的fs:段覆盖前缀。和/或寻址模式可能包含一个缩放索引寄存器,例如movl $123456, array(,%ecx,4),因此在ModRM之后需要一个SIB(缩放/索引/基数)字节来编码寻址模式。

我们可以使用mov代替add,然后也可以使用lock前缀使之成为原子的读-修改写。

指令长度的硬限制是15个字节。如果到那时解码仍未找到指令的末尾,则会引发#UD非法指令异常。 (Linux内核将向有问题的进程提供SIGILL。)

(有趣的事实:原始的8086没有限制,并且会很乐意不断循环尝试解码充满rep前缀的整个64k段)

答案 1 :(得分:3)

指令长度不限于32位。在x86维基百科页面上:

x86体系结构的指令长度可变,主要是 “ CISC”设计。

编码变量(1到15个字节)

并且来自Intel® 64 and IA-32 architectures software developer’s manual

Intel386处理器将指令长度限制为15个字节。

相关问题