Problems exporting / importing symbols across modules
I have a situation where i have to export a function from one module and call it from the other. In linux you typically do an EXPORT_SYMBOL(sym) to make it visible to the kernel. In solaris as long as function is not static the symbol is visible to the rest of the kernel namespace.
But my driver that calls the function from the other module fails to load cribbing "/kernel/drv/sparcv9/betaDrv: undefined symbol"
Here in my code thealphaDrv module has a function "export_from_alpha" which is called bybetaDrv module.
OS is Solaris9 (64bit kernel) on SPARC
Code for alphaDrv:
#include <sys/modctl.h>
#include <sys/conf.h>
#include <sys/devops.h>
#include <sys/cmn_err.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/stat.h>
#include <sys/stack.h>
#include <sys/frame.h>
#include <sys/kobj.h>
#include <sys/ksynch.h>
#include <sys/copyops.h>
#include <sys/disp.h>
dev_info_t *g_dip;
/* Function exported from alphaDrv to be called from betaDrv */
char *export_from_alpha(void)
{
cmn_err(CE_CONT,"Houston, receiving you loud and clear !!");
return"Hello World !";
}
staticint alpha_open(dev_t *devp,int flag,int otyp, cred_t *credp)
{
return 0;
}
staticint alpha_close(dev_t dev,int flag,int otyp, cred_t *credp)
{
return 0;
}
staticint alpha_read_write(dev_t dev, struct uio *uiop, cred_t *credp)
{
return 0;
}
staticint alpha_info(dev_info_t *dip, ddi_info_cmd_t infocmd,void *arg,void **result)
{
int rc = DDI_FAILURE;
cmn_err(CE_CONT,"EntryPoint(ALPHA) - alpha_info");
switch(infocmd)
{
case DDI_INFO_DEVT2DEVINFO:
*result = g_dip;
rc = DDI_SUCCESS;
case DDI_INFO_DEVT2INSTANCE:
*result = (void *)getminor((dev_t)arg);
rc = DDI_SUCCESS;
break;
default:
*result = NULL;
break;
}
return rc;
}
staticint alpha_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
int inst = ddi_get_instance(dip);
cmn_err(CE_CONT,"EntryPoint(ALPHA) - alpha_attach");
switch(cmd)
{
case DDI_ATTACH:
if(ddi_create_minor_node(dip,"ALPHA1", S_IFCHR, inst, DDI_PSEUDO, 0))
return DDI_FAILURE;
g_dip = (void *)dip;
break;
case DDI_RESUME:
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
staticint alpha_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
int inst = ddi_get_instance(dip);
cmn_err(CE_CONT,"EntryPoint(ALPHA) - alpha_detach");
switch(cmd)
{
case DDI_DETACH:
ddi_remove_minor_node(dip, NULL);
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/* Driver specific implementations */
static struct cb_ops alpha_cb_ops ={
alpha_open,
alpha_close,
nodev,
nodev,
nodev,
alpha_read_write,
alpha_read_write,
nodev,
nodev,
nodev,
nodev,
nochpoll,
ddi_prop_op,
(struct streamtab *)NULL,
D_MP | D_64BIT,
CB_REV,
nodev,
nodev
};
static struct dev_ops alpha_dev_ops ={
DEVO_REV,
0,
alpha_info,
nulldev,
nulldev,
alpha_attach,
alpha_detach,
nodev,
&alpha_cb_ops,
(struct bus_ops *)NULL,
nulldev
};
static struct modldrv alpha_modldrv ={
&mod_driverops,
"ALPHA Driver",
&alpha_dev_ops
};
static struct modlinkage alpha_modlinkage ={
MODREV_1,
(void *)&alpha_modldrv,
NULL
};
int _init(void)
{
int rc;
cmn_err(CE_CONT,"EntryPoint(ALPHA) - _init");
rc = mod_install(&alpha_modlinkage);
if(rc)
cmn_err(CE_CONT,"Failed to install driver(ALPHA) - %d", rc);
return rc;
}
int _info(struct modinfo *modInfop)
{
int rc;
cmn_err(CE_CONT,"\n\n\nEntryPoint(ALPHA) - _info");
rc = mod_info(&alpha_modlinkage, modInfop);
if(!rc)
cmn_err(CE_CONT,"Failed to get driver info(ALPHA) - %d", rc);
return rc;
}
int _fini(void)
{
return(mod_remove(&alpha_modlinkage));
}
Code for betaDrv:
-
#include <sys/modctl.h>
#include <sys/conf.h>
#include <sys/devops.h>
#include <sys/cmn_err.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/stat.h>
#include <sys/stack.h>
#include <sys/frame.h>
#include <sys/kobj.h>
#include <sys/ksynch.h>
#include <sys/copyops.h>
#include <sys/disp.h>
dev_info_t *g_dip;
/* Extern declartion for the function imported from alphaDrv */
char *export_from_alpha(void);
staticint beta_open(dev_t *devp,int flag,int otyp, cred_t *credp)
{
return 0;
}
staticint beta_close(dev_t dev,int flag,int otyp, cred_t *credp)
{
return 0;
}
staticint beta_read_write(dev_t dev, struct uio *uiop, cred_t *credp)
{
return 0;
}
staticint beta_info(dev_info_t *dip, ddi_info_cmd_t infocmd,void *arg,void **result)
{
int rc = DDI_FAILURE;
cmn_err(CE_CONT,"EntryPoint(BETA) - beta_info");
switch(infocmd)
{
case DDI_INFO_DEVT2DEVINFO:
*result = g_dip;
rc = DDI_SUCCESS;
case DDI_INFO_DEVT2INSTANCE:
*result = (void *)getminor((dev_t)arg);
rc = DDI_SUCCESS;
break;
default:
*result = NULL;
break;
}
return rc;
}
staticint beta_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
int inst = ddi_get_instance(dip);
cmn_err(CE_CONT,"EntryPoint(BETA) - beta_attach");
switch(cmd)
{
case DDI_ATTACH:
if(ddi_create_minor_node(dip,"BETA1", S_IFCHR, inst, DDI_PSEUDO, 0))
return DDI_FAILURE;
g_dip = (void *)dip;
break;
case DDI_RESUME:
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
staticint beta_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
int inst = ddi_get_instance(dip);
cmn_err(CE_CONT,"EntryPoint(BETA) - beta_detach");
switch(cmd)
{
case DDI_DETACH:
ddi_remove_minor_node(dip, NULL);
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/* Driver specific implementations */
static struct cb_ops beta_cb_ops ={
beta_open,
beta_close,
nodev,
nodev,
nodev,
beta_read_write,
beta_read_write,
nodev,
nodev,
nodev,
nodev,
nochpoll,
ddi_prop_op,
(struct streamtab *)NULL,
D_MP | D_64BIT,
CB_REV,
nodev,
nodev
};
static struct dev_ops beta_dev_ops ={
DEVO_REV,
0,
beta_info,
nulldev,
nulldev,
beta_attach,
beta_detach,
nodev,
&beta_cb_ops,
(struct bus_ops *)NULL,
nulldev
};
static struct modldrv beta_modldrv ={
&mod_driverops,
"BETA Driver",
&beta_dev_ops
};
static struct modlinkage beta_modlinkage ={
MODREV_1,
(void *)&beta_modldrv,
NULL
};
int _init(void)
{
int rc;
cmn_err(CE_CONT,"EntryPoint(BETA) - _init");
rc = mod_install(&beta_modlinkage);
if(rc)
cmn_err(CE_CONT,"Failed to install driver(BETA) - %d", rc);
/* Calling function exported from alpha */
cmn_err(CE_CONT,"Houston, we have a problem !! --> %s", export_from_alpha());
return rc;
}
int _info(struct modinfo *modInfop)
{
int rc;
cmn_err(CE_CONT,"\n\n\nEntryPoint(BETA) - _info");
rc = mod_info(&beta_modlinkage, modInfop);
if(!rc)
cmn_err(CE_CONT,"Failed to get driver info(BETA) - %d", rc);
return rc;
}
int _fini(void)
{
return(mod_remove(&beta_modlinkage));
}
This is what i do:
# rem_drv alphaDrv
# rem_drv betaDrv
# rm -f /kernel/drv/sparcv9/alphaDrv
# rm -f /kernel/drv/sparcv9/betaDrv
# /opt/SUNWspro/bin/cc -xarch=v9 -D_KERNEL -DDEBUG -D__64BIT__ -c alpha.c
# /usr/ccs/bin/ld -r -o alphaDrv alpha.o
# /opt/SUNWspro/bin/cc -xarch=v9 -D_KERNEL -DDEBUG -D__64BIT__ -c beta.c
# /usr/ccs/bin/ld -r -o betaDrv beta.o
# cp alphaDrv /kernel/drv/sparcv9
# cp betaDrv /kernel/drv/sparcv9
# add_drv alphaDrv
# add_drv betaDrv
devfsadm: driver failed to attach: betaDrv
Warning: Driver (betaDrv) successfully added to system but failed to attach
This is the outout from /var/adm/messages:
Oct 17 15:34:25 test_machine1 EntryPoint(ALPHA) - _info
Oct 17 15:34:25 test_machine1 alphaDrv: [ID 938910 kern.notice] EntryPoint(ALPHA) - alpha_detach
Oct 17 15:34:40 test_machine1 alphaDrv: [ID 394848 kern.notice]
Oct 17 15:34:40 test_machine1 EntryPoint(ALPHA) - _info
Oct 17 15:34:40 test_machine1 alphaDrv: [ID 756530 kern.notice] EntryPoint(ALPHA) - _init
Oct 17 15:34:40 test_machine1 alphaDrv: [ID 999966 kern.notice] EntryPoint(ALPHA) - alpha_attach
Oct 17 15:34:41 test_machine1 krtld: [ID 819705 kern.notice] /kernel/drv/sparcv9/betaDrv: undefined symbol
Oct 17 15:34:41 test_machine1 krtld: [ID 826211 kern.notice] 'export_from_alpha'
Oct 17 15:34:41 test_machine1 krtld: [ID 472681 kern.notice] WARNING: mod_load: cannot load module 'betaDrv'
Thanks for the help

