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>
|
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
|
||||||
|
@ -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}.
|
||||||
|
Reference in New Issue
Block a user