Observed in binutils CVS 20111121 Host: x86_64-linux-gnu Target: arm-elf-eabi (the host should not really matter, and any ARM target should show the same behaviour) Readelf's unwind table dumping implementation for ARM appears to make incorrect assumptions which mean that readelf -u only generates valid output for fully linked objects (ET_EXEC/ET_DYN). The reason seems to be that the implementation attempts to convert relocated unwind table information to absolute address offsets prematutely: this works when all loadable sections share a common addressing origin (as for fully linked objects) but not when each section has an independent origin (as for ET_REL). This appears to cause the location of both the function body and the unwind opcodes to be miscalculated. The erroneous code is in the following functions in binutils/readelf.c: dump_arm_unwind () arm_section_get_word () arm_print_vma_and_name () To fix this, the code should not be fully applying the R_ARM_PREL31 relocations at all, since cross-section relocations cannot be applied without a common addressing origin. Instead, a {section,address} pair should be generated by applying the relocation addend to the target symbol's {section,address} pair, with the resultant pair used for locating the unwind opcodes and function symbol. Consider refactoring the code when resolving this: the resulting code should hopefully be simpler than the current code, since it would need to do less relocation processing. Testcase: $ cat <<EOF >unwind.txt .type f1,%function f1: .fnstart stmfd sp!, {r0-r12,lr} .save {r0-r12,lr} bl foo ldmfd sp!, {r0-r12,pc} .fnend .size f1,.-f1 .type f2,%function f2: .fnstart stmfd sp!, {r12,lr} .save {r12,lr} stmfd sp!, {r0-r3} .save {r0-r3} bl foo ldmfd sp!, {r0-r3,r12,pc} .fnend .size f2,.-f2 .type f3,%function f3: .fnstart stmfd sp!,{r0,lr} .save {r0,lr} bl foo ldmfd sp!,{r0,pc} .fnend .size f3,.-f3 .type f4,%function f4: .fnstart stmfd sp!,{r1,lr} .save {r1,lr} bl foo ldmfd sp!,{r1,pc} .fnend .size f4,.-f4 .type f5,%function f5: .fnstart stmfd sp!,{r2,lr} .save {r2,lr} bl foo ldmfd sp!,{r2,pc} .fnend .size f5,.-f5 .type f6,%function f6: .fnstart stmfd sp!,{r3,lr} .save {r3,lr} bl foo ldmfd sp!,{r3,pc} .fnend .size f6,.-f6 EOF $ as -o unwind.o unwind.s $ readelf -u unwind.o Unwind table index '.ARM.exidx' at offset 0xc8 contains 6 entries: 0x0: @0x0 Compact model 1 0xb1 0x0f pop {r0, r1, r2, r3} 0x85 0xff pop {r4, r5, r6, r7, r8, r9, r10, r11, r12, r14} 0xb0 finish 0xb0 finish 0x0: @0x0 Compact model 1 0xb1 0x0f pop {r0, r1, r2, r3} 0x85 0xff pop {r4, r5, r6, r7, r8, r9, r10, r11, r12, r14} 0xb0 finish 0xb0 finish 0x0: @0x0 Compact model 1 0xb1 0x0f pop {r0, r1, r2, r3} 0x85 0xff pop {r4, r5, r6, r7, r8, r9, r10, r11, r12, r14} 0xb0 finish 0xb0 finish 0x0: @0x0 Compact model 1 0xb1 0x0f pop {r0, r1, r2, r3} 0x85 0xff pop {r4, r5, r6, r7, r8, r9, r10, r11, r12, r14} 0xb0 finish 0xb0 finish 0x0: @0x0 Compact model 1 0xb1 0x0f pop {r0, r1, r2, r3} 0x85 0xff pop {r4, r5, r6, r7, r8, r9, r10, r11, r12, r14} 0xb0 finish 0xb0 finish 0x0: @0x0 Compact model 1 0xb1 0x0f pop {r0, r1, r2, r3} 0x85 0xff pop {r4, r5, r6, r7, r8, r9, r10, r11, r12, r14} 0xb0 finish 0xb0 finish # Linking the .o file allows us to get valid output: $ ld -shared -o unwind unwind.o $ readelf -u unwind Unwind table index '.ARM.exidx' at offset 0x2b8 contains 7 entries: 0x224 <f1>: @0x270 Compact model 1 0xb1 0x0f pop {r0, r1, r2, r3} 0x85 0xff pop {r4, r5, r6, r7, r8, r9, r10, r11, r12, r14} 0xb0 finish 0xb0 finish 0x230 <f2>: @0x27c Compact model 1 0xb1 0x0f pop {r0, r1, r2, r3} 0x85 0x00 pop {r12, r14} 0xb0 finish 0xb0 finish 0x240 <f3>: @0x288 Compact model 1 0xb1 0x01 pop {r0} 0x84 0x00 pop {r14} 0xb0 finish 0xb0 finish 0x24c <f4>: @0x294 Compact model 1 0xb1 0x02 pop {r1} 0x84 0x00 pop {r14} 0xb0 finish 0xb0 finish 0x258 <f5>: @0x2a0 Compact model 1 0xb1 0x04 pop {r2} 0x84 0x00 pop {r14} 0xb0 finish 0xb0 finish 0x264 <f6>: @0x2ac Compact model 1 0xb1 0x08 pop {r3} 0x84 0x00 pop {r14} 0xb0 finish 0xb0 finish 0x270 <f6+0xc>: 0x1 [cantunwind]
Created attachment 6075 [details] Proposed fix
Hi Dave, > Instead, a {section,address} pair should be generated by > applying the relocation addend to the target symbol's > {section,address} pair, with the resultant pair used > for locating the unwind opcodes and function symbol. Actually this is being done already - it is just that the code that did this was broken... Please try out the uploaded patch and let me know what you think. The patch includes a lot of formatting and coding tidy-ups, (although not the full code refactoring that you suggested), so it may be hard to find the real changes. The fixes are as follows: 1. Correctly initialize the rel_type field in the arm_section structure. 2. When displaying the function name, use the computed function section/offset abdaddr structure, not the entry absaddr structure. Cheers Nick
On Fri, Nov 25, 2011 at 02:16:56PM +0000, nickc at redhat dot com wrote: > http://sourceware.org/bugzilla/show_bug.cgi?id=13421 > > Nick Clifton <nickc at redhat dot com> changed: > > What |Removed |Added > ---------------------------------------------------------------------------- > Status|NEW |WAITING > CC| |nickc at redhat dot com > > --- Comment #2 from Nick Clifton <nickc at redhat dot com> 2011-11-25 14:16:56 UTC --- > Hi Dave, > > > Instead, a {section,address} pair should be generated by > > applying the relocation addend to the target symbol's > > {section,address} pair, with the resultant pair used > > for locating the unwind opcodes and function symbol. > > Actually this is being done already - it is just that the code that did this > was broken... > > Please try out the uploaded patch and let me know what you think. > > The patch includes a lot of formatting and coding tidy-ups, (although not the > full code refactoring that you suggested), so it may be hard to find the real > changes. The fixes are as follows: > > 1. Correctly initialize the rel_type field in the arm_section structure. > > 2. When displaying the function name, use the computed function > section/offset abdaddr structure, not the entry absaddr structure. I guess I don't have a strong opinion on the code -- the fix appears to work, so I'm happy. Thanks for the quick response! Cheers ---Dave
CVSROOT: /cvs/src Module name: src Changes by: nickc@sourceware.org 2011-11-28 16:51:10 Modified files: binutils : ChangeLog readelf.c Log message: PR binutils/13421 * readelf.c (arm_section_get_word): Add descriptive comments. Initliase the rel_type field of the arm_sec structure. (expand_prel31): Rename to arm_expand_prel31. (dump_arm_unwind): Use new name. Print the function name based on the function address entry. Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/src/binutils/ChangeLog.diff?cvsroot=src&r1=1.1853&r2=1.1854 http://sourceware.org/cgi-bin/cvsweb.cgi/src/binutils/readelf.c.diff?cvsroot=src&r1=1.561&r2=1.562
Patch applied.