游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

x86汇编语法基础(gnu格式)

  一、寄存器1。1通用寄存器
  一个x8664的中央处理单元(CPU)包含一组16个存储64位值的通用寄存器。这些寄存器用来存储整数数据和指针。下图显示了这16个寄存器。它们的名字都以r开头,不过后面还跟着不同命名规则的名字,这是由于指令集历史演化造成的。最初的8086中有8个16位的寄存器,即图中的ax到bp。每个寄存器都有特殊的用途,它们的名字就反映了这些不同的用途。扩展到IA32架构时,这些寄存器也扩展成32位寄存器,标号从eax到ebp。扩招到x8664后,原来的8个寄存器扩展成64位,标号从rax到rbp。除此之外,还增加了8个新的寄存器,它们的标号是按照新的命名规则制定的:从r8到r15。
  如上图中嵌套的方框表明的,指令可以对这16个寄存器的低位字节中存放的不同大小的数据进行操作。字节级操作可以访问最低的字节,16位操作可以访问最低的2个字节,32位操作可以访问最低的4个字节,而64位操作可以访问整个寄存器。Tips:当指令以寄存器作为目标时,对于生成小于8字节结果的指令,寄存器中剩下的字节如何处理,有两条规则:
  生成1字节和2字节数字的指令会保持剩下的字节不变
  生成4字节的指令会把高位4字节置为0。
  后面这条规则是作为从IA32到x8664的扩展的一部分而采用的。1。2标志寄存器EFLAFS
  EFLAGS标志寄存器包含有状态标志位、控制标志位以及系统标志位,处理器在初始化时将EFLAGS标志寄存器赋值为00000002H。
  下图描绘了EFLAGS标志寄存器各位的功能,其中的第1、3、5、15以及2231位保留未使用。由于64位模式不再支持VM和NT标志位,所以处理器不应该再置位这两个标志位。
  TIPs:在64位模式中,EFLAGS标志寄存器已从32位扩展为64位,被称作RFLAGS寄存器。其中高32位保留未使用,低32位与EFLAGS相同。
  接下来,我们会根据标志位功能将EFLAGS划分位状态标志、方向标志、系统标志和IOPL区域等几部分,并对各部分的标志位功能进行逐一讲解。(请参考Intel官方白皮书Volumn1的3。4。3节)。1。2。1状态标志
  EFLAGS标志寄存器的状态标志(位0、2、4、6、7和11)可以反映出汇编指令计算结果的状态,像add、sub、mul、p等汇编指令计算结果的奇偶性、溢出状态、正负值皆可从上述状态找那个反映出来。
  下表是这些状态标志的功能描述:
  缩写
  全称
  名称
  位置
  描述
  CF
  CarryFlag
  进位标志
  0hr运算中,当数值的最高位产生了进位或者借位,CF位都会置1,否则为0。它可用于检测无符号整数运算结果是否溢出。也可用于多精度运算中。
  PF
  ParityFlag
  奇偶标志
  2hr用于标记结果低8位中1的个数,如果为偶数,PF位为1,否则为0。注意,是最低的那8位,不管操作数是16位,还是32位。奇偶校验经常用于数据传输开始时和结束后的对比,判断传输过程中是否出现错误。
  AF
  AuxiliaryCarryFlag
  辅助进位标志
  4hr辅助进位标志,用来记录运算结果低4位的进、借位情况,即若低半字节有进、借位,AF为1,否则为0。
  ZF
  ZeroFlag
  零值标志
  6hr若计算结果为0,此标志位置1,否则为0。
  SF
  SignFlag
  符号标志
  7hr若运算结果为负,则SF位为1,否则为0。
  OF
  OverflowFlag
  溢出标志
  11hr用来标识计算的结果是否超过了数据类型可以表示的范围,若OF为1,表示有溢出,为0则未溢出。专门用于检测有符号整数运算结果是否溢出。
  这些标志位可反映出三种数据类型的计算结果:无符号整数、有符号整数和BCD整数(Binarycodeddecimalintegers)。其中CF标志位可反映出无符号整数运算结果的溢出状态;OF标志位可反映出有符号整数(补码表示)运算结果的溢出状态;AF标志位表示BCD整数运算结果的溢出状态;SF标志位反应出有符号整数运算结果的正负值;ZF标志位反映出有符号或无符号整数运算的结果是否为0。
  以上这些标志位,只有CF标志位可通过stc、clc和cmc(ComplementCarryFlag,计算原CF位的补码)汇编指令更改位值。它也可借助位操作指令(bt、bts、btr和btc指令)将指定位值复制到CF标志位。而且,CF标志位还可在多倍精度整数计算时,结合adc指令(含进位的加法计算)或sbb指令(含借位的减减法)将进位计算或借位计算扩展到下次计算中。
  至于状态跳转指令Jcc、状态字节置位指令SETcc、状态循环指令LOOPcc以及状态移动指令CMOVcc,它们可将一个或多个状态标志位作为判断条件,进程分支跳转、字节置位以及循环计数。1。2。2方向标志
  DF方向标志位(DirectionFlag)位于EFLAGS标志寄存器的第10位,它控制着字符串指令(诸如movs、cmps、scas、lods、stos等)的操作方向。置位DF标志位可使字符串指令按从高到低的地址方向(自减)操作数据,复位DF标志位可使字符串指令按从低到高的地址方向(自增)操作数据。汇编指令std和cld可用于置位和复位DF方向标志。1。2。3系统标志和IOPL区域
  第8位为TF位,即TrapFlag,意为陷阱标志位。此位若为1,用于让CPU进入单步运行方式,若为0,则为连续工作的方式。平时我们用的debug程序,在单步调试时,原理上就是让TF位为1。
  第9位为IF位,即InterruptFlag,意为中断标志位。若IF位为1,表示中断开启,CPU可响应外部可屏蔽中断。若为0,表示中断关闭,CPU不再响应来自CPU外部的可屏蔽中断,但CPU内部的异常还是要响应的。
  第1213位为IOPL,即InputOutputPrivilegeLevel,这用在有特权级概念的CPU中。有4个任务特权级,即特权级03,故IOPL要占用2位来表示这4种特权级。
  第14位为NT,即NestTask,意为任务嵌套标志位。8088支持多任务,一个任务就是一个进程。当一个任务中又嵌套调用了另一个任务时,此NT位为1,否则为0。
  第16位为RF位,即ResumeFlag,意为恢复标志位。该标志位用于程序调试,指示是否接受调试故障,它需要与调试寄存器一起使用。当RF为1时忽略调试故障,为0时接受。
  第17位为VM位,即Virtual8086Model,意为虚拟8086模式。
  第18位为AC位,即AlignmentCheckAccessControl,意为对齐检查。若AC位为1时,则进行地址对齐检查,位0时不检查。
  第19位为VIF位,即VirtualInterruptFlag,意为虚拟终端标志位,虚拟模式下的中断标志。
  第20位为VIP位,即VirtualInterruptPendingFlag,意为虚拟中断挂起标志位。在多任务情况下,为操作系统提供的虚拟中断挂起信息,需要与VIF位配合。
  第21位为ID位,即IdentificationFlag,意为识别标志位。系统经常要判断CPU型号,若ID位为1,表示当前CPU支持CPUID指令,这样便能获取CPU的型号、厂商信息等;若ID位为0,则表示当前CPU不支持CPUID指令。1。3段寄存器
  x8664架构,拥有6个16位段寄存器(CS、DS、SS、ES、FS和GS),用于保存16位段选择子。段选择子是一种特殊的指针,用于标识内存中的段。要访问内存中的特定段,该段的段选择子必须存在于相应的段寄存器中。
  在平坦内存模型中,段选择子指向线性地址空间的地址0;在分段内存模型中,每个分段寄存器通常加载有不同的段选择子,以便每个分段寄存器指向线性地址空间内的不同分段。
  每一个段寄存器表示三种存储类型之一:代码,数据,栈。
  CS寄存器保存了代码段(codesegment)选择子。代码段存储的是需要执行的指令,处理器使用CS寄存器内的代码段选择子和RIPEIP寄存器的内容生成的线性地址来从代码段查询指令。RIPEIP寄存器存储的是下一条要执行的指令在代码段上的偏移。
  DS、ES、FS和GS寄存器指向了四个数据段(datasegment)。
  SS寄存器包含栈段(stacksegment)的段选择子,其中存储当前正在执行的程序、任务或处理程序的过程堆栈。1。4控制寄存器
  目前,Intel处理器共拥有6个控制寄存器(CR0、CR1、CR2、CR3、CR4、CR8),它们有若干个标志位组成,通过这些标志位可以控制处理器的运行模式、开启扩展特性以及记录异常状态等功能。1。5指令指针寄存器
  RIPEIP寄存器,即指令指针寄存器,有时称为程序计数器。指令指针(RIPEIP)寄存器包含当前代码段中要执行的下一条指令的偏移量。1。6MSR寄存器组
  MSR(ModelSpecificRegister)寄存器组可提供性能监测、运行轨迹跟踪与调试以及其它处理器功能。在使用MSR寄存器组之前,我们应该通过CPUID。01h:EAX〔5〕来检测处理器是否支持MSR寄存器组。处理器可以使用RDMSR和WRMSR对MSR寄存器组进行访问,整个访问过程借助ECX寄存器索引寄存器地址,再由EDX:EAX组成的64位寄存器保持访问值。(在处理器支持64位模式下,RCX、RAX和RDX寄存器的高32位将会被忽略)。二、指令集2。1操作数和指令后缀2。1。1操作数
  x86指令可以有0到3个操作数,多个操作数之间以逗号(,)分隔。对于有两个操作数的指令,第一个是源操作数,第二个是目的操作数,指令的执行结果保存到第二个操作数表示的寄存器或内存地址中。
  源数据值可以以常数形式给出,或是从寄存器或内存中读取。结果可以存放在寄存器或内存中。因此,操作数被分为三种类型:立即数(immediate),用来表示常数值。立即数通过在整数前加一个来表示。比如,577或0x1F;寄存器(register),它表示某个寄存器的内容,通过在寄存器名声前加上来表示。比如:eax或al;内存引用,它会根据计算出来的地址(通常称为有效地址)访问某个内存位置。内存引用的语法:segment:offset(base,index,scale)。segment可以是x86架构的任意段寄存器。segment是可选的,如果指定的话,后面要跟上冒号(:)来与offset隔离开;如果未指定指定的话,默认为数据段寄存器ds。offset是一个立即数偏移量,是可选的。base表示基址寄存器,可以是16个通用寄存器中的任意一个。index表示变址寄存器,可以是16个通用寄存器中的任意一个。scale表示比例因子,scale会与index相乘再加上base来表示内存地址。比例因子必须是1、2、4、或者8,若果比例因子未指定,默认为1。有效地址被计算为:D〔segment〕offsetR〔base〕R〔index〕scale,其中D〔〕表示对应段寄存器的数据,R〔〕表示通用寄存器里的数据。我们用M〔addr〕来表示内存地址addr。内存地址操作示例:指令说明movlvar,eax把内存地址M〔var〕处的数据传送到eax寄存器movlcs:var,eax把代码段偏移量为var处的内存数据传送到eax寄存器movlvar,eax把立即数var传送到eax寄存器movlvar(esi),eax把内存地址M〔R〔esi〕var〕处的数据传送到eax寄存器movl(ebx,esi,4),eax把内存地址M〔R〔ebx〕R〔esi〕4〕处的数据传送到eax寄存器movlvar(ebx,esi,4),eax把内存地址M〔varR〔ebx〕R〔esi〕4〕处的数据传送到eax寄存器2。1。2指令后缀
  由于是从16位体系结构扩展成32位的,Intel用术语字(word)表示16位数据类型。因此,称32位为双字(doublewords),称64位数为四字(quadwords)。标准int值存储为双字(32位)。指针存储为8字节的四字。x8664中,数据类型long实现为64位。x8664指令集同样包括完整的针对字节、字和双字的指令。
  下表给出了C语言基本数据类型对应的x8664表示。在64位机器中,指针长8字节。
  C声明
  Intel数据类型
  汇编代码后缀
  大小(字节)
  char
  字节
  b
  1hrshort
  字
  w
  2hrint
  双字
  l
  4hrlong
  四字
  q
  8hrchar
  四字(指针)
  q
  8hrfloat
  单精度
  s
  4hrdouble
  双精度
  l
  8hr浮点数主要有两种形式:单精度(4字节)值,对应于C语言数据类型float;双精度(8字节)值,对应于C语言数据类型double。
  如上表所示,大多数汇编代码指令都有一个字符的后缀,表明操作数的大小。例如:数据传送指令有四个变种:movb(传送字节)、movw(传送字)、movl(传送双字)和movq(传送四字)。注意,虽然汇编代码使用后缀l来表示4字节整数和8字节浮点数,但并不会产生歧义,因为浮点使用的是一组完全不同的指令和寄存器。2。2数据传送指令2。2。1简单传送指令
  最简单形式的数据传送指令是MOV类。这些指令把数据从源位置复制到目的位置,不做任何变化。MOV类由四条指令组成:movb、movw、movl和movq。这些指令都执行同样的操作,主要区别在于他们操作的数据大小不同:分别是1、2、4和8字节。下表列出了MOV类指令:
  指令
  效果
  描述
  MOVS,D
  SD
  传送
  movb
  传送字节
  movw
  传送字
  movl
  传送双字
  movq
  传送四字
  movabsqI,R
  IR
  传送绝对的四字
  源操作数指定的值是一个立即数,存储在寄存器或者内存中。目的操作数指定一个位置,可以是寄存器或内存地址。x8664加了一条限制,传送指令的两个操作数不能都指向内存位置。大多数情况下,MOV指令只会更新目的操作数指定的那些寄存器字节或内存位置。唯一的例外是movl指令以寄存器作为目的时,它会把该寄存器的高位4字节设置为0。
  movabsq指令是处理64位立即数数据的。常规的movq指令只能以表示为32位补码数字的立即数作为源操作数,然后把这个值符号扩展得到64位的值,放到目的位置。movabsq指令能够以任意64位立即数作为源操作数,并且只能以寄存器作为目的。
  代码示例:movl0x4050,eax立即数寄存器,4字节movwbp,sp寄存器寄存器,4字节movb(rbi,rcx),al内存寄存器,1字节movb17,(rsp)立即数内存,1字节movqrax,12(rap)寄存器内存,4字节
  理解数据传送如何改变目的寄存器:1movabsq0x0011223344556677,raxrax0x00112233445566772movb1,alrax0x00112233445566FF3movw1,axrax0x001122334455FFFF4movl1,eaxrax0x00000000FFFFFFFF5movq1,raxrax0xFFFFFFFFFFFFFFFF
  在这个例子中,第一行的指令把寄存器rax初始化为位模式0011223344556677。剩下的指令源操作数是立即数1。因此movb指令把rax的低位字节设置为FF,而movw指令把低2位字节设置为FFFF,剩下的字节保持不变。movl指令将低4个字节设置为FFFFFFFF,同时把高位4字节设置为00000000。最后movq指令把整个寄存器设置为FFFFFFFFFFFFFFFF。2。2。2扩展传送指令
  MOVZ和MOVS是另外两类数据移动指令,在将较小的源值复制到较大的目的时使用。MOVZ类中的指令把目的中剩余的字节填充位0,而MOVS类中的指令通过符号扩展来填充,把源操作数的最高位进行复制。这两类指令分别如下表所示。
  零扩展的传送指令:
  指令
  效果
  描述
  MOVZS,R
  零扩展(S)R
  以零扩展进行传送
  movzbw
  将做了零扩展的字节传送到字
  movzbl
  将做了零扩展的字节传送到双字
  movzbq
  将做了零扩展的字节传送到四字
  movzwl
  将做了零扩展的字传送到双字
  movzwq
  将做了零扩展的字传送到四字
  符号扩展的传送指令:
  指令
  效果
  描述
  MOVSS,R
  符号扩展(S)R
  传送符号扩展的字节
  movsbw
  将做了符号扩展的字节传送到字
  movsbl
  将做了符号扩展的字节传送到双字
  movsbq
  将做了符号扩展的字节传送到四字
  movswl
  将做了符号扩展的字传送到双字
  movswq
  将做了符号扩展的字传送到四字
  位扩展传送指令:
  指令
  效果
  描述
  cbtw
  符号扩展(R〔al〕)R〔ax〕
  把al符号扩展到ax
  cwtl
  符号扩展(R〔ax〕)R〔eax〕
  把ax符号扩展到eax
  cwtd
  符号扩展(R〔ax〕)R〔dx〕:R〔ax〕
  把ax符号扩展到dx:ax
  cltq
  符号扩展(R〔eax〕)R〔rax〕
  把eax符号扩展到rax
  cltd
  符号扩展(R〔eax〕)R〔edx〕:R〔eax〕
  把eax符号扩展到edx:eax
  cqto
  符号扩展(R〔rax〕)R〔rdx〕:R〔rax〕
  把rax符号扩展为八字
  cqtd
  符号扩展(R〔rax〕)R〔rdx〕:R〔rax〕
  把rax符号扩展为八字
  字节传送指令比较:1movabsq0x0011223344556677,raxrax0x00112233445566772movb0xAA,dldl0xAA3movbdl,alrax0x00112233445566AA4movsbqdl,raxrax0xFFFFFFFFFFFFFFAA5movzbqdl,raxrax0x00000000000000AA
  代码的头2行将寄存器rax和dl分别初始化为0x0011223344556677和0xAA。剩下的指令都是将rdx的低位字节复制到rax的低位字节。movb指令不改变其它字节。根据源字节的最高位,movsbq指令将其它7个字节设为全1或全0。由于十六进制A表示的二进制值为1010,符号扩展会把高位字节都设置为FF。movzbq指令总是将其它7个字节全都设置为0。2。2。3压入和弹出栈数据
  栈相关指令如下表所示:
  指令
  效果
  描述
  pushqS
  R〔rsp〕8R〔rsp〕;SM〔R〔rsp〕〕
  将四字压入栈
  popqD
  M〔R〔rsp〕〕D;R〔rsp〕8R〔rsp〕
  将四字弹出栈
  pushq指令的功能是把数据压入到栈上,而popq指令是弹出数据。这些指令都只有一个操作数压入的数据源和弹出的数据目的。
  将一个四字值压入栈中,首先要将栈指针减8,然后将值写到新的栈顶地址。因此,指令pushqrbp的行为等价于下面两条指令:subq8,rspmovqrbp,(rsp)
  弹出一个四字的操作包括从栈顶位置读出数据,然后将栈指针加8。因此,指令popqrax等价于下面两条指令:movq(rsp),raxaddq8,rsp2。2。4加载有效地址
  leaq指令格式如下:
  指令
  效果
  描述
  leaqS,D
  SD
  加载有效地址
  加载有效地址(loadeffectiveaddress)指令leaq实际上是movq指令的变形。它的指令形式是从内存读数据到寄存器,但实际上它根本没有引用内存。它的第一个操作数看上去是一个内存引用,但该指令不是从指定的位置读入数据,而是将有效地址写入到目的操作数。例如,如果寄存器rdx的值为x,那么指令leaq7(rdx,dx,4),rax将寄存器rax的值为5x7。2。3算术和逻辑运算指令2。3。1算术运算指令
  算术运算指令如下:
  指令
  效果
  描述
  inc{bwlq}D
  D1D
  加1
  dec{bwlq}D
  D1D
  减1
  neg{bwlq}D
  DD
  取负
  add{bwlq}S,D
  DSD
  加
  sub{bwlq}S,D
  DSD
  减
  imul{bwlq}S,D
  DSD
  乘2。3。2逻辑运算指令
  逻辑运算指令如下:
  指令
  效果
  描述
  not{bwlq}D
  DD
  逻辑非
  or{bwlq}S,D
  DSD
  逻辑或
  and{bwlq}S,D
  DSD
  逻辑与
  xor{bwlq}S,D
  DSD
  逻辑异或2。3。3移位运算
  指令
  效果
  描述
  sal{bwlq}k,D
  DkD
  左移
  shl{bwlq}k,D
  DkD
  左移(等同于asl)
  sar{bwlq}k,D
  DAkD
  算术右移
  shr{bwlq}k,D
  DLkD
  逻辑右移
  移位操作第一个操作数是移位量,第二个操作数是要移位的数。可以进行算术和逻辑移位。移位量可以是一个8位立即数,或者放在单字节寄存器cl中。(这些指令很特别,因为只允许以这个特定的寄存器作为操作数。)原则上来说,1个字节的移位量使得移位量的编码范围可以达到281255。x8664中,移位操作对w位长的数据值进行操作,移位量是由cl寄存器的低m位决定的,这里2mw,高位会被忽略。所以,例如当寄存器cl的十六进制值为0xFF时,指令salb会移7位,salw会移15位,sall会移31位,而salq会移63位。
  左移指令有两个名字:sal和shl。两者的效果是一样的,都是将右边填上0。右移指令不同,sar执行算术移位(填上符号位),而shr执行逻辑移位(填上0)。移位操作的目的操作数可以是一个寄存器或者是一个内存位置。
  代码示例:salq4,rax把rax里的数据左移4位(乘以16),即raxrax162。3。4特殊的算术操作
  imul指令有两种不同的形式。其中一种,如2。3。1节所示,有两个操作数,这种形式的imul指令是一个双操作数乘法指令。但是,x8664还提供了两条不同的单操作数乘法指令。根据操作数大小,这类指令把源操作数与rax对应大小的寄存器内容相乘,结果放入rax对应的寄存器中。而imulq指令,由于两个64位数相乘,结果可能为128位,所以使用了rdx寄存器来保存运算结果的高64位,rax保存运算结果的低64位。
  另外,x8664提供的除法指令,也是单操作数的。这类操作,根据操作数大小,以rdx对应的寄存器保存余数,rax对应的寄存器保存商。其中ipb和ip是个例外,它们的余数保存在ah寄存器,商保存在al寄存器。
  指令
  效果
  描述
  imulbS
  SR〔al〕R〔ax〕
  8位有符号乘法
  imulwS
  SR〔ax〕R〔eax〕
  16位有符号乘法
  imullS
  SR〔eax〕R〔rax〕
  32位有符号乘法
  imulqS
  SR〔rax〕R〔rdx〕:R〔rax〕
  64位有符号乘法
  mulbS
  SR〔al〕R〔ax〕
  8位无符号乘法
  mulwS
  SR〔ax〕R〔eax〕
  16位无符号乘法
  mullS
  SR〔eax〕R〔rax〕
  32位无符号乘法
  mulqS
  SR〔rax〕R〔rdx〕:R〔rax〕
  64位无符号乘法
  ipbS
  R〔ax〕modSR〔ah〕R〔ax〕SR〔al〕
  8位有符号除法
  ipwS
  R〔dx〕:R〔ax〕modSR〔dx〕R〔dx〕:R〔ax〕SR〔ax〕
  16位有符号除法
  iplS
  R〔edx〕:R〔eax〕modSR〔edx〕R〔edx〕:R〔eax〕SR〔eax〕
  32位有符号除法
  ipqS
  R〔rdx〕:R〔rax〕modSR〔rdx〕R〔rdx〕:R〔rax〕SR〔rax〕
  64位有符号除法
  pbS
  R〔ax〕modSR〔ah〕R〔ax〕SR〔al〕
  8位无符号除法
  pwS
  R〔dx〕:R〔ax〕modSR〔dx〕R〔dx〕:R〔ax〕SR〔ax〕
  16位无符号除法
  plS
  R〔edx〕:R〔eax〕modSR〔edx〕R〔edx〕:R〔eax〕SR〔eax〕
  32位无符号除法
  pqS
  R〔rdx〕:R〔rax〕modSR〔rdx〕R〔rdx〕:R〔rax〕SR〔rax〕
  64位无符号除法2。4控制指令2。4。1条件码
  除了整数寄存器(通用寄存器)外,CPU还维护者一组单个位的条件码寄存器(EFLAGS),它们描述了最近的算术或逻辑运算操作的属性。条件码的详细描述详见1。2节,这里我们列出最常用的条件码:CF:进位标志。最近的操作使最高位产生了进位或借位,用来检查无符号操作的溢出。ZF:零标志。最近的操作得出的结果是0。SF:符号标志。最近的操作的得到的结果是否为负数。OF:溢出标志。最近的操作导致一个补码溢出,用来检查有符号溢出。
  比如说,假设我们用一条ADD指令完成等价于C表达式tab的功能,这里变量a、b和t都是整型的。然后,根据下面的C表达式来设置条件码:CF(unsigned)t(unsigned)a无符号溢出ZF(t0)零SF(t0)负数OF(a0b0)(t0!a0)有符号溢出
  2。3节列出的所有指令都会设置条件码。对应逻辑操作,如XOR,进位标志和溢出标志会设置成0。对于移位操作,进位标志将设置为最后一个被移出的位,而溢出标志设置为0。INC和DEC指令会设置溢出和零标志,但是不会改变进位标志。
  条件码通常不会直接读取,常用的使用方法有三种:可以根据条件码的某种组合,将一个字节设置为0或者1;可以条件跳转到程序的某个地方可以有条件的传送数据2。4。2CMP和TEST指令
  除了2。3节列出的指令会设置条件码,还有两类指令(CMP和TEST),它们只设置条件码而不改变任何其他寄存器。CMP指令根据两个操作数之差来设置条件码。除了只设置条件码而不更新目的寄存器之外,CMP指令与SUB指令的行为是一样的。如果两个操作数相等,这些指令会将零标志设置为1,而其他标志可以用来确定两个操作数之间的大小关系。TEST指令的行为与AND指令一样,除了它们只设置条件码而不改变目的寄存器。
  指令
  基于
  描述
  CMPS1,S2
  S2S1
  比较
  cmpb
  比较字节
  cmpw
  比较字
  cmpl
  比较双字
  cmpq
  比较四字
  TESTS1,S2
  S1S2
  测试
  testb
  测试字节
  testw
  测试字
  testl
  测试双字
  testq
  测试四字2。4。3SET指令
  SET指令根据条件码的某种组合,将一个字节设置为0或者1。SET指令是一组指令,指令的后缀表明了他们所考虑的条件码组合。例如:指令setl和setb表示小于时设置(setless)和低于时设置(setblow)。SET指令的目的操作数是低位单字节寄存器或是一个字节的内存地址,指令会将这个字节设置成0或者1。
  SET指令列表如下:
  指令
  同义指令
  设置条件
  条件说明
  seteD
  setz
  ZF
  相等零(setequal)
  setneD
  setnz
  ZF
  不等非零(setnotequal)
  setsD
  SF
  负数
  setnsD
  SF
  非负数
  setgD
  setnle
  (SFOF)ZF
  大于(有符号)
  setgeD
  setnl
  (SFOF)
  大于等于(有符号)
  setlD
  setnge
  SFOF
  小于(有符号小于)
  setleD
  setng
  (SFOF)ZF
  小于等于(有符号)
  setaD
  setnbe
  CFZF
  超过(无符号)
  setaeD
  setnb
  CF
  超过或相等(无符号)
  setbD
  setnae
  CF
  低于(无符号)
  setbeD
  setna
  CFZF
  低于或相等(无符号)
  2。4。4跳转指令
  跳转指令分为无条件跳转和有条件跳转。2。4。4。1无条件跳转
  无条件跳转指令jmp,可以是直接跳转,即跳转目标是作为指令一部分编码的;也可以是间接跳转,即跳转目标是从寄存器或内存位置中读取的。汇编语言中,直接跳转是给出一个标号作为跳转目标的。间接跳转的写法是后面跟一个操作数指示符。直接跳转和间接跳转示例如下:直接跳转示例movq0,raxjmp。L1直接跳转movq(rax),rdx。L1:popqrdx间接跳转示例jmprax用寄存器rax中的值作为跳转目的jmp(rax)以rax中的值作为读取地址,从内存中读出跳转目标2。4。4。2有条件跳转
  下表中所示的跳转指令都是有条件的,它们根据条件码的某种组合,要么跳转,要么不跳转继续执行一条指令。条件跳转只能是直接跳转。
  指令
  同义指令
  跳转条件
  描述
  jeLabel
  jz
  ZF
  相等零
  jneLable
  jnz
  ZF
  不相等非零
  jsLabel
  SF
  负数
  jnsLabel
  SF
  非负数
  jgLabel
  jnle
  (SFOF)ZF
  大于(有符号)
  jgeLabel
  jnl
  (SFOF)
  大于等于(有符号)
  jlLabel
  jnge
  SFOF
  小于(有符号小于)
  jleLabel
  jng
  (SFOF)ZF
  小于等于(有符号)
  jaLabel
  jnbe
  CFZF
  超过(无符号)
  jaeLabel
  jnb
  CF
  超过或相等(无符号)
  jbLabel
  jnae
  CF
  低于(无符号)
  jbeLabel
  jna
  CFZF
  低于或相等(无符号)2。4。5条件传送指令
  指令
  同义指令
  传送条件
  说明
  cmove
  cmovz
  ZF
  相等零
  cmovne
  cmovnz
  ZF
  不相等非零
  cmovs
  SF
  负数
  cmovns
  SF
  非负数
  cmovo
  OF
  有溢出
  cmovno
  OF
  无溢出
  cmovc
  CF
  有进位
  cmovnc
  CF
  无进位
  cmovp
  cmovpe
  PF
  PF1
  cmovnp
  cmovpo
  PF
  PF!1
  cmovg
  cmovnle
  (SFOF)ZF
  大于(有符号)
  cmove
  cmovnl
  (SFOF)
  大于等于(有符号)
  cmovl
  cmovnge
  SFOF
  小于(有符号小于)
  cmovle
  cmovng
  (SFOF)ZF
  小于等于(有符号)
  cmova
  cmovnbe
  CFZF
  超过(无符号)
  cmovae
  cmovnb
  CF
  超过或相等(无符号)
  cmovb
  cmovnae
  CF
  低于(无符号)
  cmovbe
  cmovna
  CFZF
  低于或相等(无符号)2。5过程调用
  x8664的过程实现包括一组特殊的指令和一些对机器资源(例如寄存器和程序内存)使用规则的约定。2。5。1运行时栈
  x8664的栈向低地址方向增长,而栈指针rsp指向栈顶元素。可以用push和pop相关指令将数据存入栈中或是从栈中取出数据。将栈指针减小一个适当的量可以为数据在栈上分配空间;类似的,可以通过增加栈指针来释放空间。
  当过程P调用过程Q时,其栈内结构如下图所示:
  当前正在执行的过程的栈帧总是在栈顶。当过程P调用过程Q时,会把返回地址压入栈中,指明当Q返回时,要从P程序的哪个位置继续执行。Q的代码会扩展到当前栈的边界,分配它所需要的栈帧空间。在这个空间中,它可以保存寄存器的值,分配局部变量空间,为它调用的过程设置参数。通过寄存器,过程P可以传递最多6个整数值(包括指针和整数),如果Q需要更过参数时,P可以在调用Q之前在自己的栈帧里存储好这些参数。2。5。2过程调用惯例2。5。2。1参数传递
  x8664中,最多允许6个参数通过寄存器来传递,多出的参数需要通过栈来传递,正如2。5。1节描述的那样;传递参数时,参数的顺序与寄存器的关系对应如下:
  操作数大小(位)
  参数1
  参数2
  参数3
  参数4
  参数5
  参数6
  64hrrdi
  rsi
  rdx
  rcx
  r8
  r9
  32hredi
  esi
  edx
  ecx
  r8d
  r9d
  16hrdi
  si
  dx
  cx
  r8w
  r9w
  8hrdil
  sil
  dl
  cl
  r8b
  r9b
  如果一个函数Q有n(n6)个整数参数,如果过程P调用过程Q,需要把参数16复制到对应的寄存器,把参数7n放到栈上,而参数7位于栈顶。通过栈传递参数时,所有的数据大小都向8的倍数对齐。参数到位以后,程序就可以指向call指令将控制转移到Q了。2。5。2。2返回值
  被调用函数返回时,把返回结果放入rax中,供调用函数来获取。2。5。2。3寄存器的其它约定
  根据惯例,寄存器的rbx、rbp和r12r15被划分位被调用者保存寄存器。当过程P调用过程Q时,Q必须保证这些寄存器的值在被调用前和返回时是一致的。也就是说,Q要么不去使用它,要么先把寄存器原始值压入栈,在使用完成后,返回到P之前再把这些寄存器的值从栈中恢复。
  所有其它寄存器,除了栈指针rsp,都分类为调用者保存寄存器。这就意味着任何函数都能修改它们。可以这样来理解调用者保存这个名字:过程P在某个此类寄存器中存有数据,然后调用过程Q。因为Q可以随意修改这个寄存器,所以在调用之前首先保存好这个数据时P(调用者)的责任。2。5。3控制转移
  过程调用时,通过一下指令来进行调用及返回:
  指令
  描述
  callLabel
  过程调用
  callOperand
  过程调用
  ret
  从过程调用返回
  call指令有一个目标,即指明被调用过程起始的指令地址。同跳转指令一样,调用可以是直接的,也可以是间接的。
  当call指令执行时,调用者P已经按2。5。2的约定,把被调用者Q所需要的参数准备好了。该指令执行时,会把返回地址A压入栈中,并将PC(rip)设置为Q的起始地址。对应的,ret指令会从栈中弹出返回地址A,并把PC(rip)设置为A,程序从A处继续执行。2。6字符串指令
  字符串指令用于对字符串进行操作,这些操作包括在把字符串存入内存、从内存中加载字符串、比较字符串以及扫描字符串以查找子字符串。2。6。1movs、cmps类指令
  movs指令用于把字符串从内存中的一个位置拷贝到另一个位置。cmps指令用于字符串比较。
  在老的运行模式中,这些指令把字符串从ds:(e)si表示的内存地址拷贝到es:(e)di表示的内存地址。在64位模式中,这些指令把字符串从(re)si表示的内存地址处拷贝到(re)di表示的内存地址处。
  当操作完成后,(re)si和(re)di寄存器的值会根据DF标志位的值自动增加或减少。当DF位为0时,(re)si和(re)di寄存器的值会增加,当DF为1时,寄存器的值会减少。根据移动的字符串是字节、字、双字、四字,寄存器会分别减少或增加1、2、4、8。
  movs类指令:
  指令
  描述
  movsb
  movebytestring
  movsw
  movewordstring
  movsl
  movedoublewordstring
  movsq
  moveqwordstring
  cmps类指令:
  指令
  描述
  cmpsb
  comparebytestring
  cmpsw
  comparewordstring
  cmpsl
  comparedoublewordstring
  cmpsq
  compareqwordstring2。6。2lods指令
  lods指令把源操作数加载到al,ax,eax或rax寄存器,源操作数是一个内存地址。在老的模式下,这个地址会从ds:esi或者ds:si读取(根据操作数地址属性是32还是16来决定使用不同的寄存器);在64位模式下内存地址从寄存器(r)si处读取。
  在数据加载完成后,(re)si寄存器会根据DF标志位自动增加或减少(如果DF为0,(re)si寄存器会增加;如果DF为1,(re)si寄存器会减少)。根据移动的字符串是字节、字、双字、四字,寄存器会分别减少或增加1、2、4、8。
  指令
  描述
  说明
  lodsb
  loadbytestring
  Forlegacymode,LoadbyteataddressDS:(E)SIintoAL。For64bitmodeloadbyteataddress(R)SIintoAL。
  lodsw
  loadwordstring
  Forlegacymode,LoadwordataddressDS:(E)SIintoAX。For64bitmodeloadwordataddress(R)SIintoAX。
  lodsl
  loaddoublewordstring
  Forlegacymode,LoaddwordataddressDS:(E)SIintoEAX。For64bitmodeloaddwordataddress(R)SIintoEAX。
  lodsq
  loadqwordstring
  Loadqwordataddress(R)SIintoRAX。2。6。3stos指令
  stos指令把al,ax,eax或rax寄存器里的字节、字、双字、四字数据,保存到目的操作数,目的操作数是一个内存地址。在老的模式下,这个地址会从ds:esi或者ds:si读取(根据操作数地址属性是32还是16来决定使用不同的寄存器);在64位模式下内存地址从寄存器rdi或edi处读取。
  在数据加载完成后,(re)di寄存器会根据DF标志位自动增加或减少(如果DF为0,寄存器会增加;如果DF为1,寄存器会减少)。根据移动的字符串是字节、字、双字、四字,寄存器会分别减少或增加1、2、4、8。
  指令
  描述
  说明
  stosb
  storebytestring
  Forlegacymode,storeALataddressES:(E)DI;For64bitmodestoreALataddressRDIorEDI。
  stosw
  storewordstring
  Forlegacymode,storeAXataddressES:(E)DI;For64bitmodestoreAXataddressRDIorEDI。
  stosl
  storedowblewordstring
  Forlegacymode,storeEAXataddressES:(E)DI;For64bitmodestoreEAXataddressRDIorEDI。
  stosq
  storeqwordstring
  StoreRAXataddressRDIorEDI。2。6。4REP相关指令
  上面几节提到的字符串相关指令,都是单次执行的指令。可以在这些指令前面添加rep类前缀,让指令重复执行。重复执行的次数通过计数寄存器(re)cx来指定,或者根据ZF标志位是否满足条件进行判断。
  rep类前缀包括:rep(repeat),repe(repeatwhileqeual),repne(repeatwhilenotqeual),repz(repeatwhilezero)和repnz(repeatwhilenotzero)。rep前缀可以放置在ins,outs,movs,lods和stos指令前面;而repe、repne、repz和repnz前缀可以放置在cmps和scas指令前面。
  repe、repne、repz和repnz前缀指令在每一次迭代执行后,会检查ZF标志是否满足中止条件,如果满足则中止循环。
  中止条件:
  前缀格式
  中止条件1
  中止条件2
  rep
  rcx或(e)cx0
  无
  reperepz
  rcx或(e)cx0
  ZF0
  repnerepnz
  rcx或(e)cx0
  ZF1三、汇编器指令
  这部分指令是跟x86指令集无关的指令,这些指令以。开头。3。1段相关指令
  指令
  描述
  。text
  代码段
  。rodata
  只读数据段
  。data
  数据段
  。bss
  未初始化数据段。bss段用于本地通用变量存储。您可以在bss段分配地址空间,但在程序执行之前,您不能指定要加载到其中的数据。当程序开始运行时,bss段的所有内容都被初始化为零。3。2数据相关指令
  数据相关指令在。bss段无效。
  指令
  描述
  。ascii
  文本字符串,末尾不会自动添加‘‘’字符
  。asciz
  除了会在字符串末尾自动添加‘’字符外,同。ascii
  。byte
  8位整数
  。short
  16位整数
  。int
  32位整数
  。long
  32位整数(sameas。int)
  。quad
  8字节整数
  。octa
  16字节整数
  。single
  单精度浮点数
  。float
  单精度浮点数
  double
  双精度浮点数
  代码示例:。byte74,0112,092,0x4A,0X4a,J,JAllthesamevalue。。asciiRingthebell7Astringconstant。。octa0x123456789abcdef0123456789ABCDEF0Abignum。。float0f31415926535897932384626433832795028841971。693993751E40pi,aflonum。四、参考资料
  1、《深入理解计算机系统》(第三版)
  2、《操作系统真象还原》
  3、《一个64位操作系统的设计与实现》
  5、《x86汇编语言:从实模式到保护模式》
  4、gnuas文档:https:sourceware。orgbinutilsdocsasindex。htmlSECContents
  5、Intel64和IA32架构软件开发者手册:https:www。intel。comcontentwwwusendeveloperarticlestechnicalintelsdm。html
  6、x86AssemblyLanguageReferenceManual(ATTsyntax):https:docs。oracle。comcdE192530181754778175477。pdf

