一个值得讨论的伪指令是.align,它可能在很多时候不被人注意,但是不恰当的使用将导致程序无法运行,这种可能性在ARM系统上几乎是百分之百的发生。
.align的作用在于对指令或者数据的存放地址进行对齐,有些CPU架构要求固定的指令长度并且存放地址相对于2的幂指数圆整,否则程序无法正常运行,比如ARM;有些系统却不需要,如果不遵循地址的圆整规则,程序依然可以正确执行,只是降低了一些执行效率,比如i386。.align的作用范围只限于紧跟它的那条指令或者数据,而接下来的指令或者数据的地址由上一条指令的地址和其长度决定。这里给出一个很好的用来测试.align作用的例子,首先在i386上进行测试。
- .section .text #定义代码段
- data:
- .byte 0x11
- .align 2
- .globl _start
- _start:
- movl data, %ebx
- movl $1, %eax
- int $0x80
这个程序没有实际的应用意义。为了防止编译出的目标文件中不同的段均从0开始而看不到.align的效果,这里只定义一个代码段,.byte数据将被编译进代码段,_start中的第一条指令将紧跟在0x11数据之后,我们使用 as -o test.o test.S && objdump -D test.o来查看反汇编的结果:
- Disassembly of section .text:
- 00000000 :
- 0: 11 8d 76 00 bb 00 adc %ecx,0xbb0076(%ebp)
- 00000004 <_start>:
- 4: bb 00 00 00 00 mov $0x0,%ebx
- 9: a1 00 00 00 00 mov 0x0,%eax
- e: cd 80 int $0x80
objdump尝试将代码段中的所有二进制数据当作指令解析,所以不要关心非代码段反汇编后的指令adc %ecx,0xbb0076(%ebp)。我们需要关心的是mov $0x0,%ebx所在的地址4,显然它和.align指定的4可以除尽,也即相对齐于4的倍数的地址。为了作一比较,移除.align 4,得到以下的反汇编结果,显然此时的第一条mov指令的对齐地址是1。
- Disassembly of section .text:
- 00000000 :
- 0: 11 bb 00 00 00 00 adc %edi,0x0(%ebx)