xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF.cpp (revision aa1a8ff2d6dbc51ef058f46f3db5a8bb77967145)
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(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(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(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(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>("Truncated ELF buffer");
78 
79   if (memcmp(Buffer.data(), ELF::ElfMagic, strlen(ELF::ElfMagic)) != 0)
80     return make_error<JITLinkError>("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         "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(std::move(G), 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(std::move(G), std::move(Ctx));
124     return;
125   case Triple::loongarch32:
126   case Triple::loongarch64:
127     link_ELF_loongarch(std::move(G), std::move(Ctx));
128     return;
129   case Triple::ppc64:
130     link_ELF_ppc64(std::move(G), std::move(Ctx));
131     return;
132   case Triple::ppc64le:
133     link_ELF_ppc64le(std::move(G), std::move(Ctx));
134     return;
135   case Triple::riscv32:
136   case Triple::riscv64:
137     link_ELF_riscv(std::move(G), std::move(Ctx));
138     return;
139   case Triple::x86_64:
140     link_ELF_x86_64(std::move(G), std::move(Ctx));
141     return;
142   case Triple::x86:
143     link_ELF_i386(std::move(G), std::move(Ctx));
144     return;
145   default:
146     Ctx->notifyFailed(make_error<JITLinkError>(
147         "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