[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