This is the mail archive of the binutils@sources.redhat.com 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]

[RFC] Arm frame unwinding directives.


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


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