Skip to content

Commit dcc54ed

Browse files
committed
[LLD] Add EVM architecture to LLD
1 parent bd356fe commit dcc54ed

File tree

6 files changed

+109
-0
lines changed

6 files changed

+109
-0
lines changed

lld/ELF/Arch/EVM.cpp

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//===- EVM.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+
// EVM is a stack-based virtual machine with a word size of 256 bits intendent
10+
// for execution of smart contracts in Ethereum blockchain environment.
11+
//
12+
// Since it is baremetal programming, there's usually no loader to load
13+
// ELF files on EVMs. You are expected to link your program against address
14+
// 0 and pull out a .text section from the result using objcopy, so that you
15+
// can write the linked code to on-chip flush memory. You can do that with
16+
// the following commands:
17+
//
18+
// ld.lld -Ttext=0 -o foo foo.o
19+
// objcopy -O binary --only-section=.text foo output.bin
20+
//
21+
//===----------------------------------------------------------------------===//
22+
23+
#include "InputFiles.h"
24+
#include "Symbols.h"
25+
#include "Target.h"
26+
#include "lld/Common/ErrorHandler.h"
27+
#include "llvm/BinaryFormat/ELF.h"
28+
#include "llvm/Support/Endian.h"
29+
30+
using namespace llvm;
31+
using namespace llvm::object;
32+
using namespace llvm::support::endian;
33+
using namespace llvm::ELF;
34+
using namespace lld;
35+
using namespace lld::elf;
36+
37+
namespace {
38+
class EVM final : public TargetInfo {
39+
public:
40+
uint32_t calcEFlags() const override;
41+
RelExpr getRelExpr(RelType type, const Symbol &s,
42+
const uint8_t *loc) const override;
43+
void relocate(uint8_t *loc, const Relocation &rel,
44+
uint64_t val) const override;
45+
};
46+
} // namespace
47+
48+
RelExpr EVM::getRelExpr(RelType type, const Symbol &s,
49+
const uint8_t *loc) const {
50+
switch (type) {
51+
case R_EVM_DATA:
52+
return R_ABS;
53+
default:
54+
error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
55+
") against symbol " + toString(s));
56+
return R_NONE;
57+
}
58+
}
59+
60+
void EVM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
61+
switch (rel.type) {
62+
case R_EVM_DATA: {
63+
if (val > std::numeric_limits<uint32_t>::max())
64+
llvm_unreachable("R_EVM_DATA: to big relocation value");
65+
write32be(loc, val);
66+
break;
67+
}
68+
default:
69+
llvm_unreachable("unknown relocation");
70+
}
71+
}
72+
73+
TargetInfo *elf::getEVMTargetInfo() {
74+
static EVM target;
75+
return &target;
76+
}
77+
78+
static uint32_t getEFlags(InputFile *file) {
79+
return cast<ObjFile<ELF32LE>>(file)->getObj().getHeader().e_flags;
80+
}
81+
82+
uint32_t EVM::calcEFlags() const {
83+
assert(!ctx.objectFiles.empty());
84+
85+
const uint32_t flags = getEFlags(ctx.objectFiles[0]);
86+
if (auto it = std::find_if_not(
87+
ctx.objectFiles.begin(), ctx.objectFiles.end(),
88+
[flags](InputFile *f) { return flags == getEFlags(f); });
89+
it != ctx.objectFiles.end())
90+
error(toString(*it) +
91+
": cannot link object files with incompatible target ISA");
92+
93+
return flags;
94+
}

lld/ELF/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ add_lld_library(lldELF
2424
Arch/AMDGPU.cpp
2525
Arch/ARM.cpp
2626
Arch/AVR.cpp
27+
Arch/EVM.cpp
2728
Arch/EraVM.cpp
2829
Arch/Hexagon.cpp
2930
Arch/LoongArch.cpp

lld/ELF/Driver.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
#include "llvm/Config/llvm-config.h"
5353
#include "llvm/LTO/LTO.h"
5454
#include "llvm/Object/Archive.h"
55+
// EVM local begin
56+
#include "llvm/Object/ELF.h"
57+
// EVM local end
5558
#include "llvm/Remarks/HotnessThresholdParser.h"
5659
#include "llvm/Support/CommandLine.h"
5760
#include "llvm/Support/Compression.h"

lld/ELF/InputFiles.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,6 +1614,10 @@ static uint16_t getBitcodeMachineKind(StringRef path, const Triple &t) {
16141614
return t.isOSIAMCU() ? EM_IAMCU : EM_386;
16151615
case Triple::x86_64:
16161616
return EM_X86_64;
1617+
// EVM local begin
1618+
case Triple::evm:
1619+
return EM_EVM;
1620+
// EVM local end
16171621
default:
16181622
error(path + ": could not infer e_machine from bitcode target triple " +
16191623
t.str());

lld/ELF/Target.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ TargetInfo *elf::getTarget() {
9191
return getSPARCV9TargetInfo();
9292
case EM_X86_64:
9393
return getX86_64TargetInfo();
94+
// EVM local begin
95+
case EM_EVM:
96+
return getEVMTargetInfo();
97+
// EVM local end
9498
}
9599
llvm_unreachable("unknown target machine");
96100
}

lld/ELF/Target.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ TargetInfo *getRISCVTargetInfo();
188188
TargetInfo *getSPARCV9TargetInfo();
189189
TargetInfo *getX86TargetInfo();
190190
TargetInfo *getX86_64TargetInfo();
191+
// EVM local begin
192+
TargetInfo *getEVMTargetInfo();
193+
// EVM local end
191194
template <class ELFT> TargetInfo *getMipsTargetInfo();
192195

193196
struct ErrorPlace {

0 commit comments

Comments
 (0)