首页 > 编程 > ASM > 正文

计算机是如何工作的?--通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的

2019-11-08 18:24:51
字体:
来源:转载
供稿:网友

王雪 原创作品转载请注明出处 《linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000

一、理论基础 (1)冯诺依曼体系结构:存储程序计算机的工作模型 这里写图片描述 从硬件角度看程序的执行过程:其中ip(instruction pointer)为CPU中的寄存器,指向内存中的某一块,CPU执行指令时,会从IP中取出一条指令后执行,执行过后,IP自加一(增加一个指令的长度),取下一条指令执行。 从程序员的角度看: CPU是一个大的for循环,不停地执行next instruction命令,存储器主要负责数据和代码等信息的存储,CPU与Main Memory通过总线进行连接。 注意: 1.程序员不可以直接修改IP的值,只能通过一些指令,如CALL、RET、JMP等间接修改IP的值 2.IP在32位机器中表示为eip(本次实验以32位作为分析),在64位机器中表示为rip。 (2)x86汇编基础知识(32位机器) 一.寄存器:在x86体系中,寄存器可分为通用寄存器、段寄存器、标志寄存器 1通用寄存器: EAX:累加器 EBX:基地址寄存器 ECX:计数寄存器 EDX:数据寄存器 EBP:堆栈基指针 ESI,EDI:变址寄存器 ESP:堆栈顶指针 2.段寄存器:CS,DS,ES,SS,FS,GS 3.标志寄存器 CPU在实际取指令时根据CS:eip来准确确定某一个指令在内存中的地址。 二:汇编指令(以常见的MOV,PUSH,POP,CALL等进行说明) (1)MOV指令及寻址方式 1.MOV指令,能实现以下操作: ① CPU内部寄存器之间数据的任意传送(除了码段寄存器CS和指令指针IP以外)。 ② 立即数传送至CPU内部的通用寄存器组(即AX、BX、CX、DX、BP、SP、SI、DI),给这些寄存器赋初值。 ③ CPU内部寄存器(除了CS和IP以外)与存储器(所有寻址方式)之间的数据传送,可以实现一个字节或一个字的传送。 ④ 能实现用立即数给存储单元赋初值。 movb,movl,movw,movq分别针对8位,16位,32位,64位系统 (2)pushl和pop指令,pushl用于入栈(栈的扩张),pop用于出栈(栈的收缩) 栈是向下生长的,也就是说栈底位于高地址,栈顶位于低地址,用ebp指向栈底,用esp指向栈顶。 入栈操作:pushl %eax完成的操作包括两步

subl $4,%espmovl %eax,(%esp)

出栈操作:pop %eax完成的操作包括两步

movl (%esp),%eaxaddl $4,%esp

(3)CALL主要用于函数调用 call 0x12345 完成的操作包括两步

push %eipmovl %0x12345,%eip

(4)RET指令用于恢复操作,完成pop %eip操作 (5)enter和leave操作 enter 置为空栈,完成的操作包括两步

pushl %ebpmovl %esp,%ebp

leave用于撤销函数调用堆栈,完成的操作包括两步

movl %ebp,%esppopl %ebp

注: (1)函数调用堆栈是由逻辑上多个堆栈叠加起来的(比如函数的嵌套) (2)函数的返回值默认使用eax寄存器存储返回给上一级函数 (3)一定要注意的是eip不能由程序员直接修改,程序员想修改eip只能通过特殊指令间接修改。 2.寻址方式 (1)寄存器寻址(不访问内存) movl % eax,% edx <==>edx= eax,将eax中的值赋值给edx (2)立即寻址(不访问内存)用$表示立即数 movl $ 0x1234,%edx <==>edx = 0x1234 (3)直接寻址 movl 0x123,%edx <==>edx = * (int32_t*)0x123 将内存地址0x123所指向的内存数据赋值给edx (4)间接寻址 movl (%ebx),%edx <==>edx = * (int32_t*)ebx (5)变址寻址 movl 4(%ebx),%edx <==>edx = * (int32_t*)(ebx+4) 二、通过实验分析计算机是如何工作的 (1)实验代码与截图 在实验楼的linux终端下创建一个main.c文件(注意实验楼的环境为64位) main.c中的内容 利用指令(64位下生成32位的汇编文件)

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

这里写图片描述 进入main.s汇编文件,去掉所有以.开始的代码行(以.开始的代码是连接时的辅助信息)得到纯汇编代码 这里写图片描述 可以看到刚才介绍过的指令操作。 (2)实验分析——-对执行过程的分析 与C语言类似,汇编代码的入口也为main函数 初始时栈的状态 这里写图片描述 进入main函数,执行18行代码

pushl %ebp

执行后栈的状态 这里写图片描述 0标号下下存放ebp的内容,esp指向标号1处

movl %esp,%ebp

