This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFA: ARM unwinding tutorial


Nick Clifton wrote:

>> This patch adds some tutorial to the GAS manual explaining how to use
>> some of the ARM unwinding pseudo ops from hand-written assembly code.
>> The intent is to enable users who need to write assembly code that
>> calls functions which might throw exceptions.  Paul Brook has reviewed
>> the documentation for accuracy.
>>
>> OK to apply?
> 
> Approved - please apply.

> Just a suggestion - I like to follow the GNU Coding conventions in
> example pieces of code in the documentation.  It makes everything
> consistent.

Thanks, committed.  I made the GNU Coding Conventions change, and I also
took the liberty of adding a paragraph (following an offlist suggestion)
to explain the lack of constraint on the location of these directives:

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}.

Here's the version I've committed.  Please let me know if there's any
problem with me adding this additional paragraph.

Thanks,

-- 
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
Index: doc/c-arm.texi
===================================================================
RCS file: /cvs/src/src/gas/doc/c-arm.texi,v
retrieving revision 1.51
diff -c -5 -p -r1.51 c-arm.texi
*** doc/c-arm.texi	21 May 2008 08:20:17 -0000	1.51
--- doc/c-arm.texi	26 Aug 2008 15:57:05 -0000
***************
*** 21,30 ****
--- 21,31 ----
  * ARM Syntax::               Syntax
  * ARM Floating Point::       Floating Point
  * ARM Directives::           ARM Machine Directives
  * ARM Opcodes::              Opcodes
  * ARM Mapping Symbols::      Mapping Symbols
+ * ARM Unwinding Tutorial::   Unwinding
  @end menu
  
  @node ARM Options
  @section Options
  @cindex ARM options (none)
*************** it prevents accurate control of the plac
*** 500,513 ****
--- 501,516 ----
  
  @cindex @code{.pool} directive, ARM
  @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
  table entry is created when this directive is processed.
  
*************** entry for that function.  Anything betwe
*** 536,545 ****
--- 539,549 ----
  @code{.fnend} directive will be added to the exception table entry.
  
  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}.
  The format of @var{reglist} is the same as the corresponding store-multiple
  instruction.
*************** instruction.
*** 583,604 ****
--- 587,611 ----
  @end smallexample
  
  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
  the unwinder will use offsets from the stack pointer.
  
*************** is no need to code them yourself.  Suppo
*** 745,749 ****
--- 752,902 ----
  $f, $p and $m) which is also mentioned in the current ARM ELF
  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}.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]