假设当前目录位于linux内核源代码的开头,那么这是定义__kernel_vsyscall符号的文件的位置. (下面显示的全部仅用于x86,它在许多其他硬件体系结构中尚不存在).
./arch/x86/vdso/vdso32/syscall.S:
__kernel_vsyscall:
./arch/x86/vdso/vdso32/sysenter.S:
__kernel_vsyscall:
./arch/x86/vdso/vdso32/int80.S:
__kernel_vsyscall:
如您所见,它实际上是在以下三个文件中声明和实现的:int80.S,sysenter.S和syscall.S.
以syscall.S:
__kernel_vsyscall:
.LSTART_vsyscall:
push %ebp
.Lpush_ebp:
movl %ecx, %ebp
syscall
movl $__USER32_DS, %ecx
movl %ecx, %ss
movl %ebp, %ecx
popl %ebp
如果您阅读上述文件并结合了“ arch / x86 / vdso / vdso32 / sigreturn.S”,则上面的“ syscall”实际上解析为“ int 0x80”.
对于sysenter.S,它使用intel汇编指令“ sysenter”来实现系统调用转换.
对于int80.S,它使用“ int 0x80”进行系统调用转换.
并且,如果您询问用于syscall实现的方法是哪种,请查看arch / x86 / vdso / vdso32-setup.c:
int __init sysenter_setup(void)
{
void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
const void *vsyscall;
size_t vsyscall_len;
vdso32_pages[0] = virt_to_page(syscall_page);
#ifdef CONFIG_X86_32
gate_vma_init();
#endif
if (vdso32_syscall()) {
vsyscall = &vdso32_syscall_start;
vsyscall_len = &vdso32_syscall_end - &vdso32_syscall_start;
} else if (vdso32_sysenter()){
vsyscall = &vdso32_sysenter_start;
vsyscall_len = &vdso32_sysenter_end - &vdso32_sysenter_start;
} else {
vsyscall = &vdso32_int80_start;
vsyscall_len = &vdso32_int80_end - &vdso32_int80_start;
}
memcpy(syscall_page, vsyscall, vsyscall_len);
relocate_vdso(syscall_page);
return 0;
}
如您所见,现代OS首选sysenter方法,因为它比int80方法更快. (象征性地,“ vds32_syscall_start”将退回到int80).