zoukankan      html  css  js  c++  java
  • 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了。

    达到了参数传递的目的。 

  • 相关阅读:
    k8s 存活探针(健康检查)
    数据库CPU 100%处理记录
    zabbix 批量安装+自动注册
    Docker 学习目录
    ubuntu18启动zabbix-agent失败/故障记录
    使用Docker构建企业Jenkins CI平台
    记一次服务被黑处理过程
    ELK数据迁移,ES快照备份迁移
    脚本监控服务状态 微信-钉钉告警
    邮箱附件脚本
  • 原文地址:https://www.cnblogs.com/keepfocus/p/2176420.html
Copyright © 2011-2022 走看看