OpenVINOTM,给你看得见的未来!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » [原创]用函数jump表解决模块加载顺序问题

共5条 1/1 1 跳转至

[原创]用函数jump表解决模块加载顺序问题

菜鸟
2003-04-06 23:50:00    评分
by amine@263.net 用ld()加载目标模块的顺序很重要。若一个模块在加载时有未解析符号,后面再加载的其他模块对解析这些符号没有帮助。加载模块只能和先他加载的模块连接。例如:有两个模块:app1.o和app2.o,app1.o可以独立运行,而app2.o对app1.o中定义的符号有依赖。这种情况下,ld()会执行必要的连接操作,但是app1.o必须在app2.o之前加载。 但是有时不能保证这种顺序,加载可能导致连接错误“unresolved reference”。这种情况一般可通过主机工具ldarch解决,将这些紧张加载顺序的模块连接在一起。 另外还可以用jump表来解决。这种技巧在高级文件和低级文件之间添加抽象层,低级文件提供函数实现,高级文件通过全局函数指针调用。高级文件加载时不要求调用函数实际存在,只要全局的jump表结构存在就行拉。这样高级文件可先于低级文件加载。但是要求,在使用jump表的模块加载前,需先声明jump表全局指针。 当高级模块需要根据环境调用不同的低级函数实现时,该技巧也有用。单个高级文件可以和多个低级文件配合使用。 使用这种技巧需要3个步骤:在内存中创建空全局jump表;填充jump表中的函数指针;调用jump表函数指针。如下面示例代码: /*============================================================================= * jumpTbl.h - Jump table header file * Declares the jump table structure and necessary functions. */ #ifndef __INjumpTblh #define __INjumpTblh typedef struct /* Jump table */ { FUNCPTR addRoutine; FUNCPTR multRoutine; FUNCPTR divRoutine; } JUMP_TBL; STATUS setupJumpTable(void); #endif /* __INjumpTblh */ /*============================================================================= * setupJumpTbl.c – 该文件建立全局访问jump表 * 这是唯一需先加载的文件。应该连接入Vxworks映象。保证后续加载模块可找到jump表 */ #include "vxWorks.h" #include "jumpTbl.h" #include "memLib.h" #include "stdlib.h" JUMP_TBL *jumpTable; /****************************************************************************** * setupJumpTable() - Allocates memory for the jump table. * 该函数只能运行一次,可以在初始化函数中调用 */ STATUS setupJumpTable(void) { static int alreadySetup = 0; /* Only setup once */ if(alreadySetup == 0) { if((jumpTable = (JUMP_TBL *)malloc(sizeof(JUMP_TBL)))==NULL) return(ERROR); else { alreadySetup = 1; return(OK); } } return(OK); } /*============================================================================= * initJumpTbl.c - A low level jump table initialization file. * 该文件示例jump表初始化,如何使用jump表。 */ #include "vxWorks.h" #include "jumpTbl.h" #include "stdio.h" IMPORT JUMP_TBL *jumpTable; /* Globally accessable jump table */ /* Forward declarations */ LOCAL int localAdditionRtn(int inputValue1, int inputValue2); LOCAL int localMultiplyRtn(int inputValue1, int inputValue2); LOCAL uint_t localDivisionRtn(int inputValue1, int inputValue2); /***************************************************************************** * initJumpTable() - Fill the jump table with low level function pointers */ void initJumpTable(void) { if(jumpTable == NULL) /* Check that table exists already. */ setupJumpTable(); /* If table dosen\''t exist make one. */ /* Fill in the function pointers */ jumpTable->addRoutine = (FUNCPTR)localAdditionRtn; jumpTable->multRoutine = (FUNCPTR)localMultiplyRtn; jumpTable->divRoutine = (FUNCPTR)localDivisionRtn; } /***************************************************************************** * localAdditionRtn() - Low level self explanitory static function. */ LOCAL int localAdditionRtn(int inputValue1, int inputValue2) { return(inputValue1 + inputValue2); } /***************************************************************************** * localMultiplyRtn() - Low level self explanitory static function. */ LOCAL int localMultiplyRtn(int inputValue1, int inputValue2) { return(inputValue1 * inputValue2); } /***************************************************************************** * localDivisionRtn() - Low level self explanitory static function. */ LOCAL uint_t localDivisionRtn(int inputValue1, int inputValue2) { if(inputValue2 > 0) return(inputValue1/inputValue2); else{ printf("You can\''t divide by ZERO\n"); return(ERROR); } } /*============================================================================= * callJumpTbl.c - A high level library using jump table function calls */ #include "vxWorks.h" #include "stdio.h" #include "jumpTbl.h" IMPORT JUMP_TBL *jumpTable; void callJumpTable(int inputArg1, int inputArg2) { if(jumpTable != NULL) { /* Does jump table exist? */ if(jumpTable->addRoutine != NULL) { /* Anything there? */ printf("Calling jumpTable->addRoutine\n"); printf("The returned value = %d\n",jumpTable->addRoutine(inputArg1,inputArg2)); } else printf("jumpTable->addRoutine not initialized\n"); if(jumpTable->multRoutine != NULL) { /* Anything there? */ printf("Calling jumpTable->multRoutine\n"); printf("The returned value = %d\n", jumpTable->multRoutine(inputArg1,inputArg2)); } else printf("jumpTable->multRoutine not initialized\n"); if(jumpTable->divRoutine != NULL) { /* Anything there? */ printf("Calling jumpTable->divRoutine\n"); printf("The returned value = %d\n",jumpTable->divRoutine(inputArg1,inputArg2)); } else printf("jumpTable->divRoutine not initialized\n"); } else printf("jumpTable struct does not exist. Run setupJumpTable()\n"); } 参考“Windriver Tech Tips”的“How to use a jump table”。 [align=right][color=#000066][此贴子已经被作者于2003-4-6 15:58:17编辑过][/color][/align]



