linuxalready

10章 内存: 进程地址空间 / 函数调用栈 & 反汇编 / h

2022-07-10  本文已影响0人  my_passion

1 Linux 进程地址空间 布局

     —————————————————————————————————————————————————— 
    |   6) OS kernel space                             |
    |                                                  |
    |   5) stack: 维护 函数调用 的 context/上下文    |  
    |       |                                          |
    |      \|/                                         |
    |                                                  |
    |   4) 动态链接库 映射区                           | 0x4000 0000
    |                                                  |
    |      /|\                                         |
    |       |                                          |
    |   3) heap: 容纳 应用程序 动态分配的内存区        |
    |                                                  |
    |   2) 可执行文件映像                              |
    |       read/write sections (.data .bss)           |
    |                                                  |
    |       readobly sections (.init .rodata .text)    | 0x0804 8000
    |                                                  |
    |   1) 保留区                                      |
    |                                                  |    
     ——————————————————————————————————————————————————  0 = NULL addr

2 栈 与 调用惯例

(1) 栈 & 函数调用 机制

进入 funcBody 第1条指令前:

    1) para 压栈 // 有的 para 用 register 传
    
    2) call func
    
        [1] call指令 next 指令地址 压栈
        
        [2] PC 设为 funcBody 第1条指令地址
           |
           |    <=> jump 到 funcBody 执行
           |/
          CPU 要执行的 next 指令

进入 funcBody 第1条指令: 1-7 配对 / 3-6 配对

    1) 保存 ebp + ebp 指向 当前栈顶
    
        [1] push ebp // 保存 caller 的 `帧指针 ebp` 到 当前栈顶
             |
             |  push = sub + mov
             |
            sub $4, esp
            mov (esp), ebp  // ebp -> (esp): 将 caller 的 `帧指针 ebp 保存` 
           
        [2] mov ebp, esp // esp -> ebp: 让 帧指针 ebp 指向 当前栈顶
                |     |
                |     |
                |   栈顶指针: 随栈的长消 动态变化
                |
              帧指针: 定位 函数栈帧 中 各数据
          
    2)  sub esp, 0x... // 栈上开辟空间
    
    3)  push 保存的 register (调用前后需保持不变 的 register -> 用于 -> 保存 context/上下文)

        push ebx / esi / edi  
                   |      |
                   |    第 1 para
                   |
                第 2 para
            
    4) funcCalc
    
    5) mov eax, returnVal // 返回值 用 eax 传递

    6) pop edi / esi / ebx              
    
    7) 恢复 `进入 func 前` 的 esp + ebp
    
        [1] mov esp, ebp // ebp -> esp
        
        [2] pop ebp
            |
            |
           mov ebp, (esp)
           add $4, esp
           
    8) ret // 返回
        |
        |
       [1] pop ( func 的) `返回地址`
       [2] 设给 PC
                |
                |
             CPU 要执行的 next 指令地址
// 取消 `帧指针 ebp`
           |
           |
    用 栈顶指针 esp 定位
           |
           |
           |/
    帧上寻址慢 + 无法准确定位 函数的 `调用轨迹(Stack Trace)`

// 反汇编
    
    int foo()
    {
        return 123;
    }

(2) 调用惯例 (Calling Convention): C++ 名字粉碎(Name-mangling)

    默认 `调用惯例 cdecl`
        int foo(int n, float m) -> 完整形式 -> int _cdecl foo(int n, float m) 

(3) 函数 返回值传递

1) 返回值 size <= eax 的 size (= 4Byte) -> 用 eax 传递

    func   存 returnValue 到 eax
    caller 读 eax        

2) >
    
        临时变量 
            地址存到 eax 

3 Linux 堆 内存管理

(1) 2 种 `堆空间 分配方式` / 2 个 `系统调用`

    brk() 
    
    mmap()
    
        void *mmap(
            void    *start,  // 要申请空间 的 起始地址 -> 设为 0 -> OS 自动挑选 合适的起始地址
            size_t  length,  // ............. 长度
            int     prot,    // 申请的空间 权限 R/W/X
            int     flags,   // 映射类型(2种): 文件映射 / `匿名空间`
            int     fd,      // 文件映射 时的 文件描述符
            off_t   offset); // 文件映射 时的 文件偏移

    glibc 中 malloc 实现
        
        请求 <= 128KB -> 现有堆空间按 `堆分配算法 (free list / 位图 /  )` 分配/拨出 一块空间 返回
                                        
             > 128KB -> 用 mmap() 分配一块 `匿名空间`

(2) 堆分配算法: 空闲链表 (free list)

多分配 4 Byte -> 存 所分配的内存块 size -> free/delete 据这 4Byte 知应该 释放多少空间

类 C++2.91 内存池 设计: 16 条 free list (空闲链表)
程序环境.jpg Linux 进程地址空间 布局.jpg 程序栈.jpg 栈帧结构.jpg 函数调用机制: 反汇编 分析.jpg 函数栈布局.jpg 函数调用链: 栈长消.jpg 返回值 传递: 返回值 size > eax.jpg
上一篇下一篇

猜你喜欢

热点阅读