2

我正在使用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

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

4

2 回答 2

5

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

至于rax,它确实会被使用。为了延续过去的传统,eax是低 32 位的别名rax。但是,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.  */

您会看到错误的目标,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   

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

阅读https://cs.lmu.edu/~ray/notes/syscalls/了解有关系统调用的更多信息。
还有Linux 系统调用权威指南博客文章。

于 2013-03-19T15:51:03.593 回答
1

mov eax,0xa2设置整个 就足够了rax,因为修改 32 位通用寄存器(例如eax零)总是对应 64 位寄存器的前 32 位(在这种情况下rax)。

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

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

于 2013-03-19T15:50:56.103 回答