• 2017-2018-1 20179215《Linux内核原理与分析》第二周作业


    20179215《Linux内核原理与分析》第二周作业

    这一周主要了解了计算机是如何工作的,包括现在存储程序计算机的工作模型、X86汇编指令包括几种内存地址的寻址方式和push、pop、call、re等几个重要的汇编指令。主要分为两部分进行这周的学习总结。第一部分对学习内容进行总结,第二部分对实验进行分析(反汇编一个C程序)。


    一、学习内容

    1、现在计算机绝大多数采用冯诺依曼体系结构,逻辑上可以抽象成:

    以程序员的角度看:

    2、几种寻址方式

    • movl %eax,%edx edx=eax 寄存器寻址

    • movl $0x123,%edx edx=0x123 立即寻址

    • movl 0x123,%edx edx=*(int32_t)0x123 直接寻址

    • movl (%ebx),%edx edx=(int32_t)ebx 间接寻址

    • movl 4(%ebx),%edx edx=(int32_t)(ebx+4) 变址寻址

    其中%..代表寄存器,$..代表取出数据,(%..)代表取出寄存器中所存储的数据,b、w、l、q分别代表8位、16位、32位和64位。

    3、push、pop、call等几个重要的汇编指令。

    eg (1) pushl %eax 意思是把eax寄存器压栈。分解来看相当于第一步:subl $4 esp,第二步:movl %eax (%esp),来解释一下:首先我们要知道esp是指堆栈栈顶,那么由于栈的一般生长方向为自上向下增长,进行push压栈指令时栈顶指针向下移动4个字节(因为是32位机),之后把eax放入当前内存位置。

    (2) popl %eax意思是把eax寄存器出栈。分解来看相当于第一步: movl(%esp), %eax第二步:add $4 %esp,道理同(1)逆。

    (3) call 0X12345 意思是函数调用,过程是首先将当前CPU获取内存的指令压栈保存,赋予新值,CPU下次就从新地址来取指令了,即实现了函数调用。

    二、实验分析

    首先创建main.c文件,即:touch main.c,之后用如下命令输入一段C语言代码:

    $vi main.c,之后用gedit main.c 查看编写好的C程序,如下图所示:

    然后用如下命令反汇编:$gcc -S -o main.s main.c -m32,之后用gedit main.c 查看结果,如下图所示:




    由于“.”开头的大都是用于链接辅助信息,实际并不会执行,所以可以直接忽略。删除所有点开头的内容,留下来的是纯汇编代码。那么此段程序简化后就变成如下形式:

    g:

    pushl   %ebp
    movl    %esp, %ebp
    movl    8(%ebp), %eax
    addl    $20, %eax
    popl    %ebp
    ret 
    

    f:

    pushl   %ebp
    movl    %esp, %ebp
    subl    $4, %esp
    movl    8(%ebp), %eax
    movl    %eax, (%esp)
    call    g   
    leave
    ret 
    

    main:

    pushl   %ebp           
    movl    %esp, %ebp
    subl    $4, %esp
    movl    $10, (%esp)
    call    f   
    addl    $30, %eax
    

    分析如下图:


    Eip寄存器 从这条指令执行完自动执行下有一条指令

    Ebp寄存器 总是指向堆栈的栈底 概念的是相对的,跳出该函数进入其他函数堆栈有其相应的栈底

    Esp寄存器 总是指向堆栈的栈顶

    Eax寄存器 函数的返回值默认使用该寄存器存储返回给上一级函数

    分析如下:

    程序从main函数开始运行,因为之前还有别的代码运行,所以把当前ebp进行压栈,之后指针向下一个字节,相当于在下个字节内填充数据,之后调用f函数,而当前eip指向call f的下一条指令(eip在进行call f指令后压栈,下回跳转到eip继续执行)。那么对于即将要执行的f函数来说首先要将当前ebp压栈,那么和main函数类似,指针下移一个字节,把10放进寄存器eax中,再把寄存器eax给esp,当前eip指向call g的下一条指令(当前eip在进行call g指令后压栈),之后调用g函数,同样先将ebp压栈,之后esp,ebp指向同一个位置,之后ebp指针向上移动两个字节把当前字节内内容放到eax寄存器中,将eax储存的数加20后出栈,返回到f函数的leave命令,撤销函数堆栈后返回到main函数的leave命令,将eax的当前值30加30,之后撤销函数堆栈,返回程序运行值。

  • 相关阅读:
    php composer 相关及版本约束等小技巧
    Jquery 获取表单值如input,select等方法
    Apache benchmark 压力测试工具
    Linux中的随机数文件 /dev/random /dev/urandom
    redis持久化
    Python---装饰器
    高仿拉手网底部菜单实现FragmentActivity+Fragment+RadioGroup
    python实现二叉树和它的七种遍历
    Spring AOP应用实例demo
    二维数组的列排序
  • 原文地址:https://www.cnblogs.com/yl-930/p/7638587.html
Copyright © 2020-2023  润新知