c - ASM 调用约定

标签 c assembly linux-kernel x86 x86-64

我一直在阅读有关 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

我的问题是:

  1. 到目前为止我学到的是正确的吗?

  2. 如何在 x86(内核)和 x64(两者)中传递超过 6 个参数?使用堆栈?介意给我看一个小例子吗?

  3. 我有一个内核模块,我愿意从 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/

相关文章:

arrays - 使用sizeof将字符附加到字符串形式用户的末尾

c - 维吉尼亚密码错误输出

c - 将输入获取到动态分配的内存中,然后返回指针

assembly - 令人困惑的功能

linux - 尝试插入内核模块 noop-iosched.ko 导致段错误

c - 分配内存时出错

linux - 汇编代码程序发生段错误

gcc - 我的内核原型(prototype)存在问题(x86_64)

ubuntu - NR_CPUS 定义在内核编译期间翻译为 8192

linux - 如何制作一个(API 或驱动程序)来处理 Linux 中 USB 设备端的所有 USB 串行请求?