免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: nicolas.shen

运行时动态函数调用(Runtime Dynamic Invoke) [复制链接]

论坛徽章:
1
射手座
日期:2013-08-21 13:11:46
发表于 2009-09-08 12:48 |显示全部楼层
__asm
...
你还真不怕麻烦...
为啥不用函数指针直接来呢

论坛徽章:
0
发表于 2009-09-08 13:07 |显示全部楼层
函数指针的问题主要是参数固定,不能可变。

但其实很多时候简化一下设计,用函数指针就够用了,非要实现强大的功能或者灵活性,很多时候没太大必要,反而是自找麻烦,维护不过来还沾沾自喜说曲高和寡。。。。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2009-09-08 13:10 |显示全部楼层

回复 #8 syncpk99 的帖子

原帖由 syncpk99 于 2009-9-8 09:39 发表
找到这个库N久了,就是一眼也没看过啊


因为以前做过类似的工作, 所以对它的代码感到很亲切

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2009-09-08 13:13 |显示全部楼层

回复 #9 nicolas.shen 的帖子

原帖由 nicolas.shen 于 2009-9-8 11:01 发表
嗯的确有不少体力活,真是佩服啊


嗯, 敢直接写汇编那真是体力活了……
即使在x86, 还要为不同编译器写不同的代码 ……
dyncall_call_x86_nasm.asm
dyncall_call_x86_gas.S
dyncall_call_x86_nasm.asm
dyncall_call_x86_apple.s

好像不是程序生成, 4个文件都是手写的。  相当的麻烦……


我以前是直接写x86的machine code。 就不用考虑不同编译器的问题了。
但又遇到了DEP的问题。 也是体力活……  稍微轻松一些。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2009-09-08 13:16 |显示全部楼层

回复 #10 群雄逐鹿 的帖子

期待

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2009-09-08 13:16 |显示全部楼层

回复 #11 egmkang 的帖子

原帖由 egmkang 于 2009-9-8 12:48 发表
__asm
...
你还真不怕麻烦...
为啥不用函数指针直接来呢


你在仔细想想需求, 就知道函数指针也是帮不上忙的。
使用函数指针进行调用时, 参数个数在运行前就固定了。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2009-09-08 13:20 |显示全部楼层

回复 #12 drangon 的帖子

原帖由 drangon 于 2009-9-8 13:07 发表
但其实很多时候简化一下设计,用函数指针就够用了,非要实现强大的功能或者灵活性,很多时候没太大必要,反而是自找麻烦,维护不过来还沾沾自喜说曲高和寡。。。。


嗯, 很多时候。 但不是所有情况下。
在极少的情况下, 有需求就是真正的需要 —— 绕弯去实现比设计一种方法直接支持要更麻烦, 甚至不可能。

论坛徽章:
0
发表于 2009-09-08 13:48 |显示全部楼层
其实想这样做,就是想在脚本里调用api,实在是还没有想到别的办法,期待 群雄逐鹿 兄弟的 C++实现

论坛徽章:
0
发表于 2009-09-08 14:48 |显示全部楼层
实现的还是很不爽,
抛砖引玉,这个代码可以可以动态的调用printf,目前只支持%s和%d两种参数。

主要就是用detect_stack_pos检测stack位置,
然后手动填写stack.
特别要满足 detect_stack_pos 和 被调用的函数(这里是printf)处在一摸一样的stack位置,
这个可以通过 数组 any_fn funcs[ 3 ]; 保证。

VC2008和cygwin下测试通过,cygwin 结果

$ ./a.exe '---%s---%d--%d---%s' ffeww 333 22 abcd
---ffeww---333--22---abcd

$ ./a.exe '---bbs%d.chinaunix.%s--' 3 net
---bbs3.chinaunix.net--

但是不足:
1. 需要用动态数组预留stack空间,VC只能用静态的代替。
2. 需要一个全局变量记录 stack检测结果,开始认为c++可以用类成员代替全局变量,但实际上代替不了(this指针怎么都必须有)
    如果全局变量的问题能解决,就比较好包装一个通用的库了。

