zoukankan      html  css  js  c++  java
  • 2020-2021-1 20209323 《linux内核原理与分析》第二周作业

     本周的实验内容是:汇编一个C语言程序代码,反汇编并分析其汇编指令执行过程。

     在实验楼的Linux环境中用命令行创建文件,main.c截图如下图所示:

    将.c文件反汇编成.s文件,使用-m32选项让它生成32位汇编指令

    gcc -S -o main.s  main.c -m32

    编译阶段命令截断后的产物
        C源程序
    预处理 gcc -E 替换了宏的C源程序(没有了#define,#include…), 删除了注释
    编译 gcc -S 汇编源程序
    汇编 gcc -c 目标文件,二进制文件, 允许有不在此文件中的外部变量、函数
    链接 gcc 可执行程序,一般由多个目标文件或库链接而成, 二进制文件,所有变量、函数都必须找得到

     反汇编源文件生成的汇编文件如下图所示:

    代码中有许多以.开头的代码行,属于链接时候的辅助信息,在实际中不会执行,把它删除,得到下列的代码就是纯汇编代码了:

    g:
        pushl    %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        addl    $23, %eax
        popl    %ebp
        ret
    f:
        pushl    %ebp
        movl    %esp, %ebp
        pushl    8(%ebp)
        call    g
        addl    $4, %esp
        leave
        ret
    main:
        pushl    %ebp
        movl    %esp, %ebp
        pushl    $23
        call    f
        addl    $4, %esp
        addl    $1, %eax
        leave
        ret

    函数执行
    每次call一个函数,函数总是先把当前的栈底指针压入堆栈,然后把栈底指针移动到当前的栈顶,这样子做,相当于在旧的栈上新起了一个栈。然后在新栈上执行函数。
    结束函数执行的时候,如果有堆栈变化,我们在写单片机汇编的时候,我们的习惯是一个函数有多少push就写多少pop,但是,由于我们新引进了一个寄存器,我们可以用movl %ebp, %esp来瞬间恢复堆栈。当然,如果没有堆栈的变化,我们当然可以优化编译器把这句话去了。
    这时候,马上就要ret飞回调用它的函数了,在此之前,我们还需要恢复栈底指针,否则回去的日子就难过了。于是popl %ebp。然后如果可以的话,我们会用leave来代替刚刚的两行代码。

    函数调用

    call f:这是调用f(23)函数。先把23压栈,然后调用了f函数。等到ret后,返回了现在的call的下一行汇编代码。这时候,esp和ebp是一个值,所以这以后如果压栈的时候,会覆盖了栈底指针,把esp往栈顶上移动1个单位也就是4个字节,这时候就完美解决了调用后的问题,才是真正调用完成了。

    总结:

    • 每次都是各种取指针执行,在程序中各种跳转。

    • 函数执行前要enter,函数执行后要leave(如果没有改变esp就可以省去把ebp赋值给esp的步骤了),ret

    • 函数取值可以靠ebp很方便做到

    • 函数调用结束后要记住恢复堆栈指针(esp)

    • x86体系结构栈地址是向下增长的(地址不断减小),由于是我们使用的32位的x86汇编指令,这里的堆栈是从高向低入栈的,和51单片机的堆栈不同。
  • 相关阅读:
    面向对象 课堂记录
    面向对象10个案例 (来源网络)
    面向对象举例
    面向对象
    36选7
    Android ImageView的scaleType属性与adjustViewBounds属性
    安卓计算器 简单代码
    安卓单选、复选按钮简单练习
    安卓发送邮箱界面 线形、表格、相对布局方式
    UI和View 三种控制方式
  • 原文地址:https://www.cnblogs.com/qingyu-sun/p/13834666.html
Copyright © 2011-2022 走看看