文章

滴水-day11-数组反汇编-参数传递

数组在汇编中是以局部变量的形式存储的

007F1825  mov         dword ptr [array],1
007F182C  mov         dword ptr [ebp-10h],2
007F1833  mov         dword ptr [ebp-0Ch],3
007F183A  mov         dword ptr [ebp-8],4

64位的数据是如何存储的,在C/C++中64位可以写为long long类型或者是写为__int64,当程序的返回值是在32位内的话是通过eax的方式进行返回。eax存储低位,edx存储高位

参数传递的本质

参数的传递,即使函数的参数类型不是32位,在调用函数时候传递的参数也是按照32位传递的,但是在函数内部使用参数的时候是按照参数自身宽度使用的。

8位

当我push两个参数的时候,esp是递减4的,但我函数的参数是char类型8位1字节的

所以说在传递参数的时候,不论参数的宽度多少,只传递32位4字节的。

16位

esp还是递减4,这也说明了即使是16位参数也是按照32位进行参数传递的

32位

这没什么好说的了,本来就是32位的。

总结:参数的传递宽度不是按照参数的宽度传递的,而是这个程序是多少位,32位程序就按照32位进行参数传递,64位同理。但是参数在函数内部使用的过程还是按照参数的自身宽度而使用的,定义参数类型为char,short并不能节省空间,反而还会浪费空间,因为在汇编中会多一步转换。参数的传递的就是调用函数的当前函数的局部变量赋值一份传递给了被调用的函数。参数是存储在EBP+8(+4)处,而局部变量是EBP-4(+4)处,没有什么区别,都是存储在堆栈中的。

结论:整数类型的参数一律使用int类型。

局部变量的内存分配


局部变量通常都保存到当前函数的堆栈缓冲区中,

如果局部变量的类型小于32位那么分配空间的时候也是按照32位去分配的,我现在本机是64位的,vs2019默认给我的空间是C0,在32位机器中是0x40,

当给局部变量分配内存的时候0x40会递增4。

局部变量和参数没有什么区别,都是存储在堆栈中的。

虽然内存分配是32位的,但是在实际使用局部变量的时候还是按照本身的宽度使用的

数组的本质

数组的本质就是一坨局部变量

int array(char a, char b)
{
	int array[] = { 1,2,3,4,5,6,7 };
	return 0;
}


int array()
{
	int a = 1;
	int b = 2;
	int c = 3;
	int d = 4;
	int e = 5;
	//int array[] = { 1,2,3,4,5,6,7 };
	return 0;
}

这没啥区别,只是存储的地址一样,但还是存储到了局部变量的部分

在现在的C++标准中允许使用未定义的数组大小,但是不能使用变量来作为数组的大小,因为变量无法确定宽度,编译器无法开辟新的堆栈空间

数组的使用

数组使用是从下标0开始依次递增的,数组越界编译器不会提示,但在运行的过程中可能会出现未知的值。

练习

1. 返回值超过32位时,存在哪里?用long long(__int64)类型做实验

经过反汇编可以知道,当程序是32位的时候但使用了64位的数据进行存储,那么会把前32位存储到eax中,后32位存储到局部变量中,再把eax存储到局部变量中,其实就是前32位

当返回64位数据的时候是吧eax和edx作为传递中介去返回给调用者。

2. Char arr[3] = {1,2,3};与 Char arr[4] = {1,2,3,4};

哪个更节省空间,从反汇编的角度来说明你的观点

从汇编的角度来看的话,是第一个更省空间

我说过,数组其实就是局部变量,而局部变量在分配空间的时候,不论是多少位都按照32位分配

而在数组中,当数据类型小于32位的时候则不是按照32位进行分配的,当前数组是什么类型有多个字节就按多少个字节分配。

比如这里的ary[3]在分配空间的时候就是EBP-4,5,6而不是4,8,C

既然这样arry[3]肯定是用了3个字节的空间,而arr[4]用了4个字节的空间

所以来说是arr[3]更节省了空间

3. 找出下面赋值过程的反汇编代码

void Function()
{
	int x = 1;
	int y = 2;
	int r;
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};

	r = arr[1];
	r = arr[x];
	r = arr[x+y];
	r = arr[x*2+y];
}

