直到运行时才知道参数数量时调用函数 [英] Calling a function when the number of parameters isn't known till runtime

查看:92
本文介绍了直到运行时才知道参数数量时调用函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[如果有人认为这是偏离主题的话,请道歉。我最初

交叉发布到comp.lang.asm.x86,但我现在重新尝试clc

发现clax86被审核后]


我的问题:我需要调用(来自C代码)一个任意的C库

函数,但我不知道直到运行时函数名称是什么是,

需要多少参数,以及参数是什么。我可以

使用dlopen / what将函数名称转换为指向

的函数,但实际上调用它,使用正确数量的

参数,并不容易。


据我所知,只有两种解决方案:


1)这个一个是便携式的。如果您事先知道没有任何功能将需要超过2个参数,那么您可以做一些简单的事情

如:


switch(nparams){

case 0:(* user_func)();休息;

案例1:(* user_func)(P1);休息;

案例2:(* user_func)(P1,P2);打破;

}


2)如果您不知道参数的最大数量,那么

似乎没有办法做到这一点,没有编写汇编程序代码。我猜这个看起来像这样:


- C代码将所有参数推送到本地堆栈

- C代码调用汇编程序,传入函数

地址,本地堆栈地址,也许参数数量

- 汇编程序例程设置堆栈框架并间接

调用用户的C代码

- 汇编程序清除堆栈框架并返回


有什么想法?我错过了什么/这有意义吗?如果我有(b)b / b,那么我将从Linux / gcc / x86开始,如有必要,继续使用其他

系统。有谁知道任何可以帮助我这么做的b / b
的网络资源?我现在不知道该怎么做。


谢谢 -


John

[apologies if anyone thinks this is off-topic. I originally
cross-posted to comp.lang.asm.x86, but I''m now re-trying just c.l.c
after discovering that c.l.a.x86 is moderated]

My problem: I need to call (from C code) an arbitrary C library
function, but I don''t know until runtime what the function name is,
how many parameters are required, and what the parameters are. I can
use dlopen/whatever to convert the function name into a pointer to
that function, but actually calling it, with the right number of
parameters, isn''t easy.

As far as I can see, there are only two solutions:

1) This one is portable. If you know in advance that no function will
require more than, say, 2 parameters, then you can do something simple
like:

switch(nparams) {
case 0: (*user_func)(); break;
case 1: (*user_func)(P1); break;
case 2: (*user_func)(P1, P2); break;
}

2) If you don''t know the maximum number of parameters, then there
seems to be no way to do this, short of writing assembler code. I
guess this would look something like this:

- the C code pushes all the parameters onto a local stack
- the C code calls an assembler routine, passing in the function
address, the local stack address, and maybe the number of parameters
- the assembler routine sets up a stack frame and does an indirect
call to the user''s C code
- the assembler routine clears up the stack frame and returns

Any thoughts? Have I missed anything/does this make sense? If I have
to go for (2), I''ll start with Linux/gcc/x86 and move on to other
systems if necessary. Does anyone know of any web resources that could
help me do this? I''ve got no idea how to do this at the moment.

Thanks -

John

推荐答案



John Friedland写道:

John Friedland wrote:

[如果有人认为道歉]这是偏离主题的。我最初

交叉发布到comp.lang.asm.x86,但我现在重新尝试clc

发现clax86被审核后]


我的问题:我需要调用(来自C代码)一个任意的C库

函数,但我不知道直到运行时函数名称是什么是,

需要多少参数,以及参数是什么。我可以

使用dlopen / what将函数名称转换为指向

的函数,但实际上调用它,使用正确数量的

参数,并不容易。


据我所知,只有两种解决方案:


1)这个一个是便携式的。如果您事先知道没有任何功能将需要超过2个参数,那么您可以做一些简单的事情

如:


switch(nparams){

case 0:(* user_func)();休息;

案例1:(* user_func)(P1);休息;

案例2:(* user_func)(P1,P2);休息;

}
[apologies if anyone thinks this is off-topic. I originally
cross-posted to comp.lang.asm.x86, but I''m now re-trying just c.l.c
after discovering that c.l.a.x86 is moderated]

My problem: I need to call (from C code) an arbitrary C library
function, but I don''t know until runtime what the function name is,
how many parameters are required, and what the parameters are. I can
use dlopen/whatever to convert the function name into a pointer to
that function, but actually calling it, with the right number of
parameters, isn''t easy.

As far as I can see, there are only two solutions:

1) This one is portable. If you know in advance that no function will
require more than, say, 2 parameters, then you can do something simple
like:

switch(nparams) {
case 0: (*user_func)(); break;
case 1: (*user_func)(P1); break;
case 2: (*user_func)(P1, P2); break;
}



