且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在Linux内核中找不到方法__kernel_vsyscall时遇到问题

更新时间:2023-11-16 18:45:52

假设当前目录位于linux内核源代码的开头,那么这是定义__kernel_vsyscall符号的文件的位置. (下面显示的全部仅用于x86,它在许多其他硬件体系结构中尚不存在.)

Assuming your current directory is at the head of the linux kernel source, here are the locations of the files that define the __kernel_vsyscall symbol. (all shown below are only for x86, it does not exists in many other hardware architecture yet).

./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.

As you can see, it is essentially declared and implemented inside three file: int80.S, sysenter.S, and syscall.S.

正在执行syscall.S:

Taking 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".

And "syscall" above actually resolved to "int 0x80" if you read the above file and "arch/x86/vdso/vdso32/sigreturn.S" combined.

对于sysenter.S,它使用intel汇编指令"sysenter"来实现系统调用转换.

And for sysenter.S, it is using intel assembly instruction "sysenter" to implement system call transition.

对于int80.S,它使用"int 0x80"进行系统调用转换.

And for int80.S, it is using "int 0x80" for the system call transition.

如果您询问用于syscall实现的方法,请查看arch/x86/vdso/vdso32-setup.c:

And if you asked which is the method used for syscall implementation, then look into 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).

As you can see, modern OS preferred the sysenter approach, as it is faster than the int80 approach. (symbolically the "vds32_syscall_start" will fall back to int80).