zoukankan      html  css  js  c++  java
  • 程序的机器级表示内容补充及扩展

    程序的机器级表示内容补充及扩展

    第五周练习补充

    • 代码

    • 删除gcc产生代码中以"."开头的编译器指令

    • 每条指令相应栈帧的情况

    EIP & EBP & ESP

    eax, ebx, ecx, edx, esi, edi, ebp, esp等都是X86 汇编语言中CPU上的通用寄存器的名称,是32位的寄存器。如果用C语言来解释,可以把这些寄存器当作变量看待。

    比方说:add eax,-2 //可以认为是给变量eax加上-2这样的一个值。

    这些32位寄存器有多种用途,但每一个都有“专长”,有各自的特别之处。

    • EAX 是"累加器", 它是很多加法乘法指令的缺省寄存器。

    • EBX 是"基地址"寄存器, 在内存寻址时存放基地址。

    • ECX 是计数器, 是重复前缀指令和LOOP指令的内定计数器。(在汇编指令中,loop通常实现循环功能)

    • EDX 是被用来放整数除法产生的余数。

    • ESI/EDI分别叫做"源/目标索引寄存器",因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串.

    • EBP是"基址指针", 它最经常被用作高级语言函数调用的"框架指针". 在破解的时候,经常可以看见一个标准的函数起始代码:

        push ebp ;      保存当前ebp
        mov ebp,esp ;   EBP设为当前堆栈指针
        sub esp, xxx ;  预留xxx字节给函数临时变量.
        ...
      

    这样一来,EBP 构成了该函数的一个框架, 在EBP上方分别是原来的EBP, 返回地址和参数;EBP下方则是临时变量。函数返回时作mov %ebp , %esppop %ebp(相当于leave)、ret 即可。

    • ESP 专门用作堆栈指针,被形象地称为栈顶指针,堆栈的顶部是地址小的区域,压入堆栈的数据越多,ESP也就越来越小。(在32位平台上,ESP每次减少4字节)
    • esp:寄存器存放当前线程的栈顶指针
    • ebp:寄存器存放当前线程的栈底指针
    • eip:寄存器存放下一个CPU指令存放的内存地址,当CPU执行完当前的指令后,从EIP寄存器中读取下一条指令的内存地址,然后继续执行。

    EIP,EBP,ESP都是系统的寄存器,里面存的都是些地址。

    栈的数据结构,主要有以下特点:后进先出。

    其实它还有以下两个作用:

    1. 栈是用来存储临时变量,函数传递的中间结果。
    2. 操作系统维护的,对于程序员是透明的。

    栈的原理

    • 写个小程序:

    当程序进行函数调用的时候,我们经常说的是先将函数压栈,当函数调用结束后,再出栈。这一切的工作都是系统帮我们自动完成的。但在完成的过程中,系统会用到下面三种寄存器:

     1.EIP
     2.EBP
     3.ESP
    
    • 当调用test函数开始时,三者的作用:

    1.EIP寄存器里存储的是CPU下次要执行的指令的地址。
    也就是调用完test函数后,让CPU知道应该执行main函数中的printf("End of function call")语句了。

    2.EBP寄存器里存储的是栈的栈底指针,通常叫栈基址,这个是一开始进行test()函数调用之前,由ESP传递给EBP的。(在函数调用前可以这么理解:ESP存储的是栈顶地址,也是栈底地址。)

    3.ESP寄存器里存储的是在调用函数test()之后,栈的栈顶。并且始终指向栈顶。

    • 当调用test函数结束后,三者的作用:

    1.系统根据EIP寄存器里存储的地址,CPU就能够知道函数调用完,下一步应该做什么,也就是应该执行main函数中的printf("End of function call")

    2.EBP寄存器存储的是栈底地址,而这个地址是由ESP在函数调用前传递给EBP的。等到调用结束,EBP会把其地址再次传回给ESP。所以ESP又一次指向了函数调用结束后,栈顶的地址。

    代码调试中的问题

    在把test.c编译成汇编代码时,我本来想用实验楼练习中的方法gcc –S –o test.s test.c -m32编译成32位的,可是遇到了比上次还不理解的问题。在上次练习时,代码开头有#include <stdio.h>时编译就会出错,而没有时就可以编译。

    但是这次代码开头有#include <stdio.h>时编译也会出错,而没有时还是不行,这个地方不知道怎么解决。

    所以我只好直接用gcc -S test.c 编译成汇编代码。

    当我习惯性的删除所有以"."开头的语句时,发现代码中出现了".LC0"和".LC1",我想起来这两个东西是我刚才删掉的以"."开头的语句中的东西,应该是调用了这两部分的函数,但是这两部分函数具体的结构表示不知道怎么看。

    本周代码托管截图

    其他(感悟、思考等,可选)

    这篇博客没有写本周的内容,只是对上周的内容的补充和扩展,以及更深入的理解。本周的内容会写在周天的博客中。

    其他内容

    因为在创建test.c 及test.s文件时放错了文件夹目录,所以复习了文件移动的指令。

    mv命令

    • 格式
      mv [options] 源文件或目录 目标文件或目录

    • [options]主要参数

    -i:交互方式操作。如果mv操作将导致对已存在的目标文件的覆盖,此时系统询问是否重写,要求用户回答”y”或”n”,这样可以避免误覆盖文件。

    -f:禁止交互操作。mv操作要覆盖某个已有的目标文件时不给任何指示,指定此参数后i参数将不再起作用。

    • 第二个参数

    当第二个参数类型是文件时,mv命令完成文件重命名,它将所给的源文件或目录重命名为给定的目标文件名。
    当第二个参数是已存在的目录名称时,源文件或目录参数可以有多个,mv命令将各参数指定的源文件均移至目标目录中。在跨文件系统移动文件时,mv先拷贝,再将原有文件删除,而链至该文件的链接也将丢失。

    • 应用实例

    (1)将/home/20145333中的所有文件移到当前目录中:

    $ mv /home/20145333/* .
    

    (2)将文件test.c重命名为test01.c:

    $ mv test.c test01.c
    

    (3)把当前目录的一个子目录里的文件移动到另一个子目录里

    $ mv  子目录名/*  另一个目录
    

    (4)移动当前文件夹下的所有文件到上一级目录

    $ mv * ../
    

    ("*"可以换成任意文件)

    安装了"tree"

  • 相关阅读:
    centos 安装 TortoiseSVN svn 客户端
    linux 定时任务 日志记录
    centos6.5 安装PHP7.0支持nginx
    linux root 用户 定时任务添加
    composer 一些使用说明
    laravel cookie写入
    laravel composer 安装指定版本以及基本的配置
    mysql 删除重复记录语句
    linux php redis 扩展安装
    linux php 安装 memcache 扩展
  • 原文地址:https://www.cnblogs.com/rx719523850/p/5982920.html
Copyright © 2011-2022 走看看