观王爽《汇编语言》所得

Posted by Sutdown on August 27, 2023

前言:

本来时想补补计算机系统基础的课程,看到时mooc里面南京大学的袁春风老师所讲,在看到(一)的后面的时候,看的很吃力,有些汇编的寄存器或者一些指令的执行都是完全陌生的,决定中断几天看看王爽老师的书籍《汇编语言》,个人所看,确实很容易看懂,并且能对计算机有着进一步了解。看书时如果有些c语言的基础并且对计算机有基础了解,看完后都会收获很多的。

1.一个源程序是如何运行的。

源程序的运行过程:

编辑

1)使用文本编辑器(比如记事本)写下代码,再用相应的编译器编译

2)或者直接在开发环境上进行编写程序直接编译运行(比如C++/C语言可用Visual Studio或者DevC++)

预处理

预处理是由预处理器处理,将源文件中以#开头的某些数据转换成代码,它的逻辑与编辑中的源代码文件相同,最终会得到一个.i文件。

编译汇编

经过特定的编译器编译源程序文件,我们一般可以得到最多三个文件,目标文件(.obj),列表文件(.lst),交叉引用文件(.crf),后两者属于中间结果,我们最终只能得到目标文件。

每个.c程序经过编译之后都会得到一个.o文件,也就是可重定位目标文件,经过编译汇编两个操作后得到机器语言的文件。

可重定位目标文件(ELF)格式包含ELF头(存放16字节标识信息,文件类型,机器类型,节头表偏移,节头表大小等多信息),.text节(编译后的代码部分存放),.rodata节(只读数据),.data节(已经初始化的全局变量),.bss节(未初始化的全局变量,不占磁盘空间),节头表(存放每个节的节名,偏移,带线啊哦,访问元素,对其信息,起始地址等)。

但由于此时只是存放在磁盘中,并未在内存分配,起始地址均为0,并且在接下来的运行中,可以通过节头表找寻相应信息进行连接。

链接

多个可重定位目标文件(.o),系统的库文件经过链接可以合并为可执行目标文件(.exe)。

此过程会将磁盘中的各类文件放在一起,比如ELF中,固定代码(.init,.text,.rodata)会被存放在只读代码段中,未初始化和已经被初始化的数据(.data,.bss)会被存放在读写数据段中等等,另外在这个内存区中还 存在用户栈区域和堆区域以及共享库区域。

注:静态链接和动态链接

静态链接库和动态链接库是两种不同的链接方式,它们的区别主要有以下几点:

  • 静态链接库是在编译时将库文件中的目标代码直接拷贝到可执行文件中,形成一个完整的程序,不再依赖于库文件。动态链接库是在运行时或加载时将库文件中的目标代码加载到内存中,供程序调用,仅保留接口信息,依然依赖于库文件。
  • 静态链接库会增加可执行文件的大小,因为每个使用静态链接库的程序都会包含一份库文件的副本。动态链接库可以减少可执行文件的大小,因为多个使用动态链接库的程序可以共享一份库文件的副本。
  • 静态链接库可以提高程序的运行速度,因为在编译时就已经确定了所有的符号地址,无需再进行重定位。动态链接库可能会降低程序的运行速度,因为在运行时或加载时还需要进行符号解析和重定位。
  • 静态链接库不利于程序的更新和维护,因为每次修改了库文件就需要重新编译所有使用该库文件的程序。动态链接库有利于程序的更新和维护,因为只需要替换库文件就可以实现更新,无需重新编译程序。
  • 静态链接库更安全和稳定,因为不会受到其他程序或系统对库文件的影响。动态链接库可能会出现兼容性或安全性问题,因为可能会遇到版本冲突或被恶意篡改的风险。
运行

可执行文件能够直接被CPU执行。

在Windows下通常为.exe,.sys,.com,.dll文件;在Linux下为ELF文件,Mac中为.dmg或者.app文件等。

2.计算机硬件和软件等基本组成和功能。

计算机系统抽象层的描述

1)计算机软件:application(应用程序),语言处理系统(语言处理程序,运行时系统),操作系统(虚拟机,人机交互界面,提供服务功能的内核编程)

2)计算机硬件:微体系结构,功能部件,电路,器件等

3)指令集体系结构(Instruction Set Architecture)

电脑基础部件

CPU(中央处理器,执行程序和处理数据)

主板(Motherboard连接和管理各种部件)

内存(Memory暂时存放运行中的程序和数据)

硬盘(Hard Disk永久存放文件和数据)

显卡(Graphics Card电脑的图形处理器,负责输出电脑的图像和视频)

声卡(Sound Card)网卡(Network Card)

电源(Power Supply)光驱(Optical Drive)外接设备(Peripheral Devices)

