分析简单的c语言函数编译得到的X86汇编代码(VS2013)

叁歲伎倆 2022-04-05 11:29 402阅读 0赞

查看源代码生成的汇编代码:单步调试->调试->窗口->反汇编

总结:

①、函数被调用时,实参值赋值给函数栈中的形参,使用以下步骤:

I、call函数前实参值压栈

II、函数中分配局部变量的代码执行完

III、使用原始栈顶值 ebp 的正偏移量(实参),和负偏移量(形参),配合mov指令来实现值传递,如:

mov [ebp,ebp-3] [ebp+16,ebp+13] //计算时不可遗漏了栈中 push pc 和 push ebp带来的esp变化

②、vc编译c源代码时,给函数中的临时变量在栈中分配的存储区域,不是根据临时变量的多少制定的,而是一个固定值 204B

③、vc在栈中给函数中临时变量分配存储单元后,会执行一系列汇编代码,给这些存储单元赋上初始值,本例中每个字节都是十六进制 0xcc ; 执行完赋初始值操作后,才开始进行实参形参值传递

④、vc函数中的临时变量包括以下种类: ①、函数形参 ②、函数体内定义的临时变量 ③、函数返回值

⑤、本例子中 sum 函数的返回值使用 寄存器eax来传递; 一般化的适用于所有情况的函数返回值要使用栈来传递给调用本函数的代码吧。

c源代码:

int sum(int a, int b)
{
int c = a + b;
return c;
}

int main()
{
int a = 2, b = 3;
int c = 0;
c=sum(a, b);
return 1;
}

汇编代码:

int sum(int a, int b)
{
00E813C0 push ebp ;ebp值入栈保存
00E813C1 mov ebp,esp ;将当前栈顶值esp赋值给ebp
00E813C3 sub esp,0CCh ;esp=esp-204,空出204B的栈空间用于本函数的临时变量(这里为何是204B不理解,本函数不优化的情况下临时变量只需要4*4=16B)

;继续解释上行代码,本汇编语言采用递减栈,即push dword值语句等价于下面①②

①、mov dword ptr [esp],dword值 ②、mov esp esp-4
00E813C9 push ebx ;ebx值入栈保存
00E813CA push esi ;esi值入栈保存
00E813CB push edi ;edi值入栈保存
00E813CC lea edi,[ebp-0CCh] ;给edi=当前段中ebp的地址-204(即00E813C3行执行完后的esp值)
00E813D2 mov ecx,33h ;给ecx赋值33h (十进制数51,由204/4计算得出,204是栈中存储临时变量的字节数)
00E813D7 mov eax,0CCCCCCCCh ;给eax赋值 0CCCCCCCCh ,本值作为栈中临时变量区每个dword元素的初始值
00E813DC rep stos dword ptr es:[edi] ;给栈中204B的临时变量区字节赋初始值。本语句由以下①②指令复合而来

①、rep 指令 :重复执行指令ecx次(每执行完一次ecx=ecx-1,然后判断是否继续执行)

②、stos dword ptr es:[edi] : I、move dword ptr es:[edi] eax II、mov edi edi+4
int c = 0;
00E813DE mov dword ptr [c],0 ; 这里应该是 mov dword ptr [ebp-8,ebp-11],0

插入以下本编译器UI中未生成的但实际执行了的语句(此时内存中数据排布见下面分析):

mov [ebp,ebp-3] [ebp+16,ebp+13] ; sum函数形参b=sum函数实参b

mov [ebp-4,ebp-7] [ebp+12,ebp+9] ; sum函数形参a=sum函数实参a

c = a + b;
00E813E5 mov eax,dword ptr [a]
00E813E8 add eax,dword ptr [b]
00E813EB mov dword ptr [c],eax
return c;
00E813EE mov eax,dword ptr [c]

上面几行代码中a、b、c所占的存储器空间应该是:(占据栈中临时变量区起始单元)

b(实参):[ebp+16,ebp+13] (这里的ebp是esp给栈中临时变量分配空间前的值)

a(实参):[ebp+12,ebp+9]

push pc (call sum产生,占4字节)

push ebp(sum函数开始部分的操作,占4字节)

b(形参):[ebp,ebp-3]

a(形参):[ebp-4,ebp-7]

c:[ebp-8,ebp-11]

从main函数 call sum 开始(包括本行),共执行了以下汇编代码

main函数中调用sum函数的操作包括:

mov eax,dword ptr [b] ; 这里的 a b 是main函数栈内的临时变量a b
push eax ;实参入栈
mov ecx,dword ptr [a]
push ecx ;实参入栈
call sum (0E8105Fh) ; 本行等价于①、 push pc ②、move pc sum地址

}
00E813F1 pop edi
00E813F2 pop esi
00E813F3 pop ebx
00E813F4 mov esp,ebp
00E813F6 pop ebp
00E813F7 ret ; pop pc
-— 无源文件 ———————————————————————————————————-
00E813F8 int 3
00E813F9 int 3
00E813FA int 3
00E813FB int 3
00E813FC int 3
00E813FD int 3
00E813FE int 3
00E813FF int 3
-— c:\user_data\11project\practise_project\cpp\testasm\testasm\main.cpp ———-

int main()
{
00E81400 push ebp
00E81401 mov ebp,esp
00E81403 sub esp,0E4h
00E81409 push ebx
00E8140A push esi
00E8140B push edi
00E8140C lea edi,[ebp-0E4h]
00E81412 mov ecx,39h
00E81417 mov eax,0CCCCCCCCh
00E8141C rep stos dword ptr es:[edi]
int a = 2, b = 3;
00E8141E mov dword ptr [a],2
00E81425 mov dword ptr [b],3
int c = 0;
00E8142C mov dword ptr [c],0
c=sum(a, b);
00E81433 mov eax,dword ptr [b]
00E81436 push eax
00E81437 mov ecx,dword ptr [a]
00E8143A push ecx
00E8143B call sum (0E8105Fh)
00E81440 add esp,8
00E81443 mov dword ptr [c],eax
return 1;
00E81446 mov eax,1
}
00E8144B pop edi
00E8144C pop esi
00E8144D pop ebx
00E8144E add esp,0E4h
00E81454 cmp ebp,esp
00E81456 call __RTC_CheckEsp (0E8113Bh)
00E8145B mov esp,ebp
00E8145D pop ebp
00E8145E ret

发表评论

表情:
评论列表 (有 0 条评论,402人围观)

还没有评论,来说两句吧...

相关阅读