1 概述
前面学习栈溢出/格式化字符串,不懂操作系统,不懂内存管理通过看看栈内存,还能勉强懂一点,前几天开始学习堆的漏洞利用,发现不懂是真的不懂,把exp摔到脸上都看不懂,这就是问题了,于是反复思量,决定还是要分几次把内存管理学习一下,这次先是最基础的内存布局吧
参考文章:
linux系统进程的内存布局
笔记:程序内存管理 .bss .data .rodata .text stack heap
2 内存布局
先把下面经典的图亮出来

2.1 案例源码
首先编写一个程序看看:
#include<stdio.h>
#include<malloc.h>
static char *data_str = "AAAAAAAAAAAAAA";
static char bss_str[10];
int main(int argc, char **argv){
static int data_int = 12345;
static int bss_int;
int stack_int = 67890;
char *stack_str = "BBBBBBBBBBBBBBBB";
char *heap_str = NULL;
heap_str = malloc(sizeof(char) * 20);
if(!heap_str)
{
perror("malloc");
return -1;
}
sprintf(heap_str,"%s","HelloWorld\n");
printf("%s",heap_str);
free(heap_str);
return 0;
}
2.3 汇编代码
0x0804849b <+0>: lea ecx,[esp+0x4]
0x0804849f <+4>: and esp,0xfffffff0
0x080484a2 <+7>: push DWORD PTR [ecx-0x4]
0x080484a5 <+10>: push ebp
0x080484a6 <+11>: mov ebp,esp
0x080484a8 <+13>: push ecx
0x080484a9 <+14>: sub esp,0x14
0x080484ac <+17>: mov DWORD PTR [ebp-0x14],0x10932
0x080484b3 <+24>: mov DWORD PTR [ebp-0x10],0x80485cf
0x080484ba <+31>: mov DWORD PTR [ebp-0xc],0x0
0x080484c1 <+38>: sub esp,0xc
0x080484c4 <+41>: push 0x14
0x080484c6 <+43>: call 0x8048370 <malloc@plt>
0x080484cb <+48>: add esp,0x10
0x080484ce <+51>: mov DWORD PTR [ebp-0xc],eax
0x080484d1 <+54>: cmp DWORD PTR [ebp-0xc],0x0
0x080484d5 <+58>: jne 0x80484ee <main+83>
0x080484d7 <+60>: sub esp,0xc
0x080484da <+63>: push 0x80485e0
0x080484df <+68>: call 0x8048360 <perror@plt>
0x080484e4 <+73>: add esp,0x10
0x080484e7 <+76>: mov eax,0xffffffff
0x080484ec <+81>: jmp 0x804852b <main+144>
0x080484ee <+83>: mov eax,DWORD PTR [ebp-0xc]
0x080484f1 <+86>: mov DWORD PTR [eax],0x6c6c6548
0x080484f7 <+92>: mov DWORD PTR [eax+0x4],0x726f576f
0x080484fe <+99>: mov DWORD PTR [eax+0x8],0xa646c
0x08048505 <+106>: sub esp,0x8
0x08048508 <+109>: push DWORD PTR [ebp-0xc]
0x0804850b <+112>: push 0x80485e7
0x08048510 <+117>: call 0x8048340 <printf@plt>
0x08048515 <+122>: add esp,0x10
0x08048518 <+125>: sub esp,0xc
0x0804851b <+128>: push DWORD PTR [ebp-0xc]
0x0804851e <+131>: call 0x8048350 <free@plt>
0x08048523 <+136>: add esp,0x10
0x08048526 <+139>: mov eax,0x0
0x0804852b <+144>: mov ecx,DWORD PTR [ebp-0x4]
0x0804852e <+147>: leave
0x0804852f <+148>: lea esp,[ecx-0x4]
0x08048532 <+151>: ret
2.4 内存分段
2.4.1 text段
text就是代码段了,这个没啥可说的

2.4.2 data段
data段:静态内存分配区,已经初始化的静态变量存储在这里

同时注意一下rodata段

rodata段是常量数据段:
1)rodata用来存放常量数据。 ro: read only
2)字符串会被编译器自动放在rodata中,加 const 关键字的常量数据会被放在 rodata 中
3)在有的嵌入式系统中, rodata放在 ROM(或 NOR Flash)里,运行时直接读取,不须加载到RAM内存中。所以,在嵌入式开发中,常将已知的常量系数,表格数据等造表加以 const 关键字。存在ROM中,避免占用RAM空间。
因此:变量data_str在data段,但是data_str的值“AAAAAAAAAAAAAA”在rodata段
2.4.3 Bss段
未初始化的全局变量

2.4.4 heap段&stack段
因为堆的变量是保存在栈里面的,所以执行完malloc之后,堆栈图如下



所以:变量及其变量的内容都是保存在栈上。使用堆时,是把堆分配的地址放到栈上,内容放在堆上,因此赋值语句执行完成之后,可以看到,helloword字符串是保存在堆地址(0x804b008)里面的

2.5 因此最后的结果是
#include<stdio.h>
#include<malloc.h>
static char *data_str = "AAAAAAAAAAAAAA"; ####datastr变量在data段,但是字符串在rodata
static char bss_str[10];###bss段
int main(int argc, char **argv){
static int data_int = 12345;###data段
static int bss_int;###bss段
int stack_int = 67890; ###stack段
char *stack_str = "BBBBBBBBBBBBBBBB";
###stack_str在栈上保存的是字符串的地址
###字符串BB在rodata段
char *heap_str = NULL;
heap_str = malloc(sizeof(char) * 20);
###heap_str在栈上保存的地址,地址指向堆段
if(!heap_str)
{
perror("malloc");
return -1;
}
sprintf(heap_str,"%s","HelloWorld\n");
printf("%s",heap_str);
free(heap_str);
return 0;
}
本文主要探讨了Linux操作系统中的内存管理,重点介绍了内存布局,包括text段、data段(包括rodata子段)、Bss段以及堆和栈段。通过案例源码和汇编代码的分析,阐述了不同段的作用和常量数据在rodata段的存储方式。对于嵌入式系统开发者,了解这些内存管理基础知识至关重要。

417

被折叠的 条评论
为什么被折叠?



