x86与x86-64数据格式与常用的汇编指令笔记

1、数据格式

由于是从16位体系结构扩展成 32位的,Intel 用术语 “字(word)”表示16位数据类型。因此,称32位数为“双字(double words)”,称64位数为“四字(quad words )。标准 int 值存储为双字(32位)。指针(在此用 char *表示)存储为8字节的四宇,64 位机器木来就预期如此。x86-64 中.数据类型 1ong 实现为 64 位,允许表示的值范围较大。

下图为C语言基本数据类型(x86-64):

c声明 Intel数据类型 汇编代码后缀 大小(字节)
char 字节 b 1
short w 2
int 双字 l 4
long 四字 q 8
char* 四字 q 8
float 单精度 s 4
double 双精度 l 8

大多数GCC生成的汇编指令都有一个字符的后缀,表明操作数的大小。例:数据传送指令有四个变种:movb(传送字节)、movw(传送字)、movl(传送双字)和movq(传送四字)。注意,汇编代码也使用后级‘l’来表示 4 字节整数和8字节双精度浮点数,这不会产生歧义,因为浮点数使用的是一组完全不同的指令和寄存器。

2、通用寄存器

一个x86-64的中央处理器单元包含一组16个存储64位值的通用目的寄存器。
在这里插入图片描述
画的有点丑,哈哈哈

3、操作数指示符

大多数的指令都有1一或多个操作数,指示出一个操作中要使用的源数据值,以及放置结果的目的地址。源数据值可以以常数、从寄存器或内存中读出。结果可以存放在寄存器或内存中。

各种不同的操作数的可能性被分为3类:

立即数:用来表示常数值,比如:$123,$-456

寄存器:表示一个寄存器中的内容

内存:通常根据计算出来的地址访问某个内存的位置

4、数据传送指令(MOV)

最频繁使用的指令就是将数据从一个位置复制到另一个位置的指令。最简单形式的数据传送指令—MOV类,这些指令把数据从源位置复制到目的位置,不做任何变化。

MOV类指令有如下几种:

指令 效果 描述
movb I,R l->R 传送字节
movw I,R l->R 传送字
movl I,R l->R 传送双字
movq I,R l->R 传送四节
movabsq I,R l->R 传送绝对四字

源操作数指定的是一个立即数,它存在寄存器或者内存中。目的操作数指定一个位置,要么是寄存器,要么是一个内存地址。x86-64加了一条限制,传送指令的两个操作数不能都指向内存位置。大多数情况下,MOV指令只会更新目的操作数指定的那些寄存器字节或者内存位置。唯一的例外是movl指令,以寄存器作为目的时,他会把该寄存器的高4字节设置为0。原因是x86-64采用的惯例,即任何为寄存器生成32位值的指令都会把该寄存器的高部位分置成0。

movabsq指令能够以任意64位立即数值作为源操作数,并且只能以寄存器作为目的

4、入栈和出栈

两个数据的传送操作可以将数据压入程序栈中,以及从程序栈中弹出数据。栈是一种数据结构,可以添加或删除值,遵循“后进先出的原则”。通过push把数据压入栈中,通过pop操作删除数据:它具有一个属性:弹出的值永远是最近被压入而且仍然在栈中的值。程序栈存放在内存的某个区域。,栈通常向下增长(高地址—>低地址),这样一来,栈顶元素的地址是所有栈中元素地址中最低的。栈指针%rsp保存着栈顶元素的地址。

指令如下介绍:
在这里插入图片描述
将一个四字值压入栈中,首先要将栈指针减8,然后将值写到新的栈顶地址,例如:

pushq %rbp        //把%rbp压栈

等价于:

subq $8,%rsp        //%rsp地址加8
movq %rbp,(%rsp)    //%rbp的值存放到栈上

弹出一个四字的操作包括从栈顶位置读出数据,然后将栈指针加8,例如:

popq %rax    //%rax出栈

等价于:

movq (%rsp),%rax    //从栈中读出值存放到%rax
addq $8,%rsp		//%rsp地址加八

无论如何,%rsp指向的地址总是栈顶。

5、算术和逻辑操作

大多数的操作都分成了指令类,这些指令有各种带不同大小操作数的变种(只有leaq没有其他大小的变种)。给出的每个指令类都对有这四种(b、w、l、q)不同大小数据的指令。这些指令被分为四组:加载有效地址、一元操作、二元操作和移位。二元操作有两个操作数,一元操作有一个操作数。整数算术操作如下图:
整数算术操作

6、比较和测试指令

比较和测试指令如下:

在这里插入图片描述
CMP指令根据两个操作数之差来设置条件码。除了只设置条件码不更新寄存器之外,CMP指令与SUB指令的行为是一样的。

TEST指令的行为与AND指令一样,除了他们只设置条件码不改变寄存器的值。典型的用法是,两个操作数是一样的(testq %rax,%rax 用来检测%rax是负数、零,还是正数),或其中的一个操作数是一个掩码,用来指示哪些位应该被测试。

7、跳转指令

正常执行的情况下,指令按照他们出现的顺序一条条的往下执行。跳转指令会导致执行切换到程序中一个全新位置。

jmp指令是无条件跳转。它可以是直接跳转,即跳转目标是作为指令的一部分编码的;也可以是间接跳转,即跳转目标是从寄存器或内存位置中读出的。

具体指令格式如下:
在这里插入图片描述
当上表中的跳转条件满足条件时,这些指令会跳转到一条带标号的目的地址。

表中所示的其他跳转指令都是有条件的—它们根据条件码的某种组合,或者跳转,或者继续执行代码序列中下一条指令。

表中的ZF、SF、OF、CF为条件码。
在这里插入图片描述

8、条件传送指令

条件跳转指令,每条指令都有两个操作数:源寄存器或内存地址S,和目的寄存器R,这些指令的结果取决于条件码的值。只有在指定的条件满足时,源值才会被复制到目的寄存器中。

源和目的的值可以是16位、32位、64位长。不支持单字节的条件传送。
在这里插入图片描述

先记到这里,后续继续补充。

猜你喜欢

转载自blog.csdn.net/weixin_45309916/article/details/125349571