最近在学习汇编语言,和朋友聊天时聊到了 C 语言中的变长数组,想知道在汇编后是什么样子的。
变长数组(Variable-length array)
可变长数组是指在计算机程序设计中,数组对象的长度在运行时(而不是编译时)确定。
C/C++的灵活数组类型(又称柔性数组成员)是另外一个语言特性。
反汇编 VLA
C 语言代码:
#include <stdio.h>
int main(void) {
int n;
int a[n];
return 0;
}
反汇编代码:
...
mov eax,DWORD PTR [ebp-0x14] ; eax <- [n]
lea edx,[eax-0x1] ; edx <- [n - 1]
mov DWORD PTR [ebp-0xc],edx ; [n - 8] <- edx
lea edx,[eax*4+0x0] ; edx <- [n * 4 + 0] VLA 的长度
mov eax,0x10 ; eax <- 16
sub eax,0x1 ; eax -= 1 => eax = 15
add eax,edx ; eax += edx => eax = 15 + nbytes
mov ecx,0x10 ; ecx <- 16
mov edx,0x0 ; edx <- 0
div ecx ; eax /= 16
imul eax,eax,0x10 ; eax *= 16
; (15 + nbytes) / 16 * 16 用于对齐
; 因此上面几条指令没有抵消
sub esp,eax ; esp -= eax 在栈中为 VLA 预留空间
mov eax,esp ; eax <- esp VLA 的地址
add eax,0x3 ; eax += 3 => eax = 18 + nbytes
shr eax,0x2 ; eax >>= 2
shl eax,0x2 ; eax <<= 2
; (eax + 3) / 2 * 2 用于对齐
; 因此上面几条指令没有抵消
mov DWORD PTR [ebp-0x10],eax ; [n + 4] <- eax 给 a 赋上 VLA 的地址
...
因此在创建 VLA 时先在栈上分配内存同时要注意对齐,再将分配好的内存地址赋值给数组。
与直接创建在栈上的定长数组不同,变长数组访问元素时需要两次寻址。