




下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、 c语言教学程序调试之汇编指令分析 摘要:为了提升大学生对c语言语法原理的理解,通过对比c语言语句与汇编指令,提出了一种在程序调试时使用汇编指令去理解分析c语言语法原理的方案。首先对c语言可执行程序的运行原理进行了介绍,然后介绍了jfe and gcc软件的调试功能,再然后区分了at&t与intel汇编指令的不同之处,最后就一个程序调试的实例进行了汇编指令分析。实验关于赋值语句的机器指令分析,验证了c语言在编译时确定局部变量的地址空间,实验体现了汇编指令分析有效、实用。关键词:c语言;可执行程序;jfe and gcc;汇编指令;程序
2、调试:tp312 :a:1009-3044(2020)29-0147-03程序设计语言(c)(或称为大学计算机a(2)是大中专院校大学一年级理工科学生的公共基礎必修课,该课程教学内容知识点繁多、逻辑思维抽象,对于刚进人大学的新生而言,存在一定的难度;教学时间一般为72课时,分18周进行,理论课时36个或40个,实践课时36个或32个。巨同升认为,讲授该门课程时纯粹以语法为导向,耗费了大量时间和精力,教学效果却不理想1。马金霞提倡翻转课堂教学法,其中提到“让学生来当老师,让学生主宰课堂”2,认为这样能够充分调动学生学习的主动性和积极性。当前的c语言程序设计教学存在“以语法为导向”与“以教学手段为
3、导向”这两个主要的方向。本文针对c语言的内涵,挖掘c语言与汇编指令的关联,提出一种在程序调试时使用汇编指令去理解分析c语言语法原理的教学方法。c语言是一种贴近人类自然语言的高级编程语言,c语言编写的源代码在经过编译软件预处理和汇编后,将被转化为汇编指令源代码,分析此汇编源代码,可以更好地理解c语言的语句代码如何展开执行。1 c语言可执行程序的运行原理c语言编写的可执行文件这样执行:首先,由c标准库函数(c运行时库)执行“启动代码”;紧接着,载人由程序员所编写代码转化而来的指令序列;然后,指令序列进入maln函数,这个mam函数是一个主控函数,它将按顺序执行指令序列,并且根据mam函数体的具体内
4、容调用其他函数,这些其他函数既有程序员自己编写的函数也有c语言标准库函数;再接着,mam函数将控制权移交给c语言标准库函数,再执行标准库函数中的“关闭代码”;关闭代码执行完毕后,它将控制权移交给操作系统3】。2 一个小巧易用的c编译软件jfe and gccjens' file editor( jfe),是新西兰梅西大学(massey univer-sity) albany校区科学(science)院计算机科学(computer sci-ence)系开发的一款软件,旨在为gcc c/c+编译器提供集成的开发环境。jfe是免费软件,随附的gcc和gdb是开源软件( open source
5、 software),编辑器采用g+ 2.95版本,适用于win-dows系列操作系统(operating system)下。使用jfe and gcc软件编写c语言源代码,不需要新建工程,只需要在保存时选择一个文件夹把文件保存为*.c文件(*为通配符,表示1到多个字符)。编写好代码,编译通过之后,点击run命令,debug执行开始。前进执行一条c语言语句,点击工具栏的step命令;前进执行一条汇编语句,点击工具栏的step asm inst命令。两个命令结合起来,再打开寄存器窗口和内存窗口,并且在内存窗口左上角的右侧带滚动条的address文本框中输入相应地址或者点击滚动按钮,可以很方便地观
6、察内存地址中所储存数值的变化。3 at&t与intel汇编指令不同之处当前,标准c语言运行在32位的保护模式下,分析汇编代码时主要用到的cpu(central processing unit中央处理器)寄存器分别为:4个数据寄存器(eax、ebx、ecx和edx),2个变址索引寄存器(esi和edi),2个指针寄存器(esp和ebp),1个指令指针寄存器(eip),1个标志寄存器(eflags)。jfe and gcc软件使用at&t linux操作系统汇编指令格式,与intel汇编指令格式大同小异,都是基于x86架构。它们之间的不同表现在:ci)at&t和intel格
7、式中的源操作数和目标操作数的位置正好相反,在intel汇编格式中,目标操作数在源操作数的左边,比如mov ebp,esp 而在at&t汇编格式中,目标操作数在源操作数的右边,比如mov %esp,%ebp。(2)在at&t汇编格式中,寄存器名要加上%作为前缀,比如push% ebp;而在intel汇编格式中,寄存器名不需要加前缀,比如push ebp。(3)在at&t汇编格式中,用$前缀表示一个立即操作数,比如mov $0x0,%eax;而在intel汇编格式中.立即数的表示不用带任何前缀,比如moveax,0。(4)在at&t汇编格式中,操作数的字长由操作符的
8、最后一个字母决定,后缀b、w、1分别表示操作数为字节(byte,8比特)、字(word,16比特)和长字(long,32比特),比如movb $ox5,%al;而在intel汇编格式中,操作数的字长用“byteptr”和“word ptr”等前缀来表示,比如mov al,byte ptr 5。(5)在at&t汇编格式中,绝对转移和调用指令(jump/call)的操作数前要加上*作为前缀,比如汇编指令ox401780: jmp *ox4050f0;而在intel格式中则不需要;远程转移指令和远程子调用指令的操作码,在at&t汇编格式中为“ljump”和“lcall”,而在inte
9、l汇编格式中则为“jmp far”和“call far”。(6)在at&t汇编格式中,内存操作数的寻址方式是section: disp(base,index,scale),而在intel汇编格式中,内存操作数的寻址方式为section:base+ index*scale+ disp,由于linux工作在保护模式下,用的是32位线性地址,计算地址时不用考虑段基址和偏移量,计算地址的方法为disp+ base+ index scalec4。4 c语言程序调试分析实例在此处,调试程序用到了一个叫作gdb (the gnu projectdebugger)的工具软件,它是gnu(gnu s n
10、ot unix!的递归缩写)下的项目( project)调试器(debugger),遵循自由软件基金会( free software foundation)的gnu通用公共许可证(gnu gen-eral public license.gpl),使用它可以查看另一个程序在执行过程中正在执行的操作,或该程序崩溃时正在执行的操作。程序设计思路:定义两个变量,然后使用调试模式查看其内存的分配。当前测试环境:windows 7旗舰版64位,内存12gb,jfe软件2004版内含gnu gdb 6.0。c语言源代码:int main0 int i,j; i=l;j=2; return 0;)在jfe软件
11、环境中调试程序,分三个步骤进行。第一步,在jfe and gcc软件中编辑代码;第二步,点击compiler菜单下的compile命令按钮,点击view菜单下的output命令按钮,查看编译系统的输出信息,若是output窗口的最后一行出现suc-cess,则顺利通过编译。第三步,点击run命令,debug执行开始,点击source window窗口中工具行第一个深蓝色的跑步形状run按钮,跳出一个窗体内容全为黑色的控制台(console)窗口,表明调试程序(gdb)已经开始执行,再在当前窗口右上角source mode下拉按钮中选择mixed,即可展现程序清单4.1所列代码内容,它们是c语言
12、源代码与指令地址、at&t汇编代码的混合编排。4.1 程序清单1 int main0一0x4012d0: push %ebp一0x4012dl : mov %esp,%ebp(此處省略10行)一0x4012f5: call ox4014202inti,j;3i=1:j_2;一0x4012fa: movl$oxl,oxfffffffc(%ebp)一0x401301: movl $ox2,oxfffffff8(%ebp)4retum 0:一0x401308: mov $oxo,%eax一0x40130d: leave一0x40130e: ret可以看到gdb软件执行至ox4012f5处,等
13、待响应。点击工具行芯片图形模样按钮,打开registers窗口,可以看到,基址寄存器( ebp)的值为ox28ff58,0x表示采用16进制整数。call 0x401420中的一mam函数是标准c运行库的一个函数,负责完成库函数的初始化和初始化应用程序执行环境,最后自动跳转到main0,这里可以使用点击step单步执行c语言跳过其汇编指令执行细节,调试程序执行至ox4012fa处,点击memory命令按钮打开内存(memory)窗口,在内存窗口左上角address文本框中输入相应地址ox4012fa后按下回车键,可以看到地址ox401300(高地址)至ox4012fa(低地址)地址空间的值ox
14、 00 00 0001fc 45 c7,其对应的机器指令为ox c7 45fc 00 00 00叭。数据书写和存储的原则为“高高低低”,即高地址空间存储高(书写在左边)字节数值,低地址空间存储低(书写在右边)字节数值,而指令的存储从低字节到高字节。紧挨在一起的00 00 00叭是一个整体,表示16进制数值oxl,即10进制数值1.0x c7 45 fc 00 00 00 01是一个机器指令,对应的汇编助词符movl $oxl,oxfffffffc(% ebp),打开intel手册(intelan:hitecture software developer's manual volume
15、2:instructionset reference,1997),查看指令格式(原文figure 2-1. intel ar-chitecture instruction format),再打开手册第3.2章instruc-tion reference3-286页查看mov指令,得知这个机器指令采用16进制值c7 10作为第一字节编码,汇编助记符写为mov rlm32,imm32,解释为move imm32 to r/m32.imm32表示32位二进制数值,r/m32表示32位宽度的寄存器或内存空间,/0是/digit的具体数值,表示这个机器指令的操作码(opcode)除了第一字节值c7之外,
16、还有补充的额外3个二进制位作为补充opcode,这三个位是modr/m中的reg/opcode,包含在第二字节值45之中。第二字节是modr/m字节,它包含三个域:mod,reg/opcode,r/m。mod占2位,由于这个指令使用寄存器相对寻址,查表得知,mod域的二进制值为01;reg/opcode占3位,由这个指令的第一字节值c7 10看出,当前reg/opcode域是对前面第一字节的opcode进行补充,所以这里用到的是opcode而不是reg,又由前面的opcode值c7 10得知opcode值为0,所以reg/opcode域的二进制值为000;r/m占3位,结合机器指令中的16进制
17、值fc(即二进制值11111100),确定在intel手册第36页中的表格(table2-2. 32-bit addressing forms with the modr/m byte)中应为disp8ebp行,又由c7 10中的/0(/digit)确定,应为digit取值为0这列。modr/m字节16进制值45展开为二进制值01 000 101,完全符合所述分析过程。16进制数值oxffff fffc翻译成二进制数值为1111 1111 1111 1111 1111 1111 1111 1100.最高的符号位若是1表示负数,若是0表示正数(0只有正0,没有负0),负数在约翰·冯
18、183;诺依曼(john von neumann)结构的微机中采用补码表示,根据补码与原码相互转换的规则:最高(书写在最左边)的符号位不变,取反加1;或者根据补码自身逻辑意义的完整性,不必理会符号位,对所有位取反加1。该数的二进制原码为1000 0000 0000 0000 0000 0000 0000 0100,也可用补码oxfffffffc减去模oxl 0000 0000以数学运算方式(速度更快)得到- 0x4(即10进制数值-4)。点击寄存器按钮,查看到基址指针寄存器ebp的值为ox28ff58,减去ox4得到ox28ff54;点击存储器按钮查看memory状态,在左上角的文本框输入ox
19、28ff54之后回车,先看看里面存放的值是什么,然后点击工具栏的step asminst按钮让其单步执行一条指令,再次回到memory窗口查看0x28ff'54开始的4个字节宽度地址空间的值,发现已经变成了0x0000 0001,即已经执行了movl $oxl,0xfffffffc(% ebp)汇编指令,对照c语言源代码,对应i=l;这条语句,由此知道,i变量的地址为ox28ff54;此时,调试程序顺序执行至ox40130l: movl $ox2,oxfffffff8(%ebp)这一行,同样的分析可知,起始地址为ebp -8即ox28ff50开始连续的4个字节地址空间的值将会被修改为o
20、x2,对应c语言源代码j=2;这条语句。将c语言源程序修改为int main()( int i,j;j=2; i=l;return0.即将j的赋值语句放到i的赋值语句之前,同樣地,启动调试程序,摘录混合代码片段如程序清单4.2所示。4.2 程序清单ox4012f5: call ox4014202inti.j;3_j=2; i=l;一 ox4012fa: movl $ox2,oxfffffff8(%ebp)一ox401301: movl $oxl,oxfffffffc(%ebp)检查发现,交换i,i赋值顺序后,编译系统对i,j的赋值指令不变,即i=l;语句的赋值指令仍为movl$oxl,0xff
21、fffffc(%ebp),而j=2;语句的赋值指令仍为movl$ox2,0xfffffffb(%ebp)。这里需要提到程序运行时函数帧栈的原理,栈是程序在运行时进行数据存储的一段动态内存空间,其地址分配从高到低,它采取先进后出的原则对数据进行存取,这里的数据从宏观层面来看就是一个个的函数帧栈,每个函数作为一帧( frame),依次进入栈( stack)区,每个帧包含:当前函数的返回地址、函数调用链上个函数的基础地址、局部变量、函数调用链下个函数的实参。c语言程序从源代码文件至可执行文件,需要4个阶段,分别为预处理、汇编、编译、链(连)接,这4个阶段分别可以使用命令行命令来实现,通常在可视化编译软件中使用的编译包含了预处理、汇编和编译这3个阶段。c语言规定,程序需要先编译再连接后运行,程序运行所需空间在编译阶段确定。栈是一块连续的内存区域,栈顶的地址和栈的最大容量由编译系统在编译时确定,栈顶是数据出入的地方。根据实验,通过对汇编指令的分析,可以确定,编译系统在对函数进行编译时,会按照先定义的变量先分配内存的原则部署函数的局部变量,一旦分配了内存,变量就确定了它所代表的内存空间,这个空间里原来会有一个值,而赋值语句则是修改这个内存空间的值。一条c语句通常对应多条汇编指令,通过逐条分析汇编指令,可以最真实地还原cpu的工作细节。在教师的合理指导下,程序调试过程中出现的汇
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 教师招聘之《小学教师招聘》强化训练模考卷带答案详解(轻巧夺冠)
- 押题宝典教师招聘之《小学教师招聘》模考模拟试题含答案详解【达标题】
- 2025年教师招聘之《小学教师招聘》题库必背100题附完整答案详解【典优】
- 2025年教师招聘之《幼儿教师招聘》通关题库及答案详解(真题汇编)
- 教师招聘之《幼儿教师招聘》综合提升练习试题及答案详解【有一套】
- 教师招聘之《小学教师招聘》过关检测试卷及完整答案详解(名师系列)
- 危险废物环境执法检查要点培训
- 合并高校内部会计控制优化路径探索-以A大学为例
- 节气课件教学
- 企业员工廉洁举报与奖励协议
- T/CECS 10021-2019照明用LED驱动电源技术要求
- 2025年北京市东城区九年级初三一模英语试卷(含答案)
- 2024-2030全球中子刀(锎252中子源自动遥控式后装治疗系统)行业调研及趋势分析报告
- 十一学校小升初入学测试数学真题及详细解答
- 安全课件自我保护
- 资金共管协议书范本
- 大班主题:标志小家族
- 检验科复检制度及记录
- 养老院薪酬管理体系-
- 华为AAU规格标准手册-5G
- 2025年华侨港澳台学生联招考试英语试卷试题(含答案详解)
评论
0/150
提交评论