原文: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);
}

如上圖所示,完全符合預期。更新下我們通過實驗確認後的內存分佈圖:

本篇到此為止,下篇再討論命令行參數與環境變數在內存中的分佈情況

--未完待續

由於本人水平有限,翻譯必然有很多不妥的地方,歡迎指正。

同時,歡迎關注下方微信公眾號,一起交流學習:)

推薦閱讀:
相關文章