不够好,因为参数可能有不同的大小。


如果你正在调用Windows Win32 API函数,那么你很幸运,因为几乎所有(全部?)参数都是32位。但总的来说,他们不会这样的事情可能会起作用:


#define pushbyte(b)__ asm {push byte ptr b}

#define pushword(b)__ asm {push word ptr b}


#define popoff(c)__ asm {add sp,c}


void CallFunc(FuncPtr TheFunctionAddress,char * ParamInfo; unsigned

long int Params [])

{


for(i = 0; i< strlen(ParamInfo); i ++){int Len; Len = 0;

switch(ParamInfo [i]){

case''b'':pushbyte(Params [i]); LEN + = 1 ;;打破;

case''w'':pushword(Params [i]); Len + = 2;休息;

case''l:pushlong(Params [i]); Len + = 4;休息;

case''a:pushaddr(Params [i]); Len + = 4; break;

case default:printf(" bad param descriptor:!!%c",ParamInfo [i]);

}

* TheFunctionAddress();

popoff(Len);

}


你可能需要通过这段代码多次观看

推动和弹出动作,直到你完全正确。

Not good enough, as the parameters might be of different sizes.

You''re in luck if you''re calling Windows Win32 API functions, as almost
all (All?) parameters are 32-bits. But in general they won''t be
something like this might work:

#define pushbyte(b) __asm{ push byte ptr b }
#define pushword(b) __asm{ push word ptr b }

#define popoff(c) __asm{ add sp,c }

void CallFunc( FuncPtr TheFunctionAddress, char * ParamInfo; unsigned
long int Params[] )
{

for( i = 0; i < strlen( ParamInfo ); i++ ) { int Len; Len = 0;
switch( ParamInfo[i] ) {
case ''b'': pushbyte( Params[i] ); Len+=1;; break;
case ''w'': pushword( Params[i] ); Len +=2;break;
case ''l: pushlong( Params[i] ); Len +=4;break;
case ''a: pushaddr( Params[i] ); Len += 4; break;
case default: printf("bad param descriptor: !! %c", ParamInfo[i] );
}
*TheFunctionAddress();
popoff( Len );
}

You''ll probably have to step thru this code several times to watch the
pushing and popping action until you get it all just right.





John Friedland在07年11月6日10:54写道:


John Friedland wrote On 07/11/06 10:54,:

[如果有人认为这是偏离主题的话,请道歉。我最初

交叉发布到comp.lang.asm.x86,但我现在重新尝试clc

发现clax86被审核后]


我的问题:我需要调用(来自C代码)一个任意的C库

函数,但我不知道直到运行时函数名称是什么是,

需要多少参数,以及参数是什么。我可以

使用dlopen / what将函数名称转换为指向

的函数,但实际上调用它,使用正确数量的

参数,并不容易。
[apologies if anyone thinks this is off-topic. I originally
cross-posted to comp.lang.asm.x86, but I''m now re-trying just c.l.c
after discovering that c.l.a.x86 is moderated]

My problem: I need to call (from C code) an arbitrary C library
function, but I don''t know until runtime what the function name is,
how many parameters are required, and what the parameters are. I can
use dlopen/whatever to convert the function name into a pointer to
that function, but actually calling it, with the right number of
parameters, isn''t easy.



函数指针可以很容易地处理未知的

名称,但处理未知的签名。是另一回事。

C中的函数调用是静态的,因为代码要求b / b
收集参数并检索返回的值是建立的

在编译时,无法在运行时更改。一些

函数可以接受变量数甚至变量类型

的参数,但对函数的任何特定调用只有固定数量的参数
a已知类型。

A function pointer makes it easy to handle the unknown
name, but handling the unknown "signature" is another matter.
A function call in C is static in the sense that the code to
gather the arguments and retrieve the returned value is built
at compile time and cannot be changed at run time. Some
functions can accept variable numbers and even variable types
of arguments, but any particular call to a function has only
a fixed number of arguments of known types.


据我所知,只有两种解决方案:


1)这是便携。如果您事先知道没有任何功能将需要超过2个参数,那么您可以做一些简单的事情

如:


switch(nparams){

case 0:(* user_func)();休息;

案例1:(* user_func)(P1);休息;

案例2:(* user_func)(P1,P2);休息;

}
As far as I can see, there are only two solutions:

1) This one is portable. If you know in advance that no function will
require more than, say, 2 parameters, then you can do something simple
like:

switch(nparams) {
case 0: (*user_func)(); break;
case 1: (*user_func)(P1); break;
case 2: (*user_func)(P1, P2); break;
}



这将有效(经过小幅修正后)。但请注意,必须知道参数类型的
;你不能将这个