注:

1)计算机中运行的数据先由磁盘读入内存之中,然后才能被CPU处理。

但是为了提高磁盘的访问速度,可采用磁盘缓存技术,即先把磁盘经常访问的数据预先加载到内存中,以减少实际的磁盘读写操作。

为了扩大内存容量,可以使用虚拟内存的技术,即把磁盘的一部分空间当作假想内存以增加可用内存。

断电时,由于磁盘是外部存储设备其中的数据不会丢失,而对于内存,作为内部存储设备,断电就会消失,但如果当时作为虚拟内存存储在磁盘中,其中的数据不会丢失。

2)对于想要计算机系统硬件编程时,CPU存在一个内存地址空间,内存地址空间的大小同样由地址总线的宽度决定。

主板:其上的核心部件比如CPU,存储器,外围芯片组,扩展卡槽等通过总线相连

接口卡:CPU通过控制接口卡(接口卡位于扩展插槽上,扩展卡槽通过总线和CPU相连)发送命令,从而实现对外设(比如打印机,耳机,音箱,显示器等)的间接控制。

计算机中的基本部件

1)CPU通过地址总线将地址信息传入存储器,存储器通过数据总线将对应信息传送给CPU,CPU发出对应内存读写命令传给存储器进行操作。(每一条总线课传输二进制中的0或者1,由n条总线,可以找到2的n次方个内存单元)

2)CPU主要由运算器,控制器,寄存器,总线等组成。

运算器:CPU的运算部件,主要进行算术运算和逻辑运算。

寄存器:CPU的存储部件,可以暂时存放指令,数据和状态信息。

控制器:CPU的控制部件,负责解释指令,发出控制信号,协调各个部件的工作。

3.各种语言的发展历程。

机器语言

最初计算机使用的是机器语言,即只有0或者1的二进制方式,但是这种方法可移植性性低,编程困难,可读性差,容易出错。但是由于是计算机能直接识别和执行,所以它的执行速度快。现在的大多高级程序设计语言都会经过编译器最终转化为机器语言的形式。

汇编语言

汇编语言在不用的设备中对应不同的机器语言指令集,并不具备可移植性。汇编语言相对机器语言增加了字符便于理解,它主要由汇编指令,伪指令和其它符号三类指令组成。汇编指令和机器指令的差别在于指令的表示方法上,汇编指令是机器指令便于记忆的书写形式

高级程序设计语言

高级程序设计语言是一种更接近人类的自然语言,一般只有经过编译器和解释器的转换,才能编程计算机能够执行的低级语言,比如机器语言或者汇编语言。

它可以分为过程式语言(如C语言,Pascal,Fortran),面向对象语言(C++,Java,C#)等。

4.寄存器的了解以及它们的访问机制等。

汇编语言的寄存器是一种用于存储数据或地址的CPU内部的部件,通过指令进行读写操作。

不同类型的CPU有不同数量和结构的寄存器,但一般可以分为以下几类:

通用寄存器:

用于存放一般性的数据,如算术逻辑运算的操作数和结果,或内存单元的偏移量。通用寄存器的长度取决于机器字长,通常有8个或16个。例如,8086CPU有8个16位的通用寄存器:AX、BX、CX、DX、BP、SP、SI(源变址寄存器)、DI(目的变址寄存器)。其中,AX、BX、CX、DX可以分为两个独立的8位寄存器来使用,如AX可以分为AH和AL。16位寄存器用于存储字,8位寄存器用于存储字节,在此1个字等于2个字节。

在串处理指令中,SI用作隐含的源串地址,默认在DS中;DI用作隐含的目的串地址,默认在ES中。

段寄存器:

用于存放内存单元的段地址,与偏移地址相结合,形成物理地址。段寄存器是根据内存分段的管理模式而设置的,通常有4个或6个。例如,8086CPU有4个16位的段寄存器:CS(Code Segment)、DS(Data Segment)、SS(Stack Segment)、ES(附加寄存器)。其中,CS为代码段寄存器,DS为数据段寄存器,SS为堆栈段寄存器,ES为附加段寄存器。

指令指针寄存器:

用于存放下一条要执行的指令在代码段中的偏移地址。指令指针寄存器与代码段寄存器相结合,指示了CPU当前要读取指令的物理地址。例如,8086CPU有一个16位的指令指针寄存器:IP(Instruction Pointer)。

注:物理地址=段地址16+偏移地址:本质含义是CPU在访问内存时,用一个基础地址(段地址16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。

标志寄存器:

用于存放CPU执行指令后产生的一些状态信息,

如进位标志(carry flag)、零标志(zero flag)、符号标志(sign flag)、溢出标志(overflow flag),奇偶标志位(parity flag),方向标志位(Direction flag)等。标志寄存器可以影响程序的控制流程,如条件转移或循环指令。例如,8086CPU有一个16位的标志寄存器:PSW。

注:无符号时可以通过zf,cf比较大小;有符号时可以通过sf,of比较大小。

5.指令集。

8086CPU的指令系统的总结。

1.数据传送指令

比如mov,push,pop(栈),pushf(push far),popf(pop far远程),xchg(用于交换两个数据的内容,不能用立即数和段寄存器作操作数)等,这些指令实现寄存器和内存,寄存器和寄存器间的数据传送。

2.算术运算指令

比如add,sub,adc(add with carry进位加法),sbb(sub with borrow带借位减法),inc(increase),dec(decrease),cmp(compare),imul(符号乘法指令,用于两到三个操作数),idiv,aaa(ascii调整加法指令)等,这些指令实现寄存器和内存中数据的算术运算。它们的执行结果影响标志寄存器的sf,zf,of,cf,pf,af位。

3.逻辑指令

比如and,or,not,xor,test,shl,shr,sal,sar,rol,ror,rcl,rcr等都是逻辑指令,除了not指令外,它们的执行结果都会影响标志寄存器的相关标志位,逻辑运算也就是位运算的应用范围很广泛,比如字母的大小写转换等。

4.转移指令

可以修改IP或者可以同时修改CS和IP的指令系统统称为转移指令。

转移指令分为以下几类:

1)无条件转移指令,比如jmp(转移时,并不给出转移的目的地址,而是告知CPU转移的位移)

2)条件转移指令,比如jcxz,je,jb,ja,jnb,jna等

