跳转至

什么?高级语言不就是拿来简化阅读和编写的,怎么还会有人去学汇编...

哎哎,作者人菜瘾大,想看看代码最底层的逻辑。 话不多说,直接开始吧

如果想要更好的可读性,建议看一看cpp insights网站https://cppinsights.io/

开始

直接学指令真难懂吧! 还是先上一个例子

编译器

指针

用的最多的一般就是这个 qword ptr,代表quad word pointer,64位指针,该操作数后续接指针地址的值,另一个操作数则可以是寄存器的值、也可以是单独的值 还有: - dword ptr:32 位(4 字节)指针 - word ptr:16 位(2 字节)指针 - byte ptr:8 位(1 字节)指针

寄存器

在CPU中,程序员能够用指令读写的部件只有寄存器

寄存器用来存放临时数据,以8086CPU为例,所有的寄存器都是16位的。 1. %rax 作为函数返回值使用。 2. %rsp 栈指针寄存器,指向栈顶,Stack Point 3. %rbp 栈桢指针,指向栈基,大部分优化编译-O2其实已经去除了帧指针。Base Point 4. %rdi,%rsi,%rdx,%rcx,%r8,%r9 用作函数参数,依次对应第1参数,第2参数。。。 5. %rbx,%r12,%r13,%14,%15 用作数据存储,遵循被调用者使用规则,简单说就是随便用,调用子函数之前要备份它,以防他被修改 6. %r10,%r11 用作数据存储,遵循调用者使用规则,简单说就是使用之前要先保存原值 7. %rip: 相当于PC指针指向当前的指令地址,指向下一条要执行的指令

而带e前缀的寄存器,一般都是只用后8位

地址计算:物理地址,段地址和偏移地址

地址总线一般都设计为20位。 因此用16位段地址+16位偏移地址来计算出物理地址 * 物理地址=段地址X16 + 偏移地址 也就是说段地址在16进制上左移一位再加上偏移地址就是实际的物理地址。

123000c8

 :1230 + 偏移00c8

物理地址 = 12300 + 00c8 = 123c8
其中,我们可以把段地址X16 + 偏移地址看作基础地址,也可以表示为段地址:偏移地址

8086CPU 内存分布

由于8086cpu位数只有16位,总线位数20位,需要段地址+偏移地址寻址。

段寄存器

8086由四个段寄存器CS、DS、SS、ES,总之后面加个S(Segament),你就懂这个是段寄存器了! 最核心的两个:CS和IP,CS:IP指向的内容将当作指令执行

DS和内存单元[Address]

一般直接赋值地址的,赋值的都是段地址

mov bx.1000H
假设我们要读10000H(1000:0)的内存数据,那偏移地址该如何读取呢? 我们使用[···]来表示一个单元,而里面的值就是偏移地址
mov al,[0]
这还不够,想仅凭[···] 就知道10000H数据,为什么呢? 这是因为8086CPU默认自动取ds中的数据为内存单元的段地址。因此,我们必须要给ds赋值
mov dx,bx
最后,将10000H位置的数据存到al的总体顺序应该是
mov bx.1000H
mov dx,bx
mov al,[0]

现代CPU 内存分布

而现代CPU足足有64位,总线最大也有48位且一般都有32GB也是35位。后续都将以现代CPU内存分布进行总结

寄存器的变化

8086CPU --> 32位x86CPU

ax–>EAX
BP–>EBP(extended base pointer)

push,pop

push和pop是可以在寄存器和内存传输指令的!!! * push用来将后面的数据入栈,pop用来将后面的数据出栈

  • push 寄存器
  • push 段寄存器
  • push 内存单元

mov、add、sub

他们的特点都是由两个操作数,

1. mov

比如mov,从第二个操作数将内存中的数据值向第一个操作数传送过去: * mov 寄存器 ,数据 AX= 18 * mov 寄存器,寄存器 AX = BX * mov 寄存器,内存单元 AX = 内存单元 * mov 内存单元,寄存器 内存单元 = AX * mov 段寄存器,寄存器

2. add

add 意味 前后两个操作数相加,并返回到第一个操作数上 * add ax,8 即 ax = ax + 8 * add ax,bx 即 ax = ax + bx

3.sub

sub 意味着第一个操作数减去第二个操作数,再返回第一个操作数

4.cmp

lea,Load Effective Address

我在《汇编原理》里并没有看到这个指令,《深入理解计算机系统也没有看到》 后来取往网上看了下,他和mov的区别就在于。 mov传的是内存值,而lea传的是有效地址. 比如下面的mov,传送过去得到的就是[0]对应位置的值 而lea,获得的就是[0]这个偏移位置地址,可以理解为c/c++中的&

mov al,[0]
lea al,[0]

call、ret

参考

1. x86-64寄存器和栈帧 - 知乎 (zhihu.com)