学堂在线_操作系统_notes_第4讲_Lab1_bootloader启动ucore os_C实现函数调用 GCC内联汇编INLINE ASSEMBLY X86中断处理
- C实现函数调用
-
- 参考资料
- GCC内联汇编INLINE ASSEMBLY
-
- 什么是内联汇编(Inline assembly )?
- 有何用处?
- 如何工作?
- Example 1
- Syntax
- Example 2
- Example 3
- 参考资料
- X86中断处理
-
- 了解x86中的中断源
- 了解CPU如何处理与操作系统的中断
- 中断向量表(中断描述符表)IDT)进行初始化
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, %?x\n") // 把 0xffff值 赋给 eax寄存器。asm 是 内联汇编的关键词。
Syntax
// 内联汇编代码的完整句法: asm ( "assembler template" // asm 是 内联汇编的关键词。assembler template处 用于填入形,如用于填入形movl $0xffff, %?x\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。