Skip to content

Commit e0c5640

Browse files
authored
Merge pull request #162 from sx-aurora-dev/feature/lld
Implementing lld
2 parents fa0b8b5 + 79c98ac commit e0c5640

24 files changed

+1098
-5
lines changed

clang/cmake/caches/VectorEngine.cmake

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# This file sets up a CMakeCache for the simple VE build.
22

33
# The lld is not supported for VE yet.
4-
set(LLVM_ENABLE_PROJECTS "clang;clang-tools-extra" CACHE STRING "")
4+
set(LLVM_ENABLE_PROJECTS "clang;clang-tools-extra;lld" CACHE STRING "")
55
set(LLVM_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi;libunwind;openmp" CACHE STRING "")
66

77
# Compile for X86 and VE
@@ -55,6 +55,7 @@ set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "")
5555
set(LLVM_TOOLCHAIN_TOOLS
5656
dsymutil
5757
llc
58+
lld
5859
llvm-ar
5960
llvm-cxxfilt
6061
llvm-cov
@@ -79,5 +80,3 @@ set(LLVM_DISTRIBUTION_COMPONENTS
7980
runtimes
8081
${LLVM_TOOLCHAIN_TOOLS}
8182
CACHE STRING "")
82-
# lld
83-
# LTO

lld/ELF/Arch/VE.cpp

Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
//===- VE.cpp -------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "InputFiles.h"
10+
#include "Symbols.h"
11+
#include "SyntheticSections.h"
12+
#include "Target.h"
13+
#include "lld/Common/ErrorHandler.h"
14+
#include "llvm/Support/Endian.h"
15+
16+
using namespace llvm;
17+
using namespace llvm::support::endian;
18+
using namespace llvm::ELF;
19+
using namespace lld;
20+
using namespace lld::elf;
21+
22+
namespace {
23+
class VE final : public TargetInfo {
24+
public:
25+
VE();
26+
RelType getDynRel(RelType type) const override;
27+
RelExpr getRelExpr(RelType type, const Symbol &s,
28+
const uint8_t *loc) const override;
29+
int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
30+
void writeGotPltHeader(uint8_t *buf) const override;
31+
void writeGotHeader(uint8_t *buf) const override;
32+
void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
33+
void writePltHeader(uint8_t *buf) const override;
34+
void writePlt(uint8_t *buf, const Symbol &sym,
35+
uint64_t pltEntryAddr) const override;
36+
void relocate(uint8_t *loc, const Relocation &rel,
37+
uint64_t val) const override;
38+
RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;
39+
};
40+
} // namespace
41+
42+
VE::VE() {
43+
copyRel = R_VE_COPY;
44+
gotRel = R_VE_GLOB_DAT;
45+
pltRel = R_VE_JUMP_SLOT;
46+
relativeRel = R_VE_RELATIVE;
47+
symbolicRel = R_VE_REFQUAD;
48+
49+
tlsModuleIndexRel = R_VE_DTPMOD64;
50+
tlsOffsetRel = R_VE_DTPOFF64;
51+
// VE has no R_VE_TPOFF64.
52+
tlsGotRel = R_VE_NONE;
53+
54+
gotEntrySize = 8;
55+
pltEntrySize = 64;
56+
pltHeaderSize = 64;
57+
58+
// The .got has no preserved entries.
59+
// gotHeaderEntriesNum = 0;
60+
61+
// _GLOBAL_OFFSET_TABLE_ == .got.plt.
62+
gotBaseSymInGotPlt = true;
63+
64+
// _GLOBAL_OFFSET_TABLE_ has two preserved entries.
65+
// _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC.
66+
// _GLOBAL_OFFSET_TABLE_[1] = reserved by glibc.
67+
// or
68+
// _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC
69+
// glibc stores _dl_runtime_resolve in _GLOBAL_OFFSET_TABLE_[1],
70+
// link_map in _GLOBAL_OFFSET_TABLE_[2].
71+
gotPltHeaderEntriesNum = 3;
72+
73+
defaultCommonPageSize = 8192;
74+
defaultMaxPageSize = 0x100000;
75+
defaultImageBase = 0x600000000000;
76+
}
77+
78+
RelType VE::getDynRel(RelType type) const {
79+
if (type == R_VE_REFQUAD)
80+
return type;
81+
return R_VE_NONE;
82+
}
83+
84+
RelExpr VE::getRelExpr(RelType type, const Symbol &s,
85+
const uint8_t *loc) const {
86+
switch (type) {
87+
case R_VE_NONE:
88+
return R_NONE;
89+
case R_VE_REFLONG:
90+
case R_VE_REFQUAD:
91+
return R_ABS;
92+
case R_VE_SREL32:
93+
return R_PC;
94+
case R_VE_HI32:
95+
case R_VE_LO32:
96+
return R_ABS;
97+
case R_VE_PC_HI32:
98+
case R_VE_PC_LO32:
99+
return R_PC;
100+
case R_VE_GOT32:
101+
case R_VE_GOT_HI32:
102+
case R_VE_GOT_LO32:
103+
return R_GOTPLT;
104+
case R_VE_GOTOFF32:
105+
case R_VE_GOTOFF_HI32:
106+
case R_VE_GOTOFF_LO32:
107+
return R_GOTPLTREL;
108+
case R_VE_PLT32:
109+
case R_VE_PLT_HI32:
110+
case R_VE_PLT_LO32:
111+
return R_PLT_PC;
112+
#if 0
113+
case R_VE_RELATIVE:
114+
case R_VE_GLOB_DAT:
115+
case R_VE_JUMP_SLOT:
116+
case R_VE_COPY:
117+
case R_VE_DTPMOD64:
118+
#endif
119+
case R_VE_DTPOFF64:
120+
return R_DTPREL;
121+
case R_VE_TLS_GD_HI32:
122+
case R_VE_TLS_GD_LO32:
123+
return R_TLSGD_PC;
124+
case R_VE_TPOFF_HI32:
125+
case R_VE_TPOFF_LO32:
126+
// TP offset relocation types used for the local-exec TLS model.
127+
return R_TPREL;
128+
case R_VE_CALL_HI32:
129+
case R_VE_CALL_LO32:
130+
return R_ABS;
131+
default:
132+
error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
133+
") against symbol " + toString(s));
134+
return R_NONE;
135+
}
136+
}
137+
138+
void VE::relocate(uint8_t *loc, const Relocation &rel,
139+
uint64_t val) const {
140+
switch (rel.type) {
141+
case R_VE_REFLONG:
142+
// No range check for REFLONG.
143+
write32le(loc, val);
144+
break;
145+
case R_VE_REFQUAD:
146+
write64le(loc, val);
147+
break;
148+
case R_VE_SREL32:
149+
// Range check for SREL32 which is used by relative branch.
150+
checkInt(loc, val, 32, rel);
151+
write32le(loc, val);
152+
break;
153+
case R_VE_HI32:
154+
case R_VE_PC_HI32: // OK
155+
case R_VE_GOT_HI32: // OK
156+
case R_VE_GOTOFF_HI32:// OK
157+
case R_VE_PLT_HI32: // OK
158+
write32le(loc, val >> 32);
159+
break;
160+
case R_VE_LO32:
161+
case R_VE_PC_LO32: // OK
162+
case R_VE_GOT32:
163+
case R_VE_GOT_LO32: // OK
164+
case R_VE_GOTOFF32:
165+
case R_VE_GOTOFF_LO32:// OK
166+
case R_VE_PLT32:
167+
case R_VE_PLT_LO32: // OK
168+
write32le(loc, val);
169+
break;
170+
#if 0
171+
case R_VE_RELATIVE:
172+
case R_VE_GLOB_DAT:
173+
case R_VE_JUMP_SLOT:
174+
checkInt(loc, val, 64, rel);
175+
write64le(loc, val);
176+
break;
177+
case R_VE_COPY:
178+
case R_VE_DTPMOD64:
179+
#endif
180+
case R_VE_DTPOFF64:
181+
write64le(loc, val);
182+
break;
183+
case R_VE_TLS_GD_HI32:
184+
case R_VE_TPOFF_HI32:
185+
case R_VE_CALL_HI32:
186+
write32le(loc, val >> 32);
187+
break;
188+
case R_VE_TLS_GD_LO32:
189+
case R_VE_TPOFF_LO32:
190+
case R_VE_CALL_LO32:
191+
write32le(loc, val);
192+
break;
193+
default:
194+
error(getErrorLocation(loc) + "unknown relocation (" + Twine(rel.type) +
195+
")");
196+
}
197+
}
198+
199+
int64_t VE::getImplicitAddend(const uint8_t *buf, RelType type) const {
200+
switch (type) {
201+
default:
202+
internalLinkerError(getErrorLocation(buf),
203+
"cannot read addend for relocation " + toString(type));
204+
return 0;
205+
case R_VE_NONE:
206+
// This relocations are defined as not having an implicit addend.
207+
return 0;
208+
case R_VE_REFLONG:
209+
return SignExtend64<32>(read32le(buf));
210+
case R_VE_REFQUAD:
211+
return read64le(buf);
212+
case R_VE_SREL32:
213+
case R_VE_HI32:
214+
case R_VE_LO32:
215+
case R_VE_PC_HI32:
216+
case R_VE_PC_LO32:
217+
case R_VE_GOT32:
218+
case R_VE_GOT_HI32:
219+
case R_VE_GOT_LO32:
220+
case R_VE_GOTOFF32:
221+
case R_VE_GOTOFF_HI32:
222+
case R_VE_GOTOFF_LO32:
223+
case R_VE_PLT32:
224+
case R_VE_PLT_HI32:
225+
case R_VE_PLT_LO32:
226+
return SignExtend64<32>(read32le(buf));
227+
case R_VE_RELATIVE:
228+
case R_VE_GLOB_DAT:
229+
return read64le(buf);
230+
case R_VE_JUMP_SLOT:
231+
// These relocations are defined as not having an implicit addend.
232+
return 0;
233+
case R_VE_DTPMOD64:
234+
case R_VE_DTPOFF64:
235+
return read64le(buf);
236+
case R_VE_TLS_GD_HI32:
237+
case R_VE_TLS_GD_LO32:
238+
case R_VE_TPOFF_HI32:
239+
case R_VE_TPOFF_LO32:
240+
case R_VE_CALL_HI32:
241+
case R_VE_CALL_LO32:
242+
return SignExtend64<32>(read32le(buf));
243+
}
244+
}
245+
246+
RelExpr VE::adjustTlsExpr(RelType type, RelExpr expr) const {
247+
return R_NONE;
248+
// return expr;
249+
}
250+
251+
void VE::writeGotPltHeader(uint8_t *buf) const {
252+
// _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC.
253+
// The glibc stores __dso_handle (reserved) in _GLOBAL_OFFSET_TABLE[1].
254+
write64le(buf, mainPart->dynamic->getVA());
255+
}
256+
257+
void VE::writeGotHeader(uint8_t *buf) const {
258+
// _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC
259+
// glibc stores _dl_runtime_resolve in _GLOBAL_OFFSET_TABLE_[1],
260+
// link_map in _GLOBAL_OFFSET_TABLE_[2].
261+
write64le(buf, mainPart->dynamic->getVA());
262+
}
263+
264+
void VE::writeGotPlt(uint8_t *buf, const Symbol &s) const {
265+
// Entries in .got.plt initially points back to the corresponding
266+
// PLT entries with a fixed offset to skip the first instruction.
267+
write64le(buf, s.getPltVA() + 5 * 8);
268+
}
269+
270+
void VE::writePltHeader(uint8_t *buf) const {
271+
const uint8_t pltData[] = {
272+
// _PROCEDURE_LINKAGE_TABLE:
273+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x06, // lea %s62, _GLOBAL_OFFSET_TABLE_@LO
274+
0x00, 0x00, 0x00, 0x00, 0x60, 0xbe, 0x3e, 0x44, // and %s62, %s62, (32)0
275+
0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbe, 0x06, // lea.sl %s62, _GLOBAL_OFFSET_TABLE_@HI(, %s62)
276+
0x08, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x3f, 0x01, // ld %s63, 8(, %s62)
277+
0x00, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x3f, 0x19, // b.l.t (, %s63)
278+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // nop
279+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // nop
280+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // nop
281+
};
282+
memcpy(buf, pltData, sizeof(pltData));
283+
284+
uint64_t got = in.gotPlt->getVA();
285+
// Set address of _GLOBAL_OFFSET_TABLE[0]
286+
relocateNoSym(buf + 0 * 8, R_VE_LO32, got);
287+
relocateNoSym(buf + 2 * 8, R_VE_HI32, got);
288+
// uint64_t plt = in.plt->getVA();
289+
}
290+
291+
void VE::writePlt(uint8_t *buf, const Symbol & sym,
292+
uint64_t pltEntryAddr) const {
293+
const uint8_t pltData[] = {
294+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x06, // lea %s13, _GLOBAL_OFFSET_TABLE[$index + gotPltHeaderEntriesNum]@LO
295+
0x00, 0x00, 0x00, 0x00, 0x60, 0x8d, 0x0d, 0x44, // and %s13, %s13, (32)0
296+
0x00, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x8d, 0x06, // lea.sl %s13, _GLOBAL_OFFSET_TABLE[$index + gotPltHeaderEntriesNum]@HI(, %s13)
297+
0x08, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x0c, 0x01, // ld %s12, (, %s13)
298+
0x00, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x3f, 0x19, // b.l.t (, %s12)
299+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x06, // lea %s13, $index
300+
0x90, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0x18, // br.l.t _PROCEDURE_LINKAGE_TABLE_
301+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // nop
302+
};
303+
memcpy(buf, pltData, sizeof(pltData));
304+
305+
uint64_t pltEntryOff = pltEntryAddr - in.plt->getVA();
306+
uint64_t pltEntryIdx = (pltEntryOff - pltHeaderSize) / pltEntrySize;
307+
uint64_t gotPltBase = in.gotPlt->getVA();
308+
uint64_t gotPlt = gotPltBase + gotPltHeaderEntriesNum * gotEntrySize;
309+
uint64_t va = gotPlt + pltEntryIdx * gotEntrySize;
310+
311+
// Set address of _GLOBAL_OFFSET_TABLE[$index + gotPltHeaderEntriesNum]
312+
relocateNoSym(buf + 0 * 8, R_VE_LO32, va);
313+
relocateNoSym(buf + 2 * 8, R_VE_HI32, va);
314+
// Set index of relocation entry of symbol
315+
relocateNoSym(buf + 5 * 8, R_VE_REFLONG, pltEntryIdx);
316+
// Set relative jump offset to _PROCEDURE_LINKAGE
317+
relocateNoSym(buf + 6 * 8, R_VE_PC_LO32, -(pltEntryOff + 6 * 8));
318+
}
319+
320+
TargetInfo *elf::getVETargetInfo() {
321+
static VE target;
322+
return &target;
323+
}

