反汇编解析一段小代码(面试题)

#include<iostream>
using namespace std;

struct S
{
	int a;
	int *p;
};
S s;
int main()
{
	int *temp=&s.a;
	temp[0]=10;
	temp[1]=12;
	s.p=temp;
	s.p[1]=20;
	s.p[0]=120;//报错
			
	return 0;
}

请问最后s.p[0]=120;为什么会报错?

原因如下:

住要是由于把temp赋值给了s.p,即把结构体的第一个变量的地址赋值给第二个变量的地址,又temp的内容(内存地址)=&s.a=s.p=&s.p[0],那么s.p[1]的地址也就是s.p的地址了(int类型是4个字节的,所以s.p[1]地址=&s.p[0]+4,s.p地址=temp(也就是&s.a)+4,很恐怖,数组的第二个变量的地址等于了数组首地址的地址了,换句话说也就是s.p[1]的内容和s.p的内容(存放的是数组首地址&s.p[0])是相等的,在意义上一个是地址一个是变量内容,竟然用同一个内存地址)。。。

经过s.p[1]=20赋值后; s.p内容(也就是s.p[0]的地址)就成了20,而s.p是等于数组首地址s.p[0]的,那么就是s.p[0]的地址变成了0x14了。

那么最后一句s.p[0]=120的意思就是把120写入到0x14这个地址指向的内容中去(这些地址的内容一般是RAM或者OS底层用了),当然会报错了。

我这边各变量地址及内容如下:

temp=00477738
&temp=0012FF7C
s.p=00477738
&s.p=0047773C
s.p[0]=10//因为temp[0]=10
&s.p[0]=00477738
s.p[1]=4683576
&s.p[1]=0047773C

可见temp=&s.p[0]=s.p;&s.p=&s.p[1]

反汇编如下:

12:       int *temp=&s.a;
00401048   mov         dword ptr [ebp-4],offset s (00432e08)
13:       temp[0]=10;
0040104F   mov         eax,dword ptr [ebp-4]
00401052   mov         dword ptr [eax],0Ah
14:       temp[1]=12;
00401058   mov         ecx,dword ptr [ebp-4]
0040105B   mov         dword ptr [ecx+4],0Ch
15:       s.p=temp;
00401062   mov         edx,dword ptr [ebp-4]
00401065   mov         dword ptr [s+4 (00432e0c)],edx
16:       s.p[1]=20;
0040106B   mov         eax,[s+4 (00432e0c)]
00401070   mov         dword ptr [eax+4],14h
17:       s.p[0]=120;
00401077   mov         ecx,dword ptr [s+4 (00432e0c)]
0040107D   mov         dword ptr [ecx],78h
18:
19:       return 0;
00401083   xor         eax,eax
20:   }

可以看到s.p[1]和s.p[0]都是同一内存地址寻址的(00432e0c),程序执行到16:的时候,内存状态如下:

00432E08  0A 00 00 00 08 2E 43     ---------------------00432E0C这个地址是s.p的地址(&s.p),s.p内容是(432e08),它(等于s.p[0]的地址)指向的内容是0A(十进制10)
00432E0F  00 00 00 00 00 00 00  
00432E16  00 00 24 E0 42 00 20 

执行完上面16步之后,s.p[1]=20;变成向s.p也就是&s.p[0]的内容432e08写20(因为s.p[1]的地址是等于s.p的地址的,给s.p[1]赋值就相当于给s.p的内容赋值,而s.p中存放的是s.p[0]的地址),执行完16步之后,内存状态如下:

00432E08  0A 00 00 00 14 00 00  ----------------------08 2E 43 变成了14 00 00(注意变量在内存中的存放方式,低位在前,高位在后)
00432E0F  00 00 00 00 00 00 00  
00432E16  00 00 24 E0 42 00 20

执行到17步第一个mov         ecx,dword ptr [s+4 (00432e0c)]后,ECX寄存器的值变成了00000014,最后一步编译器报错,提示该内存地址不能READ。

--------------------

希望大家也掌握这种反汇编分析方法来分析程序,这样分析的更透彻(因为能看到各个寄存器内存地址的变动)。

你可能感兴趣的:(反汇编解析一段小代码(面试题))