我正在尝试学习如何使用ptrace库来跟踪所有系统调用及其参数。我被困在获取传递给系统调用的参数。
我浏览了许多在线资源和SO问题,并发现在64位机器上,参数存储在寄存器rax(sys call number), rdi, rsi, rdx, r10, r8, r9
中
以相同的顺序。检查this website。
为了证实这一点,我写了一个简单的C程序如下
#include<stdio.h>
#include<fcntl.h>
int main() {
printf("some print data");
open("/tmp/sprintf.c", O_RDWR);
}
并使用gcc -S t.c
为此生成汇编代码,但生成的汇编代码如下所示
.file "t.c"
.section .rodata
.LC0:
.string "some print data"
.LC1:
.string "/tmp/sprintf.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %edi
movl $0, %eax
call printf
movl $2, %esi
movl $.LC1, %edi
movl $0, %eax
call open
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
.section .note.GNU-stack,"",@progbits
正如您所看到的,此代码会在esi
和edi
上存储参数。
为什么会这样?
另外请指导我从C代码访问这些寄存器/内存位置传递参数的最佳方法是什么?我怎样才能弄清楚寄存器的内容是参数本身还是存储实际参数的存储位置?
谢谢!
答案 0 :(得分:0)
此代码存储
上的参数esi
和edi
32位指令较小,因此在可能的情况下是首选。另请参阅Why do most x64 instructions zero the upper part of a 32 bit register。
如何判断寄存器的内容是参数本身还是存储实际参数的存储位置?
AMD64 SystemV调用约定永远不会隐式地用隐藏指针替换函数arg。 C原型中的整数/指针args总是直接进入arg传递寄存器。
按值传递的结构/联合进入一个或多个寄存器,或进入堆栈。
完整的详细信息记录在the ABI中。查看x86标记维基中的更多链接。 http://www.x86-64.org/documentation.html现在已经关闭了,所以我在github上链接了当前版本。