public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* RE: Constructing function calls
@ 2005-07-21 23:03 Meissner, Michael
  0 siblings, 0 replies; 4+ messages in thread
From: Meissner, Michael @ 2005-07-21 23:03 UTC (permalink / raw)
  To: Jean-Sebastien Legare, gcc-help

I would say it is impossible.  The calling sequence depends on the type
of the arguments, and the declaration of the called function (ie, often
times functions that use variable arguments have a different calling
sequence than functions with a fixed number of arguments).  For example,
a 64 bit floating point value is often passed within a floating point
register, but a 64 bit integer might be required to be passed in an
even:odd register pair on a 32-bit system.

One possible way of 'solving' the program is change the code to use
variable argument function calling sequence, use va_start to create the
va_list object and pass it to the child, much like is done with vprintf.

-----Original Message-----
From: gcc-help-owner@gcc.gnu.org [mailto:gcc-help-owner@gcc.gnu.org] On
Behalf Of Jean-Sebastien Legare
Sent: Thursday, July 21, 2005 6:51 PM
To: gcc-help@gcc.gnu.org
Subject: Constructing function calls

Hi

I have a special task I would like to accomplish regarding construction
of
function calls, without (preferably) using __asm__ sections.

I would like to pass a block of data containing arguments to a function
from
which I don't know the type nor number of arguments. The only thing I
know 
is the address of the function pointer and the size of the argument
block
(number of 32bit words).

That is, I would like to fill this function:

void call_func( (void*)func(), void* args, int size) {

    1. push the contents of args to the stack;
    2. call func() with no args (func will recuperate them from the
stack);
    3. return
}

For instance, I would like to be able to call :

void print3ints(int a, int b, int c) {
    printf(" %d %d %d\n",a,b,c);
}

by doing :

{
    int* args = malloc( 3 *sizeof(int));
    args[0] = 1; args[1] = 2; args[2] = 3;
    call_func(print3ints,args,3);
}


I looked at "__builtin_apply" but it requires calling
"__builtin_apply_args"
beforehand,  which I cannot do.

I successfully managed to do that without using __asm__ on a x86. 
I filled a local int array in call_func with the passed argument block
and then 
I called the passed function (stack bashing).

However, the method breaks when compiling in -O3 mode and it would
certainly
not work on other systems where some arguments are passed inside
registers.

What are my best options ?


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Constructing function calls
@ 2005-07-21 22:52 Jean-Sebastien Legare
  0 siblings, 0 replies; 4+ messages in thread
From: Jean-Sebastien Legare @ 2005-07-21 22:52 UTC (permalink / raw)
  To: gcc-help

Hi

I have a special task I would like to accomplish regarding construction of
function calls, without (preferably) using __asm__ sections.

I would like to pass a block of data containing arguments to a function from
which I don't know the type nor number of arguments. The only thing I know 
is the address of the function pointer and the size of the argument block
(number of 32bit words).

That is, I would like to fill this function:

void call_func( (void*)func(), void* args, int size) {

    1. push the contents of args to the stack;
    2. call func() with no args (func will recuperate them from the stack);
    3. return
}

For instance, I would like to be able to call :

void print3ints(int a, int b, int c) {
    printf(" %d %d %d\n",a,b,c);
}

by doing :

{
    int* args = malloc( 3 *sizeof(int));
    args[0] = 1; args[1] = 2; args[2] = 3;
    call_func(print3ints,args,3);
}


I looked at "__builtin_apply" but it requires calling "__builtin_apply_args"
beforehand,  which I cannot do.

I successfully managed to do that without using __asm__ on a x86. 
I filled a local int array in call_func with the passed argument block and then 
I called the passed function (stack bashing).

However, the method breaks when compiling in -O3 mode and it would certainly
not work on other systems where some arguments are passed inside
registers.

What are my best options ?

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Constructing Function Calls
  2001-10-10 11:26 Constructing Function Calls Pierre NGUYEN-TUONG
@ 2001-10-10 12:14 ` John Love-Jensen
  0 siblings, 0 replies; 4+ messages in thread
From: John Love-Jensen @ 2001-10-10 12:14 UTC (permalink / raw)
  To: Pierre NGUYEN-TUONG, help-gcc

Hi Pierre,

The problem is that C or C++ are not good languges to do what you want to
do.  Pick a better language, like LISP or Perl.

Otherwise, package your parameter data better, such as:

typedef enum { kEndOfList, kString, kChar, kInt, kFloat, kDouble } Datum_t;
// Whatever you're interested in
struct Datum {
    Datum_t mType;
    void* mData;
};

void function_B(Datum* DataList)
{
    while(DataList->mType != kEndOfList)
    {
        switch(DataList->mType)
        {
            case kString: printf("--- %s\n", (char*)(DataList->mData));
break;
            case kChar: printf("--- %c\n", *(char*)(DataList->mData));
break;
            case kInt: printf("--- %d\n", *(int*)(DataList->mData)); break;
            case kFloat: printf("--- %f\n", *(float*)(DataList->mData));
break;
            case kDouble: printf("--- %lf\n", *(double*)(DataList->mData));
break;
            default: print("--- Danger, Will Robinson!\n");
        }
        ++DataList;
    }
}

I'll leave the packaging up of your data as an exercise.

Sincerely,
--Eljay





^ permalink raw reply	[flat|nested] 4+ messages in thread

* Constructing Function Calls
@ 2001-10-10 11:26 Pierre NGUYEN-TUONG
  2001-10-10 12:14 ` John Love-Jensen
  0 siblings, 1 reply; 4+ messages in thread
From: Pierre NGUYEN-TUONG @ 2001-10-10 11:26 UTC (permalink / raw)
  To: help-gcc

Hello,

