为什么函数局部变量和参数被压入堆栈?
Why functions locals and arguments are pushed to the stack?
函数如何存储在内存中,即:作为普通变量表达式的数据段或代码段
在任何一个中将什么推入堆栈
指针?或者整个函数,如果局部变量和参数已经存储在数据段中,为什么我们还需要推送它们?
例如,在C/C++中,无论何时执行一个函数,执行范围都在堆栈内存中,即在堆栈中为该函数分配内存。这意味着其中的局部变量(包括参数)仅在该堆栈内可用,除非您将参数作为 address/reference 传递而不是按值传递。
在通过 reference/address 传递的情况下,我们使用指针来访问此函数外部存在的变量。
希望它能回答您的问题。如果不是,请提供更多详细信息。
函数存储在内存中。通常使用单独的段来存储可执行代码。内存管理器可以保护此内存不被更改。使用虚拟内存,任何未使用的代码都可以换出,并在代码(函数)必须执行时恢复。
全局数据存储在全局内存中。
本地数据分配在栈上。这些数据称为 "automatic variables".
调用函数时,return地址存储在栈中,前面是函数的参数。
所以,不,函数本身(可执行代码)没有存储在堆栈中。只有它的参数、本地数据和 return 地址。
注意:此简化描述基于英特尔。 "stack".
其他架构可能有不同的概念
虽然细节因平台而异 executable file formats and calling conventions, it's common for programs to be divided into multiple segments. Here's the general layout of a program for x86 (taken from here):
+------------------------+
high address | Command line arguments |
| and environment vars |
+------------------------+
| stack |
| - - - - - - - - - - - |
| | |
| V |
| |
| ^ |
| | |
| - - - - - - - - - - - |
| heap |
+------------------------+
| global and read- |
| only data |
+------------------------+
| program text |
low address | (machine code) |
+------------------------+
函数本身存放在程序正文段中,而函数操作的数据存放在其他段中。请注意,这是 虚拟 内存布局,而不是物理内存。
在大多数系统上,当您调用函数时,会从堆栈中分配一个堆栈帧。堆栈帧将有 space 用于函数参数和局部变量,以及前一个堆栈帧的地址和函数后要执行的下一条指令的地址 returns (同样,具体细节将根据调用约定不同):
+----------------+
high address: | argument N |
+----------------+
| argument N-1 |
+----------------+
...
+----------------+
| argument 1 |
+----------------+
| return addr |
+----------------+
| prv frame addr | <---- %ebp
+----------------+
| local 1 |
+----------------+
| local 2 |
+----------------+
...
+----------------+
low address: | local N | <---- %esp
+----------------+
除了堆栈指针寄存器(x86 上的%esp
,x86_64 上的%rsp
),还有一个基指针 寄存器( %ebp
在 x86 上,%rsp
在 x86_64 上)。该寄存器存储堆栈帧的地址,函数通过该地址的偏移量引用局部变量和参数。 Quick-n-dirty 示例:
int main( void )
{
int x = 1;
int y = 2;
printf( "foo(1,2) = %d\n", foo( x, y ) );
return 0;
}
这是编译代码的片段,我们在其中分配 x
和 y
(在可执行文件上使用 objdump -d
获得的清单):
55d: c7 45 f0 01 00 00 00 movl [=13=]x1,-0x10(%ebp)
564: c7 45 f4 02 00 00 00 movl [=13=]x2,-0xc(%ebp)
在此代码中,我们将值 1 写入位置 16 字节 "below" 存储在 %ebp
中的地址,并将值 2 写入位置 12 字节 "below" .
函数如何存储在内存中,即:作为普通变量表达式的数据段或代码段 在任何一个中将什么推入堆栈 指针?或者整个函数,如果局部变量和参数已经存储在数据段中,为什么我们还需要推送它们?
例如,在C/C++中,无论何时执行一个函数,执行范围都在堆栈内存中,即在堆栈中为该函数分配内存。这意味着其中的局部变量(包括参数)仅在该堆栈内可用,除非您将参数作为 address/reference 传递而不是按值传递。 在通过 reference/address 传递的情况下,我们使用指针来访问此函数外部存在的变量。
希望它能回答您的问题。如果不是,请提供更多详细信息。
函数存储在内存中。通常使用单独的段来存储可执行代码。内存管理器可以保护此内存不被更改。使用虚拟内存,任何未使用的代码都可以换出,并在代码(函数)必须执行时恢复。
全局数据存储在全局内存中。
本地数据分配在栈上。这些数据称为 "automatic variables".
调用函数时,return地址存储在栈中,前面是函数的参数。
所以,不,函数本身(可执行代码)没有存储在堆栈中。只有它的参数、本地数据和 return 地址。
注意:此简化描述基于英特尔。 "stack".
其他架构可能有不同的概念虽然细节因平台而异 executable file formats and calling conventions, it's common for programs to be divided into multiple segments. Here's the general layout of a program for x86 (taken from here):
+------------------------+
high address | Command line arguments |
| and environment vars |
+------------------------+
| stack |
| - - - - - - - - - - - |
| | |
| V |
| |
| ^ |
| | |
| - - - - - - - - - - - |
| heap |
+------------------------+
| global and read- |
| only data |
+------------------------+
| program text |
low address | (machine code) |
+------------------------+
函数本身存放在程序正文段中,而函数操作的数据存放在其他段中。请注意,这是 虚拟 内存布局,而不是物理内存。
在大多数系统上,当您调用函数时,会从堆栈中分配一个堆栈帧。堆栈帧将有 space 用于函数参数和局部变量,以及前一个堆栈帧的地址和函数后要执行的下一条指令的地址 returns (同样,具体细节将根据调用约定不同):
+----------------+
high address: | argument N |
+----------------+
| argument N-1 |
+----------------+
...
+----------------+
| argument 1 |
+----------------+
| return addr |
+----------------+
| prv frame addr | <---- %ebp
+----------------+
| local 1 |
+----------------+
| local 2 |
+----------------+
...
+----------------+
low address: | local N | <---- %esp
+----------------+
除了堆栈指针寄存器(x86 上的%esp
,x86_64 上的%rsp
),还有一个基指针 寄存器( %ebp
在 x86 上,%rsp
在 x86_64 上)。该寄存器存储堆栈帧的地址,函数通过该地址的偏移量引用局部变量和参数。 Quick-n-dirty 示例:
int main( void )
{
int x = 1;
int y = 2;
printf( "foo(1,2) = %d\n", foo( x, y ) );
return 0;
}
这是编译代码的片段,我们在其中分配 x
和 y
(在可执行文件上使用 objdump -d
获得的清单):
55d: c7 45 f0 01 00 00 00 movl [=13=]x1,-0x10(%ebp)
564: c7 45 f4 02 00 00 00 movl [=13=]x2,-0xc(%ebp)
在此代码中,我们将值 1 写入位置 16 字节 "below" 存储在 %ebp
中的地址,并将值 2 写入位置 12 字节 "below" .