This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

how to save 2byte code address to stack manually

Hello,
I have a function void myfunc(int){...}
I want to place the address of this function on the stack, so that later I can use RET to pop the address back.
May I know how to do this in C code?
Regards,
KC

  • That is a problem for the compiler, not for you,

    Just to show

    make a small function such as

    void func (void)
    {
      EA = 1;
      ET1 = 0;
    }
    compile it and have a look at the genrated assembler.

    Erik


  • If you look at the instruction set manual for the 8051, you'll see that RET pulls the return address bytes from the stack high byte first. So, you need to push your address on the stack low byte first.

    Why do you want to manually push a return address instead of letting the compiler do it? The only reason that leaps to mind is trying to trick the processor into returning somewhere that it didn't come from -- as with a context switcher. (If you're writing that sort of code, it would be wise to study the procedure call and interrupt call sequence of the processor in detail.) Doing this sort of thing from C will break the normal flow of control of the language -- which of course is exactly what you want to do with a context switcher.

    But if that's what you want, you just need your C code to change the SP. Since you're inside a C function, there's already a return address on the for the end of that function. If you push another address on, then let the function return, it will return to the new address, but the old return address will still be on the stack. So, you really need to pop the old return address off before pushing a new one on.

    The stack pointer (SP) is SFR address 0x81. Without actually trying it myself, perhaps on easy way to change the stack would be to declare a pointer to a U8 in data space at that address:

    U8 data* stackPointer _at_ 0x81;

    If that overlays the stack pointer like I hope and generates the code I expect, then you can write C to push:

    *(++stackPointer) = val;

    and pop:

    val = *stackPointer--;

    without resorting to any assembler.

  • Hello,
    -------------------------------------------
    char *stackPointer;
    void *VoidPointer;
    char *GenericPointer;

    VoidPointer = GenericPointer;
    -------------------------------------------

    I want to save the 3byte "VoidPointer" into the stack space, which is pointed to by stackPointer.

    // Tried
    *(void *)stackPointer = VoidPtr;
    // but it doesnt work

    // this works
    *(void **)stackPointer = VoidPtr;
    // May I know why?

    Regards,
    KC

  • I want to save the 3byte "VoidPointer" into the stack space, which is pointed to by stackPointer

    WHY, explain IN DETAIL?

    There are many ways to do what you are talking about and "saving on the stack may not be the right thing. Most cases this is an automatic compilr function, but if you are doing some fancy compiler/assmbler mix, maybe you need do something unique. Again, without knowing why - no answer.

    Erik

  • You must have a rather strange meaning of "this works", it seems.

    Your first example is outright incorrect code. You can't legally dereference a pointer-to-void. There *is* nothing it points to, thus the name "void".

    The second example would overwrite StackPointer with VoidPointer, rather than storing VoidPointer on the stack. The code does the equivalent of

    	(void *)StackPointer = VoidPointer
    

    because the * before the (void **) and the second * inside the cast cancel each other.

    To do what you said you want to do, you need something along the lines of

    memcpy(StackPointer, &VoidPointer, sizeof(VoidPointer));
    StackPointer += sizeof(VoidPointer);

    NOTE: This may still be gravely wrong, depending on byte order and stack growth direction)


  • For the moment, I'm assuming "stackPointer" has nothing to do with the 8051 stack, and is just a good old C pointer for some software-maintained stack.

    You have a three-byte pointer which you want to stuff onto the stack, for some reason.

    To assign through a pointer, you need to make sure that the pointer actually points to a place where you can write your data. I'll assume that you've managed to get stackPointer to point at a spot with three bytes free that can be overwritten.

    So, the only thing left is to convince the compiler that stackPointer points at the same sort of thing that you're trying to store. I'll call the type of that thing "???". If you had a pointer to ???, you could then just dereference that pointer with '*', and do an assignment:

    ???* mysteryPointer;
    ??? m;

    *mysteryPointer = m;

    We can use a cast to change the type of the stackPointer instead of actually having a pointer declared of the correct type. So replace mysteryPointer with a cast of stackPointer:

    * ((??? *) stackPointer) = m;

    Filling in the question marks is actually pretty easy. You need cast stackPointer as a pointer to the type of thing that you're storing -- in this case a (void*). So:

    * (( (void*) *) stackPointer) = voidPointer;

    Which says "pretend stackPointer is a pointer to a void-pointer, then dereference it, and put a void-pointer there".

    You can strip off some of the spaces and redundant parentheses (hi Mark!) if you like:

    *(void**)stackPointer = voidPointer;

    which is the code that you said works. Now, you know why.

    As Hans noted, there are some other issues, like whether your stack pointer points at the last-occupied region, or whether it points at the next free spot.