gcc处理函数调用时的PUSH解决办法

一般的调用函数格式是:

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;function1

........................

push param1

push param2  

call function2

 .............................

 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;function2

.......................

push ebp

mov ebp, esp

;以后使用时候,只需

mov eax, [ebp+8] ;eax=param2。为何不是ebp+4?因为[ebp+4]是function2返回后的执行地址

mov edx, [ebp+0c] ; eax=param1。

今天学习了一下GCC编辑器。我使用的version是:

e:>gcc   -v

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=e:/mingw/bin/../libexec/gcc/mingw32/4.5.2/lto-wrapper.exe
Target: mingw32
Configured with: ../gcc-4.5.2/configure --enable-languages=c,c++,ada,fortran,objc,obj-c++ --disable-sjlj-exceptions --wi
th-dwarf2 --enable-shared --enable-libgomp --disable-win32-registry --enable-libstdcxx-debug --enable-version-specific-r
untime-libs --disable-werror --build=mingw32 --prefix=/mingw
Thread model: win32

gcc version 4.5.2 (GCC) 

GCC编译器在调用函数时,没有使用PUSH。而是在调用函数里面多申请了2个局部变量(假设被调用函数使用2个参数)。然后用mov的方式,把参数mov到这2个局部变量上。

看起来像这样(以下代码使用的是一段简单的c代码的反汇编,功能是:输入2个数,打印最大的那个数)。

;function1:

.text:004013C0 formatString= dword ptr -20h 参数传递变量3
.text:004013C0 param2= dword ptr -1Ch ;参数传递变量2
.text:004013C0 param1= dword ptr -18h 参数传递变量1。注意,这个是gcc为了参数传递时开始申请的变量
.text:004013C0 number2= dword ptr -0Ch ;我们需要使用的局部变量3
.text:004013C0 number1= dword ptr -8       ;我们需要使用的局部变量2
.text:004013C0 maxNumber= dword ptr -4  ;我们需要使用的局部变量1
.text:004013C0

;例行程序 

.text:004013C0 push    ebp
.text:004013C1 mov     ebp, esp

;开始为局部变量弄空间 

.text:004013C3 and     esp, 0FFFFFFF0h
.text:004013C6 sub     esp, 20h

; SEH等。GCC自动添加的

.text:004013C9 call    sub_401A60

;好戏开始了 

.text:004013CE lea     eax, [esp+20h+number2] ;请注意:esp+20h=ebp,但是人家不用ebp-0ch
.text:004013D2 mov     [esp+20h+param1], eax ;看见没有,这个就相当于  push eax
.text:004013D6 lea     eax, [esp+20h+number1]

.text:004013DA mov     [esp+20h+param2], eax  ;同理,push eax

.text:004013E5 call    scanf ;调用参数了。
.text:004013EA mov     edx, [esp+20h+number2]
.text:004013EE mov     eax, [esp+20h+number1]
.text:004013F2 mov     [esp+20h+param2], edx ;又开始将两个参数压入栈了。  push edx
.text:004013F6 mov     [esp+20h+formatString], eax ;push eax
.text:004013F9 call     findmaxnumber ;findmaxnumber函数时我们自己实现的。我们将其代码贴出来。见下面。

;同样的处理方式,和上面的2个调用方法一样。 

.text:004013FE mov     [esp+20h+maxNumber], eax
.text:00401402 mov     eax, [esp+20h+maxNumber]
.text:00401406 mov     [esp+20h+param2], eax
.text:0040140A mov     [esp+20h+formatString], offset aMaxD ; "max=%d"

.text:00401411 call    printf 

 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;子函数:findmaxnumber( number1, number2) 

.text:00401418 maxNumber= dword ptr -4

.text:00401418 number1= dword ptr  8 ;这个就使用了栈中的传递过来的参数1
.text:00401418 number2= dword ptr  0Ch ;传递参数2
.text:00401418
.text:00401418 push    ebp
.text:00401419 mov     ebp, esp
.text:0040141B sub     esp, 10h
.text:0040141E mov     eax, [ebp+number1]
.text:00401421 cmp     eax, [ebp+number2]
.text:00401424 jle     short loc_40142E
.text:00401426 mov     eax, [ebp+number1]
.text:00401429 mov     [ebp+maxNumber], eax
.text:0040142C jmp     short loc_401434
.text:0040142E ; ---------------------------------------------------------------------------
.text:0040142E
.text:0040142E loc_40142E:                   ; CODE XREF: sub_401418+Cj
.text:0040142E mov     eax, [ebp+number2]
.text:00401431 mov     [ebp+maxNumber], eax
.text:00401434
.text:00401434 loc_401434:                   ; CODE XREF: sub_401418+14j
.text:00401434 mov     eax, [ebp+maxNumber] ;最后把结果放在eax里面返回
.text:00401437 leave
.text:00401438 retn
.text:00401438 sub_401418 endp
.text:00401438
.text:00401438 ; ---------------------------------------------------------------------------

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

总结:

GCC编译时,被调用函数是没有什么变化的。和vs的编译器不同的是在调用函数里面,子函数使用几个参数传递,在调用函数里面就就多申请几个局部变量,然后调用函数将数据放入这些局部变量里面。形如:mov   [ebp-18], eax,这个就相当于push eax了。

达到了参数传递的目的。 

原文地址:https://www.cnblogs.com/keepfocus/p/2176420.html