美文网首页
通过x86汇编再看内存中的函数调用过程

通过x86汇编再看内存中的函数调用过程

作者: czs_0_0_0_0 | 来源:发表于2019-03-16 18:44 被阅读0次

以前通过C语言的学习大概了解了一些函数调用的过程。即在进程的栈中存在栈指针和基指针两种指针,一直指向栈顶,而基指针则指向当前函数的返回值。通过改变栈指针和基指针来实现函数的调用和返回。自从接触汇编后才对这块儿有了更深的理解。

在x86平台的汇编中栈涉及到三个寄存器:
SS(段寄存器)
SP(栈指针)
BP(基指针)
SS寄存器一直指向栈段地址,SP指向栈段偏移地址,因为汇编中地址的表示方式是"XXXX:XXXX"(不过居然不存在栈底这个概念)。

当一个函数在执行的过程中需要调用另一个函数时则会使用call指令,call指令执行时会先将IP寄存器(代码段偏移地址)的值push入栈中然后再调用jmp指令进行跳转,跳转到调用函数的地址,然后开始执行调用的函数的代码。

在执行完成后再使用ret指令进行返回,ret指令会将栈顶元素pop到IP寄存器中从而继续执行之前函数的代码。

那么举个例子,先上C语言测试代码:

int cz(int a, int b) {
    return a + b;
}

int main() {
    int c = cz(7, 8);
    return 0;
}

内容很简单,先定义一个cz函数,将两个变量a和b相加并返回。之后在main函数里进行调用。编译成可执行文件后再用反汇编工具看到汇编代码如下:

        ; ================ B E G I N N I N G   O F   P R O C E D U R E ================

        ; Variables:
        ;    var_4: int32_t, -4
        ;    var_8: int32_t, -8


                     _cz:;cz函数入口
0000000100000f60         push       rbp    ;将BP指针推入栈,BP此时的内容是cz函数的返回栈地址
0000000100000f61         mov        rbp, rsp
0000000100000f64         mov        dword [rbp+var_4], edi;下面几步执行a和b的相加
0000000100000f67         mov        dword [rbp+var_8], esi
0000000100000f6a         mov        esi, dword [rbp+var_4];由于栈是向下生长,所以地址要做减法
0000000100000f6d         add        esi, dword [rbp+var_8]
0000000100000f70         mov        eax, esi
0000000100000f72         pop        rbp
0000000100000f73         ret;函数返回并更新IP指针让main函数继续执行
                        ; endp
0000000100000f74         align      128


        ; ================ B E G I N N I N G   O F   P R O C E D U R E ================

        ; Variables:
        ;    var_4: int32_t, -4
        ;    var_8: int32_t, -8


                     _main:;mian函数入口
0000000100000f80         push       rbp
0000000100000f81         mov        rbp, rsp
0000000100000f84         sub        rsp, 0x10
0000000100000f88         mov        edi, 0x7                                    ; 参数a
0000000100000f8d         mov        esi, 0x8                                    ; 参数b
0000000100000f92         mov        dword [rbp+var_4], 0x0
0000000100000f99         call       _cz                                     ;执行cz函数
0000000100000f9e         xor        esi, esi
0000000100000fa0         mov        dword [rbp+var_8], eax
0000000100000fa3         mov        eax, esi
0000000100000fa5         add        rsp, 0x10
0000000100000fa9         pop        rbp
0000000100000faa         ret
                        ; endp
0000000100000fab         db  0x90 ; '.'

关键的地方加了注释,由于我的电脑是64位机,所以寄存器前面加了“r”表示取64位的值。

PS:当时在索尼现场搞bug的时候经常会看到的PC指针应该就是高通平台的代码段片偏移地址,当时看着底层的各种crash栈信息真是一脸懵逼。

相关文章

  • 通过x86汇编再看内存中的函数调用过程

    以前通过C语言的学习大概了解了一些函数调用的过程。即在进程的栈中存在栈指针和基指针两种指针,一直指向栈顶,而基指针...

  • C语言编程: 函数调用中堆栈的个人理解

    接下来将通过下面几个问题解析函数调用中对堆栈理解: (1)函数调用过程中堆栈在内存中存放的结构如何? (2)汇编语...

  • Linux boot的第一步:启动汇编调用main函数

    为了讲清原理,我们首先介绍C函数调用机制,然后再介绍汇编调用C函数。 一、C函数调用机制 对于汇编中的函数,其使用...

  • 多态--虚函数

    1.通过对象调用成员函数(无虚函数) 源代码 反汇编代码 2. 通过对象调用成员函数(有虚函数) 对比发现通过对象...

  • 2019-03-19

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

  • C语言10- C语言与汇编

    20:C语言与汇编 20.1:调用约定之汇编 x86调用约定: cdecl:参数从右往左依次入栈,调用者栈平衡(C...

  • Swift中结构体的方法调度&内存分区

    函数方法调度 结构体的方法调度 如下结构体 在汇编模式下,可知结构体的函数调用方式是静态调用(直接调用): 通过在...

  • Linux C编程一站式学习【学习笔记】

    第 19 章 汇编与C之间的关系 1. 函数调用 注意函数调用和返回过程中的这些规则: 这些规则并不是体系结构所强...

  • day12迭代器、生成器、模块、异常

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

  • 汇编代码——函数调用原理

    汇编代码中函数的调用过程 push 参数:64位 CPU 任性使用寄存吕 call 指令调用:将下一条指令地址入栈...

网友评论

      本文标题:通过x86汇编再看内存中的函数调用过程

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