内联汇编
内联汇编(英语:Inline assembly)是部分编译器支援的一种功能。其将非常低阶的组合语言内嵌在高阶语言源始码中。实施行内组语通常是为了以下理由:
使用处理器持有指令优化范例
下面是一段在D语言进行行内组语的程式码。该程式码使用x86架构的浮点运算器指令来计算 。此实作快于编译器产生的一系列浮点数运算,行内组语也使编程人员得以使用fldpi
指令来载入在x86架构下可得到的最佳之pi估计值。
// 計算tan(x)
real tan(real x)
{
asm
{
fld x[EBP] ; // 將x值載入浮點運算器的堆疊上
fxam ; // 測試堆疊頂端的值是否是合法、可計算浮點數
fstsw AX ;
sahf ;
jc trigerr ; // 若x是NAN,正負無限,或空值
// 387可以處理denormals數值
SC18: fptan ; // 為與8087運算器相容fptan會使堆疊頂端為1.0,再來才是tan值,
fstp ST(0) ; // 丟棄堆疊頂端的值
fstsw AX ;
sahf ;
jnp Lret ; // C2為FPU狀態變數,C2 == 1表示x超出允許的範圍
; // tan之週期為pi,下面的程式碼就是將x縮至允許的範圍
fldpi ;
fxch ;
SC17: fprem1 ;
fstsw AX ;
sahf ;
jp SC17 ;
fstp ST(1) ; // 將pi值移出堆疊
jmp SC18 ;
}
trigerr:
return real.nan;
Lret:
;
}
系统调用(system calls)范例
在保护模式运行的应用程式无法直接呼叫专属于OS的功能。因为OS的行程空间包含核心空间(kernel mode)与用户空间(user mode);运行在用户空间的程式只能透过中断来引用专属于作业系统的功能。通常高阶语言都不提供这项功能,所以要运用行内组语将呼叫system calls的过程包装为高阶语言可辨认、呼叫的函式。
下面的C语言片段即含有一个system call的包装函式。其组语语法为GNU汇编器使用的AT&T组语语法。一般这类程式都会使用巨集实作,不过为了清楚展示观念,在此列出了完整的程式码。
GNU组译器的行内组语语法相当直觉,基本型式如下:
asm("assembly code");
例如:
asm("movl %ecx, %eax"); /* 複製ecx暫存器的內容至eax暫存器*/
或
__asm_("movb %bh, (%eax)"); /* 從bh暫存器複製1位元組的資料到eax暫存器所指的記憶體區塊*/
必须注意的是,AT&T语法中的运算元顺序与Windows平台下常用的MASM刚好相反。
asm
跟__asm__
都是合法型式;当asm
与程式码中某些变数命名起冲突时可使用后者。
extern int errno;
int funcname(int arg1, int *arg2, int arg3)
{
int res;
__asm__ volatile(
"int $0x80" /* 向OS拋出請求*/
: "=a" (res) /* 請編譯器將結果將儲存於eax ("a")*/
"+b"(arg1), /* 請編譯器將arg1存於ebx ("b")*/
"+c"(arg2), /* 請編譯器將arg2存於ecx ("c")*/
"+d"(arg3) /* 請編譯器將arg3存於edx ("d")*/
: "a"(128) /* 該system call的編號放於eax ("a")*/
: "memory", "cc"); /* 通知編譯器,記憶體與condition code register(決定分支的暫存器)己被更改*/
/* 若OS回傳負值表示錯誤;則包裝函式要設定errno global variable並回傳 -1 */
if (-125 <= res && res < 0) {
errno = -res;
res = -1;
}
return res;
}