[lld] [llvm] Add initial support for Xtensa to LLD (PR #202926)

Alexey Gerenkov via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 25 02:52:38 PDT 2026


https://github.com/gerekon updated https://github.com/llvm/llvm-project/pull/202926

>From 302c52109b26bd596fd0c0899f201eecf1f5af99 Mon Sep 17 00:00:00 2001
From: Alexey Gerenkov <alexey at espressif.com>
Date: Fri, 25 Sep 2026 12:52:09 +0300
Subject: [PATCH 1/2] [Xtensa] Add ELF relocation types for linker support

Add R_XTENSA_PDIFF{8,16,32}, R_XTENSA_NDIFF{8,16,32},
R_XTENSA_PDIFF_ULEB128, and R_XTENSA_32_ABS. Have the Xtensa MC
object writer emit R_XTENSA_32_ABS for absolute data relocations so
LLVM objects use r_addend rather than GNU partial_inplace R_XTENSA_32.

Co-authored-by: Cursor <cursoragent at cursor.com>
---
 .../llvm/BinaryFormat/ELFRelocs/Xtensa.def    | 13 ++++++++++
 .../MCTargetDesc/XtensaELFObjectWriter.cpp    |  2 +-
 llvm/test/MC/Xtensa/Relocations/relocations.s |  2 +-
 .../llvm-readobj/ELF/reloc-types-xtensa.test  | 24 +++++++++++++++++++
 4 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/Xtensa.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/Xtensa.def
index 6791a842181ff..9c3e5dc15af64 100644
--- a/llvm/include/llvm/BinaryFormat/ELFRelocs/Xtensa.def
+++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/Xtensa.def
@@ -58,3 +58,16 @@ ELF_RELOC(R_XTENSA_TLS_TPOFF,        53)
 ELF_RELOC(R_XTENSA_TLS_FUNC,         54)
 ELF_RELOC(R_XTENSA_TLS_ARG,          55)
 ELF_RELOC(R_XTENSA_TLS_CALL,         56)
+ELF_RELOC(R_XTENSA_PDIFF8,           57)
+ELF_RELOC(R_XTENSA_PDIFF16,          58)
+ELF_RELOC(R_XTENSA_PDIFF32,          59)
+ELF_RELOC(R_XTENSA_NDIFF8,           60)
+ELF_RELOC(R_XTENSA_NDIFF16,          61)
+ELF_RELOC(R_XTENSA_NDIFF32,          62)
+// Positive same-section difference encoded as uleb128; rewritten in
+// place after relaxation without changing the section size.
+ELF_RELOC(R_XTENSA_PDIFF_ULEB128,    63)
+// Absolute 32-bit relocation with the addend in r_addend (same computation
+// as a standard R_XTENSA_32 S + A). Distinct from GNU R_XTENSA_32, which
+// stores the addend in the relocated word (partial_inplace).
+ELF_RELOC(R_XTENSA_32_ABS,    64)
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp
index e2b1c5683d50b..32f4fb8be0f1e 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp
@@ -51,7 +51,7 @@ unsigned XtensaObjectWriter::getRelocType(const MCFixup &Fixup,
   switch ((unsigned)Fixup.getKind()) {
   case FK_Data_4:
     return Specifier == Xtensa::S_TPOFF ? ELF::R_XTENSA_TLS_TPOFF
-                                        : ELF::R_XTENSA_32;
+                                        : ELF::R_XTENSA_32_ABS;
   default:
     return ELF::R_XTENSA_SLOT0_OP;
   }
diff --git a/llvm/test/MC/Xtensa/Relocations/relocations.s b/llvm/test/MC/Xtensa/Relocations/relocations.s
index 7937d5d729870..93483286038b1 100644
--- a/llvm/test/MC/Xtensa/Relocations/relocations.s
+++ b/llvm/test/MC/Xtensa/Relocations/relocations.s
@@ -9,7 +9,7 @@
 # INSTR - Check the instruction is handled properly by the ASMPrinter
 
 .long func
-# RELOC: R_XTENSA_32 func
+# RELOC: R_XTENSA_32_ABS func
 
 ball a1, a3, func
 # RELOC: R_XTENSA_SLOT0_OP
diff --git a/llvm/test/tools/llvm-readobj/ELF/reloc-types-xtensa.test b/llvm/test/tools/llvm-readobj/ELF/reloc-types-xtensa.test
index 0356e4f53d48f..1e878586b2605 100644
--- a/llvm/test/tools/llvm-readobj/ELF/reloc-types-xtensa.test
+++ b/llvm/test/tools/llvm-readobj/ELF/reloc-types-xtensa.test
@@ -59,6 +59,14 @@
 # CHECK-NEXT: 0xD0 R_XTENSA_TLS_FUNC - 0x0
 # CHECK-NEXT: 0xD4 R_XTENSA_TLS_ARG - 0x0
 # CHECK-NEXT: 0xD8 R_XTENSA_TLS_CALL - 0x0
+# CHECK-NEXT: 0xDC R_XTENSA_PDIFF8 - 0x0
+# CHECK-NEXT: 0xE0 R_XTENSA_PDIFF16 - 0x0
+# CHECK-NEXT: 0xE4 R_XTENSA_PDIFF32 - 0x0
+# CHECK-NEXT: 0xE8 R_XTENSA_NDIFF8 - 0x0
+# CHECK-NEXT: 0xEC R_XTENSA_NDIFF16 - 0x0
+# CHECK-NEXT: 0xF0 R_XTENSA_NDIFF32 - 0x0
+# CHECK-NEXT: 0xF4 R_XTENSA_PDIFF_ULEB128 - 0x0
+# CHECK-NEXT: 0xF8 R_XTENSA_32_ABS - 0x0
 
 --- !ELF
 FileHeader:
@@ -180,3 +188,19 @@ Sections:
          Type:   R_XTENSA_TLS_ARG
        - Offset: 0x00000000000000D8
          Type:   R_XTENSA_TLS_CALL
+       - Offset: 0x00000000000000DC
+         Type:   R_XTENSA_PDIFF8
+       - Offset: 0x00000000000000E0
+         Type:   R_XTENSA_PDIFF16
+       - Offset: 0x00000000000000E4
+         Type:   R_XTENSA_PDIFF32
+       - Offset: 0x00000000000000E8
+         Type:   R_XTENSA_NDIFF8
+       - Offset: 0x00000000000000EC
+         Type:   R_XTENSA_NDIFF16
+       - Offset: 0x00000000000000F0
+         Type:   R_XTENSA_NDIFF32
+       - Offset: 0x00000000000000F4
+         Type:   R_XTENSA_PDIFF_ULEB128
+       - Offset: 0x00000000000000F8
+         Type:   R_XTENSA_32_ABS

>From b472d92c7b6322d9ac6c41c3d39fd8e71d51828a Mon Sep 17 00:00:00 2001
From: Alexey Gerenkov <alexey at espressif.com>
Date: Fri, 25 Sep 2026 12:52:16 +0300
Subject: [PATCH 2/2] [lld][Xtensa] Add LLD linker support

Initial static ELF Xtensa support in lld for embedded targets:
R_XTENSA_32_ABS, R_XTENSA_SLOT0_OP, and ignore relaxation-only
DIFF/PDIFF/NDIFF/ASM_EXPAND/PDIFF_ULEB128 relocations.

Co-authored-by: Cursor <cursoragent at cursor.com>
---
 lld/ELF/Arch/Xtensa.cpp                | 213 +++++++++++++++++++++++++
 lld/ELF/CMakeLists.txt                 |   1 +
 lld/ELF/InputFiles.cpp                 |   2 +
 lld/ELF/Target.cpp                     |   2 +
 lld/ELF/Target.h                       |   1 +
 lld/test/ELF/xtensa-pdiff-uleb128.test |  44 +++++
 lld/test/ELF/xtensa-reloc-32.test      |  71 +++++++++
 lld/test/ELF/xtensa-reloc.s            |  63 ++++++++
 lld/test/lit.cfg.py                    |   1 +
 9 files changed, 398 insertions(+)
 create mode 100644 lld/ELF/Arch/Xtensa.cpp
 create mode 100644 lld/test/ELF/xtensa-pdiff-uleb128.test
 create mode 100644 lld/test/ELF/xtensa-reloc-32.test
 create mode 100644 lld/test/ELF/xtensa-reloc.s

diff --git a/lld/ELF/Arch/Xtensa.cpp b/lld/ELF/Arch/Xtensa.cpp
new file mode 100644
index 0000000000000..d426975cc598c
--- /dev/null
+++ b/lld/ELF/Arch/Xtensa.cpp
@@ -0,0 +1,213 @@
+//===- Xtensa.cpp ---------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Target.h"
+#include <bitset>
+#include <iostream>
+#include <string>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+
+class Xtensa final : public TargetInfo {
+public:
+  Xtensa(Ctx &ctx);
+  RelExpr getRelExpr(RelType type, const Symbol &s,
+                     const uint8_t *loc) const override;
+  void relocate(uint8_t *loc, const Relocation &rel,
+                uint64_t val) const override;
+};
+
+} // namespace
+
+Xtensa::Xtensa(Ctx &ctx) : TargetInfo(ctx) {}
+
+RelExpr Xtensa::getRelExpr(RelType type, const Symbol &s,
+                           const uint8_t *loc) const {
+  switch (type) {
+  case R_XTENSA_32:
+    // GNU R_XTENSA_32 is partial_inplace: the assembler stores the addend
+    // in the relocated word and leaves r_addend as 0. LLD cannot apply that
+    // encoding correctly alongside LLVM objects, which keep the addend in
+    // r_addend. Use R_XTENSA_32_ABS for the LLVM encoding.
+    Err(ctx) << getErrorLoc(ctx, loc)
+             << "GNU-style R_XTENSA_32 relocation found which cannot be "
+                "handled properly";
+    return R_NONE;
+  case R_XTENSA_32_ABS:
+    return R_ABS;
+  case R_XTENSA_SLOT0_OP:
+    // This relocation is used for various instructions, with varying ways to
+    // calculate the relocation value. This is unlike most ELF architectures,
+    // and is arguably bad design (see the comment on R_386_GOT32 in X86.cpp).
+    // But that's what compilers emit, so it needs to be supported.
+    //
+    // We work around this by returning R_PC here and calculating the PC address
+    // in Xtensa::relocate based on the relative value. That's ugly. A better
+    // solution would be to look at the instruction here and emit various
+    // Xtensa-specific RelTypes, but that has another problem: the RelExpr enum
+    // is at its maximum size of 64. This will need to be fixed eventually, but
+    // for now hack around it and return R_PC.
+    return R_PC;
+  case R_XTENSA_ASM_EXPAND:
+    // This relocation appears to be emitted by the GNU Xtensa compiler as a
+    // linker relaxation hint. For example, for the following code:
+    //
+    //   .section .foo
+    //   .align  4
+    //   foo:
+    //       nop
+    //       nop
+    //       call0 bar
+    //   .align  4
+    //       bar:
+    //
+    // The call0 instruction is compiled to a l32r and callx0 instruction.
+    // The LLVM Xtensa backend does not emit this relocation.
+    // Because it's a relaxation hint, this relocation can be ignored for now
+    // until linker relaxations are implemented.
+    return R_NONE;
+  case R_XTENSA_DIFF8:
+  case R_XTENSA_DIFF16:
+  case R_XTENSA_DIFF32:
+  case R_XTENSA_PDIFF8:
+  case R_XTENSA_PDIFF16:
+  case R_XTENSA_PDIFF32:
+  case R_XTENSA_NDIFF8:
+  case R_XTENSA_NDIFF16:
+  case R_XTENSA_NDIFF32:
+  case R_XTENSA_PDIFF_ULEB128:
+    // Xtensa relocations to mark the difference of two local symbols.
+    // These are only needed to support linker relaxation and can be ignored
+    // when not relaxing.
+    // Source:
+    // https://github.com/espressif/binutils-gdb/commit/30ce8e47fad9b057b6d7af9e1d43061126d34d20:
+    // Because we don't do linker relaxation, we can ignore these relocations.
+    return R_NONE;
+  default:
+    Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v
+             << ") against symbol " << &s;
+    return R_NONE;
+  }
+}
+
+static inline bool isRRI8Branch(uint8_t *loc) {
+  // instructions: ball, bany, bbc, bbci, bbs, bbsi, beq, bge, bgeu, blt,
+  // bltu, bnall, bne, bnone
+  if ((loc[0] & 0x0f) == 0b0111)
+    return true;
+  // instructions: beqi, bgei, bnei, blti
+  if ((loc[0] & 0b11'1111) == 0b10'0110)
+    return true;
+  // instructions: bgeui, bltui
+  if ((loc[0] & 0b1011'1111) == 0b1011'0110)
+    return true;
+  if ((loc[0] & 0b0111'1111) == 0b0111'0110) {
+    // instruction: bf
+    if ((loc[1] & 0b1111'0000) == 0b0000'0000)
+      return true;
+    // instruction: bt
+    if ((loc[1] & 0b1111'0000) == 0b0001'0000)
+      return true;
+  }
+  // some other instruction
+  return false;
+}
+
+static inline bool isLoop(uint8_t *loc) {
+  // instructions: loop, loopgtz, loopnez
+  if ((loc[0] & 0b1111'1111) == 0b0111'0110) {
+    // instruction: loop
+    if ((loc[1] & 0b1111'0000) == 0b1000'0000)
+      return true;
+    // instruction: loopgtz
+    if ((loc[1] & 0b1111'0000) == 0b1010'0000)
+      return true;
+    // instruction: loopnez
+    if ((loc[1] & 0b1111'0000) == 0b1001'0000)
+      return true;
+  }
+  // some other instruction
+  return false;
+}
+
+void Xtensa::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
+  switch (rel.type) {
+  case R_XTENSA_32_ABS:
+    write32le(loc, val);
+    break;
+  case R_XTENSA_SLOT0_OP: {
+    // HACK: calculate the instruction location based on the PC-relative
+    // relocation value.
+    uint64_t dest = rel.sym->getVA(ctx, rel.addend);
+    uint64_t p = dest - val;
+
+    // This relocation is used for various instructions.
+    // Look at the instruction to determine how to do the relocation.
+    uint8_t opcode = loc[0] & 0x0f;
+    if (opcode == 0b0001) { // RI16 format: l32r
+      int64_t val = dest - ((p + 3) & (uint64_t)0xfffffffc);
+      if ((val < -262144 || val > -4))
+        reportRangeError(ctx, loc, rel, Twine(static_cast<int64_t>(val)),
+                         -262141, -4);
+      checkAlignment(ctx, loc, static_cast<uint64_t>(val), 4, rel);
+      write16le(loc + 1, val >> 2);
+    } else if (opcode == 0b0101) { // call0, call4, call8, call12 (CALL format)
+      uint64_t val = dest - ((p + 4) & (uint64_t)0xfffffffc);
+      checkInt(ctx, loc, static_cast<int64_t>(val) >> 2, 18, rel);
+      checkAlignment(ctx, loc, val, 4, rel);
+      const int64_t target = static_cast<int64_t>(val) >> 2;
+      loc[0] = (loc[0] & 0b0011'1111) | ((target & 0b0000'0011) << 6);
+      loc[1] = target >> 2;
+      loc[2] = target >> 10;
+    } else if ((loc[0] & 0x3f) == 0b00'0110) { // j (CALL format)
+      uint64_t valJ = val - 4;
+      checkInt(ctx, loc, static_cast<int64_t>(valJ), 18, rel);
+      loc[0] = (loc[0] & 0b0011'1111) | ((valJ & 0b0000'0011) << 6);
+      loc[1] = valJ >> 2;
+      loc[2] = valJ >> 10;
+    } else if (isRRI8Branch(loc)) { // RRI8 format (various branch instructions)
+      uint64_t v = val - 4;
+      checkInt(ctx, loc, static_cast<int64_t>(v), 8, rel);
+      loc[2] = v & 0xff;
+    } else if (isLoop(loc)) { // loop instructions
+      uint64_t v = val - 4;
+      checkUInt(ctx, loc, v, 8, rel);
+      loc[2] = v & 0xff;
+    } else if ((loc[0] & 0b1000'1111) ==
+               0b1000'1100) { // RI16 format: beqz.n, bnez.n
+      uint64_t v = val - 4;
+      checkUInt(ctx, loc, v, 6, rel);
+      loc[0] = (loc[0] & 0xcf) | (v & 0x30);
+      loc[1] = (loc[1] & 0x0f) | ((v & 0x0f) << 4);
+    } else if ((loc[0] & 0b0011'1111) ==
+               0b0001'0110) { // BRI12 format: beqz, bgez, bltz, bnez
+      uint64_t v = val - 4;
+      checkInt(ctx, loc, static_cast<int64_t>(v), 12, rel);
+      loc[1] = ((loc[1] & 0x0f)) | ((v & 0x0f) << 4);
+      loc[2] = (v >> 4) & 0xff;
+    } else {
+      Err(ctx) << getErrorLoc(ctx, loc)
+               << "unknown opcode for relocation: " << loc[0];
+    }
+    break;
+  }
+  default:
+    llvm_unreachable("unknown relocation");
+  }
+}
+
+void elf::setXtensaTargetInfo(Ctx &ctx) { ctx.target.reset(new Xtensa(ctx)); }
diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt
index e22897c2789d8..29eb121b1c87b 100644
--- a/lld/ELF/CMakeLists.txt
+++ b/lld/ELF/CMakeLists.txt
@@ -36,6 +36,7 @@ add_lld_library(lldELF
   Arch/SystemZ.cpp
   Arch/X86.cpp
   Arch/X86_64.cpp
+  Arch/Xtensa.cpp
   ARMErrataFix.cpp
   BPSectionOrderer.cpp
   CallGraphSort.cpp
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 2f544f0fe0958..77299bc38bb06 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -1783,6 +1783,8 @@ static uint16_t getBitcodeMachineKind(Ctx &ctx, StringRef path,
     return t.isOSIAMCU() ? EM_IAMCU : EM_386;
   case Triple::x86_64:
     return EM_X86_64;
+  case Triple::xtensa:
+    return EM_XTENSA;
   default:
     ErrAlways(ctx) << path
                    << ": could not infer e_machine from bitcode target triple "
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 89e4dbeed3109..89cc9357cac1b 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -83,6 +83,8 @@ void elf::setTarget(Ctx &ctx) {
     return setSystemZTargetInfo(ctx);
   case EM_X86_64:
     return setX86_64TargetInfo(ctx);
+  case EM_XTENSA:
+    return setXtensaTargetInfo(ctx);
   default:
     Fatal(ctx) << "unsupported e_machine value: " << ctx.arg.emachine;
   }
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index c9b2af07149e0..1d264a2b8a6a9 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -217,6 +217,7 @@ void setSPARCV9TargetInfo(Ctx &);
 void setSystemZTargetInfo(Ctx &);
 void setX86TargetInfo(Ctx &);
 void setX86_64TargetInfo(Ctx &);
+void setXtensaTargetInfo(Ctx &);
 
 struct ErrorPlace {
   InputSectionBase *isec;
diff --git a/lld/test/ELF/xtensa-pdiff-uleb128.test b/lld/test/ELF/xtensa-pdiff-uleb128.test
new file mode 100644
index 0000000000000..1afd2d076505c
--- /dev/null
+++ b/lld/test/ELF/xtensa-pdiff-uleb128.test
@@ -0,0 +1,44 @@
+# REQUIRES: xtensa
+## R_XTENSA_PDIFF_ULEB128 marks a padded same-section uleb128 difference.
+## LLD does not implement Xtensa relaxation, so the reloc is ignored and the
+## assembler-written value must be preserved.
+# RUN: yaml2obj %s -o %t.o
+# RUN: llvm-readobj -r %t.o | FileCheck %s --check-prefix=RELOC
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-objdump -s -j .debug_rnglists %t | FileCheck %s
+
+# RELOC: 0x0 R_XTENSA_PDIFF_ULEB128 foo
+
+# CHECK:      Contents of section .debug_rnglists:
+# CHECK-NEXT: {{.*}}808100
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_XTENSA
+Sections:
+  - Name:    .text
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC, SHF_EXECINSTR ]
+    Content: '00000000'
+  - Name:    .debug_rnglists
+    Type:    SHT_PROGBITS
+    # Padded uleb128 for 128: 0x80 0x81 0x00 (minimal 0x80 0x01 plus one spare).
+    Content: '808100'
+  - Name:    .rela.debug_rnglists
+    Type:    SHT_RELA
+    Link:    .symtab
+    Info:    .debug_rnglists
+    Relocations:
+      - Offset: 0
+        Symbol: foo
+        Type:   R_XTENSA_PDIFF_ULEB128
+Symbols:
+  - Name:    foo
+    Section: .text
+  - Name:    _start
+    Type:    STT_FUNC
+    Section: .text
+    Binding: STB_GLOBAL
diff --git a/lld/test/ELF/xtensa-reloc-32.test b/lld/test/ELF/xtensa-reloc-32.test
new file mode 100644
index 0000000000000..23f611bfadede
--- /dev/null
+++ b/lld/test/ELF/xtensa-reloc-32.test
@@ -0,0 +1,71 @@
+# REQUIRES: xtensa
+## R_XTENSA_32_ABS is the LLVM-style absolute 32-bit reloc (S + A).
+## GNU-style R_XTENSA_32 (partial_inplace) is rejected.
+# RUN: yaml2obj --docnum=1 %s -o %t.ok.o
+# RUN: ld.lld %t.ok.o --section-start=.text=0x1000 --image-base=0x0 -o %t
+# RUN: llvm-objdump -s -j .data %t | FileCheck %s --check-prefix=OK
+
+# RUN: yaml2obj --docnum=2 %s -o %t.gnu.o
+# RUN: not ld.lld %t.gnu.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR
+
+# OK:      Contents of section .data:
+# OK-NEXT: {{.*}}00100000
+
+# ERR: error: {{.*}}: GNU-style R_XTENSA_32 relocation found which cannot be handled properly
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_XTENSA
+Sections:
+  - Name:    .text
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC, SHF_EXECINSTR ]
+    Content: '00000000'
+  - Name:    .data
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC, SHF_WRITE ]
+    Content: '00000000'
+  - Name:    .rela.data
+    Type:    SHT_RELA
+    Link:    .symtab
+    Info:    .data
+    Relocations:
+      - Offset: 0
+        Symbol: _start
+        Type:   R_XTENSA_32_ABS
+Symbols:
+  - Name:    _start
+    Type:    STT_FUNC
+    Section: .text
+    Binding: STB_GLOBAL
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_XTENSA
+Sections:
+  - Name:    .text
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC, SHF_EXECINSTR ]
+    Content: '00000000'
+  - Name:    .data
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC, SHF_WRITE ]
+    Content: '78563412'
+  - Name:    .rela.data
+    Type:    SHT_RELA
+    Link:    .symtab
+    Info:    .data
+    Relocations:
+      - Offset: 0
+        Symbol: _start
+        Type:   R_XTENSA_32
+Symbols:
+  - Name:    _start
+    Type:    STT_FUNC
+    Section: .text
+    Binding: STB_GLOBAL
diff --git a/lld/test/ELF/xtensa-reloc.s b/lld/test/ELF/xtensa-reloc.s
new file mode 100644
index 0000000000000..cf0312166ee61
--- /dev/null
+++ b/lld/test/ELF/xtensa-reloc.s
@@ -0,0 +1,63 @@
+# REQUIRES: xtensa
+# RUN: llvm-mc -filetype=obj -triple=xtensa -mcpu=esp32 %s -o %t.o
+# RUN: ld.lld %t.o --defsym=a=0x2000 --section-start=.CALL=0x1000 --defsym=b=0x40 --defsym=c=0x140 --section-start=.BRANCH=0x5000 --defsym=d=0x5010 --section-start=.BR12=0x100 --image-base=0x0  -o %t
+# RUN: llvm-objdump -d --mcpu=esp32 --print-imm-hex %t | FileCheck %s
+
+.section .BR12,"ax", at progbits
+ .globl _start
+ .balign 0x100
+ .type _start,%function
+_start:
+# CHECK-LABEL:section .BR12
+# CHECK:      beqz a2, 0x140
+# CHECK-NEXT: bnez a3, 0x140
+# CHECK-NEXT: bgez a4, 0x140
+# CHECK-NEXT: bltz a5, 0x140
+  beqz a2, c
+  bnez a3, c
+  bgez a4, c
+  bltz a5, c
+
+.section .CALL,"ax", at progbits
+# CHECK-LABEL: section .CALL:
+# CHECK:      call0 0x2000
+# CHECK-NEXT: call0 0x2000
+# CHECK-NEXT: call0 0x2000
+# CHECK-NEXT: call0 0x2000
+# CHECK-NEXT: j     0x2000
+# CHECK-NEXT: j     0x2000
+# CHECK-NEXT: j     0x2000
+# CHECK-NEXT: j     0x40
+# CHECK-NEXT: j     0x140
+# CHECK-NEXT: call0 0x40
+# CHECK-NEXT: call0 0x140
+# CHECK-NEXT: l32r a3, 0x40
+# CHECK-NEXT: callx0 a3
+# CHECK-NEXT: l32r a4, 0x140
+# CHECK-NEXT: callx0 a4
+  call0 a
+  call0 a
+  call0 a
+  call0 a
+  j a
+  j a
+  j a
+  j b
+  j c
+  call0 b
+  call0 c
+  l32r a3, b
+  callx0 a3
+  l32r a4, c
+  callx0 a4
+
+.section .BRANCH,"ax", at progbits
+# CHECK-LABEL: section .BRANCH:
+# CHECK:      beq a3, a4, 0x5010
+# CHECK-NEXT: ball a3, a4, 0x5010
+# CHECK-NEXT: blt a3, a4, 0x5010
+# CHECK-NEXT: bt b0, 0x5010
+  beq a3, a4, d
+  ball a3, a4, d
+  blt a3, a4, d
+  bt b0, d
diff --git a/lld/test/lit.cfg.py b/lld/test/lit.cfg.py
index 39c3d0aa36bfb..c560f9957b5d2 100644
--- a/lld/test/lit.cfg.py
+++ b/lld/test/lit.cfg.py
@@ -99,6 +99,7 @@
                 "SystemZ": "systemz",
                 "WebAssembly": "wasm",
                 "X86": "x86",
+                "Xtensa": "xtensa",
             },
         ),
         ("--assertion-mode", {"ON": "asserts"}),



More information about the llvm-commits mailing list