linux内核源码分析(一)X86汇编指令

时间:2024-05-21 18:19:16

目录

 

什么是冯诺伊曼体系?

X86寄存器

汇编指令

mov指令

mov指令的长度分类

mov指令的操作数

mov的操作数组合

基本的内存寻址模型

pushl/popl/call/ret

C语言反编译


什么是冯诺伊曼体系?

linux内核源码分析(一)X86汇编指令

可以看到冯诺依曼架构不区分数据与指令,将两者放在同一内存中;而哈佛结构将两者分别存放在Instruction Memory和Data Memory。
指令和数据放在一起的后果是取指令和取数据不能同时进行,否则会引起访存的混乱。发展到今天,CPU的运算速度已经远远超过了访存速度,因此CPU必须浪费时间等数据;而哈佛构架由于指令和数据是分开存放的,所以在等数据的同时可以预取指令,CPU的利用率更高。

由于指令与数据放在同一内存带来的CPU利用率(吞吐率)限制就是冯诺依曼瓶颈。

冯诺依曼瓶颈的缓解办法有:

Providing a cache between the CPU and the main memory
providing separate caches or separate access paths for data and instructions (the so-called Modified Harvard architecture)
using branch predictor algorithms and logic
providing a limited CPU stack or other on-chip scratchpad memory to reduce memory access

X86寄存器

linux内核源码分析(一)X86汇编指令

linux内核源码分析(一)X86汇编指令

linux内核源码分析(一)X86汇编指令

linux内核源码分析(一)X86汇编指令

汇编指令

参考:https://www.jianshu.com/p/fd1cfed8a2d2

linux内核源码分析(一)X86汇编指令

mov指令

介绍:在汇编中mov指令主要用于在主内存(RAM)和寄存器之间传输数据,按照传递的方向可以分为两类

  • 加载(Load)指令:从主内存(RAM)寄存器传输数据,以一个给定的内存地址作为参数,他从内存中获取该地址位置存储的数据,并将该数据放入寄存器
  • 存储(Store)指令:即从寄存器中缓存的内存地址中所指向的目标位置,并将另外一个寄存器中缓存的数据保存到该目标位置,我们可以把内存看作已经编了号的数组,而通过索引就是内存地址,通过指定的内存地址可以在特定位置中的修改内存中的数据。

mov指令的长度分类

linux内核源码分析(一)X86汇编指令

根据操作数的字长可以分为三个版本的mov指令

  • movl Source Dest : L表示可以移动4个字节
  • movw Source Dest: W表示可以移动2个字节
  • movb Source Dest: B表示可以移动1个字节

mov指令的操作数

并且在移动指令中会用到两个操作数,Source表示移动的数据源,Dest表示移动的数据最后到达的位置。
通常在x86用的比较频繁的mov指令版本是32位的movl,这里就以 movl Source Dest为例子

mov指令的操作数通常分为三类

  • 立即数(Immediate) 可以将其视为常数,和C语言的常量类似,但是以“$”为前缀,例如0x400,-500
  • 寄存器(Register)可以是以上8个整数寄存器中的其中一个,例如:“%eax”,“%edx”,当我们执行类似“movl %eax %edx”这种情况下,eax寄存器就成为源参数,而edx寄存器就成为目标参数,其含义是获取eax中的内容并存储在edx中。
  • 内存(Memory):而内存作为操作数通常是由寄存器缓存给定的内存地址来间接去操作的,该地址占用4个字节,例如(%eax),当寄存器在一个括号中,我们就说eax持有一个指向RAM中的某个位置的地址,你可以类比为类似C/C++中的指针变量,的那么 movl (%eax) %ebx 表示的是什么意思呢?你可以考虑一下表示什么意思?

mov的操作数组合

movl指令通过不同类型的操作数组合,能够表达出不同类型的指令类型的。

linux内核源码分析(一)X86汇编指令

基本的内存寻址模型

间接访问
就是“(R)”这种格式,R表示一个寄存器名称。寄存器中保存着一个内存地址,我们用mov指令操作主内存时,只能通过使用该寄存器中的内容去实现对该地址指向的RAM中位置进行读/写操作。对于操作系统来说,内存其实就是一个连续的字节数组,每个字节都有对应的编号,而这个编号就是内存地址,也可以理解为该字节数组的索引。

我们用“RAM”表示主内存,那么 (R) 其实等价于 RAM[Reg[R]],

那么“movl (%edx),%eax”类似这样的指令的含义到这里应该不用多说了吧!

移位寻址
英文名称叫“Displacement”,这个其实就是在间接寻址表达式的基础是加上一个有符号的整数N。在汇编中抽象的移位寻址表达式“N(R)

我们用“RAM”表示主内存,那么 N(R) 其实等价于 RAM[Reg[R]+N],

那么具体的例子就是

  • 例如 “-4(%ebp)”:表示ebp寄存器中缓存的内存地址向低地址方向移动了4个字节
  • 例如“8(%ebp)”:表示ebp寄存器中缓存的内存地址向高地址方向移动8个字节。
  • 那么像这种“movl 4(%esp),%ecx”其实就是寄存器esp的指针向高地址方向偏移4个字节后的个新的地址,从该新地址指向的内存位置获取数据并保存到寄存器ecx。

pushl/popl/call/ret

参考:https://blog.****.net/striver1205/article/details/25695437

linux内核源码分析(一)X86汇编指令

 

C语言反编译

linux内核源码分析(一)X86汇编指令

linux内核源码分析(一)X86汇编指令

linux内核源码分析(一)X86汇编指令