I've run into another situation that seems to require a change to mspgcc's
lower-level interfaces.  Here's the background, rationale, and impact.  This
affects you if you override certain functions like _reset_vector__, use the
"reserve" function attribute (RESERVE_MEM), use the -mno-init-stack or
-mendup-at= compiler options, or explicitly use the global ctors/dtors
lists.  Or if you rely on there being symbols like .L__FrameSize_FUNCTION
and .L__FrameOffset_FUNCTION being available.

Please let me know if you have objections to what's described below and
we'll try to find an accommodation.

Background
==========

CRT refers to "C run-time", and means the code that gets executed before and
after main(), in support of language-specific constructs and platform
initialization.  Historically, these routines were defined in msp430-libc.
They've now moved to gcc, decoupling it from msp430-libc so that alternative
libc implementations can be used and ensuring consistency between the
compiler and the runtime system.

How it is in mspgcc4 (which is mostly how it was in mspgcc3):

Before main, the following are executed in a series of linker sections
numbered .init0 through .init9:

_reset_vector__ : Invokes the following in order.  If you override this, the
  rest of the startup is also eliminated unless you put each piece back.

__init_stack : Set the stack pointer to the value of the linker symbol
  __stack, which defaults to top of RAM.

__low_level_init : Disables the watchdog

__do_copy_data : Copies initialized data from ROM to RAM

__do_clear_bss : Zeroes the remainder of RAM

__do_global_ctors : Old-style C++ constructors, calling in turn a series of
  addresses stored between __ctors_start and __ctors_end.

__jump_to_main : Jumps to main

The main routine is treated specially: in its prologue, it resets the stack
pointer (unless -mno-stack-init was given), optionally reserving additional
space with the "reserve" function attribute.  In its epilogue, it jumps to
__stop_progExec__, or the symbol given by the -mendup-at= compiler option,
instead of returning.

The default __stop_progExec__ executes the following in a series of sections
numbered .fini9 to .fini0:

__do_global_dtors : Old-style C++ destructors, calling in turn a series of
  addresses stored between __dtors_start and __dtors_end.

_endless_loop__: Infinite loop to prevent further operation

Each of the symbols described above can be overridden by the user by
re-defining them.

Somewhat related to this, the existing epilogue/prologue code includes
generation of symbols .L__FrameSize_FUNCTION and .L__FrameOffset_FUNCTION,
where "FUNCTION" is replaced by the name of the corresponding function.  The
former value attempts to define the size of the stack frame within the
function; the latter attempts to indicate the position of stack-saved
arguments relative to the stack pointer.

Problems
========

The showstopper that started all this is that, in gcc 4.5.x and higher,
special-casing the prologue/epilogue code for main() prevents generating
debug information with the -g option: the common dwarf2 code in gcc can't
process prologue and epilogue code that contains symbol references (for the
initial stack location) and jumps (to -mendup-at) instead of returns, and
the compiler aborts.

The special-casing where main gets to redefine the stack pointer also
interferes with the environment for C++ constructors that get executed
before main.

The .L__FrameSize_FOO and .L__FrameOffset_FOO values cause problems because
the user believes that they can be used relative to r1 (the stack pointer)
to access data.  In 99% of the common cases, it'll work, which is why people
have gotten away with this for things like GET_FRAME_ADDRESS() and
BIC_SR_IRQ().  In other cases, it won't, and it'll be a bear to figure out
why.  The compiler is perfectly within its rights to temporarily adjust the
stack pointer at various points in the code---e.g., when a statement block
declares a dynamically-sized auto-class array, the user calls alloca(3), or
stack space has to be reserved for function arguments or return values.
None of that is reflected in those compile-time constants.

As a minor irritant, mspgcc is the only msp430 toolchain I know that
immediately disables the watchdog, pretending it doesn't exist.  After
nearly a decade of this the default behavior can't change, but it can at
least be controlled.

Proposed Solution
=================

Most of the existing CRT functions will be retained.  __do_global_ctors and
__do_global_dtors will go away, being replaced by the gcc target-independent
approach to maintain and invoke those function lists.  Users who need
special support for things to be executed before or after main but don't
want to completely replace _reset_vector__ or __stop_progExec__ can put them
into one of the unused init or fini sections.  C++ users won't need to do
anything special.

main() will no longer re-initialize the stack pointer.  That will always be
done by the __init_stack routine.  The -mno-init-stack option goes away.

The "reserve" function attribute, which only had meaning for main, will be
removed.  Space at the top of RAM is reserved by overriding __init_stack.
An example of doing this will be added to the manual.

main() will no longer jump to some arbitrary location instead of returning.
It will return, and having done so will fall-through to the .fini9 section.
Consequently, the -mendup-at= option will be removed.  Override
__stop_progExec__ if you want it to do something else.

.L__FrameSize_FOO and .L__FrameOffset_FOO go away.  Every case I know of
where they might be used has been replaced by built-in functions which the
compiler guarantees will work, regardless of which bizarre combination of
function attributes and code generation options has been chosen.  These
include:

__builtin_frame_pointer : GCC standard builtin
__builtin_return_address : GCC standard builtin
__bi[cs]_sr_irq : adjust the value of the status register in function that
  uses reti to return.

The macros currently defined in msp430-libc's iomacros.h which used to use
these constants will be re-defined in terms of the builtins.  If you have
some other reason why you need those constants, please explain.

A new option -menable-watchdog will be added which change which libcrt0.a
file gets linked in.  The default will be the existing approach that
disables the watchdog on reset; an alternative will leave it enabled (and
ensure it gets kicked at appropriate stages during the initialization).

Caveat
======

Some of what I've described above has been done and validated; some of it is
just a plan.  Details may change as I get into the implementation.

Comments?

Peter

------------------------------------------------------------------------------
Colocation vs. Managed Hosting
A question and answer guide to determining the best fit
for your organization - today and in the future.
http://p.sf.net/sfu/internap-sfd2d
_______________________________________________
Mspgcc-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mspgcc-users

Reply via email to