天天看點

從一個小白也能看懂的例子,了解gcc編譯-O選項的作用

首先來看一段簡單的C代碼

int foo(int m, int n)
{
    return m + n;
}

int main()
{
    int m = 1;
    int n = 2;
    return foo(m, n);
}
           

緊接着看一段未使用-O選項或使用-O0優化級别編譯的反彙編代碼

foo 函數開始
00010470 <foo>:
   10470:    e52db004     push    {fp}        ; (str fp, [sp, #-4]!)
   10474:    e28db000     add    fp, sp, #0
---------------------------------------------------------------------------------------------------
   10478:    e24dd00c     sub    sp, sp, #12
   1047c:    e50b0008     str    r0, [fp, #-8]      # r0 寄存器的值寫入 fp - 8  位址處(從 main 函數可以發現,r0 = m = 1)
   10480:    e50b100c     str    r1, [fp, #-12]     # r1 寄存器的值寫入 fp - 12 位址處(從 main 函數可以發現,r0 = n = 2)
   10484:    e51b2008     ldr    r2, [fp, #-8]      # fp - 8  位址處的值,加載到 r2
   10488:    e51b300c     ldr    r3, [fp, #-12]     # fp - 12 位址處的值,加載到 r3
   1048c:    e0823003     add    r3, r2, r3         # r3 = r2 + r3(就是 r3 = 1 + 2)
   10490:    e1a00003     mov    r0, r3             # 傳回r3的值

上述彙編代碼等價于C代碼
   int a;
   int b;
   a = m;
   b = n;
   return a + b;
---------------------------------------------------------------------------------------------------
   10494:    e24bd000     sub    sp, fp, #0
   10498:    e49db004     pop    {fp}        ; (ldr fp, [sp], #4)
   1049c:    e12fff1e     bx    lr

main 函數開始
000104a0 <main>:
   104a0:    e92d4800     push    {fp, lr}
   104a4:    e28db004     add    fp, sp, #4
---------------------------------------------------------------------------------------------------
   104a8:    e24dd008     sub    sp, sp, #8
   104ac:    e3a03001     mov    r3, #1             # r3 寄存器等于1
   104b0:    e50b3008     str    r3, [fp, #-8]      # r3 寄存器的值寫入 fp - 8  位址處
   104b4:    e3a03002     mov    r3, #2             # r3 寄存器等于2
   104b8:    e50b300c     str    r3, [fp, #-12]     # r3 寄存器的值寫入 fp - 12 位址處
   104bc:    e51b100c     ldr    r1, [fp, #-12]     # r1 寄存器等于 fp - 12(可以将 r1 就是參數n)
   104c0:    e51b0008     ldr    r0, [fp, #-8]      # r0 寄存器等于 fp - 8 (可以将 r0 就是參數m)
   104c4:    ebffffe9     bl    10470 <foo>

上述彙編代碼等價于C代碼
   int a;
   int m;
   int n;
   a = 1;
   m = a;
   a = 2;
   n = a;
   foo(m, n);
---------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------
   104c8:    e1a03000     mov    r3, r0
   104cc:    e1a00003     mov    r0, r3

上述彙編代碼等價于C代碼
   将 foo 函數的傳回值當做 main 函數的傳回值
---------------------------------------------------------------------------------------------------
   104d0:    e24bd004     sub    sp, fp, #4
   104d4:    e8bd8800     pop    {fp, pc}
           

從上述的彙編代碼可以發現,在未使用-O或使用-O0優化級别的情況下,編譯出來的彙編代碼基本與C語言的代碼邏輯一一對應,沒有做任何優化

接下來在看一段使用-O1 ~ -O3優化級别編譯的反彙編代碼

foo 函數開始
00010470 <foo>:
   10470:   e0800001    add r0, r0, r1  # foo 函數被優化成,直接傳回參數 m 和 n 相加的結果。将臨時存儲的代碼優化掉了
   10474:   e12fff1e    bx  lr

main 函數開始
00010478 <main>:
   10478:   e3a00003    mov r0, #3      # main 函數直接傳回常數 3,将 foo 函數調用和變量定義的代碼都優化掉了
   1047c:   e12fff1e    bx  lr
           

因為這裡給出的C代碼比較簡單,是以-O1 ~ -O3編譯出來的彙編代碼是一樣的(完全沒必要進一步優化了啊,太簡單了)。如果C代碼複雜一點的話,可以看出-O1 ~ -O3每個等級的優化程度都是不一樣的

繼續閱讀