* c-arm.texi: Add tutorial on ARM unwinding pseudo ops.

This commit is contained in:
Mark Mitchell
2008-08-26 16:02:59 +00:00
parent 6207416c57
commit 7da4f750f8
2 changed files with 157 additions and 0 deletions

View File

@ -1,3 +1,7 @@
2008-08-26 Mark Mitchell <mark@codesourcery.com>
* c-arm.texi: Add tutorial on ARM unwinding pseudo ops.
2008-08-26 Jie Zhang <jie.zhang@analog.com> 2008-08-26 Jie Zhang <jie.zhang@analog.com>
* config/bfin-parse.y (check_macfunc_option): Fix instruction * config/bfin-parse.y (check_macfunc_option): Fix instruction

View File

@ -23,6 +23,7 @@
* ARM Directives:: ARM Machine Directives * ARM Directives:: ARM Machine Directives
* ARM Opcodes:: Opcodes * ARM Opcodes:: Opcodes
* ARM Mapping Symbols:: Mapping Symbols * ARM Mapping Symbols:: Mapping Symbols
* ARM Unwinding Tutorial:: Unwinding
@end menu @end menu
@node ARM Options @node ARM Options
@ -502,10 +503,12 @@ it prevents accurate control of the placement of literal pools.
@item .pool @item .pool
This is a synonym for .ltorg. This is a synonym for .ltorg.
@anchor{arm_fnstart}
@cindex @code{.fnstart} directive, ARM @cindex @code{.fnstart} directive, ARM
@item .fnstart @item .fnstart
Marks the start of a function with an unwind table entry. Marks the start of a function with an unwind table entry.
@anchor{arm_fnend}
@cindex @code{.fnend} directive, ARM @cindex @code{.fnend} directive, ARM
@item .fnend @item .fnend
Marks the end of a function with an unwind table entry. The unwind index Marks the end of a function with an unwind table entry. The unwind index
@ -538,6 +541,7 @@ entry for that function. Anything between this directive and the
Must be preceded by a @code{.personality} or @code{.personalityindex} Must be preceded by a @code{.personality} or @code{.personalityindex}
directive. directive.
@anchor{arm_save}
@cindex @code{.save} directive, ARM @cindex @code{.save} directive, ARM
@item .save @var{reglist} @item .save @var{reglist}
Generate unwinder annotations to restore the registers in @var{reglist}. Generate unwinder annotations to restore the registers in @var{reglist}.
@ -585,18 +589,21 @@ instruction.
Since FLDMX and FSTMX are now deprecated, this directive should be Since FLDMX and FSTMX are now deprecated, this directive should be
used in favour of @code{.save} for saving VFP registers for ARMv6 and above. used in favour of @code{.save} for saving VFP registers for ARMv6 and above.
@anchor{arm_pad}
@cindex @code{.pad} directive, ARM @cindex @code{.pad} directive, ARM
@item .pad #@var{count} @item .pad #@var{count}
Generate unwinder annotations for a stack adjustment of @var{count} bytes. Generate unwinder annotations for a stack adjustment of @var{count} bytes.
A positive value indicates the function prologue allocated stack space by A positive value indicates the function prologue allocated stack space by
decrementing the stack pointer. decrementing the stack pointer.
@anchor{arm_movsp}
@cindex @code{.movsp} directive, ARM @cindex @code{.movsp} directive, ARM
@item .movsp @var{reg} [, #@var{offset}] @item .movsp @var{reg} [, #@var{offset}]
Tell the unwinder that @var{reg} contains an offset from the current Tell the unwinder that @var{reg} contains an offset from the current
stack pointer. If @var{offset} is not specified then it is assumed to be stack pointer. If @var{offset} is not specified then it is assumed to be
zero. zero.
@anchor{arm_setfp}
@cindex @code{.setfp} directive, ARM @cindex @code{.setfp} directive, ARM
@item .setfp @var{fpreg}, @var{spreg} [, #@var{offset}] @item .setfp @var{fpreg}, @var{spreg} [, #@var{offset}]
Make all unwinder annotations relaive to a frame pointer. Without this Make all unwinder annotations relaive to a frame pointer. Without this
@ -747,3 +754,149 @@ specification is not implemented. This is because they have been
dropped from the new EABI and so tools cannot rely upon their dropped from the new EABI and so tools cannot rely upon their
presence. presence.
@node ARM Unwinding Tutorial
@section Unwinding
The ABI for the ARM Architecture specifies a standard format for
exception unwind information. This information is used when an
exception is thrown to determine where control should be transferred.
In particular, the unwind information is used to determine which
function called the function that threw the exception, and which
function called that one, and so forth. This information is also used
to restore the values of callee-saved registers in the function
catching the exception.
If you are writing functions in assembly code, and those functions
call other functions that throw exceptions, you must use assembly
pseudo ops to ensure that appropriate exception unwind information is
generated. Otherwise, if one of the functions called by your assembly
code throws an exception, the run-time library will be unable to
unwind the stack through your assembly code and your program will not
behave correctly.
To illustrate the use of these pseudo ops, we will examine the code
that G++ generates for the following C++ input:
@verbatim
void callee (int *);
int
caller ()
{
int i;
callee (&i);
return i;
}
@end verbatim
This example does not show how to throw or catch an exception from
assembly code. That is a much more complex operation and should
always be done in a high-level language, such as C++, that directly
supports exceptions.
The code generated by one particular version of G++ when compiling the
example above is:
@verbatim
_Z6callerv:
.fnstart
.LFB2:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
stmfd sp!, {fp, lr}
.save {fp, lr}
.LCFI0:
.setfp fp, sp, #4
add fp, sp, #4
.LCFI1:
.pad #8
sub sp, sp, #8
.LCFI2:
sub r3, fp, #8
mov r0, r3
bl _Z6calleePi
ldr r3, [fp, #-8]
mov r0, r3
sub sp, fp, #4
ldmfd sp!, {fp, lr}
bx lr
.LFE2:
.fnend
@end verbatim
Of course, the sequence of instructions varies based on the options
you pass to GCC and on the version of GCC in use. The exact
instructions are not important since we are focusing on the pseudo ops
that are used to generate unwind information.
An important assumption made by the unwinder is that the stack frame
does not change during the body of the function. In particular, since
we assume that the assembly code does not itself throw an exception,
the only point where an exception can be thrown is from a call, such
as the @code{bl} instruction above. At each call site, the same saved
registers (including @code{lr}, which indicates the return address)
must be located in the same locations relative to the frame pointer.
The @code{.fnstart} (@pxref{arm_fnstart,,.fnstart pseudo op}) pseudo
op appears immediately before the first instruction of the function
while the @code{.fnend} (@pxref{arm_fnend,,.fnend pseudo op}) pseudo
op appears immediately after the last instruction of the function.
These pseudo ops specify the range of the function.
Only the order of the other pseudos ops (e.g., @code{.setfp} or
@code{.pad}) matters; their exact locations are irrelevant. In the
example above, the compiler emits the pseudo ops with particular
instructions. That makes it easier to understand the code, but it is
not required for correctness. It would work just as well to emit all
of the pseudo ops other than @code{.fnend} in the same order, but
immediately after @code{.fnstart}.
The @code{.save} (@pxref{arm_save,,.save pseudo op}) pseudo op
indicates registers that have been saved to the stack so that they can
be restored before the function returns. The argument to the
@code{.save} pseudo op is a list of registers to save. If a register
is ``callee-saved'' (as specified by the ABI) and is modified by the
function you are writing, then your code must save the value before it
is modified and restore the original value before the function
returns. If an exception is thrown, the run-time library restores the
values of these registers from their locations on the stack before
returning control to the exception handler. (Of course, if an
exception is not thrown, the function that contains the @code{.save}
pseudo op restores these registers in the function epilogue, as is
done with the @code{ldmfd} instruction above.)
You do not have to save callee-saved registers at the very beginning
of the function and you do not need to use the @code{.save} pseudo op
immediately following the point at which the registers are saved.
However, if you modify a callee-saved register, you must save it on
the stack before modifying it and before calling any functions which
might throw an exception. And, you must use the @code{.save} pseudo
op to indicate that you have done so.
The @code{.pad} (@pxref{arm_pad,,.pad}) pseudo op indicates a
modification of the stack pointer that does not save any registers.
The argument is the number of bytes (in decimal) that are subtracted
from the stack pointer. (On ARM CPUs, the stack grows downwards, so
subtracting from the stack pointer increases the size of the stack.)
The @code{.setfp} (@pxref{arm_setfp,,.setfp pseudo op}) pseudo op
indicates the register that contains the frame pointer. The first
argument is the register that is set, which is typically @code{fp}.
The second argument indicates the register from which the frame
pointer takes its value. The third argument, if present, is the value
(in decimal) added to the register specified by the second argument to
compute the value of the frame pointer. You should not modify the
frame pointer in the body of the function.
If you do not use a frame pointer, then you should not use the
@code{.setfp} pseudo op. If you do not use a frame pointer, then you
should avoid modifying the stack pointer outside of the function
prologue. Otherwise, the run-time library will be unable to find
saved registers when it is unwinding the stack.
The pseudo ops described above are sufficient for writing assembly
code that calls functions which may throw exceptions. If you need to
know more about the object-file format used to represent unwind
information, you may consult the @cite{Exception Handling ABI for the
ARM Architecture} available from @uref{http://infocenter.arm.com}.