linux平臺學x86彙編(十八):內聯彙編

【版權聲明:尊重原創,轉載請保留出處:blog.csdn.net/shallnet,文章僅供學習交流,請勿用於商業用途】
        使用彙編語言筆編程最常見的方式是在高級語言(C和C++)程序內編寫彙編函數,這種吧彙編語言直接寫到C和C++語言程序內的技術稱爲內聯彙編。
        GNU的C編譯器使用asm關鍵字指出使用彙編語言編寫的源代碼段落。asm段的基本格式如下:
        asm("as code");
        括號中的彙編指令必須在括號,指令超過一條的話必須使用新的行分隔彙編語言代碼每一行,因爲編譯器逐字地取得asm段中彙編代碼,並且把它們放在爲程序生成的彙編代碼中,有時可以使用製表符字符縮進指令以便它們和標籤區別開。下面是一個簡單的內聯彙編的示例:
        asm("movl $1, %eax\n\t movl $0,%ebx\n\tint $0x80");
        該示例包括3條指令,在使用很多彙編指令時會顯得有些混亂,所以一般把指令放在單獨的行中。
        asm("movl $1, %eax\n\t"
                "movl $0,%ebx\n\t"
                "int $0x80");
        利用C全局變量可以把數據傳遞進和傳遞出內聯彙編語言,注意不能使用局部變量。
#include <stdio.h>
int     result = 10;
int main(int argc, const char *argv[])
{
    asm("addl $1, result\n\t"
        "subl $2, result\n\t");
    printf("the result is  %d\n", result);
    return 0;
}
使用gcc生成彙編代碼如下:
 .file "inline-as.c"
.globl result
.data
.align 4
.type result, @object
.size result, 4
result:
.long 10
.section .rodata
.LC0:
.string "the result is  %d\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
#APP
# 7 "inline-as.c" 1
addl $1, result
subl $2, result

# 0 "" 2
#NO_APP
movl result, %edx
movl $.LC0, %eax
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-3)"
.section .note.GNU-stack,"",@progbits
c文件編譯執行結果爲:
$ ./inline-as
the result is  9
$
反編譯的彙編代碼中#APP和#NOAPP之間的代碼爲asm段指定的內聯彙編代碼。
ANSI C規範在使用內聯彙編語句時使用關鍵字__asm__替換關鍵字asm,因爲ANSI C 關鍵字asm用於其他用途。如下:
    __asm__("addl $1, result\n\t"
        "subl $2, result\n\t");
基本的asm格式提供創建彙編代碼的簡單樣式,但是有一些侷限性。首先,所有輸入值和輸出值都必須使用C程序的全局變量,如上示例所見。其次,在內聯彙編代碼中不去改變任何寄存器的值。GNU編譯器提供asm段的擴展格式來幫助解決這些問題。擴展格式採用新的格式,如下:
<span style="font-family:Microsoft YaHei;">asm ("as code": output location : input operands : changed registers);</span>
該格式由4個部分構成,使用冒號分隔:彙編代碼、輸出位置、輸入操作數、改動的寄存器。在擴展asm格式中,不是所有部分必須出現。

大多數程序員把內聯彙編代碼定義爲宏函數,定義方式和C語言類似。定義內聯彙編宏函數如下:
    #define CAL ({
            asm("addl $1, result\n\t"
            "subl $2, result\n\t");
            })
這裏asm語句必須要在一對花括號中,以便指出語句的開頭和結尾,否則編譯器會生成錯誤信息。
如下爲使用宏的一個簡單示例:
#include <stdio.h>
#define CAL ({ \
    asm("addl $1, result\n\t"\
        "subl $2, result\n\t");\
        })
int     result = 10;
int main(int argc, const char *argv[])
{
    CAL;
    printf("the result is  %d\n", result);
    return 0;
}

發佈了165 篇原創文章 · 獲贊 370 · 訪問量 49萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章