xref: /llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF.cpp (revision 2ccf7ed277df28651b94bbee9fccefdf22fb074f)
1 //===-------------- ELF.cpp - JIT linker function for ELF -------------===//
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 // ELF jit-link function.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/ExecutionEngine/JITLink/ELF.h"
14 
15 #include "llvm/BinaryFormat/ELF.h"
16 #include "llvm/ExecutionEngine/JITLink/ELF_aarch32.h"
17 #include "llvm/ExecutionEngine/JITLink/ELF_aarch64.h"
18 #include "llvm/ExecutionEngine/JITLink/ELF_i386.h"
19 #include "llvm/ExecutionEngine/JITLink/ELF_loongarch.h"
20 #include "llvm/ExecutionEngine/JITLink/ELF_ppc64.h"
21 #include "llvm/ExecutionEngine/JITLink/ELF_riscv.h"
22 #include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h"
23 #include "llvm/Object/ELF.h"
24 #include <cstring>
25 
26 using namespace llvm;
27 
28 #define DEBUG_TYPE "jitlink"
29 
30 namespace llvm {
31 namespace jitlink {
32 
33 Expected<uint16_t> readTargetMachineArch(StringRef Buffer) {
34   const char *Data = Buffer.data();
35 
36   if (Data[ELF::EI_DATA] == ELF::ELFDATA2LSB) {
37     if (Data[ELF::EI_CLASS] == ELF::ELFCLASS64) {
38       if (auto File = llvm::object::ELF64LEFile::create(Buffer)) {
39         return File->getHeader().e_machine;
40       } else {
41         return File.takeError();
42       }
43     } else if (Data[ELF::EI_CLASS] == ELF::ELFCLASS32) {
44       if (auto File = llvm::object::ELF32LEFile::create(Buffer)) {
45         return File->getHeader().e_machine;
46       } else {
47         return File.takeError();
48       }
49     }
50   }
51 
52   if (Data[ELF::EI_DATA] == ELF::ELFDATA2MSB) {
53     if (Data[ELF::EI_CLASS] == ELF::ELFCLASS64) {
54       if (auto File = llvm::object::ELF64BEFile::create(Buffer)) {
55         return File->getHeader().e_machine;
56       } else {
57         return File.takeError();
58       }
59     } else if (Data[ELF::EI_CLASS] == ELF::ELFCLASS32) {
60       if (auto File = llvm::object::ELF32BEFile::create(Buffer)) {
61         return File->getHeader().e_machine;
62       } else {
63         return File.takeError();
64       }
65     }
66   }
67 
68   return ELF::EM_NONE;
69 }
70 
71 Expected<std::unique_ptr<LinkGraph>>
72 createLinkGraphFromELFObject(MemoryBufferRef ObjectBuffer,
73                              std::shared_ptr<orc::SymbolStringPool> SSP) {
74   StringRef Buffer = ObjectBuffer.getBuffer();
75   if (Buffer.size() < ELF::EI_NIDENT)
76     return make_error<JITLinkError>("Truncated ELF buffer");
77 
78   if (memcmp(Buffer.data(), ELF::ElfMagic, strlen(ELF::ElfMagic)) != 0)
79     return make_error<JITLinkError>("ELF magic not valid");
80 
81   uint8_t DataEncoding = Buffer.data()[ELF::EI_DATA];
82   Expected<uint16_t> TargetMachineArch = readTargetMachineArch(Buffer);
83   if (!TargetMachineArch)
84     return TargetMachineArch.takeError();
85 
86   switch (*TargetMachineArch) {
87   case ELF::EM_AARCH64:
88     return createLinkGraphFromELFObject_aarch64(ObjectBuffer, std::move(SSP));
89   case ELF::EM_ARM:
90     return createLinkGraphFromELFObject_aarch32(ObjectBuffer, std::move(SSP));
91   case ELF::EM_PPC64: {
92     if (DataEncoding == ELF::ELFDATA2LSB)
93       return createLinkGraphFromELFObject_ppc64le(ObjectBuffer, std::move(SSP));
94     else
95       return createLinkGraphFromELFObject_ppc64(ObjectBuffer, std::move(SSP));
96   }
97   case ELF::EM_LOONGARCH:
98     return createLinkGraphFromELFObject_loongarch(ObjectBuffer, std::move(SSP));
99   case ELF::EM_RISCV:
100     return createLinkGraphFromELFObject_riscv(ObjectBuffer, std::move(SSP));
101   case ELF::EM_X86_64:
102     return createLinkGraphFromELFObject_x86_64(ObjectBuffer, std::move(SSP));
103   case ELF::EM_386:
104     return createLinkGraphFromELFObject_i386(ObjectBuffer, std::move(SSP));
105   default:
106     return make_error<JITLinkError>(
107         "Unsupported target machine architecture in ELF object " +
108         ObjectBuffer.getBufferIdentifier());
109   }
110 }
111 
112 void link_ELF(std::unique_ptr<LinkGraph> G,
113               std::unique_ptr<JITLinkContext> Ctx) {
114   switch (G->getTargetTriple().getArch()) {
115   case Triple::aarch64:
116     link_ELF_aarch64(std::move(G), std::move(Ctx));
117     return;
118   case Triple::arm:
119   case Triple::armeb:
120   case Triple::thumb:
121   case Triple::thumbeb:
122     link_ELF_aarch32(std::move(G), std::move(Ctx));
123     return;
124   case Triple::loongarch32:
125   case Triple::loongarch64:
126     link_ELF_loongarch(std::move(G), std::move(Ctx));
127     return;
128   case Triple::ppc64:
129     link_ELF_ppc64(std::move(G), std::move(Ctx));
130     return;
131   case Triple::ppc64le:
132     link_ELF_ppc64le(std::move(G), std::move(Ctx));
133     return;
134   case Triple::riscv32:
135   case Triple::riscv64:
136     link_ELF_riscv(std::move(G), std::move(Ctx));
137     return;
138   case Triple::x86_64:
139     link_ELF_x86_64(std::move(G), std::move(Ctx));
140     return;
141   case Triple::x86:
142     link_ELF_i386(std::move(G), std::move(Ctx));
143     return;
144   default:
145     Ctx->notifyFailed(make_error<JITLinkError>(
146         "Unsupported target machine architecture in ELF link graph " +
147         G->getName()));
148     return;
149   }
150 }
151 
152 } // end namespace jitlink
153 } // end namespace llvm
154