了解 libc.a 中的简单 Linux 系统调用

Vil*_*ray 2 linux assembly x86-64 system-calls

我正在使用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
Run Code Online (Sandbox Code Playgroud)

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

Igo*_*sky 5

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

至于rax,它确实习惯了。为了延续过去开始的传统,eaxrax.的低 32 位的别名。然而,x64 架构有一个不太为人所知的怪癖:每当您修改低 32 位部分时,高 32 位就会归零。所以,实际上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.  */
Run Code Online (Sandbox Code Playgroud)

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

要查看重定位目标,请将-rswitch添加到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   
Run Code Online (Sandbox Code Playgroud)

您可以看到 offset 处的字节f将被修补,以便跳转到 __syscall_error.

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