主题:[讨论]C语言跟汇编,指点下新手
rickone [专家分:15390] 发布于 2006-07-03 10:56:00
最近学了下汇编,然后老拿VC的disassembly看目标码,感觉像看到了C到底是怎样做的,蛮爽的感觉
打开VC
写个简单的程序:
int f(int a,int b)
{
int c=1;
return a+b/c;
}
int main(void)
{
int a=1;
f(a,100);
return 0;
}
编译,连接,然后进入debug,然后点disassembly看目标代码:
6: int main(void)
7: {
00401060 push ebp
00401061 mov ebp,esp //从这句知道ebp堆栈段基址是相对的
00401063 sub esp,44h //为什么开这么大的存储?
00401066 push ebx //为什么要保护ebx?这个寄存器有啥用?
00401067 push esi //同上
00401068 push edi //同上
00401069 lea edi,[ebp-44h]
0040106C mov ecx,11h
00401071 mov eax,0CCCCCCCCh //而且还全部初始化成这个值,WHY?
00401076 rep stos dword ptr [edi]
8: int a=1;
00401078 mov dword ptr [ebp-4],1
9: f(a,100);
0040107F push 64h
00401081 mov eax,dword ptr [ebp-4]
00401084 push eax //从这里看出是从右往左填参数
00401085 call @ILT+0(f) (00401005)
0040108A add esp,8
10: return 0;
0040108D xor eax,eax //从这句看,函数返回值放在eax,固定的吗?
11: }
0040108F pop edi
00401090 pop esi
00401091 pop ebx
00401092 add esp,44h
00401095 cmp ebp,esp
00401097 call __chkesp (004010b0)//这一句啥意思?
0040109C mov esp,ebp
0040109E pop ebp
0040109F ret
我对要保护的寄存器不太明白,感觉高级语言面向的是存储器,就算是register变量也只是推荐性,寄存器在程序员眼中是透明的,那所有的语句都是寄存器独立的,按理可以不用保护,除非有特殊用途.
回复列表 (共9个回复)
沙发
int0x080 [专家分:90] 发布于 2006-07-03 19:28:00
我想是和编译器有关的,如下
[code]
.file "test.c"
.text
.p2align 2,,3
.globl f
.type f, @function
f:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $1, -4(%ebp)
movl 12(%ebp), %edx
leal -4(%ebp), %eax
movl %eax, -8(%ebp)
movl %edx, %eax
movl -8(%ebp), %ecx
cltd
idivl (%ecx)
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
addl 8(%ebp), %eax
leave
ret
.size f, .-f
.p2align 2,,3
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
movl $1, -4(%ebp)
pushl $100
pushl -4(%ebp)
call f
addl $8, %esp
movl $0, %eax
leave
ret
[/code]
板凳
rickone [专家分:15390] 发布于 2006-07-03 20:36:00
楼上这是哪种汇编呀,我学的是80x86的,不过还是看得大部分懂~~:)
3 楼
int0x080 [专家分:90] 发布于 2006-07-03 21:07:00
*^_^*,,我也是80x86的,这是AT&T的语法,我是用楼主的C程序,然后用gcc生成的汇编码的
4 楼
aboutbmp [专家分:830] 发布于 2006-07-03 21:15:00
main开始处多开的40h内容确实是编译器相关的,可能目的是为了方便发生堆栈访问错误时的调试吧,这一段东西似乎在release版本下就没有了?
main函数也是一个普通的函数,在函数中用到的寄存器在使用前都必须把它们的值保存起来,这是汇编写子函数的一个基本要求;
用eax存放函数返回值似乎是个通用的约定,至少所有windows API都遵从这一点;
call __chkesp就是一个普通的函数调用,作用是检查esp的值,可以试着跟踪进去的。
5 楼
rickone [专家分:15390] 发布于 2006-07-03 22:12:00
像eax使用的时候就不用保护起来呀,我觉得需要保护的不仅是要用的,而是调用它之前没有正在用的,而C++是高级语言,没有面向寄存器,任何一句高级语言的表达式都是面向存储器的,在调用子函数的时候就没有哪个寄存器在使用啊,除非有特别的功能,我这样想。是吗?
6 楼
chenzep [专家分:3640] 发布于 2006-07-03 23:32:00
建议用DASM反汇编一个C语言(不是C++)写的最简单的程序:
main()
{}
看看。
反汇编的结果肯定比你上面的详细。
7 楼
rickone [专家分:15390] 发布于 2006-07-03 23:46:00
6楼什么意思?
用VC,disassembly看的不是目标程序吗?如果说反汇编得更详细,应该是更具体吧,细心的人会发现VC反汇编的左边的地址对应每一句指令并不是等长的,有的指令可能比较‘长’,有的‘短’些。
我想知道的重点是,为什么要保护那三个寄存器?
8 楼
aboutbmp [专家分:830] 发布于 2006-07-04 10:56:00
你可以这么理解:C语言是帮助你开发汇编的工具,你用C写了一个函数,C编译器帮助生成对应的汇编代码,根本的还是产生一个汇编形式的函数。
在函数实际执行的过程中,始终需要使用寄存器的。并不是说用C开发的程序执行的时候就不用寄存器,只是在C代码的层面看不到也不需要关心寄存器的问题而已。
至于eax,约定了用它来保存返回值,即使需要保护它的值,也是调用者在调函数前做的事,而不是函数内部要做的。
9 楼
chenzep [专家分:3640] 发布于 2006-07-04 12:29:00
你看一下WIN32汇编,他们在调用的过程的时候一般都是保存EBX,ESI,EDI的,EAX一般是用来返回参数。
从系统的角度来看,MAIN也是系统的一个子过程。
更具体的话就要涉及操作系统的中断系统了,这个太复杂了。
我来回复