汇编学习--数组

数组是相同数据类型的元素的集合,它们的内存中按顺序连续存放在一起。在汇编状态下访问数组一般是通过基址加变址寻址实现的。

0x01 先找一个数组访问的C语言代码

    #include<stdio.h>
    int main()
    {
               static int a[3]={0x11,0x22,0x33};
                 int i,s=0,b[3];
    for(i=0;i<3;i++)
    {
                   s=s+a[i];
                    b[i]=s;
    }
             for(i=0;i<3;i++)
    {
                     printf("%d\n",b[i]);
    }
             return 0;
    }

0x02 查看对应的反汇编

在这里插入图片描述第一个for循环将a数字的值逐个加上s,并赋值给了b数组;第二个for循环就是将b数组里的元素逐个输出。
接下来通过反汇编对操作数组的过程简要分析:

8: s=s+a[i];
00401047   8B 4D FC  mov ecx,dword ptr [ebp-4]  //ebp-4这里存的i的值,并放到ecx寄存器里              
0040104A   8B 55 F8  mov edx,dword ptr [ebp-8]     //ebp-8存的是s的值,并放到edx寄存器里
0040104D   03 14 8D 30 4A 42 00  add edx,dword ptr [ecx*4+424A30h]  // s+a[i] ,看下面解释1
00401054   89 55 F8      mov dword ptr [ebp-8],edx      //把相加后的值在放到ebp-8处
9: b[i]=s;
00401057  8B 45 FC     mov eax,dword ptr [ebp-4]       //这里还是相当于i的值赋值到eax寄存器
0040105A  8B 4D F8     mov ecx,dword ptr [ebp-8]        //把相加后的值放到ecx寄存器
0040105D  89 4C 85 EC  mov dword ptr [ebp+eax*4-14h],ecx      //将ecx中的值放到内存地址为ebp+eax*4-14h处,看下面解释2
10: }
解释1:

dword ptr [ecx4+424A30h],这里对a数组的寻址是通过基址加变址实现的,首先我们在内存中看一下424A30h处的值,可以看到404A30h恰好就是数组的首地址,说明当我们对数组初始化时,就会分配一段内存空间出来用于存放数组中的值,那么对整个数组的取值就可以变成[ecx4+424A30h],其中当ecx的值取0,1,2,就可以遍历整个数组,由于我们把i赋值给了ecx寄存器,所以ecx的取值会通过i的值的变化而变化。

在这里插入图片描述

解释2:

mov dword ptr [ebp+eax4-14h],这是对b数组赋值,ebp指向0019FF30,ebp-14h是0019FF1C处,也是b数组的首地址,
在for循环中,i=0,也就是当eax为0的时候,此时s的值为0,ebp-8处的值为11,然后通过ecx再把11放到0019FF1C,
第二次循环,i=1,eax也为1,此时s的值为11,ebp-8处的值是22,于是相加赋值给了[ebp+1
4-14h]处,也就是0019FF20,
第三次循环,i=2,eax也为2,此时s的值是33,ebp-8处的值是33,于是相加赋值给了[ebp+2*4-14h]处,也就是0019FF24.
这里值得注意的是:我们之前定义的数组b[3] , 内存就会自动分配3个字节的内存空间用于存放数组中的元素。
在这里插入图片描述对b数组的赋值就结束了,接下来看一下如何输出b数组

12:   {
13:    printf("%d\n",b[i]);
0040107B 8B 45 FC   mov   eax,dword ptr [ebp-4]       //eax作为数组的下标
0040107E 8B 4C 85 EC   mov   ecx,dword ptr [ebp+eax*4-14h]   //还是通过基址加变址的方式对数组进行寻址,并把数组中的值通过循环逐个的赋值给ecx寄存器
00401082 51   push     ecx               //ecx进栈
00401083 68 1C 20 42 00   push  offset string "%d\n" (0042201c)   //“%的\n”进栈
00401088 E8 43 00 00 00   call  printf (004010d0)           //调用输出函数
0040108D 83 C4 08         add   esp,8             //平衡堆栈
14:   }

0x03 接下来写出这个程序的汇编代码:

写这个程序的汇编代码时,我发现其实完全一个for语句就可以完成上面对b数组的赋值和输出,所以在汇编的时候,我只用了一个for语句。

第一版:

在这里插入图片描述这个是第一次写出来的汇编,结果只输出了第一个值,于是我加断点,调试发现,当执行完第一遍输出语句之后,eax的值就变成了3,再回去执行add eax,1时,eax就变成4,cmp eax,3之后,由于大于3就直接跳出循环了,这样的话,肯定只能输出一个值。

可是eax寄存器的值为什么会变呢?

我发现printf语句执行过程中会用到eax,所以改变了eax的值

第二版

另外,我还有一个发现就是在第一版的基础上用ebx计数,那么就会输出三个值,说明ebx可以用作数组的索引,只是后两个数并不正确,那说明我不能把s的值存入寄存器,而是使用绝对地址!
在这里插入图片描述
有了这个发现,我在对代码进行了修改现在就可以成功的输出来了!汇编代码如下:

#include<stdio.h>
int main()
{
    static int a[3]={0x11,0x22,0x33};
    char *str="%d\n";
    _asm{
             mov dword ptr [ebp-8],0                 //s=0
             mov ebx,0                              //i=0
             jmp judge
round:       add ebx,1                     ebx进行计数

judge:      cmp ebx,3    
            jge end                   //  大于等于3则跳转到end
            mov edx,dword ptr [ebp-8]              
            add edx,dword ptr [ebx*4+424A30h]       //s=s+a[i]
            mov dword ptr [ebp-8],edx              // 把相加后的值放入[ebp-8]处
            mov dword ptr [ebp+ebx*4-14h],edx        //b[i]=s  
            mov ecx,dword ptr[ebp+ebx*4-14h]         
            push ecx
            push str
            call printf
            add esp,8
            jmp round
end:
                        xor eax,eax          //return 0
    }
}

运行结果:

在这里插入图片描述

0x04 小结

1.在内存中,数组可存在于栈,数据段及动态内存中,其寻址用“基址+偏移量”实现。这种间接寻址一般出现在给一些数组或是结构赋值的情况下.基址可以是常量,也可以是寄存器,为定值。根据偏移量的不同,可以对结构中相应单元赋值。

2.b[]数组放在栈中,这些栈在编译时分配。数组在声明时可以直接计算偏移地址,针对数组成员寻址是采用实际的偏移量完成的。

3.寄存器ebx可以用作数组的索引,非常类似于高级语言中的变量i

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值