【问题标题】:Understanding simple Linux syscall in libc.a了解 libc.a 中的简单 Linux 系统调用
【发布时间】:2013-03-08 08:53:44
【问题描述】:

我正在使用 glibc-2.13-1 运行 64 位 Debian 4.7.2-5 Linux 系统。当我在libc.a 中搜索一些函数调用的汇编代码时,我遇到了这个:

file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <sync>:
   0:   b9 a2 00 00 00        mov    eax,0xa2
   5:   0f 05                 syscall
   7:   48 3d 01 f0 ff ff     cmp    rax,0xfffffffffffff001
   d:   0f 83 00 00 00 00     jae    13 <sync+0x13>
  13:   c3                    ret

我对这是做什么感到有点困惑。 mov eax,0xa2 的意义何在?如果这是一台 64 位机器,为什么不使用 rax 寄存器(系统调用如何知道要进行什么系统调用)?简而言之:这 5 行代码是做什么的?

【问题讨论】:

    标签: linux assembly x86-64 system-calls


    【解决方案1】:

    0xa2 是系统调用号。内核使用它来决定执行什么实际功能,因为syscall 指令本身不包含任何信息。

    至于rax,它确实被使用了。为了延续过去的传统,eaxrax 的低 32 位的别名。但是,x64 架构有一个不为人知的怪癖:whenever you modify that low 32-bit part, the top 32-bits get zeroed。所以,实际上mov eax, 0xa2 等价于mov rax, 0xa2,只是它的编码更短。 NASM 或 as -O2 甚至会为您进行优化。

    最后三个指令执行错误处理。如果%rax 介于-1 和-4095 之间,则表示系统调用返回了错误,对于任何 Linux 系统调用。以下是它在原始来源中的样子:

    cmpq $-4095, %rax    /* Check %rax for error.  */
    jae __syscall_error  /* Branch forward if it failed.  */
    ret                  /* Return to caller.  */
    

    您看到 jae 的目标错误,因为您正在反汇编一个可重定位对象,并且可重定位字段已设置为 0,因为它们将在最终链接时进行修补。

    要查看重定位目标,-r 切换到objdump 命令行

    0000000000000000 <sync>:
       0:   b8 a2 00 00 00          mov    $0xa2,%eax
       5:   0f 05                   syscall 
       7:   48 3d 01 f0 ff ff       cmp    $0xfffffffffffff001,%rax
       d:   0f 83 00 00 00 00       jae    13 <sync+0x13>
                            f: R_X86_64_PC32        __syscall_error-0x4
      13:   c3                      retq   
    

    您可以看到偏移量f 处的字节将被修补,以便跳转到__syscall_error

    阅读https://cs.lmu.edu/~ray/notes/syscalls/ 了解有关系统调用的更多信息。
    还有The Definitive Guide to Linux System Calls博客文章。

    【讨论】:

      【解决方案2】:

      mov eax,0xa2 足以设置整个rax,因为修改诸如eax 之类的32 位通用寄存器总是将相应64 位寄存器的前32 位清零(在本例中为rax)。

      系统调用号a2sync,请参阅/usr/src/linux/usr/include/asm/unistd_64.h 获取Linux x86-64 系统调用列表(将/usr/src/linux/ 替换为您安装Linux 源代码的目录)。

      总的来说,这些行打开了一个在这些指令之前已经定义的文件,然后将syscall(在rax)的返回值与0xfffffffffffff001进行比较,然后有一些奇怪的东西:0f 83 00 00 00 00@ 987654333@ 是条件跳转到下一条指令,无论如何都会到达。

      【讨论】:

      • 在安装了 glibc 头文件的普通 Linux 系统中,/usr/include/asm/unistd_64.h 或其他等效项将存在,因此您可以在用户空间 C 程序中使用 #include &lt;asm/unistd.h&gt;__NR_sync
      猜你喜欢
      • 1970-01-01
      • 2014-03-26
      • 1970-01-01
      • 1970-01-01
      • 2020-05-18
      • 1970-01-01
      • 2023-03-18
      • 2011-08-18
      • 2012-06-30
      相关资源
      最近更新 更多