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_loongarch.h" |
19 | #include "llvm/ExecutionEngine/JITLink/ELF_ppc64.h" |
20 | #include "llvm/ExecutionEngine/JITLink/ELF_riscv.h" |
21 | #include "llvm/ExecutionEngine/JITLink/ELF_x86.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(Object: 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(Object: 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(Object: 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(Object: 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>(Args: "Truncated ELF buffer" ); |
77 | |
78 | if (memcmp(s1: Buffer.data(), s2: ELF::ElfMagic, n: strlen(s: ELF::ElfMagic)) != 0) |
79 | return make_error<JITLinkError>(Args: "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, SSP: std::move(SSP)); |
89 | case ELF::EM_ARM: |
90 | return createLinkGraphFromELFObject_aarch32(ObjectBuffer, SSP: std::move(SSP)); |
91 | case ELF::EM_PPC64: { |
92 | if (DataEncoding == ELF::ELFDATA2LSB) |
93 | return createLinkGraphFromELFObject_ppc64le(ObjectBuffer, SSP: std::move(SSP)); |
94 | else |
95 | return createLinkGraphFromELFObject_ppc64(ObjectBuffer, SSP: std::move(SSP)); |
96 | } |
97 | case ELF::EM_LOONGARCH: |
98 | return createLinkGraphFromELFObject_loongarch(ObjectBuffer, SSP: std::move(SSP)); |
99 | case ELF::EM_RISCV: |
100 | return createLinkGraphFromELFObject_riscv(ObjectBuffer, SSP: std::move(SSP)); |
101 | case ELF::EM_X86_64: |
102 | return createLinkGraphFromELFObject_x86_64(ObjectBuffer, SSP: std::move(SSP)); |
103 | case ELF::EM_386: |
104 | return createLinkGraphFromELFObject_x86(ObjectBuffer, SSP: std::move(SSP)); |
105 | default: |
106 | return make_error<JITLinkError>( |
107 | Args: "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(G: std::move(G), Ctx: 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(G: std::move(G), Ctx: std::move(Ctx)); |
123 | return; |
124 | case Triple::loongarch32: |
125 | case Triple::loongarch64: |
126 | link_ELF_loongarch(G: std::move(G), Ctx: std::move(Ctx)); |
127 | return; |
128 | case Triple::ppc64: |
129 | link_ELF_ppc64(G: std::move(G), Ctx: std::move(Ctx)); |
130 | return; |
131 | case Triple::ppc64le: |
132 | link_ELF_ppc64le(G: std::move(G), Ctx: std::move(Ctx)); |
133 | return; |
134 | case Triple::riscv32: |
135 | case Triple::riscv64: |
136 | link_ELF_riscv(G: std::move(G), Ctx: std::move(Ctx)); |
137 | return; |
138 | case Triple::x86_64: |
139 | link_ELF_x86_64(G: std::move(G), Ctx: std::move(Ctx)); |
140 | return; |
141 | case Triple::x86: |
142 | link_ELF_x86(G: std::move(G), Ctx: std::move(Ctx)); |
143 | return; |
144 | default: |
145 | Ctx->notifyFailed(Err: make_error<JITLinkError>( |
146 | Args: "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 | |