汇编里的数组

汇编里的数组

一维数组

编译器为Visual Studio 2019

一维数组在汇编里看到其实就是简化版的声明n个变量而已,学过java的可以理解为一个语法糖?

int arr[5] = { 0,1,2,3,4 };
__asm{
    mov    dword ptr [ebp-3Ch],0  
	mov    dword ptr [ebp-38h],1  
	mov    dword ptr [ebp-34h],2  
	mov    dword ptr [ebp-30h],3  
 	mov    dword ptr [ebp-2Ch],4
}
//等价于
int arr_0=0;
int arr_1=1;
int arr_2=2;
int arr_3=3;
int arr_4=4;

寻址方式

#include
void function() {
    int x = 1;//mov dword ptr [ebp-8],1
    int y = 2;//mov dword ptr [ebp-14h],2
    int r;
    int arr[5] = { 0,1,2,3,4 };
    r = arr[1];
    __asm{
      mov  eax,4  
      shl  eax,0  
      mov  ecx,dword ptr [ebp+eax-3Ch]  
	  mov  dword ptr [ebp-20h],ecx 
    }
    r = arr[x];
    __asm{
      mov eax,dword ptr [ebp-8]  
	  mov ecx,dword ptr [ebp+eax*4-3Ch]  
	  mov dword ptr [ebp-20h],ecx
    }
    r = arr[x + y];
    __asm{
      mov eax,dword ptr [ebp-8]  
	  add eax,dword ptr [ebp-14h]  
	  mov ecx,dword ptr [ebp+eax*4-3Ch]  
	  mov dword ptr [ebp-20h],ecx
    }
    r = arr[x * 2 + y];
    __asm{
      mov eax,dword ptr [ebp-8]  
	  mov ecx,dword ptr [ebp-14h]  
	  lea edx,[ecx+eax*2]  
	  mov eax,dword ptr [ebp+edx*4-3Ch]  
	  mov dword ptr [ebp-20h],eax
    }
}
int main()
{
    function();
    return 0;
}

一个很显著的特征就是 [ e b p + e d x ∗ 4 − 3 C h ] [ebp+edx*4-3Ch] [ebp+edx43Ch],这个形式可能会绕晕?稍微调换一下位置就很明了了,像这样 [ e b p − 3 C h + e d x ∗ 4 ] [ebp-3Ch+edx*4] [ebp3Ch+edx4], [ e b p − 3 C h ] [ebp-3Ch] [ebp3Ch]是啥?不就是arr[0]的地址吗?至于为什么是乘以4,其实是因为这是一个int数组,如果换成short就是乘以2 [ e b p − 3 C h + e d x ∗ 2 ] [ebp-3Ch+edx*2] [ebp3Ch+edx2],换成char就是乘以1 [ e b p − 3 C h + e d x ] [ebp-3Ch+edx] [ebp3Ch+edx].

内存分配

之所以开头说明了编译器是啥,是因为每个编译器在申请内存时申请的大小都不尽相同,当然不同的仅仅是大小而已,依然遵守原则的。之所以提到这一点,首先来看一个问题

char arr[3] = {1,2,3};与 char arr[4] = {1,2,3,4};哪个更节省空间,从反汇编的角度来说明你的观点

说到这个又不得不提一下本机尺寸,对应尺寸大小的数据在处理上会更快,例如32位机器在处理32位的数据时反而会比16位,8位的数据更快。编译器在内存大小处理速度之间选择了处理速度

接下来依然是一段实例代码

eg1:有3个char的数组arr1

#include
void function() {
    char arr1[3] = { 0,1,2 };
}
int main()
{
    function();
    return 0;
}

eg2:有4个char的数组arr2

#include
void function() {
    char arr2[4] = { 0,1,2,3 };
}
int main()
{
    function();
    return 0;
}

eg3:有5个char的数组arr3

#include
void function() {
    char arr3[5] = { 0,1,2,3,4 };
}
int main()
{
    function();
    return 0;
}

可以看到eg1中的内存和eg2中的内存一样,而eg3中明明只是多一个char但是内存却多了一个DWORD(D0h-CCh=4h),这就是为了符合本机尺寸使得处理速度更快做出的调整。

那么问题的答案显而易见了,从反汇编的角度来看节省排名是arr2>arr1>arr3

多维数组

内存分配

从汇编的角度来说,不管你是几维在汇编来看都是一维

int arr1[4] = { 0,1,2,3 };
__asm{
    mov dword ptr [ebp-14h],0  
    mov dword ptr [ebp-10h],1  
    mov dword ptr [ebp-0Ch],2  
    mov dword ptr [ebp-8],3
}
int arr2[2][2] = { 4,5,6,7 };
__asm{
    mov dword ptr [ebp-2Ch],4  
    mov dword ptr [ebp-28h],5  
    mov dword ptr [ebp-24h],6  
    mov dword ptr [ebp-20h],7
}

寻址方式

寻址方式就跟一维数组不太一样了

int arr1[4] = { 0,1,2,3 };
int n = arr1[3];
__asm{
    mov eax,4  
    imul ecx,eax,3  
    mov edx,dword ptr [ebp+ecx-14h]  
    mov dword ptr [ebp-38h],edx
}
int arr2[2][2] = { 4,5,6,7 };
int m = arr2[1][0];
__asm{
    mov eax,8---->2*4  
    shl eax,0  
    lea ecx,[ebp+eax-2Ch]  
    mov edx,4  
    imul eax,edx,0  
    mov ecx,dword ptr [ecx+eax]  
    mov dword ptr [ebp-44h],ecx
}

简单来说假设声明一个n维数组 a r r [ a 0 ] [ a 1 ] ⋅ ⋅ ⋅ [ a n ] arr[a_0][a_1]···[a_n] arr[a0][a1][an]

String str="int arr[a_0][a_1]···[a_n]";
String str="我们想要查找arr[m][m]···[m]的元素";
String str="定义一个mul(int num)运算符,表示a_(num)*a_(num+1)···*a_(n)"

那么寻址公式是这样的 ∑ x = 0 n m ∗ m u l ( x ) \sum_{x=0}^{n}{m*mul(x)} x=0nmmul(x)

你可能感兴趣的:(汇编,C)