| // REQUIRES: arm |
| // RUN: rm -rf %t && split-file %s %t |
| |
| // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi --arm-add-build-attributes %t/a.s -o %t/a.o |
| // RUN: ld.lld %t/a.o -T %t/exidx-non-zero-offset.t -o %t/non-zero |
| // RUN: llvm-readelf --program-headers --unwind --symbols -x .exceptions %t/non-zero | FileCheck %s |
| // RUN: ld.lld %t/a.o -T %t/exidx-zero-offset.t -o %t/zero |
| // RUN: llvm-readelf --program-headers --unwind --symbols -x .exceptions %t/zero | FileCheck %s |
| |
| /// On platforms that load ELF files directly the ARM.exidx sections |
| /// are located with the PT_ARM_EXIDX program header. This requires |
| /// all .ARM.exidx input sections to be placed in a single |
| /// .ARM.exidx output section. Embedded systems that do not load |
| /// from an ELF file use the linker defined symbols __exidx_start and |
| /// __exidx_stop. There is no requirement to place the .ARM.exidx |
| /// input sections in their own output section. This test case checks |
| /// that a .ARM.exidx synthetic section that isn't at a zero offset |
| /// within the output section gets the correct offsets. We check |
| /// this by checking that equal amounts of alignment padding |
| /// inserted before and after the section start produce the same |
| /// results. |
| |
| /// For the two linker scripts, one with the .ARM.exidx table |
| /// at a zero offset within its output section and one with a |
| /// non-zero offset, but both at the same file and address; |
| /// the PT_ARM_EXIDX, symbols and table contents should be the |
| /// same. |
| // CHECK: EXIDX 0x010080 0x00000080 0x00000080 0x00028 0x00028 R 0x4 |
| |
| /// unwind entries starting from the right address are identical. |
| /// llvm-readelf does not seem to be able to detect Thumb functionNames |
| /// whereas arm-none-eabi-readelf can. Used CHECK rather than CHECK-NEXT |
| /// to cope with possible improvements llvm-readelf. |
| // CHECK: FunctionAddress: 0x0 |
| // CHECK-NEXT: FunctionName: f1 |
| // CHECK-NEXT: Model: Compact (Inline) |
| // CHECK-NEXT: PersonalityIndex: 0 |
| // CHECK-NEXT: Opcodes [ |
| // CHECK-NEXT: 0x97 ; vsp = r7 |
| // CHECK-NEXT: 0x84 0x08 ; pop {r7, lr} |
| // CHECK-NEXT: ] |
| // CHECK-NEXT: } |
| // CHECK-NEXT: Entry { |
| // CHECK-NEXT: FunctionAddress: 0x8 |
| // CHECK-NEXT: FunctionName: f2 |
| // CHECK-NEXT: Model: CantUnwind |
| // CHECK-NEXT: } |
| // CHECK-NEXT: Entry { |
| // CHECK-NEXT: FunctionAddress: 0xE |
| // CHECK: ExceptionHandlingTable: .ARM.extab |
| // CHECK-NEXT: TableEntryAddress: 0xA8 |
| // CHECK-NEXT: Model: Generic |
| // CHECK-NEXT: PersonalityRoutineAddress: 0x12 |
| // CHECK-NEXT: } |
| // CHECK-NEXT: Entry { |
| // CHECK-NEXT: FunctionAddress: 0x10 |
| // CHECK: Model: CantUnwind |
| // CHECK-NEXT: } |
| // CHECK-NEXT: Entry { |
| // CHECK-NEXT: FunctionAddress: 0x14 |
| // CHECK-NEXT: FunctionName: __ARMv7ABSLongThunk_f3 |
| // CHECK-NEXT: Model: CantUnwind |
| // CHECK-NEXT: } |
| |
| // CHECK: {{[0-9]+}}: 00000080 {{.*}} __exidx_start |
| // CHECK-NEXT: {{[0-9]+}}: 000000a8 {{.*}} __exidx_end |
| |
| // CHECK: 0x00000080 80ffff7f 08849780 80ffff7f 01000000 |
| // CHECK-NEXT: 0x00000090 7effff7f 14000000 78ffff7f 01000000 |
| // CHECK-NEXT: 0x000000a0 74ffff7f 01000000 |
| |
| //--- exidx-non-zero-offset.t |
| SECTIONS { |
| .text : { *(.text .text.*) } |
| /* Addition of thunk in .text changes alignment padding */ |
| .exceptions : { |
| /* Alignment padding within .exceptions */ |
| . = ALIGN(128); |
| /* Embedded C libraries find exceptions via linker defined |
| symbols */ |
| __exidx_start = .; |
| *(.ARM.exidx) ; |
| __exidx_end = .; |
| } |
| .ARM.extab : { *(.ARM.extab .ARM.extab.*) } |
| } |
| |
| //--- exidx-zero-offset.t |
| SECTIONS { |
| .text : { *(.text .text.*) } |
| /* Addition of thunk in .text changes alignment padding */ |
| /* alignment padding before .exceptions starts */ |
| .exceptions : ALIGN(128) { |
| /* Embedded C libraries find exceptions via linker defined |
| symbols */ |
| __exidx_start = .; |
| *(.ARM.exidx) ; |
| __exidx_end = .; |
| } |
| .ARM.extab : { *(.ARM.extab .ARM.extab.*) } |
| } |
| |
| //--- a.s |
| .syntax unified |
| |
| /// Expect inline unwind instructions. |
| .section .text.01, "ax", %progbits |
| .arm |
| .balign 4 |
| .global f1 |
| .type f1, %function |
| f1: |
| .fnstart |
| /// provoke an interworking thunk. |
| b f3 |
| bx lr |
| .save {r7, lr} |
| .setfp r7, sp, #0 |
| .fnend |
| |
| /// Expect no unwind information from assembler. The linker must |
| /// synthesise an EXIDX_CANTUNWIND entry to prevent an exception |
| /// thrown through f2 from matching against the unwind instructions |
| /// for f1. |
| .section .text.02, "ax", %progbits |
| .global f2 |
| .type f2, %function |
| .balign 4 |
| f2: |
| bx lr |
| |
| /// Expect 1 EXIDX_CANTUNWIND entry that can be merged into the linker |
| /// generated EXIDX_CANTUNWIND as if the assembler had generated it. |
| .section .text.03, "ax",%progbits |
| .global f3 |
| .type f3, %function |
| .thumb |
| .balign 2 |
| f3: |
| .fnstart |
| bx lr |
| .cantunwind |
| .fnend |
| |
| /// Expect a section with a reference to an .ARM.extab. |
| .section .text.04, "ax",%progbits |
| .global f4 |
| .balign 2 |
| .type f4, %function |
| f4: |
| .fnstart |
| bx lr |
| .personality __gxx_personality_v0 |
| .handlerdata |
| .long 0 |
| .fnend |
| |
| |
| /// Dummy implementation of personality routines to satisfy reference |
| /// from exception tables, linker will generate EXIDX_CANTUNWIND. |
| .section .text.__aeabi_unwind_cpp_pr0, "ax", %progbits |
| .global __aeabi_unwind_cpp_pr0 |
| .type __aeabi_unwind_cpp_pr0, %function |
| .balign 2 |
| __aeabi_unwind_cpp_pr0: |
| bx lr |
| |
| .section .text.__gcc_personality_v0, "ax", %progbits |
| .global __gxx_personality_v0 |
| .type __gcc_personality_v0, %function |
| .balign 2 |
| __gxx_personality_v0: |
| bx lr |