c - 在 Linux 内核中混合汇编和 C 函数 - x64 模式

标签 c assembly linux-kernel x86-64 calling-convention

我正在学习汇编语言,并且创建了一个简单的 Linux 内核模块来尝试如何从模块调用汇编函数,该模块又调用 C 函数。该代码编译良好。但是,当我尝试插入模块时,它会导致内核崩溃。我从这篇文章中得到了这个想法:Calling C functions from x86 assembly language 。我想知道是否有人可以帮助我理解为什么它不起作用。

第一个是汇编代码:

#include <linux/linkage.h>
ENTRY(sample_assembly_function)
pushq $10
call printMessage
add $0x4, %rsp
END(sample_assembly_function)

第二个文件是示例模块文件:

#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("Proprietary");

void sample_assembly_function(void);

void printMessage(int num)
{
 printk(KERN_ERR "MixAssemblyAndC: PrintMessage=%d.\n", num);
}

static int __init AModule_init(void)
{
sample_assembly_function();
return 0;
}

static void __exit AModule_exit(void)
{
printk("MixAssemblyAndC: Goodbye, world!\n");
}

module_init(AModule_init);
module_exit(AModule_exit);

最后这是 Makefile:

KERNELDIR:=/lib/modules/$(shell uname -r)/build
PWD=$(shell pwd)
obj-m += test.o
test-y := AModule.o ASample.o

all:
    $(MAKE) -C $(KERNELDIR) M=$(PWD)

clean:
     $(MAKE) -C $(KERNELDIR) M=$(PWD) clean

install:
     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

最佳答案

使用 Linux 64-bit System V ABI 时调用约定传递寄存器 RDI、RSI、RDX、RCX、R8 和 R9 中的前 6 个整数类或指针参数。任何剩余的参数都被压入堆栈。您在问题中链接到的代码是 32 位代码,并且使用 Linux i386 System V ABI作为调用约定。这与 64 位代码不兼容。

只需执行 mov $10, %rdi 即可加载第一个参数。最好您可以执行 mov $10, %edi。后者将值 10 移入 EDI,但由于目标是 32 位寄存器,处理器会自动将值在 64 位寄存器上进行零扩展,因此 10 被移至 RDI。后者是较短的编码。

您需要一个 ret 指令来结束您的汇编语言例程。生成的代码应如下所示:

#include <linux/linkage.h>

ENTRY(sample_assembly_function)
mov $10, %edi
call printMessage
ret
END(sample_assembly_function)

由于 callret 之前的最后一件事,因此您也可以只 jmp printMessage ( Tail Call )。当到达 printMessage 中的 ret 时,控制权将返回到调用 sample_assemble_function 的函数。此代码应该有效:

ENTRY(sample_assembly_function)
mov $10, %edi
jmp printMessage
END(sample_assembly_function)

关于c - 在 Linux 内核中混合汇编和 C 函数 - x64 模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48633971/

相关文章:

c - 在理解如何正确使用 C 中的函数时遇到问题

c++ - zlib 的压缩函数没有做任何事情。为什么?

c - 炸弹实验室第 4 阶段 func4

c - Linux 设备驱动读写函数问题

c - 这个 C 结构如何被翻译成 Cobol

无法在C中正确获取数组的大小

C内联汇编帮助(digital mars c编译器)

使用泰勒展开的 sin(x) 汇编代码

Linux 默认调度程序替代方案

linux - 使用 perf 确定进程何时以及为何进入不间断 sleep