这里写图片描述 esp和ebp指向相同位置

subl $4,%esp

这里写图片描述

movl $8,(%esp)

这里写图片描述

call f

执行call时实际执行两个动作,pushl %eip ; movl f ,%eip 此时eip指向第23行代码 这里写图片描述 执行后,eip指向f 跳转到f中执行:

pushl %ebpmovl %esp,%ebpsubl $4,%esp

这里写图片描述 在执行过movl%esp,%ebp后,esp和ebp置于相同的标号处(4) 执行subl $4,%esp,esp向下移动到标号5 这里写图片描述

movl 8(%ebp),%eaxmovl %eax,(%esp)

movl 8(%ebp),%eax 变址寻址,将ebp(此处为标号4)加8(向上移动两个标号,也就是标号2处)的值赋给eax,所以%eax = 8 movl %eax,(%esp),将eax的内容也就是8赋值到esp下也就是标号5处 这里写图片描述

call gleave

执行call时实际执行两个动作,pushl %eip ; movl g,%eip 此时eip指向第15行代码leave的位置,此时eip指向g跳转到g中去执行 这里写图片描述 在g中执行:

pushl %ebpmovl %esp,%ebp

pushl %ebp同上,将esp向下移动,将ebp(标号为4)压栈 这里写图片描述 movl %esp,%ebp esp和ebp指向相同的位置 这里写图片描述

movl 8(%ebp),%eax

强ebp向上移动两个标号的值(也就是8)赋给eax

addl $57,%eaxpopl %ebpret

%eax中存放的值为8,addl操作,将eax的值与立即数57相加,结果为65,将65存回到eax popl %ebp,将ebp的值放回到ebp,执行效果:ebp重新指向标号为4的位置,同时esp减4 这里写图片描述 ret执行popl %eip,也就是说esp向上移动指向5的标号的位置,同时eip指向15行指令的位置(call的下一条指令) 这里写图片描述 回到f中执行

leaveret

leave执行两条指令, movl %ebp,%esp popl %ebp 首先,将esp指向ebp相同的位置(也就是标号4的位置),popl %ebp,将ebp出栈,此时ebp指回标号1的位置,由于popl,esp向上移动 这里写图片描述

这里写图片描述 ret执行popl %eip 由于popl,esp向上增加一个,指向标号2,eip指向第23行代码处 这里写图片描述 eip执行第23行代码,回到main处,执行

addl $1,%eaxleaveret

eax此时的值为65,执行addl,65+1 = 66,将66存回到eax。 函数返回值默认使用eax来存储 执行leave,分为两步, movl %ebp,%esp,将esp指向ebp的位置,popl %ebp,将ebp出栈(ebp指向0的位置),popl指令时esp向上移动,也就是说esp,ebp均指向标号0的位置,栈回到main函数最初的状态。 ret,return的是main函数之前的堆栈,此处由操作系统管理。 这里写图片描述 栈向下生长,向上还原,增增减减,将程序变为指令流,从CPU上流过。 此时,小程序执行完成 三、实验总结–对计算机如何工作的理解 1.计算机的基本原理是存储程序和程序控制,预先要把指挥计算机如何进行操作的指令序列(称为程序)和原始数据通过输入设备输送到计算机内存贮器中。每一条指令中明确规定了计算机从哪个地址取数,进行什么操作,然后送到什么地址去等步骤。 计算机在运行时,先从内存中取出第一条指令,通过控制器的译码,按指令的要求,从存储器中取出数据进行指定的运算和逻辑操作等加工,然后再按地址把结果送到内存中去。接下来,再取出第二条指令,在控制器的指挥下完成规定操作。依此进行下去。直至遇到停止指令。简单来说就是CPU负责处理和运算,存储器负责保存指令和数据。通过操作系统得调度和安排,不停地进行取址、译码、执行的循环。 2.汇编代码是什么? 计算机语言的发展过程从机器语言(计算机能直接识别的二进制0和1的组合)->汇编语言(为了减轻使用机器语言编程的痛苦,人们进行了一种有益的改进:用一些简洁的英文字母、符号串来替代一个特定的指令的二进制串,依赖于硬件)->高级语言(接近于数学语言或人的自然语言,同时又不依赖于计算机硬件,编出的程序能在所有机器上通用)。 我们编写了一个小程序,比如上面实验中写到的main.c文件,编译器执行的过程,这里写图片描述 可执行的二进制文件是计算机“认识”的文件,可以直接执行。 3.以上便是我对这次实验的总结,计算机很“单纯”,它可以执行很多复杂的指令,但它也是被“告诉”要执行什么,才会去执行什么,通过对汇编语言的分析可以方便我们理解计算机处理的过程,了解计算机如何工作等等,这也会成为我今后学习的重点。感谢为我们辛苦准备课程的老师!


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选