汇编语言程序设计(ATamp;T

上传人:小** 文档编号:199030610 上传时间:2023-04-10 格式:DOC 页数:33 大小:168KB
收藏 版权申诉 举报 下载
汇编语言程序设计(ATamp;T_第1页
第1页 / 共33页
汇编语言程序设计(ATamp;T_第2页
第2页 / 共33页
汇编语言程序设计(ATamp;T_第3页
第3页 / 共33页
资源描述:

《汇编语言程序设计(ATamp;T》由会员分享,可在线阅读,更多相关《汇编语言程序设计(ATamp;T(33页珍藏版)》请在装配图网上搜索。

1、汇编语言程序设计陶治江四川大学电气信息学院1gcc编译器:C语言:vitest.cgcc-otesttest.c./test(不用进行连接,而且不用改变生成的可执行代码的执行位)gcc-Stest.c会生成C语言的汇编代码,默认生成的文件名是:test.s使用目标文件生成汇编代码的方法:gcc-ctest.c/默认生成test.o;-c表示编译或者汇编代码而不进行连接,生成目标文件objdump-dtest.o/生成test.s代码汇编:.section.dataoutput:.ascizNowmyageis%dnage:.int23.section.text.global_start_sta

2、rt:noppushlagepushl$outputcallprintfadd$8,%esppushl$0callexit编译:as-otest.otest.s连接:ld-dynamic-linker/lib/ld-linux.so.2-otest-lctest.o/使用了标准C语言库函数执行:./test汇编语言的调试:gdb工具,若要调试,在编译的时候就需要添加-gstabs选项,生成调试的信息,这个编译的结果要大的多:as-gstabs-otestotest.cld-dynamic-linker/lib/ld-linux.so.2-otest-lctest.ogdbtest关于gdb的命

3、令:run运行程序break*_start+1设置断点next单步执行contcontinue程序正常执行inforegisters查看所有寄存器的信息print查看具体的某个寄存器的信息print/x$eaxx十六进制t二进制d十进制x查看具体内寸处的信息x/42cb&output数字是要显示的字段数&内存地址c字符d十进制x十六进制字段的长度:b字节hl6为半字节w32位字数据段:.data.rodata定义只读数据段,修改后会发生段错误常用数据类型:.ascii.asciz(末尾有空字节).byte.double.float.int.octa(八字整数,16个字节).quad(四字整数,

4、八个字节).short定义数组:number:.int23,34,45movlnumber+4,%eax/然后number+4引用的就是第二个元素,以字节为偏移量对于其他的数据类型:number:.octa23,34,45movlnumber+4,%eax此时number+16引用的就是34,因为数据本身是比较小的,所以只引用了四个自己也可以读出数据,其实是不允许的。定义静态符号:.equnum,0xamovl$num,%eax一般的使用都是作为4字节的整数使用的,可以是不同的记数进制bss段:.commbuffer,1000(字节为单位).comm申明未初始化的数据的内存区域.lcomm申明

5、未初始化的数据的本地内存区域,不允许本地汇编代码之外进行访问由于不需要初始化,这部分内存在汇编连接后不用关注,可执行的代码块很小数据的传送:movxsource,destination传送的目标和地址不能同时是内存x为b字节w字l双字movb%al,%blmovw%ax,%bxmovl%eax,%ebx基于数组的求值,除了像上面的使用地址相加的办法,还可以的用法是:base_address(offset_address,index,size)base_address一般是数组名offset_address般是零,但是只能是寄存器,所以就空着index就是元素个数)size(每个元素的字节数)关

6、于offset_address,是可以用来访问跨数组名的数组元素的:data1:.int1,2,3data2:.int4,5,6那么data1(12,1,4)访问的就是5,当然,前两个参数必须要放在寄存器中一个数组的循环访问:.section.rodataoutput:.ascizThenumbernowis:%dnnum:.int12,23,4324,35.section.text.global_start_start:nopmovl$0,%ediloop:pushlnum(,%edi,4)pushl$outputcallprintfaddl$8,%espinc%edicmpl$4,%edi

7、jnelooppushl$0callexit寄存器间接寻址(使用指针):对于一个普通变量value他的地址是$value,当一个寄存器edi拥有这个地址时,(edi)就是这个地址所指向的内存的值,而地址的偏移表示为4(%edi),-4(%edi)等,而($value)就是value,前者是不允许使用的。条件传送指令:cmovxsource,destination条件取决于EFLAGS寄存器的值对于无符号数,检查的是进位标志,零标志和奇偶校验标志来判断两个数的关系的对于有符号数,检查符号标志和溢出标志来判断两个数的关系的无符号数:abovebelowequal(同zero)carry有符号数:g

8、reaterlessequalsign(有符号,是负数)overflow注意:比较指令是使用第二个数来减去第一个数后来设置标记寄存器的,所以比较的时候后一个数不能使立即数:(cmpl%edi,$4就是不合法的)应用:比较出数组的最大值.section.dataoutput:.ascizThemaxnumbernowis:%dnnum:.int12,23,35346,43,2425,346.section.text.global_start_start:nopmovl$1,%edimovlnum,%eaxloop:movlnum(,%edi,4),%ebx5汇编语言程序设计(AT&T语法)cmp

9、l%eax,%ebxcmovgl%ebx,%eaxinc%edicmpl$6,%edijnzlooppushl%eaxpushl$outputcallprintfaddl$8,%esppushl$0callexit数据交换:可以不使用第三个临时交换寄存器条件下在寄存器之间或者寄存器和内存之间交换数据xchg:xchgoperand1operand2;操作数的长度必须相等,当使用在寄存器和内存之间交换数据的时候,处理器LOCK信号被标识,防止其他过程的改动,这个过程比较耗时bswap用于反转寄存器中的字节顺序(非比特顺序),使小尾数与大尾数之间的数进行转换,操作数只能在寄存器中(似乎只用于32位

10、的寄存器)。xaddsource,destination,将sourcedestination的值相交换,然后将两者相加后将结果保存在destination中,其source必须是寄存器,xadd可以添加后缀,也可以没有后缀,寄存器可以是16,32位冒泡法排序的源代码:.section.dataarray:.int23,2345,12,5,36,457,453,3252,423,54.section.text.global_start_start:nopmovl$9,%ecxmovl$9,%ebxmovl$array,%esiloop:movl(%esi),%eaxcmpl4(%esi),%e

11、axjlskipxchg%eax,4(%esi)movl%eax,(%esi)skip:addl$4,%esidec%ebxjnzloopdec%ecxjzend汇编语言程序设计(AT&T语法)movl%ecx,%ebxmovl$array,%esijmploopend:pushl$0/一定要有,否则程序不能正常结束callexit堆栈:在堆栈中可以使用pushlpopl进行四个字节的数据的压入和弹出,使用pushwpopw可以对两个字节的数据进行操作,但是要注意的是,在压入堆栈进行prinf操作的时候,默认是使用一个双字进行输出的,即两个两个字节的元素是一次输出的,当然使用ESP指针也可以进

12、行同样的效果的操作:subl$8,%espmovl$10,4(%esp)movl$output,(%esp)当然操作完成之后还要还原堆栈:addl$8,%esp在内存中:数据元素是按照从低内存位置开始,依次向高内存的位置存放的;而堆栈却相反,堆栈被保存在内存的末尾的位置,当在里面存放数据的时候,向下增长,地址不断减少。pusha/popa将八个16位寄存器压入弹出堆栈pushad/popad将八个32位寄存器压入弹出堆栈pushf/popf压入或者弹出EFLAGS寄存器的低16位pushfd/popfd压入或者弹出EFLAGS寄存器的全部32位跳转:短跳转:使用一个字节作为偏移地址,所以跳转的

13、距离最多就是128个字节,远跳转是在分段内存模式下从一个段跳转到另外一个断使用的,近跳转是其他的跳转情况,在汇编指令中,只需要使用jmp就可以了,而不用顾及跳转的距离。调用与跳转的区别是保留了返回地址以便返回,使用ret指令返回,在执行call指令的时候,它把EIP的值放到堆栈中,然后修改EIP的值使它对到要调用的函数的地址,调用结束后从堆栈中获得EIP原先的值以便返回到原先的地址。在实际的函数的编写的过程中是将ESP的值复制到EIP寄存器中的,然后使用EIP寄存器的值获得在CALL指令之前传递给堆栈的信息的,并且可以将本地变量保存在堆栈中。函数编写的模式:function_label:pus

14、hl%ebpmovl%esp,%ebpmovl%ebp,%esppopl%ebpret在函数中要注意对堆栈的清理:但是从函数的调用模式中可以发现,最后总是要使用movl%ebp,%esp进行恢复的,可能不用手工恢复:.section.dataoutput:.ascizTheresultis:%dn.section.text.global_start_start:7汇编语言程序设计(AT&T语法)nopcallfunctionpushl$0callexitfunction:pushl%ebpmovl%esp,%ebppushl$10pushl$outputcallprintfaddl$8,%es

15、p/用不用?movl%ebp,%esppopl%ebpret中断:中断分为软中断和硬中断,硬中断时由硬件发出的信号(如IO操作),软中断是由操作系统提供的,可以调用操作系统的核心函数,甚至可以调用底层的BIOS层次,在Linux中是使用0x80调用的。条件跳转指令:无符号数:abovebelowequal(同zero)carry有符号数:greaterlessequalsign(有符号,是负数)overflow多了两个指令:JCXZJCXNZ是专门针对EXC寄存器的状态进行判断的,看它是否是零注意的是条件跳转指令在分段的内存模式下是不支持远跳转的,这时就只能使用条件判断后使用无条件跳转指令进行

16、实现了。常使用的标志位:1. 零标志:可以是比较结果相等,或者是计算的结果是零从而进行置位jzjnzjejne2. 溢出标志:处理带符号数据jojno3. 奇偶校验:用于计数数据中的二进制的1的个数,当1的个数是奇数时,不置位;当1的个数是偶数的时候进行置位。jpjnp4. 符号标志:当时有符号数时,如果是负数,符号位就被置位:jsjns符号标志的一个用处就是在处理数组的时候,当使用一般的jnzjne指令的时候,当计数到达零的时候就停了,而使用jns指令在到达零的时候还可以进行一次的循环,就可以引用下标为0的首元素了。.section.dataoutput:.ascizTheresultis:

17、%dndata:.int12,24,2543,3425,2645.section.text.global_start_start:nopmovl$4,%ediloop1:pushldata(,%edi,4)pushl$outputcallprintfaddl$8,%espdec%edijnsloop1pushl$0callexit5. 进位标志:当无符号数发生溢出的时候被置位,但是和溢出标志不同的是:当无符号的数小于零时,进位标志被置位;当使用DECINC自增自减的指令进行操作数据时,即使数据发生溢出或者小于零的时候也不会对进位标志进行置位,即此时:subl$1,%eax同dec%eax语句是

18、不等价的关于进位标志可以使用指令进行操作:clc清空进位标志cmc对进位标志取反stc置位进位标志循环:使用ECX寄存器进行计数loop当exc的值为零时停止循环loopz/loope循环直到exc的值为零或者没有设置zp标志loopnz/loopne循环直到exc的值为零或者设置了zp标志循环指令只支持8位的地址偏移量,只能进行128字节内的循环,这里的循环的一个好处是可以递减EXC的值而不影响EFLAGS寄存器的标志位,当ecx的值为零时ZP也不会因为它而置位。loop灾难:由于loop只察看exc寄存器的值(作为无符号的值进行看待),如果exc的值一开始就是零,就会无限递增下去直到寄存器

19、溢出,可以在循环之前进行使用jcxz察看。.section.dataoutput:.ascizTheresultis:%dn.section.text.global_start_start:nopmovl$0,%ecxmovl$0,%eaxjcxzendloop1:addl%ecx,%eaxlooploop1pushl%eaxpushl$outputcallprintfaddl$8,%espend:pushl$0callexit高级语言for语句的伪指令:.section.datavalue:.int23output:.ascizThevalueofecxregisternowis:%dn.s

20、ection.text.global_start_start:nopmovl$0,%ecxfor:cmpl$22,%ecxjleforcodejmpendforcode:pushl%ecx/一定要局部保存,否则会被破坏pushl%ecxpushl$outputcallprintfaddl$8,%esppopl%ecxinc%ecxjmpforend:pushl$0callexit使用数字:在内存中数据是按照小尾数的顺序进行排列的,就是低字节的数据放在内存位置较低的位置,其余的字节依次向高内存的位置进行排放,当数据传输到寄存器的时候,数据会自动地转换为大尾数的顺序放在寄存器中的。扩展数据:当将数

21、据转换为到较大的数据位置时,会有数据扩展,分为有符号扩展和无符号扩展,用于有符号数和无符号数的扩展:movzx;movsx如movsx%cl,%eax源操作数可以使内存数或者寄存器数,而目标操作数必须是寄存器数,可以依据目标操作数的长度进行正确的扩展。在gdb中察看8个字节的数据的时候可使用:x/1gd&data在输出数据的时候,压入堆栈的时候应该记住内存的数据是小尾数的:pushldata+4pushldatapushl$output.ascizThevaluenowis:%qdn如果没有q参数的时候就认为是两个数据SIMD指令:打包的整数是能够表示多个整数的一系列的字节,可以把这些字节当作

22、一个整体,对它进行数学操作,并行的处理多个整数值。MMX(多煤体扩展技术)整数使用8个64位的MMX寄存器(标号mm0-mm7),在处理器内部被影射为FPU寄存器,可以将8个字节数,4个字整数或者2个双字整数放入寄存器中:movqsource,destination目标和源可以是MMX,SSE或者64位的内存位置,但是不能同是内存位置,使用print$mm0查看SSE(流化SIMD扩展技术)整数使用8个128位的XMM(xmmO-xmm7)寄存器,可以将16个字节,8个字,4个双字,2个四字的数据传入其中,使用movdqu传送:movdqusource,destination目标和源可以是12

23、8位的SSE寄存器或者内存位置(不能同是内存)。data:.int1,23,34,2data2:.quad2,33data3:.octa23movdqudata,%xmmOmovdqudata2,%xmm1movdqudata3,%xmm2(但是otca不能正常显示,只显示其16进制的数据)BCD数据:分为打包的和不打包的数据类型,打包的使用一个字节表示两个位数。FPU可以用于在FPU的内部进行BCD的数学操作,FPU有8个80位的寄存器,使用低位的9个字节储存BCD值,格式是打包的BCD值,包含18个数据位,大多数的情况下不使用最到的字节,而将最高字节的最高一个比特用作符号位;为了将打包的数

24、据加载到寄存器中,必须首先在内存中创建打包的数据,然后将数据传送到FPU寄存器中之后,它就会被自动转换为扩展双精度的浮点格式,当要从寄存器中获得结果的时候,扩展的浮点数会自动转换为80位打包的BCD格式。FPU寄存器的使用类似于堆栈的操作,使用fbld压入寄存器,fbstp弹出寄存器data:.byte0x89,0x67,0x56,0x34,0x12,0x11,0x22,0x33,0x44(gdb)print$st0$1=443322111234566789使用16进制的数据进行创建(只能18位),然后FPU自动转换,st0-st7显示。data:.int0x89675634,0x121122

25、33这样也能显示相应的BCD值,但是由于小尾数的转换问题,不能正确显示:(gdb)print$st0$1=1211223389675634.section.datadata:.byte0x56,0x34,0x12,0x00,0x00,0x00,0x00,0x00,0x00data2:.int2.section.text.global_start_start:nopfblddatafimuldata2fbstpdatapushl$0callexit浮点数:单精度:1+8+23双精度:1+11+52扩展双精度:1+15+64浮点数是在FPU寄存器中进行操作的,操作方式类似于堆栈:单精度:fldsf

26、sts双精度:fldlfstl查看使用print$st0-7命令;对于内存中的浮点数:x/f单精度x/gf双精度对浮点数据进行压入与弹出的时候,是不能对立即数进行操作的,否则就会发生错误,即使压入的是整数也不可以。压入常用的预置的数据:fldl正1fldl2t以2为底的10的对数fldl2e以2为底的e的对数fldpi圆周率fldlg2以10为底的2的对数fldln2以自然数为底的2的对数fldz正零SSE的浮点数据类型:拥有8个128位的XMM寄存器,可以容纳4个单精度浮点值或者2个双精度的浮点值。单精度浮点数movups将四个单精度的浮点值传送到XMM寄存器或者内存中movss把一个单精度

27、的浮点值传送到寄存器的低4个字节或内存中movlps把2个单精度的浮点值传送到寄存器的低8个字节中或者内存中movhps把2个单精度的浮点值传送到寄存器的高8字节movlhps把2个单精度的浮点值从低8字节传送到高8字节movhlps把2个单精度的浮点值从高8字节传送到低8字节双精度浮点数movupd把两个双精度的浮点值传送到XXM寄存器或者内存中movsd把1个双精度的浮点值传送到寄存器的底8字节或者内存movhpd把1个双精度的浮点值传送到寄存器的高8字节或者内存movlpd把1个双精度的浮点值传送到寄存器的低8字节或者内存SSE3技术:movshdup传送128位,复制了2,4元素DCB

28、ADDBBmovsldup传送128位,复制1,2元素DCBACCAAmovddup传送64位复制128位AAA在实际的寄存器的查看中可能显示的不同寄存器显示的是ABCDBBDDABCDAACCdata1:.float23.24,123.123data2:.float11.11,22.22movssdata1,%xmm0movhpsdata2,%xmm0v4_float=23.2399998,0,11.1099997,22.2199993可见这里的寄存器的后面是高位,前面是低位。数学计算:加法与减法:addsub他们通用于有符号的和无符号的数据。加法的操作记住检查CFOF标志,对于减法,当计算

29、的结果为负数的时候,如果当作是武无符号的操作时,CF是被置位的。其实计算机本身的操作是不区分带符号与不带符号的数据的,区分是由程序员本身进行区分的。例如:sub3,2虽然结果是-1这个正确的数据,但是使用jc仍然可以进行跳转。neg对寄存器的数据进行取反操作,速度比用零减要快多特殊的长数据的加法与减法运算:adcsbb可以用于长度很大的数据的加减操作,它把上次计算的借位或者进位标志自动算在其中了。.section.datadata1:.quad7252051615data2:.quad5732348928outputsum:.ascizThesumofthenumberis:%qdnoutpu

30、tdif:.ascizThedifofthenumberis:%qdn.section.text.global_start_start:nopmovldata1,%ebxmovldata1+4,%eaxmovldata2,%edxmovldata2+4,%ecxaddl%edx,%ebxadcl%ecx,%eaxpushl%eaxpushl%ebxpushl$outputsumcallprintfmovldata1,%ebxmovldata1+4,%eaxmovldata2,%edxmovldata2+4,%ecxsubl%ebx,%edxsbbl%eax,%ecxpushl%ecxpushl

31、%edxpushl$outputdifcallprintfaddl$24,%esppushl$0callexitThesumofthenumberis:12984400543Thedifofthenumberis:-1519702687自增与自减:incdec用于无符号的数据的自增与自减操作,他们不会影响进位标志,当程序输入的是从Oxffffffff进行递增还是递减时,是被当作是一个很大的无符号的数进行操作的。乘法与除法:他们是进行有符号与无符号计算的区分的,而且都要在指令的结尾标明长度。无符号的乘法:mulsource目标是寄存器或者内存的位置,隐藏的操作数是:ALAXEAX的寄存器中,结果

32、储存的位置是原来的两个操作数的两倍:AXDX:AXEDX:EAX有符号的乘法:imul1,imulsource同无符号的乘法mul2,imulsource,destination目标可以是16,32位的通用寄存器,就是结果可以指定存放在某个寄存器中,但是要注意不要溢出3,imulmultiplier,source,destinationmultiplier必须是一个立即数,这个指令方式用于将一个带符号的立即值同一个数进行快速的相乘并将结果存放在特定的通用寄存器中。除法:divdivisor有符号:idivdivisor可以是寄存器或者一个内存值,被除数在AXDX:AXEDX:EAX中,除数的长

33、度只能是被除数的一半,不满足使用movsx进行扩充。计算的结果:商ALAXEAX余数AHDXEDX对于有符号的除法,余数的符号总是同被除数的符号相同。.section.dataoutput:.ascizThequotientis:%dnoutput1:.ascizTheremainderis%dndividend:.quad-2352347divisor:.int23quotient:.int0remainder:.int0.section.text.global_start_start:nopmovldividend,%eaxmovldividend+4,%edxidivldivisormo

34、vl%edx,remainder/这里的两步不是多余的,在除法结束后要尽快保护计算的结果movl%eax,quotient/否则就会被破坏而发生错误pushlquotientpushl$output1callprintfpushlremainderpushl$outputcallprintfaddl$16,%esppushl$0callexit移位指令:salshl向左移位,由于右端全部都是添零,所以这两个指令是等价的,指令需要添加后缀。saldestinationsal%cl,destination/只能使用这个寄存器salshifter,destination/shifter是一个立即值其

35、中的destination可以是寄存器或者内存,移位操作从左边出去的数据都被放到了CF中了右移指令:sar算数右移,用于有符号的友谊操作shr逻辑右移,用于无符号的右移操作语法同左移,右边溢出的数据放于CF中由于处理器的乘法与除法的操作时很费时的,使用移位操作可以进行一些快速的乘除计算循环移位:rol向左循环移位ror向右循环移位rclrcr向左向右循环移位,包含CF标志操作的语法同前面的移位操作不打包的BCD运算:这种数据在内存中创建小尾数的数据后,在正常计算后(一般是计进位的计算方法)后每步对操作的结果进行指令自动的调整aaaaasaamaad这些指令能够一般用在addadcsubsbbm

36、ul等指令之后aad指令不同,它是对被除数进行先操作后再进行除法计算。这些调整指令都用到了一个隐含的操作数据:AL寄存器,假设前面计算的结果都被保留在了AL寄存器中,并把值调整为不打包的BCD格式,ADD指令假设被除数以不打包的格式放在AX寄存器中的,结果是AL中的商和AH中的余数,他们都是不打包BCD的形式。.section.datadata:.byte0x04,0x03,0x02data2:.byte0x02,0x03,0x01.section.bss.lcommsum,4.section.text.global_start_start:nopxor%edi,%edimovl$3,%ecx

37、loop1:movbdata(,%edi,1),%aladcbdata2(,%edi,1),%alaaamovb%al,sum(,%edi,1)inc%edilooploop115汇编语言程序设计(AT&T语法)adcb$0,sum(,%edi,1)/捕捉最后的进位标志pushl$0callexit打包的BCD运算:DAADAS只用于加减的调整,具体的使用方法同不打包的计算方法布尔操作:ANDORXORNOT只有NOT使用单一的操作数TESTsourcedestination相当于AND操作但是不改变操作数的本身。FPU高级数学功能:FPU寄存器堆栈:FPU是一个自持单元,用与标准寄存器独立的

38、一组寄存器操作数据,有8个80位的数据寄存器和3个16位的控制,状态,标志寄存器。FPU寄存器命令为R0-R7,和内存的堆栈不同的是这个堆栈是循环的,堆栈的最后一个寄存器连接最先的一个寄存器,当堆栈满时,如果把第九个数据加载到堆栈寄存器中,堆栈指针会绕回到第一个寄存器中,使用新值替换这个值,并引发一个FPU异常错误(后来加入的值被显示为nan无效值)。 状态寄存器:fstat寄存器使用fstsw指令可以将fstat寄存器的值加载到内存或者AX寄存器中:fstsw%axfstswstatus默认情况下fstat寄存器的所有位都是被置零的。 控制寄存器:fctrl寄存器前6位用于设置错误的掩码的,

39、默认的情况下所有的掩码都被置位,即屏蔽所有的异常。8-9控制确定浮点的计算精度,00单精度01未使用10双精度11扩展双精度默认情况下是使用扩展双精度,但最为耗时10-11控制舍入的方法:00舍入到最近值01向下舍入10向上舍入11向零舍入默认是向最近值舍入整个控制寄存器默认的设置值是0x037f将它设置为0x7f使用单精度的浮点计算,加快浮点的计算速度,使用fstcw将寄存器的内容弹出到内存中fldcw将内存中的值加载到控制寄存器中 标志寄存器:ftag寄存器顺序是R7R1最右端的和最左端的零往往省略。使用16个字节表示8个数据寄存器的状态,每个寄存器两个字节00一个合法的扩展双精度值01零

40、值10特殊的浮点数(nan值)11空,无内容数据寄存器的堆栈操作:首先使用finit初始化控制寄存器和状态寄存器和标志寄存器为默认的值,但不改变数据寄存器的数据操作的结果是将数据放入栈低,然后将ftag标志为0xffff,数据是不可以使用的,等于是全部清除了,但是会遗留一些无效的数据。整数fildsfists单精度fldsfsts双精度fldlfstl其他指令:fst%st(4)将st(0)的数据复制到st(4)中fxch%st(4)交换寄存器st和st(4)fstp同fst一样复制数据,但是复制完st(0)的数据之后就把st(0)的数据弹出fstp%st(4)是将st(0)的数据复制到st(

41、4)中的,然后将st(0)的数值弹出,实际数据在st(3)中了弹出的数据正如是循环的堆栈,放在寄存器的高位,但是标志寄存器标志为无效的数据。浮点的基本运算:faddfdivfdivrfmulfsubfsubr带有r标志的是进行反序操作另外在指令中添加一个i用于整数操作,结尾添加一个p字将结果弹出堆栈关于每个指令的扩充:faddsource将内存中的值与st(0)中的数据进行相加(faddsource,%st(0)fadd%st(x),%st(0)fadd%st(0),%st(x)汇编语言程序设计(AT&T语法)faddp%st(0),%st(x)相加的结果储存在st(x)中,并弹出st(0)f

42、addp(faddp%st(1)%,st(0)fiaddsource(source中是16或者32位的内存整数值)在使用到内存值得时候要使用S1后缀高级浮点运算指令:fabS计算St0绝对值fchS改变St0中值得符号fcoS计算St0的余弦值fpatan计算St0的部分反正切fprem计算St0/St1的部分余数fpreml计算stO/stl的部分余数(IEEE格式的)fptan计算st0的部分正切frndint对st0最近取整(取整的方向由fctrl控制)fscale计算st0乘以2的stl次方fsin计算st0的正弦fsincos计算st0的正弦和余弦,正弦在stl,余弦在st0fsqr

43、tfyl2x计算stl*logst0(以2为底数)fyl2xpl计算st1*log(stO+1)(以2为底数)fprem是Intel开发出来的指令,默认是向零舍入的方法fpreml使用的是IEEE的格式,是向上舍入的方法这两个指令使用的都是FPU状态寄存器的C2位来决定迭带的次数,可以将状态寄存器的值加载到ax寄存器中使用test来检测C2的第10位)fldsflfldldlloop:fpremlfstsw%axtestb$4,%ahjnzloopfstsresult三角函数:默认使用st0操作数,结果存储在st0中,数据使用的是弧度值,如果是角度值就需要自己进行换算:finitfildsva

44、ll80fldpifdivpfmulldatafsinfptan计算stO的正切值,并把值放在stO后,再压入1,原来的值就在st1中了,这样滞后就可以使用fdivp就可以计算正切的倒数了。fpatan计算st1/st0的反正切,结果在st1中,然后弹出st0,结果保存在st0中,返回的结果是弧度值对数操作:fyl2x计算st1*logst0(以2为底数)fyl2xp1计算st1*log(st0+1)(以2为底数)公式是以2位底数的,实际可以用公式将一般的底数转为以2为底的底数fld1fldldata1fyl2xfld1fdivpfldldata17汇编语言程序设计(AT&T语法)fyl2x浮

45、点条件分支:fcom比较stOstl寄存器fcomst(x)比较stO同其他的寄存器fcomsource比较stO与内存内的一个32位或者64位值fcompfcompst(x)fcompsourcefcompp比较stOstl并两次弹出堆栈ftst比较stO同0.0fcomstlstO默认的格式比较之后可以进行fstat状态寄存器的设置,通常将其映射为普通的EFLAGS寄存器,使用普通的跳转指令等进行跳转fldldatafldldatalfcomfstsw%axsahfjaend记住:这里使用的是abe等比较的方法sahf指令很关键,因为它将状态寄存器的值(此时在AX寄存器中)映射到EFLAG

46、S中,只设置CFPFZFSF和对准标志而不影响其他的标志另外,由于浮点数表示是由一定的误差的,所以不建议用这个方法比较两个浮点数的相等fcomifcomip是将fcomsahf合并的指令,比较之后就可以直接使用abe等指令了但是他们的缺陷是只能用于两个寄存器之间的比较条件传送指令:fcmov(n)b(e)source,%st(0)fcmov(n)a(e)source,%st(0)用于将另外一个寄存器的值传送到st0寄存器,经常使用在fcomi指令之后保护和恢复FPU状态由于MMX技术使用的是FPU寄存器的映射,所以在同时使用打包的数据计算和浮点计算的时候可能会破坏FPU寄存器的状态和数据保护和

47、恢复FPU环境:fstenvfldenv这些指令的操作数是一个28字节的用于保存状态的内存块,主要保存的是:三个特殊的寄存器,FPU指令指针的偏移量,FPU数据指针,FPU最后执行的操作码保存和恢复FPU状态:fsavefrstor他们的操作数是一个108字节的内存块,主要保存三个特殊的寄存器,8个数据寄存器。字符串的处理:movs指令,用于将字符串从内存的一个位置传到另外的一个内存位置,他们具体使用movsbmovswmovsl分别传送1,2,4个字节,不用指明操作数,默认的操作数分别是%ESI%EDI寄存器指向的内存地址加载内存地址:movl$output,%edi或者lealoutput

48、,%edi,在调试的时候使用x/s&output查看字符串,在使用.bss段时,所有的字节都被默认的初始化为0,自动的作为字符串结尾的0在每次进行转移操作的时候,%ESI%EDI的值都会自动变更,具体的方向取决与EFLAGS寄存器的DF标志位:如果这个位被清零,寄存器的值递增,正向操作;如果DF被置位,寄存器的值递减,字符串反向操作,可以使用指令cldstd进行DF的清除与置位,汇编语言程序设计(AT&T语法)注意的是当DF被置位的时候,如果每次移动的数据是不同的,那每次都会从字符串的结尾记数,就是每次从头开始,而每次转移的字符串大小一样或者进行正向操作没有这个问题。x/12bc&desrep

49、前缀:用于反复前缀之后的一条指令,反复的次数是ECX寄存器的次数,单步调试的时候,rep的指令时当作一步进行处理的,如果是进行反向的传送数据,建议使用movsb,其他的指令同rep前缀似乎不能搭配使用.section.datasrc:.ascizTaoZhijangn.section.bss.lcommdes,13.section.text.global_start_start:noplealdes,%edilealsrc,%esicldmov$13,%ecxshrl$2,%ecxrepmovslmovl$13,%ecxand$3,%ecxrepmovsbpushl$descallprintf

50、addl$4,%esppushl$0callexit其他rep前缀指令:reperepnerepzrepnz单独的rep指令前缀是只关心ecx寄存器的次数的,而这些指令不仅关心ecx寄存器的数目,而且每次都检查ZF标记,用于查找等十分方便存储和加载字符串:lods把内存中的字符串加载到eax寄存器中,有(bwl)三个后缀,隐含的操作数是%ESIstos将exc中的字符串加载到另外的一个内存位置中去,有(bwl)三个后缀,隐含的操作数是%EDI,stos同rep一起使用可以将eax中的内容多倍复制到内存中。字符串函数:用于文本的转换为大写.section.datasrc:.ascizTaoZhi

51、jiangisstudyinginsichuanuniversity!nlength:.equlen,length-src.section.bss汇编语言程序设计(AT&T语法).lcommdes,len.section.text.global_start_start:noplealdes,%edilealsrc,%esicldmovl$len,%ecxloop1:lodsbcmpb$a,%aljbokcmpb$z,%aljaoksubb$0x20,%alok:stosblooploop1pushl$descallprintfaddl$4,%esppushl$0callexit字符串的比较(非

52、字符的比较)cmps(bwl)进行比较后设置EFLAGS寄存器,可以使用一般的跳转指令进行跳转,可以将cmps同reperepnerepzrepnz指令进行配合使用,repzrepe(相等时继续跳转),repnzrepne(不相等时进行跳转),操作数默认是ESI,%EDI寄存器比较的原则:ASCII的原则zaZA,长的短的扫描字符串:scas(bwl)默认的操作数是%ESI和%EAX中的数据,常同repne等使用,完整的字符串比较函数的代码:.section.datasrc1:.ascizTaozhijiangisstudyinginsichuanuniversity!nlength1:.eq

53、ulen1,length1-src1src2:.ascizTaoZhijiangisstudyinginsichuanuniversity!nlength2:.equlen2,length2-src2a:.ascizsourceisgreaterthandestinationnb:.ascizsourceislessthandestinationn汇编语言程序设计(AT&T语法)e:.ascizsourceisequaltodestinationn.section.text.global_start_start:noplealsrc1,%esilealsrc2,%edimovl$len1,%e

54、axmovl$len2,%ecxcmpl%eax,%ecxjgeskipxchgl%eax,%ecxskip:cldrepcmpsbjagreaterjblessjeequalgreater:pushl$ajmpendless:pushl$bjmpendequal:movl$len2,%eaxcmpl$len1,%eaxjalessjbgreaterpushl$eend:callprintfaddl$4,%esppushl$0callexit查找字符串全代码:.section.datasrc:.ascizTaozhijiangisstudyinginsichuanuniversity!nlen

55、gth:.equlen,length-srcdes:汇编语言程序设计(AT&T语法)!.asciisnotfound:.ascizstringisnotfound!nfound:.ascizstringisfound,theaddressis:%d!n.section.text.global_start_start:noplealsrc,%edilealdes,%esimovl$len,%ecxcldlodsbrepnzscasbsubl$len,%ecxneg%ecxcmpl$0,%ecxjnzfinditpushl$notfoundcallprintfaddl$4,%espjmpendfi

56、ndit:pushl%ecxpushl$foundcallprintfaddl$8,%espend:pushl$0callexit这个代码用于”0”查找来确定字符串的长度函数:(可以使用XMMFPU等寄存器的操作)输入:寄存器,全局变量,堆栈输出:寄存器,全局变量的内存中汇编函数同一般的高等语言函数不同,他们不需要在函数定义之前进行定义或者声明,在函数调用中,函数对寄存器的操作是不确定的,所以要进行pushapopa进行保存和恢复C语言进行数据的传递约束:参数使用堆栈进行传递,返回值在%EAX%EDX:%EAXST(0)寄存器中程序堆栈:函数参数316(%ebp)函数参数212(%ebp)函数

57、参数18(%ebp)返回地址4(%ebp)旧的EBP值(%ebp)汇编语言程序设计(AT&T语法)局部变量1-4(%ebp)局部变量2-8(%ebp)通常使用subl$8,%esp可以为局部变量保存一定的内存空间,这样就可以在函数内部进行pushlpopl进行堆栈操作而不会破坏局部变量了使用call指令进行函数调用完成之后,要使用addl$-,%esp将传入的参数的堆栈进行恢复使用独立的函数文件:这样的函数文件同独立的汇编代码文件,不用使用_start和数据段,而把函数名声明为全局的,这样所有的其他的文件就可以访问这个函数了,函数写完后单独汇编,只要在连接的时候将函数文件添加就可以了,调用的过

58、程没有区别但是在调试的时候好象在主函数的输出都发生段错误Linux系统的程序堆栈分析:环境变量,命令行参数指向环境变量的指针0x00000000指向命令行参数3的指针指向命令行参数2的指针指向命令行参数1的指针程序名称参数个数(vESP)注意:所有的命令行参数都是字符串,即使看起来象数字,程序名称是第一个命令行参数转换函数都需要将要转换的字符串的指针放在%EAX中,结果:atoiEAXatol()EDX:EAXatof()st(0)显示命令行参数:.section.dataoutput1:.ascizThereare%dargumentsoftheprogram.noutput2:.asciz

59、%sn.section.text.global_start_start:movl%esp,%ebppushl(%ebp)pushl$output1callprintfaddl$8,%espmovl(%ebp),%ecxloop1:pushl%ecxaddl$4,%ebppushl(%ebp)pushl$output2callprintf汇编语言程序设计(AT&T语法)addl$8,%esppopl%ecxlooploop1pushl$0callexit查看系统的环境变量:(环境变量的指针数组是以NULL结尾的,当没有其他的命令行参数时,命令行参数指针地址同ESP相差12个地址),代码如下:.s

60、ection.dataoutput:.asciz%sn.section.text.global_start_start:movl%esp,%ebpaddl$12,%ebploop1:cmpl$0,(%ebp)jeendpushl(%ebp)pushl$outputcallprintfaddl$8,%espaddl$4,%ebpjmploop1end:pushl$0callexit命令行参数使用范例:.section.dataoutput:.ascizThesumis:%dntemp:.int0.section.text.global_start_start:pushl8(%esp)callat

61、oiaddl$4,%espmovl%eax,temppushl12(%esp)汇编语言程序设计(AT&T语法)callatoiaddl$4,%espaddltemp,%eaxpushl%eaxpushl$outputcallprintfaddl$8,%esppushl$0callexit注意:函数调用之后需要自己进行堆栈的清理工作,这是C调用的规定Linux系统调用:查看系统调用的编号:cat/usr/include/asm/unistd.h查看具体的调用函数:man2exitman2brk等具体的调用格式:EAX具体的调用编号EBX,ECX,EDX,ESI,EDI按照函数原形顺序的参数,超过6个参数就要

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!