1463 字
7 分钟
x86汇编
2024-08-10
无标签

寄存器#

  • PC
  • 通用寄存器
  • 段寄存器 Pasted image 20240810194832 对通用寄存器名字的解释:
  • 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语法后缀
8b
16w
32l
64q

语法格式#

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],2
        • add word ptr [bx],2
        • add dword ptr [bx],2
    • at&t subq rax, rbx

指令#

传送指令#

  • 对于8位数据或者是16位数据写入寄存器,寄存器高位数据并不会发生改变,而写入32位数据会导致高位归零。

相同宽度的数据传送#

  • imm(inst) 或者 (reg) 或者 [mem_addr] -> (reg) 或者 [mem_addr] 但是两边不能同时是内存的引用 Pasted image 20240810200813
  • movabsq装入一个大立刻数

小宽度传入大宽度#

  • (reg)或者 [mem_addr] —零拓展或者符号拓展—> (reg)
  • 分为符号拓展和无符号拓展两类指令 Pasted image 20240810201034 并没有movzlq或者movslq指令,前面提到过而写入32位数据会导致高位归零。

条件传送#

Pasted image 20240810204734

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

算术指令#

Pasted image 20240810201519

加载有效地址#

计算基址加偏移量加比例变址寻址的有效地址,汇编的形式语法为lea offset(base,index,scale), D,效果为EA=base+offset+scale×indexEA = base + offset + scale \times index,目的操作数必须 是一个寄存器。

  • 比例变址系数必须设置为2的整数次幂
  • 没有用到的参数可以省去默认为0(比例变址参数默认为1),但是除了结尾处的参数逗号必须保留,不然会把后面的参数当成这个位置上的参数。
  • lea指令不加载有效地址上的操作数
  • lea指令不设置条件码
  • 还可以简洁地描述普通的算术操作。例如,如果寄存器rdx 的值为x,那么指令leaq 7(%rdx,%rdx,4), %rax将设置寄存器rax的值为5x+7。编译器经常发现leaq的一些灵活用法,根本就与有效地址计算无关。

一元与二元操作#

  • 一元操作,只有一个操作数,既是源又是目的。这个操作数可以是一个寄存器,也可以是一个内存位置
  • 第二个操作数既是源又是目的。要注意,源操作数是第一个,目的操作数是第二个,第一个操作数可以是立即数、寄存器或是内存位置。第二个操作数可以是寄存器或是内存位置。注意,当第二个操作数为内存地址时,处理器必须从内存读出值,执行操作,再把结果写回内存。

移位操作#

最后一组是移位操作,先给出移位量,然后第二项给出的是要移位的数。可以进行算术和逻辑右移。移位量可以是一个立即数,或者放在单字节寄存器%cl中。(这些指令很特别,因为只允许以这个特定的寄存器作为操作数。)原则上来说,1个字节的移位量使得 移位量的编码范围可以达到281=2552^8-1=255。x86-64中,移位操作对w位长的数据值进行操作,移位量是由cl寄存器的低m位决定的,这里2m=w2^m=w高位会被忽略

大乘法、除法#

Pasted image 20240810203854

堆栈操作#

Pasted image 20240810203108

控制#

设置条件码#

  • cmp S1, S2等效于S2 - S1
  • test S1, S2等效于S2 & S1 Pasted image 20240810204027

访问条件码#

一条SET指令的目的操作数是低位单字节寄存器元素之一,或是一个字节的内存位置,指令根据条件将这个字节设量成0或者1。为了得到一个32位或64位结果,我们必须对高位清零 Pasted image 20240810204148

跳转#

  • 直接间接
    • 直接跳转 指令中的立刻数就是跳转目标(如果是相对寻址是PC+imm)
    • 间接跳转
      • switch-case 跳转表
      • 函数指针
      • 虚函数调用
  • 相对与绝对跳转
  • 相对跳转相对于下一条指令的地址进行跳转 Pasted image 20240810204550