详细解读01、汇编语言概述

简介: 详细解读01、汇编语言概述

文章目录

1、前言2、汇编语言是什么3、来历4、寄存器5、寄存器的种类6、内存模式:Heap7、内存模型:Stack8、CPU指令8.1、一个实例8.2、push指令8.3、call指令8.4、mov指令8.5、add指令8.6、pop指令8.7、ret指令

1、前言

??早起入门单片机的时候,学习的C语言,程序编写也比较方便。近期由于换了个工作环境,使用的单片机不支持 C 编译,只能用汇编进行编程开发。于是就捡起来重新学习汇编语言。心想多学点知识肯定对自己是有好处的。所以想在自己学习汇编的同时做好学习笔记,方便自己的同时也方便他人。

??学习编程其实就是学高级语言,即那些为人类设计的计算机语言。

??但是,计算机不理解高级语言,必须通过编译器转成二进制代码,才能运行。学会高级语言,并不等于理解计算机实际的运行步骤。

??计算机真正能够理解的是低级语言,它专门用来控制硬件。汇编语言就是低级语言,直接描述/控制 CPU 的运行。如果你想了解 CPU 到底干了些什么,以及代码的运行步骤,就一定要学习汇编语言。

2、汇编语言是什么

??我们知道,CPU 只负责计算,本身不具备智能。你输入一条指令,它就运行一次,然后停下来,等待下一条指令。

??这些指令都是二进制的,称为操作码(opcode),比如加法指令就是 00000011。编译器的作用,就是将高级语言写好的程序,翻译成一条条操作码。

??对于人类来说,二进制程序是不可读的,根本看不出来机器干了什么。为了解决可读性的问题,以及偶尔的编辑要求,就诞生了汇编语言。

??汇编语言是二进制指令的文本形式,与指令是一一对应的关系。比如,加法指令 00000011 写成汇编语言就是 ADD。只要还原成二进制,汇编语言就可以被 CPU 直接执行,所以它是最底层的低级语言。

3、来历

??最早的时候,编写程序就是手写二进制指令,然后通过各种开关输入计算机,比如要做加法了,就按一下加法开关。后来,发明了纸带打孔机,通过在纸带上打孔,将二进制指令自动输入计算机。

??为了解决二进制指令的可读性问题,工程师将那些指令写成了八进制。二进制转八进制是轻而易举的,但是八进制的可读性也不行。很自然地,最后还是用文字表达,加法指令写成 ADD。内存地址也不再直接引用,而是用标签表示。

??这样的话,就多出一个步骤,要把这些文字指令翻译成二进制,这个步骤就称为 assembling,完成这个步骤的程序就叫做 assembler。它处理的文本,自然就叫做 aseembly code。标准化以后,称为 assembly language,缩写为 asm,中文译为汇编语言。

??每一种 CPU 的机器指令都是不一样的,因此对应的汇编语言也不一样。本文介绍的是目前最常见的 x86 汇编语言,即 Intel 公司的 CPU 使用的那一种。

4、寄存器

??学习汇编语言,首先必须了解两个知识点:寄存器和内存模型。

??先来看寄存器。CPU 本身只负责运算,不负责储存数据。数据一般都储存在内存之中,CPU 要用的时候就去内存读写数据。但是,CPU 的运算速度远高于内存的读写速度,为了避免被拖慢, CPU 都自带一级缓存和二级缓存。基本上,CPU 缓存可以看作是读写速度较快的内存。

??但是,CPU 缓存还是不够快,另外数据在缓存里面的地址是不固定的,CPU 每次读写都要寻址也会拖慢速度,因此,除了缓存之外,CPU 还自带了寄存器(register),用来存储最常用的数据。也就是说,那些最频繁读写的数据(比如循环变量),都会放在寄存器里面,CPU 优先读写寄存器,再由寄存器跟内存交换数据。

??寄存器不依靠地址区分数据,而依靠名称。每一个寄存器都有自己的名称,我们告诉 CPU 去具体的哪一个寄存器拿数据,这样的速度是最快的。有人比喻寄存器是 CPU 的零级缓存。

5、寄存器的种类

??早期的 x86 CPU 只有8个寄存器,而且每个都有不同的用途。现在的寄存器已经有100多个了,都变成通用寄存器,不特别指定用途了,但是早期寄存器的名字都被保存了下来。

EAX、EBX、ECX、EDX、EDI、ESI、EBP、ESP

上面这8个寄存器之中,前面七个都是通用的。ESP 寄存器有特定用途,保存当前 Stack 的地址

我们常常看到 32位 CPU、64位 CPU 这样的名称,其实指的就是寄存器的大小。32位 CPU 的寄存器大小就是 4 个字节。

6、内存模式:Heap

??寄存器只能存放很少量的数据,大多数时候,CPU 要指挥寄存器,直接跟内存交换数据。所以,除了寄存器,还必须了解内存怎么储存数据。

??程序运行的时候,操作系//代码效果参考:http://www.zidongmutanji.com/bxxx/341476.html

统会给它分配一段内存,用来储存程序和运行产生的数据。这段内存有起始地址和结束地址,比如从0x1000到0x8000,起始地址是较小的那个地址,结束地址是较大的那个地址。

程序运行过程中,对于动态的内存占用请求(比如新建对象,或者用 malloc 命令),系统就会从预分配好的那段内存之中,划出一部分给用户,具体规则是从起始地址开始划分(实际上,其实地址会有一段静态数据,这里忽略)。举例来说,用户要求得到10个字节的内存,那么从起始地址0x1000开始给他分配,一直分配到地址 0x100A,如果再要求得到22个字节,那么就分配到 0x1020。

