我一直在阅读有关 ASM 中调用约定的内容,这是我目前所了解的内容:
x86(userland) x86(kernel) x64(userland) x64(kernel)
1st arg Stack EBX RDI RDI
2nd arg Stack ECX RSI RSI
3rd arg Stack EDX RDX RDX
4th arg Stack ESI RCX R10
5th arg Stack EDI R8 R8
6th arg Stack EBP R9 R9
result EAX EAX RAX RAX
我的问题是:
到目前为止我学到的是正确的吗?
如何在 x86(内核)和 x64(两者)中传递超过 6 个参数?使用堆栈?介意给我看一个小例子吗?
我有一个内核模块,我愿意从 ASM 调用该模块中的函数。我应该使用什么约定?内核态还是用户态?
最佳答案
1) 是的,它似乎只适用于 Linux。我认为您可以依赖此处描述的 Linux 约定:http://www.x86-64.org/documentation/abi.pdf .但实际上您可以按照 intel assembly manual 中描述的方式自由传递参数。第6.3.3章
2) 使用堆栈是编译器的处理方式:
int func(int i, int j, int k, int l, int m, int n, int o, int p, int q) { return q; }
void func2() { func(1, 2, 3, 4, 5, 6, 7, 8, 9); }
然后:
$ gcc -c func.c && objdump -d func.o
在我的 x86_64 机器上输出:
0000000000000000 <func>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 89 7d fc mov %edi,-0x4(%rbp)
7: 89 75 f8 mov %esi,-0x8(%rbp)
a: 89 55 f4 mov %edx,-0xc(%rbp)
d: 89 4d f0 mov %ecx,-0x10(%rbp)
10: 44 89 45 ec mov %r8d,-0x14(%rbp)
14: 44 89 4d e8 mov %r9d,-0x18(%rbp)
18: 8b 45 20 mov 0x20(%rbp),%eax
1b: 5d pop %rbp
1c: c3 retq
000000000000001d <func2>:
1d: 55 push %rbp
1e: 48 89 e5 mov %rsp,%rbp
21: 48 83 ec 18 sub $0x18,%rsp
25: c7 44 24 10 09 00 00 movl $0x9,0x10(%rsp)
2c: 00
2d: c7 44 24 08 08 00 00 movl $0x8,0x8(%rsp)
34: 00
35: c7 04 24 07 00 00 00 movl $0x7,(%rsp)
3c: 41 b9 06 00 00 00 mov $0x6,%r9d
42: 41 b8 05 00 00 00 mov $0x5,%r8d
48: b9 04 00 00 00 mov $0x4,%ecx
4d: ba 03 00 00 00 mov $0x3,%edx
52: be 02 00 00 00 mov $0x2,%esi
57: bf 01 00 00 00 mov $0x1,%edi
5c: e8 00 00 00 00 callq 61 <func2+0x44>
61: c9 leaveq
62: c3 retq
3) 我会说内核,因为您是在内核模块中调用该函数。要获得完整有效的示例,您可以在模块中从 C 调用您的函数,并按照我查看编译器如何处理它的方式反汇编 .ko。它应该是直截了当的。
关于c - ASM 调用约定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20530052/