代码之家  ›  专栏  ›  技术社区  ›  Alex B

32位应用程序如何在64位Linux上进行系统调用?

  •  30
  • Alex B  · 技术社区  · 14 年前

    1

    我想知道 力学 32位应用程序如何在64位内核上进行系统调用。我怀疑答案在libc和/或内核源代码中的某个地方,但是深入研究源代码对我来说是很费时的,因为我不知道在哪里可以找到。

    还有一个更重要的问题, 2 从逻辑上讲,来自32位应用程序系统调用的调用必须转换为64位内部内核环境。这是如何实现的,在哪里实现的?

    1 “32位”=IA-32,“64位”=AMD64
    2 在你的回答中,假设它很重要:)

    1 回复  |  直到 14 年前
        1
  •  28
  •   caf    14 年前

    从用户空间的角度来看,机制与在32位本机内核上进行系统调用是相同的——所有的用户模式代码,包括32位glibc,都以相同的方式工作。

    在内核方面,旧的IA32入口点来自用户空间(例如。 int 0x80 ia32_syscall 汇编程序例程(转换到内核空间涉及处理器加载内核的代码段选择器,这会导致转换到64位“长”模式。

    这个 ia32\系统调用

    movl    %edi,%r8d
    .if \noebp
    .else
    movl    %ebp,%r9d
    .endif
    xchg    %ecx,%esi
    movl    %ebx,%edi
    movl    %edx,%edx   /* zero extension */
    

    然后它使用IA32 syscall编号通过表进行函数调用, ia32_sys_call_table . 这实际上是将IA32 syscall编号与本机syscall实现相匹配(IA32和x86\u64之间的syscall编号差别很大)。此表的第一部分如下所示:

    ia32_sys_call_table:
        .quad sys_restart_syscall
        .quad sys_exit
        .quad stub32_fork
        .quad sys_read
        .quad sys_write
    

    对于大多数系统调用,x86\u64实现现在可以像 exit() . 对于其他人,比如 fork()

    如您所见,内核代码中的开销是最小的—只需对寄存器值进行一些微不足道的修改,对于一些函数,还需要额外的函数调用。我不确定如果加载一个代码段选择器导致从32位模式转换到64位模式,处理器执行起来是否比不加载的慢-请查看处理器体系结构手册。