关键词: 原创     函数     解决     模块     加载     顺序     问题     文件     t    

菜鸟
2003-04-06 23:51:00    评分
2楼
另外还有一种更奇异的用法,模块自己解析外部引用,而不依赖loader的解析过程。Loader总是从系统符号表中来解析符号地址,模块需要自己实现这部分功能。写程序时就知道要引用函数或变量的名称和类型,模块程序中使用symFindByName从系统符号表中查找引用符号地址,再加以使用。该模块对符号表中的符号的引用,对loader来说是不可见的,根本不是显示的外部引用,而只是一些取符号地址传给指针的操作。这个用法我没实际试过,好像也没有什么实际用途,只是觉得有趣,让大家看看,用以加深对概念的理解。

菜鸟
2003-04-07 16:43:00    评分
3楼
ld()是指loader,不是编译器中的linker 但是有类似功能:模块重定位,符号解析等。 但是是两个不同的东西,load是run-time的。。。 是不能保证加载所有模块,这也是和linker的区别 主机工具ldarch可以集中个模块,保证相关模块加载一致性 这个工具可能就类似gnu ld的GROUP vxworks的支持目标模块动态加载 和通常意义上动态连接还是两回事 vxworks的loader机制只能说是“动态加载,静态连接” HTH

菜鸟
2003-04-07 17:47:00    评分
4楼
ld在主机和目标机都有实现, 主机使用loadlib(dll库), 目标机使用loadLib(vxworks库) vxworks目标文件没有依赖文件信息, 只是标准目标格式,入a.out,elf等 你推测vxworks维护了一张符号表是对的, 你没用过vxworks, 能作出这种推测, 实现令人佩服:) wShell的ld主要完成代码增量开发调试 tShell的ld主要增加软件使用的灵活, 功能分模块, 便以程序发布, 现场升级等

菜鸟
2003-04-07 17:56:00    评分
5楼
动态加载是只模块内存重定位是动态的 静态连接是指加载模块的外部符号解析是和编译器linker机制类似 与win的动态库机制,或linux的共享库机制不相同 我对这两种机制不是太熟,不能作具体比较描述:( 主机使用ldarch将app1.o和app2.o合为app.out, 可分离加载, 如果app2.o需要引用app1.o中的符号,app1.o 需先于app2.o加载 也可以单独加载app.out, 不再和两目标模块本身相关 自动保证了两模块之间的符号解析 [align=right][color=#000066][此贴子已经被作者于2003-4-7 9:58:28编辑过][/color][/align]

共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]