原文:Hack The Virtual Memory: C strings & /proc - Holberton

翻译:RobotCode俱乐部

我们之前讨论过在进程的虚拟内存中可以找到什么,以及在哪里可以找到它。今天,我们将尝试「重建」下图,方法是列印程序中各个元素的地址。

The stack(栈)

我们要在图中定位的第一个区域就是栈。我们知道在C语言中,局部变数位于栈上。如果我们列印一个局部变数的地址,它应该会告诉我们在虚拟内存中哪里可以找到栈。让我们使用下面的程序来找出各种元素在内存中的分布:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/**
* main - print locations of various elements
*
* Return: EXIT_FAILURE if something failed. Otherwise EXIT_SUCCESS
*/
int main(void)
{
int a;

printf("Address of a: %p
", (void *)&a);
return (EXIT_SUCCESS);
}

译者注:实际程序被我修改了下,在printf后加了while(1);以方便我们观察maps

如上图所示,局部变数显然们于[stack]区。(译者注:但是静态局部变数不是放在stack区,而是放在heap区,后面再讨论

The heap(堆)

当你为变数malloc空间时,将使用堆。让我们添加一行代码来使用malloc,看看malloc返回的内存地址位于哪里(main-1.c):

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/**
* main - print locations of various elements
*
* Return: EXIT_FAILURE if something failed. Otherwise EXIT_SUCCESS
*/
int main(void)
{
int a;
void *p;

printf("Address of a: %p
", (void *)&a);
p = malloc(98);
if (p == NULL)
{
fprintf(stderr, "Cant malloc
");
return (EXIT_FAILURE);
}
printf("Allocated space in the heap: %p
", p);
return (EXIT_SUCCESS);
}

如上图很显然可以看出堆与栈的分布情况。可以画出如下图所示的图:

The executable(可执行文件)

你的程序也在虚拟内存中。如果我们列印主函数的地址,我们应该知道与栈和堆相比,程序的位置。让我们看看它是否像预期的那样位于堆下面(main-2.c):

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/**
* main - print locations of various elements
*
* Return: EXIT_FAILURE if something failed. Otherwise EXIT_SUCCESS
*/
int main(void)
{
int a;
void *p;

printf("Address of a: %p
", (void *)&a);
p = malloc(98);
if (p == NULL)
{
fprintf(stderr, "Cant malloc
");
return (EXIT_FAILURE);
}
printf("Allocated space in the heap: %p
", p);
printf("Address of function main: %p
", (void *)main);
return (EXIT_SUCCESS);
}

看起来我们的程序代码的确位于堆之下,这是意料之中的。

但我们要确保这是程序的实际代码,而不是指向其他位置的指针。让我们用objdump来分析我们的程序2,看看主函数的「内存地址」:

我们找到了完全相同的地址(0x8048464)。如果你仍然有任何疑问,可以列印位于这个地址的第一个位元组,以确保它们匹配objdump 的输出,看如下程序:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/**
* main - print locations of various elements
*
* Return: EXIT_FAILURE if something failed. Otherwise EXIT_SUCCESS
*/
int main(void)
{
int a;
void *p;
unsigned int i;

printf("Address of a: %p
", (void *)&a);
p = malloc(98);
if (p == NULL)
{
fprintf(stderr, "Cant malloc
");
return (EXIT_FAILURE);
}
printf("Allocated space in the heap: %p
", p);
printf("Address of function main: %p
", (void *)main);
printf("First bytes of the main function:
");
for (i = 0; i < 15; i++)
{
printf("%02x ", ((unsigned char *)main)[i]);
}
printf("
");
return (EXIT_SUCCESS);
}

如上图所示,完全符合预期。更新下我们通过实验确认后的内存分布图:

本篇到此为止,下篇再讨论命令行参数与环境变数在内存中的分布情况

--未完待续

由于本人水平有限,翻译必然有很多不妥的地方,欢迎指正。

同时,欢迎关注下方微信公众号,一起交流学习:)

推荐阅读:
相关文章