学堂在线_操作系统_notes_第4讲_Lab1_bootloader启动ucore os_C函数调用的实现+GCC内联汇编INLINE ASSEMBLY+X86中的中断处理
20220629.No.1824
C函数调用的实现
-
理解C函数调用在汇编级是如何实现的
-
理解如何在汇编级代码中调用C函数
-
理解基于EBP寄存器的函数调用栈
-
其他需要注意的事项
-
参数(parameters)& 函数返回值(return values)可通过
寄存器或位于内存中的栈来传递。用寄存器效率更高。 -
不需要保存/恢复(save/restore)所有寄存器.
-
参考资料
- Understanding the
Stack: http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Mips/stack.html
GCC内联汇编INLINE ASSEMBLY
什么是内联汇编(Inline assembly )?
- 这是GCC对C语言的扩张
- 可直接在C语句中插入汇编指令
有何用处?
- 调用C语言不支持的指令(例如:用C语言无法表示寄存器)
- 用汇编在C语言中手动优化
如何工作?
- 用给定的模板和约束来生成汇编指令
- 在C函数内形成汇编源码.
Example 1
// 汇编语言:
Assembly (*.S):
movl $0xffff, %eax // 把 0xffff值 赋给 eax寄存器。
// 以上代码 改写为 C的内联汇编:
Inline assembly (*.c):
asm ("movl $0xffff, %%eax\n") // 把 0xffff值 赋给 eax寄存器。asm 是 内联汇编的关键字。
Syntax
// 内联汇编代码的完整句法:
asm ( "assembler template" // asm 是 内联汇编的关键字。assembler template处 用于填入形如“movl $0xffff, %%eax\n”的字符串。
: output operands // (optional) 输出操作数的约束表示。把某变量用某寄存器表示。
: input operands // (optional) 输入操作数的约束表示。把某变量用某寄存器表示。
: clobbers // (optional) 约束表示。把某变量用某寄存器表示。
);
Example 2
Inline assembly (*.c):
uint32_t cr0; // cr0 是 内存变量。
asm volatile ("movl %%cr0, %0\n" :"=r"(cr0)); // 把 cr0寄存器的值 写入 %0寄存器,(用 输出操作数的约束表示)再把 %0寄存器的值 赋给 cr0内存变量。
cr0|= 0x80000000; // 把 cr0内存变量的某个bit 置为 1.
asm volatile ("movl %0, %%cr0\n" ::"r"(cr0)); // 把 cr0内存变量的值 写入 %0寄存器,(用 输入操作数的约束表示)再把 %0寄存器的值 赋给 cr0寄存器。
// •volatile (不需要做进一步优化,不需要重新排序):No reordering; No elimination
// •%0 (%0寄存器):The first constraint following
// •r (任一寄存器):A constraint; GCC is free to use any register
// 把上述内联汇编代码 翻译为 汇编语言:
Generated asssembly code (*.s):
movl %cr0, %ebx // 把 cr0寄存器的值 赋给 ebx寄存器。
movl %ebx, 12(%esp) // 把 ebx寄存器的值 赋给 esp局部变量。
orl $-2147483648, 12(%esp) // 把 esp局部变量的某个bit 置为 1.
movl 12(%esp), %eax // 把 esp局部变量的值 赋给 eax寄存器。
movl %eax, %cr0 // 把 eax寄存器的值 赋给 cr0寄存器。
// 内联汇编的代码更简洁,因为加入约束表示后,由gcc编译器自动把寄存器之间的关系建立好了。
Example 3
// 调用 "int 80"指令 产生 软中断,内联汇编代码如下:
long __res, arg1 = 2, arg2 = 22, arg3 = 222, arg4 = 233; // 给 相应局部变量 赋值。
__asm__ volatile ("int $0x80" // 软中断指令。
: "=a" (__res) // 输出操作数的约束表示:eax寄存器 表示 返回值。
: "0" (11),"b" (arg1),"c" (arg2),"d" (arg3),"S" (arg4)); // 输入操作数的约束表示:把 arg1局部变量的值 赋给 ebx寄存器,把 arg2局部变量的值 赋给 ecx寄存器,把 arg3局部变量的值 赋给 edx寄存器,把 arg4局部变量的值 赋给 esi寄存器。
// Constraints (字母与寄存器之间的对应关系(约定、约束表示)):
// a = %eax
// b = %ebx
// c = %ecx
// d = %edx
// S = %esi
// D = %edi
// 0 = same as the first
// 上述 内联汇编代码 翻译为 汇编语言:
// 把 相应局部变量的值 赋给 相应寄存器,再调用 "int 80"指令 产生 软中断,最后把 eax寄存器的值 作为 返回值 返回。
……
movl $11, %eax
movl -28(%ebp), %ebx
movl -24(%ebp), %ecx
movl -20(%ebp), %edx
movl -16(%ebp), %esi
int $0x80
movl %eax, -12(%ebp)
参考资料
- GCC Manual 6.41 –6.43
- Inline assembly for x86 in Linux: http://www.ibm.com/developerworks/library/l-ia/index.html
X86中的中断处理
- 详见PPT。
- Chap. 6, Vol. 3, Intel® and IA-32 Architectures Software Developer’s Manual
本文详细探讨了C函数调用在汇编层面的实现,包括内联汇编的使用技巧,如GCC内联汇编的语法、X86中断处理和C函数调用栈管理。通过实例演示了如何利用内联汇编优化代码,并介绍了如何在C函数中处理中断和初始化中断向量表。

被折叠的 条评论
为什么被折叠?



