From 7da4f750f81ddb655fe4b96f779b70f6086c2aa4 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Tue, 26 Aug 2008 16:02:59 +0000 Subject: [PATCH] * c-arm.texi: Add tutorial on ARM unwinding pseudo ops. --- gas/ChangeLog | 4 ++ gas/doc/c-arm.texi | 153 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) diff --git a/gas/ChangeLog b/gas/ChangeLog index ca0e411c359..ebf6828a29c 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,7 @@ +2008-08-26 Mark Mitchell + + * c-arm.texi: Add tutorial on ARM unwinding pseudo ops. + 2008-08-26 Jie Zhang * config/bfin-parse.y (check_macfunc_option): Fix instruction diff --git a/gas/doc/c-arm.texi b/gas/doc/c-arm.texi index 6c027bdae52..9e698b0c377 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}. -- 2.30.2