读书笔记:10.1:1.汇编语言是使用助记符来编写程序的。
1.汇编需要使用汇编器来完成
2.通过反汇编可以得到人类能够理解的源代码。
3.汇编语言源文件的扩展名在Windows中主要是.asm,在Linux中主要是.S。
4.在高级编程语言的源代码中,指令和数据都是分散在各个位置的,但在编译后它们会被分别汇总到不同的段中。
5.汇编语言中可以使用跳转指令实现循环和条件分支。
计算机的CPU能够直接解释执行的只有本机代码(机器语言)。用C语言等编写的源代码,需要使用各个编程语言相对应的编译器进行编译,转换成本机代码。
即使是用汇编语言编写的源代码,最终也必须转换成本机代码才能运行。用来完成这种转换的程序称为汇编器,这个转换的过程称为汇编。在将源代码转换成本机代码这一点上,可以说汇编器和编译器的功能是相同的。
用汇编语言编写的源代码和本机代码是-一对应的,因此我们也可以将本机代码反过来转换成汇编语言的源代码。具有这种反向转换功能的程序称为反汇编器这种反向转换的过程称为反汇编.
10.2:用C编译器输出汇编语言源代码
除对本机代码进行反汇编之外我们还可以通过其他方法得到汇编语言源代码。大部分C语言编译器提供了将C语言源代码转换成汇编语言源代码的功能。使用这一功能,我们就可以对C语言源代码和汇编语言源代码进行对比研究了。
10.3:伪指令与注释
相信各位读者之中肯定有人是第一次看到汇编语言源代码。汇编语言看起来似乎很难,但实际上很简单,说汇编语言比C语言还简单一点都不夸张。在详细讲解源代码的内容之前,我们先来了解一下伪指令和注释汇编语言源代码中的指令分为两一种是会被转换成本机代码的一种般指令,另一种是专门针对汇编器的伪指令。伪指令负责告诉汇编器程序的结构和汇编的方法,因此也被称为汇编程序指令。
10.4汇编语言的语法是“操作码操作数”
在汇编语言中,每一行都表示CPU要执行的一个指令。汇编语言指令的语法是“操作码操作数"。
寄存器是CPU内部的存储空间但是寄存器的功能并不仅限于存储指令和数据,寄存器还可以参与运算。
10.5 最常用的movl指令
用于向寄存器和内存存放数据的movl指令可以说是最常用的指令。movl指令有两个操作数,分别表示数据取出和存放的目标位置。操作数可以是数值、标签(命名的地址)、寄存器名,我们也可以在它们的左右两边加上圆括号()来使用。
操作数左右两边没有括号时,表示直接处理这个数值,有括号时表示将括号中的值作为内存地址来解释并对该内存地址进行读写。
10.6 将数据存入栈中
程序在运行时会分配一块名为栈的内存空间。栈的英文stack原本是干草堆的意思,顾名思义,数据在栈中是从下(编号较大的地址)往上(编号较小的地址)堆积起来,然后从上往下取出的。esp寄存器(栈指针寄存器)会记录当前栈顶数据的内存地址。
10.7 函数调用的工作原理
用C语言编写的AddNum函数和MyFunc函数的入口分别用_AddNum:和_MyFunc:标签表示。函数名的前面加下划线(_)是BCC32编译器的规定。标签不是指令,它只用来表示某个位置。当调用函数时,我们就可以指定要调用的函数的入口位置的标签作为call指令的操作数。
执行call指令时,指向call指令的下一条指令的内存地址(也就是函数返回的目标地址)会被自动保存到栈中,esp寄存器的值也会随之更新。
10.9 全局变量和局部变量的工作原理
C语言中的变量分为两种,在函数外部声明的变量称为全局变量,在函数内部声明的变量称为局部变量。全局变量可以在程序的所有函数中访问,而局部变量只能在声明它的函数中访问。
当程序运行时,指令段和数据段会被一起加载到内存中,并在程序运行过程中一直驻留内存,因此程序中所有的函数都可以访问全局变量。
相对地,局部变量则是在调用函数时,由函数的代码临时存入栈中的。
10.10 循环的工作原理
下面我们通过分析汇编语言源代码,看一看C语言中的for循环和if条件分支在计算机内部是如何实现的。在循环和条件分支的实现上,尚未介绍的比较指令和转跳转指令发挥了很大的作用。
10.11条件分支的工作原理
下面我们来研究一下条件分支的工作原理。条件分支也是通过比较指令和跳转指令来实现的。
C语言的条件分支是通过if语句来描述的,程序中调用的两个函数都是空函数。