Forcing args in registers for function pointers

Hello, world

QNX 4.25, Watcom C 10.6 environment.

I need to force into specific registers the arguments passed to a
function (implemented into a .asm module) called through a function
pointer.

The target asm function expects the 3 arguments in EAX, EDX and ECX
registers.

I’ve tried something like this:

struct myStruct
{
/* Some fields… */

void (* FuncPtr) ( char *, char *, char * );

pragma aux FuncPtr parm [eax] [edx] [ecx];

/* Some other fields… */
};

The .S generated by “cc -S” shows that the C call load the last
arguments into EBX, not in ECX as expected.

The first two parameters get loaded into EAX and EDX as expected, but I
think this is also the default behaviour for Watcom compiler.

Is “#pragma aux parm” working for functions only (and not for function
pointers) ?

How can I solve my problem?

Sorry for my bad english… and thanks in advance!


/------------------------------------------------------------

  • Davide Ancri - Prisma Engineering
  • email = davidea AT prisma DASH eng DOT it
    ------------------------------------------------------------/

Davide <doesnot@exist.spam> wrote:

Hello, world

QNX 4.25, Watcom C 10.6 environment.

I need to force into specific registers the arguments passed to a
function (implemented into a .asm module) called through a function
pointer.

I think you have to define the calling parameters when you define
the function, not at the point of calling the function.

The target asm function expects the 3 arguments in EAX, EDX and ECX
registers.

I’ve tried something like this:

struct myStruct
{
/* Some fields… */

void (* FuncPtr) ( char *, char *, char * );

pragma aux FuncPtr parm [eax] [edx] [ecx];

/* Some other fields… */
};

At some point you must say:

struct_instance.FuncPtr = func_name;

And somewher you must prototype:

void func_name( char *, char *, char *);

I think you need to do the pragma where you prototype the function, e.g.:

void func_name( char *, char *, char *);
#pragma aux func_name parm [eax] [edx] [ecx];

The .S generated by “cc -S” shows that the C call load the last
arguments into EBX, not in ECX as expected.

The first two parameters get loaded into EAX and EDX as expected, but I
think this is also the default behaviour for Watcom compiler.

Yes, that is default.


Is “#pragma aux parm” working for functions only (and not for function
pointers) ?

Only for functions. Of course, you can then take a pointer to the
function that has been so described.

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

David Gibbs <dagibbs@qnx.com> wrote:

Davide <> doesnot@exist.spam> > wrote:
Hello, world

QNX 4.25, Watcom C 10.6 environment.

I need to force into specific registers the arguments passed to a
function (implemented into a .asm module) called through a function
pointer.

I think you have to define the calling parameters when you define
the function, not at the point of calling the function.

That should have been “not at the point of defining a pointer to the
function”.

A function ptr could point to any number of different functions with
different calling parameters.

Hm… on further thought, this gets even messier.

Ok… try two. It seems you can apply these pragmas to function
names, and possibly to type definitons that resolve to functions.

So, you might be able to do:

typedef void (*asm_func_type)(char *, char *, char * );
#pragma aux asm_func_type parm [eax] [edx] [ecx];

struct myStruct
{
/* Some fields… */

asm_func_type FuncPtr;

/* Some other fields… */
};


I would still want to include:

struct_instance.FuncPtr = func_name;

void func_name( char *, char *, char *);
#pragma aux func_name parm [eax] [edx] [ecx];

Just to be careful.

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

I would like to know how this gets resolved. Please keep me informed.

It would seem to me that since the pointer may be initialized in a different
scope then the call that there must be a way to designate the pragma toward
the pointer instead of, or in addition to the function definition.

“David Gibbs” <dagibbs@qnx.com> wrote in message
news:asqn28$7pm$1@nntp.qnx.com

David Gibbs <> dagibbs@qnx.com> > wrote:
Davide <> doesnot@exist.spam> > wrote:
Hello, world

QNX 4.25, Watcom C 10.6 environment.

I need to force into specific registers the arguments passed to a
function (implemented into a .asm module) called through a function
pointer.

I think you have to define the calling parameters when you define
the function, not at the point of calling the function.

That should have been “not at the point of defining a pointer to the
function”.

A function ptr could point to any number of different functions with
different calling parameters.

Hm… on further thought, this gets even messier.

Ok… try two. It seems you can apply these pragmas to function
names, and possibly to type definitons that resolve to functions.

So, you might be able to do:

typedef void (*asm_func_type)(char *, char *, char * );
#pragma aux asm_func_type parm [eax] [edx] [ecx];

struct myStruct
{
/* Some fields… */

asm_func_type FuncPtr;

/* Some other fields… */
};


