diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -3496,7 +3496,7 @@ } executableSections = std::move(selectedSections); } - + // offset is within the SyntheticSection. size_t offset = 0; size = 0; for (InputSection *isec : executableSections) { @@ -3538,7 +3538,10 @@ dataOffset += 4) write32(buf + offset + dataOffset, read32(d->content().data() + dataOffset)); - target->relocateAlloc(*d, buf + d->outSecOff); + // Recalculate outSecOff as finalizeAddressDependentContent() + // may have altered syntheticSection outSecOff. + d->outSecOff = offset + outSecOff; + target->relocateAlloc(*d, buf + offset); offset += d->getSize(); } else { // A Linker generated CANTUNWIND section. diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -2635,6 +2635,23 @@ OutputSection *first = p->firstSec; OutputSection *last = p->lastSec; + // .ARM.exidx sections may not be within a single .ARM.exidx + // output section. We always want to describe just the + // SyntheticSection. + if (part.armExidx && p->p_type == PT_ARM_EXIDX) { + p->p_filesz = part.armExidx->getSize(); + p->p_memsz = part.armExidx->getSize(); + p->p_offset = first->offset + part.armExidx->outSecOff; + p->p_vaddr = first->addr + part.armExidx->outSecOff; + p->p_align = part.armExidx->addralign; + if (part.elfHeader) + p->p_offset -= part.elfHeader->getParent()->offset; + + if (!p->hasLMA) + p->p_paddr = first->getLMA() + part.armExidx->outSecOff; + return; + } + if (first) { p->p_filesz = last->offset - first->offset; if (last->type != SHT_NOBITS) diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -41,3 +41,9 @@ WebAssembly Improvements ------------------------ +Fixes +##### + +* Arm exception index tables (.ARM.exidx sections) are now ouptut + correctly when they are at a non zero offset within their output + section. (`D148033 `_) diff --git a/lld/test/ELF/arm-exidx-nonzero-offset.s b/lld/test/ELF/arm-exidx-nonzero-offset.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/arm-exidx-nonzero-offset.s @@ -0,0 +1,173 @@ +// 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