[comp.lang.c] Calling functions by address

src@mssx.UUCP (Pleschutznig Andreas) (08/29/88)

Suppose following:

We want to write a software emulation for another processor on UNIX 

So the main problem is to get into the emulation routines as fast as possible,
and therefore it doe not seem to be good enough to do

	switch (code) {
		case ..
		case ..
		}

So we thought of doing that job by declaring the addresses of the emulation 
routines and jumping to the routines by address like this

	(*addressarray[code]);

I know, I know that *does not* work, but maybe there is someone knowing to
get around.

byron@pyr.gatech.EDU (Robert Viduya) (08/31/88)

In article <679@mssx.UUCP> src@mssx.UUCP (Pleschutznig Andreas) writes:
>Suppose following:
>
>We want to write a software emulation for another processor on UNIX 
>
>So the main problem is to get into the emulation routines as fast as possible,
>and therefore it doe not seem to be good enough to do
>
>	switch (code) {
>		case ..
>		case ..
>		}
>
>So we thought of doing that job by declaring the addresses of the emulation 
>routines and jumping to the routines by address like this
>
>	(*addressarray[code]);
>
>I know, I know that *does not* work, but maybe there is someone knowing to
>get around.

Here's something I came up with in 5 minutes that seems to
do the job. The declaration for variable functions is an array of
pointers to functions that return integer. Note how the '*'
and the '[]' must be put in parens so they are evaluated
first.
------ Cut Here ------

int one(), two(), three(), four(), five();

int (*functions[])() = {one,two,three,four,five};

main(argc,argv)
{
   if (argc > 0 && argc < 6) 
      functions[argc-1]();
   else
      printf("Invalid number of arguments\n");
}

one()
{
   printf("There is one argument on the command line\n");
}


two()
{
   printf("There are two arguments on the command line\n");
}

three()
{
   printf("There are three arguments on the command line\n");
}

four()
{
   printf("There are four arguments on the command line\n");
}

five()
{
   printf("There are five arguments on the command line\n");
}
-- 
Another random extraction from the mental bit stream of...
Byron A. Jeff
Georgia Tech, Atlanta GA 30332
Internet:	byron@pyr.gatech.edu  uucp:	...!gatech!pyr!byron

pardo@june.cs.washington.edu (David Keppel) (08/31/88)

First, a "leading question" for those who don't want to read the
rest of this article: Can somebody describe for me "knotted code",
as compared to "threaded code"?

