汇编

寄存器

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

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

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

种类

32 位 CPU 的寄存器大小就是4个字节

  • EAX
  • EBX
  • ECX
  • EDX
  • EDI
  • ESI
  • EBP
  • ESP 保存当前 Stack top 的地址
  • EIP(指令指针)包含正在执行的当前指令的地址

EAX的最低有效2字节可被视为称为AX的16位寄存器。AX的最低有效字节可以用作单个8位寄存器AL,而AX的最高有效字节可以用作单个8位寄存器AH

操作

-x86指令

CPU 指令,%ebx是该指令要用到的运算子。一个 CPU 指令可以有零个到多个运算子。

操作码 [操作数, 操作数]

  • 8位无符号数的范围为0-255
  • 16位无符号数的范围为0-65 535
  • 8位有符号数的范围为-128-+127
  • 16位有符号数的范围为-32 768-+32 767

  • 8位 byte 字节 、16位 word 字、32 dword 双字

_main:
   push   3  ; push指令其实有一个前置操作。它会先取出 ESP 寄存器里面的地址 ESP -4 (-4) (- 高位向低位地址,4 类型是int,占用4个字节)
   push   2  ; 运算子2 放入 Stack  ESP-4 (-8)
   call   _add_a_and_b ; 调用函数 找_add_a_and_b标签
   add    %esp, 8 ; add_a_and_b函数终止执行,系统就回到刚才main函数中断的地方,继续往下执行 , ESP 寄存器里面的地址,手动加上8个字节,再写回 ESP 寄存器。这是因为 ESP 寄存器的是 Stack 的写入开始地址
   ret          ; 

_add_a_and_b:
   push   %ebx  ; 将 EBX 寄存器里面的值,写入_add_a_and_b这个帧。这是因为后面要用到这个寄存器,就先把里面的值取出来,用完后再写回去 ESP-4(-12)
   mov    %eax, [%esp+8] ; ESP 寄存器里面的地址加上8个字节就是push的2 取出的是2,再将2写入 EAX 寄存器。
   mov    %ebx, [%esp+12] ; ESP 寄存器里面的地址加上8个字节就是push的3 取出的是3,将其写入 EBX 寄存器
   add    %eax, %ebx  ; EAX 寄存器的值(即2)加上 EBX 寄存器的值(即3),得到结果5,再将这个结果写入第一个运算子 EAX 寄存器
   pop    %ebx   ; esp + 4 (-8) 取出 Stack 最近写入的值(即 EBX 寄存器的原始值),再将这个值写回 EBX 寄存器(因为加法已经做完了,EBX 寄存器用不到了)
   ret  ; 终止当前函数的执行,运行权交还给上层函数。也就是,当前函数的帧将被回收


   

大小端存储方式 通常是小端