Use SymbolStringPtr for Symbol names in LinkGraph. This reduces string interning on the boundary between JITLink and ORC, and allows pointer comparisons (rather than string comparisons) between Symbol names. This should improve the performance and readability of code that bridges between JITLink and ORC (e.g. ObjectLinkingLayer and ObjectLinkingLayer::Plugins). To enable use of SymbolStringPtr a std::shared_ptr<SymbolStringPool> is added to LinkGraph and threaded through to its construction sites in LLVM and Bolt. All LinkGraphs that are to have symbol names compared by pointer equality must point to the same SymbolStringPool instance, which in ORC sessions should be the pool attached to the ExecutionSession. --------- Co-authored-by: Lang Hames <lhames@gmail.com>
154 lines
4.9 KiB
C++
154 lines
4.9 KiB
C++
//===-------------- ELF.cpp - JIT linker function for ELF -------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// ELF jit-link function.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ExecutionEngine/JITLink/ELF.h"
|
|
|
|
#include "llvm/BinaryFormat/ELF.h"
|
|
#include "llvm/ExecutionEngine/JITLink/ELF_aarch32.h"
|
|
#include "llvm/ExecutionEngine/JITLink/ELF_aarch64.h"
|
|
#include "llvm/ExecutionEngine/JITLink/ELF_i386.h"
|
|
#include "llvm/ExecutionEngine/JITLink/ELF_loongarch.h"
|
|
#include "llvm/ExecutionEngine/JITLink/ELF_ppc64.h"
|
|
#include "llvm/ExecutionEngine/JITLink/ELF_riscv.h"
|
|
#include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h"
|
|
#include "llvm/Object/ELF.h"
|
|
#include <cstring>
|
|
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "jitlink"
|
|
|
|
namespace llvm {
|
|
namespace jitlink {
|
|
|
|
Expected<uint16_t> readTargetMachineArch(StringRef Buffer) {
|
|
const char *Data = Buffer.data();
|
|
|
|
if (Data[ELF::EI_DATA] == ELF::ELFDATA2LSB) {
|
|
if (Data[ELF::EI_CLASS] == ELF::ELFCLASS64) {
|
|
if (auto File = llvm::object::ELF64LEFile::create(Buffer)) {
|
|
return File->getHeader().e_machine;
|
|
} else {
|
|
return File.takeError();
|
|
}
|
|
} else if (Data[ELF::EI_CLASS] == ELF::ELFCLASS32) {
|
|
if (auto File = llvm::object::ELF32LEFile::create(Buffer)) {
|
|
return File->getHeader().e_machine;
|
|
} else {
|
|
return File.takeError();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Data[ELF::EI_DATA] == ELF::ELFDATA2MSB) {
|
|
if (Data[ELF::EI_CLASS] == ELF::ELFCLASS64) {
|
|
if (auto File = llvm::object::ELF64BEFile::create(Buffer)) {
|
|
return File->getHeader().e_machine;
|
|
} else {
|
|
return File.takeError();
|
|
}
|
|
} else if (Data[ELF::EI_CLASS] == ELF::ELFCLASS32) {
|
|
if (auto File = llvm::object::ELF32BEFile::create(Buffer)) {
|
|
return File->getHeader().e_machine;
|
|
} else {
|
|
return File.takeError();
|
|
}
|
|
}
|
|
}
|
|
|
|
return ELF::EM_NONE;
|
|
}
|
|
|
|
Expected<std::unique_ptr<LinkGraph>>
|
|
createLinkGraphFromELFObject(MemoryBufferRef ObjectBuffer,
|
|
std::shared_ptr<orc::SymbolStringPool> SSP) {
|
|
StringRef Buffer = ObjectBuffer.getBuffer();
|
|
if (Buffer.size() < ELF::EI_NIDENT)
|
|
return make_error<JITLinkError>("Truncated ELF buffer");
|
|
|
|
if (memcmp(Buffer.data(), ELF::ElfMagic, strlen(ELF::ElfMagic)) != 0)
|
|
return make_error<JITLinkError>("ELF magic not valid");
|
|
|
|
uint8_t DataEncoding = Buffer.data()[ELF::EI_DATA];
|
|
Expected<uint16_t> TargetMachineArch = readTargetMachineArch(Buffer);
|
|
if (!TargetMachineArch)
|
|
return TargetMachineArch.takeError();
|
|
|
|
switch (*TargetMachineArch) {
|
|
case ELF::EM_AARCH64:
|
|
return createLinkGraphFromELFObject_aarch64(ObjectBuffer, std::move(SSP));
|
|
case ELF::EM_ARM:
|
|
return createLinkGraphFromELFObject_aarch32(ObjectBuffer, std::move(SSP));
|
|
case ELF::EM_PPC64: {
|
|
if (DataEncoding == ELF::ELFDATA2LSB)
|
|
return createLinkGraphFromELFObject_ppc64le(ObjectBuffer, std::move(SSP));
|
|
else
|
|
return createLinkGraphFromELFObject_ppc64(ObjectBuffer, std::move(SSP));
|
|
}
|
|
case ELF::EM_LOONGARCH:
|
|
return createLinkGraphFromELFObject_loongarch(ObjectBuffer, std::move(SSP));
|
|
case ELF::EM_RISCV:
|
|
return createLinkGraphFromELFObject_riscv(ObjectBuffer, std::move(SSP));
|
|
case ELF::EM_X86_64:
|
|
return createLinkGraphFromELFObject_x86_64(ObjectBuffer, std::move(SSP));
|
|
case ELF::EM_386:
|
|
return createLinkGraphFromELFObject_i386(ObjectBuffer, std::move(SSP));
|
|
default:
|
|
return make_error<JITLinkError>(
|
|
"Unsupported target machine architecture in ELF object " +
|
|
ObjectBuffer.getBufferIdentifier());
|
|
}
|
|
}
|
|
|
|
void link_ELF(std::unique_ptr<LinkGraph> G,
|
|
std::unique_ptr<JITLinkContext> Ctx) {
|
|
switch (G->getTargetTriple().getArch()) {
|
|
case Triple::aarch64:
|
|
link_ELF_aarch64(std::move(G), std::move(Ctx));
|
|
return;
|
|
case Triple::arm:
|
|
case Triple::armeb:
|
|
case Triple::thumb:
|
|
case Triple::thumbeb:
|
|
link_ELF_aarch32(std::move(G), std::move(Ctx));
|
|
return;
|
|
case Triple::loongarch32:
|
|
case Triple::loongarch64:
|
|
link_ELF_loongarch(std::move(G), std::move(Ctx));
|
|
return;
|
|
case Triple::ppc64:
|
|
link_ELF_ppc64(std::move(G), std::move(Ctx));
|
|
return;
|
|
case Triple::ppc64le:
|
|
link_ELF_ppc64le(std::move(G), std::move(Ctx));
|
|
return;
|
|
case Triple::riscv32:
|
|
case Triple::riscv64:
|
|
link_ELF_riscv(std::move(G), std::move(Ctx));
|
|
return;
|
|
case Triple::x86_64:
|
|
link_ELF_x86_64(std::move(G), std::move(Ctx));
|
|
return;
|
|
case Triple::x86:
|
|
link_ELF_i386(std::move(G), std::move(Ctx));
|
|
return;
|
|
default:
|
|
Ctx->notifyFailed(make_error<JITLinkError>(
|
|
"Unsupported target machine architecture in ELF link graph " +
|
|
G->getName()));
|
|
return;
|
|
}
|
|
}
|
|
|
|
} // end namespace jitlink
|
|
} // end namespace llvm
|