汇编夜读 第一篇
来源:互联网 发布:店铺淘宝客软件有哪些 编辑:程序博客网 时间:2024/09/21 09:27
好多东西不太清楚,于是就想窥探一下程序内部运行的究竟,于是有了以下的文章
一、从空函数探究
vim learn.c
什么也不写
gcc -S learn.c
查看learn.s中内容如下:
----------------------------------------------------------------------------------
1 .file "learn.c"
2 .ident "GCC: (GNU) 4.1.2 20070925 (Red Hat 4.1.2-33)"
3 .section .note.GNU-stack,"",@progbits
----------------------------------------------------------------------------------
写了如下代码
int main(){}
gcc -S learn.c
查看learn.s中内容如下:
----------------------------------------------------------------------------------
1 .file "learn.c"
2 .text
3 .globl main
4 .type main, @function
5 main:
6 leal 4(%esp), %ecx
7 andl $-16, %esp
8 pushl -4(%ecx)
9 pushl %ebp
10 movl %esp, %ebp
11 pushl %ecx
12 popl %ecx
13 popl %ebp
14 leal -4(%ecx), %esp
15 ret
16 .size main, .-main
17 .ident "GCC: (GNU) 4.1.2 20070925 (Red Hat 4.1.2-33)"
18 .section .note.GNU-stack,"",@progbits
----------------------------------------------------------------------------------
增加了从行2-16的代码。
可以看出11-12 有一个pushl %ecx,并接着popl %ecx的过程
类似的,又将learn.c中内容改成如下:
int min(){}
gcc -S learn.c
查看learn.s中内容如下:
----------------------------------------------------------------------------------
1 .file "learn.c"
2 .text
3 .globl min
4 .type min, @function
5 min:
6 pushl %ebp
7 movl %esp, %ebp
8 popl %ebp
9 ret
10 .size min, .-min
11 .ident "GCC: (GNU) 4.1.2 20070925 (Red Hat 4.1.2-33)"
12 .section .note.GNU-stack,"",@progbits
----------------------------------------------------------------------------------
同上例相比,learn.s中的内容少了好多。同样的都是定义一个空函数,main()函数汇编后的代码要比普通函数多,这也说明了main函数的特殊性
若将learn.c中内容改为如下
void min(){}
gcc -S learn.c
可以发现learn.s中的内容没有变化
改为
double min(){}后learn.s中的内容倒是变化不少,增加了
----------------------------------------------------------------------------------
4 .LC0:
5 .long 2143289344
...
11 movl %esp, %ebp
12 flds .LC0
13 popl %ebp
----------------------------------------------------------------------------------
具体意义暂时不懂。
从上面3段.s代码中可以看到第1行,和最后两行都是完全相同的,倒数第3行和函数名称有关。
2-4行的代码格式也基本类似
对于main()函数,在压榨push %ebp之前,有如下操作:
6 leal 4(%esp), %ecx
7 andl $-16, %esp
8 pushl -4(%ecx)
其意义尚未理解。
二、变量声明
将learn.c中内容改为如下
int min(){int a;}
gcc -S learn.c
可以发现learn.s中的内容如下:
----------------------------------------------------------------------------------
5 min:
6 pushl %ebp
7 movl %esp, %ebp
8 subl $16, %esp
9 leave
10 ret
----------------------------------------------------------------------------------
即定义了变量a后,汇编代码中对应的片段为第8行,而且此时不再执行pop %ebp,而是用一条leave指令代替。
将learn.c中内容改为如下
int main(){int a;}
可以发现learn.s中的内容相比原来的空main()函数在11行之后多了两行代码:
----------------------------------------------------------------------------------
10 movl %esp, %ebp
11 pushl %ecx
12 subl $16, %esp
13 addl $16, %esp
14 popl %ecx
...
----------------------------------------------------------------------------------
进一步修改main()为
int main(){int a,b;}
可以发现learn.s中的内容没有变化。这是什么意思?
继续修改
int main(){int a,b,c;}
发现learn.s中的内容还是没有变化,但是,subl %16,%esp是将栈顶下移了16个字节,估计我们只要声明4个以上的整形变量就会不一样吧
int main(){int a,b,c,d,e;}
果然,此时learn.s中的代码变为
----------------------------------------------------------------------------------
12 subl $32, %esp
13 addl $32, %esp
----------------------------------------------------------------------------------
这个发现还是比较有价值滴,暂且记下。
继续修改
int main(){double a;}
此时learn.s中的代码变为
----------------------------------------------------------------------------------
12 subl $20, %esp
13 addl $20, %esp
----------------------------------------------------------------------------------
即声明double类型变量时,栈顶位置会向下移动20个字节,我们知道double是8个字节,那么生命
超过3个double变量,20个字节就不够用了,所以
继续修改
int main(){double a,b,c;}
汇编后learn.s如下:
----------------------------------------------------------------------------------
12 subl $36, %esp
13 addl $36, %esp
----------------------------------------------------------------------------------
呵呵,变成36了,挺有意思的。突然想起来,这是不是就是用C语言写代码时变量生命必须放在函数罪
前面的原因呢,因为栈顶会根据定义变量的总和以决定下移合适的位置。我想应该是这个原因吧,呵呵
,貌似又发现了一个小秘密。
继续修改
int main(){double a;int b;}这个仔细想象也觉得应该是首先指定20个字节,验证后果然如此
三、变量定义
将learn.c中内容改为如下
int main(){int a = 3;}
汇编后learn.s如下:
----------------------------------------------------------------------------------
12 subl $16, %esp
13 movl $3, -8(%ebp)
14 addl $16, %esp
----------------------------------------------------------------------------------
就13行发生了变化,其他行不变。$3,很容易理解,就是立即数3的意思,-8(%ebp)呢,为什么用原来
栈顶位置-8呢,既然分配了16个字节,-8是不是跟数立即数的大小有关,将3改为256,发现没有变化,哎,失败,看来不是这个原因,暂且记下这个问题。
继续修改
int main(){int a = 3;int b = 4;}
汇编后learn.s如下:
----------------------------------------------------------------------------------
12 subl $16, %esp
13 movl $3, -12(%ebp)
14 movl $4, -8(%ebp)
15 addl $16, %esp
----------------------------------------------------------------------------------
这样跟上面的一对比,好像明白了。
继续修改
int main(){int a = 3;int b = 4;int c = 5;}
汇编后learn.s如下:
----------------------------------------------------------------------------------
12 subl $16, %esp
13 movl $3, -16(%ebp)
14 movl $4, -12(%ebp)
15 movl $5, -8(%ebp)
16 addl $16, %esp
----------------------------------------------------------------------------------
可见-8(%ebp)到%ebp的8个位置是备用的。具体用作什么,估计慢慢就明白了。
继续修改
int main(){int a = 3;int b = 4;b = a;}
汇编后learn.s如下:
----------------------------------------------------------------------------------
13 movl $3, -12(%ebp)
14 movl $4, -8(%ebp)
15 movl -12(%ebp), %eax
16 movl %eax, -8(%ebp)
----------------------------------------------------------------------------------
15,16行是对应的赋值语句。
玩了半天,感觉挺有意思的,自己不明白什么就去研究一下,应该能逐渐找到答案的。
- 汇编夜读 第一篇
- 第一篇汇编文章(基于8086)
- 【汇编】学习笔记——第一篇
- HLA高级汇编 进入高级汇编语言的世界 第一篇
- 第一篇 自制内核的环境、汇编器、编译器选择
- s3c2440 ARM9 裸机驱动第一篇-GPIO驱动(汇编)
- 第一篇。
- 第一篇
- 第一篇
- 第一篇
- 第一篇
- 第一篇
- 第一篇
- 第一篇
- 第一篇
- 第一篇
- 第一篇
- 第一篇
- 解密慈善家为何“难当”?
- 无法向会话状态服务器发出会话状态请求请。确保 ASP.NET State Service (ASP.NET 状态服务)已启动
- 学java得这样学,学习东西确实也得这样【转】
- 转帖--如何在Linux使用Eclipse + CDT开发C/C++程序?
- Visual Studio 2005 中的新增安全性功能
- 汇编夜读 第一篇
- 关于头文件
- css中display与visibility的不同
- 表达式求值的程序
- 声明与函数、函数指针 (*(void (*)( ) )0)( )
- 找个仿站高手,谁来接,重酬!重酬!重酬!重酬!
- filemarge
- oracle 笔记 II 之DML:数据操作语言
- n皇后问题