C++中的return和exit區別

一見發表於2019-01-29

 

在main函式中,return和exit經常混用,兩者的一個區別:return會執行statck unwinding,而exit不會。如果觸發了訊號,exit也同樣不會做stack unwinding,除此之外異常如果沒有相應的catch,也同樣不會有棧展開(stack unwinding)。

原因是C++編譯器只會在遇到“}”或“return”時,才會安插棧展開程式碼,對於exit等則沒這回事。

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

 

class X

{

public:

    X(int m): _m(m) { printf("X::ctor:%d\n", m); }

    ~X() { printf("X::dtor:%d\n", _m); }

 

private:

    int _m;

};

 

int main()

{

    X x(1);

#if USE_EXIT

    exit(0);

#if USE_RAISE

    raise(SIGSEGV);

#else

    return 0;

#endif

}

 

以上述程式碼為例,通過彙編,可很容易看出這兩者的區別:

1) return程式碼

int main()

{

    X x(1);

    return(0);

}

 

反彙編main函式,可以看到有呼叫~X:

0x08048474 <main+0>:    lea    0x4(%esp),%ecx

0x08048478 <main+4>:    and    $0xfffffff0,%esp

0x0804847b <main+7>:    pushl  0xfffffffc(%ecx)

0x0804847e <main+10>:   push   %ebp

0x0804847f <main+11>:   mov    %esp,%ebp

0x08048481 <main+13>:   push   %ebx

0x08048482 <main+14>:   push   %ecx

0x08048483 <main+15>:   sub    $0x20,%esp

0x08048486 <main+18>:   movl   $0x1,0x4(%esp)

0x0804848e <main+26>:   lea    0xfffffff4(%ebp),%eax

0x08048491 <main+29>:   mov    %eax,(%esp)

0x08048494 <main+32>:   call   0x80484b6 <X>

0x08048499 <main+37>:   mov    $0x0,%ebx

0x0804849e <main+42>:   lea    0xfffffff4(%ebp),%eax

0x080484a1 <main+45>:   mov    %eax,(%esp)

0x080484a4 <main+48>:   call   0x80484da <~X>

0x080484a9 <main+53>:   mov    %ebx,%eax

0x080484ab <main+55>:   add    $0x20,%esp

0x080484ae <main+58>:   pop    %ecx

0x080484af <main+59>:   pop    %ebx

0x080484b0 <main+60>:   pop    %ebp

0x080484b1 <main+61>:   lea    0xfffffffc(%ecx),%esp

0x080484b4 <main+64>:   ret

 

2) exit程式碼

int main()

{

    X x(1);

    exit(0);

}

 

反彙編main函式,可以看到沒有呼叫~X:

0x080484a4 <main+0>:    lea    0x4(%esp),%ecx

0x080484a8 <main+4>:    and    $0xfffffff0,%esp

0x080484ab <main+7>:    pushl  0xfffffffc(%ecx)

0x080484ae <main+10>:   push   %ebp

0x080484af <main+11>:   mov    %esp,%ebp

0x080484b1 <main+13>:   push   %ecx

0x080484b2 <main+14>:   sub    $0x24,%esp

0x080484b5 <main+17>:   movl   $0x1,0x4(%esp)

0x080484bd <main+25>:   lea    0xfffffff8(%ebp),%eax

0x080484c0 <main+28>:   mov    %eax,(%esp)

0x080484c3 <main+31>:   call   0x80484d4 <X>

0x080484c8 <main+36>:   movl   $0x0,(%esp)

0x080484cf <main+43>:   call   0x80483c8 <exit@plt>

附:彙編指令

call指令

分兩步:

1) 將當前的IP或CS和IP壓入棧中

2) 轉移(能實現短轉移,它的書寫格式同jmp指令)

ret指令

相當於pop IP

retf指令

相當於:

1) pop IP

2) pop CS

lea指令

把運算元OPRD的偏移地址傳送到暫存器REG,語法:LEA REG, OPRD

 

相關文章