summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2008-08-26 16:02:59 +0000
committerMark Mitchell <mark@codesourcery.com>2008-08-26 16:02:59 +0000
commit3a57e45938a922786e1f535242c0b882155d5dfa (patch)
treecc04f87863122832266683fc8f2c7bed39cb2ba6
parent8a5701fc764c30c6c27daaaec68d3b0348edac43 (diff)
downloadbinutils-redhat-3a57e45938a922786e1f535242c0b882155d5dfa.tar.gz
* c-arm.texi: Add tutorial on ARM unwinding pseudo ops.
-rw-r--r--gas/ChangeLog4
-rw-r--r--gas/doc/c-arm.texi153
2 files changed, 157 insertions, 0 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index ca0e411c35..ebf6828a29 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -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
diff --git a/gas/doc/c-arm.texi b/gas/doc/c-arm.texi
index 6c027bdae5..9e698b0c37 100644
--- a/gas/doc/c-arm.texi
+++ b/gas/doc/c-arm.texi
@@ -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}.