This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
[RFC] Arm frame unwinding directives.
- From: Paul Brook <paul at codesourcery dot com>
- To: binutils at sources dot redhat dot com
- Cc: Richard Earnshaw <rearnsha at arm dot com>
- Date: Tue, 22 Jun 2004 17:03:09 +0100
- Subject: [RFC] Arm frame unwinding directives.
- Organization: CodeSourcery
I'm currently working on implementing EABI compliant exception handling/frame
unwinding for arm targets. This involves generating frame unwind tables.
My current thinking is that the best way to generate these is via assembly
directives embedded in the function code. This has some advantages over
generating raw data tables in the compiler:
- It allows easy annotation of hand-written assembly code.
- It simplifies the compiler.
- Maybe allows the assembler to pick an appropriate personality routine/format
based on the function size.
A similar technique is used by ia64 targets.
I propose to add the following directives, encoding the unwinding actions
described below.
.unwind_fnstart
Marks the start of a function.
.unwind_fnend
Marks the end of a function. All other unwind directives should be enclosed
within a fnend/fnstart pair.
.unwind_pad #<imm>
The stack pointer should be incremented by <imm> bytes.
.unwind_save <reglist>
The registers in <reglist> should be popped from the stack. The format of
<reglist> is that same as used by store multiple instructions, eg {r4, lr}.
.unwind_movsp <reg>
Copy <reg> to the stack pointer.
.unwind_setfp <reg1>, <reg2>[, #<imm>]
The stack pointer should be set based on the value of frame pointer <reg1>.
The frame pointer will have been initialized by the instruction
sub <reg1>, <reg2>, #<imm>
<reg2> must be either <sp> or the subject of a .unwind_movsp directive. #<imm>
may be ommitted, in which case it is assumed to be zero.
This directive implies that sp may be changed within the function, so must be
restored before unwinding. Otherwise it is assumed that sp is constant
througout the funcion body. The assembler will adjust the offset as
appropriate based on the positioning of other unwind directives.
.unwind_handlerdata
The exception handling table data for this function follows this directive. It
will be terminated by a .unwind_fnend directive.
I'll also want to add directives for restoring coprocessor registers, and
maybe for generaing the contents of the exception handling table.
Does this seem reasonable? I've only just started implementing this, so any
comments/suggestions are more than welcome.
A couple of examples of how these would be used:
void bar(void);
int
foo (int a)
{
bar();
return a;
}
Compiles to:
.text
.align 2
.global _Z3fooi
.type _Z3fooi, %function
_Z3fooi:
.LFB2:
.unwind_fnbegin
.unwind_save {r4, lr}
stmfd sp!, {r4, lr}
mov r4, r0
bl _Z3barv
mov r0, r4
ldmfd sp!, {r4, pc}
@ .unwind_handlerdata would go here
.unwind_fnend
.size _Z3fooi, .-_Z3fooi
And generates unwid opcodes as follows:
POP {r4, lr}
Or, with -fno-omit-frame-pointer:
.text
.align 2
.global _Z3fooi
.type _Z3fooi, %function
_Z3fooi:
.LFB2:
.unwind_fnbegin
.unwind_movsp ip
mov ip, sp
.unwind_pad 4
.unwind_save {r4, fp, ip, lr}
stmfd sp!, {r4, fp, ip, lr, pc}
.unwind_setfp fp, ip, #4
sub fp, ip, #4
mov r4, r0
bl _Z3barv
@ code here could change sp, eg. by calling alloca
mov r0, r4
ldmfd sp, {r4, fp, sp, pc}
.unwind_fnend
.size _Z3fooi, .-_Z3fooi
And generates unwind opcodes as folows:
sp = fp - 16 /* 20 bytes pushed, and fp=original_sp-4 */
POP {r4, fp, ip, lr}
sp += 4 /* not needed, so maybe don't output this. */
sp = ip
Paul