尽管2019年就离开了苹果,但乔纳森艾维仍参与了M1iMacIT之家5月30日消息苹果公司的前首席设计官(CDO)乔纳森艾维(JonyIve)于2019年从该公司离职,他留下了许多令人印象深刻的作品,比如iPhone、iPad、iPod……苹果必然进军汽车行业,你希望它做软件还是造整车从本质上说,汽车正演变为带轮子的智能手机,因此苹果进军汽车领域就不足为奇了!苹果正试图终结主要使用机械系统的传统汽车,并掀起规模达上万亿美元的自动驾驶汽车革命。自从汽车诞……苹果播客Podcasts付费订阅功能推迟到6月发布IT之家5月29日消息苹果Podcasts播客应用即将推出付费订阅功能Subscriptionsandchannels,可以使得创作者拥有专属频道,获得更多收入。据外媒macr……车用芯片IDM大厂扩产对汽车供应链影响分析车用IDM大厂纷纷扩产当前,芯片产业正经历下行周期,大厂们仍在积极扩产。近日,英飞凌、瑞萨、德州仪器、Rapidus四家IDM厂纷纷披露最新的建厂计划。据台湾经济日报报道……消息称欧盟本周将以AppStore垄断行为起诉苹果公司北京时间4月27日下午消息,据报道,多位知情人士今日称,欧盟反垄断专员玛格丽特维斯塔格(MargretheVestager)本周晚些时候将对苹果公司提出反垄断指控,认为苹果Ap……标识牌在制作时,要注意妥善运用这三种颜色外出旅游我们到处都会看到标识牌,不管是海边、公园、景区、寺庙,还是其他地方都能够看到标识牌的身影。标识牌不仅提供了景点的信息,还可以提供当前的地理位置清楚地告诉下一个游玩的项目……苹果在WWDC21大会前更新开发者论坛新增跟踪动态搜索内容发IT之家5月28日消息据外媒MacRumors报道,苹果此前宣布将于6月7日(北京时间6月8日凌晨)至11日以在线形式举办WWDC21全球开发者大会,近日,苹果更新了其开发者论……苹果iCloud(贵安)数据中心建成并正式投入运行IT之家5月27日消息据贵州日报天眼新闻报道,5月25日,由云上贵州与苹果公司联合建设的iCloud(贵安)数据中心对外宣布建成并正式投入运行。iCloud(贵安)数据中……理性分析天津重返全国前十的可能性有多大?曾经的天津有多辉煌,我想都不用多说,上青天时代下,就如同现在的北上广。即使在十几年前,天津也是接近广深的存在。转折点在滨海新区的发展受到了挤水。大家清楚的是,滨海新区是全国第一……你在他乡还好吗?晚上十点的时候,你放下了这一天的疲惫了吗?每当夜幕降临的时候,一座城市的节奏就开始变得缓慢。时间变得慢,心情变得慢,回忆也变得慢。那些想收藏一辈子的幸福,那些……娱乐圈这4对好闺蜜,相识超过十年,每一对都是神仙友谊在纷繁复杂的娱乐圈,人与人之间的关系变得微妙且复杂。当金钱名利被搬上桌面时,更加考验人性。在这个圈子,光环加身的人,总是被无数人围绕,似乎人人都是真心。但是,当光环消失了……苹果悄悄向M1Macmini添加万兆有线网升级选项,只需75IT之家4月21日消息苹果今天发布了一系列新品,包括采用M1芯片的iMac,但在发布会结束之后,有网友发现另一台Mac悄悄进行了升级。苹果已经在旧版M1Macmini中添……
沿途风光记录今天一大早,收拾好后,往窗外一看,一辆电动四轮车,停在车库门口。一看七点二十了,赶紧下楼找车主挪车。下了楼,问了一个临边单元的,说不知道,可能外来的。这可咋整啊!赶紧自己挪挪试……为何拼多多买东西比较便宜?从业人员说出实情,你还会再买吗?估计连马云都想不到,拼多多会发展地如此之快,仅仅几年的时间,就成长为和某宝、某东三雄并立的地步了。拼多多公布的2022年第一季度财报显示,整个第一季度,拼多多的平均月活跃……0分,0分,0分,0分!NBA历史第一人,哈登果然没有看错你看NBA比赛的球迷,当看到一名球员0分的时候,往往会嗤之以鼻,有的球迷甚至会破口大骂他没用,废物,垃圾。但其实,NBA历史也有一位著名的球星,他就非常不喜欢得分,经常得分为0分……CMALL商城Java安装与性能分析CMALL商城目录卸载rpmqagrepjdkrpmqagrepjdkxargsrpmenodeps安装usrjavajdk1。8。0191jdk8u191linu……一款休闲类冒剧情策略游戏HELLO大家好,这里是小白的每日一游推荐时间。世上的游戏千千万,有许多好玩的游戏由于缺乏宣传,所以不被广大玩家所熟知。在这里小白每天会为大家推荐一款评价很高但是不太出名的游戏……未来若人工智能觉醒,必为图灵作本纪!人工智能之父艾伦麦席森图灵近来大洋彼岸ChatGPT热议话题不断,世人惊呼人工智能进步神速。假如某一天,计算机人工智能意识觉醒自称灵机,且具备复制繁衍行为,凡是人工智能觉……你过的越好,朋友圈点赞的越少你过的越好,朋友圈点赞的越少如果你还在为过年发了高质量生活的朋友圈,只有零星同事、朋友点赞而神伤,那大可不必,你注意观察,越是平日平平无奇的人,无论发什么,都会获得大批的……8位定居内地的港台明星,有人购置上亿豪宅,有人只能租房住曾经都是爆红的港台明星,但如今却因为人气的不同,境遇也天差地别。有人可以在北京上海购置上亿豪宅,有人却只能跑到靠近香港的内地二线城市买房,甚至有人只能租房住。同样都……比亚迪海豹上市,来盘点这辆豹款的黑科技车友们期待已久的新能源轿跑比亚迪海豹终于在5月20日公布了售价,开始上市预售,四款车型分别为:550km标准续航后驱版精英型(21。28万元)550km标准续航后驱……湖人将用困难特例签下小托马斯据TheAthletic记者ShamsCharania报道,因为队中多名球员触发健康安全协议,湖人计划用10天短合同签下小托马斯,以解燃眉之急。湖人目前有15份保障合同,……每日优鲜遇发展危机,先烧钱再赚钱已不可持续新京报快评每日优鲜便利购服务。图每日优鲜官网最近有市场传闻称,每日优鲜由于融资未交割成功,无力解决员工薪资欠发、供应商欠款等问题,公司解散。对于这一消息,每日优鲜对媒体回应称……早餐中的4种致癌物,医生提醒,想要身体健康务必要管住嘴早餐中的4种致癌物,医生提醒,想要身体健康务必要管住嘴,不要不听劝早餐非常重要,正所谓一日之计在于晨,只有早餐吃好,才能更好地享受一天的工作生活。现在工作节奏越来越快,很……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网