1463 字
7 分钟
x86汇编
2024-08-10
无标签
寄存器
- PC
- 通用寄存器
- 段寄存器
对通用寄存器名字的解释: - 8008处理器 寄存器叫作 ABCDEHL,A即Accumulator,BCDE是随便选的字母,H与L代表内存寻址时用到的高位地址与低位地址
- 初代x86处理器有8个16位寄存器,分别是AX,BX,CX,DX,SI,DI,SP,BP。为了保持兼容性都是能够逻辑上拆成两个8位寄存器用的AX的高8位叫AH,低位叫AL,所以8位寄存器的L表示低8位的意思,而X代表数学上的任意数在这里代表H与L
- 另外这里的AX,BX,CX,DX,SI,DI,SP,BP是有含义的
- AX:Accumulator Register 累加器
- BX:Base Register 基址寄存器
- CX:Counter Register 计数器
- DX:Data Register 数据寄存器
- SI:Source Index 来源索引
- DI:Destination Index 目的索引
- BP:Base Pointer 栈基址
- SP:Stack Pointer 栈顶指针
- 到了32位的时代,原来的16位寄存器拓展到了32位,E就是代表Extension的意思
- 到了64位时代,再次拓展的寄存器前缀用的是R,另外新增了8个通用寄存器,并没有采用像前八个寄存器那么费解的命名方法
- …
数据格式
| 位数 | AT&T语法后缀 |
|---|---|
| 8 | b |
| 16 | w |
| 32 | l |
| 64 | q |
语法格式
intel格式与at&t格式
- 立刻数
- intel语法 0xff
- at&t $0xff
- 引用寄存器 at&t语法要加%前缀
- intel mov rax, rax
- at&t movq %rax, %rax
- 引用内存
- intel mov rax, [rbx]
- at&t movq %rax, (%rax)
- 运算方向
- intel sub D, S //D -= S
- at&t subq S, D //D -= S
- at&t显示指明本次运算的位数
- intel sub rax, rbx
- 对于来自寄存器操作数来说 宽度由寄存器的名字隐式给出
- 对于来自内存的操作数 要用word ptr或者byte ptr或者dword ptr显示给出如
add byte ptr [bx],2add word ptr [bx],2add dword ptr [bx],2
- at&t subq rax, rbx
- intel sub rax, rbx
指令
传送指令
- 对于8位数据或者是16位数据写入寄存器,寄存器高位数据并不会发生改变,而写入32位数据会导致高位归零。
相同宽度的数据传送
- imm(inst) 或者 (reg) 或者 [mem_addr] -> (reg) 或者 [mem_addr] 但是两边不能同时是内存的引用

- movabsq装入一个大立刻数
小宽度传入大宽度
- (reg)或者 [mem_addr] —零拓展或者符号拓展—> (reg)
- 分为符号拓展和无符号拓展两类指令
并没有movzlq或者movslq指令,前面提到过而写入32位数据会导致高位归零。
条件传送

- 跟分支指令相比不会改变控制流
- 源操作数是内存或者是寄存器 目标操作数是寄存器
- 源和目的的值可以是16位、32位或64位长。不支持单字节的条件传送
算术指令

加载有效地址
计算基址加偏移量加比例变址寻址的有效地址,汇编的形式语法为lea offset(base,index,scale), D,效果为,目的操作数必须 是一个寄存器。
- 比例变址系数必须设置为2的整数次幂
- 没有用到的参数可以省去默认为0(比例变址参数默认为1),但是除了结尾处的参数逗号必须保留,不然会把后面的参数当成这个位置上的参数。
- lea指令不加载有效地址上的操作数
- lea指令不设置条件码
- 还可以简洁地描述普通的算术操作。例如,如果寄存器rdx 的值为x,那么指令
leaq 7(%rdx,%rdx,4), %rax将设置寄存器rax的值为5x+7。编译器经常发现leaq的一些灵活用法,根本就与有效地址计算无关。
一元与二元操作
- 一元操作,只有一个操作数,既是源又是目的。这个操作数可以是一个寄存器,也可以是一个内存位置
- 第二个操作数既是源又是目的。要注意,源操作数是第一个,目的操作数是第二个,第一个操作数可以是立即数、寄存器或是内存位置。第二个操作数可以是寄存器或是内存位置。注意,当第二个操作数为内存地址时,处理器必须从内存读出值,执行操作,再把结果写回内存。
移位操作
最后一组是移位操作,先给出移位量,然后第二项给出的是要移位的数。可以进行算术和逻辑右移。移位量可以是一个立即数,或者放在单字节寄存器%cl中。(这些指令很特别,因为只允许以这个特定的寄存器作为操作数。)原则上来说,1个字节的移位量使得 移位量的编码范围可以达到。x86-64中,移位操作对w位长的数据值进行操作,移位量是由cl寄存器的低m位决定的,这里。高位会被忽略。
大乘法、除法

堆栈操作

控制
设置条件码
- cmp S1, S2等效于S2 - S1
- test S1, S2等效于S2 & S1

访问条件码
一条SET指令的目的操作数是低位单字节寄存器元素之一,或是一个字节的内存位置,指令根据条件将这个字节设量成0或者1。为了得到一个32位或64位结果,我们必须对高位清零 
跳转
- 直接间接
- 直接跳转 指令中的立刻数就是跳转目标(如果是相对寻址是PC+imm)
- 间接跳转
- switch-case 跳转表
- 函数指针
- 虚函数调用
- 相对与绝对跳转
- 相对跳转相对于下一条指令的地址进行跳转

