c 函数调用产生的汇编指令和数据在内存情况(2)
一直对函数调用的具体汇编指令和各种变量在内存的具体分配,一知半解。各种资料都很详细,但是不实践,不亲自查看下内存总不能笃定。那就自己做下。
两个目的:
一,函数和函数调用编译后的汇编指令基本样貌
二,各种变量类型的内存状况。
二,各种变量类型的内存状况。
1)常见变量在内存的位置
2)自定义结构体
1),常见变量在内存的位置。
结论:全局变量:程序一加载,和代码一样,已经在内存,放入静态区。
未初始化,内存数据用00或默认直代替。
地址变量(指针类型)放入地址直。
未初始化放入0x00000000.
局部变量: int 和char 等基本类型,程序加载时,不放入任何地方。
只有通过代码才能知道定义了一个变量。
运行代码时 push 1,放入栈中,通过 ebp+x等方式获取。
而int[5] 和char[5] 类拭固定大小数据,一般是放入静态区,编译器在编译阶段已经把使用变量的地方用 变量的偏移地址代替了。如果函数没使用,直接作为其他函数的参数,那也会直接push。不放入静态区,如下例的 p_char2[5]。
不是固定大小的变量放入,如指针,放入静态区。。等等,如果中途改变大小呢,怎么办?等下测试。测试发现会有2个临时变量名。
char * p_char3="hi.";
int p_int2[5]={1,2,3,4,5};
p_char3="hihi.";
LC2:
DB "hihi.",0x00
LC0:
DB "hi.",0x00
代码
int g_int1=3;//静态区.装载程序时已经放入内存
int g_int2;//静态区.装载程序时已经放入内存(放在 char * p_char3="hi."的后面).用4个字节的0来占位。
int HariMain(void)
{
int p_int=1;//代码没有执行,不存在任何地方,执行后,push 1,放入栈中。
char p_char='a';// 代码没有执行,不存在任何地方,执行后,push 1,放入栈中。
char p_char2[5]={'a','b','c','d','e'};//
//代码没有执行,不存在任何地方,执行后,用mov指令放入栈.
//mov BYTE [-56+EBP],97
char
* p_char3="hi.";//静态区. 装载程序时已经放入内存
int p_int2[5]={1,2,3,4,5};//静态区. 装载程序时已经放入内存
unsigned int sum;
sum=count(p_int,p_char,p_char2,p_char3,p_int2);
sum+=g_int1;
sum+=g_int2;
}
unsigned int count(int a,char c1,char c2[5],char * c3,int i2[5])
{
unsigned int c;
c=0;
c+=a;
c=c+c1;
c+=c2[0];
c+=c2[3];
c+=i2[0];
c+=i2[4];
c+=c3[0];
c+=c3[1];
return c;
}
数据 在内存的位置
程序装载时,
//代码区 0x0028001b
//
//^
//栈顶(空栈) 0x00310000
//静态区 0x00310000
程序运行时
//代码区 0x0028001b
/
//(栈顶)被调者的临时变量
//被调者的局部变量
//调用前的ebp寄存器直(而当前的ebp寄存器存放的这个位置的地址)
//返回地址
//参数
//栈底(空栈) 0x00310000
//静态区 0x00310000
二,自定义结构体
结论:自定义结构,可以看作数组。
自定义结构,作为参数的话,会把所有成员变量,一个一个入栈
如果 传递自定义结构指针,那么只传地址。
//全局自定义结构体变量, 和全局定长数组类拭。
程序一加载,和代码一样,已经在内存,放入静态区。
未初始化放入00数据,
代码中出现变量名,用地址代替。[_struce_a]
赋直:
MOV BYTE [_myStruck_a+4],97
直接 地址+数字定位成员
全局自定义结构体地址变量(指针),
程序一加载,和代码一样,已经在内存,放入静态区。
但是大小不是struck的大小,而是4B,也就是一个地址变量的大小。
未初始化放入0x00000000.
赋直:
MOV EDX,DWORD [_myStruck_c]
MOV DWORD [8+EDX],3
必须取地址的直得到真正的地址再加数字定位成员
//局部变量,
程序一加载,不存在任何地方。
只有运行时,放入栈中。如:
struct myStruck myStruck_d;
编译为SUB ESP,60
myStruck_d.char_b='e'
编译为
MOV BYTE [-36+EBP],101
call 之后的栈数据.
struct myStruck{
int int_a;
char char_b;
int int_array[2];
char * char_array;
};
int HariMain(void)
{
char c1[2]={'b','c'};
//myStruck_a.int_a=1;
myStruck_a.char_b='a';//MOV BYTE [_myStruck_a+4],97
myStruck_a.int_array[0]=1;//MOV DWORD [_myStruck_a+8],1
myStruck_a.int_array[1]=2;//MOV DWORD [_myStruck_a+12],2
//myStruck_a.char_array=c1;
//MOV EAX,DWORD [_myStruck_c]
myStruck_c->int_a=2;//MOV DWORD [EAX],2
myStruck_c->char_b='c';//MOV BYTE [4+EAX],99
//MOV EDX,DWORD [_myStruck_c]
myStruck_c->int_array[0]=3;//MOV DWORD [8+EDX],3
myStruck_c->int_array[1]=4;//MOV DWORD [12+EDX],4
myStruck_c->char_array=c1;//LEA EAX,DWORD [-42+EBP] MOV DWORD [16+EDX],EAX
//MOV EBP,ESP
//SUB ESP,60
struct myStruck myStruck_d;
myStruck_d.char_b='e';//MOV BYTE [-36+EBP],101
myStruck_d.int_array[0]=5;//MOV DWORD [-32+EBP],5
myStruck_d.int_array[1]=6;//MOV DWORD [-28+EBP],6
unsigned int c=counta(myStruck_a,myStruck_c,myStruck_d);
io_hlt();
return 0;
}
unsigned int counta(struct myStruck mys,struct myStruck * mysc,struct myStruck mys2)
{
unsigned int c;
c=0;
c=mys.int_a;
c=c+mysc->int_a;//ADD EAX,DWORD [8+EBP]
c=c+mysc->char_array[0];//MOV EDX,DWORD [28+EBP] MOV EDX,DWORD [16+EDX] ADD EAX,EDX //char_array[0]
c=c+mys.char_array[0];//
c=c+mys2.int_a;
return c;
}
c 函数调用产生的汇编指令和数据在内存情况(2)的更多相关文章
- c 函数调用产生的汇编指令和数据在内存情况(1)
一直对函数调用的具体汇编指令和各种变量在内存的具体分配,一知半解.各种资料都很详细,但是不实践,不亲自查看下内存总不能笃定.那就自己做下. 两个目的: 一,函数和函数调用编译后的汇编指令基本样貌 二, ...
- C语言函数调用过程,汇编角度查看
C语言函数调用过程,汇编角度查看 把函数的参数按照调用约定压栈或者存储到寄存器中 调用要使用的函数,先把调用者的地址入栈,方便回来 跳转到函数 把函数使用到的一些寄存器压栈,避免修改寄存器的值 执行函 ...
- c++ 汇编代码看内存分配
汇编代码看内存分配 (1). 程序运行时分为存储区域分为 存储区域 存储内容 extra 代码区 存放代码指令,包括除字符串常量的字面值 静态存储区 存放静态变量和全局变量 执行main之前就分配好了 ...
- iOS图片加载到内存中占用内存情况
我的测试结果: 图片占用内存 图片尺寸 .png文件大小 1MB 512*512 316KB 4MB 10 ...
- php测试程序运行时间和占用内存情况
php测试程序运行时间和占用内存情况: $HeaderTime = microtime(true);//参数true表示返回浮点数值 /** *CODE */ printf(" total ...
- Android内存管理(5)*官方教程:Logcat内存日志各字段含义,查看当前内存快照,跟踪记录内存分配,用adb查看内存情况时各行列的含义,捕获内存快照的3种方法,如何让程序暴漏内存泄漏的方法
Investigating Your RAM Usage In this document Interpreting Log Messages 内存分析日志中各消息的含 ...
- linux 查看cpu个数,内存情况,系统版本
查看cpu个数 总核数 = 物理CPU个数 * 每颗物理CPU的核数 总逻辑CPU数 = 物理CPU个数 * 每颗物理CPU的核数 * 超线程数 查看物理CPU个数 cat /proc/cpuinfo ...
- Linux 查看进程消耗内存情况总结
在Linux中,有很多命令或工具查看内存使用情况,今天我们来看看如何查看进程消耗.占用的内存情况,Linux的内存管理和相关概念要比Windows复杂一些.在此之前,我们需要了解一下Linux系统下面 ...
- 使用jconsole分析内存情况-JVM
JVM调优分析演练: Jconsole中对内存为如下结构: 原始代码: public static void main(String[] args) { BigInteger [] pArr=new ...
随机推荐
- Windows Thin PC 激活方法
Windows Thin PC 激活方法 笔者之前分享了Windows Thin PC ,如果你已经安装了Windows Thin PC ,但还没有激活,可以参照以下方式进行Windows Thin ...
- expdp impdp中 exclude/include 的使用
exclude和include参数能够在使用expdp或impdp是对特定的对象或对象类型进行筛选或过滤.比如因工作的需要导出特定的表或不导出特定 的表.视图以及存储过程.索引.约束.授权统计信息等等 ...
- Android studio中设置颜色的状态选择器
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item andro ...
- Git and GitHub
1.GitHub 创建一个仓库 2.进入本地要管理的某个文件夹下,感觉目录的操作命令和linux里面差不多, $git init 此时该文件下就会多出一个.git的文件 3.进入要上传的仓库,右键gi ...
- java中的内存一般分成几部分?
java中的内存被分成以下四部分: ①.代码区 ②.栈区 ③.堆区 ④.静态区域 栈区:由编译器自动分配释放,存放函数的参数值.局部变量的值等:具体方法执行结束后,系统自动释放JVM内存资源 ...
- quick lua 使用spine骨骼动画
看下下面两个文件 <spine/SkeletonRenderer.h><spine/SkeletonAnimation.h> 1.lua中创建方法: sp.SkeletonAn ...
- vi编辑文件E437: terminal capability "cm" required 解决办法
E437: terminal capability "cm" required 这个错误一般是环境变量TERM没有配置或者配置错误所致. 解决办法: 执行export TERM=x ...
- UVa 10047,独轮车
题目链接:https://uva.onlinejudge.org/external/100/10047.pdf 题目链接:http://vjudge.net/contest/132239#proble ...
- laravel框架总结(一) -- 请求和响应
一.laravel请求 1.获取请求 1>获取请求的 URI path 方法会返回请求的 URI.所以,如果接收到的请求目标是 http://domain.com/foo/bar,那么 path ...
- log4j: 不同的类使用不同的日志
有时候会需要某些功能中使用独立的日志文件,以下为代码示例. public final static String LOGGER_NAME = "MyFunction"; priva ...