X86汇编语言学习
80X86汇编语言电子教案(3-2-MOV指令)

提供的基本寻址方式可以分为三类立即寻址寄存器寻址存储器寻址与存储器有关的寻址的有效地址由以下四种成分组成1位移量存放在指令中的一个81632位的数2基址存放在基址寄存器中的内容3变址存放在变址寄存器中的内容4比例因子386及后继机型增加的一个术语1无比例因子8086286386及后继机型共有位移量直接寻址基址或变址位移量基址或变址—基址变址寻址2带比例因子386及后继机型位移量变址比例因子比例变址寻址比例因子基址+比例因子说明这些寻址方式不仅可以用于源操作数的寻址也可以用于目的操作数的寻址唯一例外的是立即寻址只能用于源操作数例MOV [BX][DI]AX 则源操作数为寄存器寻址目的操作数为基址变址寻址存储器寻址时所确定的内存地址既可以是字节字也可以是双字地址那么上述指令的目的操作数的宽度是多少呢指令中操作数要具有明确的类型寄存器寻址类型确定存储器操作数寻址类型由变量的类型属性确定其它情况类型下操作数类型由指令中其它操作数的类型或指令缺省类型来确定确定的操作数为字类型指令指示对一定操作对象进行何种操作的命令指令系统计算机CPU的指令集合称为指令系统一指令集说明学习要求指令的基本功能二数据传送指令1通用数据传送指令2累加器专用传送指令3地址传送指令4标志寄存器传送指令5类型转换指令特点负责把数据地址或立即数传送到寄存器或存储单元中1通用数据传送指令1传送指令传送指令执行操作DSTSRC DST SRC 的类型要一致双字字节MOV AXMOV AH MOV AX MOV BXMOV MAST[BP][DI]MOV BL MOV BYTE PTR [BX]MOV DSMOV ES MOV AXMOV [BX]MOV DS例MOV EAX MOV ES 哪些指令为非法形式例MOV AXMOV AHMOV AXMOV BXMOV MAST[BP][DI]MOV BLMOV BYTE PTR [BX]MOV DSMOV ESMOV AXMOV [BX]MOV DS寄存器寄存器字寄存器寄存器字节存储器寄存器字存储器寄存器寄存器存储器字节立即数寄存器立即数存储器字节寄存器段寄存器存储器段寄存器段寄存器寄存器存储器存储器段寄存器段寄存器MOV ES立即数段寄存器MOV EAX存储器寄存器双字MOV CS AXMOV 5ALMOV EAX BX都是非法指令如为了使指令字不要过长规定双操作数指令的两个操作数中只能有一个使用存储器寻址方式因此不允许双存储器操作在有通用性MOV [BX]2带符号扩展传送指令有符号数的扩展MOVSX386及后继机型可用格式MOVSX DST, SRC执行操作本指令有两种格式REG1REG源操作数可以是或存储单元的内容目的操作数必须是功能传送时将源操作数符号扩展送入目的寄存器可以是位MOVSX3带零扩展传送指令无符号数的扩展MOVZX386及后继机型可用格式MOVZX DST, SRC执行操作本指令有两种格式REG1REG源操作数目的操作数MOVSX功能传送时将高位扩展为送入目的寄存器可以是位MOVSX例1MOVSX EAX 2MOVZX EAX 若执行前DATA =0FFE0H DATA 为字单元1EAX =0FFFFFFE0H 2EAX=0000FFE0H一般的双操作数指令源目的操作数的长度一致MOVZX MOVSX 指令的源操作数的长度一定要小于目的操作数的长度如MOVSX DXALMOVZX EBXAL 4堆栈操作指令堆栈PC 机的堆栈是在内存中开辟的一端固定一端活动的存储区采用的工作方式栈顶SP 或ESP 址由低注意 1.信息的存入和取出都是从栈顶开始中栈顶由指示当堆栈地址长度为位时堆栈操作使用SP 当堆栈地址长度为位时堆栈操作使用ESP为了将清楚堆栈操作指令我们分8086/8088803868086/8088 PUSH/POP进栈指令执行操作出栈指令执行操作例SP→SP→例SP→SP→ES)=2367H, (SP)=0100H,试画出堆栈的变化情况(SP)=100H12H12H例都是非法指令80386SP SP 2 ESP ESP 2 SP SP 4 ESP ESP 4 1616位位在实方式下803868086为编写80386及后继的程序可利用位通用寄存器可使用新增指令可采用新增的寻址方式但是段的最大长64KB 当存储单元的地址偏移超过64KB 时不会引起地址的反绕而导致段跨越异常在实方式下80386的兼容最大段为64称为位段在保护方式下段长可达4G 称为位段在实方式下运行的程序只能使用位段尽管在实方式下只能使用位段但可以使用位操作数也可以使用位形式表示的存储单元地址例MOV EAX关于实方式程序的几点说明为单位指令可以有四种格式不允许它使用立即数寻址方式指令允许三种格式能为字节类型5PUSHA/PU格式PUSHA286及后继PUSHAD386及后继执行操作PUSHA位通用寄存器依次入栈入栈次序为AX CX DX BX指令执行前的SP BP SI DISP SP-16PUSHAD位通用寄存器依次入栈入栈次序为EAX ECX EDX EBX指令执行前的ESP EBP ESI EDIESP ESP-326POPA/POP格式执行操作POPA位通用寄存器依次出栈出栈次序为DI SI BP SP BX DX CX AXSP SP+16POPAD位通用寄存器依次出栈出栈次序为EDI E SI EBP ESP EBX EDX ECX EAXESP ESP+32PUSHA POPA PUSHAD不影响标志位例例7交换交换指令执行操作OPR1OPR1OPR1例如XCHG EAX,EBX ; EAX 字AL 为要查找数据在表格2累加器专用传送指令EAX AX 传送信息IN OUT 输出程序设计中讲解换码指令格式执行操作累加器EAX AX AL例MOV BX, OFFSET TABLE ; (BX)=0040H长度不超过256)或EBX下标→(AL)3地址传送指令1LEA REG, SRC ;2LDS REG, SRC ;3LES REG, SRC ;4LFS REG, SRC ;5LGS REG, SRC ;6LSS REG, SRC ;把首地址偏移地址传送指令执行操作位有效地址位有效地址位有效地址截取低位有效地址零扩展后存入则MOV BX LEA BXBX =3412H BX=0100HBLOCK的区别假设0100H BLOCK =3412H 例值而不是该地址所在的存储单元的内容必须注意取地址到和寄存器指令执行操作或SREG ←位寄存器REG 不能是段R R LFS 段址偏移地址偏移地址段址例LDS SI, [10H]例LES DI, [BX]例TABLE DW 40H, 3000H , 2000HLSS ESP TABLE ;ESP=30000040H; (SS) =2000H4标志寄存器传送指令执行操作送标志寄存器指令执行操作(FLAGS标志进栈指令执行操作PUSHF: (SP)标志出栈指令执行操作LAHFSAHF例PUSHF TF=1TF15类型转换CBW AL的符号扩展到AH形成中的字CWD/CWDECWD AX的符号扩展到DX形成DX AX双字CWDE AX的符号扩展到EAX形成EAX双字CDQ EAX的符号扩展到EDX形成EDX EAXBSWAP 486及后继机型可用格式BSWAP R32 R32位寄存器操作将位寄存器的字节次序变反即14字节互换23字节互换指令合法的指令格式堆栈操作指令的指令与指令的区别掌握XCHG XLAT MOVSX MOVZX类型转换其余堆栈操作指令标志操作指令MOVSX作业。
汇编语言基于x86处理器

汇编语言基于x86处理器汇编语言是一种低级编程语言,它直接操作计算机硬件进行指令级编程。
在x86架构下,汇编语言主要用于编写操作系统、驱动程序以及底层的系统软件。
以下是一些关于x86汇编语言的参考内容:1. x86处理器的架构和特点:x86处理器系列有很多型号和版本,比如Intel的Pentium和Core系列、AMD的Athlon和Ryzen系列等。
了解每种型号处理器的架构和特点对于编写高效的汇编程序非常重要。
2. 汇编语言的基本语法:汇编语言是一种低级语言,它使用汇编指令来直接操作计算机硬件。
了解汇编语言的基本语法,包括寄存器、指令和操作码等内容,是编写汇编程序的基础。
3. 寄存器和内存:在x86汇编语言中,寄存器是非常重要的概念。
了解常用的寄存器,如通用寄存器、段寄存器以及标志寄存器,以及寄存器的使用方法和操作规则,在编写汇编程序时能够更加灵活地使用寄存器。
4. 指令集和操作码:x86处理器支持的指令集非常丰富,包括算术和逻辑指令、数据传输指令、控制指令等。
了解常用的指令集和操作码,以及它们的使用方法和功能,是编写汇编程序的基础。
5. 汇编程序的编写和调试:了解如何编写和调试汇编程序,包括使用汇编器将汇编代码转换为机器码、使用调试器进行程序的调试和内存的查看等。
学习汇编程序的编写和调试技巧,能够更加高效地完成汇编程序的开发和调试任务。
6. 汇编程序的优化:汇编语言可以直接操作硬件,因此在一些对性能要求较高的场景,使用汇编语言编写程序可以实现更高效的代码。
了解汇编程序的编译器优化和硬件优化方法,可以提高汇编程序的执行效率。
7. 汇编语言应用案例:了解汇编语言在实际项目中的应用案例,包括操作系统、驱动程序、嵌入式系统等。
通过学习实际应用案例,能够更好地理解汇编语言在底层系统软件开发中的重要性。
总之,汇编语言是一种低级编程语言,基于x86处理器的汇编语言编程需要了解x86处理器的架构和特点,掌握汇编语言的基本语法、指令集和操作码,熟悉寄存器和内存的使用方法,以及编写和调试汇编程序的技巧。
简明x86汇编语言教程

第一章汇编语言简介先说一点和实际编程关系不太大的东西。
当然,如果你迫切的想看到更实质的内容,完全可以先跳过这一章。
那么,我想可能有一个问题对于初学汇编的人来说非常重要,那就是:汇编语言到底是什么?汇编语言是一种最接近计算机核心的编码语言。
不同于任何高级语言,汇编语言几乎可以完全和机器语言一一对应。
不错,我们可以用机器语言写程序,但现在除了没有汇编程序的那些电脑之外,直接用机器语言写超过1000条以上指令的人大概只能算作那些被我们成为“圣人”的牺牲者一类了。
毕竟,记忆一些短小的助记符、由机器去考虑那些琐碎的配位过程和检查错误,比记忆大量的随计算机而改变的十六进制代码、可能弄错而没有任何提示要强的多。
熟练的汇编语言编码员甚至可以直接从十六进制代码中读出汇编语言的大致意思。
当然,我们有更好的工具——汇编器和反汇编器。
简单地说,汇编语言就是机器语言的一种可以被人读懂的形式,只不过它更容易记忆。
至于宏汇编,则是包含了宏支持的汇编语言,这可以让你编程的时候更专注于程序本身,而不是忙于计算和重写代码。
汇编语言除了机器语言之外最接近计算机硬件的编程语言。
由于它如此的接近计算机硬件,因此,它可以最大限度地发挥计算机硬件的性能。
用汇编语言编写的程序的速度通常要比高级语言和C/C++快很多--几倍,几十倍,甚至成百上千倍。
当然,解释语言,如解释型LISP,没有采用JIT技术的Java虚机中运行的Java 等等,其程序速度更无法与汇编语言程序同日而语。
永远不要忽视汇编语言的高速。
实际的应用系统中,我们往往会用汇编彻底重写某些经常调用的部分以期获得更高的性能。
应用汇编也许不能提高你的程序的稳定性,但至少,如果你非常小心的话,它也不会降低稳定性;与此同时,它可以大大地提高程序的运行速度。
我强烈建议所有的软件产品在最后Release之前对整个代码进行Profile,并适当地用汇编取代部分高级语言代码。
至少,汇编语言的知识可以告诉你一些有用的东西,比如,你有多少个寄存器可以用。
80X86汇编语言程序设计教程+课后习题答案(清华大学版)

第二章答案Tarzan 版题2.1 8086/8088通用寄存器的通用性表现在何处?8个通用寄存器各自有何专门用途?哪些寄存器可作为存储器寻址方式的指针寄存器?答:8086/8088通用寄存器的通用性表现在:这些寄存器除了各自规定的专门用途外,他们均可以用于传送和暂存数据,可以保存算术逻辑运算中的操作数和运算结果;8个通用寄存器的专门用途如下:AX 字乘法,字除法,字I/OBX 存储器指针CX 串操作或循环控制中的计数器DX 字乘法,字除法,间接I/OSI 存储器指针(串操作中的源指针)DI 存储器指针(串操作中的目的指针)BP 存储器指针(存取堆栈的指针)SP 堆栈指针其中BX,SI,DI,BP可作为存储器寻址方式的指针寄存器题2.2 从程序员的角度看,8086/8088有多少个可访问的16位寄存器?有多少个可访问的8位寄存器?答:从程序员的角度看,8086/8088有14个可访问的16位寄存器;有8个可访问的8位寄存器;题2.3 寄存器AX与寄存器AH和AL的关系如何?请写出如下程序片段中每条指令执行后寄存器AX的内容:MOV AX,1234HMOV AL,98HMOV AH,76HADD AL,81HSUB AL,35HADD AL,AHADC AH,ALADD AX,0D2HSUB AX,0FFH答: MOV AX,1234H AX=1234HMOV AL,98H AX=1298HMOV AH,76H AX=7698HADD AL,81H AX=7619HSUB AL,35H AX=76E4HADD AL,AH AX=765AHADC AH,AL AX=D15AHADD AX,0D2H AX=D22CHSUB AX,0FFH AX=D12DH题2.4 8086/8088标志寄存器中定义了哪些标志?这些标志可分为哪两类?如何改变这些标志的状态?答: 8086/8088标志寄存器中定义了9个标志,如下:CF: Carry FlagZF: Zero FlagSF: Sign FlagOF: Overflow FlagPF: Parity FlagAF: Auxiliary Carry FlagDF: Direction FlagIF: Interrupt-enable FlagTF: Trap Flag这些标志可分为两类,分别为:1、运算结果标志;2、状态控制标志;采用指令SAHF可把AH中的指定位送至标志寄存器低8位SF、ZF、AF、PF、CF;采用CLC可清除CF,置CF到0采用STC可置CF到1采用CLD可置DF到0采用sTD可置DF到1采用CLI可置IF到0采用STI可置IF到1另外,在某些指令执行过程中会改变部分标志的状态;题2.5 请说说标志CF和标志OF的差异。
汇编语言的学习步骤

汇编语言的学习步骤汇编语言作为低级语言的一种,是计算机硬件与高级编程语言之间的桥梁。
学习汇编语言可以帮助我们更深入地理解计算机底层的工作原理,提升编程的效率与质量。
下面是学习汇编语言的步骤,希望对你有所帮助。
Step 1:了解计算机体系结构在学习汇编语言之前,了解计算机的体系结构是非常重要的。
学习者需要了解计算机的组成部分,包括处理器、内存、输入输出设备以及其他外围设备。
掌握各组件之间的工作原理和相互关系,可以帮助我们理解汇编语言的运行机制。
Step 2:选取适合的汇编语言在市场上有多种不同的汇编语言可供选择,如x86、ARM等。
选择合适的汇编语言要根据自己的需求和实际情况进行判断。
一般而言,x86是最常见和广泛使用的汇编语言之一。
Step 3:学习汇编语言基础知识汇编语言是一种与硬件直接交互的语言,因此学习者需要掌握一些基础的概念和知识。
首先,了解各种指令的含义和功能,如数据传输指令、算术和逻辑指令等。
其次,要学会使用寄存器进行数据的读写和计算。
最后,掌握常用的编程技巧和调试方法,如单步执行、断点调试等。
Step 4:阅读汇编语言文档和教程阅读和理解汇编语言文档和教程是学习的关键。
可以选择一些经典的教材或者网络资源,比如《汇编语言》一书,或者在线的教学视频、博客文章等。
通过系统地学习和实践,逐渐掌握汇编语言的基本原理和技能。
Step 5:练习编写简单的程序尽早动手实践是掌握汇编语言的关键。
选择一些简单的编程项目,如计算器、加密算法等,通过编写相应的汇编语言程序来提升自己的编程能力。
可以加入一些汇编语言编程的社区或者论坛,与其他学习者一起交流和分享经验。
Step 6:深入学习高级的汇编语言特性一旦掌握了汇编语言的基础知识,可以进一步学习一些高级的特性和技巧,如宏汇编、模块化编程等。
学习者可以深入研究相关的文献和资料,提升自己的编程水平。
Step 7:应用汇编语言进行优化汇编语言被广泛应用于性能敏感的领域,如游戏开发、图形处理等。
汇编语言基于x86处理器课后答案第七版

汇编语言基于x86处理器课后答案第七版在进行汇编语言基于x86处理器课后答案第七版的整理和总结前,我们先回顾一下课程的主要内容。
本课程主要涉及汇编语言的基础知识、x86处理器的体系结构、汇编语言的程序设计等内容。
通过本课程的学习,我们能够了解并掌握x86汇编语言的编写和调试方法,为以后的系统级编程和软件优化打下坚实的基础。
那么,在开始答案的整理之前,我们首先来了解一下第七版的课后习题。
第七版的课后习题分为多个章节,包含了大量的问题和编程练习。
这些习题涵盖了课程的各个方面,从基础的概念理解到实际的程序设计。
下面,我们就以第七版课后习题中的几个问题为例,进行答案的整理和讲解。
1. 问题一:请解释x86汇编语言中的寻址方式,并举例说明。
在x86汇编语言中,寻址方式是指指令如何访问和操作内存中的数据和地址。
x86处理器提供了多种寻址方式,包括直接寻址、寄存器间接寻址、立即寻址等。
直接寻址是最简单的寻址方式,指令中直接给出了要访问的内存地址。
例如,mov ax, [0x1234]表示将地址为0x1234的内存单元中的数据传送到寄存器ax中。
寄存器间接寻址是指令中使用寄存器来传送地址。
例如,mov ax, [bx]表示将寄存器bx中的值作为地址,读取该地址中的数据,并传送到寄存器ax中。
立即寻址是指令中直接给出了要操作的数据。
例如,mov ax, 1234表示将立即数1234传送到寄存器ax中。
2. 问题二:请解释x86汇编语言中的标志位,并说明其作用。
在x86汇编语言中,标志位是由处理器中的标志寄存器(FLAGS)中的各个标志位组成的。
这些标志位用来表示当前程序执行的状态或者某些操作的结果。
常用的标志位包括零标志位(ZF)、进位标志位(CF)、溢出标志位(OF)等。
ZF用来表示最近的运算结果是否为零,当最近的运算结果为零时,ZF被置为1,否则为0。
CF用来表示最近的运算结果是否产生了进位或借位,当最近的运算结果产生了进位或借位时,CF被置为1,否则为0。
x86架构汇编指令

x86架构汇编指令x86架构汇编指令是一种底层的机器语言指令集,用于在x86架构的计算机上执行任务。
它包含了一系列指令,用于操作寄存器、内存和其他硬件设备,以及进行算术和逻辑运算等操作。
本文将介绍几个常用的x86架构汇编指令,包括MOV、ADD、SUB和JMP。
1. MOV指令:MOV指令用于将数据从一个位置复制到另一个位置。
它的语法如下:MOV destination, source其中destination可以是一个寄存器或内存地址,source可以是一个寄存器、内存地址或立即数。
例如,MOV AX, BX将BX寄存器的值复制到AX寄存器中。
2. ADD指令:ADD指令用于将两个数相加,并将结果存储在目标位置。
它的语法如下:ADD destination, source其中destination可以是一个寄存器或内存地址,source可以是一个寄存器、内存地址或立即数。
例如,ADD AX, BX将AX寄存器的值与BX寄存器的值相加,并将结果存储在AX寄存器中。
3. SUB指令:SUB指令用于将两个数相减,并将结果存储在目标位置。
它的语法如下:SUB destination, source其中destination可以是一个寄存器或内存地址,source可以是一个寄存器、内存地址或立即数。
例如,SUB AX, BX将AX寄存器的值减去BX寄存器的值,并将结果存储在AX寄存器中。
4. JMP指令:JMP指令用于无条件地跳转到指定的地址。
它的语法如下:JMP destination其中destination可以是一个标签或地址。
例如,JMP LOOP将跳转到LOOP标签所在的位置。
除了上述指令外,x86架构汇编还包括许多其他指令,如CMP、AND、OR、NOT、XOR等,用于进行比较、逻辑运算和位操作等。
这些指令可以组合使用,以实现复杂的功能。
x86架构汇编指令的编写需要遵循一定的规范和语法。
每条指令都由一个助记符和操作数组成,它们之间用逗号隔开。
汇编语言指令大全X86和X87汇编指令大全(带注释)

汇编语⾔指令⼤全X86和X87汇编指令⼤全(带注释)⽬录⼀、数据传输指令1. 通⽤数据传送指令.2. 输⼊输出端⼝传送指令.3. ⽬的地址传送指令.4. 标志传送指令.⼆、算术运算指令三、逻辑运算指令四、串指令五、程序转移指令六、伪指令七、处理机控制指令:标志处理指令浮点运算指令集1、控制指令2、数据传送指令3、⽐较指令4、运算指令其它1.机械码,⼜称机器码.2.需要熟练掌握的全部汇编知识(只有这么多)3.常见修改(机器码)4.两种不同情况的不同修改⽅法⼀、数据传输指令它们在存贮器和寄存器、寄存器和输⼊输出端⼝之间传送数据.1. 通⽤数据传送指令.MOV 传送字或字节.MOVSX 先符号扩展,再传送.MOVZX 先零扩展,再传送.PUSH 把字压⼊堆栈.POP 把字弹出堆栈.PUSHA 把AX,CX,DX,BX,SP,BP,SI,DI依次压⼊堆栈.POPA 把DI,SI,BP,SP,BX,DX,CX,AX依次弹出堆栈.PUSHAD 把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次压⼊堆栈.POPAD 把EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX依次弹出堆栈.BSWAP 交换32位寄存器⾥字节的顺序XCHG 交换字或字节.(⾄少有⼀个操作数为寄存器,段寄存器不可作为操作数)CMPXCHG ⽐较并交换操作数.(第⼆个操作数必须为累加器AL/AX/EAX)XADD 先交换再累加.(结果在第⼀个操作数⾥)XLAT 字节查表转换.----BX指向⼀张256字节的表的起点,AL为表的索引值(0-255,即0-FFH);返回AL为查表结果.([BX+AL]->AL)2. 输⼊输出端⼝传送指令.IN I/O端⼝输⼊. ( 语法: IN 累加器, {端⼝号│DX} )OUT I/O端⼝输出. ( 语法: OUT {端⼝号│DX},累加器 )输⼊输出端⼝由⽴即⽅式指定时, 其范围是 0-255; 由寄存器 DX 指定时,其范围是 0-65535.3. ⽬的地址传送指令.LEA 装⼊有效地址.例: LEA DX,string ;把偏移地址存到DX.LDS 传送⽬标指针,把指针内容装⼊DS.例: LDS SI,string ;把段地址:偏移地址存到DS:SI.LES 传送⽬标指针,把指针内容装⼊ES.例: LES DI,string ;把段地址:偏移地址存到ES:DI.LFS 传送⽬标指针,把指针内容装⼊FS.例: LFS DI,string ;把段地址:偏移地址存到FS:DI.LGS 传送⽬标指针,把指针内容装⼊GS.例: LGS DI,string ;把段地址:偏移地址存到GS:DI.LSS 传送⽬标指针,把指针内容装⼊SS.例: LSS DI,string ;把段地址:偏移地址存到SS:DI.4. 标志传送指令.LAHF 标志寄存器传送,把标志装⼊AH.SAHF 标志寄存器传送,把AH内容装⼊标志寄存器.PUSHF 标志⼊栈.POPF 标志出栈.PUSHD 32位标志⼊栈.POPD 32位标志出栈.⼆、算术运算指令ADD 加法.ADC 带进位加法.INC 加 1.AAA 加法的ASCII码调整.DAA 加法的⼗进制调整.SUB 减法.SBB 带借位减法.DEC 减 1.NEG 求反(以 0 减之).CMP ⽐较.(两操作数作减法,仅修改标志位,不回送结果).AAS 减法的ASCII码调整.DAS 减法的⼗进制调整.MUL ⽆符号乘法.结果回送AH和AL(字节运算),或DX和AX(字运算),IMUL 整数乘法.结果回送AH和AL(字节运算),或DX和AX(字运算),AAM 乘法的ASCII码调整.DIV ⽆符号除法.结果回送:商回送AL,余数回送AH, (字节运算);或商回送AX,余数回送DX, (字运算).IDIV 整数除法.结果回送:商回送AL,余数回送AH, (字节运算);或商回送AX,余数回送DX, (字运算).AAD 除法的ASCII码调整.CBW 字节转换为字. (把AL中字节的符号扩展到AH中去)CWD 字转换为双字. (把AX中的字的符号扩展到DX中去)CWDE 字转换为双字. (把AX中的字符号扩展到EAX中去)CDQ 双字扩展. (把EAX中的字的符号扩展到EDX中去)三、逻辑运算指令AND 与运算.XOR 异或运算.NOT 取反.TEST 测试.(两操作数作与运算,仅修改标志位,不回送结果).SHL 逻辑左移.SAL 算术左移.(=SHL)SHR 逻辑右移.SAR 算术右移.(=SHR)ROL 循环左移.ROR 循环右移.RCL 通过进位的循环左移.RCR 通过进位的循环右移.以上⼋种移位指令,其移位次数可达255次.移位⼀次时, 可直接⽤操作码. 如 SHL AX,1.移位>1次时, 则由寄存器CL给出移位次数.如 MOV CL,04 SHL AX,CL四、串指令DS:SI 源串段寄存器 :源串变址.ES:DI ⽬标串段寄存器:⽬标串变址.CX 重复次数计数器.AL/AX 扫描值.D标志 0表⽰重复操作中SI和DI应⾃动增量; 1表⽰应⾃动减量.Z标志⽤来控制扫描或⽐较操作的结束.MOVS 串传送.( MOVSB 传送字符. MOVSW 传送字. MOVSD 传送双字. )CMPS 串⽐较.( CMPSB ⽐较字符. CMPSW ⽐较字. )SCAS 串扫描.把AL或AX的内容与⽬标串作⽐较,⽐较结果反映在标志位.LODS 装⼊串.把源串中的元素(字或字节)逐⼀装⼊AL或AX中.( LODSB 传送字符. LODSW 传送字. LODSD 传送双字. ) STOS 保存串.是LODS的逆过程.REP 当CX/ECX<>0时重复.REPE/REPZ 当ZF=1或⽐较结果相等,且CX/ECX<>0时重复.REPNE/REPNZ 当ZF=0或⽐较结果不相等,且CX/ECX<>0时重复.REPC 当CF=1且CX/ECX<>0时重复.REPNC 当CF=0且CX/ECX<>0时重复.五、程序转移指令1. ⽆条件转移指令 (长转移)JMP ⽆条件转移指令CALL 过程调⽤RET/RETF 过程返回.2. 条件转移指令 (短转移,-128到+127的距离内)( 当且仅当(SF XOR OF)=1时,OP1<OP2 )JA/JNBE 不⼩于或不等于时转移.JAE/JNB ⼤于或等于转移.JB/JNAE ⼩于转移.JBE/JNA ⼩于或等于转移.以上四条,测试⽆符号整数运算的结果(标志C和Z).JG/JNLE ⼤于转移.JGE/JNL ⼤于或等于转移.JL/JNGE ⼩于转移.JLE/JNG ⼩于或等于转移.以上四条,测试带符号整数运算的结果(标志S,O和Z).JE/JZ 等于转移.JNE/JNZ 不等于时转移.JC 有进位时转移.JNC ⽆进位时转移.JNO 不溢出时转移.JNP/JPO 奇偶性为奇数时转移.JNS 符号位为 "0" 时转移.JO 溢出转移.JP/JPE 奇偶性为偶数时转移.JS 符号位为 "1" 时转移.3. 循环控制指令(短转移)LOOP CX不为零时循环.LOOPE/LOOPZ CX不为零且标志Z=1时循环.LOOPNE/LOOPNZ CX不为零且标志Z=0时循环.JCXZ CX为零时转移.JECXZ ECX为零时转移.4. 中断指令INT 中断指令INTO 溢出中断IRET 中断返回5. 处理器控制指令HLT 处理器暂停, 直到出现中断或复位信号才继续.WAIT 当芯⽚引线TEST为⾼电平时使CPU进⼊等待状态.ESC 转换到外处理器.LOCK 封锁总线.NOP 空操作.STC 置进位标志位.CLC 清进位标志位.CMC 进位标志取反.STD 置⽅向标志位.CLD 清⽅向标志位.STI 置中断允许位.CLI 清中断允许位.六、伪指令DW 定义字(2字节).PROC 定义过程.ENDP 过程结束.SEGMENT 定义段.ASSUME 建⽴段寄存器寻址.ENDS 段结束.END 程序结束.七、处理机控制指令:标志处理指令CMC 进位位求反指令STC 进位位置为1指令CLD ⽅向标志置1指令STD ⽅向标志位置1指令CLI 中断标志置0指令STI 中断标志置1指令NOP ⽆操作HLT 停机WAIT 等待ESC 换码LOCK 封锁浮点运算指令集1、控制指令(带9B的控制指令前缀F变为FN时浮点不检查,机器码去掉9B)FINIT 初始化浮点部件机器码 9B DB E3FCLEX 清除异常机器码 9B DB E2FDISI 浮点检查禁⽌中断机器码 9B DB E1FENI 浮点检查禁⽌中断⼆机器码 9B DB E0WAIT 同步CPU和FPU 机器码 9BFWAIT 同步CPU和FPU 机器码 D9 D0FNOP ⽆操作机器码 DA E9FXCH 交换ST(0)和ST(1) 机器码 D9 C9FXCH ST(i) 交换ST(0)和ST(i) 机器码 D9 C1iiiFSTSW ax 状态字到ax 机器码 9B DF E0FSTSW word ptr mem 状态字到mem 机器码 9B DD mm111mmmFLDCW word ptr mem mem到状态字机器码 D9 mm101mmmFSTCW word ptr mem 控制字到mem 机器码 9B D9 mm111mmmFLDENV word ptr mem mem到全环境机器码 D9 mm100mmmFSTENV word ptr mem 全环境到mem 机器码 9B D9 mm110mmmFRSTOR word ptr mem mem到FPU状态机器码 DD mm100mmmFSAVE word ptr mem FPU状态到mem 机器码 9B DD mm110mmmFFREE ST(i) 标志ST(i)未使⽤机器码 DD C0iiiFDECSTP 减少栈指针1->0 2->1 机器码 D9 F6FINCSTP 增加栈指针0->1 1->2 机器码 D9 F7FSETPM 浮点设置保护机器码 DB E42、数据传送指令FLDZ 将0.0装⼊ST(0) 机器码 D9 EEFLD1 将1.0装⼊ST(0) 机器码 D9 E8FLDPI 将π装⼊ST(0) 机器码 D9 EBFLDL2T 将ln10/ln2装⼊ST(0) 机器码 D9 E9FLDL2E 将1/ln2装⼊ST(0) 机器码 D9 EAFLDLG2 将ln2/ln10装⼊ST(0) 机器码 D9 ECFLDLN2 将ln2装⼊ST(0) 机器码 D9 EDFLD real4 ptr mem 装⼊mem的单精度浮点数机器码 D9 mm000mmmFLD real8 ptr mem 装⼊mem的双精度浮点数机器码 DD mm000mmmFLD real10 ptr mem 装⼊mem的⼗字节浮点数机器码 DB mm101mmmFILD word ptr mem 装⼊mem的⼆字节整数机器码 DF mm000mmmFILD dword ptr mem 装⼊mem的四字节整数机器码 DB mm000mmmFILD qword ptr mem 装⼊mem的⼋字节整数机器码 DF mm101mmmFBLD tbyte ptr mem 装⼊mem的⼗字节BCD数机器码 DF mm100mmmFST real4 ptr mem 保存单精度浮点数到mem 机器码 D9 mm010mmmFST real8 ptr mem 保存双精度浮点数到mem 机器码 DD mm010mmmFIST word ptr mem 保存⼆字节整数到mem 机器码 DF mm010mmmFIST dword ptr mem 保存四字节整数到mem 机器码 DB mm010mmmFSTP real4 ptr mem 保存单精度浮点数到mem并出栈机器码 D9 mm011mmmFSTP real8 ptr mem 保存双精度浮点数到mem并出栈机器码 DD mm011mmmFSTP real10 ptr mem 保存⼗字节浮点数到mem并出栈机器码 DB mm111mmmFISTP word ptr mem 保存⼆字节整数到mem并出栈机器码 DF mm011mmmFISTP dword ptr mem 保存四字节整数到mem并出栈机器码 DB mm011mmmFISTP qword ptr mem 保存⼋字节整数到mem并出栈机器码 DF mm111mmmFBSTP tbyte ptr mem 保存⼗字节BCD数到mem并出栈机器码 DF mm110mmmFCMOVB ST(0),ST(i) <时传送机器码 DA C0iiiFCMOVBE ST(0),ST(i) <=时传送机器码 DA D0iiiFCMOVE ST(0),ST(i) =时传送机器码 DA C1iiiFCMOVNB ST(0),ST(i) >=时传送机器码 DB C0iiiFCMOVNBE ST(0),ST(i) >时传送机器码 DB D0iiiFCMOVNE ST(0),ST(i) !=时传送机器码 DB C1iiiFCMOVNU ST(0),ST(i) 有序时传送机器码 DB D1iiiFCMOVU ST(0),ST(i) ⽆序时传送机器码 DA D1iii3、⽐较指令FCOM ST(0)-ST(1) 机器码 D8 D1FCOMI ST(0),ST(i) ST(0)-ST(1) 机器码 DB F0iiiFCOMIP ST(0),ST(i) ST(0)-ST(1)并出栈机器码 DF F0iiiFCOM real4 ptr mem ST(0)-实数mem 机器码 D8 mm010mmmFCOM real8 ptr mem ST(0)-实数mem 机器码 DC mm010mmmFICOM word ptr mem ST(0)-整数mem 机器码 DE mm010mmmFICOM dword ptr mem ST(0)-整数mem 机器码 DA mm010mmmFICOMP word ptr mem ST(0)-整数mem并出栈机器码 DE mm011mmmFICOMP dword ptr mem ST(0)-整数mem并出栈机器码 DA mm011mmmFTST ST(0)-0 机器码 D9 E4FUCOM ST(i) ST(0)-ST(i) 机器码 DD E0iiiFUCOMP ST(i) ST(0)-ST(i)并出栈机器码 DD E1iiiFUCOMPP ST(0)-ST(1)并⼆次出栈机器码 DA E9FXAM ST(0)规格类型机器码 D9 E54、运算指令FADD 把⽬的操作数 (直接接在指令后的变量或堆栈缓存器) 与来源操作数 (接在⽬的操作数后的变量或堆栈缓存器) 相加,并将结果存⼊⽬的操作数FADDP ST(i),ST 这个指令是使⽬的操作数加上 ST 缓存器,并弹出 ST 缓存器,⽽⽬的操作数必须是堆栈缓存器的其中之⼀,最后不管⽬的操作数为何,经弹出⼀次后,⽬的操作数会变成上⼀个堆栈缓存器了FIADD FIADD 是把 ST 加上来源操作数,然后再存⼊ ST 缓存器,来源操作数必须是字组整数或短整数形态的变数FSUB 减FSUBPFSUBR 减数与被减数互换FSUBRPFISUBFISUBRFMUL 乘FMULPFIMULFDIV 除FDIVPFDIVRFDIVRPFIDIVFIDIVRFCHS 改变 ST 的正负值FABS 把 ST 之值取出,取其绝对值后再存回去。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
X86汇编语言学习手记X86汇编语言学习手记(1)1. 编译环境OS: Solaris 9 X86Compiler: gcc 3.3.2Linker: Solaris Link Editors 5.xDebug Tool: mdbEditor: vi注:关于编译环境的安装和设置,可以参考文章:Solaris 上的开发环境安装及设置。
mdb是Solaris提供的kernel debug工具,这里用它做反汇编和汇编语言调试工具。
如果在Linux平台可以用gdb进行反汇编和调试。
2. 最简C代码分析为简化问题,来分析一下最简的c代码生成的汇编代码:# vi test1.cint main(){return 0;}编译该程序,产生二进制文件:# gcc test1.c -o test1# file test1test1: ELF 32-bit LSB executable 80386 Version 1, dynamically linked, not strippedtest1是一个ELF格式32位小端(Little Endian)的可执行文件,动态链接并且符号表没有去除。
这正是Unix/Linux平台典型的可执行文件格式。
用mdb反汇编可以观察生成的汇编代码:# mdb test1Loading modules: [ libc.so.1 ]> main::dis ; 反汇编main函数,mdb的命令一般格式为<地址>::dismain: pushl %ebp ; ebp寄存器内容压栈,即保存main函数的上级调用函数的栈基地址main+1: movl %esp,%ebp ; esp值赋给ebp,设置main函数的栈基址main+3: subl $8,%espmain+6: andl $0xf0,%espmain+9: movl $0,%eaxmain+0xe: subl %eax,%espmain+0x10: movl $0,%eax ; 设置函数返回值0main+0x15: leave ; 将ebp值赋给esp,pop先前栈内的上级函数栈的基地址给ebp,恢复原栈基址main+0x16: ret ; main函数返回,回到上级调用>注:这里得到的汇编语言语法格式与Intel的手册有很大不同,Unix/Linux采用AT&T 汇编格式作为汇编语言的语法格式如果想了解AT&T汇编可以参考文章:Linux AT&T 汇编语言开发指南问题:谁调用了main函数?在C语言的层面来看,main函数是一个程序的起始入口点,而实际上,ELF可执行文件的入口点并不是main而是_start。
mdb也可以反汇编_start:> _start::dis ;从_start 的地址开始反汇编_start: pushl $0_start+2: pushl $0_start+4: movl %esp,%ebp_start+6: pushl %edx_start+7: movl $0x80504b0,%eax_start+0xc: testl %eax,%eax_start+0xe: je +0xf <_start+0x1d>_start+0x10: pushl $0x80504b0_start+0x15: call -0x75 <atexit>_start+0x1a: addl $4,%esp_start+0x1d: movl $0x8060710,%eax_start+0x22: testl %eax,%eax_start+0x24: je +7 <_start+0x2b>_start+0x26: call -0x86 <atexit>_start+0x2b: pushl $0x80506cd_start+0x30: call -0x90 <atexit>_start+0x35: movl +8(%ebp),%eax_start+0x38: leal +0x10(%ebp,%eax,4),%edx_start+0x3c: movl %edx,0x8060804_start+0x42: andl $0xf0,%esp_start+0x45: subl $4,%esp_start+0x48: pushl %edx_start+0x49: leal +0xc(%ebp),%edx_start+0x4c: pushl %edx_start+0x4d: pushl %eax_start+0x4e: call +0x152 <_init>_start+0x53: call -0xa3 <__fpstart>_start+0x58: call +0xfb <main> ;在这里调用了main 函数_start+0x5d: addl $0xc,%esp_start+0x60: pushl %eax_start+0x61: call -0xa1 <exit>_start+0x66: pushl $0_start+0x68: movl $1,%eax_start+0x6d: lcall $7,$0_start+0x74: hlt>问题:为什么用EAX寄存器保存函数返回值?实际上IA32并没有规定用哪个寄存器来保存返回值。
但如果反汇编Solaris/Linux的二进制文件,就会发现,都用EAX保存函数返回值。
这不是偶然现象,是操作系统的ABI(Application Binary Interface)来决定的。
Solaris/Linux操作系统的ABI就是Sytem V ABI。
概念:SFP (Stack Frame Pointer) 栈框架指针正确理解SFP必须了解:IA32 的栈的概念CPU 中32位寄存器ESP/EBP的作用PUSH/POP 指令是如何影响栈的CALL/RET/LEAVE 等指令是如何影响栈的如我们所知:1)IA32的栈是用来存放临时数据,而且是LIFO,即后进先出的。
栈的增长方向是从高地址向低地址增长,按字节为单位编址。
2) EBP是栈基址的指针,永远指向栈底(高地址),ESP是栈指针,永远指向栈顶(低地址)。
3) PUSH一个long型数据时,以字节为单位将数据压入栈,从高到低按字节依次将数据存入ESP-1、ESP-2、ESP-3、ESP-4的地址单元。
4) POP一个long型数据,过程与PUSH相反,依次将ESP-4、ESP-3、ESP-2、ESP-1从栈内弹出,放入一个32位寄存器。
5) CALL指令用来调用一个函数或过程,此时,下一条指令地址会被压入堆栈,以备返回时能恢复执行下条指令。
6) RET指令用来从一个函数或过程返回,之前CALL保存的下条指令地址会从栈内弹出到EIP寄存器中,程序转到CALL之前下条指令处执行7) ENTER是建立当前函数的栈框架,即相当于以下两条指令:pushl %ebpmovl %esp,%ebp8) LEAVE是释放当前函数或者过程的栈框架,即相当于以下两条指令:movl ebp esppopl ebp如果反汇编一个函数,很多时候会在函数进入和返回处,发现有类似如下形式的汇编语句:pushl %ebp ; ebp寄存器内容压栈,即保存main函数的上级调用函数的栈基地址movl %esp,%ebp ; esp值赋给ebp,设置main函数的栈基址........... ; 以上两条指令相当于enter 0,0...........leave ; 将ebp值赋给esp,pop先前栈内的上级函数栈的基地址给ebp,恢复原栈基址ret ; main函数返回,回到上级调用这些语句就是用来创建和释放一个函数或者过程的栈框架的。
原来编译器会自动在函数入口和出口处插入创建和释放栈框架的语句。
函数被调用时:1) EIP/EBP成为新函数栈的边界函数被调用时,返回时的EIP首先被压入堆栈;创建栈框架时,上级函数栈的EBP被压入堆栈,与EIP一道行成新函数栈框架的边界2) EBP成为栈框架指针SFP,用来指示新函数栈的边界栈框架建立后,EBP指向的栈的内容就是上一级函数栈的EBP,可以想象,通过EBP 就可以把层层调用函数的栈都回朔遍历一遍,调试器就是利用这个特性实现backtrace功能的3) ESP总是作为栈指针指向栈顶,用来分配栈空间栈分配空间给函数局部变量时的语句通常就是给ESP减去一个常数值,例如,分配一个整型数据就是ESP-44) 函数的参数传递和局部变量访问可以通过SFP即EBP来实现由于栈框架指针永远指向当前函数的栈基地址,参数和局部变量访问通常为如下形式:+8+xx(%ebp) ; 函数入口参数的的访问-xx(%ebp) ; 函数局部变量访问假如函数A调用函数B,函数B调用函数C ,则函数栈框架及调用关系如下图所示:[b:771101bbb0]下图有点乱,因此删去部分内容,要看原图可参考我的blog[/b:771101bbb0] +----------------------------+----> 高地址| EIP (上级函数返回地址) |+----------------------------+| EBP (上级函数的EBP) |+----------------------------+| Local Variables || .......... |+-----------------------------+| Arg n(函数B的第n个参数) |+-----------------------------+| Arg .(函数B的第.个参数) |+-----------------------------+| Arg 1(函数B的第1个参数) |+-----------------------------+| Arg 0(函数B的第0个参数) |+-----------------------------+EIP (A函数的返回地址) |+-----------------------------+| EBP (A函数的EBP) |+-----------------------------+| Local Variables || .......... |+-----------------------------+| Arg n(函数C的第n个参数) |+-----------------------------+| Arg .(函数C的第.个参数) |+-----------------------------+| Arg 1(函数C的第1个参数) |+-----------------------------+| Arg 0(函数C的第0个参数) |+-----------------------------+| EIP (B函数的返回地址) |+-----------------------------+| EBP (B函数的EBP) |+-----------------------------+| Local Variables || .......... |+-----------------------------+---> 低地址图1-1再分析test1反汇编结果中剩余部分语句的含义:# mdb test1Loading modules: [ libc.so.1 ]> main::dis ; 反汇编main函数main: pushl %ebpmain+1: movl %esp,%ebp ; 创建Stack Frame(栈框架)main+3: subl $8,%esp ; 通过ESP-8来分配8字节堆栈空间main+6: andl $0xf0,%esp ; 使栈地址16字节对齐main+9: movl $0,%eax ; 无意义main+0xe: subl %eax,%esp ; 无意义main+0x10: movl $0,%eax ; 设置main函数返回值main+0x15: leave ; 撤销Stack Frame(栈框架)main+0x16: ret ; main 函数返回>以下两句似乎是没有意义的,果真是这样吗?movl $0,%eaxsubl %eax,%esp用gcc的O2级优化来重新编译test1.c:# gcc -O2 test1.c -o test1# mdb test1> main::dismain: pushl %ebpmain+1: movl %esp,%ebpmain+3: subl $8,%espmain+6: andl $0xf0,%espmain+9: xorl %eax,%eax ; 设置main返回值,使用xorl异或指令来使eax为0main+0xb: leavemain+0xc: ret>新的反汇编结果比最初的结果要简洁一些,果然之前被认为无用的语句被优化掉了,进一步验证了之前的猜测。