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