[9fans] getcallerpc on arm7 - Plan9

This is a discussion on [9fans] getcallerpc on arm7 - Plan9 ; Hi, trying to adapt the getcallerpc function - that exists on Plan9 and p9p - to the arm7 using the arm-elf-gcc compiler, I realized that this would not be easy, as most function arguments are put into registers (the return ...

+ Reply to Thread
Results 1 to 5 of 5

Thread: [9fans] getcallerpc on arm7

  1. [9fans] getcallerpc on arm7

    Hi,

    trying to adapt the getcallerpc function - that
    exists on Plan9 and p9p - to the arm7 using the arm-elf-gcc
    compiler, I realized that this would not be easy, as
    most function arguments are put into registers
    (the return value into lr), and only pushed on the
    stack on demand - so it seems one can not expect to find
    the return address at a fixed position starting with
    the first argument's address.

    (Looking at runtime some ulongs around &firstarg I
    actually can see the return address, but it is a varying
    number of longs upwards (not downwards) of &firstarg)

    I wonder under what conditions plan9port's
    "return ((ulong*)x)[-2]" for arm-linux/gcc actually works.

    So far I found out that I could implement getcallerpc as
    a macro using gcc's __builtin_return_address(0), but this would
    not fit getcallerpc's normal behaviour (which I suppose
    only depends on &firstarg, not the current function
    context).

    Although I know that the Plan9 compilers and gcc organize
    function calls differently, I thought it would be helpful to
    understand what /sys/src/libc/arm/getcallerpc.s does -
    after having a look at A Manual for the Plan 9 assembler:

    MOVW 0(R13), R0
    RET

    Does this mean that it is just returning the contents of the
    first word on the Stack (R13) - and not interpreting &firstarg
    at all?

    Thanks for any hint,

    Michael


  2. Re: [9fans] getcallerpc on arm7

    > Although I know that the Plan9 compilers and gcc organize
    > function calls differently, I thought it would be helpful to
    > understand what /sys/src/libc/arm/getcallerpc.s does -
    > after having a look at A Manual for the Plan 9 assembler:
    >
    > MOVW 0(R13), R0
    > RET
    >
    > Does this mean that it is just returning the contents of the
    > first word on the Stack (R13) - and not interpreting &firstarg
    > at all?


    This appears to be wrong, but I don't have time to dig in.

    The pointer is intended to be used on architectures like the x86
    that automatically push the return address on the stack.

    On architectures that don't push the return address on the
    stack during the call instruction, the caller of getcallerpc
    will have saved the desired return address somewhere in
    its stack frame, and getcallerpc must root it out.

    vc (the MIPS compiler) saves the return PC in the very last
    word of the stack frame, so that /sys/src/libc/mips/getcallerpc.s:

    TEXT getcallerpc(SB), $0
    MOVW 0(SP), R1
    RET

    is correct.

    It appears that 5c (the ARM compiler) saves the return PC
    as the first word of the stack frame, which may be somewhat
    hard to locate.

    Russ



  3. Re: [9fans] getcallerpc on arm7

    > On architectures that don't push the return address on the
    > stack during the call instruction, the caller of getcallerpc
    > will have saved the desired return address somewhere in
    > its stack frame, and getcallerpc must root it out.


    It appears the implementation below
    works well with arm-elf-gcc on arm7tdmi:

    /*
    * Functions generated by arm-elf-gcc start
    * like this (always?):
    * mov ip, sp
    * stmdb sp!, {fp, ip, lr, pc}
    *
    * (The first argument, which is still in r0,
    * is pushed later, when its address is taken so
    * that it can be provided to getcallerpc.)
    *
    * To get the value of `lr', the return address,
    * walk up the stack, starting with x, until a
    * value *u is found which is the previous stack
    * pointer, i.e. which equals the address u+3.
    * In that case, the return address is expected
    * to be in u[1].
    *
    * If no such address is found, return an invalid value.
    */
    ulong
    getcallerpc(void *x)
    {
    ulong *u;
    int i;

    u = (ulong*)x;
    for (i=0; i<128; i++, u++)
    if (*u == (ulong)(u+3))
    return u[1];
    return ~0;
    }

    A helpful document was http://www.cems.uwe.ac.uk/~cduffy/es/5.ppt,
    to get an idea of how function arguments are provided
    and the stack is managed by the gcc on arm.

    If the stack contains a value which matches the
    condition for `ip', but which is not ip, getcallerpc
    will find it before the real ip/lr, and report a
    garbage address.

    Michael



  4. Re: [9fans] getcallerpc on arm7

    >It appears that 5c (the ARM compiler) saves the return PC
    >as the first word of the stack frame, which may be somewhat
    >hard to locate.


    it should be the same as the other risc machines, and seems
    all right when i test it with 5c/5l. gcc typically also uses a frame
    pointer, which might make it nearly as easy for that compiler.



  5. Re: [9fans] getcallerpc on arm7

    > it should be the same as the other risc machines, and seems all right
    > when i test it with 5c/5l. gcc typically also uses a frame pointer,
    > which might make it nearly as easy for that compiler.


    This seems to work well:

    .text
    .globl getcallerpc
    getcallerpc:
    ldr r0, [fp, #-4]
    bx lr

    I was a bit confused about whether or not the firstarg pointer
    is expected to be used by a getcallerpc implementation (so that
    it would also work in subfunctions of the current, provided
    &firstarg is passed down). The BUGS section of getcallerpc(2/3)
    gives a hint how this could be answered.


+ Reply to Thread