> Hi all,
> I want to initialize the stack pointer. Instead of using the
> STACKINITIALVALUE like in the mspgcc doc example :
> #define STACKINITIALVALUE 0x0280
> NAKED(_reset_vector__)
> {
> /* Initialise the stack */
> __asm__ __volatile__("mov %0, r1"::"i" (STACKINITIALVALUE));
> /* Your startup code goes here */
> __asm__ __volatile__("br #main"::);
> }
> 
> I want to use the =93__stack=94 variable defined in the linker but if I =
> try
> this:
> NAKED(_reset_vector__){
> 
>   extern int __stack;
> 
>   // Initialize the stack pointer
>   // N.B. Don't forget to add the compiler option "-mno-stack-init"
>   __asm__ __volatile__("mov %0, r1"::"i" (__stack));
> 
> }
> 
> I obtain this error:
> inconsistent operand constraints in an `asm'
> 
> Is there someone who knows how to use =93__stack=94?

First I'll tell you why the compiler won't accept what you are
doing.  Then I'll tell you why it won't work anyway, so pay attention.

Given your other question,

> Is it possible to give me an example of how I can get the function
> pointer at compile time?
> Thank you very much!

You can't get it at *compile* time, exactly, but you can trivially
get it at link time, with something like

void * const interesting_functions[] = {
        (void *)&main,
        (void *)&function_foo,
        (void *)&function_bar,
        (void *)&function_baz
};

Note that I declared the array "const" so it can be put in ROM rather
than needing to be copied to RAM.

This is such an elementary thing to be confused about that I'll risk being
personally offensive and guess that you're not a particularly experienced
C programmer.  As such, I recommend an *extremely* careful reading of the
manual and relevant source code before trying to get tricky with asm()
and reset vectors.  You can get into deep trouble that way.

In particular, "if you lie to the compiler, it will get you".  GCC's asm()
features are extremely powerful and let you describe your asm to the
optimizer so it can work with it.  If you describe it correctly, the
optimizer can do wonderful things for you.  But if you do not correctly
describe the conditions the asm requires to operate, the optimizer
will do things you didn't imagine and the asm may malfunction in highly
mysterious ways.

Just for example,
        asm("..." : "=r" (x) : "r" (x))
Some people have assumed that %0 and %1 would have to be the same register,
the one that contained "x".  FALSE!  There's a way to tell the optimizer that,
either
        asm("..." : "=r" (x) : "0" (x))
or the more compact
        asm("..." : "+r" (x)))
but if you use the original form, the optimizer will happily take
advantage of the fact that it copies from place-to-place and turn:
        x = y;
        asm("..." : "=r" (x) : "r" (y))
        foo(y);

into
        asm("..." : "=r" (x) : "r" (y))
        foo(y);
to save an instruction.  If your "..." code doesn't cope with the
possibility that %0 and %1 might be different registers, it will either
operate on the wrong data (if it reads from %0), or overwrite %1 which GCC
needs to remain unchanged so it can call foo(y).



Okay, back from the digression to your problem.  What's wrong with

        __asm__ __volatile__("mov %0, r1"::"i" (__stack));

Well, the reason it won't compile is that you are using a *variable*
__stack, but telling the compiler, via the "i" constraint, that only
an *immediate constant* is legal.

You can actually use any addressing mode in the source of a mov, so
        asm("mov %0, r1" :: "g" (__stack));

will generate correct assembly code.  Note that you don't need the
underscores around __asm__ unless you're compiling in strict-ANSI mode,
and any asm() with no output operands is automatically assumed to be
volatile by the compiler.  (It must have strange side effects, because
it doesn't have any non-strange ones and presumably you put it in the
source for *some* reason.)

However, DON'T try to put that in your code!  It won't work!

The reason is that you have declared __stack as "extern int".
(Really, it could be "extern int *", since that's what it is -
a pointer to a 16-bit aligned piece of memory.)

There's no "const" in the declaration.  That means that the variable
is in RAM.  Which means that its value is UNDEFINED until the initial
startup code is executed which copies the initialized variables from
ROM to RAM.

In your naked reset vector, that code hasn't been run yet!  Until you
call it, THE VALUES OF ALL NON-CONST VARIABLES ARE UNDEFINED.
Specifically including __stack.


Now, you could place the __stack variable in ROM (which will happen
automatically if you declare it as const and don't do anything
weird with the linker) and fetch from that, but you could just as
easily copy the initializer in-line and make it an immediate
operand after all.

The only reason to use a constant "variable" in ROM is if its value
cannot be computed when the C is compiled, and is going to be
provided by linking in some non-C object file or by patching the
final binary.

Reply via email to