Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

get the caller's lr from subroutine into C variable - arm

Tags:

assembly

arm

I've got a C function that's supposed to get the value of the caller's lr register into a local variable.

I've tried the following code:

volatile long lr;
asm(
    "str %0, [sp, #4]\n" :
    "=r", (lr)
);

However, this doesn't change anything. It's not that I get the wrong value, it's just that the value of the lr local variable doesn't change at all ( contains garbage ).

Any ideas?

Thanks!

like image 667
Niv Avatar asked Dec 25 '22 22:12

Niv


1 Answers

To answer the question directly, there are two solutions.

    long lr;
    asm(" mov %0,lr\n" :: "=r" (lr));

This will put the lr value in the lr variable. You may wish to do this to analyse something. If you are assuming that the lr contains a return address, then this is untrue as Igor explains. In a non-leaf function, the compiler may use the lr as a temporary when computing a function argument as it is going to be clobbered.

    register long lr asm("lr");

This form allows you to reference the variable lr anywhere and the compiler will use the live lr value. The value may change through-out the function. For instance, when you call another function, it will usually be set to the return point in the currently active function.

As Igor explains whether getting the lr may not give you exactly what you expect. And the mechanism's we are using are gcc specific. You can not do this in a portable way; but accessing an lr is intrinsically non-portable.

See: ARM link register and frame pointer question for a little more on the use of lr.

like image 197
artless noise Avatar answered Jan 21 '23 02:01

artless noise