【逆向学习记录】linux内存管理-内存布局

本文主要探讨了Linux操作系统中的内存管理,重点介绍了内存布局,包括text段、data段(包括rodata子段)、Bss段以及堆和栈段。通过案例源码和汇编代码的分析,阐述了不同段的作用和常量数据在rodata段的存储方式。对于嵌入式系统开发者,了解这些内存管理基础知识至关重要。

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值