在linux内核 - x64模式下混合汇编和C函数

时间:2018-02-06 01:09:05

标签: 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

1 个答案:

答案 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)

由于callret之前的最后一件事,您也可以jmp printMessageTail Call)。达到ret中的printMessage时,控件将返回调用sample_assembly_function的函数。这段代码应该有效:

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