汇编语言调用指令会替换为从内联模板 (*.il) 文件获得的相应函数主体的副本。
内联文件带有后缀 .il,例如:
% CC foo.il hello.c
内联由编译器的代码生成器完成。
每个 inlinefile 包含一个或多个有标签的汇编语言模板,其格式为:
inline-directive instructions ... .end
其中 instructions 构成指定例程的内联扩展。inline-directive 是以下格式的命令:
.inline identifier, argsize
此命令为由 identifier 指定的例程声明代码块,其中 argsize 作为例程参数的总大小(以字节数表示)。对指定例程的调用会替换为内联模板中的代码。
注意:将忽略 argsize 的值,但是应该包括此参数,以便与早于 Sun WorkShop[tm] 5.0 编译器的编译器版本兼容。
允许使用多个模板;将忽略第一个后面的匹配模板。
内联模板应该编码为 C 兼容过程调用的扩展,不同之处在于,无法依靠返回地址在预期位置,因为尚未执行任何调用指令。
内联模板必须遵守标准的 Oracle Solaris Studio 参数传递和寄存器使用约定,如下详述。它们不得调用违反这些约定的例程;例如,setjmp(3C) 等汇编语言例程可能会引起问题。
不得使用或设置除下方提及的寄存器之外的寄存器。
只能将内联模板中的分支指令传输给在内联模板中定义的数字标签(1f、2b 等)。不允许其他任何控制传输。
模板不需要 ret 或 retl 指令,不得包括它们。
只保证由 Oracle Solaris Studio 编译器生成的操作代码和寻址模式起作用。不支持指令的二进制编码。
前六个参数在寄存器 %o0-%o5 中传递。超过第六个的参数按照目标 ABI 使用堆栈位置进行传递。%sp 保证 64 位对齐。%o7 的内容未定义,因为尚未执行任何调用指令。
结果将在 %o0 或 %f0/%f1 中返回。
寄存器 %o0-%o5 和 %f0-%f31 可能会用作临时寄存器。
整数和单精度浮点参数 32 位对齐。
如果双精度浮点参数的偏移量是 8 的倍数,则保证 64 位对齐。
每个控制传输指令(分支和调用)后面必须紧跟 nop。
调用指令必须包括一个额外(最终)参数,它表示用于将参数传递给所调用例程的寄存器数量。
请注意,对于 SPARC 系统,将删除扩展“调用”后面的指令。
参数在堆栈上传递。由于未发出任何调用指令,因此第一个参数位于 (%esp),第二个参数位于 4 (%esp) 等等。32 位或更小的整数结果在 %eax 中返回,64 位整数结果在 %edx:%eax 中返回。浮点结果在 %st(0) 中返回。
代码可能会使用寄存器 %eax、%ecx 和 %edx。其他任何寄存器中的值都必须保留。浮点堆栈在内联扩展模板开头处为空,并且在结尾处也必须为空(返回的浮点值除外)。
以 -xarch={sse|sse2} 编译的要在 Oracle Solaris x86 SSE/SSE2 Pentium 4 兼容平台上运行的程序只能在启用了 SSE/SSE2 的平台上运行。在未启用 SSE/SSE2 的平台上运行此类程序会导致段故障或出现错误结果,而不发出任何显式警告消息。从 Solaris 10 发行版开始,操作系统和编译器将阻止在未启用 SSE/SSE2 的平台上执行 SSE/SSE2 编译的二进制文件。
从 Solaris 9 Update 6 开始的操作系统发行版在 Pentium 4 兼容平台上启用了 SSE/SSE2。早期版本的 Solaris OS 未启用 SSE/SSE2。
此警告还会扩展到采用 .il 内联汇编语言函数或 __asm() 汇编程序代码(使用 SSE/SSE2 指令)的程序。
如果在不同的步骤中进行编译和链接,请始终使用编译器和 -xarch={sse|sse2} 进行链接,以确保链接正确的启动例程。
参数根据其分类传递。分类包括整数、sse 和内存参数。
_Bool、char、short、int、long、long long 和 pointer 类型(带符号和无符号)的参数是整数参数。大小小于或等于 16 字节且包含 _Bool、char、short、int、long、long long 和 pointer 类型对齐成员的聚合类型(结构、联合、数组)的参数也是整数参数。
float 和 double 类型的参数是 sse 参数。大小小于或等于 16 字节且包含 float 和 double 类型对齐成员的聚合类型的参数也是 sse 参数。
long double 类型的参数和大小大于 16 字节或包含未对齐成员的聚合类型的参数是内存参数。
整数参数在整数寄存器中由下一个序列传递:%rdi、%rsi、%rdx、%rcx、%r8 和 %r9。一个聚合类型的整数参数最多可容纳 2 个整数寄存器。如果整数参数的数量大于 6 个,则将第 7 个以及后续整数参数视为内存参数。
Sse 参数在 sse 寄存器中按从 %xmm0 到 %xmm7 的顺序传递。一个聚合类型的 sse 参数最多可容纳 2 个 sse 寄存器,每个 sse 寄存器最多可容纳 8 字节的参数。例如,double complex 类型的参数在 2 个后续 sse 寄存器中传递,float complex 类型的参数在 1 个 sse 寄存器中传递。如果 sse 参数的数量大于 8 个,则将第 9 个以及后续 sse 参数视为内存参数。
整数参数和 sse 参数独立编号。
内存参数在堆栈上按在函数参数列表中从右向左的显示顺序传递。堆栈上的每个参数都根据其大小对齐,如果大小小于或等于 8,则在 8 处对齐;否则,如果在内联扩展模板堆栈开头,则在 16 处对齐。
由于未发出任何调用指令,因此第一个内存参数位于 (%rsp),第二个内存参数位于 8(%rsp) 或位于 16(%rsp),具体取决于第一个内存参数的大小和第二个内存参数的对齐方式等等。
返回值分类的方式与参数相同。
8 字节或更小的整数结果在 %rax 中返回,9 到 16 字节的整数结果在 %rdx:%rax 中返回。
Sse 结果也根据其大小在 %xmm0 或 %xmm1:%xmm0 中返回。
long double 类型的结果在 %st(0) 中返回。
如果返回值的类型是 long double complex,则值的实部在 %st0 中返回,虚部在 %st1 中返回。
对于内存结果,调用方会为返回值提供空间,并在 %rdi 中传递此存储的地址,如同这是函数的第一个参数。实际上,此地址将成为隐藏的首参数。返回时,%rax 将包含调用方已在 %rdi 中传入的地址。
代码无法更改寄存器 %rbp。浮点堆栈在内联扩展模板开头处为空,并且在结尾处也必须为空(返回的浮点值除外)。
除 %rbp 之外,寄存器 %rbx 和 %r12-%r15 中的值必须在内联的代码中保留。
有关示例,请参见 libm.il 或 vis.il。您可以在编译器的 lib/ 目录下找到特定于支持的每个体系结构的这些库的一个版本。
inline 不会检查是否违反上述编码约定。
由 Darryl Gove 编著的《Solaris Application Programming》,(Prentice-Hall 2008 ISBN:0138134553)
由 SPARC International Inc. 提供的《The SPARC Architecture Manual Version 9》,网址 http://www.sparc.com/resource.htm。请参见附录 G。