3)循环指令,比如loop(cx存放循环次数)

4)过程,比如call,ret,retf(call和ret类似于C语言中函数的调用,call调用时吗,先将下一步的CS和IP压入栈中,在进行转移,ret使用时,先出栈地址再进行返回)

5)中断,比如int,iret

它的转移行为可以分为段内转移(指修改IP)和段间转移(修改CS和IP),段内转移又分为短转移和近转移。注意如果使用转移指令时寄存器冲突,则可以在使用前先将寄存器入栈,指令执行完再出栈。

5.处理机控制指令

这些指令对标志寄存器或其他处理机状态进行设置,比如cld,std,cli,sti,nop,clc,cmc,stc,hlt,wait,esc,lock等

6.串处理指令

这些指令对内存中的批量数据进行处理,比如movsb,movsw,cmps,scas,lods,stos等。若要用这些指令方便进行批量数据处理,则需要和rep,repe,repne等前缀指令配合使用。

6.汇编语言和高级程序设计语言C语言的共性。

由于高级程序设计语言也是由低级语言一步步转化的,所以它们之间在思想上的共同点很多,通过了解汇编语言,也能进一步的加深对于高级语言的认知。

比如函数调用,在C语言中我们只能理解到参数的传递,然后调用函数,但是在了解之后,这个应该是于转移指令有关,比如call和ret,首先将主函数中的地址压入栈中,再通过转移指令到达函数中,转移指令并不是把你直接带入函数的地址,而是给你两者的相对地址,计算后到达函数,在它们的存储中分别为数据区和代码区,因此相对地址位移是不变的,在函数执行完后,将CS和IP地址出栈,回到原函数。

比如我们在代码的第一行写的#include或者#define,这两者都只不过高级程序语言的一种写法,在编译连接时会找到相对于的库函数,和原函数进行数据的比对操作,对于define,则是直接将对应的字符转换,所以#define在代码中起到的作用仅是增强可读性。

比如循环,书中只是简单的介绍了用cx存储次数的循环,并没有深入解析,但也思路和while或者for都相差无几,汇编语言还有待深入学习。

比如你初始化数据和不初始化数据编译器的处理,它们在编译时是分别放在不同的空间,如果不初始化,在编译时并不会分配内存。

比如在数据结构中了解到数组的寻址是通过计算,而在汇编中也分为直接变址寻址 等多种方式的寻址和数组也很类似。

7.计算机中内存空间的理解。

