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
@@ -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)
Index: lld/docs/ReleaseNotes.rst
===================================================================
--- lld/docs/ReleaseNotes.rst
+++ 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 <https://reviews.llvm.org/D148033>`_)
Index: lld/test/ELF/arm-exidx-nonzero-offset.s
===================================================================
--- /dev/null
+++ 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