我使用 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行代码做了什么?
答案 0 :(得分:3)
0xa2是系统调用号。内核使用它来决定要执行的实际函数,因为syscall
指令本身不包含任何信息。
至于rax
, 会被使用。为了延续过去开始的传统,eax
是rax
的低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 a2
为sync
,有关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
是条件跳转到下一条指令,无论如何都会达到。