int x = 1; ----> mov dword ptr [ebp-8],1

int y = 2; ----> mov dword ptr [ebp-14h],2

int arr[10] ---->

mov dword ptr [ebp-50h],1

mov dword ptr [ebp-4Ch],2

mov dword ptr [ebp-48h],3

mov dword ptr [ebp-44h],4

mov dword ptr [ebp-40h],5

mov dword ptr [ebp-3Ch],6

mov dword ptr [ebp-38h],7

mov dword ptr [ebp-34h],8

mov dword ptr [ebp-30h],9

mov dword ptr [ebp-2Ch],0Ah

r = arr[1] ---->

00C35801 mov ecx,dword ptr [ebp+eax-50h]

00C35805 mov dword ptr [ebp-20h],ecx

ebp+4是偏移量,arr[1]在数组中的偏移量就是4个字节。

r = arr[x] --->

00C35808 mov eax,dword ptr [ebp-8]

00C3580B mov ecx,dword ptr [ebp+eax*4-50h]

mov dword ptr [ebp-20h],ecx

ebp-8是局部变量1,ebp+eax*4-50

为什么乘以4呢,因为数组是int类型的,每个数据之间的偏移量就是4,当ebp-8存储的的2的时候

2*4=8,0x50-8=0x48取到的是数组ebp-48处就是3.

r = arr[x+y]---->

mov eax,dword ptr [ebp-8]

add eax,dword ptr [ebp-14h]

mov ecx,dword ptr [ebp+eax*4-50h]

mov dword ptr [ebp-20h],ecx

两个局部变量相加保存到eax中,3,通过ebp+eax*4-50h可以取到ebp-44处就是4

r = arr[x*2+y]---->

mov eax,dword ptr [ebp-8]

mov ecx,dword ptr [ebp-14h]

lea edx,[ecx+eax*2]

mov eax,dword ptr [ebp+edx*4-50h]

mov dword ptr [ebp-20h],eax

eax=1,ecx=2,edx=4

eax=ebp-40=5

ebp-20=5

4. 桶排序

void arraySort()
{
	int array[] = { 2,4,6,5,3,1,2,7 };
	int array2[8] = { 0 };
	for (int i = 0; i < 8; i++)
	{
		for (int j = 0; j < 8; j++)
		{
			if (array[i] == j)
			{
				array2[j] += 1;
			}
		}
	}

	// 抽象代码。。。。。
	for (int i = 0; i < 8; i++)
	{

		if (array2[i] == 1)
		{
			printf("%d ", i);
		}
		else if (array2[i] == 2)
		{
			printf("%d %d ", i, i);
		}
	}
}

代码很抽象,实在是想不到好像方式输出了。

void arraySort()
{
	int array[] = { 2,4,6,5,3,1,2,7 };
	int arrayLength = sizeof(array) / sizeof(array[0]);

	// 找出数组最大值
	int bigNumber = array[0];
	for (int i = 0; i < arrayLength; i++)
	{
		if (array[i] > bigNumber){
			bigNumber = array[i];
		}
	}

	// 动态分配内存
	int* array2 = new int[10]{0};

	//// 动态分配内存
	//int* array2 = (int*)malloc((bigNumber + 1) * sizeof(int));
	//if (array2 == NULL)
	//{
	//	printf("Memory allocation failed\\\\n");
	//	return;
	//}
	//// 内存初始化
	//for (int i = 0; i <= bigNumber; i++)
	//{
	//	array2[i] = 0;
	//}

    // 桶排序逻辑执行
	for (int i = 0; i < arrayLength; i++)
	{
		for (int j = 0; j < 8; j++)
		{
			if (array[i] == j)
			{
				array2[j] += 1;
			}
		}
	}

	// 抽象代码。。。。。
	/*for (int i = 0; i < 8; i++)
	{

		if (array2[i] == 1)
		{
			printf("%d ", i);
		}
		else if (array2[i] == 2)
		{
			printf("%d %d ", i, i);
		}
	}*/
	for (int i = 0; i < 8; i++)
	{
		for (int j = 0; j < array2[i]; j++)
		{
			printf("%d ", i);
		}
	}

	delete[] array2;
}

练习

day11.cpp

License:  CC BY 4.0