免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5661 | 回复: 8

模块的符号导出后其他模块不能调用求解 [复制链接]

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:50:28
发表于 2009-04-29 21:36 |显示全部楼层
5可用积分
其实就是LDD的例子,其中作者自己实现了一个简单的总线 ldd_bus 代码如下:
ldd_bus.h

MODULE_LICENSE("GPL");
extern struct bus_type ldd_bus_type;
/*
 * The LDD driver type.
 */

struct ldd_driver {
    char *version;
    struct module *module;
    struct device_driver driver;
    struct driver_attribute version_attr;
};

#define to_ldd_driver(drv) container_of(drv, struct ldd_driver, driver);

/*
 * A device type for things "plugged" into the LDD bus.
 */


struct ldd_device {
    char *name;
    struct ldd_driver *driver;
    struct device dev;
};

#define to_ldd_device(dev) container_of(dev, struct ldd_device, dev);

extern int register_ldd_device(struct ldd_device *);
extern void unregister_ldd_device(struct ldd_device *);
extern int register_ldd_driver(struct ldd_driver *);
extern void unregister_ldd_driver(struct ldd_driver *);
ldd_bus.c

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include "lddbus.h"

MODULE_AUTHOR("Jonathan Corbet");
MODULE_LICENSE("GPL");
static char *Version = "$Revision: 1.9 $";

/*
 * Respond to hotplug events.
 */

//static int ldd_hotplug(struct device *dev, char **envp, int num_envp,

//        char *buffer, int buffer_size)

static int ldd_uevent(struct device *dev, struct kobj_uevent_env *env)
{
    struct ldd_device *pdev;

    if (!dev)
        return -ENODEV;
    
    pdev = to_ldd_device(dev);
    
    if (!pdev)
        return -ENODEV;
    
    if (add_uevent_var(env, "LDDBUS_VERSION=%s", Version))
        return -ENOMEM;    
    /*    
    envp[0] = buffer;
    if (snprintf(buffer, buffer_size, "LDDBUS_VERSION=%s",
                Version) >= buffer_size)
        return -ENOMEM;
    envp[1] = NULL;
    */

    
    return 0;
}

/*
 * Match LDD devices to drivers.  Just do a simple name test.
 */

static int ldd_match(struct device *dev, struct device_driver *driver)
{
    return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
}


/*
 * The LDD bus device.
 */

static void ldd_bus_release(struct device *dev)
{
    printk(KERN_DEBUG "lddbus release\n");
}
    
struct device ldd_bus = {
    .bus_id   = "ldd0",
    .release  = ldd_bus_release
};


/*
 * And the bus type.
 */

struct bus_type ldd_bus_type = {
    .name = "ldd",
    .match = ldd_match,
    //.hotplug  = ldd_hotplug,

    .uevent = ldd_uevent,
};

/*
 * Export a simple attribute.
 */

static ssize_t show_bus_version(struct bus_type *bus, char *buf)
{
    return snprintf(buf, PAGE_SIZE, "%s\n", Version);
}

static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);



/*
 * LDD devices.
 */


/*
 * For now, no references to LDDbus devices go out which are not
 * tracked via the module reference count, so we use a no-op
 * release function.
 */

static void ldd_dev_release(struct device *dev)
{ }

int register_ldd_device(struct ldd_device *ldddev)
{
    ldddev->dev.bus = &ldd_bus_type;
    ldddev->dev.parent = &ldd_bus;
    ldddev->dev.release = ldd_dev_release;
    strncpy(ldddev->dev.bus_id, ldddev->name, BUS_ID_SIZE);
    return device_register(&ldddev->dev);
}
EXPORT_SYMBOL(register_ldd_device);

