Elta提示
1. GCC 內嵌彙編的基本格式
asm("assembly code");
如:
asm("syscall"); //觸發一個系統調用
如果有多條指令,則需在指令尾部添加'/t'和'/n',如:
asm("li v0, 4011/t/n" "syscall");
括號裏的字符串 GCC 前端不作分析,直接傳給彙編器 as ,故而相聯指令間需插入換行符。
'/t' 加入只爲排版對齊一些而已,可以使用 gcc -S tst.c -o tst.s 查看生成的 tst.s
因爲 GCC 並不對 asm 後括號中的指令作分析,故而如果指令修改一些的寄存器的值,GCC是不知道的,這個會引入一些問題。
另外 asm 可以替換爲 __asm__ ,效果等價。__asm__ 一般用於頭文件中,防止關鍵字 asm 可能與一些變量、函數名衝突。
內嵌彙編如何與 C 變量交換數據?
2. GCC 內嵌彙編擴展格式
asm (
"assembly code"
: output_operand
: input_operand
: clobbered_operand
);
以一個例子來說明:
如果我們要讀取CP0 25 號硬件計數寄存器的值,並返回之,可以這樣:
int get_counter()
{
int rst;
asm(
"mfc0 %0, $25/t/n"
: "=r" (rst)
);
return rst;
}
"=r" 中,'=' 爲修飾符,表示該操作對象只寫,一般用於修飾輸出參數列表中。'r' 表示任意一個通用寄存器。由於我們只要取得一個值,故而只用到了輸出列表。代碼中也沒修改一些寄存器的值gcc不知道,(輸出、輸入列表中的寄存器gcc是知道的)故而被改變的操作對象列表亦可省去。
如果我們要重設CP0 24 號硬件計數器之控制寄存器的值,則:
unsigned int op = 0x80f;
asm volatile(
"mtc0 %0, $24"
:
:"r"(op)
);
volatile 關鍵字表示讓GCC優化生成代碼時,不要移動、刪除我們的彙編碼。另外 __volatile__與其含義相同,引入的目的與__asm__是一樣的。
如果我們重設後,立即讀取CP0 24號寄存器的值,則:
unsigned int rst;
unsigned int op = 0x80f;
asm volatile(
"mtc0 %1, $24/t/n"
"mfc0 %0, $25/t/n"
: "=r" (rst)
: "r" (op)
);
如果我們要操作的對象位於存儲器中,我們可以使用 'm' 來修飾輸入輸出參數,如:
unsigned short data[] = {
0x0, 0x0, 0x0, 0x0,
0x1, 0x3, 0x5, 0x7,
0x1, 0x3, 0x5, 0x7,
};
void pmullh()
{
asm volatile
(
".set mips3/n/t"
".set noreorder/n/t"
"ldc1 $f0, %1/n/t"
"ldc1 $f2, %2/n/t"
"pmullh $f2, $f2, $f0/n/t"
"sdc1 $f2, %0/n/t"
".set reorder/n/t"
".set mips0/n/t"
: "=m"(*data)
: "m"(*(data+4)), "m"(*(data+8))
: "$f0", "$f2", "memory"
);
}
注意到使用'm'修飾的操作數,後面括號裏跟的不是指針,而是開始的第一個元素值。
%0,%1, %2 依次對應輸出列表的一個,輸入列表的兩個操作數,編譯後會被gcc替換成類似 0($12),8($12),16($12)的形式,其中$12置數組首地址,即: %0等價於0($12)
由於我們嵌入的代碼改變了 $f0, $f2 的值,而他們不在輸出、輸入列表中,故而要將其陳列於被改變操作數列表(clobbered operand list)中,以告訴gcc 我們改變了他們的值,以免gcc 誤判。
因爲代碼中我們改變了內存中數據的值,如果此前gcc生成的代碼讀取了該內存處的值,並保存於寄存器中的話,由於我們更新了這段數據,所以需要告訴gcc在後面要重新加載數據,這個需要在被改變操作數列表中(clobbered operand list)寫入 "memory"。
3. 修飾符
= 只寫,常用於修飾所有輸出操作數
+ 只讀
& 只用於輸出,一般和'='一起用,如:"=&r" (val)
4. 其他對輸入、輸出對象的操作符
d General-purpose integer register
f Floating-point register (if available)
h ‘Hi’ register
ll ‘Lo’ register
x ‘Hi’ or ‘Lo’ register
y General-purpose integer register
z Floating-point status register
I Signed 16-bit constant (for arithmetic instructions)
J Zero
K Zero-extended 16-bit constant (for logic instructions)
L Constant with low 16 bits zero (can be loaded with lui)
M 32-bit constant which requires two instructions to load (a constant which is not ‘I’, ‘K’, or ‘L’)
N Negative 16-bit constant
O Exact power of two
P Positive 16-bit constant
G Floating point zero
Q Memory reference that can be loaded with more than one instruction (‘m’ is preferable for asm statements)
R Memory reference that can be loaded with one instruction (‘m’ is preferable for asm statements)
S Memory reference in external OSF/rose PIC format (‘m’ is preferable for asm statements)
轉自:http://blog.csdn.net/comcat/article/details/1557963