方法延伸到匿名参数。您可以使用一个发烧友

调度方法,而不仅仅是参数计数,但是你还需要为不同的签名编写不同的调用。


小的修正是你需要转换

函数指针以匹配函数的实际类型

,当你调用它时,和函数's'类型包含关于其参数列表的信息

。你需要类似的东西


void(* user_func)(void)= ...;

...

switch(nparams){

case 0:(* user_func)(); break;

case 1:(*(void(*)(int))user_func)(P1); break;

case 2:(*(void(*)(int,int))user_func)(P1,P2);休息;

...


这是一个案例,其中一些typedef是一个独特的帮助

可读性。使用它们(并删除不必要的

虽然无害的解除引用操作符),你会得到


typedef void(* Fptr0)(void);

typedef void(* Fptr1)(int);

typedef void(* Fptr2)(int,int);

Fptr0 user_func = ... ;

...

switch(nparams){

case 0:user_func();休息;

案例1:((Fptr1)user_func)(P1);中断;

案例2:((Fptr2)user_func)(P1,P2);休息;

...

This will work (after a small correction). Note, though,
that the argument types must be known; you cannot extend this
approach to "anonymous" arguments. You could use a fancier
dispatching method than simply the argument count, but you''ll
still need to write different calls for different signatures.

The small correction is that you need to convert the
function pointer to match the actual type of the function
when you call it, and a function''s type includes information
about its argument list. You''d need something like

void (*user_func)(void) = ...;
...
switch (nparams) {
case 0: (*user_func)(); break;
case 1: (*(void (*)(int))user_func)(P1); break;
case 2: (*(void (*)(int,int))user_func)(P1,P2); break;
...

This is a case where a few typedefs are a distinct aid
to readability. Using them (and dropping the unnecessary
albeit harmless dereference operator), you''d have

typedef void (*Fptr0)(void);
typedef void (*Fptr1)(int);
typedef void (*Fptr2)(int, int);
Fptr0 user_func = ...;
...
switch (nparams) {
case 0: user_func(); break;
case 1: ((Fptr1)user_func)(P1); break;
case 2: ((Fptr2)user_func)(P1, P2); break;
...


2)如果您不知道参数的最大数量,那么

似乎没有办法做到这一点,缺少编写汇编程序代码。我猜这个看起来像这样:


- C代码将所有参数推送到本地堆栈

- C代码调用汇编程序,传入函数

地址,本地堆栈地址,也许参数数量

- 汇编程序例程设置堆栈框架并且间接

调用用户的C代码

- 汇编程序例程清除堆栈帧并返回
2) If you don''t know the maximum number of parameters, then there
seems to be no way to do this, short of writing assembler code. I
guess this would look something like this:

- the C code pushes all the parameters onto a local stack
- the C code calls an assembler routine, passing in the function
address, the local stack address, and maybe the number of parameters
- the assembler routine sets up a stack frame and does an indirect
call to the user''s C code
- the assembler routine clears up the stack frame and returns



...适用于类似的东西的值。将参数传递给函数的机制

是特定于平台的。一些

平台使用由调用者弹出的堆栈,其他人使用被调用者弹出的

堆栈。有些人会尽可能地将它们的参数传递给CPU

寄存器而不是堆栈。一些

对不同的参数类型使用不同的策略:整数

和指针在A0,A1,...寄存器和浮点数

F0,F1,......中的值在调用

可变参数函数时使用不同的策略,而不是在调用具有固定长度

参数列表的函数时。一些调用struct-valued函数的方式与int-valued函数不同。简而言之,这种方法需要

对你想要支持的各种平台上子程序链接细节的深入了解。

... for suitable values of "something like." The mechanisms
for passing arguments to functions are platform-specific. Some
platforms use a stack that''s popped by the caller, others use a
stack popped by the callee. Some pass their arguments in CPU
registers instead of on a stack, to the extent possible. Some
use different strategies for different argument types: integers
and pointers in the A0,A1,... registers and floating-point
values in F0,F1,... Some use different strategies when calling
variadic functions than when calling functions with fixed-length
parameter lists. Some call struct-valued functions differently
than int-valued functions. In short, this approach requires an
intimate knowledge of the details of subroutine linkage on the
various platforms you want to support.


有什么想法吗?我错过了什么/这有意义吗?如果我有(b)b / b,那么我将从Linux / gcc / x86开始,如有必要,继续使用其他

系统。有谁知道任何可以帮助我这么做的b / b
的网络资源?我此刻不知道该怎么做。
Any thoughts? Have I missed anything/does this make sense? If I have
to go for (2), I''ll start with Linux/gcc/x86 and move on to other
systems if necessary. Does anyone know of any web resources that could
help me do this? I''ve got no idea how to do this at the moment.



方法#1是实用的,如果你可以使用预定的

套签名并且套装不是太大。方法#2是灵活的
,但每次代码遇到新机器时需要重新完成大量的工作

(有时,甚至

a新编译器)。就个人而言,我只会在非常苛刻的情况下坚持使用#1并且只能使用#2

;它会变得更加昂贵。


事实上,在诉诸#2之前我会退后一步并且

思考一段时间。你正在寻找一种方法来构建一个函数

在运行时调用,这在C中是不可能完成的(甚至

#1是只是从一堆预先建立的电话中选择)。你可能认为这不仅仅是为了纯粹的享受,而是为了解决更广泛的问题。

或许现在是时候再次检查更广泛的问题,看看是否有更多的C-

友好接近它的方式,甚至是否应该接近它完全用另一种语言处理



-
Er ********* @ sun.com

Approach #1 is practical, if you can live with a predetermined
set of "signatures" and the set is not too large. Approach #2 is
flexible, but requires a lot of work that will need to be re-done
each time the code encounters a new machine (or sometimes, even
a new compiler). Personally, I''d stick with #1 and resort to #2
only in the very direst circumstances; it will turn out to be far
more expensive.

In fact, before resorting to #2 I''d take a step back and
ponder for a while. You''re looking for a way to build a function
call at run-time, something that really can''t be done in C (even
#1 is just choosing from among a bunch of pre-built calls). You
are presumably doing this not for the sheer enjoyment, but in
pursuit of a solution to a wider problem. Perhaps it''s time to
re-examine the wider problem and see whether there''s a more C-
friendly way to approach it, or even whether it ought to be
tackled with a different language altogether.

--
Er*********@sun.com


2006年7月11日08 :33:23-0700,Ancient_Hacker < gr ** @ comcast.net>

写道:
On 11 Jul 2006 08:33:23 -0700, "Ancient_Hacker" <gr**@comcast.net>
wrote:

> switch(nparams) {
案例0:(* user_func)();破解;
案例1:(* user_func)(P1);破解;
情况2:(* user_func)(P1,P2);休息;
}
>switch(nparams) {
case 0: (*user_func)(); break;
case 1: (*user_func)(P1); break;
case 2: (*user_func)(P1, P2); break;
}


不够好,因为参数可能有不同的大小。


Not good enough, as the parameters might be of different sizes.



忘了说 - 我知道所有Pn都是相同的整数类型。我不知道
知道''user_func''的作用,但是我可以为Pn指定整数类型。

但即便如此,我也不会喜欢这个解决方案。

Forgot to say - I know that all Pn are the same integer type. I don''t
know what ''user_func'' does, but I can specify the integer type for Pn.
But, even so, I don''t like this solution.


>这样的事情可能有用:

#define pushbyte(b)__ asm {push byte ptr b}
#define pushword(b)__ asm {push word ptr b}

#define popoff(c)__ asm {add sp,c}

void CallFunc(FuncPtr TheFunctionAddress) ,char * ParamInfo; unsigned
long int Params [])

for(i = 0; i< strlen(ParamInfo); i ++){int Len; Len = 0;

switch(ParamInfo [i]){
case''b'':pushbyte(Params [i]); LEN + = 1 ;;休息;
案例''w'':pushword(Params [i]); Len + = 2;休息;
case''l:pushlong(Params [i]); Len + = 4; break;
case''a:pushaddr(Params [i]); Len + = 4; break;
case default:printf(" bad param descriptor:!!%c",ParamInfo [i]);
}
* TheFunctionAddress();
popoff(Len ); $
}
>something like this might work:

#define pushbyte(b) __asm{ push byte ptr b }
#define pushword(b) __asm{ push word ptr b }

#define popoff(c) __asm{ add sp,c }

void CallFunc( FuncPtr TheFunctionAddress, char * ParamInfo; unsigned
long int Params[] )
{

for( i = 0; i < strlen( ParamInfo ); i++ ) { int Len; Len = 0;
switch( ParamInfo[i] ) {
case ''b'': pushbyte( Params[i] ); Len+=1;; break;
case ''w'': pushword( Params[i] ); Len +=2;break;
case ''l: pushlong( Params[i] ); Len +=4;break;
case ''a: pushaddr( Params[i] ); Len += 4; break;
case default: printf("bad param descriptor: !! %c", ParamInfo[i] );
}
*TheFunctionAddress();
popoff( Len );
}



哇。你试过这个吗?我会试一试gcc -S,如果有意义,请看




谢谢 -


John

Wow. Have you ever tried this? I''ll give it a go with gcc -S and see
if it makes sense.

Thanks -

John


这篇关于直到运行时才知道参数数量时调用函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