Here is how the code *could* look, like a rough draft or so (not yet complete, but)
// Loads all data into the correct places and calls the function.// intArgSize is the size in bytes for how much data to put in int registers// floatArgSize is the size in bytes for how much data to put in float registers// stackArgSize is the size in bytes for how much data to put on the callstackextern "C" asQWORD ppcFunc(int intArgSize, int floatArgSize, int stackArgSize, asDWORD func){ asQWORD result; asDWORD *args = ppcArgs; __asm__ ( "\tmr r27,%1\n" // intArgSize "\tmr r28,%2\n" // floatArgSize "\tmr r29,%3\n" // stackArgSize "\tmr r30,%4\n" // args pointer "\tmr r31,%5\n" // func pointer #define LOAD_WORD(_reg,_off) "\tcmpwi r27,"#_off"\n" "\tble L"#_reg"\n" "\tlwz "#_reg","#_off"(r30)\n" "L"#_reg":\n" LOAD_WORD(r3,0) LOAD_WORD(r4,4) LOAD_WORD(r5,8) LOAD_WORD(r6,12) LOAD_WORD(r7,16) LOAD_WORD(r8,20) LOAD_WORD(r9,24) LOAD_WORD(r10,28) "\taddi r30,r30,32\n" #define LOAD_DOUBLE(_reg,_off) "\tcmpwi r28,"#_off"\n" "\tble L"#_reg"\n" "\tlfd "#_reg",0(r30)\n" "L"#_reg":\n" LOAD_DOUBLE(f0,0) LOAD_DOUBLE(f1,8) LOAD_DOUBLE(f2,16) LOAD_DOUBLE(f3,24) LOAD_DOUBLE(f4,32) LOAD_DOUBLE(f5,40) LOAD_DOUBLE(f6,48) LOAD_DOUBLE(f7,52) LOAD_DOUBLE(f8,60) LOAD_DOUBLE(f9,68) LOAD_DOUBLE(f10,76) LOAD_DOUBLE(f11,84) LOAD_DOUBLE(f12,92) LOAD_DOUBLE(f13,100) LOAD_DOUBLE(f14,108) "\taddi r30,r30,96\n" // TODO: set up stack frame // TODO: load r29 bytes from r30 "\tbl r31\n" "\tmr %0,r3\n" // TODO: take down stack frame /* outputs: */ : "=&r" (result) /* inputs: */ : "r" (intArgSize), "r" (floatArgSize), "r" (stackArgSize), "r" (args), "r" (func) /* clobbers: */ : "memory"); return result; /* * "=&r" (result) means: 'result' is written on (the '='), it's any GP * register (the 'r'), and it must not be the same as * any of the input registers (the '&'). * "r" (func) means: 'func' is any GP reg * * "memory" in the 'clobbers' section means that gcc will make * sure that anything that should be in memory IS there * before calling this routine. */}