学堂在线_操作系统_notes_第4讲_Lab1_bootloader启动ucore os_C函数调用的实现+GCC内联汇编INLINE ASSEMBLY+X86中的中断处理

本文详细探讨了C函数调用在汇编层面的实现,包括内联汇编的使用技巧,如GCC内联汇编的语法、X86中断处理和C函数调用栈管理。通过实例演示了如何利用内联汇编优化代码,并介绍了如何在C函数中处理中断和初始化中断向量表。


20220629.No.1824


C函数调用的实现

  • 理解C函数调用在汇编级是如何实现的

  • 理解如何在汇编级代码中调用C函数

  • 理解基于EBP寄存器的函数调用栈

  • 其他需要注意的事项

    • 参数(parameters)& 函数返回值(return values)可通过寄存器位于内存中的栈来传递。用寄存器效率更高。

    • 不需要保存/恢复(save/restore)所有寄存器.

参考资料


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)

参考资料


X86中的中断处理

  • 详见PPT。
  • Chap. 6, Vol. 3, Intel® and IA-32 Architectures Software Developer’s Manual

了解x86中的中断源

了解CPU与操作系统如何处理中断

能够对中断向量表(中断描述符表,简称IDT)进行初始化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值