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

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

第五周练习补充

  • 代码

  • 删除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"

posted on 2016-10-20 22:31  20145333茹翔  阅读(172)  评论(1编辑  收藏  举报

导航