无效的模块格式 [英] Invalid module format

查看:422
本文介绍了无效的模块格式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

$insmod helloworld module generates the error message "Invalid module format".

$dmesg outputs:

overflow in relocation type 10 val ffffffff88640070
'hello' likely not compiled with -mcmodel=kernel

Makefile是传统格式(使用(CC))和模块构建系统格式"make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules"的混合.

The Makefile is a mix of tradition format (using (CC)) and module build system format "make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules".

系统为1.6.18-194.el5 x86_64.当在i386机器中使用相同的Makefile时,它可以正常工作.

The system is 1.6.18-194.el5 x86_64. The same Makefile works fine when it is used in i386 machine.

关于要研究什么的任何想法?谢谢.

Any idea of what to look into? Thanks.

#Makefile, mix of (CC) and kernel module build system

CFLAGS+=-D"KBUILD_STR(s)=\#s" -D"KBUILD_BASENAME=KBUILD_STR(hello)"
CFLAGS+=-D__KERNEL__ -DMODULE -I$(KERNEL_BUILD_DIR)/include

KERNEL_BUILD_DIR=/lib/modules/2.6.18-194.el5/build
TARGETNAME=hello
BUILD_ALT_DIR=linux

# The main target (note that both library and driver are .ko files
#
all: $(BUILD_ALT_DIR)/$(TARGETNAME).ko
$(BUILD_ALT_DIR)/_$(TARGETNAME).o: hello.o
@echo Linking objects to loadable module
@mkdir -p $(BUILD_ALT_DIR)
@echo $(CURDIR)/$@
@$(LD) -Map=$@.map -r -o $@ $^
@echo " LD_D [$@]"

$(BUILD_ALT_DIR)/$(TARGETNAME).ko: $(BUILD_ALT_DIR)/_$(TARGETNAME).o
@rm -f $(BUILD_ALT_DIR)/$(TARGETNAME).o
@echo create Makefile
@$(SHELL) -c 'echo "obj-m := $(TARGETNAME).o" > $(BUILD_ALT_DIR)/Makefile'
@$(SHELL) -c 'echo "$(TARGETNAME)-objs := _$(TARGETNAME).o" >> $(BUILD_ALT_DIR)/Makefile'
@$(SHELL) -c 'echo ".PHONY: `pwd`/$(BUILD_ALT_DIR)/_$(TARGETNAME).o" >> $(BUILD_ALT_DIR)/Makefile'
@$(SHELL) -c 'cd $(BUILD_ALT_DIR); $(MAKE) -C $(KERNEL_BUILD_DIR) M=`pwd`'
@echo " KO_D [$@]"


$(BUILD_ALT_DIR)/%.o: %.c
@echo Compiling C source to object file:
@mkdir -p $(BUILD_ALT_DIR)
# @echo $(CURDIR)/$@
@$(CC) -c -Wall $(CFLAGS) $(CFLAGS) $< -o $@
@echo " CC_D [$@]"

clean:
    rm -f $(BUILD_ALT_DIR)/*.o $(BUILD_ALT_DIR)/*.d  $(BUILD_ALT_DIR)/core  $(BUILD_ALT_DIR)/*.map

hello.c

#include <linux/autoconf.h> // this is needed

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

static int hello_init(void)
{ 
  printk(KERN_ALERT "Hello, world\n");

    return 0;
}

static void hello_exit(void)
{
    printk(KERN_ALERT "Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);

推荐答案

dmesg输出告诉您什么地方不对:

The dmesg output tells you what is wrong:

'hello' likely not compiled with -mcmodel=kernel

在x86-64架构上,必须使用特殊标志编译内核(包括模块)中运行的所有代码(包括模块),该标志指示编译器生成将在代码的上半部分运行的代码.虚拟地址空间(用户模式程序在地址空间的下半部分运行).

On the x86-64 architecture, all code running in the kernel (including modules) must be compiled with a special flag, which tells the compiler to generate code which will run in the top half of the virtual address space (user mode programs run on the bottom half of the address space).

如果我正确地读取了Makefile,则说明您是在内核构建系统外部 编译C代码,并且仅为了最终链接而调用内核构建系统. 请勿执行此操作.这不仅是内存模型,在编译C源代码时还必须添加其他几个标志.这些标志可以随内核版本甚至内核配置而更改.您不知道,也不应该知道,因为内核构建系统会为您处理所有这些事情.

If I am reading your Makefile correctly, you are compiling the C code outside the kernel build system, and calling into the kernel build system only for the final linking. Do not do this. It is not just the memory model, there are several other flags which must be added when compiling the C source code. These flags can change with the kernel version, or even with the kernel configuration — you do not know, and you are not supposed to have to know, since the kernel build system deals with it all for you.

不仅是-mcmodel=kernel.还有很多其他的东西,弄错它们会并且会引起问题.

It is not just -mcmodel=kernel. There are many others, and getting them wrong can and will cause problems.

您缺少正确标志的事实在您的代码中非常明显:

The fact that you are missing the correct flags is quite visible in your code:

#include <linux/autoconf.h> // this is needed

否,这不是必需的.如果需要它,说明您做错了.看一下内核构建系统传递给C编译器的标志之一:

No, this is not needed. If you need it, you are doing it wrong. Take a look at one of the flags the kernel build system passes to the C compiler:

-include include/linux/autoconf.h

此标志告诉C编译器始终隐式包括linux/autoconf.h头.由于总是隐式包含它,因此您不必手动包含它.而且,由于您永远不会手动添加它,因此可以更改其位置—它移到了generated/autoconf.h,后来又移到了linux/kconfig.h,谁知道下一步将在哪里结束.

This flags tells the C compiler to always implicitly include the linux/autoconf.h header. Since it is always implicitly included, you never have to include it manually. And since you never include it manually, its location is allowed to change — it moved to generated/autoconf.h and later to linux/kconfig.h, and who knows where else it will end up next.

在32位x86上它完全可以为您工作的事实真是太幸运了.即使在32位系统上,也应该以正确的方式进行操作.

The fact that it worked at all for you in 32-bit x86 is just luck. You should do it the correct way even on 32-bit.

这篇关于无效的模块格式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