2013-03-19 115 views
2

我正在运行一个64位Debian 4.7.2-5 Linux系统,使用glibc-2.13-1。当我正在寻找在libc.a一些函数调用的汇编代码我碰到这样的:了解libc.a中的简单Linux系统调用

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是什么点,为什么不是rax寄存器被使用,如果这是一个64位机器(系统调用如何知道系统调用)?简而言之,这5行代码是做什么的?

回答

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

+0

为什么你说“'mov rax,0xa2'等价于'mov rax,0xa2',你的意思是:'mov eax,0xa2'等价于'mov rax,0xa2'? – 2013-12-12 14:34:32

+0

@VilhelmGray:良好的捕获,将解决它! – 2013-12-12 14:46:40

+0

我在我的评论中也遇到了自己的错字:“为什么”应该是“何时”。 :-P – 2013-12-12 16:09:12

1

mov eax,0xa2足以设置整个rax,因为修改的32位通用寄存器如eax零总是相应的64位寄存器的顶端32位(在这种情况下rax)。

系统调用号a2sync,看到/usr/src/linux/usr/include/asm/unistd_64.h为Linux系统调用X86-64的列表(在安装了你的Linux源代码目录替换/usr/src/linux/)。

作为一个整体,这些行打开这些指令之前已定义的文件,然后用0xfffffffffffff001比较syscall(在rax)的返回值,然后有东西有点怪:0f 83 00 00 00 00jae 13是条件跳转到下一个指令,无论如何都会被触及。