汇编笔记
平台
汇编语言是跟平台相关的,使用哪个平台的 GCC,生成的汇编代码就是哪个平台的。
x86 平台:
gcc -S simple.i -o simple.s
ARM 平台:
arm-linux-gcc -S simple.i -o simple_arm.s
所以,编译四步骤:预处理、编译、汇编、链接,第一步预处理在各个平台上都是一致的,当然库文件内容不同也会产生差异;从第二步编译,就真正开始不同了。
参考:
.text
.LFB0
c - 编译器生成的汇编代码中的 .LFB .LBB .LBE .LVL .loc 是什么
#define FUNC_BEGIN_LABEL "LFB"
#define FUNC_END_LABEL "LFE"
#define BLOCK_BEGIN_LABEL "LBB"
#define BLOCK_END_LABEL "LBE"
ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", loclabel_num);
LFB
和 LFE
在函数的开头和结尾生成
%rbp
rbp 是寄存器的名字
AT&T 格式的汇编,寄存器之前要加 %
rbp:register of base pointer 堆栈基指针寄存器(64位环境用 rbp 表示,32 位环境用 ebp 表示)
函数调用过程中栈到底是怎么压入和弹出的? 一图胜千言
草图
eax、ebx、ecx、edx
首先介绍我们会经常看到的一些寄存器: 4个数据寄存器(EAX、EBX、ECX和EDX) 2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP)
32位CPU有4个32位的通用寄存器EAX、EBX、ECX和EDX。对低16位数据的存取,不会影响高16位的数据。这些低16位寄存器分别命名为:AX、BX、CX和DX,它和先前的CPU中的寄存器相一致。 4个16位寄存器又可分割成8个独立的8位寄存器(AX:AH-AL、BX:BH-BL、CX:CH-CL、DX:DH-DL),每个寄存器都有自己的名称,可独立存取。程序员可利用数据寄存器的这种“可分可合”的特性,灵活地处理字/字节的信息。
那么如何理解eax,ax,al(ah)之间的关系呢? 专业点可以这样解释:Eax是32位寄存器,ax是16位寄存器,al(ah)是八位寄存器。 那么eax存储的数据就是ax的两倍,ax是al(ah)的两倍。 Eax可以存储的数字是DWORD(双字)ax存储的是WORD(字)AL(AH)存储的是BYTE(字节),那么为什么又有AH和AL呢,我们可以这样理解,AX=AH+AL,AH存储的是AX的高8位数据,AL存储的是AX的低八位数据。H这里就是HIGH,L就是LOW. 假设eax是0x64636261;那么ax就是eax的低十六位,也就是0x6261;Al是0x61;AH是0x62。
其他ebx,ecx,edx也有类似的bx,bl,bh等对应的寄存器,原理和上面相同。
在用途方面,他们有各自默认的用途:
-
Eax用来保存所有API函数的返回值。
-
寄存器AX和AL通常称为累加器(Accumulator),用累加器进行的操作可能需要更少时间。累加器可用于乘、除、输入/输出等操作,它们的使用频率很高;
-
寄存器BX称为基地址寄存器(Base Register)。它可作为存储器指针来使用;
-
寄存器CX称为计数寄存器(Count Register)。在循环和字符串操作时,要用它来控制循环次数;在位操作中,当移多位时,要用CL来指明移位的位数;
-
寄存器DX称为数据寄存器(Data Register)。在进行乘、除运算时,它可作为默认的操作数参与运算,也可用于存放I/O的端口地址。
由于存储的数据大小关系,AX、BX、CX和DX不能作为基址和变址寄存器来存放存储单元的地址, 32位寄存器EAX、EBX、ECX和EDX不仅可传送数据、暂存数据保存算术逻辑运算结果,而且也可作为指针寄存器,所以,这些 32 位寄存器更具有通用性。(什么是基址,什么是变址以后会说到)
参考:
edi、esi
2个变址和指针寄存器(ESI和EDI) 32位CPU有2个32位通用寄存器ESI和EDI。其低16位对应先前CPU中的SI和DI,对低16位数据的存取,不影响高16位的数据。
esp、ebp
这两个指针寄存器都和“栈”这个神秘的东东有关,
那么ESP和EBP指的分别是什么呢?
- ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。
- EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。
重点内容:记住eax一般用来保存函数的返回值,esp是栈顶指针寄存器,ebp是栈底指针寄存器,其它的就当通用寄存器。
.global
在汇编语言中导出符号名用 global 关键字,global 将符号导出为全局属性,对程序中的所有文件可见,这样其他外部文件中也可以引用被 global 导出的符号啦,无论该符号是函数,还是变量。
下面这个示例是为了将 _start 导出为全局符号,为的是给链接器用的。
——《操作系统真象还原》
.global _start
_start:
jmp _start
STM32 汇编
参考:基于LPC2000和STM32F103的视频教学(ARM)(汇编详细)
语法
- 使用 “;” 进行注释,单行注释。汇编没有多行注释
- 文件名以“.S”结尾,英特尔使用“.asm”
- 转向 process on
大佬
汇编语言入门教程 ——阮一峰
汇编 ——csdn shenmingik
参考
汇编 —— 函数 介绍了什么情况下只需要用寄存器就行了,什么情况下需要用到内存。正和我意。