我正在学习汇编语言,我创建了一个简单的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
答案 0 :(得分:2)
使用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)
由于call
是ret
之前的最后一件事,您也可以jmp printMessage
(Tail Call)。达到ret
中的printMessage
时,控件将返回调用sample_assembly_function
的函数。这段代码应该有效:
ENTRY(sample_assembly_function)
mov $10, %edi
jmp printMessage
END(sample_assembly_function)