I would still want to include:

struct_instance.FuncPtr = func_name;

void func_name( char *, char *, char *);
#pragma aux func_name parm [eax] [edx] [ecx];

Just to be careful.

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

David Gibbs <dagibbs@qnx.com> wrote:

Davide <> doesnot@exist.spam> > wrote:

I need to force into specific registers the arguments passed to a
function (implemented into a .asm module) called through a function
pointer.

typedef void (*asm_func_type)(char *, char *, char * );
#pragma aux asm_func_type parm [eax] [edx] [ecx];

The above doesn’t seem to work for me, but the following does:

typedef void asm_func_type(char *, char *, char * );
#pragma aux asm_func_type parm [eax] [edx] [ecx];


Here’s my complete test program:

#include <stdio.h>

typedef void (*asm_func_ptr)( int esi, int edi ); // Your way
#pragma aux asm_func_ptr parm [esi] [edi]

typedef void asm_func_type( int esi, int edi ); // My way
#pragma aux asm_func_type parm [esi] [edi]

#pragma aux asm_fun parm [esi] [edi]
void asm_fun( int esi, int edi ) {
printf( “esi=%d, edi=%d\n”, esi, edi );
}

int main( void ) {
asm_func_ptr fp = asm_fun; // Your way
asm_func_type *ff = asm_fun; // My way
fp( 1, 2 ); // Your way
ff( 1, 2 ); // My way
return 0;
}

$ cc -Q -ofoo foo.c && ./foo
esi=40504, edi=1
esi=1, edi=2


It’s also good to know that in the opposite case – when you need to
call a C function from assembly – you can use the typedef instead of
repeating the #pragma for each function:

asm_func_type asm_fun;
void asm_fun( int esi, int edi ) {
printf( “esi=%d, edi=%d\n”, esi, edi );
}


\

Wojtek Lerch QNX Software Systems Ltd.

Wojtek Lerch <wojtek_l@yahoo.ca> wrote:

David Gibbs <> dagibbs@qnx.com> > wrote:
Davide <> doesnot@exist.spam> > wrote:

I need to force into specific registers the arguments passed to a
function (implemented into a .asm module) called through a function
pointer.

typedef void (*asm_func_type)(char *, char *, char * );
#pragma aux asm_func_type parm [eax] [edx] [ecx];

The above doesn’t seem to work for me, but the following does:

typedef void asm_func_type(char *, char *, char * );
#pragma aux asm_func_type parm [eax] [edx] [ecx];

My fault… I shouldn’t have the * inside.

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

“Bill Caroselli (Q-TPS)” <QTPS@earthlink.net> wrote:

I would like to know how this gets resolved. Please keep me informed.

It would seem to me that since the pointer may be initialized in a different
scope then the call that there must be a way to designate the pragma toward
the pointer instead of, or in addition to the function definition.

That is what, I think, the typedef is doing. The pragma is associated
with the typedef, and then the pointer is declared to be of that type.

This associates the pointer with the pragma. Now, if you assign to
the pointer a function for which the pragma and typedef do not apply,
then you’ve written broken code. And, the compiler may not catch this –
pragmas are low-level manipulations. (That is, if the prototype matches
but the function doesn’t expect that calling order, I don’t think the
compiler would catch it. I could be wrong.)

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

David Gibbs <dagibbs@qnx.com> wrote:

That is what, I think, the typedef is doing. The pragma is associated
with the typedef, and then the pointer is declared to be of that type.

This associates the pointer with the pragma. Now, if you assign to
the pointer a function for which the pragma and typedef do not apply,
then you’ve written broken code. And, the compiler may not catch this –
pragmas are low-level manipulations. (That is, if the prototype matches
but the function doesn’t expect that calling order, I don’t think the
compiler would catch it. I could be wrong.)

I don’t think it would be impossible or even difficult for the compiler
to detect the incompatibility – it’s just being lazy. It’s silly to
behave as if a “function that takes one int argument in EAX” were more
compatible with a “function that takes one int argument in EBX” than
with a “function that takes one long argument in EAX”…


Wojtek Lerch QNX Software Systems Ltd.

Wojtek Lerch wrote:

The above doesn’t seem to work for me, but the following does:

typedef void asm_func_type(char *, char *, char * );
#pragma aux asm_func_type parm [eax] [edx] [ecx];

[CUT]

Thanks to all. Your answers had been very useful.

Davide


/------------------------------------------------------------

  • Davide Ancri - Prisma Engineering
  • email = davidea AT prisma DASH eng DOT it
    ------------------------------------------------------------/