博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

汇编笔记

Posted on 2011-10-17 13:36  bug yang  阅读(232)  评论(0编辑  收藏  举报

  一、计算机体系结构基础

  eax,ebx,eip为寄存器,有些寄存器保存的数据只能用于某种特定的用途,比如eip寄存器用作程序计数器,叫做特俗寄存器。而另外一些寄存器保存的数据可以用在各种运算和读写内存的指令中,比如eax寄存器,这称为通用寄存器(General-purpose Register)。

  程序计数器(PC,Program Counter),保存着CPU取指令的地址,每次CPU读出程序计数器中保存的地址,然后按这个地址去内存中取指令,这时程序计数器保存的地址会自动加上该指令的长度,指向内存中的下一条指令。

  指令解码器(Instruction Decoder)。CPU取上来的指令由若干个字节组成,这些字节中有些位表示内存地址,有些位表示寄存器编号,有些位表示这种指令做什么操作,是加、减、乘、除还是读、写,指令解码器负责解释这条指令的含义,然后调动相应的执行单元去执行它。

  算术逻辑单元(ALU,Arithmetic and Logic Unit)。如果解码器将一条指令解释为运算指令,就调动算术逻辑单元去做运算,比如加减乘除、位运算、判断一个条件是否成立等。运算结果可能保存在寄存器中,也可能保存到内存中。

  内存读一个数到寄存器,则执行过程可以想像成这样:

  1.  CPU内部将寄存器对接到数据总线上,使寄存器的每一位对接到一条数据线,等待接收数据。

  2.  CPU将内存地址通过地址线发给内存,然后通过另外一条控制线发一个读请求。

  3. 内存收到地址和读请求之后,将相应的存储单元对接到数据总线的另一端,这样,存储单元每一位的1或0状态通过一条数据线到达CPU寄存器中相应的位,就完成了数据传送。

  从CPU的角度来看,访问设备只有内存映射I/O和端口I/O两种,要么像内存一样访问,要么用一种专用的指令访问。其实访问设备是相当复杂的,由于计算机的设备五花八门,各种设备的性能要求都不一样,有的要求带宽大,有的要求响应快,有的要求热插拔,于是出现了各种适应不同要求的设备总线,比如PCI、AGP、USB、1394、SATA等等,这些设备总线并不直接和CPU相连,CPU通过内存映射I/O或端口I/O访问相应的总线控制器,通过它再去访问挂在总线上的设备。

  访问设备还有一点和访问内存不同。内存只是保存数据而不会产生新的数据,如果CPU不去读它,它也不需要主动提供数据给CPU,所以内存总是被动地等待被读或被写。而设备往往会自己产生数据,并且需要主动通知CPU来读这些数据,例如敲键盘产生一个输入字符,用户希望计算机马上响应自己的输入,这就要求键盘设备主动通知CPU来读这个字符并做相应处理,给用户响应。这是由中断(Interrupt)机制实现的,每个设备都有一条中断线,通过中断控制器连接到CPU,当设备需要主动通知CPU时就引发一个中断信号,CPU正在执行的指令将被打断,程序计数器会设置成某个固定的地址(这个地址由体系结构定义),于是CPU从这个地址开始取指令(或者说跳转到这个地址),执行中断服务程序(ISR,Interrupt Service Routine),完成中断处理之后再返回先前被打断的地方执行后续指令。比如某种体系结构规定发生中断时跳转到地址0x0000 0010执行,那么就要事先把一段ISR程序加载到这个地址,ISR程序是由内核代码提供的,中断处理的步骤通常是先判断哪个设备引发了中断,然后调用该设备驱动程序提供的中断处理函数(Interrupt Handler)做进一步处理。

  虚拟内存管理(Virtual Memory Management)

  如果处理器没有MMU,或者有MMU但没有启用,CPU执行单元发出的内存地址将直接传到芯片引脚上,被内存芯片(以下称为物理内存,以便与虚拟内存区分)接收,这称为物理地址(Physical Address,以下简称PA);

  如果处理器启用了MMU,CPU执行单元发出的内存地址将被MMU截获,从CPU到MMU的地址称为虚拟地址(Virtual Address,以下简称VA),而MMU将这个地址翻译成另一个地址发到CPU芯片的外部地址引脚上,也就是将虚拟地址映射成物理地址

  通常操作系统把虚拟地址空间划分为用户空间和内核空间,例如x86平台的Linux系统虚拟地址空间是0x0000 0000~0xffff ffff,前3GB(0x0000 0000~0xbfff ffff)是用户空间,后1GB(0xc000 0000~0xffff ffff)是内核空间。用户程序在用户模式下执行,不能访问内核中的数据,也不能跳转到内核代码中执行。这样可以保护内核,如果一个进程访问了非法地址,顶多这一个进程崩溃,而不会影响到内核和其它进程。CPU在产生中断或异常时会自动切换模式,由用户模式切换到特权模式,因此跳转到内核代码中执行中断或异常服务程序就被允许了。事实上,所有内核代码的执行都是从中断或异常服务程序开始的,整个内核就是由各种中断处理和异常处理程序组成。

  通用寄存器和特殊寄存器

  x86的通用寄存器有eax、ebx、ecx、edx、edi、esi。这些寄存器在大多数指令中是可以任意选用的,比如movl指令可以把一个立即数传送到eax中,也可传送到ebx中。但也有一些指令规定只能用其中某些寄存器做某种用途,例如除法指令idivl要求被除数在eax寄存器中,edx寄存器必须是0,而除数可以在任意寄存器中,计算结果的商数保存在eax寄存器中(覆盖原来的被除数),余数保存在edx寄存器中。也就是说,通用寄存器对于某些指令而言不是通用的。

  x86的特殊寄存器有ebp、esp、eip、eflags。eip是程序计数器,eflags保存着计算过程中产生的标志位,包括第 3 节 “整数的加减运算”讲过的进位、溢出、零、负数四个标志位,在x86的文档中这几个标志位分别称为CF、OF、ZF、SF。ebp和esp用于维护函数调用的栈帧