GCC內聯彙編(2)GCC生成彙編程式碼簡單例項

鍾超發表於2012-07-09

GCC內聯彙編(2)GCC生成彙編程式碼簡單例項

  • 作者:柳大·Poechant(鍾超)
  • 郵箱:zhongchao.ustc#gmail.com(# -> @)
  • 部落格:Blog.CSDN.net/Poechant
  • 日期:July 8th, 2012

1 準備示例

先看一個空的 main 函式會生成怎樣的彙編程式碼。要注意的是我這裡是在 Mac OS X 上進行的測試,編譯器是 Apple’s version of GCC,實際上用的是 llvm-gcc。

[程式碼段-1]


int main() {
    return 0;
}

[命令列-1]


gcc -S main.c

生成的彙編如下(這裡只擷取主要部分,下同):

[程式碼段-2]


Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    movl    $0, -8(%rbp)
    movl    -8(%rbp), %eax
    movl    %eax, -4(%rbp)
    movl    -4(%rbp), %eax
    pop     %rbp
    ret
Leh_func_end1:

如果開啟優化編譯選項呢?一定會有一些變化吧。

[命令列-2]


gcc -S main.c -O3

[程式碼段-3]


Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    xorl    %eax, %eax
    popq    %rbp
    pop     %rbp
    ret
Leh_func_end1:

是的,一些“廢話”被優化掉了。

[程式碼段-4]


int main() {
    int a = 19, b = 100;
    return 0;
}

看下面的簡單例項,宣告兩個整形變數,並賦以初值。

[命令列-3]


gcc -S main.c

生成的彙編程式碼如下。可以看到 a 代表的區域性變數值 19 被壓入棧中,位置是棧基址減去 12,b 代表的區域性變數壓入棧中,位置是棧基址減去 16,而返回值所使用的立即數 0 被放入棧基址減去 8。

[程式碼段-5]


Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    movl    $19, -12(%rbp)
    movl    $100, -16(%rbp)
    movl    $0, -8(%rbp)
    movl    -8(%rbp), %eax
    movl    %eax, -4(%rbp)
    movl    -4(%rbp), %eax
    pop     %rbp
    ret
Leh_func_end1:

如果開啟優化編譯選項編譯,則會把int a = 19, b = 100這句優化掉,從而與[程式碼段-3]一樣。

2 內聯彙編例項


int main(){
    int a = 19, b = 100;
    __asm__ (
        "addl %2, %1";
        : "=a"(a)
        : "a"(a), "b"(b)
        : "%eax", "%ebx"
    )
    return 0;
}

生成的彙編如下:


_main:
Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    pushq   %rbx
    subq    $24, %rsp
Ltmp2:
    movl    $19, -20(%rbp) # 區域性變數 a 的位置是棧基址減去 20
    movl    $100, -24(%rbp) # 區域性變數 b 的位置是棧基址減去 24
    
    # 處理內斂彙編的入口
    movl    -20(%rbp), %eax
    movl    -24(%rbp), %ecx
    movl    %ecx, %ebx
    
    ## InlineAsm Start
    addl    %ebx, %eax;
    ## InlineAsm End
    movl    %eax, -20(%rbp) # 返回值放在指定的區域性變數 a 中
    
    # 剩下的部分與前面的簡單例項一樣,就是處理返回值
    movl    $0, -16(%rbp)
    movl    -16(%rbp), %eax
    movl    %eax, -12(%rbp)
    movl    -12(%rbp), %eax
    popq    %rbx
    popq    %rbp
    ret 
Leh_func_end1:

#include <stdio h=""></stdio><stdio h=""><span class="keyword" style="font-weight: bold; ">int</span> main() {
    <span class="keyword" style="font-weight: bold; ">int</span> a = <span class="number" style="color: rgb(0, 136, 0); ">19</span>, b = <span class="number" style="color: rgb(0, 136, 0); ">100</span>;
    __asm__ (
        <span class="string" style="color: rgb(136, 0, 0); ">"addl %1, %0;"</span>
        : <span class="comment" style="color: rgb(136, 136, 136); ">//no output</span>
        : <span class="string" style="color: rgb(136, 0, 0); ">"a"</span>(a), <span class="string" style="color: rgb(136, 0, 0); ">"b"</span>(b)
        : <span class="string" style="color: rgb(136, 0, 0); ">"%eax"</span>, <span class="string" style="color: rgb(136, 0, 0); ">"%ebx"</span>
    );  
    <span class="keyword" style="font-weight: bold; ">return</span> <span class="number" style="color: rgb(0, 136, 0); ">0</span>;
}
</stdio>

_main:
Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    pushq   %rbx
Ltmp2:
    # Immediate numbers
    movl    $19, -20(%rbp)
    movl    $100, -24(%rbp)
    
    # Input
    movl    -20(%rbp), %eax
    movl    -24(%rbp), %ecx
    movl    %ecx, %ebx
    
    ## InlineAsm Start
    addl %ebx, %eax;
    ## InlineAsm End
    
    # Note: no output
    
    # Similar to above examples
    movl    $0, -16(%rbp)
    movl    -16(%rbp), %eax
    movl    %eax, -12(%rbp)
    movl    -12(%rbp), %eax
    popq    %rbx
    popq    %rbp
    ret 
Leh_func_end1:

也間接證實了%0,%1,%2⋯⋯ 是從輸出開始排序的,如果沒有輸出,就從輸入開始排序。

另外使用m則可以表示memory,即變數是在記憶體中,而非暫存器中。如下示例:


#include <stdio h=""></stdio><stdio h=""><span class="keyword" style="font-weight: bold; ">int</span> main() {
    <span class="keyword" style="font-weight: bold; ">int</span> a = <span class="number" style="color: rgb(0, 136, 0); ">17</span>, b = <span class="number" style="color: rgb(0, 136, 0); ">100</span>;
    __asm__ (
        <span class="string" style="color: rgb(136, 0, 0); ">"addl %2, %1;"</span>
        : <span class="string" style="color: rgb(136, 0, 0); ">"=m"</span>(a)
        : <span class="string" style="color: rgb(136, 0, 0); ">"m"</span>(a), <span class="string" style="color: rgb(136, 0, 0); ">"b"</span>(b)
        : <span class="string" style="color: rgb(136, 0, 0); ">"memory"</span>, <span class="string" style="color: rgb(136, 0, 0); ">"%ebx"</span>
    );  
    printf(<span class="string" style="color: rgb(136, 0, 0); ">"%d\n"</span>, a); 
    <span class="keyword" style="font-weight: bold; ">return</span> <span class="number" style="color: rgb(0, 136, 0); ">0</span>;
}
</stdio>

生成的彙編程式碼的主要部分如下:


movl    $17, -20(%rbp)
movl    $100, -24(%rbp)
movl    -24(%rbp), %eax
movl    %eax, %ebx

## InlineAsm Start
addl    %ebx, -20(%rbp)
## InlineAsm End

## 下面的部分同此前的所有程式碼段,略去

可以看到是直接加到操作上的,而非暫存器。

-

轉載請註明來自柳大的CSDN部落格:Blog.CSDN.net/Poechant

-

相關文章