写一个程序从VM进程地址空间理解函数激活(函数栈)以及代码段(正文段)

Posted 狱典司

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了写一个程序从VM进程地址空间理解函数激活(函数栈)以及代码段(正文段)相关的知识,希望对你有一定的参考价值。

  • 理解的过程看输出就能明白
  • 输出结果:
  • 代码如下:
#include<iostream>
#include<stdio.h>
#include<typeinfo>
#include <stdlib.h>

using namespace std;


int func1(int val, int *preAddr){
	int a = 0;
	unsigned int i;
	int *ad = &a;

	printf("the address of func1:%p\\n", &func1);
	if(preAddr != 0) printf("the Pre-address of a(十进制): %d\\n", preAddr);
	printf("the address of a in func1(十进制): %d\\n", ad);
	printf("the address of a in func1(32位十六进制): %p\\n", &a);
	

	long long int len = (int&)preAddr - (int&)ad;
	preAddr = ad;
	
	if(len > 0)	printf("由func1两次递归中各自a的地址差值可知栈中函数激活的长度为 : %lld Bytes\\n", len);
	printf("__________________________________________________________\\n");
	
	
	val++;
	while(val < 2) val += func1(val,preAddr);
	return val;
}

void func2(){
	int a = 0;
}

void func3(){
	int a = 0;
}

void func4(){
	int a = 0;
}

void func5(){
	int a; 
}

void func6(){
	int a; 
}

void func7(){
	int a;
	a = 0; 
}

void func8(){
	int a;
	a = 0; 
}

#define SHW_ADR(ID,I) printf("The %s is at address: %d\\n",ID,&I);//打印地址宏
int main(){
	func1(0,0);
	SHW_ADR("main ",main);//查看代码段main函数位置
	SHW_ADR("func2 ",func2);
	SHW_ADR("func3 ",func3);
	SHW_ADR("func4 ",func4);
	int *ad3 = ( (int*)(&func3) ); //做函数类型到指针类型的转换,难点 
	int *ad4 = ( (int*)(&func4) );
	int lenOfFunc3 = (int&)ad4 - (int&)ad3;
	printf("可以看到func2~4的起始地址间隔相等,且它们的函数体也相等,\\n故可以得出func2~func4的大小就是他们起始地址的间隔:%lld Bytes\\n",lenOfFunc3);
	
	printf("__________________________________________________________\\n");
	printf("在上述结果的基础上,我们设置四个函数:\\n(1) func5函数:只做int a的声明\\n(2) func6函数:与func5一致,为计算func5的大小\\n(3) func7函数:在func5的基础上给a赋值\\n(4) func8函数:与func7一致,为计算func7的大小\\n");
	
	SHW_ADR("func5 ",func5);
	SHW_ADR("func6 ",func6);
	SHW_ADR("func7 ",func7);
	SHW_ADR("func8 ",func8);
	
	int *ad5 = ( (int*)(&func5) ); //做函数类型到指针类型的转换,难点 
	int *ad6 = ( (int*)(&func6) );
	int lenOfFunc5 = (int&)ad6 - (int&)ad5;
	printf("func5函数大小为:%d Bytes\\n",lenOfFunc5);
	
	int *ad7 = ( (int*)(&func7) ); //做函数类型到指针类型的转换,难点 
	int *ad8 = ( (int*)(&func8) );
	int lenOfFunc7 = (int&)ad8 - (int&)ad7;
	printf("func7函数大小为:%d Bytes\\n\\n",lenOfFunc7);
	
	printf("由于func7只比func5多了一个赋值语句,\\n故可知一个赋值语句的大小大约是:%d Bytes\\n", lenOfFunc7-lenOfFunc5); 
	return 0; 
}

需要注意的是各种类型数据地址的类型转化

以上是关于写一个程序从VM进程地址空间理解函数激活(函数栈)以及代码段(正文段)的主要内容,如果未能解决你的问题,请参考以下文章

Linux进程地址空间与进程内存布局详解,内核空间与用户空间

环境变量与进程地址空间理解

从c语言函数调用看程序的栈机制

[Android Pro] 深入理解函数的调用过程——栈帧

可重入函数与线程安全

深入理解C语言从函数栈帧角度理解return关键字