I have a slight problem. Consider two functions, function_A and 
function_B. I want to call function_B
inside function_A, with the same arguments of function_A, but without 
knowing the prototype of
function_B, ie passing all arguments of funtion_A to function_B (I don't 
want to use va_list in function_B).

A set of builtin functions allows this :
__builtin_apply_args()
__builtin__apply(void (*function)(),void *arguments,size_t size)

As you can see, you need to know the size of the stack arguments passed 
to the function.

Let see the code. The function_B is

---------------------------------------------------------
void function_B(char *name,void *function,int a,long b,float *c,int d)
{
printf("Function B : printing\n") ;

printf("--- name=%s\n"  ,name  ) ;
printf("--- a=%i\n"     ,a     ) ;
printf("--- b=%li\n"    ,b     ) ;
printf("--- c=%e\n"     ,*c    ) ;
printf("--- d=%i\n"     ,d     ) ;
}
---------------------------------------------------------

Inside the function_A, I try to guess the stack size. I forgot to tell 
you: function_A is a variadic
function, so you can use va_start, va_arg and va_end to parse the 
unknown arguments. I assume that
all the arguments are 4 bytes wide (float are 4 bytes wide, but are 
expanded to 8 bytes on the stack.
This is the problem ?).

Function_A is

---------------------------------------------------------
void function_A(char *name,void *function,...)
{
va_list ap               = NULL              ;
void    *dummy     = NULL              ;

int     cpt                = 1                       ;

size_t  size             = 0                       ;
void    *arguments = NULL              ;



/* Guessing stack size      */
/* I am using the va_arg macro */

printf("Function A : stack size\n") ;

va_start(ap,function) ;
dummy = va_arg(ap,void *) ;

printf("--- arg #%i : %p\n",cpt,dummy) ;

while(dummy != NULL)
   {
     cpt++ ;
     dummy = va_arg(ap,void *) ;
     printf("--- arg #%i : %p\n",cpt,dummy) ;
   }

va_end(ap) ;


/* Now calculating the stack size. Every argument shoud be 4 bytes wide */
size = cpt * 4 ;

printf("--- %i args, stack size=%i\n",cpt,size) ;


/* Storing arguments in the stack */
printf("Function A : applying arguments\n") ;

arguments = __builtin_apply_args(size) ;

printf("Function A : calling function\n") ;

/* The call */
__builtin_apply(function,arguments,size) ;
}
---------------------------------------------------------

The main program is

---------------------------------------------------------
int main(int argc,char *argv[])
{
float flottant = 0.0 ;

flottant = 7.999 ;

printf("--------------------------Test  A calling B\n\n") ;
function_A("le test",function_B,5,67L,&flottant,10,NULL) ;

return 0 ;
}
---------------------------------------------------------

And the result :

---------------------------------------------------------

--------------------------Test  A calling B

Function A : stack size
--- arg #1 : 0x5
--- arg #2 : 0x43
--- arg #3 : 0xbfffed84
--- arg #4 : 0xa
--- arg #5 : (nil)
--- 5 args, stack size=20
Function A : applying arguments
Function A : calling function
Function B : printing
--- name=le test
--- a=5
--- b=67
--- c=7.999000e+00
--- d=5

---------------------------------------------------------

Ok, it works. So, where is the problem ? Well, I used a pointer to give 
the float argument. But I want to give a float,
not a pointer to a float. So, lets examine function_C and the main program:

---------------------------------------------------------

void function_C(char *name,void *function,int a,long b,float *c,float 
d,int e)
{
printf("Function B : printing\n") ;

printf("--- name=%s\n"  ,name  ) ;
printf("--- a=%i\n"     ,a     ) ;
printf("--- b=%li\n"    ,b     ) ;
printf("--- c=%e\n"     ,*c    ) ;
printf("--- d=%e\n"     ,d     ) ;
printf("--- e=%i\n"     ,e     ) ;
}

/***/

int main(int argc,char *argv[])
{
float flottant = 0.0 ;

flottant = 7.999 ;


printf("--------------------------Test  A calling C\n\n") ;
function_A("le test",function_C,5,67L,&flottant,flottant,10,NULL) ;


return 0 ;
}
---------------------------------------------------------

And now the trace of the execution:

---------------------------------------------------------

--------------------------Test  A calling C

Function A : stack size
--- arg #1 : 0x5
--- arg #2 : 0x43
--- arg #3 : 0xbfffed84
--- arg #4 : 0xe0000000
--- arg #5 : 0x401ffef9
--- arg #6 : 0xa
--- arg #7 : (nil)
--- 7 args, stack size=28
Function A : applying arguments
Function A : calling function
Function B : printing
--- name=le test
--- a=5
--- b=67
--- c=7.999000e+00
--- d=-3.689349e+19
--- e=1075838713

---------------------------------------------------------
Arrgh !!! Big problem on the float... If I give the correct size for the 
stack (remember, a float
is 8 bytes wide in the stack) the result is the same.

So, finally, my question (sorry for the long explanation):

Is there a solution ? Shall I use only 32 bits arguments, ie pointers 
instead of float ? Am I wrong or
is there a bug somewhere ?
I don't see why the __builtin_apply function has a different behaviour 
for floats and for other types...
(By the way, I am working on Linux RedHat, AMD K6II.)


Any help is (really) appreciated,


Sincerely yours,


Pierre Nguyen Tuong.


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2005-07-21 23:03 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-07-21 23:03 Constructing function calls Meissner, Michael
  -- strict thread matches above, loose matches on Subject: below --
2005-07-21 22:52 Jean-Sebastien Legare
2001-10-10 11:26 Constructing Function Calls Pierre NGUYEN-TUONG
2001-10-10 12:14 ` John Love-Jensen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).