void unregister_ldd_device(struct ldd_device *ldddev)
{
    device_unregister(&ldddev->dev);
}
EXPORT_SYMBOL(unregister_ldd_device);
int sculld_init(void)
{
&nbsp;&nbsp;&nbsp;&nbsp;int result, i;
&nbsp;&nbsp;&nbsp;&nbsp;dev_t dev = MKDEV(sculld_major, 0);
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;/*
&nbsp;&nbsp;&nbsp;&nbsp; * Register your major, and accept a dynamic number.
&nbsp;&nbsp;&nbsp;&nbsp; */

&nbsp;&nbsp;&nbsp;&nbsp;if (sculld_major)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = register_chrdev_region(dev, sculld_devs, "sculld");
&nbsp;&nbsp;&nbsp;&nbsp;else {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = alloc_chrdev_region(&dev, 0, sculld_devs, "sculld");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sculld_major = MAJOR(dev);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;if (result < 0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return result;

&nbsp;&nbsp;&nbsp;&nbsp;/*
&nbsp;&nbsp;&nbsp;&nbsp; * Register with the driver core.
&nbsp;&nbsp;&nbsp;&nbsp; */

&nbsp;&nbsp;&nbsp;&nbsp;register_ldd_driver(&sculld_driver);
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;/*
&nbsp;&nbsp;&nbsp;&nbsp; * allocate the devices -- we can't have them static, as the number
&nbsp;&nbsp;&nbsp;&nbsp; * can be specified at load time
&nbsp;&nbsp;&nbsp;&nbsp; */

&nbsp;&nbsp;&nbsp;&nbsp;sculld_devices = kmalloc(sculld_devs*sizeof (struct sculld_dev), GFP_KERNEL);
&nbsp;&nbsp;&nbsp;&nbsp;if (!sculld_devices) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = -ENOMEM;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goto fail_malloc;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;memset(sculld_devices, 0, sculld_devs*sizeof (struct sculld_dev));
&nbsp;&nbsp;&nbsp;&nbsp;for (i = 0; i < sculld_devs; i++) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sculld_devices[i].order = sculld_order;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sculld_devices[i].qset = sculld_qset;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sema_init (&sculld_devices[i].sem, 1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sculld_setup_cdev(sculld_devices + i, i);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sculld_register_dev(sculld_devices + i, i);
&nbsp;&nbsp;&nbsp;&nbsp;}


//#ifdef SCULLD_USE_PROC /* only when available */

&nbsp;&nbsp;&nbsp;&nbsp;create_proc_read_entry("sculldmem", 0, NULL, sculld_read_procmem, NULL);
//#endif

&nbsp;&nbsp;&nbsp;&nbsp;return 0; /* succeed */

&nbsp;&nbsp;fail_malloc:
&nbsp;&nbsp;&nbsp;&nbsp;unregister_chrdev_region(dev, sculld_devs);
&nbsp;&nbsp;&nbsp;&nbsp;return result;
}

在另一个模块里调用EXPORT的函数,编译的时候 WARNING: "register_ldd_driver" [/sculld/sculld.ko] undefined! insmod 的时候出错 Unknown symbol in module

cat /proc/kallsyms | grep register_ldd_driver
ffffffffa0493310 r __ksymtab_unregister_ldd_driver        [lddbus]
ffffffffa0493370 r __kstrtab_unregister_ldd_driver        [lddbus]
ffffffffa0493350 r __kcrctab_unregister_ldd_driver        [lddbus]
ffffffffa0493320 r __ksymtab_register_ldd_driver        [lddbus]
ffffffffa0493386 r __kstrtab_register_ldd_driver        [lddbus]
ffffffffa0493358 r __kcrctab_register_ldd_driver        [lddbus]
ffffffffa0493330 r __ksymtab_unregister_ldd_device        [lddbus]
ffffffffa049339a r __kstrtab_unregister_ldd_device        [lddbus]
ffffffffa0493360 r __kcrctab_unregister_ldd_device        [lddbus]
ffffffffa0493130 t unregister_ldd_driver        [lddbus]
00000000cea62aa1 a __crc_unregister_ldd_device        [lddbus]
00000000750790d6 a __crc_register_ldd_device        [lddbus]
ffffffffa04931f0 t register_ldd_device        [lddbus]
0000000073ce301d a __crc_unregister_ldd_driver        [lddbus]
ffffffffa04930d0 t unregister_ldd_device        [lddbus]
000000002db493e5 a __crc_register_ldd_driver        [lddbus]
ffffffffa0493140 t register_ldd_driver        [lddbus]


[ 本帖最后由 www1862 于 2009-4-29 21:45 编辑 ]

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
发表于 2009-04-29 21:59 |显示全部楼层

回复 #1 www1862 的帖子

前面有个哥们说,符号表里面要是类型u的才能被调用

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:50:28
发表于 2009-04-29 22:02 |显示全部楼层

回复 #2 dreamice 的帖子

你的问题解决了吗?不是已经用EXPORT_SYMBOL(fun) 导出了吗?为什么还不能用?

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:50:28
发表于 2009-04-29 23:12 |显示全部楼层
看了一下,ssb b43 的代码,发现没什么不一样,不过SSB B43都在内核树里。关于2楼的说法,我的理解是U 是调用者 USE的意思,因为b43 依赖ssb模块,且ssb_device_enable 是ssb模块里的 函数。
cat /proc/kallsyms | grep ssb_device_enable
ffffffffa0033310 u ssb_device_enable        [b43]
ffffffffa0037c60 r __ksymtab_ssb_device_enable        [ssb]
ffffffffa0037e79 r __kstrtab_ssb_device_enable        [ssb]
ffffffffa0037d68 r __kcrctab_ssb_device_enable        [ssb]
ffffffffa0033310 T ssb_device_enable        [ssb]
00000000654ba824 a __crc_ssb_device_enable        [ssb]


[ 本帖最后由 www1862 于 2009-4-29 23:13 编辑 ]

论坛徽章:
0
发表于 2009-04-29 23:36 |显示全部楼层
.H文件里:
extern int register_ldd_device(struct ldd_device *);
extern void unregister_ldd_device(struct ldd_device *);
extern int register_ldd_driver(struct ldd_driver *);
extern void unregister_ldd_driver(struct ldd_driver *);

上面前2行和后面2行一样的啊?另外,EXTERN似乎可以去掉吧?因为在.C里面实现了啊。又不是在其他地方实现的。

还有,你调用 register_ldd_driver 的模块是怎么写的? 应该加了 extern int register_ldd_driver(struct ldd_driver *); 这句吧?

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:50:28
发表于 2009-04-30 00:54 |显示全部楼层

回复 #5 accessory 的帖子

不一样,一个是device 一个是driver。
解决了,原来是lddbus.c 头文件的引用问题。

[ 本帖最后由 www1862 于 2009-4-30 16:43 编辑 ]

论坛徽章:
0
发表于 2009-04-30 22:58 |显示全部楼层
不错,学习了。

论坛徽章:
0
发表于 2010-12-03 14:53 |显示全部楼层
回复 1# www1862


    楼主能再具体说下怎么解决的吗? 我看lddbus.c头文件的引用 找不到问题啊?

论坛徽章:
0
发表于 2011-02-12 17:21 |显示全部楼层
u的意思是undefined吧
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP