美文网首页linuxalready
10章 内存: 进程地址空间 / 函数调用栈 & 反汇编 / h

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

作者: my_passion | 来源:发表于2022-07-10 16:38 被阅读0次

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

相关文章

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

    1 Linux 进程地址空间 布局 2 栈 与 调用惯例 (1) 栈 & 函数调用 机制 进入 funcBody ...

  • linux 下的进程内存和c++程序的内存分配

    一、进程的空间分配/C语言 1、栈 向下生长及内存地址减小的方向 定义:自动变量以及每次函数调用时所需保存的信息...

  • Day14

    内存管理 程序是静态的,进程是动态的 进程空间图示 栈内存 堆内存 基本概念 malloc函数 memset函数 ...

  • 2019-03-19

    1.函数调用过程: 函数调用过程又叫压栈的过程:每次调用函数,系统都会在内存的栈区间自动开辟一个临时的内存空间, ...

  • 图解Linux是如何进行函数调用的?

    开篇依旧先提出几个问题: 进程虚拟地址空间是如何分布的? 函数调用的栈帧结构是什么样子? 函数调用涉及到的寄存器都...

  • [c/c++]3.如何查看和更改程序运行栈的大小

    进程内存布局 我们写程序运行栈的栈帧保存在栈区,函数调用深度太多将导致爆栈栈的大小有上限,每个进程可以指定软上限,...

  • Android性能优化---基础知识

    进程的地址空间为0到4GB,示意图如下: Stack空间(进栈和出栈)由操作系统控制,其中主要存储函数地址、函数参...

  • 数组

    一. 栈和堆 栈:当一个函数调用时,会在栈内存中申请一个空间,当函数中定义一个变量时,会分配到这个函数申请的栈空间...

  • 2018-07-30

    一、什么是内联函数 在C语言中,如果一些函数被频繁调用,不断地有函数入栈,即函数栈,会造成栈空间或栈内存的大量消耗...

  • 第15章 进程地址空间

    内核除了管理本身的内存外,还必须管理用户空间中进程的内存,也就是进程地址空间。 一、地址空间 进程地址空间由进程可...

网友评论

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

    本文链接:https://www.haomeiwen.com/subject/tswwbrtx.html