Register usage for inline assembly with gcc

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Register usage for inline assembly with gcc

Post by Fanjita »

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.
holger
Posts: 204
Joined: Thu Aug 18, 2005 10:57 am

Post by holger »

you can specify in the "r" constraints into which registers the variables should get passed. Read the gcc info pages for details. (if I remember correctly for most architectures things like "r4" and "r5" worked, but not for all... some had different semantics)
User avatar
groepaz
Posts: 305
Joined: Thu Sep 01, 2005 7:44 am
Contact:

Post by groepaz »

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
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

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
Posts: 204
Joined: Thu Aug 18, 2005 10:57 am

Post by holger »

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");
}

Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

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. :)
mrbrown
Site Admin
Posts: 1537
Joined: Sat Jan 17, 2004 11:24 am

Post by mrbrown »

Um, your arguments are already in the correct registers for the syscall. What are you trying to do exactly?
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

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.
User avatar
Jim
Posts: 476
Joined: Sat Jul 02, 2005 10:06 pm
Location: Sydney
Contact:

Post by Jim »

A few possibilities:

Compile with -fno-inline.
Maybe __declspec(noinline) works with C too.
Put the syscall functions in a different C file.

Jim
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

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).
holger
Posts: 204
Joined: Thu Aug 18, 2005 10:57 am

Post by holger »

isn't the "asm volatile" tag enough to tell gcc that it should not optimize away that section?
User avatar
Jim
Posts: 476
Joined: Sat Jul 02, 2005 10:06 pm
Location: Sydney
Contact:

Post by Jim »

The thing is, I don't mind letting the compiler inline the functions, so long as it gets the registers right
Are you sure you need to optimise down to this level?
Every syscall is cycle critical?

I think you need to reconsider your priorities!

Jim
holger
Posts: 204
Joined: Thu Aug 18, 2005 10:57 am

Post by holger »

function inlining is enabled by default for -O2.
mrbrown
Site Admin
Posts: 1537
Joined: Sat Jan 17, 2004 11:24 am

Post by mrbrown »

Jim wrote:Maybe __declspec(noinline) works with C too.
__declspec? MSVC now are we? :P

Try __attribute__(noinline) instead :).
Post Reply