计算机中的存储空间是由不同的硬件设备组成的,它们可以分为以下几类:

  • 寄存器:寄存器是CPU内部的最小存储单元,它们可以存放指令、数据或地址,通常有8位、16位或32位。寄存器的访问速度最快,但数量有限,只能由CPU直接访问。

  • 缓存:缓存是位于CPU和内存之间的一种高速缓冲存储器,它可以暂时存放CPU经常访问的数据或指令,以减少CPU和内存之间的数据传输时间。缓存的容量比寄存器大,但比内存小,它可以由CPU或操作系统自动管理。

  • 内存:内存是计算机中主要的随机存取存储器,它可以存放程序和数据,供CPU直接读写。内存的容量比缓存大,但比硬盘小,它通常是易失性的,即断电后数据会丢失。内存的访问速度比硬盘快,但比缓存慢。

  • 硬盘:硬盘是计算机中主要的辅助存储器,它可以永久地存放大量的程序和数据,供CPU间接读写。硬盘的容量比内存大,但比光盘小,它通常是非易失性的,即断电后数据不会丢失。硬盘的访问速度比光盘快,但比内存慢。

  • 光盘:光盘是一种利用光学原理进行信息记录和读取的外部存储器,它可以用于备份或传输程序和数据。光盘的容量比硬盘大,但比磁带小,它通常是只读或可擦写的。光盘的访问速度比磁带快,但比硬盘慢。

  • 磁带:磁带是一种利用磁性原理进行信息记录和读取的外部存储器,它可以用于归档或备份大量的程序和数据。磁带的容量最大,但访问速度最慢,它通常是顺序访问或随机访问的。

8.外中断和内中断的理解。

说明:由于此问题理解程度不深,以下部分参考bing回答。

外中断和内中断是两种不同类型的中断,它们都是指在程序执行过程中,由于某些原因而暂停当前程序,转而执行另一个程序的过程。中断的目的是为了提高计算机的效率和响应能力,以及处理异常情况。

外中断

由外部设备或事件引起的中断,如键盘、鼠标、打印机、时钟、电源等。外中断通常是异步的,即它们不依赖于当前程序的状态,而是随机发生的。外中断需要硬件支持,即需要有专门的中断请求线和中断控制器来传递和处理中断信号。外中断可以分为可屏蔽中断和不可屏蔽中断,前者可以通过设置标志位来开启或关闭,后者则不能被屏蔽,必须立即处理。

内中断

由程序本身引起的中断,如除零错误、溢出错误、非法指令、缺页异常等。内中断通常是同步的,即它们依赖于当前程序的状态,而是在特定条件下发生的。内中断不需要硬件支持,即不需要有专门的中断请求线和中断控制器来传递和处理中断信号。内中断通常由操作系统或编译器提供相应的处理程序来处理。

中断的优先级

指在多个中断请求同时发生时,计算机按照一定的规则选择优先处理哪一个中断的顺序。中断的优先级是由硬件和软件共同决定的,具体的方法有以下几种:

  • 中断向量表法:计算机在内存中建立一个中断向量表,每个中断请求都有一个对应的中断向量号,通常越小的号码表示越高的优先级。当多个中断请求同时发生时,计算机按照中断向量号从小到大的顺序依次处理。
  • 中断屏蔽字法:计算机在内存中设置一个中断屏蔽字,每个中断请求都有一个对应的屏蔽位,通常为0表示允许中断,为1表示屏蔽中断。当多个中断请求同时发生时,计算机按照屏蔽位从低到高的顺序依次处理,如果某个屏蔽位为1,则忽略该中断请求。
  • 中断控制器法:计算机使用一个专门的硬件设备,即中断控制器,来管理和分配多个中断请求。每个中断请求都有一个对应的优先级码,通常越大的码表示越高的优先级。当多个中断请求同时发生时,中断控制器按照优先级码从高到低的顺序依次处理,并向CPU发送相应的信号。
CPU如何响应多个中断请求的问题,
  • CPU如何检测中断请求:CPU有一个专门的引脚,即中断请求线,用于接收来自外部设备或内部程序的中断信号。当有一个或多个中断信号到达时,CPU会在每条指令执行完毕后,检测中断请求线的状态,如果为高电平,则表示有中断请求发生,需要进行处理。
  • CPU如何识别中断请求:CPU有一个专门的硬件设备,即中断控制器,用于管理和分配多个中断请求。每个中断请求都有一个对应的优先级码,通常越大的码表示越高的优先级。当多个中断请求同时发生时,中断控制器按照优先级码从高到低的顺序依次处理,并向CPU发送相应的信号。CPU根据信号的内容,确定是哪个中断请求,并找到相应的中断服务程序的地址。
  • CPU如何执行中断服务程序:CPU在执行中断服务程序之前,需要保存当前程序的执行状态,即将当前程序的标志寄存器、指令指针寄存器和其他相关寄存器的内容压入堆栈。然后,CPU根据中断服务程序的地址,跳转到该地址开始执行。在执行完毕后,CPU需要恢复原来程序的执行状态,即将堆栈中保存的内容弹出到相应的寄存器。最后,CPU返回到原来程序被中断的地方继续执行。

附录:

参考资料:

1,《汇编语言(第四版)》王爽

2,mooc南京大学袁春风老师计算机系统基础(一)