Register usage for inline assembly with gcc
Register usage for inline assembly with gcc
One of the main stumbling blocks I found for using the toolchain for 2.0 exploit development was setting up the registers for syscalls.
Initially I was trying
void sceAnyOldFunction(void *parm1, int parm2)
{
asm("syscall 0x2100");
}
as seen in various forums. But this assumes that the parameters are already in registers $a0, $a1 etc. I found out the hard way that that's not true if the compiler optimisation flags are on.
I eventually came up with the workaround of:
asm __volatile__ ("move $4, %0;"
"move $5, %1;"
"syscall 0x2100;"
: // no output regs
: "r" (parm1), "r" (parm2)
: "$4","$5"
);
which does work under optimisation, but is wasteful. I'm sure there's a better way of doing this by using the correct constraint parameters, but all the docs I could find on this were incomprehensible (to me).
Is there anyone with a better working knowledge of gcc, who can explain how this should be done?
Thanks.
Initially I was trying
void sceAnyOldFunction(void *parm1, int parm2)
{
asm("syscall 0x2100");
}
as seen in various forums. But this assumes that the parameters are already in registers $a0, $a1 etc. I found out the hard way that that's not true if the compiler optimisation flags are on.
I eventually came up with the workaround of:
asm __volatile__ ("move $4, %0;"
"move $5, %1;"
"syscall 0x2100;"
: // no output regs
: "r" (parm1), "r" (parm2)
: "$4","$5"
);
which does work under optimisation, but is wasteful. I'm sure there's a better way of doing this by using the correct constraint parameters, but all the docs I could find on this were incomprehensible (to me).
Is there anyone with a better working knowledge of gcc, who can explain how this should be done?
Thanks.
http://hitmen.c02.at/files/docs/gcc_mix ... _and_c.txt
look at this text....its originally for arm assembly, but the principles stay the same
look at this text....its originally for arm assembly, but the principles stay the same
Groepaz - unfortunately I'm not sure yoru code helps - it still allows GCC to allocate to its choice of registers.
Holger - thanks for your tip, I'll try that to see if it helps for the PSP.
I found lots of info on this for x86-architectures, but nothing much that helped apply it to the PSP. Looks like r4, r5 etc. is promising though.
Holger - thanks for your tip, I'll try that to see if it helps for the PSP.
I found lots of info on this for x86-architectures, but nothing much that helped apply it to the PSP. Looks like r4, r5 etc. is promising though.
try something like this:
Code: Select all
void func (void *arg)
{
register void *ptr __asm__ ("a0") = arg;
__asm__ volatile ("/*asm code here*/": "=r"(ptr) : "r"(ptr) : "memory");
}
Heh, that's exactly what I've been trying since posting (since there are no explicit names for the registers in the MIPS-variant asm constraints).
This variant seems to work, and generate the right opcodes:
int sceCtrlReadBufferPositive(SceCtrlData *pad_data, int count)
{
register SceCtrlData * lpaddata asm("$4") = pad_data;
register SceCtrlData * lcount asm("$5") = count;
asm __volatile__ (
"syscall 0x215b;"
: // no output regs
: "r" (lpaddata), "r" (lcount)
);
}
Just a shame that the 'register' modifier can't be used against the function parameters directly, i.e.
int sceBlah(register int param asm("$4"))
{
}
because that would be much neater. :)
This variant seems to work, and generate the right opcodes:
int sceCtrlReadBufferPositive(SceCtrlData *pad_data, int count)
{
register SceCtrlData * lpaddata asm("$4") = pad_data;
register SceCtrlData * lcount asm("$5") = count;
asm __volatile__ (
"syscall 0x215b;"
: // no output regs
: "r" (lpaddata), "r" (lcount)
);
}
Just a shame that the 'register' modifier can't be used against the function parameters directly, i.e.
int sceBlah(register int param asm("$4"))
{
}
because that would be much neater. :)
The point is that the arguments aren't guaranteed to be in the right registers, unless appropriate constraints are supplied.
The classic
void func(int foo)
{
asm ("syscall bar")
}
format works OK if optimisation is turned off, but with optimisation gcc tends to inline the functions, and not bother setting up the registers.
The constraints given force the use of the correct registers, and don't appear to cause the generation of any surplus opcodes - which was my end goal, even though it looks pretty ugly.
The classic
void func(int foo)
{
asm ("syscall bar")
}
format works OK if optimisation is turned off, but with optimisation gcc tends to inline the functions, and not bother setting up the registers.
The constraints given force the use of the correct registers, and don't appear to cause the generation of any surplus opcodes - which was my end goal, even though it looks pretty ugly.
The thing is, I don't mind letting the compiler inline the functions, so long as it gets the registers right. Letting it optimise my code (so long as it can do it safely) seems like A Good Thing(tm).
As I said, declaring register local variables seems to be the way to do it - it works, it's safe, it results in tight code, it just doesn't look nice (but I don't really care about that).
As I said, declaring register local variables seems to be the way to do it - it works, it's safe, it results in tight code, it just doesn't look nice (but I don't really care about that).