一般的调用函数格式是:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;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了。
达到了参数传递的目的。