汇编语言学习笔记

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

汇编语言学习笔记---傻瓜学汇编前言当我在学汇编的时候发现一到了实际编程就发现学过的那些指令串不起来,什么浮点数啊整数啊,怎么跳转啊,怎么循环啊,脑袋立马变成浆糊。下面的文档是我的学习经历,希望对初学者在学习加密解密,软件调试,单片机编程有点帮助。目录1.编程环境的搭建2.深入理解汇编语言的数据3.顺序程序设计4.分支结构程序设计5.循环6.数组及指针7.函数8.结构9.综合运用10.参考文献一:编程环境的搭建首先装好masm32v10和windbg,和editplus,然后在editplus中输入下面的程序,具体的请参考罗云彬的那本书,里面有详尽的说明,编译运行看看:.386.modelflat,stdcalloptioncasemap:noneincludelibmsvcrt.libprintfprotoC:VARARG.datamsgdbhello,thisisthefirsttestprogram!,0dh,0ah,0.codestart:callmainretmainprocpushoffsetmsgcallprintfaddesp,4pushoffsetmsgcallprintfaddesp,4retmainendpendstart下面是运行结果:这里输出两行消息主要是我在写这个最简单的程序的时候发现他不换行,于是我在数据定义后面我加了“0ah,0dh”,呵呵,就是回车换行的十六进制表示,你也可以用其他方法试试,程序就不多解释了,后面会有更多的解释,不过你一定要走到这以步,才能进行下一章。2.深入理解汇编语言的数据整数常量及变量,先看一段很简单的汇编程序:.386.modelflat,stdcalloptioncasemap:noneincludelibmsvcrt.libprintfprotoC:VARARG.dataPRICEEQU30msg1dbtotal=%d,0dh,0ah,0.codestart:callmainretmainproclocalnum:dwordlocaltotal:dwordmovnum,10moveax,numimuleax,eax,PRICEmovtotal,eaxpushoffsetmsg1callprintfaddesp,4retmainendpendstart程序的意思很简单就是在屏幕上打印出某个东西的价格,如过要你拿笔和纸算,拿你肯定很快就能算出来,但你让电脑怎么算呢?当电脑执行到第一个语句的时候,也就是num=10,它就把10放到某个地方并且记住这个值,寄存器或者内存,呵呵,它也就这两个地方,为什么要这么做呢?因为后面要用它来计算啊,为了算出这个值,电脑好的办法就是放在它的内存里,为什么不是寄存器?因为寄存器太少了,就那么几个,呵呵,所以了它就把10存在一个叫num的内存里,注意了哦,num是程序里的变量名,是存中里的一个位置的名称,它的值是10,你可能会问,不起名不行么?行,等下在调试器中你看到的就是没名的。来看看它在调试器中的样子:num变成了[ebp-4]了,现在你想象有个几千行的程序如果都用[ebp-4]这样的名字的话,那我们会疯的,所以汇编程序就让我们给程序里面的变量起个直观的名字,而不是用具体的数字去让你去记住变量内存的位置。程序中imuleax,eax,1eh中的1eh就是个整形常量,也就是30.现在你应该对常量和变量有点感觉了吧。再看个例子:.386.modelflat,stdcalloptioncasemap:noneincludelibmsvcrt.libprintfprotoC:VARARG.dataadb12hbdw1234hc1dd12345678hmsg1dbthenumberis=%xh,0dh,0ah,0.codestart:callmainretmainprocmoval,acbwcwdepusheaxpushoffsetmsg1callprintfaddesp,8movax,wordptracwdepusheaxpushoffsetmsg1callprintfaddesp,8moveax,dwordptrapusheaxpushoffsetmsg1callprintfaddsp,8retmainendpendstart首先,你得想a,b,c1三个变量在程序中到底是怎么存的,是12123412345678,还是78563412341212呢?呵呵,用调试器载入程序看看就知道了:哈哈,看到了没,正确的是这个:00403000:1234127856341274-68,这是为什么?还有就是这个程序打印的三个结果又是什么呢?是12h和0012h和00000012h吗?如果是,那你就错了哦,应该是:thenumberis=12hthenumberis=3412hthenumberis=78123412h呵呵,首先,你得明白这三个你定义的数据在内存是怎么存的,一个原则就是你定义的数据的高位存在内存中的高字节地址,你定义的第二个数据:1234h,高位字节是12吧,低位字节是34吧,所以编译器它先存34字节存在内存的低地址,然后再把12存在高地址,当然如果是你只定义了一个字节那顺序就没反了,就像你定义的第一个字节数据12好一样,同样第三个双自数据12345678h,编译器它就先存78好字节了,然后是56好字节,34h字节,12h字节。下面我们来看看程序:moval,a,就是是把12h放到al中,movzxax,al0扩展指令,将al中的字节扩展到ax中,不足的位用0填充,不改变al的值,al里面是什么值,扩展后ax的值还是等于al中的值。movzxeax,ax;0扩展指令,将ax中的字节扩展到eax中,不足的位用0填充,不改变ax的值,al里面是什么值,扩展后eax的值还是等于ax中的值。然后pusheax,和pushoffsetmsg1,callprintf就是调用c语言库函数printf打印消息,就相当于c语言里面的:printf(thenumberis=%xh\n,a);下面的和这段一样,我就不写废话了。如果面对的是有符号数,那就得用movsx了,当然还有其他指令,后面再介绍。浮点数:在计算机内部,浮点数是以二进制表示的,所以,要先转换为二进制浮点数,转换分两部,整数部分的装换,采用“除2取余法”,小数部分的装换,采用“乘2取整法”,例如19.2,先将19转换成二进制:10011,然后将0.2转换成二进制:00110011……0011,它是个无穷循环小数,然后就是规格化,分三种情况:如果定义的数据类型是dword或者是real4,那么符号位占一位,阶码占8位,位数占23位,总共是32位,如果定义的类型是qword或real8,那么符号位占一位,阶码占11位,位数占52位,总共64位,如果定义的类型是real10或者是tword,那么阶码占15位,位数占64位,符号位占一位,总共80位。怎么算阶码呢?如果是32位,就将阶码加上127,然后转换成二进制,如果是64位,就加上1023,如果是80位,就加上16383。我们看看怎么将19.2转换成32位的二进制浮点数:首先将19转换成二进制:10011,然后将0.2转换成二进制:00110011……0011,整理成32位就是:10011,001100110011001100110011001。然后规格化为:1,0011001100110011001100110011001x2的4次方,阶码为127加4等于131:10000011。所以当浮点数19.2表示为三种不同的数据类型为:32位(dword,real4):0,10000011,001100110011001100110164位(qword,real8):0,100000000011,001100110011001100110011001100110011001100110011001180位:0,100000000000011,001100110011001100110011001100110011001100110011001100110011001100110011。转换成16进制就是4199999Ah,4033333333333333h,403999999999999999ah。然后我们yong程序来验证一下对不对。例子如下:.386.modelflat,stdcalloptioncasemap:noneincludelibmsvcrt.libprintfprotoC:VARARG.dataf1real419.2f2real819.2f3real1019.2msg1dbthefloatingnumberis=%g,0dh,0ah,0.codestart:callmainretmainproclocalf:real8flddwordptrf1fstpfpushdwordptrf+4pushdwordptrf+8pushoffsetmsg1callprintfaddesp,12pushdwordptrf2+4pushdwordptrf2pushdwordptroffsetmsg1callprintfaddesp,12fldf3fstpqwordptrfpushdwordptrf+4pushdwordptrf+8pushoffsetmsg1callprintfaddesp,12retmainendpendstart程序很简单,就是分别在屏幕上打印三个浮点值,如下图:在这里我要说明下,我只有把32位和80位的转换为64位的,才能打印成功,这可能是库函数printf的原因,怎么转换呢?32位浮点转换64位浮点:首先得借助一个64位的浮点局部变量:localf:real8flddwordptrf1fstpf第一句定义了f位一个64位的浮点局部变量,第二句就是把32位浮点数转换为80位的,然后第三句就是把80位的转换位64位的。80位浮点转换位64位浮点数:同样借助一个64位的浮点局部变量:fldf3fstpqwordptrf第二句就是把80位的浮点转换位60位的。但是这两句怎么解释呢:pushdwordptrf2+4pushdwordptrf2为什么要先把f2的高4位字节入栈呢?好,我们先来看看这个数转换成64位的16进制为:4033333333333333h,前面我说了高低对应原则,那么这个64位的16进制在内存中高4字节地址应该存40333333h,也就是存它的高4字节,然后是33333333h,但是,呵呵,在堆栈中的地址是从高往低增长的,所以我们应该先把这个数的高四字节入栈,也就是40333333h,怎么在内存中得到这高4字节呢?就是从f2+4处压入4字节就可以了,然后就是低4字节入栈。如果还没理解,用cdb调试一下就清楚了。浮点与整数之间的转换:先看例子成ch2-4:.386.modelflat,stdcalloptioncasemap:noneincludelibmsvcrt.libprintfprotoC:VARARG.dataf1real819.2f2dword20msg1dbthefloatingtointnumberis=%d,0dh,0ah,0msg2dbtheinttofloatingnumberis=%f,0dh,0ah,0.codestart:callmainretmainproclocalf:real8fldf1fistpdwordptrfpushdwordptrfpushoffsetmsg1callprintfaddesp,8fildf2fstpfpushdwordptrf+4pushdwordptrf+8pushoffsetmsg2callprintfaddesp,12retmainendpendstart运行结果为:浮点数转换成整数:fldf1fistpwordptrf首先我们还是借助了一个64位的局部变量,先把浮点数装入浮点寄存器,然后用装换整行的指令变成整数再存入一个局部变量就行了。整数转换成浮点数:f

1 / 63
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功