This patch replaces the dependency on `libelf` with LLVM's ELF support.
With this patch the user no-longer needs to have `libelf` on their
system to build and configure OpenMP offloading. The replacement is
mostly mechanical, with the exception of the hash table support which
was added in D131309.
Depends on D131309
Reviewed By: JonChesterfield, saiislam
Differential Revision: https://reviews.llvm.org/D131401
# Try to detect in the system several dependencies required by the different
# components of libomptarget. These are the dependencies we have:
#
-# libelf : required by some targets to handle the ELF files at runtime.
# libffi : required to launch target kernels given function and argument
# pointers.
# CUDA : required to control offloading to NVIDIA GPUs.
endif()
################################################################################
-# Looking for libelf...
-################################################################################
-
-find_path (
- LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR
- NAMES
- libelf.h
- PATHS
- /usr/include
- /usr/local/include
- /opt/local/include
- /sw/include
- ENV CPATH
- PATH_SUFFIXES
- libelf)
-
-find_library (
- LIBOMPTARGET_DEP_LIBELF_LIBRARIES
- NAMES
- elf
- PATHS
- /usr/lib
- /usr/local/lib
- /opt/local/lib
- /sw/lib
- ENV LIBRARY_PATH
- ENV LD_LIBRARY_PATH)
-
-set(LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIRS ${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR})
-find_package_handle_standard_args(
- LIBOMPTARGET_DEP_LIBELF
- DEFAULT_MSG
- LIBOMPTARGET_DEP_LIBELF_LIBRARIES
- LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIRS)
-
-mark_as_advanced(
- LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIRS
- LIBOMPTARGET_DEP_LIBELF_LIBRARIES)
-
-################################################################################
# Looking for libffi...
################################################################################
find_package(PkgConfig)
# - tmachine_libname: machine name to be appended to the plugin library name.
macro(build_generic_elf64 tmachine tmachine_name tmachine_libname tmachine_triple elf_machine_id)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "${tmachine}$")
- if(LIBOMPTARGET_DEP_LIBELF_FOUND)
- if(LIBOMPTARGET_DEP_LIBFFI_FOUND)
+ if(LIBOMPTARGET_DEP_LIBFFI_FOUND)
- libomptarget_say("Building ${tmachine_name} offloading plugin.")
+ libomptarget_say("Building ${tmachine_name} offloading plugin.")
- # Define macro to be used as prefix of the runtime messages for this target.
- add_definitions("-DTARGET_NAME=${tmachine_name}")
+ # Define macro to be used as prefix of the runtime messages for this target.
+ add_definitions("-DTARGET_NAME=${tmachine_name}")
- # Define macro with the ELF ID for this target.
- add_definitions("-DTARGET_ELF_ID=${elf_machine_id}")
+ # Define macro with the ELF ID for this target.
+ add_definitions("-DTARGET_ELF_ID=${elf_machine_id}")
- add_llvm_library("omptarget.rtl.${tmachine_libname}"
- SHARED
+ add_llvm_library("omptarget.rtl.${tmachine_libname}"
+ SHARED
- ${CMAKE_CURRENT_SOURCE_DIR}/../generic-elf-64bit/src/rtl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/../generic-elf-64bit/src/rtl.cpp
- ADDITIONAL_HEADER_DIRS
- ${LIBOMPTARGET_INCLUDE_DIR}
- ${LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIR}
- ${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR}
+ ADDITIONAL_HEADER_DIRS
+ ${LIBOMPTARGET_INCLUDE_DIR}
+ ${LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIR}
LINK_LIBS
PRIVATE
elf_common
${LIBOMPTARGET_DEP_LIBFFI_LIBRARIES}
- ${LIBOMPTARGET_DEP_LIBELF_LIBRARIES}
${OPENMP_PTHREAD_LIB}
"-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exports"
- NO_INSTALL_RPATH
- )
-
- # Install plugin under the lib destination folder.
- install(TARGETS "omptarget.rtl.${tmachine_libname}"
- LIBRARY DESTINATION "${OPENMP_INSTALL_LIBDIR}")
- set_target_properties("omptarget.rtl.${tmachine_libname}" PROPERTIES
- INSTALL_RPATH "$ORIGIN" BUILD_RPATH "$ORIGIN:${CMAKE_CURRENT_BINARY_DIR}/..")
-
- target_include_directories( "omptarget.rtl.${tmachine_libname}" PRIVATE
- ${LIBOMPTARGET_INCLUDE_DIR}
- ${LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIR}
- ${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR})
-
- list(APPEND LIBOMPTARGET_TESTED_PLUGINS
- "omptarget.rtl.${tmachine_libname}")
-
- # Report to the parent scope that we are building a plugin.
- set(LIBOMPTARGET_SYSTEM_TARGETS
- "${LIBOMPTARGET_SYSTEM_TARGETS} ${tmachine_triple} ${tmachine_triple}-oldDriver" PARENT_SCOPE)
- set(LIBOMPTARGET_SYSTEM_TARGETS
- "${LIBOMPTARGET_SYSTEM_TARGETS} ${tmachine_triple} ${tmachine_triple}-LTO" PARENT_SCOPE)
- set(LIBOMPTARGET_TESTED_PLUGINS
- "${LIBOMPTARGET_TESTED_PLUGINS}" PARENT_SCOPE)
-
- else(LIBOMPTARGET_DEP_LIBFFI_FOUND)
- libomptarget_say("Not building ${tmachine_name} offloading plugin: libffi dependency not found.")
- endif(LIBOMPTARGET_DEP_LIBFFI_FOUND)
- else(LIBOMPTARGET_DEP_LIBELF_FOUND)
- libomptarget_say("Not building ${tmachine_name} offloading plugin: libelf dependency not found.")
- endif(LIBOMPTARGET_DEP_LIBELF_FOUND)
+ NO_INSTALL_RPATH
+ )
+
+ # Install plugin under the lib destination folder.
+ install(TARGETS "omptarget.rtl.${tmachine_libname}"
+ LIBRARY DESTINATION "${OPENMP_INSTALL_LIBDIR}")
+ set_target_properties("omptarget.rtl.${tmachine_libname}" PROPERTIES
+ INSTALL_RPATH "$ORIGIN" BUILD_RPATH "$ORIGIN:${CMAKE_CURRENT_BINARY_DIR}/..")
+
+ target_include_directories( "omptarget.rtl.${tmachine_libname}" PRIVATE
+ ${LIBOMPTARGET_INCLUDE_DIR}
+ ${LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIR})
+
+ list(APPEND LIBOMPTARGET_TESTED_PLUGINS
+ "omptarget.rtl.${tmachine_libname}")
+
+ # Report to the parent scope that we are building a plugin.
+ set(LIBOMPTARGET_SYSTEM_TARGETS
+ "${LIBOMPTARGET_SYSTEM_TARGETS} ${tmachine_triple} ${tmachine_triple}-oldDriver" PARENT_SCOPE)
+ set(LIBOMPTARGET_SYSTEM_TARGETS
+ "${LIBOMPTARGET_SYSTEM_TARGETS} ${tmachine_triple} ${tmachine_triple}-LTO" PARENT_SCOPE)
+ set(LIBOMPTARGET_TESTED_PLUGINS
+ "${LIBOMPTARGET_TESTED_PLUGINS}" PARENT_SCOPE)
+
+ else(LIBOMPTARGET_DEP_LIBFFI_FOUND)
+ libomptarget_say("Not building ${tmachine_name} offloading plugin: libffi dependency not found.")
+ endif(LIBOMPTARGET_DEP_LIBFFI_FOUND)
else()
libomptarget_say("Not building ${tmachine_name} offloading plugin: machine not found in the system.")
endif()
# as of rocm-3.7, hsa is installed with cmake packages and kmt is found via hsa
find_package(hsa-runtime64 QUIET 1.2.0 HINTS ${CMAKE_INSTALL_PREFIX} PATHS /opt/rocm)
-if(NOT LIBOMPTARGET_DEP_LIBELF_FOUND)
- libomptarget_say("Not building AMDGPU plugin: LIBELF not found")
- return()
-endif()
-
if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(ppc64le)|(aarch64)$" AND CMAKE_SYSTEM_NAME MATCHES "Linux")
libomptarget_say("Not building AMDGPU plugin: only support AMDGPU in Linux x86_64, ppc64le, or aarch64 hosts")
return()
PRIVATE
elf_common
${LIBOMPTARGET_DEP_LIBRARIES}
- ${LIBOMPTARGET_DEP_LIBELF_LIBRARIES}
${OPENMP_PTHREAD_LIB}
"-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exports"
${LDFLAGS_UNDEFINED}
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
-#include <libelf.h>
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Object/ELFObjectFile.h"
#include <cassert>
#include <sstream>
#include "msgpack.h"
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
namespace hsa {
// Wrap HSA iterate API in a shim that allows passing general callables
template <typename C>
}
}
-static std::pair<unsigned char *, unsigned char *>
-find_metadata(void *binary, size_t binSize) {
- std::pair<unsigned char *, unsigned char *> failure = {nullptr, nullptr};
-
- Elf *e = elf_memory(static_cast<char *>(binary), binSize);
- if (elf_kind(e) != ELF_K_ELF) {
- return failure;
+static std::pair<const unsigned char *, const unsigned char *>
+findMetadata(const ELFObjectFile<ELF64LE> &ELFObj) {
+ constexpr std::pair<const unsigned char *, const unsigned char *> Failure = {
+ nullptr, nullptr};
+ const auto &Elf = ELFObj.getELFFile();
+ auto PhdrsOrErr = Elf.program_headers();
+ if (!PhdrsOrErr) {
+ consumeError(PhdrsOrErr.takeError());
+ return Failure;
}
- size_t numpHdrs;
- if (elf_getphdrnum(e, &numpHdrs) != 0) {
- return failure;
- }
+ for (auto Phdr : *PhdrsOrErr) {
+ if (Phdr.p_type != PT_NOTE)
+ continue;
- Elf64_Phdr *pHdrs = elf64_getphdr(e);
- for (size_t i = 0; i < numpHdrs; ++i) {
- Elf64_Phdr pHdr = pHdrs[i];
-
- // Look for the runtime metadata note
- if (pHdr.p_type == PT_NOTE && pHdr.p_align >= sizeof(int)) {
- // Iterate over the notes in this segment
- address ptr = (address)binary + pHdr.p_offset;
- address segmentEnd = ptr + pHdr.p_filesz;
-
- while (ptr < segmentEnd) {
- Elf_Note *note = reinterpret_cast<Elf_Note *>(ptr);
- address name = (address)¬e[1];
-
- if (note->n_type == 7 || note->n_type == 8) {
- return failure;
- } else if (note->n_type == 10 /* NT_AMD_AMDGPU_HSA_METADATA */ &&
- note->n_namesz == sizeof "AMD" &&
- !memcmp(name, "AMD", note->n_namesz)) {
- // code object v2 uses yaml metadata, no longer supported
- return failure;
- } else if (note->n_type == 32 /* NT_AMDGPU_METADATA */ &&
- note->n_namesz == sizeof "AMDGPU" &&
- !memcmp(name, "AMDGPU", note->n_namesz)) {
-
- // n_descsz = 485
- // value is padded to 4 byte alignment, may want to move end up to
- // match
- size_t offset = sizeof(uint32_t) * 3 /* fields */
- + sizeof("AMDGPU") /* name */
- + 1 /* padding to 4 byte alignment */;
-
- // Including the trailing padding means both pointers are 4 bytes
- // aligned, which may be useful later.
- unsigned char *metadata_start = (unsigned char *)ptr + offset;
- unsigned char *metadata_end =
- metadata_start + core::alignUp(note->n_descsz, 4);
- return {metadata_start, metadata_end};
- }
- ptr += sizeof(*note) + core::alignUp(note->n_namesz, sizeof(int)) +
- core::alignUp(note->n_descsz, sizeof(int));
- }
+ Error Err = Error::success();
+ for (auto Note : Elf.notes(Phdr, Err)) {
+ if (Note.getType() == 7 || Note.getType() == 8)
+ return Failure;
+
+ // Code object v2 uses yaml metadata and is no longer supported.
+ if (Note.getType() == NT_AMD_HSA_METADATA && Note.getName() == "AMD")
+ return Failure;
+ // Code object v3 should have AMDGPU metadata.
+ if (Note.getType() == NT_AMDGPU_METADATA && Note.getName() != "AMDGPU")
+ return Failure;
+
+ ArrayRef<uint8_t> Desc = Note.getDesc();
+ return {Desc.data(), Desc.data() + Desc.size()};
+ }
+
+ if (Err) {
+ consumeError(std::move(Err));
+ return Failure;
}
}
- return failure;
+ return Failure;
+}
+
+static std::pair<const unsigned char *, const unsigned char *>
+find_metadata(void *binary, size_t binSize) {
+ constexpr std::pair<const unsigned char *, const unsigned char *> Failure = {
+ nullptr, nullptr};
+
+ StringRef Buffer = StringRef(static_cast<const char *>(binary), binSize);
+ auto ElfOrErr = ObjectFile::createELFObjectFile(MemoryBufferRef(Buffer, ""),
+ /*InitContent=*/false);
+ if (!ElfOrErr) {
+ consumeError(ElfOrErr.takeError());
+ return Failure;
+ }
+
+ if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(ElfOrErr->get()))
+ return findMetadata(*ELFObj);
+ return Failure;
}
namespace {
// also, the kernel name is not the same as the symbol name -- so a
// symbol->name map is needed
- std::pair<unsigned char *, unsigned char *> metadata =
+ std::pair<const unsigned char *, const unsigned char *> metadata =
find_metadata(binary, binSize);
if (!metadata.first) {
return HSA_STATUS_ERROR_INVALID_CODE_OBJECT;
#include <cstdlib>
#include <cstring>
#include <functional>
-#include <libelf.h>
#include <list>
#include <memory>
#include <mutex>
using namespace llvm;
using namespace llvm::object;
+using namespace llvm::ELF;
// hostrpc interface, FIXME: consider moving to its own include these are
// statically linked into amdgpu/plugin if present from hostrpc_services.a,
}
bool elfMachineIdIsAmdgcn(__tgt_device_image *Image) {
- const uint16_t AmdgcnMachineID = 224; // EM_AMDGPU may not be in system elf.h
- int32_t R = elf_check_machine(Image, AmdgcnMachineID);
+ const uint16_t AmdgcnMachineID = EM_AMDGPU;
+ const int32_t R = elf_check_machine(Image, AmdgcnMachineID);
if (!R) {
DP("Supported machine ID not found\n");
}
}
uint32_t elfEFlags(__tgt_device_image *Image) {
- char *ImgBegin = (char *)Image->ImageStart;
+ const char *ImgBegin = (char *)Image->ImageStart;
size_t ImgSize = (char *)Image->ImageEnd - ImgBegin;
- Elf *E = elf_memory(ImgBegin, ImgSize);
- if (!E) {
- DP("Unable to get ELF handle: %s!\n", elf_errmsg(-1));
- return 0;
- }
-
- Elf64_Ehdr *Eh64 = elf64_getehdr(E);
-
- if (!Eh64) {
- DP("Unable to get machine ID from ELF file!\n");
- elf_end(E);
+ StringRef Buffer = StringRef(ImgBegin, ImgSize);
+ auto ElfOrErr = ObjectFile::createELFObjectFile(MemoryBufferRef(Buffer, ""),
+ /*InitContent=*/false);
+ if (!ElfOrErr) {
+ consumeError(ElfOrErr.takeError());
return 0;
}
- uint32_t Flags = Eh64->e_flags;
-
- elf_end(E);
- DP("ELF Flags: 0x%x\n", Flags);
- return Flags;
+ if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(ElfOrErr->get()))
+ return ELFObj->getPlatformFlags();
+ return 0;
}
template <typename T> bool enforceUpperBound(T *Value, T Upper) {
if (NOT(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(ppc64le)|(aarch64)$" AND CMAKE_SYSTEM_NAME MATCHES "Linux"))
libomptarget_say("Not building CUDA offloading plugin: only support CUDA in Linux x86_64, ppc64le, or aarch64 hosts.")
return()
-elseif (NOT LIBOMPTARGET_DEP_LIBELF_FOUND)
- libomptarget_say("Not building CUDA offloading plugin: libelf dependency not found.")
- return()
endif()
libomptarget_say("Building CUDA offloading plugin.")
ADDITIONAL_HEADER_DIRS
${LIBOMPTARGET_INCLUDE_DIR}
- ${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIRS}
LINK_LIBS
PRIVATE
elf_common
MemoryManager
${LIBOMPTARGET_DEP_CUDA_DRIVER_LIBRARIES}
- ${LIBOMPTARGET_DEP_LIBELF_LIBRARIES}
${OPENMP_PTHREAD_LIB}
"-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exports"
"-Wl,-z,defs"
ADDITIONAL_HEADER_DIRS
${LIBOMPTARGET_INCLUDE_DIR}
- ${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIRS}
LINK_LIBS
PRIVATE
elf_common
MemoryManager
- ${LIBOMPTARGET_DEP_LIBELF_LIBRARIES}
${OPENMP_PTHREAD_LIB}
"-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exports"
"-Wl,-z,defs"
target_include_directories(omptarget.rtl.cuda PRIVATE
${LIBOMPTARGET_INCLUDE_DIR}
- ${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIRS}
)
# Report to the parent scope that we are building a plugin for CUDA.
#include "elf_common.h"
#define NUMBER_OF_DEVICES 4
-#define OFFLOADSECTIONNAME "omp_offloading_entries"
+#define OFFLOAD_SECTION_NAME "omp_offloading_entries"
/// Array of Dynamic libraries loaded for this target.
struct DynLibTy {
size_t ImageSize = (size_t)Image->ImageEnd - (size_t)Image->ImageStart;
size_t NumEntries = (size_t)(Image->EntriesEnd - Image->EntriesBegin);
- DP("Expecting to have %zd entries defined.\n", NumEntries);
// load dynamic library and get the entry points. We use the dl library
// to do the loading of the library, but we could do it directly to avoid the
ADDITIONAL_HEADER_DIRS
${LIBOMPTARGET_INCLUDE_DIR}
- ${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR}
${LIBOMPTARGET_DEP_VEO_INCLUDE_DIR}
LINK_LIBS
PRIVATE
elf_common
${LIBOMPTARGET_DEP_LIBFFI_LIBRARIES}
- ${LIBOMPTARGET_DEP_LIBELF_LIBRARIES}
${additional_libs}
"-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exports -Wl,-z,defs"
target_include_directories("omptarget.rtl.${tmachine_libname}" PRIVATE
${LIBOMPTARGET_INCLUDE_DIR}
- ${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR}
${LIBOMPTARGET_DEP_VEO_INCLUDE_DIR})
target_link_libraries(
"omptarget.rtl.${tmachine_libname}"
elf_common
${LIBOMPTARGET_DEP_LIBFFI_LIBRARIES}
- ${LIBOMPTARGET_DEP_LIBELF_LIBRARIES}
${additional_libs}
"-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exports -Wl,-z,defs")