我们都知道一个程序四区:代码区,静态区,栈区,堆区。
先说一下各个变量以及对象字函数在内存中的的位置:
02A18AC2-4594-4F0B-B9DD-579A5418F7F1.png
对象可在栈区,也可在堆区。主要是是不是用malloc ,relloc,calloc,new,alloc等,而这些代码会在代码区存放。静态字符串,全变量等则在静态区。
为了更好的说明,我们简化一下代码:
void test(int a);
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
test(10);//函数地址堆
//汇编的下局代码地址 栈
}
return 0;
}
void test(int a)
{
int pp = 10;
printf("%d",a + pp);
}
然后打个断点看看。
DC1FAF09-1199-4E1E-85FB-924BD6BFAED6.png
test 函数的函数地址是0x100000f30;而返回地址应该是0x100000f19;
而作为参数( movl $0xa, %edi)的10应该是栈区的,我刚刚重新运行了代码,所以地址有所偏差,我去看看栈区。
那么怎么看栈区,先用 register read看看堆栈的区域
(可以看出代码段指针是rip.)
我们注意到rbp和rsp 分别是0x00007fff5fbff660。和0x00007fff5fbff640。这一块就是当前的栈区了。我在我去读下memory read --size 8 -f x --count 20 0x00007fff5fbff640
94603A1C-A4DA-4091-B192-4EA9A5E597FC.png
发现没有10 没入栈,这是为什么呢。以为上面的汇编地址:
-> 0x100000f10 <+32>: movq %rax, -0x18(%rbp)
说明这样传值进去平不会把10放进栈区。那加一个变量吧。立马会有的最终代码是这样的:
void test(int a);
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
int a = 10;
test(a);//函数地址堆
//汇编的下局代码地址 栈
}
return 0;
}
void test(int a)
{
int pp = 10;
printf("%d",a + pp);
}
汇编代码如下:
EBBDDAF2-CD65-4237-902D-A2AFBDFCA29B.png
0x100000f0b <+27>: movl $0xa, -0x14(%rbp)
10被放在rbp-0x14的地方了。由于加了一句代码返回地址变为:0x0000000100000f1e(执行完test函数要到test下面代码这里执行。)。
ED72CE3A-7957-4091-B08E-01765273207C.png
int 占4个自己所以size 要用4了。可以清楚的看到int a 被放进栈区了。
其实test 函数地址也是在栈区的。上面有说过返回地址(call 0x10000f1e)也是在栈区的。虽然没有看到把函数地址和返回地址入栈。说明call方法帮我做了这些。我在test方法里面打了断点。进去看看。看看栈内存就知道了。
5A2CC5BD-0F27-4B6F-9C4C-D5F099C04B78.png
确实返回函数已经入栈。
在返回地址上面我可以看出里面有个10也入栈了(--szie 4看的话)。
这充分说明实参和形参是值传递。我就截图给你们看看吧:
FC704615-011C-4A3A-9FD8-8E80E3B91AE4.png
地址明显不一样哦。
还有可以看看当前栈区地址。和main里面又啥不一样。
此外可以看看返回值是问题。我可以告诉你返回值是rax寄存器里面的。
网友评论