Index: lld/ELF/SyntheticSections.cpp =================================================================== --- lld/ELF/SyntheticSections.cpp +++ 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. Index: lld/ELF/Writer.cpp =================================================================== --- lld/ELF/Writer.cpp +++ lld/ELF/Writer.cpp @@ -2625,6 +2625,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 (config->emachine == EM_ARM && 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) Index: lld/test/ELF/arm-exidx-nonzero-offset.s =================================================================== --- /dev/null +++ lld/test/ELF/arm-exidx-nonzero-offset.s @@ -0,0 +1,130 @@ +// 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 --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 --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. + +/// PT_ARM_EXIDX program header should be identical. +// CHECK: EXIDX 0x010080 0x00000080 0x00000080 0x00028 0x00028 R 0x4 + +// 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 +.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 +.balign 4 +__aeabi_unwind_cpp_pr0: +bx lr + +.section .text.__gcc_personality_v0, "ax", %progbits +.global __gxx_personality_v0 +__gxx_personality_v0: +bx lr