还有返回值可以不可以用,还没验证。




  1. #include <stdlib.h>
  2. #include <stdio.h>

  3. typedef void (*any_fn)( );
  4. typedef struct
  5. {
  6.         void *stack_pos0;
  7.         void *stack_pos1;
  8.         int argc;
  9.         char **argv;
  10. } stack_t;

  11. stack_t g_stack;

  12. void detect_stack_pos( void *arg0, void *arg1 )
  13. {
  14.         stack_t *stack = &g_stack;
  15.         stack->stack_pos0 = (void *)&arg0;
  16.         stack->stack_pos1 = (void *)&arg1;
  17.         //printf( "stack pos = %p %p\n", &arg0, &arg1 );
  18. }
  19.        
  20. void set_stack( )
  21. {
  22.         stack_t *stack = &g_stack;
  23.        
  24.         int direction = ( stack->stack_pos0 < stack->stack_pos1 ? 1 : -1 );

  25.         int i;               
  26.         void *stack_pos = stack->stack_pos0;
  27.         const char *p;
  28.         const char *fmt = stack->argv[ 1 ];
  29.                
  30.         *(const char **)stack_pos = fmt;
  31.         stack_pos = (void *)( (const char **)stack_pos + direction );
  32.                
  33.         i = 2;
  34.         for( p = fmt; *p != '\0'; ++p )
  35.         {
  36.                 if( *p != '%' )
  37.                         continue;
  38.                 ++p;
  39.                 if( *p == '\0' )
  40.                         break;
  41.                        
  42.                 switch( *p )
  43.                 {
  44.                 case 'd':
  45.                         *(int *)stack_pos = atoi( stack->argv[ i++ ] );
  46.                         stack_pos = (void *)( (int *)stack_pos + direction );
  47.                         break;
  48.                 case 's':
  49.                         *(const char **)stack_pos = stack->argv[ i++ ];
  50.                         printf( "%s\n", *(const char **)stack_pos);
  51.                         stack_pos = (void *)( (const char **)stack_pos + direction );
  52.                         break;
  53.                 }
  54.         }
  55. }


  56. size_t get_min_stack_size( const char *fmt )
  57. {
  58.         size_t param_num = 1;
  59.         while( *fmt != '\0' )
  60.         {
  61.                 if( *fmt == '%' )
  62.                         ++param_num;
  63.                 ++fmt;
  64.         }
  65.        
  66.         /* Only support %d %s now, so just use sizeof(void *) instead */
  67.         return param_num * sizeof(void *);
  68. }

  69.        
  70. void call_func( int argc, char **argv )
  71. {
  72.         int i;
  73.         size_t min_stack_size;
  74.         any_fn funcs[ 3 ];
  75.        
  76.         funcs[ 0 ] = (any_fn)&detect_stack_pos;
  77.         funcs[ 1 ] = (any_fn)&set_stack;
  78.         funcs[ 2 ] = (any_fn)&printf;
  79.        
  80.         g_stack.argc = argc;
  81.         g_stack.argv = argv;
  82.        
  83.        
  84.         min_stack_size = get_min_stack_size( argv[ 1 ] );
  85.        
  86.         for( i = 0; i < sizeof( funcs ) / sizeof( funcs[ 0 ] ); ++i )
  87.         {
  88.                 volatile any_fn func = funcs[ i ];
  89.                 {
  90.                         /* Allocate stack size */
  91. #ifdef __GNUC__
  92.                         volatile char buffer[ min_stack_size ];
  93. #else
  94.                         volatile char buffer[ 400 ];
  95. #endif
  96.                         /* Prevent optimization by assigning a value */
  97.                         if( i <= 1 )
  98.                         {
  99.                                 buffer[ 0 ] = 0;
  100.                                 buffer[ sizeof( buffer ) / sizeof( buffer[ 0 ] ) - 1 ] = 0;
  101.                         }
  102.                        
  103.                         (*func)( );
  104.                 }
  105.         }
  106. };

  107. int main( int argc, char **argv )
  108. {
  109.         call_func( argc, argv );
  110.         return 0;
  111. }


复制代码

[ 本帖最后由 群雄逐鹿 于 2009-9-8 14:50 编辑 ]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2009-09-08 14:59 |显示全部楼层

回复 #19 群雄逐鹿 的帖子

确实是纯C/C++的,也实现得很巧妙。

但不是可移植的, 因为代码中已经假设机器具有栈结构, 参数通过栈传递, 所有函数指针都有相同表示。
这些都是C/C++没有规定的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP