Home Page
RABiD BUNNY FEVER
K.T.K

  • December 02, 2021, 02:48:20 PM *
  • Welcome, Guest
Please login or register.

Login with username, password and session length
Advanced search  

News:

Official site launch very soon, hurrah!


Author Topic: C Jump Tables  (Read 4865 times)

Dakusan

  • Programmer Person
  • Administrator
  • Hero Member
  • *****
  • Posts: 528
    • View Profile
    • Dakusan's Domain
C Jump Tables
« on: September 28, 2009, 05:31:19 AM »

Original post for C Jump Tables can be found at https://www.castledragmire.com/Posts/C_Jump_Tables.
Originally posted on: 07/11/08

I was thinking earlier today how it would be neat for C/C++ to be able to get the address of a jump-to label to be used in jump tables, specifically, for an emulator. A number of seconds after I did a Google query, I found out it is possible in gcc (the open source native Linux compiler) through the “label value operator” “&&”. I am crushed that MSVC doesn’t have native support for such a concept :-(.

The reason it would be great for an emulator is for emulating the CPU, in which, usually, each first byte of a CPU instruction’s opcode [see ASM] gives what the instruction is supposed to do. An example to explain the usefulness of a jump table is as follows:


void DoOpcode(int OpcodeNumber, ...)
{
   void *Opcodes[]={&&ADD, &&SUB, &&JUMP, &&MUL}; //assuming ADD=opcode 0 and so forth
   goto *Opcodes[OpcodeNumber];
    ADD:
      //...
   SUB:
      //...
   JUMP:
      //...
   MUL:
      //...
}

Of course, this could still be done with virtual functions, function pointers, or a switch statement, but those are theoretically much slower. Having them in separate functions would also remove the possibility of local variables.

Although, again, theoretically, it wouldn’t be too bad to use, I believe, the _fastcall function calling convention with function pointers, and modern compilers SHOULD translate switches to jump tables in an instance like this, but modern compilers are so obfuscated you never know what they are really doing.

It would probably be best to try and code such an instance so that all 3 methods (function pointers, switch statement, jump table) could be utilized through compiler definitions, and then profile for whichever method is fastest and supported.


//Define the switch for which type of opcode picker we want
#define UseSwitchStatement
//#define UseJumpTable
//#define UseFunctionPointers

//Defines for how each opcode picker acts
#if defined(UseSwitchStatement)
   #define OPCODE(o) case OP_##o:
#elif defined(UseJumpTable)
   #define OPCODE(o) o:
   #define GET_OPCODE(o) &&o
#elif defined(UseFunctionPointers)
   #define OPCODE(o) void Opcode_##o()
   #define GET_OPCODE(o) (void*)&Opcode_##o
   //The above GET_OPCODE is actually a problem since the opcode functions aren't listed until after their ...
   //address is requested, but there are a couple of ways around that I'm not going to worry about going into here.
#endif

enum {OP_ADD=0, OP_SUB}; //assuming ADD=opcode 0 and so forth
void DoOpcode(int OpcodeNumber, ...)
{
   #ifndef UseSwitchStatement //If using JumpTable or FunctionPointers we need an array of the opcode jump locations
      void *Opcodes[]={GET_OPCODE(ADD), GET_OPCODE(SUB)}; //assuming ADD=opcode 0 and so forth
   #endif
   #if defined(UseSwitchStatement)
      switch(OpcodeNumber) { //Normal switch statement
   #elif defined(UseJumpTable)
      goto *Opcodes[OpcodeNumber]; //Jump to the proper label
   #elif defined(UseFunctionPointers)
      *(void(*)(void))Opcodes[OpcodeNumber]; //Jump to the proper function
      } //End the current function
   #endif

   //For testing under "UseFunctionPointers" (see GET_OPCODE comment under "defined(UseFunctionPointers)")
   //put the following OPCODE sections directly above this "DoOpcode" function
   OPCODE(ADD)
   {
      //...
   }
   OPCODE(SUB)
   {
      //...
   }

   #ifdef UseSwitchStatement //End the switch statement
   }
   #endif

#ifndef UseFunctionPointers //End the function
}
#endif

After some tinkering, I did discover through assembly insertion it was possible to retrieve the offset of a label in MSVC, so with some more tinkering, it could be utilized, though it might be a bit messy.

void ExamplePointerRetreival()
{
   void *LabelPointer;
   TheLabel:
   _asm mov LabelPointer, offset TheLabel
}
Logged