How program works
1.gdb常用调试命令
要用gdb调试的话,编译命令需要添加-g参数,例如
- gcc -g main.c -o main
b linenum 在第 linenum行打断点
l 显示源代码;
Ctrl-d 退出gdb
where 显示当前程序运行位置
print /d $eax 十进制地方式打印$eax 值,/x是十六进制,/t是二进制
c 执行到下一个断点
n 下一行
layout split 把当前Terminal分割成两半,上面显示源码及汇编,下面可以输入调试命令,效果如下:
2.Example.c程序分析
程序代码:
- #include <stdio.h>
- intg(intx)
- {
- returnx+3;
- }
- intf(intx)
- {
- returng(x);
- }
- intmain(void)
- {
- printf("Hello\n");
- returnf(8)+1;
- }
将源代码编译为二进制文件又需要经过以下四个步骤:预处理(cpp) → 编译(gcc或g++) → 汇编(as) → 链接(ld) ;括号中表示每个阶段所使用的程序,它们分别属于 GCC 和 Binutils 软件包。
用gcc的编译参数和生成的对应文件。
2.1预编译
- gcc -E Example.c -o Example.cpp
生成的cpp文件内容如下:
- ...
- ...
- ...
- //a lot of extern statement
- externchar*ctermid (char*__s) __attribute__ ((__nothrow__ , __leaf__));
- # 910 "/usr/include/stdio.h" 3 4
- externvoidflockfile (FILE*__stream) __attribute__ ((__nothrow__ , __leaf__));
- externintftrylockfile (FILE*__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
- externvoidfunlockfile (FILE*__stream) __attribute__ ((__nothrow__ , __leaf__));
- # 940 "/usr/include/stdio.h" 3 4
- # 2 "Example.c" 2
- intg(intx)
- {
- returnx+3;
- }
- intf(intx)
- {
- returng(x);
- }
- intmain(void)
- {
- returnf(8)+1;
- }
主要代码基本没有变化,添加了很多extern声明。
分析
预编译的主要作用如下:
●将源文件中以”include”格式包含的文件复制到编译的源文件中。
●用实际值替换用“#define”定义的字符串。
●根据“#if”后面的条件决定需要编译的代码。
在该阶段,编译器将C源代码中的包含的头文件stdio.h编译进来,生成扩展的c程序。当对一个源文件进行编译时, 系统将自动引用预处理程序对源程序中的预处理部分作处理, 处理完毕自动进入对源程序的编译。
2.2编译
执行编译的结果是得到汇编代码。
- gcc -S Example.c -o Example.s
生成.s文件内容如下:
- .file "Example.c"
- .text
- .globl g
- .type g, @function
- g:
- .LFB0:
- .cfi_startproc
- pushl %ebp ;ebp寄存器内容压栈
- .cfi_def_cfa_offset 8
- .cfi_offset 5, -8
- movl %esp, %ebp ;esp值赋给ebp,设置函数的栈基址。
- .cfi_def_cfa_register 5
- movl 8(%ebp), %eax ;将ebp+8所指向内存的内容存至eax
- addl $3, %eax ;将3与eax中的数值相加,结果存至eax中
- popl %ebp ;ebp中的内容出栈
- .cfi_restore 5
- .cfi_def_cfa 4, 4
- ret
- .cfi_endproc
- .LFE0:
- .size g, .-g
- .globl f
- .type f, @function
- f:
- .LFB1:
- .cfi_startproc
- pushl %ebp ;ebp寄存器内容压栈
- .cfi_def_cfa_offset 8
- .cfi_offset 5, -8
- movl %esp, %ebp ;esp值赋给ebp,设置函数的栈基址。
- .cfi_def_cfa_register 5
- subl $4, %esp ;esp下移动四个单位
- movl 8(%ebp), %eax ;将ebp+8所指向内存的内容存至eax
- movl %eax, (%esp) ;将eax存至esp所指内存中
- call g ;调用g函数
- leave ;将ebp值赋给esp,pop先前栈内的上级函数栈的基地址给ebp,恢复原栈基址
- .cfi_restore 5
- .cfi_def_cfa 4, 4
- ret ;函数返回,回到上级调用
- .cfi_endproc
- .LFE1:
- .size f, .-f
- .globl main
- .type main, @function
- main:
- .LFB2:
- .cfi_startproc
- pushl %ebp ;ebp寄存器内容压栈
- .cfi_def_cfa_offset 8
- .cfi_offset 5, -8
- movl %esp, %ebp ;esp值赋给ebp,设置函数的栈基址。
- .cfi_def_cfa_register 5
- subl $4, %esp ;esp下移动四个单位
- movl $8, (%esp) ;将8存入esp所指向的内存空间
- call f ;调用f函数
- addl $1, %eax ;将1与eax的内容相加
- leave ;将ebp值赋给esp,pop先前栈内的上级函数栈的基地址给ebp,恢复原栈基址
- .cfi_restore 5
- .cfi_def_cfa 4, 4
- ret ;函数返回,回到上级调用
- .cfi_endproc
- .LFE2:
- .size main, .-main
- .ident "GCC: (SUSE Linux) 4.7.1 20120723 [gcc-4_7-branch revision 189773]"
- .section .comment.SUSE.OPTs,"MS",@progbits,1
- .string "ospwg"
- .section .note.GNU-stack,"",@progbits
分析
第1行为gcc留下的文件信息;第2行标识下面一段是代码段,第3、4行表示这是g函数的入口,第5行为入口标号;6~20行为 g 函数体,稍后 分析;21行为 f 函数的代码段的大小;22、23行表示这是 f 函数的入口;24行为入口标识,25到41为 f 函数的汇编实现;42行为f函数的代码段的大小;43、44行表示这是main函数的入口;45行为入口标识,46到62为main函数的汇编实现;63行为main函数的代码段的大小;54到67行为 gcc留下的信息。
具体程序运行时内存的调用情况如下图:
以.cfi开头的命令如.cfi_startproc,主要用于作用是出现异常时stack的回滚(unwind),而回滚的过程是一级级CFA往上回退,直到异常被catch。
这里不做讨论,需要详细了解的点这里。
每一个函数在开始都会调用到
- pushl %ebp ;ebp寄存器内容压栈,即保存函数的上级调用函数的栈基地址
- movl %esp,%ebp ;esp值赋给ebp,设置函数的栈基址
主要作用是保存当前程序执行的状态。
还有两句在函数调用结束时也会出现:
- leave ; 将ebp值赋给esp,pop先前栈内的上级函数栈的基地址给ebp,恢复原栈基址
- ret ; 函数返回,回到上级调用
用于在函数执行完后回到执行前的状态。
还有要注意的是汇编中的push和pop
pop系列指令的格式是:
pop destination
pop指令把栈顶指定长度的数据存放到destination中,并且设置相应的esp的值使它始终指向栈顶位置。
push刚好相反。
pushl %eax 等价于
subl $4 %esp
movl %eax (%esp)
popl %eax 等价于
movl (%esp) %eax
addl %4 %esp
2.3汇编
汇编之后得到的是.o文件,终端执行命令:
- as Example.s -o Example.o
在终端用vim打开:
- vim -b Example.o
用16进制进行查看,在vim中输入
- :%!xxd
结果如下(未完全显示)
分析
目标文件就是源代码编译后但未进行链接的那些中间文件,包含有编译后的机器指令代码,还包括链接时所需要的一些信息,比如符号表、调试信息、字符串等。
可以查看目标文件的信息,在终端执行
- file Example.o
得到:
Example.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
其中的relocatable指出该文件为ELF中的可重定位文件类型。
2.4链接
链接后的文件为可执行文件,在linux中没有扩展名。
终端执行:
- gcc Example.o -o Example
执行Example,终端运行:
- ./Example
运行结果:
、
分析
用file命令查看Example属性:
- file Example
Example: ELF 32-bit LSB executable , Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, BuildID[sha1]=0xffdc8de348d59ce38f1f933e55b7a5c55184ef39, not stripped
其中的executable指出该文件为ELF中的可执行文件类型。
由于程序没有任何打印语句,所以程序执行完之后就直接退出了。
3.计算机工作流程-单任务和多任务
How program works相关推荐
- 开源(Open Source)那些事儿 (一)
景 最近有幸参与了王克伟的开源项目iToday,详情可以参考 我在Windows嵌入式系统上的一个绚丽用户界面开源项目(iToday).克伟的号召力超人,Q群一下子就爆满200人.如果扩容了,大家有兴 ...
- 要求用户提供输入,直到他们给出有效的答复
本文翻译自:Asking the user for input until they give a valid response I am writing a program that accepts ...
- MSIL 教程(二):数组、分支、循环、使用不安全代码和如何调用Win32 API(转)...
转自:http://www.cnblogs.com/Yahong111/archive/2007/08/16/857574.html 续上文[翻译]MSIL 教程(一) ,本文继续讲解数组.分支.循环 ...
- ssh tunnel 上网
用DNS隧道实现免费上网 大多数机场.酒店之类场所,当你输入一个网址比如www.google.com时,会弹出一个页面要你输入帐号密码才能上网.这个时候DNS能正确解析,但是上网要付费认证. 可以通过 ...
- winpcap编程 解析数据包
WinPcap和Libpcap的最强大的特性之一,是拥有过滤数据包的引擎. 它提供了有效的方法去获取网络中的某些数据包,这也是WinPcap捕获机制中的一个组成部分. 用来过滤数据包的函数是 pcap ...
- 软件分类:自由软件、开放源代码软件、公共软件、私有软件、版权所无软件...
自由软件(free software) "Free software" means software that respects users' freedom and commun ...
- qpython怎么用matplotlib_python-通过文本框的交互式matplotlib图
我正在尝试创建具有三个参数变化的多维函数的交互式matplotlib图.问题在于参数可以在很大的范围内变化,因此我宁愿不使用滑块,而直接键入想要的值.基本上,我想重新创建下面的规范示例,在该示例中,我 ...
- ui设计未来十年前景_UI设计的10条诫命
ui设计未来十年前景 重点 (Top highlight) The year is approximately 1,300 BC when Moses received the 10 UI desig ...
- php字符串反转函数_PHP | 反转给定的字符串而不使用库函数
php字符串反转函数 Given a string and we have to reverse it without using a library function. 给定一个字符串,我们必须不使 ...
最新文章
- 程序猿的节日:1024,今天祝愿全球所有程序猿们、IT精英们节日快乐!——我在上海写代码
- 花椒web端实时互动流媒体播放器
- SAP IBASE category 01 download
- mybatis学习(23):分页1 多参数传递(索引方式)
- IDEA中 @override报错的解决方法
- windows上的一些命令和工具
- Git笔记(27) 储藏与清理
- 报表中表达式的全局集合(Visual Studio 报表设计器)
- python官网的软件-python
- 编程基本功:给不同的电脑贴标
- (LINPACK)HPL测试成功步骤整理
- mysql加载audit失败_MySQL5.5 安装mcafee mysql-audit插件 不成功
- 微信内嵌浏览器打开手机浏览器下载APP(APK)的方法
- 2022年下半年软考报名时间陆续公布(持续更新)
- 基于JavaScript+css写一个简单的h5动态下雨效果
- Java GridBagLayout(网格包布局管理器)
- mysql主从同步的三种模式
- 移位运算符(<<、>>和>>>)
- vue 安装不上,报错,解决办法如下
- 大疆Tello编队飞行教程(特洛教育版)/多机视频流获取