《86汇编语言学习.docx》由会员分享,可在线阅读,更多相关《86汇编语言学习.docx(16页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、X86汇编语言学习手记X86汇编语言学习手记(1)1. 编编译环境境 OOS: Sollariis 99 X886 CComppileer: gccc 3.3.22 Liinkeer: Sollariis LLinkk Edditoors 5.xx Deebugg Toool: mddb EEdittor: vii 注注:关于于编译环环境的安安装和设设置,可可以参考考文章:Sollariis 上上的开发发环境安安装及设设置。 mddb是SSolaariss提供的的kerrnell deebugg工具,这里用用它做反反汇编和和汇编语语言调试试工具。 如如果在LLinuux平台台可以用用gdbb进
2、行反反汇编和和调试。 2. 最最简C代代码分析析 为简化化问题,来分析析一下最最简的cc代码生生成的汇汇编代码码: # vvi ttestt1.cc intt maain() reeturrn 00; 编编译该程程序,产产生二进进制文件件: # ggcc tesst1.c -o ttestt1 # ffilee teest11 teest11: EELF 32-bitt LSSB eexeccutaablee 8003866 Veersiion 1, dynnamiicallly linnkedd, nnot strrippped tesst1是是一个EELF格格式322位小端端(Liittl
3、le EEndiian)的可执执行文件件,动态态链接并并且符号号表没有有去除。 这这正是UUnixx/Liinuxx平台典典型的可可执行文文件格式式。 用mddb反汇汇编可以以观察生生成的汇汇编代码码: # mmdb tesst1 Looadiing moddulees: llibcc.soo.1 mmainn:ddis ; 反汇编编maiin函数数,mddb的命命令一般般格式为为 :ddis maain: puushll %ebbp ; ebbp寄存存器内容容压栈,即保存存maiin函数数的上级级调用函函数的栈栈基地址址 mmainn+1: mmovll %eesp,%ebbp ; eesp
4、值值赋给eebp,设置mmainn函数的的栈基址址 mmainn+3: suubl $8,%essp maiin+66: aandll $00xf00,%eesp maain+9: movvl $0,%eaxx mmainn+0xxe: suubl %eaax,%espp mmainn+0xx10: mmovll $00,%eeax ; 设设置函数数返回值值0 maiin+00x155: leaave ; 将ebbp值赋赋给essp,ppop先先前栈内内的上级级函数栈栈的基地地址给eebp,恢复原原栈基址址 mmainn+0xx16: rret ; mmainn函数返返回,回回到上级级调用 注
5、:这这里得到到的汇编编语言语语法格式式与Inntell的手册册有很大大不同,Uniix/LLinuux采用用AT&T汇编编格式作作为汇编编语言的的语法格格式 如如果想了了解ATT&T汇汇编可以以参考文文章:LLinuux AAT&TT 汇编编语言开开发指南南 问题:谁调用用了 mmainn函数? 在C语语言的层层面来看看,maain函函数是一一个程序序的起始始入口点点,而实实际上,ELFF可执行行文件的的入口点点并不是是maiin而是是_sttartt。 mddb也可可以反汇汇编_sstarrt: _staart:diis ;从_staart 的地址址开始反反汇编 _sstarrt: puus
6、hll $0 _sstarrt+22: puushll $0 _sstarrt+44: moovl %essp,%ebpp _staart+6: ppushhl %eedx _sstarrt+77: moovl $0xx805504bb0,%eaxx _staart+0xcc: ttesttl %eeax,%eaax _sttartt+0xxe: je +0xff _sttartt+0xx10: pusshl $0x8805004b00 _staart+0x115: ccalll -00x755 _sttartt+0xx1a: adddl $4,%espp _staart+0x11d: mmo
7、vll $00x800607710,%eaax _sttartt+0xx22: tesstl %eaxx,%eeax _sstarrt+00x244: jee +7 _sstarrt+00x266: caall -0xx86 _staart+0x22b: ppushhl $00x8005066cd _sstarrt+00x300: caall -0xx90 _staart+0x335: mmovll +88(%eebp),%eeax _sstarrt+00x388: leeal +0xx10(%ebbp,%eaxx,4),%eedx _sstarrt+00x3cc: moovl %eddx,0
8、0x800608804 _sstarrt+00x422: anndl $0xxf0,%essp _sttartt+0xx45: subbl $4,%espp _staart+0x448: ppushhl %eedx _sstarrt+00x499: leeal +0xxc(%ebpp),%edxx _staart+0x44c: ppushhl %eedx _sstarrt+00x4dd: puushll %eaax _sttartt+0xx4e: calll +0x1152 _sttartt+0xx53: calll -0xaa3 _sstarrt+00x588: calll +0xffb ;
9、在这里里调用了了maiin函数数 _staart+0x55d: aaddll $00xc,%essp _sttartt+0xx60: pusshl %eaxx _staart+0x661: ccalll -00xa11 _sstarrt+00x666: puushll $0 _sstarrt+00x688: moovl $1,%eaax _sttartt+0xx6d: lcaall $7,$0 _sttartt+0xx74: hltt 问题:为什么么用EAAX寄存存器保存存函数返返回值? 实实际上IIA322并没有有规定用用哪个寄寄存器来来保存返返回值。但如果果反汇编编Sollariis/LL
10、inuux的二二进制文文件,就就会发现现,都用用EAXX保存函函数返回回值。 这不不是偶然然现象,是操作作系统的的ABII(Apppliicattionn Biinarry IInteerfaace)来决定定的。 Soolarris/Linnux操操作系统统的ABBI就是是Syttem V AABI。 概念:SFPP (SStacck FFramme PPoinnterr) 栈栈框架指指针 正确理理解SFFP必须须了解: IA332 的的栈的概概念 CPPU 中中32位位寄存器器ESPP/EBBP的作作用 PUUSH/POPP 指令令是如何何影响栈栈的 CAALL/RETT/LEEAVEE 等
11、指指令是如如何影响响栈的 如我们们所知: 11)IAA32的的栈是用用来存放放临时数数据,而而且是LLIFOO,即后后进先出出的。栈栈的增长长方向是是从高地地址向低低地址增增长,按按字节为为单位编编址。 2) EBBP是栈栈基址的的指针,永远指指向栈底底(高地地址),ESPP是栈指指针,永永远指向向栈顶(低地址址)。 3) PUUSH一一个loong型型数据时时,以字字节为单单位将数数据压入入栈,从从高到低低按字节节依次将将数据存存入ESSP-11、ESSP-22、ESSP-33、ESSP-44的地址址单元。 44) PPOP一一个loong型型数据,过程与与PUSSH相反反,依次次将ESSP
12、-44、ESSP-33、ESSP-22、ESSP-11从栈内内弹出,放入一一个322位寄存存器。 5) CAALL指指令用来来调用一一个函数数或过程程,此时时,下一一条指令令地址会会被压入入堆栈,以备返返回时能能恢复执执行下条条指令。 66) RRET指指令用来来从一个个函数或或过程返返回,之之前CAALL保保存的下下条指令令地址会会从栈内内弹出到到EIPP寄存器器中,程程序转到到CALLL之前前下条指指令处执执行 7) ENTTER是是建立当当前函数数的栈框框架,即即相当于于以下两两条指令令: puushll %ebbp moovl %essp,%ebpp 88) LLEAVVE是释释放当前
13、前函数或或者过程程的栈框框架,即即相当于于以下两两条指令令: moovl ebpp essp poopl ebbp 如果反反汇编一一个函数数,很多多时候会会在函数数进入和和返回处处,发现现有类似似如下形形式的汇汇编语句句: ppushhl %eebp ; ebbp寄存存器内容容压栈,即保存存maiin函数数的上级级调用函函数的栈栈基地址址 movvl %espp,%eebp ; eesp值值赋给eebp,设置 maiin函数数的栈基基址 . ; 以上两两条指令令相当于于 ennterr 0,0 . leaave ; 将将ebpp值赋给给espp,poop先前前栈内的的上级函函数栈的的基地址址给
14、ebbp,恢恢复原栈栈基址 rret ; maain函函数返回回,回到到上级调调用 这些语语句就是是用来创创建和释释放一个个函数或或者过程程的栈框框架的。 原原来编译译器会自自动在函函数入口口和出口口处插入入创建和和释放栈栈框架的的语句。 函函数被调调用时: 11) EEIP/EBPP成为新新函数栈栈的边界界 函函数被调调用时,返回时时的EIIP首先先被压入入堆栈;创建栈栈框架时时,上级级函数栈栈的EBBP被压压入堆栈栈,与EEIP一一道行成成新函数数栈框架架的边界界 22) EEBP成成为栈框框架指针针SFPP,用来来指示新新函数栈栈的边界界 栈栈框架建建立后,EBPP指向的的栈的内内容就是
15、是上一级级函数栈栈的EBBP,可可以想象象,通过过EBPP就可以以把层层层调用函函数的栈栈都回朔朔遍历一一遍,调调试器就就是利用用这个特特性实现现 baackttracce功能能的 3) ESPP总是作作为栈指指针指向向栈顶,用来分分配栈空空间 栈分配配空间给给函数局局部变量量时的语语句通常常就是给给ESPP减去一一个常数数值,例例如,分分配一个个整型数数据就是是 ESSP-44 44) 函函数的参参数传递递和局部部变量访访问可以以通过SSFP即即EBPP来实现现 由于栈栈框架指指针永远远指向当当前函数数的栈基基地址,参数和和局部变变量访问问通常为为如下形形式: +8+xxx(%ebpp) ;
16、 函数入入口参数数的的访访问 -xxx(%ebpp) ; 函函数局部部变量访访问 假如如函数AA调用函函数B,函数BB调用函函数C ,则函函数栈框框架及调调用关系系如下图图所示: b:77711101bbbb00下图图有点乱乱,因此此删去部部分内容容,要看看原图可可参考我我的bllog/b:77111011bbbb0 +-+- 高地址址 | EIPP (上上级函数数返回地地址) | +-+ | EBPP (上上级函数数的EBBP) | +-+ | Loocall Vaariaablees | | . | +-+ | AArg n(函函数B的的第n个个参数) | +-+ | Argg .(函数B
17、B的第.个参数数) | +-+ | Argg 1(函数BB的第11个参数数) | +-+ | AArg 0(函函数B的的第0个个参数) | +-+ EEIP (A函函数的返返回地址址) | +-+ | EEBP (A函函数的EEBP) | +-+ | Loccal Varriabbless | | . | +-+ | Argg n(函数CC的第nn个参数数) | +-+ | Arrg .(函数数C的第第.个参参数) | +-+ | Argg 1(函数CC的第11个参数数) | +-+ | AArg 0(函函数C的的第0个个参数) | +-+ | EIPP (BB函数的的返回地地址) | +-+
18、 | EBPP (BB函数的的EBPP) | +-+ | Loccal Varriabbless | | . | +-+- 低地址址 图图 1-1 再分析析tesst1反反汇编结结果中剩剩余部分分语句的的含义: # mddb ttestt1 Loaadinng mmoduuless: liibc.so.1 maain:diis ; 反汇编编maiin函数数 mmainn: ppushhl %eebp mmainn+1: mmovll %eesp,%ebbp ; 创创建Sttackk Frramee(栈框框架) maain+3: subbl $8,%espp ; 通过EESP-8来分分配8字字节
19、堆栈栈空间 maain+6: anddl $0xff0,%espp ; 使栈地地址166字节对对齐 maiin+99: mmovll $00,%eeax ; 无无意义 maain+0xee: subbl %eaxx,%eesp ; 无意义义 mmainn+0xx10: mmovll $00,%eeax ; 设设置maain函函数返回回值 maiin+00x155: leaave ; 撤销SStacck FFramme(栈栈框架) mmainn+0xx16: rret ; mmainn 函数数返回 以下两两句似乎乎是没有有意义的的,果真真是这样样吗? mmovll $00,%eeax subbl
20、 %eaax,%espp 用ggcc的的O2级级优化来来重新编编译teest11.c: # gccc -O2 tesst1.c -o ttestt1 # mmdb tesst1 maiin:diss mmainn: puushll %ebbp maiin+11: mmovll %eesp,%ebbp maiin+33: ssubll $88,%eesp maain+6: anddl $0xff0,%espp mmainn+9: xoorl %eaax,%eaxx ; 设设置maain返返回值,使用xxorll异或指指令来使使eaxx为0 maain+0xbb: leaave maain+0xc
21、c: rett 新的反反汇编结结果比最最初的结结果要简简洁一些些,果然然之前被被认为无无用的语语句被优优化掉了了,进一一步验证证了之前前的猜测测。 提示:编译器器产生的的某些语语句可能能在程序序实际语语义上没没有用处处,可以以用优化化选项去去掉这些些语句。 问题:为什么么用xoorl来来设置eeax的的值? 注意意到优化化后的代代码中,eaxx返回值值的设置置由 mmovll $00,%eeax 变为 xorrl %eaxx,%eeax ,这是是因为IIA322指令中中,xoorl比比movvl有更更高的运运行速度度。 概念:Staack aliigneed 栈栈对齐 那么么,以下下语句到到底
22、是和和作用呢呢? suubl $8,%essp anddl $0xff0,%espp ; 通过过anddl使低低4位为为0,保保证栈地地址166字节对对齐 表表面来看看,这条条语句最最直接的的后果是是使ESSP的地地址后44位为00,即116字节节对齐,那么为为什么这这么做呢呢? 原来,IA332 系系列CPPU的一一些指令令分别在在4、88、166字节对对齐时会会有更快快的运行行速度,因此ggcc编编译器为为提高生生成代码码在IAA32上上的运行行速度,默认对对产生的的代码进进行166字节对对齐 anndl $0xxf0,%essp 的的意义很很明显,那么 subbl $8,%espp 呢,
23、是必须须的吗? 这这里假设设在进入入maiin函数数之前,栈是116字节节对齐的的话,那那么,进进入maain函函数后,EIPP和EBBP被压压入堆栈栈后,栈栈地址最最末4位位二进制制位必定定是 110000,essp -8则恰恰好使后后4位地地址二进进制位为为00000。看看来,这这也是为为保证栈栈16字字节对齐齐的。 如果查查一下ggcc的的手册,就会发发现关于于栈对齐齐的参数数设置: -mprrefeerreed-sstacck-bbounndarry=nn ; 希望栈栈按照22的n次次的字节节边界对对齐, n的取取值范围围是2-12 默认情情况下,n是等等于4的的,也就就是说,默认情情
24、况下,gccc是166字节对对齐,以以适应IIA322大多数数指令的的要求。 让我们们利用-mprrefeerreed-sstacck-bbounndarry=22来去除除栈对齐齐指令: # ggcc -mpprefferrred-staack-bouundaary=2 ttestt1.cc -oo teest11 maiin:diss mmainn: ppushhl %eebp maain+1: moovl %essp,%ebpp mmainn+3: mmovll $00,%eeax maain+8: leeavee mmainn+9: rret 可以看看到,栈栈对齐指指令没有有了,因因为,
25、IIA322的栈本本身就是是4字节节对齐的的,不需需要用额额外指令令进行对对齐。 那么么,栈框框架指针针SFPP是不是是必须的的呢? # gccc -mmpreeferrredd-sttackk-boounddaryy=2 -foomitt-frramee-poointter tesst1.c -o ttestt maiin:diss mmainn: mmovll $00,%eeax maain+5: reet 由此可可知,-fommit-fraame-poiinteer 可可以去除除SFPP。 问问题:去去除SFFP后有有什么缺缺点呢? 1)增加调调式难度度 由于SSFP在在调试器器bacc
26、ktrracee的指令令中被使使用到,因此没没有SFFP该调调试指令令就无法法使用。 22)降低低汇编代代码可读读性 函数数参数和和局部变变量的访访问,在在没有eebp的的情况下下,都只只能通过过+xxx(essp)的的方式访访问,而而很难区区分两种种方式,降低了了程序的的可读性性。 问问题:去去除SFFP有什什么优点点呢? 1)节节省栈空空间 2)减减少建立立和撤销销栈框架架的指令令后,简简化了代代码 3)使使ebpp空闲出出来,使使之作为为通用寄寄存器使使用,增增加通用用寄存器器的数量量 44)以上上3点使使得程序序运行速速度更快快 概念:Calllinng CConvventtionn
27、调调用约定定和 AABI (Apppliicattionn Biinarry IInteerfaace) 应用用程序二二进制接接口 函函数如何何找到它它的参数数? 函数数如何返返回结果果? 函数数在哪里里存放局局部变量量? 那一一个硬件件寄存器器是起始始空间? 那一个个硬件寄寄存器必必须预先先保留? Calllinng CConvventtionn 调调用约定定对以上上问题作作出了规规定。CCalllingg Coonveentiion也也是ABBI的一一部分。 因因此,遵遵守相同同ABII规范的的操作系系统,使使其相互互间实现现二进制制代码的的互操作作成为了了可能。 例例如:由由于Soola
28、rris、Linnux都都遵守SSysttem V的AABI,Sollariis 110就提提供了直直接运行行Linnux二二进制程程序的功功能。 详见见文章:关注: Soolarris 10的的10大大新变化化 3. 小结结 本本文通过过最简的的C程序序,引入入以下概概念: SSFP 栈框架架指针 SStacck aaliggnedd 栈对对齐 Caalliing Connvenntioon 调用约约定 和和 ABBI (Apppliccatiion Binnaryy Innterrfacce) 应用程程序二进进制接口口 今今后,将将通过进进一步的的实验,来深入入了解这这些概念念。通过过掌握
29、这这些概念念,使在在汇编级级调试程程序产生生的coore dummp、掌掌握C语语言高级级调试技技巧成为为了可能能。X86汇汇编语言言学习手手记(22)这是作者者在学习习X866汇编过过程中的的学习笔笔记,难难免有错错误和疏疏漏之处处,欢迎迎指正。作者将将随时修修改错误误并将新新的版本本发布在在自己的的Bloog站点点上。严严格说来来,本篇篇文档更更侧重于于C语言言和C编编译器方方面的知知识,如如果涉及及到基本本的汇编编语言的的内容,可以参参考相关关文档。 自XX86 汇编语语言学习习手记(1)在在作者的的Bloog上发发布以来来,得到到了很多多网友的的肯定和和鼓励,并且还还有热心心网友指指出
30、了其其中的错错误,b:bbea666dddae00作者者已经将将文档中中已发现现的错误误修正后后更新在在Bloog上。/bb:beea666ddaae0 上一篇篇文章通通过分析析一个最最简的CC程序,引出了了以下概概念: SStacck FFramme 栈栈框架 和 SSFP 栈框架架指针 SStacck aaliggnedd 栈对对齐 Caalliing Connvenntioon 调用约约定 和和 ABBI (Apppliccatiion Binnaryy Innterrfacce) 应用程程序二进进制接口口 本本章中,将通过过进一步步的实验验,来深深入了解解这些概概念。如如果还不不了解这
31、这些概念念,可以以参考 X866汇编语语言学习习手记(1)。 1. 局部部变量的的栈分配配 上篇文文章已经经分析过过一个最最简的CC程序, 下下面我们们分析一一下C编编译器如如何处理理局部变变量的分分配,为为此先给给出如下下程序: #vii teest22.c intt maain() innt ii; innt jj=2; i=33; i=+ii; reeturrn ii+j; 编译该该程序,产生二二进制文文件,并并利用mmdb来来观察程程序运行行中的sstacck的状状态: #ggcc tesst2.c -o ttestt2 #mddb ttestt2 Loaadinng mmoduuless: liibc.so.1 maain:diis maiin: puushll %ebbp maiin+11: moovl %essp,%ebpp ; maiin至mmainn+1,创建SStacck FFramme maiin+33: suubl $8,%essp ; 为局部部变量ii,j分分配栈空空间,并并保证栈栈