LDD2代码阅读手记: export.c 和 import.c
时间:2006-05-21 来源:lanttor.guo
笔记原创: 兰特
联系邮件: [email protected]
参考资料:
1. Linux Device Drivers, Second Edition, Alessandro
2. The Linux Kernel Module Programming Guide (v2.4.0), Peter Jay Salzman Ori Pomerantz
/*
* export.c -- export a symbol (maybe a versioned one) (v2.1)
*
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
* Copyright (C) 2001 O'Reilly & Associates
*
* The source code in this file can be freely used, adapted,
* and redistributed in source or binary form, so long as an
* acknowledgment appears in derived source files. The citation
* should list that the code comes from the book "Linux Device
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
* by O'Reilly & Associates. No warranty is attached;
* we cannot take responsibility for errors or fitness for use.
*
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
/* This stuff might go in the Makefile, but I'd better put it here */
#include <linux/config.h> /* retrieve the CONFIG_* macros */
#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
# define MODVERSIONS
#endif
/*
* Include the versioned definitions for both kernel symbols and our
* symbol, *unless* we are generating checksums (__GENKSYMS__
* defined) */
#if defined(MODVERSIONS) && !defined(__GENKSYMS__)
# include <linux/modversions.h>
# include "export.ver" /* redefine "export_function" to include CRC */
#endif
/*
* Everything from now on is normal. The previous stuff can be replaced
* by "$(CC) -D__KERNEL__ -DMODULE -DMODVERSIONS -DEXPORT_SYMTAB \
* -include $(INCLUDEDIR)/linux/modversions.h" if versioning
* is enabled, and the following (simpler) cmdline for genksyms:
* "$(CC) -E -DCONFIG_MODVERSIONS -DEXPORT_SYMTAB"
*/
#ifndef EXPORT_SYMTAB
# define EXPORT_SYMTAB /* need this one 'cause we export symbols */
#endif
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
#include "sysdep.h"
/* our dumb function, with two dumb arguments */
int export_function(int a, int b);
#ifdef __USE_OLD_SYMTAB__
static struct symbol_table export_syms = {
#include <linux/symtab_begin.h>
X(export_function),
#include <linux/symtab_end.h>
};
#else
EXPORT_SYMBOL(export_function);
#endif
int export_init(void)
{
REGISTER_SYMTAB(&export_syms);
return 0;
}
void export_cleanup(void)
{
}
int export_function(int a, int b)
{return a+b;}
module_init(export_init);
module_exit(export_cleanup);
MODULE_LICENSE("GPL");
export.c主要说明了EXPORT_SYMBOL的用法,我们已经在hello2.c中分析过了.
在这个程序里关于REGISTER_SYMTAB的用法是为了兼容2.0内核的, 我们可以现不用管它.(事实上,ldd2的作者
在编写针对内核2.0和2.4兼容的驱动程序上,做了大量的工作, 头文件"sysdep.h"主要就是做这个工作的)
显示的命名初始化函数和清除函数:
module_init(export_init);
module_exit(export_cleanup);
这样做的好处是内核中每一个模块的初始化函数和清除函数都会有唯一的名字,给调试带来方便.
要使用module_init和module_exit之前, 程序必须包含头文件<linux/init.h>.
在这个程序里导出了函数符号export_function, 它实现一个加法运算.
我们在import.c中用这个导出的符号. 下面是import.c的代码:
/*
* import.c -- a module using a symbol from export.c
*
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
* Copyright (C) 2001 O'Reilly & Associates
*
* The source code in this file can be freely used, adapted,
* and redistributed in source or binary form, so long as an
* acknowledgment appears in derived source files. The citation
* should list that the code comes from the book "Linux Device
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
* by O'Reilly & Associates. No warranty is attached;
* we cannot take responsibility for errors or fitness for use.
*
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
/*
* Use versioning if needed
*/
#include <linux/config.h> /* retrieve the CONFIG_* macros */
#ifdef CONFIG_MODVERSIONS
# undef MODVERSIONS /* it might be defined */
# define MODVERSIONS
#endif
#ifdef MODVERSIONS
# include <linux/modversions.h>
# include "export.ver"
#endif
#include <linux/module.h>
#include <linux/kernel.h>
#include "sysdep.h"
extern int export_function(int, int);
int import_init(void)
{
int i = export_function(2,2);
printk("import: my mate tells that 2+2 = %i\n",i);
return 0;
}
void import_cleanup(void)
{}
module_init(import_init);
module_exit(import_cleanup);
MODULE_LICENSE("GPL");
在import.c中, 使用了由export.o模块导出的符号export_function(int, int), 我们加载import.o模块: insmod import.o
结果报错:import.o: unresolved symbol export_function_Rsmp_888cb211, 错误显示export_function是一个没有定义的符号. 所以这需要我们首先加载export.o, 因为这个符号在export.c中定义:
sh# insmod export.o
sh# insmod import.o
用dmesg查看输出显示: import: my mate tells that 2+2 = 4
这种技术称为模块堆叠(module stacking)技术: 一个模块的实现倚赖于其他模块的导出的符号. 在加载这个模块之前,首先加载它所倚赖的其他模块. 只有这样, 这个模块才能成功加载和使用.
联系邮件: [email protected]
参考资料:
1. Linux Device Drivers, Second Edition, Alessandro
2. The Linux Kernel Module Programming Guide (v2.4.0), Peter Jay Salzman Ori Pomerantz
/*
* export.c -- export a symbol (maybe a versioned one) (v2.1)
*
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
* Copyright (C) 2001 O'Reilly & Associates
*
* The source code in this file can be freely used, adapted,
* and redistributed in source or binary form, so long as an
* acknowledgment appears in derived source files. The citation
* should list that the code comes from the book "Linux Device
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
* by O'Reilly & Associates. No warranty is attached;
* we cannot take responsibility for errors or fitness for use.
*
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
/* This stuff might go in the Makefile, but I'd better put it here */
#include <linux/config.h> /* retrieve the CONFIG_* macros */
#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
# define MODVERSIONS
#endif
/*
* Include the versioned definitions for both kernel symbols and our
* symbol, *unless* we are generating checksums (__GENKSYMS__
* defined) */
#if defined(MODVERSIONS) && !defined(__GENKSYMS__)
# include <linux/modversions.h>
# include "export.ver" /* redefine "export_function" to include CRC */
#endif
/*
* Everything from now on is normal. The previous stuff can be replaced
* by "$(CC) -D__KERNEL__ -DMODULE -DMODVERSIONS -DEXPORT_SYMTAB \
* -include $(INCLUDEDIR)/linux/modversions.h" if versioning
* is enabled, and the following (simpler) cmdline for genksyms:
* "$(CC) -E -DCONFIG_MODVERSIONS -DEXPORT_SYMTAB"
*/
#ifndef EXPORT_SYMTAB
# define EXPORT_SYMTAB /* need this one 'cause we export symbols */
#endif
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
#include "sysdep.h"
/* our dumb function, with two dumb arguments */
int export_function(int a, int b);
#ifdef __USE_OLD_SYMTAB__
static struct symbol_table export_syms = {
#include <linux/symtab_begin.h>
X(export_function),
#include <linux/symtab_end.h>
};
#else
EXPORT_SYMBOL(export_function);
#endif
int export_init(void)
{
REGISTER_SYMTAB(&export_syms);
return 0;
}
void export_cleanup(void)
{
}
int export_function(int a, int b)
{return a+b;}
module_init(export_init);
module_exit(export_cleanup);
MODULE_LICENSE("GPL");
export.c主要说明了EXPORT_SYMBOL的用法,我们已经在hello2.c中分析过了.
在这个程序里关于REGISTER_SYMTAB的用法是为了兼容2.0内核的, 我们可以现不用管它.(事实上,ldd2的作者
在编写针对内核2.0和2.4兼容的驱动程序上,做了大量的工作, 头文件"sysdep.h"主要就是做这个工作的)
显示的命名初始化函数和清除函数:
module_init(export_init);
module_exit(export_cleanup);
这样做的好处是内核中每一个模块的初始化函数和清除函数都会有唯一的名字,给调试带来方便.
要使用module_init和module_exit之前, 程序必须包含头文件<linux/init.h>.
在这个程序里导出了函数符号export_function, 它实现一个加法运算.
我们在import.c中用这个导出的符号. 下面是import.c的代码:
/*
* import.c -- a module using a symbol from export.c
*
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
* Copyright (C) 2001 O'Reilly & Associates
*
* The source code in this file can be freely used, adapted,
* and redistributed in source or binary form, so long as an
* acknowledgment appears in derived source files. The citation
* should list that the code comes from the book "Linux Device
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
* by O'Reilly & Associates. No warranty is attached;
* we cannot take responsibility for errors or fitness for use.
*
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
/*
* Use versioning if needed
*/
#include <linux/config.h> /* retrieve the CONFIG_* macros */
#ifdef CONFIG_MODVERSIONS
# undef MODVERSIONS /* it might be defined */
# define MODVERSIONS
#endif
#ifdef MODVERSIONS
# include <linux/modversions.h>
# include "export.ver"
#endif
#include <linux/module.h>
#include <linux/kernel.h>
#include "sysdep.h"
extern int export_function(int, int);
int import_init(void)
{
int i = export_function(2,2);
printk("import: my mate tells that 2+2 = %i\n",i);
return 0;
}
void import_cleanup(void)
{}
module_init(import_init);
module_exit(import_cleanup);
MODULE_LICENSE("GPL");
在import.c中, 使用了由export.o模块导出的符号export_function(int, int), 我们加载import.o模块: insmod import.o
结果报错:import.o: unresolved symbol export_function_Rsmp_888cb211, 错误显示export_function是一个没有定义的符号. 所以这需要我们首先加载export.o, 因为这个符号在export.c中定义:
sh# insmod export.o
sh# insmod import.o
用dmesg查看输出显示: import: my mate tells that 2+2 = 4
这种技术称为模块堆叠(module stacking)技术: 一个模块的实现倚赖于其他模块的导出的符号. 在加载这个模块之前,首先加载它所倚赖的其他模块. 只有这样, 这个模块才能成功加载和使用.
相关阅读 更多 +