这种因为用户主动请求而划分出来的内存区域,叫做 Heap(堆)。它由起始地址开始,从低位(地址)向高位(地址)增长。Heap 的一个重要特点就是不会自动消失,必须手动释放,或者由垃圾回收机制来回收。

7、内存模型:Stack

??除了 Heap 以外,其他的内存占用叫做 Stack(栈)。简单说,Stack 是由于函数运行而临时占用的内存区域。

请看下面的例子:

int main(){ int a = 2; int b = 3;}

上面代码中,系统开始执行 main 函数时,会为它在内存里面建立一个帧(frame),所有main的内部变量(比如a和b)都保存在这个帧里面。main函数执行结束后,该帧就会被回收,释放所有的内部变量,不再占用空间。

如果函数内部调用了其他函数,会发生什么情况?

int main(){ int a = 2; int b = 3; return add_a_and_b(a,b);}

等到add_a_and_b运行结束,它的帧就会被回收,系统会回到函数main刚才中断执行的地方,继续往下执行。通过这种机制,就实现了函数的层层调用,并且每一层都能使用自己的本地变量。

??所有的帧都存放在 Stack,由于帧是一层层叠加的,所以 Stack //代码效果参考:http://www.zidongmutanji.com/bxxx/347424.html

叫做栈。生成新的帧,叫做“入栈”,英文是 push;栈的回收叫做“出栈”,英文是pop。Stack的特点就是,最晚入栈的帧最早出栈(因为最内层的函数调用,最先结束运行),这就叫做“后进先出”的数据结构。每一次函数执行结束,就自动释放一个帧,所有函数执行结束,整个 Stack 就都释放了。

Stack是有内存区域的结束地址开始,从高位(地址)向低位(地址)分配。比如,内存区域的结束地址是0x8000,第一帧假定是16字节,那么下一次分配的地址就会从0x7FF0开始;第二帧假定需要64字节,那么地址就会移动到0x7FB0。

8、CPU指令

8.1、一个实例

了解寄存器和内存模型以后,就可以来看汇编语言到底是什么了。下面是一个简单的程序example.c。

int add_a_and_b(int a,int b){ return a+b;} int main(){ return add_a_and_b(2,3);}

gcc 将这个程序转成汇编语言。

$ gcc -S example.c

上面的命令执行以后,会生成一个文本文件example.s,里面就是汇编语言,包含了几十行指令。这么说吧,一个高级语言的简单操作,底层可能由几个,甚至几十个 CPU 指令构成。CPU 依次执行这些指令,完成这一步操作。

example.s经过简化以后,大概是下面的样子。

_add_a_and_b: push %ebx mov %eax, 【%esp+8】 mov %ebx, 【%esp+12】 add %eax, %ebx pop %ebx ret _main: push 3 push 2 call _add_a_and_b add %esp, 8 ret

可以看到,原程序的两个函数add_a_and_b 和 main,对应两个标签//代码效果参考:http://www.zidongmutanji.com/zsjx/21991.html

==_add_a_and_b== 和 main。每个标签里面是该函数所转成的 CPU 运行流程。

每一行就是 CPU 执行的依次操作。它又分成两部分,就以其中一行为例。

push

相关文章
|
6月前
|
存储 Java 程序员
汇编语言教程及实例
汇编语言教程及实例
|
6月前
|
存储 缓存 Java
详细解读01、汇编语言概述
详细解读01、汇编语言概述
50 0
|
7月前
|
自然语言处理 算法 前端开发
编译原理 -概述
编译原理 -概述
47 0
|
7月前
|
存储 小程序 程序员
嵌入式C语言基本操作方法之经典
嵌入式C语言基本操作方法之经典
103 0
|
自然语言处理 JavaScript 前端开发
程序设计语言概述
程序设计语言是用于编写计算机程序的一种形式化语言。它提供了一套语法和语义规则,用于描述计算机程序的结构和行为。
289 0
|
存储 安全 程序员
5.1 汇编语言:汇编语言概述
汇编语言是一种面向机器的低级语言,用于编写计算机程序。汇编语言与计算机机器语言非常接近,汇编语言程序可以使用符号、助记符等来代替机器语言的二进制码,但最终会被汇编器编译成计算机可执行的机器码。相较于高级语言(如C、Python等),汇编语言学习和使用难度相对较大,需要对计算机内部结构、指令集等有深入的了解,以及具有良好的编程习惯和调试能力。但对于需要对计算机底层进行操作的任务,汇编语言是极其高效的,因为其可以实现对计算机底层资源的精细控制,极大地提高了计算机运行效率。
141 0
|
缓存 前端开发 Java
汇编语言简介
汇编语言(assembly language)是一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。在汇编语言中,用助记符(Mnemonics)代替机器指令的操作码,用地址符号(Symbol)或标号(Label)代替指令或操作数操作数的地址。在不同的设备中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令。普遍地说,特定的汇编语言和特定的机器语言指令集是一一对应的,不同平台之间不可直接移植。
|
Unix Linux C语言
C语言的概述
#include <stdio.h> //标准输入输出头文件 int main(void) //主函数main { int num; //定义名为num的变量 num = 1; //为num赋一个值 printf("I am a simple!); //打印I am a simple return 0; }
140 1
C语言的概述
|
存储 编译器 C语言
C语言文件操作的基础应用(超详细)(一)
C语言文件操作的基础应用(超详细)
263 0
C语言文件操作的基础应用(超详细)(一)
|
C语言
C语言文件操作的基础应用(超详细)(二)
C语言文件操作的基础应用(超详细)
129 0
C语言文件操作的基础应用(超详细)(二)
下一篇
DataWorks