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

时间:2013-03-19 15:26:59

标签: 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

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

2 个答案:

答案 0 :(得分:3)

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

至于rax 会被使用。为了延续过去开始的传统,eaxrax的低32位的别名。但是,有一个不太知名的x64架构的怪癖:每当你修改那个低32位的部分时,前32位的就会被归零。因此,实际上mov eax, 0xa2等同于mov rax, 0xa2,但其编码较短。

最后三条指令执行错误处理。如果%rax介于-1和-4095之间,则表示系统调用返回了错误。以下是它在原始资料中的外观:

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

有关系统调用的更多信息,see here

答案 1 :(得分:1)

mov eax,0xa2足以设置整个rax,因为修改32位通用寄存器(如eax 0)始终是相应64位寄存器的前32位(在此案例rax)。

Syscall number a2sync,有关Linux x86-64系统调用的列表,请参阅/usr/src/linux/usr/include/asm/unistd_64.h(将/usr/src/linux/替换为安装了Linux源的目录)

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