lld/ELF/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ add_lld_library(lldELF
2222
Arch/SPARCV9.cpp
2323
Arch/X86.cpp
2424
Arch/X86_64.cpp
25+
Arch/VE.cpp
2526
ARMErrataFix.cpp
2627
CallGraphSort.cpp
2728
DWARF.cpp

lld/ELF/Driver.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef emul) {
163163
.Case("elf_iamcu", {ELF32LEKind, EM_IAMCU})
164164
.Case("elf64_sparc", {ELF64BEKind, EM_SPARCV9})
165165
.Case("msp430elf", {ELF32LEKind, EM_MSP430})
166+
.Case("elf64ve", {ELF64LEKind, EM_VE})
166167
.Default({ELFNoneKind, EM_NONE});
167168

168169
if (ret.first == ELFNoneKind)
@@ -948,7 +949,7 @@ static bool getIsRela(opt::InputArgList &args) {
948949
// Otherwise use the psABI defined relocation entry format.
949950
uint16_t m = config->emachine;
950951
return m == EM_AARCH64 || m == EM_AMDGPU || m == EM_HEXAGON || m == EM_PPC ||
951-
m == EM_PPC64 || m == EM_RISCV || m == EM_X86_64;
952+
m == EM_PPC64 || m == EM_RISCV || m == EM_X86_64 || m == EM_VE;
952953
}
953954

954955
static void parseClangOption(StringRef opt, const Twine &msg) {

lld/ELF/InputSection.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,14 @@ static int64_t getTlsTpOffset(const Symbol &s) {
620620
return s.getVA(0) + (tls->p_vaddr & (tls->p_align - 1)) - 0x7000;
621621
case EM_RISCV:
622622
return s.getVA(0) + (tls->p_vaddr & (tls->p_align - 1));
623+
case EM_VE:
624+
// Adjusted Variant 1. TP is placed after a gap which is the size of
625+
// 6 pointers. This gap is defined as TCB_OFFSET (0x30) here,
626+
// https://github.com/veos-sxarr-NEC/gdb-ve/blob/master/bfd/elf64-ve.c#L2512.
627+
// This TCB_OFFSET is defined as tcbhead_t at
628+
// https://github.com/veos-sxarr-NEC/glibc-ve/blob/master/sysdeps/ve/nptl/tls.h#L60-L68.
629+
return s.getVA(0) + config->wordsize * 6 +
630+
(tls->p_vaddr & (tls->p_align - 1));
623631

624632
// Variant 2.
625633
case EM_HEXAGON:

lld/ELF/Relocations.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,7 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
12101210
bool toExecRelax = !config->shared && config->emachine != EM_ARM &&
12111211
config->emachine != EM_HEXAGON &&
12121212
config->emachine != EM_RISCV &&
1213+
config->emachine != EM_VE &&
12131214
!c.file->ppc64DisableTLSRelax;
12141215

12151216
// If we are producing an executable and the symbol is non-preemptable, it

0 commit comments

Comments
 (0)