mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-27 22:48:57 +08:00
* c-arm.texi: Add tutorial on ARM unwinding pseudo ops.
This commit is contained in:
@ -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>
|
||||
|
||||
* config/bfin-parse.y (check_macfunc_option): Fix instruction
|
||||
|
@ -23,6 +23,7 @@
|
||||
* ARM Directives:: ARM Machine Directives
|
||||
* ARM Opcodes:: Opcodes
|
||||
* ARM Mapping Symbols:: Mapping Symbols
|
||||
* ARM Unwinding Tutorial:: Unwinding
|
||||
@end menu
|
||||
|
||||
@node ARM Options
|
||||
@ -502,10 +503,12 @@ it prevents accurate control of the placement of literal pools.
|
||||
@item .pool
|
||||
This is a synonym for .ltorg.
|
||||
|
||||
@anchor{arm_fnstart}
|
||||
@cindex @code{.fnstart} directive, ARM
|
||||
@item .fnstart
|
||||
Marks the start of a function with an unwind table entry.
|
||||
|
||||
@anchor{arm_fnend}
|
||||
@cindex @code{.fnend} directive, ARM
|
||||
@item .fnend
|
||||
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}
|
||||
directive.
|
||||
|
||||
@anchor{arm_save}
|
||||
@cindex @code{.save} directive, ARM
|
||||
@item .save @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
|
||||
used in favour of @code{.save} for saving VFP registers for ARMv6 and above.
|
||||
|
||||
@anchor{arm_pad}
|
||||
@cindex @code{.pad} directive, ARM
|
||||
@item .pad #@var{count}
|
||||
Generate unwinder annotations for a stack adjustment of @var{count} bytes.
|
||||
A positive value indicates the function prologue allocated stack space by
|
||||
decrementing the stack pointer.
|
||||
|
||||
@anchor{arm_movsp}
|
||||
@cindex @code{.movsp} directive, ARM
|
||||
@item .movsp @var{reg} [, #@var{offset}]
|
||||
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
|
||||
zero.
|
||||
|
||||
@anchor{arm_setfp}
|
||||
@cindex @code{.setfp} directive, ARM
|
||||
@item .setfp @var{fpreg}, @var{spreg} [, #@var{offset}]
|
||||
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
|
||||
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}.
|
||||
|
Reference in New Issue
Block a user