In article <679@mssx.UUCP> src@mssx.UUCP (Pleschutznig Andreas) writes:
>[ Emulation for another processor ]
>[ "switch(opcode){ case AAA: [...]" isn't fast enough ]

You can dereference a pointer to a function by the following:

    typedef void (*fptr_t)();
    fptr_t instruction[ OPCODES ] = { opc_aaa, ... };

	(*(instruction[opcode]))();

This still involves a function call/return overhead.  In high-
performance virtual machine interpreters such as Smalltalk, "threaded"
interpreters are often used.  To the best of my knowledge, threaded
code cannot be generated portably from C.  It may be possible to
generate by writing a special set of #defines and "fake functions",
having the compiler generate assembly, and then walking over the
assembly to generate the threading tables and the transfer sequences.

Original:

    main:
	jsb	foo
	jsb	bar
	<...>

    foo:
	<...>
	rsb

    bar:
	<...>
	rsb


Threaded:

    codeptrs:
	.long	foo
	.long	bar

    main:
	movl	&codeptrs,r4
	jmp	(r4)
	<...>
    
    foo:
	<...>
	jmp	*(r4)+

    bar:
	<...>
	jmp	*(r4)+
    
    

Citations Follow:
%A James R. Bell
%T Threaded Code
%J CACM
%V 16
%N 6
%D JUN 1973
%P 370-372

%A Robert B. K. Dewar
%T Indirect Threaded Code
%J CACM
%V 18
%N 6
%D JUN 1975
%P 330-331

	;-D on  ( To be conflagnulated )  Pardo
-- 
		    pardo@cs.washington.edu
    {rutgers,cornell,ucsd,ubc-cs,tektronix}!uw-beaver!june!pardo

noren@dinl.uucp (Charles Noren) (08/31/88)

I'm not sure if I understand, but try something like this:

  typedef void (*func)()  funcarray;

  void func1(), func2(), func3(),...   /* Function Prototypes */

  funcarray addressarray [] = {
    func1, func2, func3,...
  }

  ...and then execute this function to call function by address code:

  void execute (array, code)
  funcarray array[];
  int       code;
  {
    void (*function) ();

    function = array[code];
    (*function)();
  }

  ...the calling code would look like:

  execute (addressarray, code);

I have not tried this, but I have used something very similar for implementing
finite state machines using state/event matrices and it worked quite well.

                          chuck

djones@megatest.UUCP (Dave Jones) (08/31/88)

From article <679@mssx.UUCP>, by src@mssx.UUCP (Pleschutznig Andreas):
...

> 
> So we thought of doing that job by declaring the addresses of the emulation 
> routines and jumping to the routines by address like this
> 
> 	(*addressarray[code]);
> 
> I know, I know that *does not* work, but maybe there is someone knowing to
> get around.

Nothing to "get around".  There is nothing in your way.  You just left off
the empty parameter list ().  (First language Pascal?)

/* declaration */

int routine1(), routine2(), routineN();

int (*addressarray[])() = { routine1, routine2, routineN }; 

/* calling sequence */

  int return_value = (*addressarray[code])();

djones@meest.UUCP (Dave Jones) (08/31/88)

From article <679@mssx.UUCP>, by src@mssx.UUCP (Pleschutznig Andreas):
...

> 
> So we thought of doing that job by declaring the addresses of the emulation 
> routines and jumping to the routines by address like this
> 
> 	(*addressarray[code]);
> 
> I know, I know that *does not* work, but maybe there is someone knowing to
> get around.

Nothing to "get around".  There is nothing in your way.  You just left off
the empty parameter list ().  (First language Pascal?)

/* declaration */

int routine1(), routine2(), routineN();

int (*addressarray[])() = { routine1, routine2, routineN }; 

/* calling sequence */

  int return_value = (*addressarray[code])();
#! 

chris@mimsy.UUCP (Chris Torek) (08/31/88)

In article <626@dinl.mmc.UUCP> noren@dinl.uucp (Charles Noren) writes:

Your syntax needs work:

>typedef void (*func)()  funcarray;

`typedef void (*func)();' or `typedef void (*funcarray[])()'.

>void func1(), func2(), func3(),...   /* Function Prototypes */

These are declarations, but not prototype declarations.  (There is
a substantial difference.)

>funcarray addressarray [] = {
>   func1, func2, func3,...
>}

If the typedef includes the []s, the declaration should not; conversely,
if the typedef does not, the declaration should.  This would work given

    typedef void (*funcarray)();

although I think this is a misleading name (there is no array here).

>...and then execute this function to call function by address code:
>
>void execute (array, code)
>funcarray array[];
>int       code;
>{
>  void (*function) ();
>
>  function = array[code];
>  (*function)();
>}

This syntax is correct.

>...the calling code would look like:
>
>  execute (addressarray, code);

The multiple levels of calling are unnecessary.  If `a' is an object of
type `array N of pointer to function (args) returning void', then the
syntax to call that function is

	(*a[i])(args);

so the call to `execute(addressarray, code)' can be replaced with
`(*addressarray[code])()'.  Note that subscript `[]' binds more tightly
than indirection `*', so the format (*(a[i]))(args) suggested in
another article is also correct.  The formats a[i](args) (and,
equivalently, (a[i])(args)) are NOT correct by K&R 1st ed., although
they have been legitimised in the three draft proposed ANSI standards
submitted for public review, and are accepted by numerous compilers.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

bill@proxftl.UUCP (T. William Wells) (08/31/88)

In article <679@mssx.UUCP> src@mssx.UUCP (Pleschutznig Andreas) writes:
: Suppose following:
:
: We want to write a software emulation for another processor on UNIX
:
: So the main problem is to get into the emulation routines as fast as possible,
: and therefore it doe not seem to be good enough to do
:
:       switch (code) {
:               case ..
:               case ..
:               }
:
: So we thought of doing that job by declaring the addresses of the emulation
: routines and jumping to the routines by address like this
:
:       (*addressarray[code]);
:
: I know, I know that *does not* work, but maybe there is someone knowing to
: get around.

The correct call is

	(*addressarray[code])();

However, you will probably find the switch to be faster.

----

The following analysis presumes that we are running on something
of the order of a Vax, 386, or 68k, and have a reasonable C
compiler.

Here is what the switch is likely to generate:

	move    a0,code         (written in GASM: Generic Assembler)
	cmp     a0,256
	jgrtr   after           (branch if *unsigned* greater than 256)
	shiftl  a0,2
	jmp     table[a0]

The call should generate something like

	move    a0,code
	shiftl  a0,2
	call    table[a0]

and the function should add to this

	sub     sp,#locals      (or something else to make a stack frame)
	...
	return

The difference between these is:

	move    a0,code         move    a0,code
	cmp     a0,256          shiftl  a0,2
	jgrtr   after           call    table[a0]
	shiftl  a0,2            sub     sp,#locals
	jmp     table[a0]       return

On the machines I am familiar with, the cmp and sub instructions
are about equivalent in execution time, so leaving out that and
the common instructions, we have:

	jgrtr   after           call    table[a0]
	jmp     table[a0]       return

I would expect that the not-taken branch + the indirect branch to
take significantly less time than the call + return.  I also have
been *very* generous in my assumptions about how fast the call
will be; it often will have more overhead than the one
instruction I added.

You could also get rid of the cmp and jgrtr instructions, if you
are *certain* that the code passed will always be within range.
Some compilers let you create assembler output instead of object
output; you take that assembler output, run a sed script on it,
and then assemble that.  You can use this method to tweak all
sorts of things, besides.  But do this only if you are *really*
desperate for speed.

(I wanna #pragma :-)

---
Bill
novavax!proxftl!bill

bill@proxftl.UUCP (T. William Wells) (08/31/88)

In article <6351@pyr.gatech.EDU> byron@pyr.UUCP (Byron A Jeff) writes:
:       functions[argc-1]();

Nice try, but that is not portable. You need to write it as:

:       (*functions[argc-1])();

ANSI makes your example legal, however.

---
Bill
novavax!proxftl!bill

ark@alice.UUCP (Andrew Koenig) (09/01/88)

> From article <679@mssx.UUCP>, by src@mssx.UUCP (Pleschutznig Andreas):
> So we thought of doing that job by declaring the addresses of the emulation 
> routines and jumping to the routines by address like this

> 	(*addressarray[code]);

Before you travel this route, I suggest you measure the relative
time it takes to execute a switch vs. to call a function.
You may find that the switch is faster.
-- 
				--Andrew Koenig
				  ark@europa.att.com

lai@vedge.UUCP (David Lai) (09/01/88)

In article <679@mssx.UUCP> src@mssx.UUCP (Pleschutznig Andreas) writes:
>Suppose following:
>
>We want to write a software emulation for another processor on UNIX 
>So we thought of doing that job by declaring the addresses of the emulation 
>routines and jumping to the routines by address like this
>
>	(*addressarray[code]);
>
>I know, I know that *does not* work, but maybe there is someone knowing to
>get around.

You're missing the function call parenthesis: (*addressarray[code])();

the example below works, and is approx what you want to do
(besides out news wont let me send the above unless I have more
 new text):

typedef int (*ptr_to_int_returning_func)(); /* declares a type for readability */
extern int printf(), fprintf(), scanf(), strlen();

ptr_to_int_returning_func array_of_func_ptrs[]=
	{
	printf,
	fprintf,
	scanf,
	strlen
	};	/* get the idea? */

main()
{
/* lets do a few calls */
int i;
i = (*array_of_func_ptrs[3])("test_strlen");
(*array_of_func_ptrs[0])("size was %d\n",i); /* test printf */
}

I hope the example helps with the nasty syntax.
-- 
	"What is a DJ if he can't scratch?"  - Uncle Jamms Army
The views expressed are those of the author, and not of Visual Edge, nor Usenet.
David Lai (vedge!lai@larry.mcrcim.mcgill.edu || ...watmath!onfcanim!vedge!lai)
-- 
	"What is a DJ if he can't scratch?"  - Uncle Jamms Army
The views expressed are those of the author, and not of Visual Edge, nor Usenet.
David Lai (vedge!lai@larry.mcrcim.mcgill.edu || ...watmath!onfcanim!vedge!lai)

cdold@starfish.Convergent.COM (Clarence Dold) (09/10/88)

 From article <679@mssx.UUCP>, by src@mssx.UUCP (Pleschutznig Andreas):
> 
> So we thought of doing that job by declaring the addresses of the emulation 
> routines and jumping to the routines by address like this
> 
> 	(*addressarray[code]);
> 
> I know, I know that *does not* work, but maybe there is someone knowing to
> get around.

I don't know about that not working, but this one does work.
For QuickC, running on a PC, jumps to a ROM based routine (actually the 
reset jump for an 8088 CPU chip).
I use this same method to 'wrap' the ROM based disk format that is contained
in BIOS ROM on the controller card with a friendlier menu.

main ()
{
  void (far *bye) ();
  int far *pt;

  pt = ((int far *) (0x0000472L);
  *pt = 0x1234;                    /* for warm boot */
  /*  *pt = 0x0000;  */           /* for cold boot */

  bye = (void far *) 0x0ffff0000L;
  (*bye) ();
}
-- 
Clarence A Dold - cdold@starfish.Convergent.COM		(408) 435-5274
		...pyramid!ctnews!mitisft!professo!dold
		P.O.Box 6685, San Jose, CA 95150-6685

chris@mimsy.UUCP (Chris Torek) (09/10/88)

In article <707@starfish.Convergent.COM> cdold@starfish.Convergent.COM
(Clarence Dold) writes:
>... For QuickC, running on a PC, jumps to a ROM based routine (actually the 
>reset jump for an 8088 CPU chip)...
>
>main ()
>{
>  void (far *bye) ();
>  int far *pt;
>
>  pt = ((int far *) (0x0000472L);	[missing ) somewhere here]
>  *pt = 0x1234;                    /* for warm boot */
>  /*  *pt = 0x0000;  */           /* for cold boot */
>
>  bye = (void far *) 0x0ffff0000L;
>  (*bye) ();
>}

Incidentally, this program can be `simplified' (and from dumb-but-fast
compilers, the resulting code probably will be noticeably shorter) to

	main()
	{

		*(int far *)0x472L = 0x1234;	/* warm boot */
		/*                 = 0		   cold boot */
		(*(void (far *)())0xffff0000L)();
	}

The addresses can (and probably should) be prettied up with `#define's,
at least for anything even slightly more substantial than this example.

(I confess to being somewhat surprised at the difference between warm
and cold boots; more often, a warm boot is done by jumping to some other
address than the ROM restart address.  Something like

		#define COLDBOOT ((void (*)())0xfc000000)
		#define WARMBOOT ((void (*)())0xfc000004)
		(*(cold ? COLDBOOT : WARMBOOT))();

or if you prefer the readable version :-) ,

		if (cold) (*COLDBOOT)(); else (*WARMBOOT)();

)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris