Compare commits
10 Commits
2d06a804da
...
181dd8561e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
181dd8561e | ||
|
|
76fcccd0ef | ||
|
|
0143bceffa | ||
|
|
84aff0d930 | ||
|
|
c95df9cfbd | ||
|
|
7a7f526d00 | ||
|
|
edd0e50379 | ||
|
|
f44e6fa9fc | ||
|
|
d81cf8022e | ||
|
|
fe23fa4d5c |
@ -0,0 +1,78 @@
|
|||||||
|
From 7f14e7c1b116fc865ddebb78e67816bfc5216178 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jinyang He <hejinyang@loongson.cn>
|
||||||
|
Date: Wed, 15 Nov 2023 09:57:45 +0800
|
||||||
|
Subject: [PATCH 01/14] [lld][LoongArch] Support the R_LARCH_{ADD,SUB}6
|
||||||
|
relocation type (#72190)
|
||||||
|
|
||||||
|
The R_LARCH_{ADD,SUB}6 relocation type are usually used by DwarfCFA to
|
||||||
|
calculate a tiny offset. They appear after binutils 2.41, with GAS
|
||||||
|
enabling relaxation by default.
|
||||||
|
|
||||||
|
(cherry picked from commit 72accbfd0a1023b3182202276904120524ff9200)
|
||||||
|
Change-Id: Iad676e522f11c52e5dc381243f1df60edcef58f5
|
||||||
|
---
|
||||||
|
lld/ELF/Arch/LoongArch.cpp | 8 ++++++++
|
||||||
|
lld/test/ELF/loongarch-add-sub.s | 6 +++++-
|
||||||
|
2 files changed, 13 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
|
||||||
|
index 04ddb4682917..d3a538577a59 100644
|
||||||
|
--- a/lld/ELF/Arch/LoongArch.cpp
|
||||||
|
+++ b/lld/ELF/Arch/LoongArch.cpp
|
||||||
|
@@ -444,10 +444,12 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
|
||||||
|
case R_LARCH_TLS_LE64_LO20:
|
||||||
|
case R_LARCH_TLS_LE64_HI12:
|
||||||
|
return R_TPREL;
|
||||||
|
+ case R_LARCH_ADD6:
|
||||||
|
case R_LARCH_ADD8:
|
||||||
|
case R_LARCH_ADD16:
|
||||||
|
case R_LARCH_ADD32:
|
||||||
|
case R_LARCH_ADD64:
|
||||||
|
+ case R_LARCH_SUB6:
|
||||||
|
case R_LARCH_SUB8:
|
||||||
|
case R_LARCH_SUB16:
|
||||||
|
case R_LARCH_SUB32:
|
||||||
|
@@ -650,6 +652,9 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
|
||||||
|
write32le(loc, setK12(read32le(loc), extractBits(val, 63, 52)));
|
||||||
|
return;
|
||||||
|
|
||||||
|
+ case R_LARCH_ADD6:
|
||||||
|
+ *loc = (*loc & 0xc0) | ((*loc + val) & 0x3f);
|
||||||
|
+ return;
|
||||||
|
case R_LARCH_ADD8:
|
||||||
|
*loc += val;
|
||||||
|
return;
|
||||||
|
@@ -662,6 +667,9 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
|
||||||
|
case R_LARCH_ADD64:
|
||||||
|
write64le(loc, read64le(loc) + val);
|
||||||
|
return;
|
||||||
|
+ case R_LARCH_SUB6:
|
||||||
|
+ *loc = (*loc & 0xc0) | ((*loc - val) & 0x3f);
|
||||||
|
+ return;
|
||||||
|
case R_LARCH_SUB8:
|
||||||
|
*loc -= val;
|
||||||
|
return;
|
||||||
|
diff --git a/lld/test/ELF/loongarch-add-sub.s b/lld/test/ELF/loongarch-add-sub.s
|
||||||
|
index 63a3f7de179e..35f8a053d69c 100644
|
||||||
|
--- a/lld/test/ELF/loongarch-add-sub.s
|
||||||
|
+++ b/lld/test/ELF/loongarch-add-sub.s
|
||||||
|
@@ -6,7 +6,7 @@
|
||||||
|
# RUN: llvm-readelf -x .rodata %t.la64 | FileCheck --check-prefix=CHECK %s
|
||||||
|
# CHECK: section '.rodata':
|
||||||
|
# CHECK-NEXT: 0x9876543210 10325476 98badcfe 804602be 79ffffff
|
||||||
|
-# CHECK-NEXT: 0x9876543220 804602be 804680
|
||||||
|
+# CHECK-NEXT: 0x9876543220 804602be 80468097
|
||||||
|
|
||||||
|
.text
|
||||||
|
.global _start
|
||||||
|
@@ -34,3 +34,7 @@ quux:
|
||||||
|
.byte 0
|
||||||
|
.reloc quux, R_LARCH_ADD8, 1b
|
||||||
|
.reloc quux, R_LARCH_SUB8, 2b
|
||||||
|
+qux:
|
||||||
|
+ .byte 0b10000000
|
||||||
|
+ .reloc qux, R_LARCH_ADD6, qux
|
||||||
|
+ .reloc qux, R_LARCH_SUB6, 2b
|
||||||
|
--
|
||||||
|
2.20.1
|
||||||
|
|
||||||
@ -0,0 +1,239 @@
|
|||||||
|
From d53182c7fcc371f575fd71fa74e28220db6e9b82 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Job Noorman <jnoorman@igalia.com>
|
||||||
|
Date: Sat, 9 Sep 2023 10:24:16 +0200
|
||||||
|
Subject: [PATCH 09/14] [ELF][RISCV] Implement --emit-relocs with relaxation
|
||||||
|
|
||||||
|
Linker relaxation may change relocations (offsets and types). However,
|
||||||
|
when --emit-relocs is used, relocations are simply copied from the input
|
||||||
|
section causing a mismatch with the corresponding (relaxed) code
|
||||||
|
section.
|
||||||
|
|
||||||
|
This patch fixes this as follows: for non-relocatable RISC-V binaries,
|
||||||
|
`InputSection::copyRelocations` reads relocations from the relocated
|
||||||
|
section's `relocations` array (since this gets updated by the relaxation
|
||||||
|
code). For all other cases, relocations are read from the input section
|
||||||
|
directly as before.
|
||||||
|
|
||||||
|
In order to reuse as much code as possible, and to keep the diff small,
|
||||||
|
the original `InputSection::copyRelocations` is changed to accept the
|
||||||
|
relocations as a range of `Relocation` objects. This means that, in the
|
||||||
|
general case when reading from the input section, raw relocations need
|
||||||
|
to be converted to `Relocation`s first, which introduces quite a bit of
|
||||||
|
boiler plate. It also means there's a slight code size increase due to
|
||||||
|
the extra instantiations of `copyRelocations` (for both range types).
|
||||||
|
|
||||||
|
Reviewed By: MaskRay
|
||||||
|
|
||||||
|
Differential Revision: https://reviews.llvm.org/D159082
|
||||||
|
|
||||||
|
(cherry picked from commit 649cac3b627fa3d466b8807536c8be970cc8c32f)
|
||||||
|
Change-Id: I53aeeeed4bea0d74c5571bc90405bcbd363781b2
|
||||||
|
---
|
||||||
|
lld/ELF/InputSection.cpp | 56 ++++++++++++++++-----
|
||||||
|
lld/ELF/InputSection.h | 6 ++-
|
||||||
|
lld/test/ELF/riscv-relax-emit-relocs.s | 69 ++++++++++++++++++++++++++
|
||||||
|
3 files changed, 117 insertions(+), 14 deletions(-)
|
||||||
|
create mode 100644 lld/test/ELF/riscv-relax-emit-relocs.s
|
||||||
|
|
||||||
|
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
|
||||||
|
index 2edaa2b40493..1aff6b968d86 100644
|
||||||
|
--- a/lld/ELF/InputSection.cpp
|
||||||
|
+++ b/lld/ELF/InputSection.cpp
|
||||||
|
@@ -349,29 +349,61 @@ InputSectionBase *InputSection::getRelocatedSection() const {
|
||||||
|
return sections[info];
|
||||||
|
}
|
||||||
|
|
||||||
|
+template <class ELFT, class RelTy>
|
||||||
|
+void InputSection::copyRelocations(uint8_t *buf) {
|
||||||
|
+ if (config->relax && !config->relocatable && config->emachine == EM_RISCV) {
|
||||||
|
+ // On RISC-V, relaxation might change relocations: copy from
|
||||||
|
+ // internal ones that are updated by relaxation.
|
||||||
|
+ InputSectionBase *sec = getRelocatedSection();
|
||||||
|
+ copyRelocations<ELFT, RelTy>(buf, llvm::make_range(sec->relocations.begin(),
|
||||||
|
+ sec->relocations.end()));
|
||||||
|
+ } else {
|
||||||
|
+ // Convert the raw relocations in the input section into Relocation objects
|
||||||
|
+ // suitable to be used by copyRelocations below.
|
||||||
|
+ struct MapRel {
|
||||||
|
+ const ObjFile<ELFT> &file;
|
||||||
|
+ Relocation operator()(const RelTy &rel) const {
|
||||||
|
+ // RelExpr is not used so set to a dummy value.
|
||||||
|
+ return Relocation{R_NONE, rel.getType(config->isMips64EL), rel.r_offset,
|
||||||
|
+ getAddend<ELFT>(rel), &file.getRelocTargetSym(rel)};
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ using RawRels = ArrayRef<RelTy>;
|
||||||
|
+ using MapRelIter =
|
||||||
|
+ llvm::mapped_iterator<typename RawRels::iterator, MapRel>;
|
||||||
|
+ auto mapRel = MapRel{*getFile<ELFT>()};
|
||||||
|
+ RawRels rawRels = getDataAs<RelTy>();
|
||||||
|
+ auto rels = llvm::make_range(MapRelIter(rawRels.begin(), mapRel),
|
||||||
|
+ MapRelIter(rawRels.end(), mapRel));
|
||||||
|
+ copyRelocations<ELFT, RelTy>(buf, rels);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
// This is used for -r and --emit-relocs. We can't use memcpy to copy
|
||||||
|
// relocations because we need to update symbol table offset and section index
|
||||||
|
// for each relocation. So we copy relocations one by one.
|
||||||
|
-template <class ELFT, class RelTy>
|
||||||
|
-void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) {
|
||||||
|
+template <class ELFT, class RelTy, class RelIt>
|
||||||
|
+void InputSection::copyRelocations(uint8_t *buf,
|
||||||
|
+ llvm::iterator_range<RelIt> rels) {
|
||||||
|
const TargetInfo &target = *elf::target;
|
||||||
|
InputSectionBase *sec = getRelocatedSection();
|
||||||
|
(void)sec->contentMaybeDecompress(); // uncompress if needed
|
||||||
|
|
||||||
|
- for (const RelTy &rel : rels) {
|
||||||
|
- RelType type = rel.getType(config->isMips64EL);
|
||||||
|
+ for (const Relocation &rel : rels) {
|
||||||
|
+ RelType type = rel.type;
|
||||||
|
const ObjFile<ELFT> *file = getFile<ELFT>();
|
||||||
|
- Symbol &sym = file->getRelocTargetSym(rel);
|
||||||
|
+ Symbol &sym = *rel.sym;
|
||||||
|
|
||||||
|
auto *p = reinterpret_cast<typename ELFT::Rela *>(buf);
|
||||||
|
buf += sizeof(RelTy);
|
||||||
|
|
||||||
|
if (RelTy::IsRela)
|
||||||
|
- p->r_addend = getAddend<ELFT>(rel);
|
||||||
|
+ p->r_addend = rel.addend;
|
||||||
|
|
||||||
|
// Output section VA is zero for -r, so r_offset is an offset within the
|
||||||
|
// section, but for --emit-relocs it is a virtual address.
|
||||||
|
- p->r_offset = sec->getVA(rel.r_offset);
|
||||||
|
+ p->r_offset = sec->getVA(rel.offset);
|
||||||
|
p->setSymbolAndType(in.symTab->getSymbolIndex(&sym), type,
|
||||||
|
config->isMips64EL);
|
||||||
|
|
||||||
|
@@ -408,8 +440,8 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
- int64_t addend = getAddend<ELFT>(rel);
|
||||||
|
- const uint8_t *bufLoc = sec->content().begin() + rel.r_offset;
|
||||||
|
+ int64_t addend = rel.addend;
|
||||||
|
+ const uint8_t *bufLoc = sec->content().begin() + rel.offset;
|
||||||
|
if (!RelTy::IsRela)
|
||||||
|
addend = target.getImplicitAddend(bufLoc, type);
|
||||||
|
|
||||||
|
@@ -432,7 +464,7 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) {
|
||||||
|
if (RelTy::IsRela)
|
||||||
|
p->r_addend = sym.getVA(addend) - section->getOutputSection()->addr;
|
||||||
|
else if (config->relocatable && type != target.noneRel)
|
||||||
|
- sec->addReloc({R_ABS, type, rel.r_offset, addend, &sym});
|
||||||
|
+ sec->addReloc({R_ABS, type, rel.offset, addend, &sym});
|
||||||
|
} else if (config->emachine == EM_PPC && type == R_PPC_PLTREL24 &&
|
||||||
|
p->r_addend >= 0x8000 && sec->file->ppc32Got2) {
|
||||||
|
// Similar to R_MIPS_GPREL{16,32}. If the addend of R_PPC_PLTREL24
|
||||||
|
@@ -1106,11 +1138,11 @@ template <class ELFT> void InputSection::writeTo(uint8_t *buf) {
|
||||||
|
// If -r or --emit-relocs is given, then an InputSection
|
||||||
|
// may be a relocation section.
|
||||||
|
if (LLVM_UNLIKELY(type == SHT_RELA)) {
|
||||||
|
- copyRelocations<ELFT>(buf, getDataAs<typename ELFT::Rela>());
|
||||||
|
+ copyRelocations<ELFT, typename ELFT::Rela>(buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (LLVM_UNLIKELY(type == SHT_REL)) {
|
||||||
|
- copyRelocations<ELFT>(buf, getDataAs<typename ELFT::Rel>());
|
||||||
|
+ copyRelocations<ELFT, typename ELFT::Rel>(buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h
|
||||||
|
index 15122d6abd6b..2b91711abba3 100644
|
||||||
|
--- a/lld/ELF/InputSection.h
|
||||||
|
+++ b/lld/ELF/InputSection.h
|
||||||
|
@@ -396,8 +396,10 @@ public:
|
||||||
|
static InputSection discarded;
|
||||||
|
|
||||||
|
private:
|
||||||
|
- template <class ELFT, class RelTy>
|
||||||
|
- void copyRelocations(uint8_t *buf, llvm::ArrayRef<RelTy> rels);
|
||||||
|
+ template <class ELFT, class RelTy> void copyRelocations(uint8_t *buf);
|
||||||
|
+
|
||||||
|
+ template <class ELFT, class RelTy, class RelIt>
|
||||||
|
+ void copyRelocations(uint8_t *buf, llvm::iterator_range<RelIt> rels);
|
||||||
|
|
||||||
|
template <class ELFT> void copyShtGroup(uint8_t *buf);
|
||||||
|
};
|
||||||
|
diff --git a/lld/test/ELF/riscv-relax-emit-relocs.s b/lld/test/ELF/riscv-relax-emit-relocs.s
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000000..ebd69b742d4f
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/lld/test/ELF/riscv-relax-emit-relocs.s
|
||||||
|
@@ -0,0 +1,69 @@
|
||||||
|
+# REQUIRES: riscv
|
||||||
|
+## Test that we can handle --emit-relocs while relaxing.
|
||||||
|
+
|
||||||
|
+# RUN: rm -rf %t && mkdir %t && cd %t
|
||||||
|
+
|
||||||
|
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s -o 32.o
|
||||||
|
+# RUN: ld.lld -Ttext=0x10000 --emit-relocs 32.o -o 32
|
||||||
|
+# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases 32 | FileCheck %s
|
||||||
|
+
|
||||||
|
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s -o 64.o
|
||||||
|
+# RUN: ld.lld -Ttext=0x10000 --emit-relocs 64.o -o 64
|
||||||
|
+# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases 64 | FileCheck %s
|
||||||
|
+
|
||||||
|
+## -r should keep original relocations.
|
||||||
|
+# RUN: ld.lld -r 64.o -o 64.r
|
||||||
|
+# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases 64.r | FileCheck %s --check-prefix=CHECKR
|
||||||
|
+
|
||||||
|
+## --no-relax should keep original relocations.
|
||||||
|
+# RUN: ld.lld --emit-relocs --no-relax 64.o -o 64.norelax
|
||||||
|
+# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases 64.norelax | FileCheck %s --check-prefix=CHECKNORELAX
|
||||||
|
+
|
||||||
|
+# CHECK: <_start>:
|
||||||
|
+# CHECK-NEXT: jal ra, 0x10008 <f>
|
||||||
|
+# CHECK-NEXT: R_RISCV_JAL f
|
||||||
|
+# CHECK-NEXT: R_RISCV_RELAX *ABS*
|
||||||
|
+# CHECK-NEXT: jal ra, 0x10008 <f>
|
||||||
|
+# CHECK-NEXT: R_RISCV_JAL f
|
||||||
|
+# CHECK-NEXT: R_RISCV_RELAX *ABS*
|
||||||
|
+# CHECK-EMPTY:
|
||||||
|
+# CHECK-NEXT: <f>:
|
||||||
|
+# CHECK-NEXT: jalr zero, 0(ra)
|
||||||
|
+# CHECK-NEXT: R_RISCV_ALIGN *ABS*+0x4
|
||||||
|
+
|
||||||
|
+# CHECKR: <_start>:
|
||||||
|
+# CHECKR-NEXT: auipc ra, 0
|
||||||
|
+# CHECKR-NEXT: R_RISCV_CALL_PLT f
|
||||||
|
+# CHECKR-NEXT: R_RISCV_RELAX *ABS*
|
||||||
|
+# CHECKR-NEXT: jalr ra, 0(ra)
|
||||||
|
+# CHECKR-NEXT: auipc ra, 0
|
||||||
|
+# CHECKR-NEXT: R_RISCV_CALL_PLT f
|
||||||
|
+# CHECKR-NEXT: R_RISCV_RELAX *ABS*
|
||||||
|
+# CHECKR-NEXT: jalr ra, 0(ra)
|
||||||
|
+# CHECKR-NEXT: addi zero, zero, 0
|
||||||
|
+# CHECKR-NEXT: R_RISCV_ALIGN *ABS*+0x4
|
||||||
|
+# CHECKR-EMPTY:
|
||||||
|
+# CHECKR-NEXT: <f>:
|
||||||
|
+# CHECKR-NEXT: jalr zero, 0(ra)
|
||||||
|
+
|
||||||
|
+# CHECKNORELAX: <_start>:
|
||||||
|
+# CHECKNORELAX-NEXT: auipc ra, 0
|
||||||
|
+# CHECKNORELAX-NEXT: R_RISCV_CALL_PLT f
|
||||||
|
+# CHECKNORELAX-NEXT: R_RISCV_RELAX *ABS*
|
||||||
|
+# CHECKNORELAX-NEXT: jalr ra, 16(ra)
|
||||||
|
+# CHECKNORELAX-NEXT: auipc ra, 0
|
||||||
|
+# CHECKNORELAX-NEXT: R_RISCV_CALL_PLT f
|
||||||
|
+# CHECKNORELAX-NEXT: R_RISCV_RELAX *ABS*
|
||||||
|
+# CHECKNORELAX-NEXT: jalr ra, 8(ra)
|
||||||
|
+# CHECKNORELAX-EMPTY:
|
||||||
|
+# CHECKNORELAX-NEXT: <f>:
|
||||||
|
+# CHECKNORELAX-NEXT: jalr zero, 0(ra)
|
||||||
|
+# CHECKNORELAX-NEXT: R_RISCV_ALIGN *ABS*+0x4
|
||||||
|
+
|
||||||
|
+.global _start
|
||||||
|
+_start:
|
||||||
|
+ call f
|
||||||
|
+ call f
|
||||||
|
+ .balign 8
|
||||||
|
+f:
|
||||||
|
+ ret
|
||||||
|
--
|
||||||
|
2.20.1
|
||||||
|
|
||||||
563
0004-Backport-lld-ELF-Support-relax-R_LARCH_ALIGN.patch
Normal file
563
0004-Backport-lld-ELF-Support-relax-R_LARCH_ALIGN.patch
Normal file
@ -0,0 +1,563 @@
|
|||||||
|
From 80c56e85d742bb88533e4789c76ae2b55dc36835 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jinyang He <hejinyang@loongson.cn>
|
||||||
|
Date: Tue, 6 Feb 2024 09:09:13 +0800
|
||||||
|
Subject: [PATCH 10/14] [lld][ELF] Support relax R_LARCH_ALIGN (#78692)
|
||||||
|
|
||||||
|
Refer to commit 6611d58f5bbc ("Relax R_RISCV_ALIGN"), we can relax
|
||||||
|
R_LARCH_ALIGN by same way. Reuse `SymbolAnchor`, `RISCVRelaxAux` and
|
||||||
|
`initSymbolAnchors` to simplify codes. As `riscvFinalizeRelax` is an
|
||||||
|
arch-specific function, put it override on `TargetInfo::finalizeRelax`,
|
||||||
|
so that LoongArch can override it, too.
|
||||||
|
|
||||||
|
The flow of relax R_LARCH_ALIGN is almost consistent with RISCV. The
|
||||||
|
difference is that LoongArch only has 4-bytes NOP and all executable
|
||||||
|
insn is 4-bytes aligned. So LoongArch not need rewrite NOP sequence.
|
||||||
|
Alignment maxBytesEmit parameter is supported in psABI v2.30.
|
||||||
|
|
||||||
|
(cherry picked from commit 06a728f3feab876f9195738b5774e82dadc0f3a7)
|
||||||
|
(cherry picked from commit 60a8ec3a35c722a9eb8298c215321b89d0faf5b5)
|
||||||
|
Change-Id: I680e9a44f05fb2cc820736eee63ddd999e689daf
|
||||||
|
---
|
||||||
|
lld/ELF/Arch/LoongArch.cpp | 156 ++++++++++++++++++++-
|
||||||
|
lld/ELF/Arch/RISCV.cpp | 28 +---
|
||||||
|
lld/ELF/InputSection.cpp | 5 +-
|
||||||
|
lld/ELF/InputSection.h | 24 +++-
|
||||||
|
lld/ELF/Target.h | 3 +
|
||||||
|
lld/ELF/Writer.cpp | 4 +-
|
||||||
|
lld/test/ELF/loongarch-relax-align.s | 126 +++++++++++++++++
|
||||||
|
lld/test/ELF/loongarch-relax-emit-relocs.s | 49 +++++++
|
||||||
|
8 files changed, 362 insertions(+), 33 deletions(-)
|
||||||
|
create mode 100644 lld/test/ELF/loongarch-relax-align.s
|
||||||
|
create mode 100644 lld/test/ELF/loongarch-relax-emit-relocs.s
|
||||||
|
|
||||||
|
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
|
||||||
|
index d3a538577a59..3f57a76873f9 100644
|
||||||
|
--- a/lld/ELF/Arch/LoongArch.cpp
|
||||||
|
+++ b/lld/ELF/Arch/LoongArch.cpp
|
||||||
|
@@ -36,6 +36,8 @@ public:
|
||||||
|
bool usesOnlyLowPageBits(RelType type) const override;
|
||||||
|
void relocate(uint8_t *loc, const Relocation &rel,
|
||||||
|
uint64_t val) const override;
|
||||||
|
+ bool relaxOnce(int pass) const override;
|
||||||
|
+ void finalizeRelax(int passes) const override;
|
||||||
|
};
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
@@ -521,8 +523,9 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
|
||||||
|
case R_LARCH_TLS_GD_HI20:
|
||||||
|
return R_TLSGD_GOT;
|
||||||
|
case R_LARCH_RELAX:
|
||||||
|
- // LoongArch linker relaxation is not implemented yet.
|
||||||
|
- return R_NONE;
|
||||||
|
+ return config->relax ? R_RELAX_HINT : R_NONE;
|
||||||
|
+ case R_LARCH_ALIGN:
|
||||||
|
+ return R_RELAX_HINT;
|
||||||
|
|
||||||
|
// Other known relocs that are explicitly unimplemented:
|
||||||
|
//
|
||||||
|
@@ -696,6 +699,155 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+static bool relax(InputSection &sec) {
|
||||||
|
+ const uint64_t secAddr = sec.getVA();
|
||||||
|
+ const MutableArrayRef<Relocation> relocs = sec.relocs();
|
||||||
|
+ auto &aux = *sec.relaxAux;
|
||||||
|
+ bool changed = false;
|
||||||
|
+ ArrayRef<SymbolAnchor> sa = ArrayRef(aux.anchors);
|
||||||
|
+ uint64_t delta = 0;
|
||||||
|
+
|
||||||
|
+ std::fill_n(aux.relocTypes.get(), relocs.size(), R_LARCH_NONE);
|
||||||
|
+ aux.writes.clear();
|
||||||
|
+ for (auto [i, r] : llvm::enumerate(relocs)) {
|
||||||
|
+ const uint64_t loc = secAddr + r.offset - delta;
|
||||||
|
+ uint32_t &cur = aux.relocDeltas[i], remove = 0;
|
||||||
|
+ switch (r.type) {
|
||||||
|
+ case R_LARCH_ALIGN: {
|
||||||
|
+ const uint64_t addend =
|
||||||
|
+ r.sym->isUndefined() ? Log2_64(r.addend) + 1 : r.addend;
|
||||||
|
+ const uint64_t allBytes = (1 << (addend & 0xff)) - 4;
|
||||||
|
+ const uint64_t align = 1 << (addend & 0xff);
|
||||||
|
+ const uint64_t maxBytes = addend >> 8;
|
||||||
|
+ const uint64_t off = loc & (align - 1);
|
||||||
|
+ const uint64_t curBytes = off == 0 ? 0 : align - off;
|
||||||
|
+ // All bytes beyond the alignment boundary should be removed.
|
||||||
|
+ // If emit bytes more than max bytes to emit, remove all.
|
||||||
|
+ if (maxBytes != 0 && curBytes > maxBytes)
|
||||||
|
+ remove = allBytes;
|
||||||
|
+ else
|
||||||
|
+ remove = allBytes - curBytes;
|
||||||
|
+ // If we can't satisfy this alignment, we've found a bad input.
|
||||||
|
+ if (LLVM_UNLIKELY(static_cast<int32_t>(remove) < 0)) {
|
||||||
|
+ errorOrWarn(getErrorLocation((const uint8_t *)loc) +
|
||||||
|
+ "insufficient padding bytes for " + lld::toString(r.type) +
|
||||||
|
+ ": " + Twine(allBytes) + " bytes available for " +
|
||||||
|
+ "requested alignment of " + Twine(align) + " bytes");
|
||||||
|
+ remove = 0;
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // For all anchors whose offsets are <= r.offset, they are preceded by
|
||||||
|
+ // the previous relocation whose `relocDeltas` value equals `delta`.
|
||||||
|
+ // Decrease their st_value and update their st_size.
|
||||||
|
+ for (; sa.size() && sa[0].offset <= r.offset; sa = sa.slice(1)) {
|
||||||
|
+ if (sa[0].end)
|
||||||
|
+ sa[0].d->size = sa[0].offset - delta - sa[0].d->value;
|
||||||
|
+ else
|
||||||
|
+ sa[0].d->value = sa[0].offset - delta;
|
||||||
|
+ }
|
||||||
|
+ delta += remove;
|
||||||
|
+ if (delta != cur) {
|
||||||
|
+ cur = delta;
|
||||||
|
+ changed = true;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (const SymbolAnchor &a : sa) {
|
||||||
|
+ if (a.end)
|
||||||
|
+ a.d->size = a.offset - delta - a.d->value;
|
||||||
|
+ else
|
||||||
|
+ a.d->value = a.offset - delta;
|
||||||
|
+ }
|
||||||
|
+ // Inform assignAddresses that the size has changed.
|
||||||
|
+ if (!isUInt<32>(delta))
|
||||||
|
+ fatal("section size decrease is too large: " + Twine(delta));
|
||||||
|
+ sec.bytesDropped = delta;
|
||||||
|
+ return changed;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+// When relaxing just R_LARCH_ALIGN, relocDeltas is usually changed only once in
|
||||||
|
+// the absence of a linker script. For call and load/store R_LARCH_RELAX, code
|
||||||
|
+// shrinkage may reduce displacement and make more relocations eligible for
|
||||||
|
+// relaxation. Code shrinkage may increase displacement to a call/load/store
|
||||||
|
+// target at a higher fixed address, invalidating an earlier relaxation. Any
|
||||||
|
+// change in section sizes can have cascading effect and require another
|
||||||
|
+// relaxation pass.
|
||||||
|
+bool LoongArch::relaxOnce(int pass) const {
|
||||||
|
+ if (config->relocatable)
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ if (pass == 0)
|
||||||
|
+ initSymbolAnchors();
|
||||||
|
+
|
||||||
|
+ SmallVector<InputSection *, 0> storage;
|
||||||
|
+ bool changed = false;
|
||||||
|
+ for (OutputSection *osec : outputSections) {
|
||||||
|
+ if (!(osec->flags & SHF_EXECINSTR))
|
||||||
|
+ continue;
|
||||||
|
+ for (InputSection *sec : getInputSections(*osec, storage))
|
||||||
|
+ changed |= relax(*sec);
|
||||||
|
+ }
|
||||||
|
+ return changed;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void LoongArch::finalizeRelax(int passes) const {
|
||||||
|
+ log("relaxation passes: " + Twine(passes));
|
||||||
|
+ SmallVector<InputSection *, 0> storage;
|
||||||
|
+ for (OutputSection *osec : outputSections) {
|
||||||
|
+ if (!(osec->flags & SHF_EXECINSTR))
|
||||||
|
+ continue;
|
||||||
|
+ for (InputSection *sec : getInputSections(*osec, storage)) {
|
||||||
|
+ RelaxAux &aux = *sec->relaxAux;
|
||||||
|
+ if (!aux.relocDeltas)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ MutableArrayRef<Relocation> rels = sec->relocs();
|
||||||
|
+ ArrayRef<uint8_t> old = sec->content();
|
||||||
|
+ size_t newSize = old.size() - aux.relocDeltas[rels.size() - 1];
|
||||||
|
+ uint8_t *p = context().bAlloc.Allocate<uint8_t>(newSize);
|
||||||
|
+ uint64_t offset = 0;
|
||||||
|
+ int64_t delta = 0;
|
||||||
|
+ sec->content_ = p;
|
||||||
|
+ sec->size = newSize;
|
||||||
|
+ sec->bytesDropped = 0;
|
||||||
|
+
|
||||||
|
+ // Update section content: remove NOPs for R_LARCH_ALIGN and rewrite
|
||||||
|
+ // instructions for relaxed relocations.
|
||||||
|
+ for (size_t i = 0, e = rels.size(); i != e; ++i) {
|
||||||
|
+ uint32_t remove = aux.relocDeltas[i] - delta;
|
||||||
|
+ delta = aux.relocDeltas[i];
|
||||||
|
+ if (remove == 0 && aux.relocTypes[i] == R_LARCH_NONE)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ // Copy from last location to the current relocated location.
|
||||||
|
+ const Relocation &r = rels[i];
|
||||||
|
+ uint64_t size = r.offset - offset;
|
||||||
|
+ memcpy(p, old.data() + offset, size);
|
||||||
|
+ p += size;
|
||||||
|
+ offset = r.offset + remove;
|
||||||
|
+ }
|
||||||
|
+ memcpy(p, old.data() + offset, old.size() - offset);
|
||||||
|
+
|
||||||
|
+ // Subtract the previous relocDeltas value from the relocation offset.
|
||||||
|
+ // For a pair of R_LARCH_XXX/R_LARCH_RELAX with the same offset, decrease
|
||||||
|
+ // their r_offset by the same delta.
|
||||||
|
+ delta = 0;
|
||||||
|
+ for (size_t i = 0, e = rels.size(); i != e;) {
|
||||||
|
+ uint64_t cur = rels[i].offset;
|
||||||
|
+ do {
|
||||||
|
+ rels[i].offset -= delta;
|
||||||
|
+ if (aux.relocTypes[i] != R_LARCH_NONE)
|
||||||
|
+ rels[i].type = aux.relocTypes[i];
|
||||||
|
+ } while (++i != e && rels[i].offset == cur);
|
||||||
|
+ delta = aux.relocDeltas[i - 1];
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TargetInfo *elf::getLoongArchTargetInfo() {
|
||||||
|
static LoongArch target;
|
||||||
|
return ⌖
|
||||||
|
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
|
||||||
|
index d0d75118e30d..06120cabc132 100644
|
||||||
|
--- a/lld/ELF/Arch/RISCV.cpp
|
||||||
|
+++ b/lld/ELF/Arch/RISCV.cpp
|
||||||
|
@@ -44,6 +44,7 @@ public:
|
||||||
|
void relocate(uint8_t *loc, const Relocation &rel,
|
||||||
|
uint64_t val) const override;
|
||||||
|
bool relaxOnce(int pass) const override;
|
||||||
|
+ void finalizeRelax(int passes) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end anonymous namespace
|
||||||
|
@@ -513,33 +514,14 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-namespace {
|
||||||
|
-struct SymbolAnchor {
|
||||||
|
- uint64_t offset;
|
||||||
|
- Defined *d;
|
||||||
|
- bool end; // true for the anchor of st_value+st_size
|
||||||
|
-};
|
||||||
|
-} // namespace
|
||||||
|
-
|
||||||
|
-struct elf::RISCVRelaxAux {
|
||||||
|
- // This records symbol start and end offsets which will be adjusted according
|
||||||
|
- // to the nearest relocDeltas element.
|
||||||
|
- SmallVector<SymbolAnchor, 0> anchors;
|
||||||
|
- // For relocations[i], the actual offset is r_offset - (i ? relocDeltas[i-1] :
|
||||||
|
- // 0).
|
||||||
|
- std::unique_ptr<uint32_t[]> relocDeltas;
|
||||||
|
- // For relocations[i], the actual type is relocTypes[i].
|
||||||
|
- std::unique_ptr<RelType[]> relocTypes;
|
||||||
|
- SmallVector<uint32_t, 0> writes;
|
||||||
|
-};
|
||||||
|
|
||||||
|
-static void initSymbolAnchors() {
|
||||||
|
+void elf::initSymbolAnchors() {
|
||||||
|
SmallVector<InputSection *, 0> storage;
|
||||||
|
for (OutputSection *osec : outputSections) {
|
||||||
|
if (!(osec->flags & SHF_EXECINSTR))
|
||||||
|
continue;
|
||||||
|
for (InputSection *sec : getInputSections(*osec, storage)) {
|
||||||
|
- sec->relaxAux = make<RISCVRelaxAux>();
|
||||||
|
+ sec->relaxAux = make<RelaxAux>();
|
||||||
|
if (sec->relocs().size()) {
|
||||||
|
sec->relaxAux->relocDeltas =
|
||||||
|
std::make_unique<uint32_t[]>(sec->relocs().size());
|
||||||
|
@@ -766,7 +748,7 @@ bool RISCV::relaxOnce(int pass) const {
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
-void elf::riscvFinalizeRelax(int passes) {
|
||||||
|
+void RISCV::finalizeRelax(int passes) const {
|
||||||
|
llvm::TimeTraceScope timeScope("Finalize RISC-V relaxation");
|
||||||
|
log("relaxation passes: " + Twine(passes));
|
||||||
|
SmallVector<InputSection *, 0> storage;
|
||||||
|
@@ -774,7 +756,7 @@ void elf::riscvFinalizeRelax(int passes) {
|
||||||
|
if (!(osec->flags & SHF_EXECINSTR))
|
||||||
|
continue;
|
||||||
|
for (InputSection *sec : getInputSections(*osec, storage)) {
|
||||||
|
- RISCVRelaxAux &aux = *sec->relaxAux;
|
||||||
|
+ RelaxAux &aux = *sec->relaxAux;
|
||||||
|
if (!aux.relocDeltas)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
|
||||||
|
index 1aff6b968d86..b178d82407e3 100644
|
||||||
|
--- a/lld/ELF/InputSection.cpp
|
||||||
|
+++ b/lld/ELF/InputSection.cpp
|
||||||
|
@@ -351,8 +351,9 @@ InputSectionBase *InputSection::getRelocatedSection() const {
|
||||||
|
|
||||||
|
template <class ELFT, class RelTy>
|
||||||
|
void InputSection::copyRelocations(uint8_t *buf) {
|
||||||
|
- if (config->relax && !config->relocatable && config->emachine == EM_RISCV) {
|
||||||
|
- // On RISC-V, relaxation might change relocations: copy from
|
||||||
|
+ if (config->relax && !config->relocatable &&
|
||||||
|
+ (config->emachine == EM_RISCV || config->emachine == EM_LOONGARCH)) {
|
||||||
|
+ // On LoongArch and RISC-V, relaxation might change relocations: copy from
|
||||||
|
// internal ones that are updated by relaxation.
|
||||||
|
InputSectionBase *sec = getRelocatedSection();
|
||||||
|
copyRelocations<ELFT, RelTy>(buf, llvm::make_range(sec->relocations.begin(),
|
||||||
|
diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h
|
||||||
|
index 2b91711abba3..842bc369909d 100644
|
||||||
|
--- a/lld/ELF/InputSection.h
|
||||||
|
+++ b/lld/ELF/InputSection.h
|
||||||
|
@@ -101,7 +101,23 @@ protected:
|
||||||
|
link(link), info(info) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
-struct RISCVRelaxAux;
|
||||||
|
+struct SymbolAnchor {
|
||||||
|
+ uint64_t offset;
|
||||||
|
+ Defined *d;
|
||||||
|
+ bool end; // true for the anchor of st_value+st_size
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct RelaxAux {
|
||||||
|
+ // This records symbol start and end offsets which will be adjusted according
|
||||||
|
+ // to the nearest relocDeltas element.
|
||||||
|
+ SmallVector<SymbolAnchor, 0> anchors;
|
||||||
|
+ // For relocations[i], the actual offset is
|
||||||
|
+ // r_offset - (i ? relocDeltas[i-1] : 0).
|
||||||
|
+ std::unique_ptr<uint32_t[]> relocDeltas;
|
||||||
|
+ // For relocations[i], the actual type is relocTypes[i].
|
||||||
|
+ std::unique_ptr<RelType[]> relocTypes;
|
||||||
|
+ SmallVector<uint32_t, 0> writes;
|
||||||
|
+};
|
||||||
|
|
||||||
|
// This corresponds to a section of an input file.
|
||||||
|
class InputSectionBase : public SectionBase {
|
||||||
|
@@ -222,9 +238,9 @@ public:
|
||||||
|
// basic blocks.
|
||||||
|
JumpInstrMod *jumpInstrMod = nullptr;
|
||||||
|
|
||||||
|
- // Auxiliary information for RISC-V linker relaxation. RISC-V does not use
|
||||||
|
- // jumpInstrMod.
|
||||||
|
- RISCVRelaxAux *relaxAux;
|
||||||
|
+ // Auxiliary information for RISC-V and LoongArch linker relaxation.
|
||||||
|
+ // They do not use jumpInstrMod.
|
||||||
|
+ RelaxAux *relaxAux;
|
||||||
|
|
||||||
|
// The compressed content size when `compressed` is true.
|
||||||
|
size_t compressedSize;
|
||||||
|
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
|
||||||
|
index 47dbe6b4d1c6..bf831afa1793 100644
|
||||||
|
--- a/lld/ELF/Target.h
|
||||||
|
+++ b/lld/ELF/Target.h
|
||||||
|
@@ -94,6 +94,8 @@ public:
|
||||||
|
|
||||||
|
// Do a linker relaxation pass and return true if we changed something.
|
||||||
|
virtual bool relaxOnce(int pass) const { return false; }
|
||||||
|
+ // Do finalize relaxation after collecting relaxation infos.
|
||||||
|
+ virtual void finalizeRelax(int passes) const {}
|
||||||
|
|
||||||
|
virtual void applyJumpInstrMod(uint8_t *loc, JumpModType type,
|
||||||
|
JumpModType val) const {}
|
||||||
|
@@ -234,6 +236,7 @@ void addArmInputSectionMappingSymbols();
|
||||||
|
void addArmSyntheticSectionMappingSymbol(Defined *);
|
||||||
|
void sortArmMappingSymbols();
|
||||||
|
void convertArmInstructionstoBE8(InputSection *sec, uint8_t *buf);
|
||||||
|
+void initSymbolAnchors();
|
||||||
|
|
||||||
|
LLVM_LIBRARY_VISIBILITY extern const TargetInfo *target;
|
||||||
|
TargetInfo *getTarget();
|
||||||
|
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
|
||||||
|
index 368c9aabceae..dd37bbbf76c1 100644
|
||||||
|
--- a/lld/ELF/Writer.cpp
|
||||||
|
+++ b/lld/ELF/Writer.cpp
|
||||||
|
@@ -1668,8 +1668,8 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- if (!config->relocatable && config->emachine == EM_RISCV)
|
||||||
|
- riscvFinalizeRelax(pass);
|
||||||
|
+ if (!config->relocatable)
|
||||||
|
+ target->finalizeRelax(pass);
|
||||||
|
|
||||||
|
if (config->relocatable)
|
||||||
|
for (OutputSection *sec : outputSections)
|
||||||
|
diff --git a/lld/test/ELF/loongarch-relax-align.s b/lld/test/ELF/loongarch-relax-align.s
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000000..ab61e15d5cac
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/lld/test/ELF/loongarch-relax-align.s
|
||||||
|
@@ -0,0 +1,126 @@
|
||||||
|
+# REQUIRES: loongarch
|
||||||
|
+
|
||||||
|
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
|
||||||
|
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
|
||||||
|
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o -o %t.32
|
||||||
|
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o -o %t.64
|
||||||
|
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o --no-relax -o %t.32n
|
||||||
|
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o --no-relax -o %t.64n
|
||||||
|
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck %s
|
||||||
|
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck %s
|
||||||
|
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32n | FileCheck %s
|
||||||
|
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64n | FileCheck %s
|
||||||
|
+
|
||||||
|
+## Test the R_LARCH_ALIGN without symbol index.
|
||||||
|
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.o64.o --defsym=old=1
|
||||||
|
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o -o %t.o64
|
||||||
|
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o --no-relax -o %t.o64n
|
||||||
|
+# RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck %s
|
||||||
|
+# RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck %s
|
||||||
|
+
|
||||||
|
+## -r keeps section contents unchanged.
|
||||||
|
+# RUN: ld.lld -r %t.64.o -o %t.64.r
|
||||||
|
+# RUN: llvm-objdump -dr --no-show-raw-insn %t.64.r | FileCheck %s --check-prefix=CHECKR
|
||||||
|
+
|
||||||
|
+# CHECK-DAG: {{0*}}10000 l .text {{0*}}44 .Ltext_start
|
||||||
|
+# CHECK-DAG: {{0*}}10038 l .text {{0*}}0c .L1
|
||||||
|
+# CHECK-DAG: {{0*}}10040 l .text {{0*}}04 .L2
|
||||||
|
+# CHECK-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start
|
||||||
|
+
|
||||||
|
+# CHECK: <.Ltext_start>:
|
||||||
|
+# CHECK-NEXT: break 1
|
||||||
|
+# CHECK-NEXT: break 2
|
||||||
|
+# CHECK-NEXT: nop
|
||||||
|
+# CHECK-NEXT: nop
|
||||||
|
+# CHECK-NEXT: break 3
|
||||||
|
+# CHECK-NEXT: break 4
|
||||||
|
+# CHECK-NEXT: nop
|
||||||
|
+# CHECK-NEXT: nop
|
||||||
|
+# CHECK-NEXT: pcalau12i $a0, 0
|
||||||
|
+# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 0
|
||||||
|
+# CHECK-NEXT: pcalau12i $a0, 0
|
||||||
|
+# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 56
|
||||||
|
+# CHECK-NEXT: pcalau12i $a0, 0
|
||||||
|
+# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 64
|
||||||
|
+# CHECK-EMPTY:
|
||||||
|
+# CHECK-NEXT: <.L1>:
|
||||||
|
+# CHECK-NEXT: nop
|
||||||
|
+# CHECK-NEXT: nop
|
||||||
|
+# CHECK-EMPTY:
|
||||||
|
+# CHECK-NEXT: <.L2>:
|
||||||
|
+# CHECK-NEXT: break 5
|
||||||
|
+
|
||||||
|
+# CHECK: <.Ltext2_start>:
|
||||||
|
+# CHECK-NEXT: pcalau12i $a0, 0
|
||||||
|
+# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 0
|
||||||
|
+# CHECK-NEXT: nop
|
||||||
|
+# CHECK-NEXT: nop
|
||||||
|
+# CHECK-NEXT: break 6
|
||||||
|
+
|
||||||
|
+# CHECKR: <.Ltext2_start>:
|
||||||
|
+# CHECKR-NEXT: pcalau12i $a0, 0
|
||||||
|
+# CHECKR-NEXT: {{0*}}00: R_LARCH_PCALA_HI20 .Ltext2_start
|
||||||
|
+# CHECKR-NEXT: {{0*}}00: R_LARCH_RELAX *ABS*
|
||||||
|
+# CHECKR-NEXT: addi.d $a0, $a0, 0
|
||||||
|
+# CHECKR-NEXT: {{0*}}04: R_LARCH_PCALA_LO12 .Ltext2_start
|
||||||
|
+# CHECKR-NEXT: {{0*}}04: R_LARCH_RELAX *ABS*
|
||||||
|
+# CHECKR-NEXT: nop
|
||||||
|
+# CHECKR-NEXT: {{0*}}08: R_LARCH_ALIGN .Lalign_symbol+0x4
|
||||||
|
+# CHECKR-NEXT: nop
|
||||||
|
+# CHECKR-NEXT: nop
|
||||||
|
+# CHECKR-NEXT: break 6
|
||||||
|
+
|
||||||
|
+.macro .fake_p2align_4 max=0
|
||||||
|
+ .ifdef old
|
||||||
|
+ .if \max==0
|
||||||
|
+ .reloc ., R_LARCH_ALIGN, 0xc
|
||||||
|
+ nop; nop; nop
|
||||||
|
+ .endif
|
||||||
|
+ .else
|
||||||
|
+ .reloc ., R_LARCH_ALIGN, .Lalign_symbol + 0x4 + (\max << 8)
|
||||||
|
+ nop; nop; nop
|
||||||
|
+ .endif
|
||||||
|
+.endm
|
||||||
|
+
|
||||||
|
+ .text
|
||||||
|
+.Lalign_symbol:
|
||||||
|
+.Ltext_start:
|
||||||
|
+ break 1
|
||||||
|
+ break 2
|
||||||
|
+## +0x8: Emit 2 nops, delete 1 nop.
|
||||||
|
+ .fake_p2align_4
|
||||||
|
+
|
||||||
|
+ break 3
|
||||||
|
+## +0x14: Emit 3 nops > 8 bytes, not emit.
|
||||||
|
+ .fake_p2align_4 8
|
||||||
|
+
|
||||||
|
+ break 4
|
||||||
|
+ .fake_p2align_4 8
|
||||||
|
+## +0x18: Emit 2 nops <= 8 bytes.
|
||||||
|
+
|
||||||
|
+## Compensate
|
||||||
|
+.ifdef old
|
||||||
|
+ nop; nop
|
||||||
|
+.endif
|
||||||
|
+
|
||||||
|
+## +0x20: Test symbol value and symbol size can be handled.
|
||||||
|
+ la.pcrel $a0, .Ltext_start
|
||||||
|
+ la.pcrel $a0, .L1
|
||||||
|
+ la.pcrel $a0, .L2
|
||||||
|
+
|
||||||
|
+## +0x38: Emit 2 nops, delete 1 nop.
|
||||||
|
+.L1:
|
||||||
|
+ .fake_p2align_4
|
||||||
|
+.L2:
|
||||||
|
+ break 5
|
||||||
|
+ .size .L1, . - .L1
|
||||||
|
+ .size .L2, . - .L2
|
||||||
|
+ .size .Ltext_start, . - .Ltext_start
|
||||||
|
+
|
||||||
|
+## Test another text section.
|
||||||
|
+ .section .text2,"ax",@progbits
|
||||||
|
+.Ltext2_start:
|
||||||
|
+ la.pcrel $a0, .Ltext2_start
|
||||||
|
+ .fake_p2align_4
|
||||||
|
+ break 6
|
||||||
|
+ .size .Ltext2_start, . - .Ltext2_start
|
||||||
|
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000000..581fce8c95ca
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/lld/test/ELF/loongarch-relax-emit-relocs.s
|
||||||
|
@@ -0,0 +1,49 @@
|
||||||
|
+# REQUIRES: loongarch
|
||||||
|
+## Test that we can handle --emit-relocs while relaxing.
|
||||||
|
+
|
||||||
|
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
|
||||||
|
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
|
||||||
|
+# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.32.o -o %t.32
|
||||||
|
+# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64
|
||||||
|
+# RUN: llvm-objdump -dr %t.32 | FileCheck %s
|
||||||
|
+# RUN: llvm-objdump -dr %t.64 | FileCheck %s
|
||||||
|
+
|
||||||
|
+## -r should keep original relocations.
|
||||||
|
+# RUN: ld.lld -r %t.64.o -o %t.64.r
|
||||||
|
+# RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR
|
||||||
|
+
|
||||||
|
+## --no-relax should keep original relocations.
|
||||||
|
+## TODO Due to R_LARCH_RELAX is not relaxed, it plays same as --relax now.
|
||||||
|
+# RUN: ld.lld -Ttext=0x10000 --emit-relocs --no-relax %t.64.o -o %t.64.norelax
|
||||||
|
+# RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s
|
||||||
|
+
|
||||||
|
+# CHECK: 00010000 <_start>:
|
||||||
|
+# CHECK-NEXT: pcalau12i $a0, 0
|
||||||
|
+# CHECK-NEXT: R_LARCH_PCALA_HI20 _start
|
||||||
|
+# CHECK-NEXT: R_LARCH_RELAX *ABS*
|
||||||
|
+# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 0
|
||||||
|
+# CHECK-NEXT: R_LARCH_PCALA_LO12 _start
|
||||||
|
+# CHECK-NEXT: R_LARCH_RELAX *ABS*
|
||||||
|
+# CHECK-NEXT: nop
|
||||||
|
+# CHECK-NEXT: R_LARCH_ALIGN .Lla-relax-align0+0x4
|
||||||
|
+# CHECK-NEXT: nop
|
||||||
|
+# CHECK-NEXT: ret
|
||||||
|
+
|
||||||
|
+# CHECKR: <_start>:
|
||||||
|
+# CHECKR-NEXT: pcalau12i $a0, 0
|
||||||
|
+# CHECKR-NEXT: R_LARCH_PCALA_HI20 _start
|
||||||
|
+# CHECKR-NEXT: R_LARCH_RELAX *ABS*
|
||||||
|
+# CHECKR-NEXT: addi.d $a0, $a0, 0
|
||||||
|
+# CHECKR-NEXT: R_LARCH_PCALA_LO12 _start
|
||||||
|
+# CHECKR-NEXT: R_LARCH_RELAX *ABS*
|
||||||
|
+# CHECKR-NEXT: nop
|
||||||
|
+# CHECKR-NEXT: R_LARCH_ALIGN .Lla-relax-align0+0x4
|
||||||
|
+# CHECKR-NEXT: nop
|
||||||
|
+# CHECKR-NEXT: nop
|
||||||
|
+# CHECKR-NEXT: ret
|
||||||
|
+
|
||||||
|
+.global _start
|
||||||
|
+_start:
|
||||||
|
+ la.pcrel $a0, _start
|
||||||
|
+ .p2align 4
|
||||||
|
+ ret
|
||||||
|
--
|
||||||
|
2.20.1
|
||||||
|
|
||||||
@ -0,0 +1,199 @@
|
|||||||
|
From a5c1174c902a9dc7fb15aa047ca31e012aea6af9 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jinyang He <hejinyang@loongson.cn>
|
||||||
|
Date: Tue, 5 Mar 2024 15:50:14 +0800
|
||||||
|
Subject: [PATCH 12/14] [lld][LoongArch] Support the R_LARCH_{ADD,SUB}_ULEB128
|
||||||
|
relocation types (#81133)
|
||||||
|
|
||||||
|
For a label difference like `.uleb128 A-B`, MC generates a pair of
|
||||||
|
R_LARCH_{ADD,SUB}_ULEB128 if A-B cannot be folded as a constant. GNU
|
||||||
|
assembler generates a pair of relocations in more cases (when A or B is
|
||||||
|
in a code section with linker relaxation). It is similar to RISCV.
|
||||||
|
|
||||||
|
R_LARCH_{ADD,SUB}_ULEB128 relocations are created by Clang and GCC in
|
||||||
|
`.gcc_except_table` and other debug sections with linker relaxation
|
||||||
|
enabled. On LoongArch, first read the buf and count the available space.
|
||||||
|
Then add or sub the value. Finally truncate the expected value and fill
|
||||||
|
it into the available space.
|
||||||
|
|
||||||
|
(cherry picked from commit eaa9ef678c63bf392ec2d5b736605db7ea7e7338)
|
||||||
|
Change-Id: Ic49d34146e47eeeabbbba00ef70b76a13322d80e
|
||||||
|
---
|
||||||
|
lld/ELF/Arch/LoongArch.cpp | 19 +++++
|
||||||
|
lld/test/ELF/loongarch-reloc-leb128.s | 102 ++++++++++++++++++++++++++
|
||||||
|
2 files changed, 121 insertions(+)
|
||||||
|
create mode 100644 lld/test/ELF/loongarch-reloc-leb128.s
|
||||||
|
|
||||||
|
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
|
||||||
|
index 3f57a76873f9..160fab4aeba9 100644
|
||||||
|
--- a/lld/ELF/Arch/LoongArch.cpp
|
||||||
|
+++ b/lld/ELF/Arch/LoongArch.cpp
|
||||||
|
@@ -11,6 +11,7 @@
|
||||||
|
#include "Symbols.h"
|
||||||
|
#include "SyntheticSections.h"
|
||||||
|
#include "Target.h"
|
||||||
|
+#include "llvm/Support/LEB128.h"
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
using namespace llvm::object;
|
||||||
|
@@ -210,6 +211,16 @@ static bool isJirl(uint32_t insn) {
|
||||||
|
return (insn & 0xfc000000) == JIRL;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void handleUleb128(uint8_t *loc, uint64_t val) {
|
||||||
|
+ const uint32_t maxcount = 1 + 64 / 7;
|
||||||
|
+ uint32_t count;
|
||||||
|
+ uint64_t orig = decodeULEB128(loc, &count);
|
||||||
|
+ if (count > maxcount)
|
||||||
|
+ errorOrWarn(getErrorLocation(loc) + "extra space for uleb128");
|
||||||
|
+ uint64_t mask = count < maxcount ? (1ULL << 7 * count) - 1 : -1ULL;
|
||||||
|
+ encodeULEB128((orig + val) & mask, loc, count);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
LoongArch::LoongArch() {
|
||||||
|
// The LoongArch ISA itself does not have a limit on page sizes. According to
|
||||||
|
// the ISA manual, the PS (page size) field in MTLB entries and CSR.STLBPS is
|
||||||
|
@@ -451,11 +462,13 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
|
||||||
|
case R_LARCH_ADD16:
|
||||||
|
case R_LARCH_ADD32:
|
||||||
|
case R_LARCH_ADD64:
|
||||||
|
+ case R_LARCH_ADD_ULEB128:
|
||||||
|
case R_LARCH_SUB6:
|
||||||
|
case R_LARCH_SUB8:
|
||||||
|
case R_LARCH_SUB16:
|
||||||
|
case R_LARCH_SUB32:
|
||||||
|
case R_LARCH_SUB64:
|
||||||
|
+ case R_LARCH_SUB_ULEB128:
|
||||||
|
// The LoongArch add/sub relocs behave like the RISCV counterparts; reuse
|
||||||
|
// the RelExpr to avoid code duplication.
|
||||||
|
return R_RISCV_ADD;
|
||||||
|
@@ -670,6 +683,9 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
|
||||||
|
case R_LARCH_ADD64:
|
||||||
|
write64le(loc, read64le(loc) + val);
|
||||||
|
return;
|
||||||
|
+ case R_LARCH_ADD_ULEB128:
|
||||||
|
+ handleUleb128(loc, val);
|
||||||
|
+ return;
|
||||||
|
case R_LARCH_SUB6:
|
||||||
|
*loc = (*loc & 0xc0) | ((*loc - val) & 0x3f);
|
||||||
|
return;
|
||||||
|
@@ -685,6 +701,9 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
|
||||||
|
case R_LARCH_SUB64:
|
||||||
|
write64le(loc, read64le(loc) - val);
|
||||||
|
return;
|
||||||
|
+ case R_LARCH_SUB_ULEB128:
|
||||||
|
+ handleUleb128(loc, -val);
|
||||||
|
+ return;
|
||||||
|
|
||||||
|
case R_LARCH_MARK_LA:
|
||||||
|
case R_LARCH_MARK_PCREL:
|
||||||
|
diff --git a/lld/test/ELF/loongarch-reloc-leb128.s b/lld/test/ELF/loongarch-reloc-leb128.s
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000000..7740ca797fca
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/lld/test/ELF/loongarch-reloc-leb128.s
|
||||||
|
@@ -0,0 +1,102 @@
|
||||||
|
+# REQUIRES: loongarch
|
||||||
|
+# RUN: rm -rf %t && split-file %s %t && cd %t
|
||||||
|
+
|
||||||
|
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax a.s -o a.o
|
||||||
|
+# RUN: llvm-readobj -r -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a.o | FileCheck %s --check-prefix=REL
|
||||||
|
+# RUN: ld.lld -shared --gc-sections a.o -o a.so
|
||||||
|
+# RUN: llvm-readelf -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a.so | FileCheck %s
|
||||||
|
+
|
||||||
|
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax a.s -o a32.o
|
||||||
|
+# RUN: llvm-readobj -r -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a32.o | FileCheck %s --check-prefix=REL
|
||||||
|
+# RUN: ld.lld -shared --gc-sections a32.o -o a32.so
|
||||||
|
+# RUN: llvm-readelf -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a32.so | FileCheck %s
|
||||||
|
+
|
||||||
|
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax extraspace.s -o extraspace32.o
|
||||||
|
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax extraspace.s -o extraspace64.o
|
||||||
|
+# RUN: not ld.lld -shared extraspace32.o 2>&1 | FileCheck %s --check-prefix=ERROR
|
||||||
|
+# RUN: not ld.lld -shared extraspace64.o 2>&1 | FileCheck %s --check-prefix=ERROR
|
||||||
|
+# ERROR: error: extraspace{{.*}}.o:(.rodata+0x0): extra space for uleb128
|
||||||
|
+
|
||||||
|
+#--- a.s
|
||||||
|
+.cfi_startproc
|
||||||
|
+.cfi_lsda 0x1b,.LLSDA0
|
||||||
|
+.cfi_endproc
|
||||||
|
+
|
||||||
|
+.section .text.w,"axR"
|
||||||
|
+break 0; break 0; break 0; w1:
|
||||||
|
+ .p2align 4 # 4 bytes after relaxation
|
||||||
|
+w2: break 0
|
||||||
|
+
|
||||||
|
+.section .text.x,"ax"
|
||||||
|
+break 0; break 0; break 0; x1:
|
||||||
|
+ .p2align 4 # 4 bytes after relaxation
|
||||||
|
+x2: break 0
|
||||||
|
+
|
||||||
|
+.section .gcc_except_table,"a"
|
||||||
|
+.LLSDA0:
|
||||||
|
+.uleb128 w2-w1+116 # initial value: 0x0080
|
||||||
|
+.uleb128 w1-w2+141 # initial value: 0x0080
|
||||||
|
+.uleb128 w2-w1+16372 # initial value: 0x008080
|
||||||
|
+.uleb128 w1-w2+16397 # initial value: 0x008080
|
||||||
|
+.uleb128 w2-w1+2097140 # initial value: 0x00808080
|
||||||
|
+.uleb128 w1-w2+2097165 # initial value: 0x00808080
|
||||||
|
+
|
||||||
|
+.section .debug_rnglists
|
||||||
|
+.uleb128 w2-w1+116 # initial value: 0x0080
|
||||||
|
+.uleb128 w1-w2+141 # initial value: 0x0080
|
||||||
|
+.uleb128 w2-w1+16372 # initial value: 0x008080
|
||||||
|
+.uleb128 w1-w2+16397 # initial value: 0x008080
|
||||||
|
+.uleb128 w2-w1+2097140 # initial value: 0x00808080
|
||||||
|
+.uleb128 w1-w2+2097165 # initial value: 0x00808080
|
||||||
|
+
|
||||||
|
+.section .debug_loclists
|
||||||
|
+.uleb128 x2-x1 # references discarded symbols
|
||||||
|
+
|
||||||
|
+# REL: Section ({{.*}}) .rela.debug_rnglists {
|
||||||
|
+# REL-NEXT: 0x0 R_LARCH_ADD_ULEB128 w2 0x74
|
||||||
|
+# REL-NEXT: 0x0 R_LARCH_SUB_ULEB128 w1 0x0
|
||||||
|
+# REL-NEXT: 0x2 R_LARCH_ADD_ULEB128 w1 0x8D
|
||||||
|
+# REL-NEXT: 0x2 R_LARCH_SUB_ULEB128 w2 0x0
|
||||||
|
+# REL-NEXT: 0x4 R_LARCH_ADD_ULEB128 w2 0x3FF4
|
||||||
|
+# REL-NEXT: 0x4 R_LARCH_SUB_ULEB128 w1 0x0
|
||||||
|
+# REL-NEXT: 0x7 R_LARCH_ADD_ULEB128 w1 0x400D
|
||||||
|
+# REL-NEXT: 0x7 R_LARCH_SUB_ULEB128 w2 0x0
|
||||||
|
+# REL-NEXT: 0xA R_LARCH_ADD_ULEB128 w2 0x1FFFF4
|
||||||
|
+# REL-NEXT: 0xA R_LARCH_SUB_ULEB128 w1 0x0
|
||||||
|
+# REL-NEXT: 0xE R_LARCH_ADD_ULEB128 w1 0x20000D
|
||||||
|
+# REL-NEXT: 0xE R_LARCH_SUB_ULEB128 w2 0x0
|
||||||
|
+# REL-NEXT: }
|
||||||
|
+# REL: Section ({{.*}}) .rela.debug_loclists {
|
||||||
|
+# REL-NEXT: 0x0 R_LARCH_ADD_ULEB128 x2 0x0
|
||||||
|
+# REL-NEXT: 0x0 R_LARCH_SUB_ULEB128 x1 0x0
|
||||||
|
+# REL-NEXT: }
|
||||||
|
+
|
||||||
|
+# REL: Hex dump of section '.gcc_except_table':
|
||||||
|
+# REL-NEXT: 0x00000000 80008000 80800080 80008080 80008080 .
|
||||||
|
+# REL-NEXT: 0x00000010 8000 .
|
||||||
|
+# REL: Hex dump of section '.debug_rnglists':
|
||||||
|
+# REL-NEXT: 0x00000000 80008000 80800080 80008080 80008080 .
|
||||||
|
+# REL-NEXT: 0x00000010 8000 .
|
||||||
|
+# REL: Hex dump of section '.debug_loclists':
|
||||||
|
+# REL-NEXT: 0x00000000 00 .
|
||||||
|
+
|
||||||
|
+# CHECK: Hex dump of section '.gcc_except_table':
|
||||||
|
+# CHECK-NEXT: 0x[[#%x,]] f8008901 f8ff0089 8001f8ff ff008980 .
|
||||||
|
+# CHECK-NEXT: 0x[[#%x,]] 8001 .
|
||||||
|
+# CHECK: Hex dump of section '.debug_rnglists':
|
||||||
|
+# CHECK-NEXT: 0x00000000 f8008901 f8ff0089 8001f8ff ff008980 .
|
||||||
|
+# CHECK-NEXT: 0x00000010 8001 .
|
||||||
|
+# CHECK: Hex dump of section '.debug_loclists':
|
||||||
|
+# CHECK-NEXT: 0x00000000 0c .
|
||||||
|
+
|
||||||
|
+#--- extraspace.s
|
||||||
|
+.text
|
||||||
|
+w1:
|
||||||
|
+ la.pcrel $t0, w1
|
||||||
|
+w2:
|
||||||
|
+
|
||||||
|
+.rodata
|
||||||
|
+.reloc ., R_LARCH_ADD_ULEB128, w2
|
||||||
|
+.reloc ., R_LARCH_SUB_ULEB128, w1
|
||||||
|
+.fill 10, 1, 0x80
|
||||||
|
+.byte 0
|
||||||
|
--
|
||||||
|
2.20.1
|
||||||
|
|
||||||
20
README.en.md
20
README.en.md
@ -1,22 +1,8 @@
|
|||||||
# lld
|
# lld
|
||||||
|
|
||||||
#### Description
|
#### Description
|
||||||
LLVM Linker
|
This package contains library and header files needed to develop new native
|
||||||
|
programs that use the LLD infrastructure.
|
||||||
#### Software Architecture
|
|
||||||
Software architecture description
|
|
||||||
|
|
||||||
#### Installation
|
|
||||||
|
|
||||||
1. xxxx
|
|
||||||
2. xxxx
|
|
||||||
3. xxxx
|
|
||||||
|
|
||||||
#### Instructions
|
|
||||||
|
|
||||||
1. xxxx
|
|
||||||
2. xxxx
|
|
||||||
3. xxxx
|
|
||||||
|
|
||||||
#### Contribution
|
#### Contribution
|
||||||
|
|
||||||
@ -33,4 +19,4 @@ Software architecture description
|
|||||||
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
|
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
|
||||||
4. The most valuable open source project [GVP](https://gitee.com/gvp)
|
4. The most valuable open source project [GVP](https://gitee.com/gvp)
|
||||||
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
|
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
|
||||||
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||||
21
README.md
21
README.md
@ -1,23 +1,8 @@
|
|||||||
# lld
|
# lld
|
||||||
|
|
||||||
#### 介绍
|
#### 介绍
|
||||||
LLVM Linker
|
This package contains library and header files needed to develop new native
|
||||||
|
programs that use the LLD infrastructure.
|
||||||
#### 软件架构
|
|
||||||
软件架构说明
|
|
||||||
|
|
||||||
|
|
||||||
#### 安装教程
|
|
||||||
|
|
||||||
1. xxxx
|
|
||||||
2. xxxx
|
|
||||||
3. xxxx
|
|
||||||
|
|
||||||
#### 使用说明
|
|
||||||
|
|
||||||
1. xxxx
|
|
||||||
2. xxxx
|
|
||||||
3. xxxx
|
|
||||||
|
|
||||||
#### 参与贡献
|
#### 参与贡献
|
||||||
|
|
||||||
@ -34,4 +19,4 @@ LLVM Linker
|
|||||||
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
|
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
|
||||||
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
|
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
|
||||||
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
|
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
|
||||||
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||||
@ -0,0 +1,500 @@
|
|||||||
|
From 43dfe54ce017c8d37eaec480a2f13a492bbc4203 Mon Sep 17 00:00:00 2001
|
||||||
|
From: serge-sans-paille <sguelton@redhat.com>
|
||||||
|
Date: Thu, 25 Feb 2021 14:24:14 +0100
|
||||||
|
Subject: [PATCH 2/2] [PATCH][lld] Import compact_unwind_encoding.h from
|
||||||
|
libunwind
|
||||||
|
|
||||||
|
This avoids an implicit cross package dependency
|
||||||
|
|
||||||
|
Signed-off-by: Chenxi Mao <chenxi.mao@suse.com>
|
||||||
|
---
|
||||||
|
lld/include/mach-o/compact_unwind_encoding.h | 477 +++++++++++++++++++++++++++
|
||||||
|
1 file changed, 477 insertions(+)
|
||||||
|
create mode 100644 lld/include/mach-o/compact_unwind_encoding.h
|
||||||
|
|
||||||
|
diff --git a/lld/include/mach-o/compact_unwind_encoding.h b/lld/include/mach-o/compact_unwind_encoding.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..5301b10
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/lld/include/mach-o/compact_unwind_encoding.h
|
||||||
|
@@ -0,0 +1,477 @@
|
||||||
|
+//===------------------ mach-o/compact_unwind_encoding.h ------------------===//
|
||||||
|
+//
|
||||||
|
+// 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
|
||||||
|
+//
|
||||||
|
+//
|
||||||
|
+// Darwin's alternative to DWARF based unwind encodings.
|
||||||
|
+//
|
||||||
|
+//===----------------------------------------------------------------------===//
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#ifndef __COMPACT_UNWIND_ENCODING__
|
||||||
|
+#define __COMPACT_UNWIND_ENCODING__
|
||||||
|
+
|
||||||
|
+#include <stdint.h>
|
||||||
|
+
|
||||||
|
+//
|
||||||
|
+// Compilers can emit standard DWARF FDEs in the __TEXT,__eh_frame section
|
||||||
|
+// of object files. Or compilers can emit compact unwind information in
|
||||||
|
+// the __LD,__compact_unwind section.
|
||||||
|
+//
|
||||||
|
+// When the linker creates a final linked image, it will create a
|
||||||
|
+// __TEXT,__unwind_info section. This section is a small and fast way for the
|
||||||
|
+// runtime to access unwind info for any given function. If the compiler
|
||||||
|
+// emitted compact unwind info for the function, that compact unwind info will
|
||||||
|
+// be encoded in the __TEXT,__unwind_info section. If the compiler emitted
|
||||||
|
+// DWARF unwind info, the __TEXT,__unwind_info section will contain the offset
|
||||||
|
+// of the FDE in the __TEXT,__eh_frame section in the final linked image.
|
||||||
|
+//
|
||||||
|
+// Note: Previously, the linker would transform some DWARF unwind infos into
|
||||||
|
+// compact unwind info. But that is fragile and no longer done.
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+//
|
||||||
|
+// The compact unwind endoding is a 32-bit value which encoded in an
|
||||||
|
+// architecture specific way, which registers to restore from where, and how
|
||||||
|
+// to unwind out of the function.
|
||||||
|
+//
|
||||||
|
+typedef uint32_t compact_unwind_encoding_t;
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+// architecture independent bits
|
||||||
|
+enum {
|
||||||
|
+ UNWIND_IS_NOT_FUNCTION_START = 0x80000000,
|
||||||
|
+ UNWIND_HAS_LSDA = 0x40000000,
|
||||||
|
+ UNWIND_PERSONALITY_MASK = 0x30000000,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+//
|
||||||
|
+// x86
|
||||||
|
+//
|
||||||
|
+// 1-bit: start
|
||||||
|
+// 1-bit: has lsda
|
||||||
|
+// 2-bit: personality index
|
||||||
|
+//
|
||||||
|
+// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=DWARF
|
||||||
|
+// ebp based:
|
||||||
|
+// 15-bits (5*3-bits per reg) register permutation
|
||||||
|
+// 8-bits for stack offset
|
||||||
|
+// frameless:
|
||||||
|
+// 8-bits stack size
|
||||||
|
+// 3-bits stack adjust
|
||||||
|
+// 3-bits register count
|
||||||
|
+// 10-bits register permutation
|
||||||
|
+//
|
||||||
|
+enum {
|
||||||
|
+ UNWIND_X86_MODE_MASK = 0x0F000000,
|
||||||
|
+ UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
|
||||||
|
+ UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
|
||||||
|
+ UNWIND_X86_MODE_STACK_IND = 0x03000000,
|
||||||
|
+ UNWIND_X86_MODE_DWARF = 0x04000000,
|
||||||
|
+
|
||||||
|
+ UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
|
||||||
|
+ UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
|
||||||
|
+
|
||||||
|
+ UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
|
||||||
|
+ UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
|
||||||
|
+ UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
|
||||||
|
+ UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
|
||||||
|
+
|
||||||
|
+ UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+enum {
|
||||||
|
+ UNWIND_X86_REG_NONE = 0,
|
||||||
|
+ UNWIND_X86_REG_EBX = 1,
|
||||||
|
+ UNWIND_X86_REG_ECX = 2,
|
||||||
|
+ UNWIND_X86_REG_EDX = 3,
|
||||||
|
+ UNWIND_X86_REG_EDI = 4,
|
||||||
|
+ UNWIND_X86_REG_ESI = 5,
|
||||||
|
+ UNWIND_X86_REG_EBP = 6,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+//
|
||||||
|
+// For x86 there are four modes for the compact unwind encoding:
|
||||||
|
+// UNWIND_X86_MODE_EBP_FRAME:
|
||||||
|
+// EBP based frame where EBP is push on stack immediately after return address,
|
||||||
|
+// then ESP is moved to EBP. Thus, to unwind ESP is restored with the current
|
||||||
|
+// EPB value, then EBP is restored by popping off the stack, and the return
|
||||||
|
+// is done by popping the stack once more into the pc.
|
||||||
|
+// All non-volatile registers that need to be restored must have been saved
|
||||||
|
+// in a small range in the stack that starts EBP-4 to EBP-1020. The offset/4
|
||||||
|
+// is encoded in the UNWIND_X86_EBP_FRAME_OFFSET bits. The registers saved
|
||||||
|
+// are encoded in the UNWIND_X86_EBP_FRAME_REGISTERS bits as five 3-bit entries.
|
||||||
|
+// Each entry contains which register to restore.
|
||||||
|
+// UNWIND_X86_MODE_STACK_IMMD:
|
||||||
|
+// A "frameless" (EBP not used as frame pointer) function with a small
|
||||||
|
+// constant stack size. To return, a constant (encoded in the compact
|
||||||
|
+// unwind encoding) is added to the ESP. Then the return is done by
|
||||||
|
+// popping the stack into the pc.
|
||||||
|
+// All non-volatile registers that need to be restored must have been saved
|
||||||
|
+// on the stack immediately after the return address. The stack_size/4 is
|
||||||
|
+// encoded in the UNWIND_X86_FRAMELESS_STACK_SIZE (max stack size is 1024).
|
||||||
|
+// The number of registers saved is encoded in UNWIND_X86_FRAMELESS_STACK_REG_COUNT.
|
||||||
|
+// UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
|
||||||
|
+// saved and their order.
|
||||||
|
+// UNWIND_X86_MODE_STACK_IND:
|
||||||
|
+// A "frameless" (EBP not used as frame pointer) function large constant
|
||||||
|
+// stack size. This case is like the previous, except the stack size is too
|
||||||
|
+// large to encode in the compact unwind encoding. Instead it requires that
|
||||||
|
+// the function contains "subl $nnnnnnnn,ESP" in its prolog. The compact
|
||||||
|
+// encoding contains the offset to the nnnnnnnn value in the function in
|
||||||
|
+// UNWIND_X86_FRAMELESS_STACK_SIZE.
|
||||||
|
+// UNWIND_X86_MODE_DWARF:
|
||||||
|
+// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||||
|
+// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||||
|
+// This mode is never used in object files. It is only generated by the
|
||||||
|
+// linker in final linked images which have only DWARF unwind info for a
|
||||||
|
+// function.
|
||||||
|
+//
|
||||||
|
+// The permutation encoding is a Lehmer code sequence encoded into a
|
||||||
|
+// single variable-base number so we can encode the ordering of up to
|
||||||
|
+// six registers in a 10-bit space.
|
||||||
|
+//
|
||||||
|
+// The following is the algorithm used to create the permutation encoding used
|
||||||
|
+// with frameless stacks. It is passed the number of registers to be saved and
|
||||||
|
+// an array of the register numbers saved.
|
||||||
|
+//
|
||||||
|
+//uint32_t permute_encode(uint32_t registerCount, const uint32_t registers[6])
|
||||||
|
+//{
|
||||||
|
+// uint32_t renumregs[6];
|
||||||
|
+// for (int i=6-registerCount; i < 6; ++i) {
|
||||||
|
+// int countless = 0;
|
||||||
|
+// for (int j=6-registerCount; j < i; ++j) {
|
||||||
|
+// if ( registers[j] < registers[i] )
|
||||||
|
+// ++countless;
|
||||||
|
+// }
|
||||||
|
+// renumregs[i] = registers[i] - countless -1;
|
||||||
|
+// }
|
||||||
|
+// uint32_t permutationEncoding = 0;
|
||||||
|
+// switch ( registerCount ) {
|
||||||
|
+// case 6:
|
||||||
|
+// permutationEncoding |= (120*renumregs[0] + 24*renumregs[1]
|
||||||
|
+// + 6*renumregs[2] + 2*renumregs[3]
|
||||||
|
+// + renumregs[4]);
|
||||||
|
+// break;
|
||||||
|
+// case 5:
|
||||||
|
+// permutationEncoding |= (120*renumregs[1] + 24*renumregs[2]
|
||||||
|
+// + 6*renumregs[3] + 2*renumregs[4]
|
||||||
|
+// + renumregs[5]);
|
||||||
|
+// break;
|
||||||
|
+// case 4:
|
||||||
|
+// permutationEncoding |= (60*renumregs[2] + 12*renumregs[3]
|
||||||
|
+// + 3*renumregs[4] + renumregs[5]);
|
||||||
|
+// break;
|
||||||
|
+// case 3:
|
||||||
|
+// permutationEncoding |= (20*renumregs[3] + 4*renumregs[4]
|
||||||
|
+// + renumregs[5]);
|
||||||
|
+// break;
|
||||||
|
+// case 2:
|
||||||
|
+// permutationEncoding |= (5*renumregs[4] + renumregs[5]);
|
||||||
|
+// break;
|
||||||
|
+// case 1:
|
||||||
|
+// permutationEncoding |= (renumregs[5]);
|
||||||
|
+// break;
|
||||||
|
+// }
|
||||||
|
+// return permutationEncoding;
|
||||||
|
+//}
|
||||||
|
+//
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+//
|
||||||
|
+// x86_64
|
||||||
|
+//
|
||||||
|
+// 1-bit: start
|
||||||
|
+// 1-bit: has lsda
|
||||||
|
+// 2-bit: personality index
|
||||||
|
+//
|
||||||
|
+// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=DWARF
|
||||||
|
+// rbp based:
|
||||||
|
+// 15-bits (5*3-bits per reg) register permutation
|
||||||
|
+// 8-bits for stack offset
|
||||||
|
+// frameless:
|
||||||
|
+// 8-bits stack size
|
||||||
|
+// 3-bits stack adjust
|
||||||
|
+// 3-bits register count
|
||||||
|
+// 10-bits register permutation
|
||||||
|
+//
|
||||||
|
+enum {
|
||||||
|
+ UNWIND_X86_64_MODE_MASK = 0x0F000000,
|
||||||
|
+ UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
|
||||||
|
+ UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
|
||||||
|
+ UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
|
||||||
|
+ UNWIND_X86_64_MODE_DWARF = 0x04000000,
|
||||||
|
+
|
||||||
|
+ UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
|
||||||
|
+ UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
|
||||||
|
+
|
||||||
|
+ UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
|
||||||
|
+ UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
|
||||||
|
+ UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
|
||||||
|
+ UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
|
||||||
|
+
|
||||||
|
+ UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+enum {
|
||||||
|
+ UNWIND_X86_64_REG_NONE = 0,
|
||||||
|
+ UNWIND_X86_64_REG_RBX = 1,
|
||||||
|
+ UNWIND_X86_64_REG_R12 = 2,
|
||||||
|
+ UNWIND_X86_64_REG_R13 = 3,
|
||||||
|
+ UNWIND_X86_64_REG_R14 = 4,
|
||||||
|
+ UNWIND_X86_64_REG_R15 = 5,
|
||||||
|
+ UNWIND_X86_64_REG_RBP = 6,
|
||||||
|
+};
|
||||||
|
+//
|
||||||
|
+// For x86_64 there are four modes for the compact unwind encoding:
|
||||||
|
+// UNWIND_X86_64_MODE_RBP_FRAME:
|
||||||
|
+// RBP based frame where RBP is push on stack immediately after return address,
|
||||||
|
+// then RSP is moved to RBP. Thus, to unwind RSP is restored with the current
|
||||||
|
+// EPB value, then RBP is restored by popping off the stack, and the return
|
||||||
|
+// is done by popping the stack once more into the pc.
|
||||||
|
+// All non-volatile registers that need to be restored must have been saved
|
||||||
|
+// in a small range in the stack that starts RBP-8 to RBP-2040. The offset/8
|
||||||
|
+// is encoded in the UNWIND_X86_64_RBP_FRAME_OFFSET bits. The registers saved
|
||||||
|
+// are encoded in the UNWIND_X86_64_RBP_FRAME_REGISTERS bits as five 3-bit entries.
|
||||||
|
+// Each entry contains which register to restore.
|
||||||
|
+// UNWIND_X86_64_MODE_STACK_IMMD:
|
||||||
|
+// A "frameless" (RBP not used as frame pointer) function with a small
|
||||||
|
+// constant stack size. To return, a constant (encoded in the compact
|
||||||
|
+// unwind encoding) is added to the RSP. Then the return is done by
|
||||||
|
+// popping the stack into the pc.
|
||||||
|
+// All non-volatile registers that need to be restored must have been saved
|
||||||
|
+// on the stack immediately after the return address. The stack_size/8 is
|
||||||
|
+// encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 2048).
|
||||||
|
+// The number of registers saved is encoded in UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT.
|
||||||
|
+// UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
|
||||||
|
+// saved and their order.
|
||||||
|
+// UNWIND_X86_64_MODE_STACK_IND:
|
||||||
|
+// A "frameless" (RBP not used as frame pointer) function large constant
|
||||||
|
+// stack size. This case is like the previous, except the stack size is too
|
||||||
|
+// large to encode in the compact unwind encoding. Instead it requires that
|
||||||
|
+// the function contains "subq $nnnnnnnn,RSP" in its prolog. The compact
|
||||||
|
+// encoding contains the offset to the nnnnnnnn value in the function in
|
||||||
|
+// UNWIND_X86_64_FRAMELESS_STACK_SIZE.
|
||||||
|
+// UNWIND_X86_64_MODE_DWARF:
|
||||||
|
+// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||||
|
+// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||||
|
+// This mode is never used in object files. It is only generated by the
|
||||||
|
+// linker in final linked images which have only DWARF unwind info for a
|
||||||
|
+// function.
|
||||||
|
+//
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+// ARM64
|
||||||
|
+//
|
||||||
|
+// 1-bit: start
|
||||||
|
+// 1-bit: has lsda
|
||||||
|
+// 2-bit: personality index
|
||||||
|
+//
|
||||||
|
+// 4-bits: 4=frame-based, 3=DWARF, 2=frameless
|
||||||
|
+// frameless:
|
||||||
|
+// 12-bits of stack size
|
||||||
|
+// frame-based:
|
||||||
|
+// 4-bits D reg pairs saved
|
||||||
|
+// 5-bits X reg pairs saved
|
||||||
|
+// DWARF:
|
||||||
|
+// 24-bits offset of DWARF FDE in __eh_frame section
|
||||||
|
+//
|
||||||
|
+enum {
|
||||||
|
+ UNWIND_ARM64_MODE_MASK = 0x0F000000,
|
||||||
|
+ UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
|
||||||
|
+ UNWIND_ARM64_MODE_DWARF = 0x03000000,
|
||||||
|
+ UNWIND_ARM64_MODE_FRAME = 0x04000000,
|
||||||
|
+
|
||||||
|
+ UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
|
||||||
|
+ UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
|
||||||
|
+ UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
|
||||||
|
+ UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
|
||||||
|
+ UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
|
||||||
|
+ UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
|
||||||
|
+ UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
|
||||||
|
+ UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
|
||||||
|
+ UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800,
|
||||||
|
+
|
||||||
|
+ UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
|
||||||
|
+ UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
|
||||||
|
+};
|
||||||
|
+// For arm64 there are three modes for the compact unwind encoding:
|
||||||
|
+// UNWIND_ARM64_MODE_FRAME:
|
||||||
|
+// This is a standard arm64 prolog where FP/LR are immediately pushed on the
|
||||||
|
+// stack, then SP is copied to FP. If there are any non-volatile registers
|
||||||
|
+// saved, then are copied into the stack frame in pairs in a contiguous
|
||||||
|
+// range right below the saved FP/LR pair. Any subset of the five X pairs
|
||||||
|
+// and four D pairs can be saved, but the memory layout must be in register
|
||||||
|
+// number order.
|
||||||
|
+// UNWIND_ARM64_MODE_FRAMELESS:
|
||||||
|
+// A "frameless" leaf function, where FP/LR are not saved. The return address
|
||||||
|
+// remains in LR throughout the function. If any non-volatile registers
|
||||||
|
+// are saved, they must be pushed onto the stack before any stack space is
|
||||||
|
+// allocated for local variables. The stack sized (including any saved
|
||||||
|
+// non-volatile registers) divided by 16 is encoded in the bits
|
||||||
|
+// UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK.
|
||||||
|
+// UNWIND_ARM64_MODE_DWARF:
|
||||||
|
+// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||||
|
+// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||||
|
+// This mode is never used in object files. It is only generated by the
|
||||||
|
+// linker in final linked images which have only DWARF unwind info for a
|
||||||
|
+// function.
|
||||||
|
+//
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+////////////////////////////////////////////////////////////////////////////////
|
||||||
|
+//
|
||||||
|
+// Relocatable Object Files: __LD,__compact_unwind
|
||||||
|
+//
|
||||||
|
+////////////////////////////////////////////////////////////////////////////////
|
||||||
|
+
|
||||||
|
+//
|
||||||
|
+// A compiler can generated compact unwind information for a function by adding
|
||||||
|
+// a "row" to the __LD,__compact_unwind section. This section has the
|
||||||
|
+// S_ATTR_DEBUG bit set, so the section will be ignored by older linkers.
|
||||||
|
+// It is removed by the new linker, so never ends up in final executables.
|
||||||
|
+// This section is a table, initially with one row per function (that needs
|
||||||
|
+// unwind info). The table columns and some conceptual entries are:
|
||||||
|
+//
|
||||||
|
+// range-start pointer to start of function/range
|
||||||
|
+// range-length
|
||||||
|
+// compact-unwind-encoding 32-bit encoding
|
||||||
|
+// personality-function or zero if no personality function
|
||||||
|
+// lsda or zero if no LSDA data
|
||||||
|
+//
|
||||||
|
+// The length and encoding fields are 32-bits. The other are all pointer sized.
|
||||||
|
+//
|
||||||
|
+// In x86_64 assembly, these entry would look like:
|
||||||
|
+//
|
||||||
|
+// .section __LD,__compact_unwind,regular,debug
|
||||||
|
+//
|
||||||
|
+// #compact unwind for _foo
|
||||||
|
+// .quad _foo
|
||||||
|
+// .set L1,LfooEnd-_foo
|
||||||
|
+// .long L1
|
||||||
|
+// .long 0x01010001
|
||||||
|
+// .quad 0
|
||||||
|
+// .quad 0
|
||||||
|
+//
|
||||||
|
+// #compact unwind for _bar
|
||||||
|
+// .quad _bar
|
||||||
|
+// .set L2,LbarEnd-_bar
|
||||||
|
+// .long L2
|
||||||
|
+// .long 0x01020011
|
||||||
|
+// .quad __gxx_personality
|
||||||
|
+// .quad except_tab1
|
||||||
|
+//
|
||||||
|
+//
|
||||||
|
+// Notes: There is no need for any labels in the the __compact_unwind section.
|
||||||
|
+// The use of the .set directive is to force the evaluation of the
|
||||||
|
+// range-length at assembly time, instead of generating relocations.
|
||||||
|
+//
|
||||||
|
+// To support future compiler optimizations where which non-volatile registers
|
||||||
|
+// are saved changes within a function (e.g. delay saving non-volatiles until
|
||||||
|
+// necessary), there can by multiple lines in the __compact_unwind table for one
|
||||||
|
+// function, each with a different (non-overlapping) range and each with
|
||||||
|
+// different compact unwind encodings that correspond to the non-volatiles
|
||||||
|
+// saved at that range of the function.
|
||||||
|
+//
|
||||||
|
+// If a particular function is so wacky that there is no compact unwind way
|
||||||
|
+// to encode it, then the compiler can emit traditional DWARF unwind info.
|
||||||
|
+// The runtime will use which ever is available.
|
||||||
|
+//
|
||||||
|
+// Runtime support for compact unwind encodings are only available on 10.6
|
||||||
|
+// and later. So, the compiler should not generate it when targeting pre-10.6.
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+////////////////////////////////////////////////////////////////////////////////
|
||||||
|
+//
|
||||||
|
+// Final Linked Images: __TEXT,__unwind_info
|
||||||
|
+//
|
||||||
|
+////////////////////////////////////////////////////////////////////////////////
|
||||||
|
+
|
||||||
|
+//
|
||||||
|
+// The __TEXT,__unwind_info section is laid out for an efficient two level lookup.
|
||||||
|
+// The header of the section contains a coarse index that maps function address
|
||||||
|
+// to the page (4096 byte block) containing the unwind info for that function.
|
||||||
|
+//
|
||||||
|
+
|
||||||
|
+#define UNWIND_SECTION_VERSION 1
|
||||||
|
+struct unwind_info_section_header
|
||||||
|
+{
|
||||||
|
+ uint32_t version; // UNWIND_SECTION_VERSION
|
||||||
|
+ uint32_t commonEncodingsArraySectionOffset;
|
||||||
|
+ uint32_t commonEncodingsArrayCount;
|
||||||
|
+ uint32_t personalityArraySectionOffset;
|
||||||
|
+ uint32_t personalityArrayCount;
|
||||||
|
+ uint32_t indexSectionOffset;
|
||||||
|
+ uint32_t indexCount;
|
||||||
|
+ // compact_unwind_encoding_t[]
|
||||||
|
+ // uint32_t personalities[]
|
||||||
|
+ // unwind_info_section_header_index_entry[]
|
||||||
|
+ // unwind_info_section_header_lsda_index_entry[]
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct unwind_info_section_header_index_entry
|
||||||
|
+{
|
||||||
|
+ uint32_t functionOffset;
|
||||||
|
+ uint32_t secondLevelPagesSectionOffset; // section offset to start of regular or compress page
|
||||||
|
+ uint32_t lsdaIndexArraySectionOffset; // section offset to start of lsda_index array for this range
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct unwind_info_section_header_lsda_index_entry
|
||||||
|
+{
|
||||||
|
+ uint32_t functionOffset;
|
||||||
|
+ uint32_t lsdaOffset;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+//
|
||||||
|
+// There are two kinds of second level index pages: regular and compressed.
|
||||||
|
+// A compressed page can hold up to 1021 entries, but it cannot be used
|
||||||
|
+// if too many different encoding types are used. The regular page holds
|
||||||
|
+// 511 entries.
|
||||||
|
+//
|
||||||
|
+
|
||||||
|
+struct unwind_info_regular_second_level_entry
|
||||||
|
+{
|
||||||
|
+ uint32_t functionOffset;
|
||||||
|
+ compact_unwind_encoding_t encoding;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+#define UNWIND_SECOND_LEVEL_REGULAR 2
|
||||||
|
+struct unwind_info_regular_second_level_page_header
|
||||||
|
+{
|
||||||
|
+ uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR
|
||||||
|
+ uint16_t entryPageOffset;
|
||||||
|
+ uint16_t entryCount;
|
||||||
|
+ // entry array
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+#define UNWIND_SECOND_LEVEL_COMPRESSED 3
|
||||||
|
+struct unwind_info_compressed_second_level_page_header
|
||||||
|
+{
|
||||||
|
+ uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED
|
||||||
|
+ uint16_t entryPageOffset;
|
||||||
|
+ uint16_t entryCount;
|
||||||
|
+ uint16_t encodingsPageOffset;
|
||||||
|
+ uint16_t encodingsCount;
|
||||||
|
+ // 32-bit entry array
|
||||||
|
+ // encodings array
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
|
||||||
|
+#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) ((entry >> 24) & 0xFF)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
--
|
||||||
|
1.8.3.1
|
||||||
|
|
||||||
BIN
lld-17.0.6.src.tar.xz
Normal file
BIN
lld-17.0.6.src.tar.xz
Normal file
Binary file not shown.
141
lld.spec
Normal file
141
lld.spec
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
%bcond_without sys_llvm
|
||||||
|
%bcond_without check
|
||||||
|
|
||||||
|
%global maj_ver 17
|
||||||
|
%global min_ver 0
|
||||||
|
%global patch_ver 6
|
||||||
|
|
||||||
|
%if %{with sys_llvm}
|
||||||
|
%global pkg_name lld
|
||||||
|
%global install_prefix %{_prefix}
|
||||||
|
%global install_datadir %{_datadir}
|
||||||
|
%else
|
||||||
|
%global pkg_name lld%{maj_ver}
|
||||||
|
%global install_prefix %{_libdir}/llvm%{maj_ver}
|
||||||
|
%global install_datadir %{install_prefix}/share
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%global install_bindir %{install_prefix}/bin
|
||||||
|
%if 0%{?__isa_bits} == 64
|
||||||
|
%global install_libdir %{install_prefix}/lib64
|
||||||
|
%else
|
||||||
|
%global install_libdir %{install_prefix}/lib
|
||||||
|
%endif
|
||||||
|
%global install_includedir %{install_prefix}/include
|
||||||
|
|
||||||
|
# Don't include unittests in automatic generation of provides or requires.
|
||||||
|
%global __provides_exclude_from ^%{_libdir}/lld/.*$
|
||||||
|
%global __requires_exclude ^libgtest.*$
|
||||||
|
|
||||||
|
# Disable LTO as this causes crash if gcc lto enabled.
|
||||||
|
%define _lto_cflags %{nil}
|
||||||
|
|
||||||
|
Name: %{pkg_name}
|
||||||
|
Version: %{maj_ver}.%{min_ver}.%{patch_ver}
|
||||||
|
Release: 2
|
||||||
|
Summary: The LLVM Linker
|
||||||
|
|
||||||
|
License: NCSA
|
||||||
|
URL: http://llvm.org
|
||||||
|
Source0: https://github.com/llvm/llvm-project/releases/download/llvmorg-%{version}/lld-%{version}.src.tar.xz
|
||||||
|
|
||||||
|
Patch1: fedora-PATCH-lld-Import-compact_unwind_encoding.h-from-libu.patch
|
||||||
|
Patch2: 0002-Backport-lld-LoongArch-Support-the-R_LARCH_-ADD-SUB-6-relocation-type.patch
|
||||||
|
Patch3: 0003-Backport-ELF-RISCV-Implement-emit-relocs-with-relaxation.patch
|
||||||
|
Patch4: 0004-Backport-lld-ELF-Support-relax-R_LARCH_ALIGN.patch
|
||||||
|
Patch5: 0005-Backport-lld-LoongArch-Support-the-R_LARCH_-ADD-SUB-_ULEB128-relocation-types.patch
|
||||||
|
|
||||||
|
BuildRequires: clang
|
||||||
|
BuildRequires: cmake
|
||||||
|
%if %{with sys_llvm}
|
||||||
|
BuildRequires: llvm-devel = %{version}
|
||||||
|
BuildRequires: llvm-googletest = %{version}
|
||||||
|
BuildRequires: llvm-test = %{version}
|
||||||
|
BuildRequires: llvm-cmake-utils = %{version}
|
||||||
|
%else
|
||||||
|
BuildRequires: llvm%{maj_ver}-devel = %{version}
|
||||||
|
BuildRequires: llvm%{maj_ver}-googletest = %{version}
|
||||||
|
BuildRequires: llvm%{maj_ver}-test = %{version}
|
||||||
|
BuildRequires: llvm%{maj_ver}-cmake-utils = %{version}
|
||||||
|
%endif
|
||||||
|
BuildRequires: ncurses-devel
|
||||||
|
BuildRequires: ninja-build
|
||||||
|
BuildRequires: python3-rpm-macros
|
||||||
|
BuildRequires: python3-lit >= %{version}
|
||||||
|
BuildRequires: zlib-devel
|
||||||
|
|
||||||
|
Requires(post): %{_sbindir}/update-alternatives
|
||||||
|
Requires(preun): %{_sbindir}/update-alternatives
|
||||||
|
|
||||||
|
Requires: %{name}-libs = %{version}-%{release}
|
||||||
|
|
||||||
|
%description
|
||||||
|
The LLVM project linker.
|
||||||
|
|
||||||
|
%package devel
|
||||||
|
Summary: Libraries and header files for LLD
|
||||||
|
Requires: %{name}-libs%{?_isa} = %{version}-%{release}
|
||||||
|
|
||||||
|
%description devel
|
||||||
|
This package contains library and header files needed to develop new native
|
||||||
|
programs that use the LLD infrastructure.
|
||||||
|
|
||||||
|
%package libs
|
||||||
|
Summary: LLD shared libraries
|
||||||
|
|
||||||
|
%description libs
|
||||||
|
Shared libraries for LLD.
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%autosetup -n lld-%{version}.src -p2
|
||||||
|
|
||||||
|
%build
|
||||||
|
mkdir -p _build
|
||||||
|
cd _build
|
||||||
|
%cmake .. -G Ninja \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=%{install_prefix} \
|
||||||
|
-DLLVM_LINK_LLVM_DYLIB:BOOL=ON \
|
||||||
|
-DLLVM_DYLIB_COMPONENTS="all" \
|
||||||
|
-DCMAKE_SKIP_RPATH:BOOL=ON \
|
||||||
|
-DPYTHON_EXECUTABLE=%{__python3} \
|
||||||
|
-DLLVM_INCLUDE_TESTS=ON \
|
||||||
|
-DLLVM_EXTERNAL_LIT=%{_bindir}/lit \
|
||||||
|
-DLLVM_LIT_ARGS="-sv \
|
||||||
|
--path %{install_prefix}" \
|
||||||
|
-DLLVM_COMMON_CMAKE_UTILS=%{install_datadir}/llvm/cmake \
|
||||||
|
-DLLVM_MAIN_SRC_DIR=%{install_prefix}/src
|
||||||
|
|
||||||
|
%ninja_build
|
||||||
|
|
||||||
|
%install
|
||||||
|
%ninja_install -C _build
|
||||||
|
|
||||||
|
rm %{buildroot}%{install_includedir}/mach-o/compact_unwind_encoding.h
|
||||||
|
|
||||||
|
%check
|
||||||
|
%if %{with check}
|
||||||
|
%ninja_build check-lld -C _build
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%files
|
||||||
|
%license LICENSE.TXT
|
||||||
|
%{install_bindir}/*
|
||||||
|
|
||||||
|
%files devel
|
||||||
|
%{install_includedir}/lld
|
||||||
|
%{install_libdir}/liblld*.so
|
||||||
|
%{install_libdir}/cmake/lld/
|
||||||
|
|
||||||
|
%files libs
|
||||||
|
%{install_libdir}/liblld*.so.*
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Mon Mar 25 2024 zhanglimin <zhanglimin@loongson.cn> - 17.0.6-2
|
||||||
|
- Supoort `relax` feature on LoongArch
|
||||||
|
|
||||||
|
* Fri Dec 1 2023 zhoujing <zhoujing106@huawei.com> - 17.0.6-1
|
||||||
|
- Update to 17.0.6
|
||||||
|
|
||||||
|
* Thu May 25 2023 cf-zhao <zhaochuanfeng@huawei.com> - 12.0.1-1
|
||||||
|
- Package init
|
||||||
Loading…
x
Reference in New Issue
Block a user