vzakhari updated this revision to Diff 333378.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D99360/new/

https://reviews.llvm.org/D99360

Files:
  clang/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp
  llvm/include/llvm/BinaryFormat/ELF.h
  llvm/tools/llvm-readobj/ELFDumper.cpp
  openmp/libomptarget/plugins/amdgpu/CMakeLists.txt
  openmp/libomptarget/plugins/common/elf_common/CMakeLists.txt
  openmp/libomptarget/plugins/common/elf_common/elf_common.cpp
  openmp/libomptarget/plugins/common/elf_common/elf_common.h
  openmp/libomptarget/plugins/common/elf_common/elf_constants.h
  openmp/libomptarget/plugins/common/elf_common/elf_light.cpp
  openmp/libomptarget/plugins/common/elf_common/elf_light.h
  openmp/libomptarget/plugins/remote/server/CMakeLists.txt

Index: openmp/libomptarget/plugins/remote/server/CMakeLists.txt
===================================================================
--- openmp/libomptarget/plugins/remote/server/CMakeLists.txt
+++ openmp/libomptarget/plugins/remote/server/CMakeLists.txt
@@ -10,7 +10,6 @@
 #
 ##===----------------------------------------------------------------------===##
 
-include_directories(${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIRS})
 include_directories(${LIBOMPTARGET_SRC_DIR})
 include_directories(${LIBOMPTARGET_INCLUDE_DIR})
 include_directories(${GRPC_INCLUDE_DIR})
@@ -28,4 +27,4 @@
         grpc++
         protobuf
         ${OPENMP_PTHREAD_LIB}
-        "-ldl" "-lomp" "-fopenmp" "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../../exports" ${LIBOMPTARGET_DEP_LIBELF_LIBRARIES})
+        "-ldl" "-lomp" "-fopenmp" "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../../exports")
Index: openmp/libomptarget/plugins/common/elf_common/elf_light.h
===================================================================
--- /dev/null
+++ openmp/libomptarget/plugins/common/elf_common/elf_light.h
@@ -0,0 +1,122 @@
+//===-- elf_light.h - Basic ELF functionality -------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Light ELF implementation provides basic ELF reading functionality.
+// It may be used in systems without libelf support, if the corresponding
+// LLVM ELF implementation is available.
+// The interface declared here must be independent of libelf.h/elf.h.
+//
+// NOTE: we can try to rely on https://github.com/WolfgangSt/libelf
+//       on Windows, if this implementation gets more complex.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LIBOMPTARGET_PLUGINS_ELF_LIGHT_H
+#define LIBOMPTARGET_PLUGINS_ELF_LIGHT_H
+
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+
+class ElfL;
+class ElfLSegmentNoteIterator;
+class ElfLSectionNoteIterator;
+class ElfNote;
+
+// Class representing NOTEs from PT_NOTE segments and SHT_NOTE sections.
+class ElfLNote {
+  const void *Impl = nullptr;
+
+  friend class ElfLSegmentNoteIterator;
+  friend class ElfLSectionNoteIterator;
+
+  // Only ElfLSectionNoteIterator is allowed to create notes via its operator*().
+  explicit ElfLNote(const void *I);
+  ElfLNote &operator=(const ElfLNote &) = delete;
+
+public:
+  // FIXME: add move copy constructor and assignment operator.
+  ElfLNote(const ElfLNote &);
+  ~ElfLNote();
+  uint64_t getNameSize() const;
+  const char *getName() const;
+  uint64_t getDescSize() const;
+  const uint8_t *getDesc() const;
+  uint64_t getType() const;
+};
+
+// Iterator over NOTEs in PT_NOTE segments.
+class ElfLSegmentNoteIterator
+    : std::iterator<std::forward_iterator_tag, ElfLNote> {
+
+  void *Impl = nullptr;
+
+  friend class ElfL;
+
+  // Only ElfL is allowed to create iterators to itself.
+  ElfLSegmentNoteIterator(const void *I, bool IsEnd = false);
+  ElfLSectionNoteIterator &operator=(const ElfLSegmentNoteIterator &) = delete;
+
+public:
+  // FIXME: add move copy constructor and assignment operator.
+  ElfLSegmentNoteIterator(const ElfLSegmentNoteIterator &Other);
+  ~ElfLSegmentNoteIterator();
+  ElfLSegmentNoteIterator &operator++();
+  bool operator==(const ElfLSegmentNoteIterator Other) const;
+  bool operator!=(const ElfLSegmentNoteIterator Other) const;
+  ElfLNote operator*() const;
+};
+
+// Iterator over NOTEs in SHT_NOTE sections.
+class ElfLSectionNoteIterator
+    : std::iterator<std::forward_iterator_tag, ElfLNote> {
+
+  void *Impl = nullptr;
+
+  friend class ElfL;
+
+  // Only ElfL is allowed to create iterators to itself.
+  ElfLSectionNoteIterator(const void *I, bool IsEnd = false);
+  ElfLSectionNoteIterator &operator=(const ElfLSectionNoteIterator &) = delete;
+
+public:
+  // FIXME: add move copy constructor and assignment operator.
+  ElfLSectionNoteIterator(const ElfLSectionNoteIterator &Other);
+  ~ElfLSectionNoteIterator();
+  ElfLSectionNoteIterator &operator++();
+  bool operator==(const ElfLSectionNoteIterator Other) const;
+  bool operator!=(const ElfLSectionNoteIterator Other) const;
+  ElfLNote operator*() const;
+};
+
+// Wrapper around the given ELF image.
+class ElfL {
+  // Opaque pointer to the actual implementation.
+  void *Impl = nullptr;
+
+  // FIXME: implement if needed.
+  ElfL(const ElfL &) = delete;
+  ElfL &operator=(const ElfL &) = delete;
+
+public:
+  ElfL(char *Begin, size_t Size);
+  ~ElfL();
+  bool isValidElf() const;
+  const char *getErrmsg(int N) const;
+  uint16_t getEMachine() const;
+  uint16_t getEType() const;
+
+  static bool isDynType(uint16_t Ty);
+
+  ElfLSectionNoteIterator section_notes_begin() const;
+  ElfLSectionNoteIterator section_notes_end() const;
+  ElfLSegmentNoteIterator segment_notes_begin() const;
+  ElfLSegmentNoteIterator segment_notes_end() const;
+};
+
+#endif  // LIBOMPTARGET_PLUGINS_ELF_LIGHT_H
Index: openmp/libomptarget/plugins/common/elf_common/elf_light.cpp
===================================================================
--- /dev/null
+++ openmp/libomptarget/plugins/common/elf_common/elf_light.cpp
@@ -0,0 +1,1281 @@
+//===-- elf_light.cpp - Basic ELF functionality -----------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+#include "Debug.h"
+#include "elf_light.h"
+
+#ifndef TARGET_NAME
+#define TARGET_NAME ELF light
+#endif
+#define DEBUG_PREFIX "TARGET " GETNAME(TARGET_NAME)
+
+#if MAY_USE_LIBELF
+
+// Implementation based on libelf.
+#include <gelf.h>
+#include <libelf.h>
+
+// Helper methods to align addresses.
+template <typename T> inline T alignDown(T value, size_t alignment) {
+  return (T)(value & ~(alignment - 1));
+}
+
+template <typename T> inline T *alignDown(T *value, size_t alignment) {
+  return reinterpret_cast<T *>(alignDown((intptr_t)value, alignment));
+}
+
+template <typename T> inline T alignUp(T value, size_t alignment) {
+  return alignDown((T)(value + alignment - 1), alignment);
+}
+
+template <typename T> inline T *alignUp(T *value, size_t alignment) {
+  return reinterpret_cast<T *>(
+      alignDown((intptr_t)(value + alignment - 1), alignment));
+}
+
+// FIXME: this is taken from openmp/libomptarget/plugins/amdgpu/impl/system.cpp,
+//        but it may be incorrect for 64-bit ELF. Elf64_Nhdr and Elf32_Nhdr
+//        have different representation. The alignment used for the name and
+//        the descriptor is still 4 bytes. At the same time, it seems to work
+//        for 64-bit ELFs produced by LLVM.
+typedef struct {
+  uint32_t n_namesz; // Length of note's name.
+  uint32_t n_descsz; // Length of note's value.
+  uint32_t n_type;   // Type of note.
+  // then name
+  // then padding, optional
+  // then desc, at 4 byte alignment (not 8, despite being elf64)
+} Elf_Note;
+
+static const uint32_t NoteAlignment = 4;
+
+// Implementation of the iterator for SHT_NOTE sections.
+// The iterator allows processing all NOTEs in all SHT_NOTE sections
+// in the ELF image provided during the iterator object construction.
+class ElfLSectionNoteIteratorImpl {
+  // A pointer to Elf object created by elf_memory() for
+  // the ELF image we are going to iterate.
+  Elf *EF;
+
+  // A pointer to the current SHT_NOTE section.
+  // In the initial state of the iterator object this will actually
+  // point to the very first section in the ELF image, but it will be
+  // adjusted right away either to point to the first SHT_NOTE section
+  // or set to nullptr (if there are no SHT_NOTE sections).
+  Elf_Scn *CurrentSection = nullptr;
+
+  // A pointer to the current NOTE inside a SHT_NOTE section
+  // pointed by CurrentSection. If it is nullptr, then this means
+  // that the iterator object is an end() iterator.
+  Elf_Note *NPtr = nullptr;
+
+  uint64_t getNotesBeginAddr(const GElf_Shdr &Shdr) const {
+    return reinterpret_cast<uint64_t>(elf_rawfile(EF, nullptr)) +
+        Shdr.sh_offset;
+  }
+
+  uint64_t getNotesEndAddr(const GElf_Shdr &Shdr) const {
+    return getNotesBeginAddr(Shdr) + Shdr.sh_size;
+  }
+
+  uint64_t getNoteSize(const Elf_Note &Note) const {
+    return sizeof(Note) + alignUp(Note.n_namesz, NoteAlignment) +
+        alignUp(Note.n_descsz, NoteAlignment);
+  }
+
+  // Given the current state of the iterator object, advances
+  // the iterator forward to point to the next NOTE in the next
+  // SHT_NOTE section.
+  // If there is no such a NOTE, then it sets the iterator
+  // object to the end() state.
+  //
+  // Note that this method does not change the iterator, if
+  // NPtr is pointing to a valid note within CurrentSection.
+  // The iterator advancement in this case is done via operator++.
+  void autoAdvance(bool IsFirst = false) {
+    // Cannot advance, if CurrentSection is NULL.
+    if (!CurrentSection)
+      return;
+
+    // NPtr points to a valid NOTE in CurrentSection, thus,
+    // no auto advancement.
+    if (NPtr)
+      return;
+
+    GElf_Shdr Shdr;
+    gelf_getshdr(CurrentSection, &Shdr);
+
+    // CurrentSection is a valid section, and NPtr is an end() iterator.
+    //
+    // If IsFirst is true, then we just in the initial state, and
+    // we need to set CurrentSection to the first SHT_NOTE section (if any),
+    // and, then, NPtr to the first note in this section.
+    //
+    // If IsFirst is false, then we've reached the end of the current
+    // SHT_NOTE section, and should find the next section with notes.
+    if (!IsFirst ||
+        gelf_getshdr(CurrentSection, &Shdr)->sh_type != SHT_NOTE)
+      CurrentSection = elf_nextscn(EF, CurrentSection);
+
+    while (CurrentSection &&
+           gelf_getshdr(CurrentSection, &Shdr)->sh_type != SHT_NOTE)
+      CurrentSection = elf_nextscn(EF, CurrentSection);
+
+    if (!CurrentSection) {
+      // No more sections.
+      // Note that NPtr is already nullptr indicating the end() iterator.
+      return;
+    }
+
+    gelf_getshdr(CurrentSection, &Shdr);
+    uint64_t NotesBegin = getNotesBeginAddr(Shdr);
+    uint64_t NotesEnd = getNotesEndAddr(Shdr);
+    if (NotesBegin >= NotesEnd) {
+      // Something went wrong. Assume that we've reached
+      // the end of all notes.
+      CurrentSection = nullptr;
+      NPtr = nullptr;
+      return;
+    }
+
+    NPtr = reinterpret_cast<Elf_Note *>(NotesBegin);
+    assert(NPtr && "Invalid SHT_NOTE section.");
+  }
+
+  bool operator!=(const ElfLSectionNoteIteratorImpl Other) const {
+    return !(*this == Other);
+  }
+
+public:
+  ElfLSectionNoteIteratorImpl(Elf *RawElf, bool IsEnd = false)
+    : EF(RawElf) {
+    assert(EF && "Trying to iterate invalid ELF.");
+
+    if (IsEnd) {
+      // NPtr equal to nullptr means end() iterator.
+      return;
+    }
+
+    // Set CurrentSection to the very first section,
+    // and let autoAdvance() find the first valid note (if any).
+    CurrentSection = elf_getscn(EF, 0);
+    autoAdvance(true);
+  }
+
+  bool operator==(const ElfLSectionNoteIteratorImpl Other) const {
+    // They should be pointing to the same NOTE to be equal.
+    return NPtr == Other.NPtr;
+  }
+
+  const Elf_Note *operator*() const {
+    assert(*this != ElfLSectionNoteIteratorImpl(EF, true) &&
+           "Dereferencing the end iterator.");
+    return NPtr;
+  }
+
+  // Advance to the next NOTE in the CurrentSection.
+  // If there is no next NOTE, then autoAdvance() to the next
+  // SHT_NOTE section and its first NOTE.
+  ElfLSectionNoteIteratorImpl &operator++() {
+    assert(*this != ElfLSectionNoteIteratorImpl(EF, true) &&
+           "Incrementing the end iterator.");
+
+    GElf_Shdr Shdr;
+    gelf_getshdr(CurrentSection, &Shdr);
+    uint64_t NotesBegin = getNotesBeginAddr(Shdr);
+    uint64_t NotesEnd = getNotesEndAddr(Shdr);
+    assert(reinterpret_cast<uint64_t>(NPtr) >= NotesBegin &&
+           reinterpret_cast<uint64_t>(NPtr) < NotesEnd &&
+           "Invalid pointer to a note computed somewhere else.");
+
+    uint64_t NoteSize = getNoteSize(*NPtr);
+    NPtr = reinterpret_cast<Elf_Note *>(reinterpret_cast<char *>(NPtr) +
+                                        NoteSize);
+    if (reinterpret_cast<uint64_t>(NPtr) >= NotesEnd ||
+        reinterpret_cast<uint64_t>(NPtr) + sizeof(*NPtr) >= NotesEnd) {
+      // We've reached the end of the current NOTE section.
+      NPtr = nullptr;
+    }
+
+    // Auto advance to the next section, if needed.
+    autoAdvance();
+    return *this;
+  }
+};
+
+// Implementation of the iterator for PT_NOTE segments.
+// The iterator allows processing all NOTEs in all PT_NOTE segments
+// in the ELF image provided during the iterator object construction.
+class ElfLSegmentNoteIteratorImpl {
+  // A pointer to Elf object created by elf_memory() for
+  // the ELF image we are going to iterate.
+  Elf *EF;
+
+  // A pointer to the current PT_NOTE segment.
+  // In the initial state of the iterator object this will actually
+  // point to the very first segment in the ELF image, but it will be
+  // adjusted right away either to point to the first PT_NOTE segment
+  // or set to nullptr (if there are no PT_NOTE segments).
+  size_t NumberOfPhdrs = (std::numeric_limits<size_t>::max)();
+  size_t CurrentSegment = (std::numeric_limits<size_t>::max)();
+
+  // A pointer to the current NOTE inside a PT_NOTE segment
+  // pointed by CurrentSegment. If it is nullptr, then this means
+  // that the iterator object is an end() iterator.
+  Elf_Note *NPtr = nullptr;
+
+  uint64_t getNotesBeginAddr(const GElf_Phdr &Phdr) const {
+    return reinterpret_cast<uint64_t>(elf_rawfile(EF, nullptr)) +
+        Phdr.p_offset;
+  }
+
+  uint64_t getNotesEndAddr(const GElf_Phdr &Phdr) const {
+    return getNotesBeginAddr(Phdr) + Phdr.p_filesz;
+  }
+
+  uint64_t getNoteSize(const Elf_Note &Note) const {
+    return sizeof(Note) + alignUp(Note.n_namesz, NoteAlignment) +
+        alignUp(Note.n_descsz, NoteAlignment);
+  }
+
+  // Given the current state of the iterator object, advances
+  // the iterator forward to point to the next NOTE in the next
+  // PT_NOTE segment.
+  // If there is no such a NOTE, then it sets the iterator
+  // object to the end() state.
+  //
+  // Note that this method does not change the iterator, if
+  // NPtr is pointing to a valid note within CurrentSegment.
+  // The iterator advancement in this case is done via operator++.
+  void autoAdvance(bool IsFirst = false) {
+    // Cannot advance, if CurrentSegment is invalid.
+    if (CurrentSegment >= NumberOfPhdrs)
+      return;
+
+    // NPtr points to a valid NOTE in CurrentSegment, thus,
+    // no auto advancement.
+    if (NPtr)
+      return;
+
+    GElf_Phdr Phdr;
+    gelf_getphdr(EF, CurrentSegment, &Phdr);
+
+    // CurrentSegment is a valid segment, and NPtr is an end() iterator.
+    //
+    // If IsFirst is true, then we just in the initial state, and
+    // we need to set CurrentSegment to the first PT_NOTE segment (if any),
+    // and, then, NPtr to the first note in this segment.
+    //
+    // If IsFirst is false, then we've reached the end of the current
+    // PT_NOTE segment, and should find the next segment with notes.
+    if (!IsFirst || Phdr.p_type != PT_NOTE)
+      ++CurrentSegment;
+
+    while (CurrentSegment < NumberOfPhdrs) {
+      if (gelf_getphdr(EF, CurrentSegment, &Phdr) != &Phdr)
+        continue;
+
+      if (Phdr.p_type == PT_NOTE)
+        break;
+
+      ++CurrentSegment;
+    }
+
+    if (CurrentSegment >= NumberOfPhdrs) {
+      // No more segments.
+      // Note that NPtr is already nullptr indicating the end() iterator.
+      return;
+    }
+
+    if (gelf_getphdr(EF, CurrentSegment, &Phdr) != &Phdr)
+      assert("Invalid program header selected above.");
+
+    uint64_t NotesBegin = getNotesBeginAddr(Phdr);
+    uint64_t NotesEnd = getNotesEndAddr(Phdr);
+    if (NotesBegin >= NotesEnd) {
+      // Something went wrong. Assume that we've reached
+      // the end of all notes.
+      CurrentSegment = NumberOfPhdrs;
+      NPtr = nullptr;
+      return;
+    }
+
+    NPtr = reinterpret_cast<Elf_Note *>(NotesBegin);
+    assert(NPtr && "Invalid PT_NOTE segment.");
+  }
+
+  bool operator!=(const ElfLSegmentNoteIteratorImpl Other) const {
+    return !(*this == Other);
+  }
+
+public:
+  ElfLSegmentNoteIteratorImpl(Elf *RawElf, bool IsEnd = false)
+    : EF(RawElf) {
+    assert(EF && "Trying to iterate invalid ELF.");
+
+    if (IsEnd) {
+      // NPtr equal to nullptr means end() iterator.
+      return;
+    }
+
+    // Set CurrentSegment to the very first segment,
+    // and let autoAdvance() find the first valid note (if any).
+    CurrentSegment = 0;
+
+    // Set NumberOfPhdrs to 0, if we cannot query it.
+    if (elf_getphdrnum(EF, &NumberOfPhdrs) != 0)
+      NumberOfPhdrs = 0;
+    autoAdvance(true);
+  }
+
+  bool operator==(const ElfLSegmentNoteIteratorImpl Other) const {
+    // They should be pointing to the same NOTE to be equal.
+    return NPtr == Other.NPtr;
+  }
+
+  const Elf_Note *operator*() const {
+    assert(*this != ElfLSegmentNoteIteratorImpl(EF, true) &&
+           "Dereferencing the end iterator.");
+    return NPtr;
+  }
+
+  // Advance to the next NOTE in the CurrentSegment.
+  // If there is no next NOTE, then autoAdvance() to the next
+  // PT_NOTE segment and its first NOTE.
+  ElfLSegmentNoteIteratorImpl &operator++() {
+    assert(*this != ElfLSegmentNoteIteratorImpl(EF, true) &&
+           "Incrementing the end iterator.");
+
+    GElf_Phdr Phdr;
+    gelf_getphdr(EF, CurrentSegment, &Phdr);
+    uint64_t NotesBegin = getNotesBeginAddr(Phdr);
+    uint64_t NotesEnd = getNotesEndAddr(Phdr);
+    assert(reinterpret_cast<uint64_t>(NPtr) >= NotesBegin &&
+           reinterpret_cast<uint64_t>(NPtr) < NotesEnd &&
+           "Invalid pointer to a note computed somewhere else.");
+
+    uint64_t NoteSize = getNoteSize(*NPtr);
+    NPtr = reinterpret_cast<Elf_Note *>(reinterpret_cast<char *>(NPtr) +
+                                        NoteSize);
+    if (reinterpret_cast<uint64_t>(NPtr) >= NotesEnd ||
+        reinterpret_cast<uint64_t>(NPtr) + sizeof(*NPtr) >= NotesEnd) {
+      // We've reached the end of the current NOTE section.
+      NPtr = nullptr;
+    }
+
+    // Auto advance to the next section, if needed.
+    autoAdvance();
+    return *this;
+  }
+};
+
+// Actual implementation of ElfL via libelf.
+// It is constructed from an ELF image defined by its
+// starting pointer in memory and a length in bytes.
+class ElfLImpl {
+  // A pointer to Elf object created by elf_memory() for
+  // the ELF image.
+  Elf *EF = nullptr;
+
+  // Class of the ELF image.
+  unsigned ElfClass = ELFCLASSNONE;
+
+  // A pointer to the ELF image's header.
+  // Depending on the class it may be either 'Elf32_Ehdr *'
+  // or 'Elf64_Ehdr '.
+  const void *Header = nullptr;  
+
+  // Let the owning object access this.
+  friend class ElfL;
+
+public:
+  ElfLImpl(Elf *RawElf, unsigned ElfClass, const void *Header)
+    : EF(RawElf), ElfClass(ElfClass), Header(Header) {}
+
+  // Allocates and constructs a new iterator for NOTEs in
+  // SHT_NOTE sections of the ELF image.
+  ElfLSectionNoteIteratorImpl *create_section_note_iterator_impl(bool IsEnd) const {
+    return new ElfLSectionNoteIteratorImpl(EF, IsEnd);
+  }
+
+  // Allocates and constructs a new iterator for NOTEs in
+  // PT_NOTE segments of the ELF image.
+  ElfLSegmentNoteIteratorImpl *create_segment_note_iterator_impl(bool IsEnd) const {
+    return new ElfLSegmentNoteIteratorImpl(EF, IsEnd);
+  }
+};
+
+ElfL::ElfL(char *Begin, size_t Size) {
+  Elf *ElfHandle = elf_memory(Begin, Size);
+  if (!ElfHandle) {
+    elf_end(ElfHandle);
+    return;
+  }
+
+  const Elf32_Ehdr *Header32 = elf32_getehdr(ElfHandle);
+  const Elf64_Ehdr *Header64 = elf64_getehdr(ElfHandle);
+
+  if (!Header32 == !Header64) {
+    // Ambiguous ELF header or unrecognized ELF image.
+    elf_end(ElfHandle);
+    return;
+  }
+
+  const void *Header = nullptr;
+  unsigned ElfClass = ELFCLASSNONE;
+
+  if (Header32) {
+    ElfClass = ELFCLASS32;
+    Header = reinterpret_cast<const void *>(Header32);
+  } else {
+    ElfClass = ELFCLASS64;
+    Header = reinterpret_cast<const void *>(Header64);
+  }
+
+  Impl = reinterpret_cast<void *>(new ElfLImpl(ElfHandle, ElfClass, Header));
+}
+
+ElfL::~ElfL() {
+  if (Impl) {
+    ElfLImpl *EImpl = reinterpret_cast<ElfLImpl *>(Impl);
+    elf_end(EImpl->EF);
+    delete EImpl;
+  }
+}
+
+bool ElfL::isValidElf() const {
+  ElfLImpl *EImpl = reinterpret_cast<ElfLImpl *>(Impl);
+  return Impl && EImpl->Header && EImpl->ElfClass != ELFCLASSNONE;
+}
+
+const char *ElfL::getErrmsg(int N) const {
+  return elf_errmsg(-1);
+}
+
+uint16_t ElfL::getEMachine() const {
+  assert(isValidElf() && "Invalid ELF.");
+  ElfLImpl *EImpl = reinterpret_cast<ElfLImpl *>(Impl);
+  if (EImpl->ElfClass == ELFCLASS32)
+    return reinterpret_cast<const Elf32_Ehdr *>(EImpl->Header)->e_machine;
+  else if (EImpl->ElfClass == ELFCLASS64)
+    return reinterpret_cast<const Elf64_Ehdr *>(EImpl->Header)->e_machine;
+  else
+    assert("Unsupported ELF class.");
+
+  return EM_NONE;
+}
+
+uint16_t ElfL::getEType() const {
+  assert(isValidElf() && "Invalid ELF.");
+  ElfLImpl *EImpl = reinterpret_cast<ElfLImpl *>(Impl);
+  if (EImpl->ElfClass == ELFCLASS32)
+    return reinterpret_cast<const Elf32_Ehdr *>(EImpl->Header)->e_type;
+  else if (EImpl->ElfClass == ELFCLASS64)
+    return reinterpret_cast<const Elf64_Ehdr *>(EImpl->Header)->e_type;
+  else
+    assert("Unsupported ELF class.");
+
+  return ET_NONE;
+}
+
+bool ElfL::isDynType(uint16_t Ty) {
+  return Ty == ET_DYN;
+}
+
+ElfLSectionNoteIterator ElfL::section_notes_begin() const {
+  return ElfLSectionNoteIterator(reinterpret_cast<const ElfLImpl *>(Impl));
+}
+
+ElfLSectionNoteIterator ElfL::section_notes_end() const {
+  return ElfLSectionNoteIterator(reinterpret_cast<const ElfLImpl *>(Impl), true);
+}
+
+ElfLSectionNoteIterator::ElfLSectionNoteIterator(const void *I, bool IsEnd) {
+  const ElfLImpl *EImpl = reinterpret_cast<const ElfLImpl *>(I);
+  Impl = EImpl->create_section_note_iterator_impl(IsEnd);
+}
+
+ElfLSectionNoteIterator::ElfLSectionNoteIterator(const ElfLSectionNoteIterator &Other) {
+  ElfLSectionNoteIteratorImpl *IImpl =
+      reinterpret_cast<ElfLSectionNoteIteratorImpl *>(Other.Impl);
+  Impl = new ElfLSectionNoteIteratorImpl(*IImpl);
+}
+
+ElfLSectionNoteIterator::~ElfLSectionNoteIterator() {
+  assert(Impl && "Invalid ElfLSectionNoteIterator object.");
+  ElfLSectionNoteIteratorImpl *IImpl =
+      reinterpret_cast<ElfLSectionNoteIteratorImpl *>(Impl);
+  delete IImpl;
+}
+
+bool ElfLSectionNoteIterator::operator==(const ElfLSectionNoteIterator Other) const {
+  const ElfLSectionNoteIteratorImpl *Lhs =
+      reinterpret_cast<const ElfLSectionNoteIteratorImpl *>(Impl);
+  const ElfLSectionNoteIteratorImpl *Rhs =
+      reinterpret_cast<const ElfLSectionNoteIteratorImpl *>(Other.Impl);
+  return (*Lhs == *Rhs);
+}
+
+bool ElfLSectionNoteIterator::operator!=(const ElfLSectionNoteIterator Other) const {
+  return !(*this == Other);
+}
+
+ElfLSectionNoteIterator &ElfLSectionNoteIterator::operator++() {
+  ElfLSectionNoteIteratorImpl *IImpl =
+      reinterpret_cast<ElfLSectionNoteIteratorImpl *>(Impl);
+  ++(*IImpl);
+  return *this;
+}
+
+ElfLNote ElfLSectionNoteIterator::operator*() const {
+  ElfLSectionNoteIteratorImpl *IImpl =
+      reinterpret_cast<ElfLSectionNoteIteratorImpl *>(Impl);
+  return ElfLNote(**IImpl);
+}
+
+ElfLSegmentNoteIterator ElfL::segment_notes_begin() const {
+  return ElfLSegmentNoteIterator(reinterpret_cast<const ElfLImpl *>(Impl));
+}
+
+ElfLSegmentNoteIterator ElfL::segment_notes_end() const {
+  return ElfLSegmentNoteIterator(reinterpret_cast<const ElfLImpl *>(Impl), true);
+}
+
+ElfLSegmentNoteIterator::ElfLSegmentNoteIterator(const void *I, bool IsEnd) {
+  const ElfLImpl *EImpl = reinterpret_cast<const ElfLImpl *>(I);
+  Impl = EImpl->create_segment_note_iterator_impl(IsEnd);
+}
+
+ElfLSegmentNoteIterator::ElfLSegmentNoteIterator(const ElfLSegmentNoteIterator &Other) {
+  ElfLSegmentNoteIteratorImpl *IImpl =
+      reinterpret_cast<ElfLSegmentNoteIteratorImpl *>(Other.Impl);
+  Impl = new ElfLSegmentNoteIteratorImpl(*IImpl);
+}
+
+ElfLSegmentNoteIterator::~ElfLSegmentNoteIterator() {
+  assert(Impl && "Invalid ElfLSegmentNoteIterator object.");
+  ElfLSegmentNoteIteratorImpl *IImpl =
+      reinterpret_cast<ElfLSegmentNoteIteratorImpl *>(Impl);
+  delete IImpl;
+}
+
+bool ElfLSegmentNoteIterator::operator==(const ElfLSegmentNoteIterator Other) const {
+  const ElfLSegmentNoteIteratorImpl *Lhs =
+      reinterpret_cast<const ElfLSegmentNoteIteratorImpl *>(Impl);
+  const ElfLSegmentNoteIteratorImpl *Rhs =
+      reinterpret_cast<const ElfLSegmentNoteIteratorImpl *>(Other.Impl);
+  return (*Lhs == *Rhs);
+}
+
+bool ElfLSegmentNoteIterator::operator!=(const ElfLSegmentNoteIterator Other) const {
+  return !(*this == Other);
+}
+
+ElfLSegmentNoteIterator &ElfLSegmentNoteIterator::operator++() {
+  ElfLSegmentNoteIteratorImpl *IImpl =
+      reinterpret_cast<ElfLSegmentNoteIteratorImpl *>(Impl);
+  ++(*IImpl);
+  return *this;
+}
+
+ElfLNote ElfLSegmentNoteIterator::operator*() const {
+  ElfLSegmentNoteIteratorImpl *IImpl =
+      reinterpret_cast<ElfLSegmentNoteIteratorImpl *>(Impl);
+  return ElfLNote(**IImpl);
+}
+
+ElfLNote::ElfLNote(const void *I) {
+  // ElfLNote::Impl is a pointer to Elf_Note in this implementation.
+  // A pointer to Elf_Note is returned by ElfLSectionNoteIteratorImpl::operator*().
+  Impl = I;
+}
+
+ElfLNote::ElfLNote(const ElfLNote &Other) {
+  Impl = Other.Impl;
+}
+
+ElfLNote::~ElfLNote() {}
+
+uint64_t ElfLNote::getNameSize() const {
+  const Elf_Note *Note = reinterpret_cast<const Elf_Note *>(Impl);
+  return Note->n_namesz;
+}
+
+const char *ElfLNote::getName() const {
+  const Elf_Note *Note = reinterpret_cast<const Elf_Note *>(Impl);
+  return reinterpret_cast<const char *>(Note) + sizeof(*Note);
+}
+
+uint64_t ElfLNote::getDescSize() const {
+  const Elf_Note *Note = reinterpret_cast<const Elf_Note *>(Impl);
+  return Note->n_descsz;
+}
+
+const uint8_t *ElfLNote::getDesc() const {
+  const Elf_Note *Note = reinterpret_cast<const Elf_Note *>(Impl);
+  return reinterpret_cast<const uint8_t *>(Note) + sizeof(*Note) +
+      alignUp(getNameSize(), NoteAlignment);
+}
+
+uint64_t ElfLNote::getType() const {
+  const Elf_Note *Note = reinterpret_cast<const Elf_Note *>(Impl);
+  return Note->n_type;
+}
+
+#else // MAY_USE_LIBELF
+
+// Implementation based on LLVM ELF binary format.
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+
+class ElfLNoteImplBase {
+public:
+  virtual ~ElfLNoteImplBase() = default;
+  virtual ElfLNoteImplBase *clone() const = 0;
+  virtual size_t getNameSize() const = 0;
+  virtual const char *getName() const = 0;
+  virtual size_t getDescSize() const = 0;
+  virtual const uint8_t *getDesc() const = 0;
+  virtual uint32_t getType() const = 0;
+};
+
+template <class ELFT>
+class ElfLNoteImpl : public ElfLNoteImplBase {
+  using Elf_Note = typename ELFT::Note;
+  const Elf_Note Note;
+
+public:
+  ElfLNoteImpl(const Elf_Note Note) : Note(Note) {}
+  ElfLNoteImpl(const ElfLNoteImpl &) = default;
+  ElfLNoteImplBase *clone() const {
+    return new ElfLNoteImpl(*this);
+  }
+  ~ElfLNoteImpl() = default;
+  size_t getNameSize() const override {
+    return Note.getName().size();
+  }
+  const char *getName() const override {
+    return Note.getName().data();
+  }
+  size_t getDescSize() const override {
+    return Note.getDesc().size();
+  }
+  const uint8_t *getDesc() const override {
+    return Note.getDesc().data();
+  }
+  uint32_t getType() const override {
+    return Note.getType();
+  }
+};
+
+class ElfLNoteIteratorImplBase {
+protected:
+  const endianness TargetEndianness;
+  const bool Is64Bits;
+  const bool IsSectionIterator;
+
+  ElfLNoteIteratorImplBase(endianness TargetEndianness, bool Is64Bits, bool IsSectionIterator)
+    : TargetEndianness(TargetEndianness),
+      Is64Bits(Is64Bits),
+      IsSectionIterator(IsSectionIterator) {}
+
+public:
+  ElfLNoteIteratorImplBase(const ElfLNoteIteratorImplBase &) = default;
+  virtual ~ElfLNoteIteratorImplBase() = default;
+  virtual ElfLNoteIteratorImplBase *clone() const = 0;
+  virtual ElfLNoteIteratorImplBase &operator++() = 0;
+  virtual bool operator==(const ElfLNoteIteratorImplBase &) const = 0;
+  virtual ElfLNoteImplBase *operator*() const = 0;
+
+  endianness getEndianness() const {
+    return TargetEndianness;
+  }
+
+  bool is64Bits() const {
+    return Is64Bits;
+  }
+
+  bool isSectionIterator() const {
+    return IsSectionIterator;
+  }
+};
+
+template <class ELFT>
+class ElfLNoteIteratorImpl : public ElfLNoteIteratorImplBase {
+protected:
+  using NoteIterator = typename ELFT::NoteIterator;
+
+  const ELFFile<ELFT> &EF;
+  NoteIterator NotesIt;
+  Error &Err;
+
+  explicit ElfLNoteIteratorImpl(const ELFFile<ELFT> &EF, Error &Err, bool IsSectionIterator)
+    : ElfLNoteIteratorImplBase(ELFT::TargetEndianness, ELFT::Is64Bits, IsSectionIterator),
+      EF(EF), NotesIt(EF.notes_end()), Err(Err) {}
+
+public:
+  ElfLNoteIteratorImpl(const ElfLNoteIteratorImpl&) = default;
+  virtual ~ElfLNoteIteratorImpl() = default;
+
+  static bool classof(const ElfLNoteIteratorImplBase *B) {
+    return (B->getEndianness() == ELFT::TargetEndianness &&
+            B->is64Bits() == ELFT::Is64Bits);
+  }
+};
+
+template <class ELFT>
+class ElfLSectionNoteIteratorImpl : public ElfLNoteIteratorImpl<ELFT> {
+  using Elf_Shdr = typename ELFT::Shdr;
+  using Elf_Shdr_Range = typename ELFT::ShdrRange;
+  using NoteIterator = typename ElfLNoteIteratorImpl<ELFT>::NoteIterator;
+  using SectionsIteratorTy = typename Elf_Shdr_Range::iterator;
+
+  SectionsIteratorTy SectionsIt;
+
+  const ELFFile<ELFT> &getEF() const {
+    return this->EF;
+  }
+  const NoteIterator &getNotesIt() const {
+    return this->NotesIt;
+  }
+  Error &getErr() const {
+    return this->Err;
+  }
+  NoteIterator &getNotesIt() {
+    return this->NotesIt;
+  }
+  SectionsIteratorTy section_begin() const {
+    Expected<Elf_Shdr_Range> Sections = getEF().sections();
+    if (!Sections)
+      return SectionsIteratorTy();
+
+    return Sections->begin();
+  }
+
+  SectionsIteratorTy section_end() const {
+    Expected<Elf_Shdr_Range> Sections = getEF().sections();
+    if (!Sections)
+      return SectionsIteratorTy();
+
+    return Sections->end();
+  }
+
+  bool isEqual(const ElfLSectionNoteIteratorImpl &Lhs,
+               const ElfLSectionNoteIteratorImpl &Rhs) const {
+    // Check for end() iterators, first.
+    if (Lhs.SectionsIt ==  section_end() &&
+        Rhs.SectionsIt == section_end())
+      return true;
+
+    if (Lhs.SectionsIt != Rhs.SectionsIt)
+      return false;
+
+    return Lhs.getNotesIt() == Rhs.getNotesIt();
+  }
+
+  void autoAdvance(bool IsFirst = false) {
+    if (SectionsIt == section_end())
+      return;
+
+    if (getNotesIt() != getEF().notes_end())
+      return;
+
+    // SectionsIt is not an end iterator, and NotesIt is an end()
+    // iterator.
+    //
+    // If IsFirst is true, then we just in the initial state, and
+    // we need to set SectionsIt to the first SHT_NOTE section (if any),
+    // and, then, NotesIt to the first note in this section.
+    //
+    // If IsFirst is false, then we've reached the end of the current
+    // SHT_NOTE section, and should find the next section with notes.
+    if (!IsFirst || SectionsIt->sh_type != ELF::SHT_NOTE)
+      ++SectionsIt;
+
+    while (SectionsIt != section_end() &&
+           SectionsIt->sh_type != ELF::SHT_NOTE) {
+      ++SectionsIt;
+    }
+
+    if (SectionsIt == section_end()) {
+      // No more sections.
+      return;
+    }
+
+    const Elf_Shdr &Section = *SectionsIt;
+    getNotesIt() = getEF().notes_begin(Section, getErr());
+
+    // Auto advance the iterator, if the NOTE section
+    // does not contain any notes (e.g. some error happened
+    // during the note parsing).
+    autoAdvance();
+  }
+
+  bool operator!=(const ElfLSectionNoteIteratorImpl &Other) const {
+    return !(*this == Other);
+  }
+
+public:
+  ElfLSectionNoteIteratorImpl(const ELFFile<ELFT> &EF, Error &Err, bool IsEnd = false) 
+    : ElfLNoteIteratorImpl<ELFT>(EF, Err, true) {
+    if (IsEnd) {
+      SectionsIt = section_end();
+      // It is an end() iterator, if SectionsIt is an end() iterator.
+      return;
+    }
+
+    SectionsIt = section_begin();
+    autoAdvance(true);
+  }
+
+  ElfLSectionNoteIteratorImpl(const ElfLSectionNoteIteratorImpl &Copy) = default;
+
+  ElfLNoteIteratorImplBase *clone() const {
+    return new ElfLSectionNoteIteratorImpl(*this);
+  }
+
+  bool operator==(const ElfLNoteIteratorImplBase &Other) const override {
+    if (const ElfLSectionNoteIteratorImpl *OPtr = dyn_cast<const ElfLSectionNoteIteratorImpl>(&Other)) {
+      return isEqual(*this, *OPtr);
+    }
+    return false;
+  }
+
+  ElfLSectionNoteIteratorImpl &operator++() override {
+    assert(*this != ElfLSectionNoteIteratorImpl(getEF(), getErr(), true) &&
+           "Incrementing the end iterator.");
+    // Move the notes iterator within the current section.
+    ++getNotesIt();
+    autoAdvance();
+
+    return *this;
+  }
+
+  ElfLNoteImplBase *operator*() const override {
+    assert(*this != ElfLSectionNoteIteratorImpl(getEF(), getErr(), true) &&
+           "Dereferencing the end iterator.");
+    return new ElfLNoteImpl<ELFT>(*getNotesIt());
+  }
+
+  static bool classof(const ElfLNoteIteratorImplBase *B) {
+    return (ElfLNoteIteratorImpl<ELFT>::classof(B) &&
+            B->isSectionIterator() == true);
+  }
+};
+
+template <class ELFT>
+class ElfLSegmentNoteIteratorImpl : public ElfLNoteIteratorImpl<ELFT> {
+  using Elf_Phdr = typename ELFT::Phdr;
+  using Elf_Phdr_Range = typename ELFT::PhdrRange;
+  using NoteIterator = typename ElfLNoteIteratorImpl<ELFT>::NoteIterator;
+  using SegmentIteratorTy = typename Elf_Phdr_Range::iterator;
+
+  SegmentIteratorTy SegmentsIt;
+
+  const ELFFile<ELFT> &getEF() const {
+    return this->EF;
+  }
+  const NoteIterator &getNotesIt() const {
+    return this->NotesIt;
+  }
+  Error &getErr() const {
+    return this->Err;
+  }
+  NoteIterator &getNotesIt() {
+    return this->NotesIt;
+  }
+  SegmentIteratorTy segment_begin() const {
+    Expected<Elf_Phdr_Range> Segments = getEF().program_headers();
+    if (!Segments)
+      return SegmentIteratorTy();
+
+    return Segments->begin();
+  }
+
+  SegmentIteratorTy segment_end() const {
+    Expected<Elf_Phdr_Range> Segments = getEF().program_headers();
+    if (!Segments)
+      return SegmentIteratorTy();
+
+    return Segments->end();
+  }
+
+  bool isEqual(const ElfLSegmentNoteIteratorImpl &Lhs,
+               const ElfLSegmentNoteIteratorImpl &Rhs) const {
+    // Check for end() iterators, first.
+    if (Lhs.SegmentsIt == segment_end() &&
+        Rhs.SegmentsIt == segment_end())
+      return true;
+
+    if (Lhs.SegmentsIt != Rhs.SegmentsIt)
+      return false;
+
+    return Lhs.getNotesIt() == Rhs.getNotesIt();
+  }
+
+  void autoAdvance(bool IsFirst = false) {
+    if (SegmentsIt == segment_end())
+      return;
+
+    if (getNotesIt() != getEF().notes_end())
+      return;
+
+    // SegmentsIt is not an end iterator, and NotesIt is an end()
+    // iterator.
+    //
+    // If IsFirst is true, then we just in the initial state, and
+    // we need to set SegmentsIt to the first PT_NOTE segment (if any),
+    // and, then, NotesIt to the first note in this segment.
+    //
+    // If IsFirst is false, then we've reached the end of the current
+    // PT_NOTE segment, and should find the next segment with notes.
+    if (!IsFirst || SegmentsIt->p_type != ELF::SHT_NOTE)
+      ++SegmentsIt;
+
+    while (SegmentsIt != segment_end() &&
+           SegmentsIt->p_type != ELF::PT_NOTE) {
+      ++SegmentsIt;
+    }
+
+    if (SegmentsIt == segment_end()) {
+      // No more segments.
+      return;
+    }
+
+    const Elf_Phdr &Segment = *SegmentsIt;
+    getNotesIt() = getEF().notes_begin(Segment, getErr());
+
+    // Auto advance the iterator, if the NOTE segment
+    // does not contain any notes (e.g. some error happened
+    // during the note parsing).
+    autoAdvance();
+  }
+
+  bool operator!=(const ElfLSegmentNoteIteratorImpl &Other) const {
+    return !(*this == Other);
+  }
+
+public:
+  ElfLSegmentNoteIteratorImpl(const ELFFile<ELFT> &EF, Error &Err, bool IsEnd = false) 
+    : ElfLNoteIteratorImpl<ELFT>(EF, Err, false) {
+    if (IsEnd) {
+      SegmentsIt = segment_end();
+      // It is an end() iterator, if SegmentsIt is an end() iterator.
+      return;
+    }
+
+    SegmentsIt = segment_begin();
+    autoAdvance(true);
+  }
+
+  ElfLSegmentNoteIteratorImpl(const ElfLSegmentNoteIteratorImpl &Copy) = default;
+
+  ElfLNoteIteratorImplBase *clone() const {
+    return new ElfLSegmentNoteIteratorImpl(*this);
+  }
+
+  bool operator==(const ElfLNoteIteratorImplBase &Other) const override {
+    if (const ElfLSegmentNoteIteratorImpl *OPtr = dyn_cast<const ElfLSegmentNoteIteratorImpl>(&Other)) {
+      return isEqual(*this, *OPtr);
+    }
+    return false;
+  }
+
+  ElfLSegmentNoteIteratorImpl &operator++() override {
+    assert(*this != ElfLSegmentNoteIteratorImpl(getEF(), getErr(), true) &&
+           "Incrementing the end iterator.");
+    // Move the notes iterator within the current segment.
+    ++getNotesIt();
+    autoAdvance();
+
+    return *this;
+  }
+
+  ElfLNoteImplBase *operator*() const override {
+    assert(*this != ElfLSegmentNoteIteratorImpl(getEF(), getErr(), true) &&
+           "Dereferencing the end iterator.");
+    return new ElfLNoteImpl<ELFT>(*getNotesIt());
+  }
+
+  static bool classof(const ElfLNoteIteratorImplBase *B) {
+    return (ElfLNoteIteratorImpl<ELFT>::classof(B) &&
+            B->isSectionIterator() == false);
+  }
+ 
+};
+
+class ElfLImplBase {
+public:
+  ElfLImplBase() = default;
+  ElfLImplBase(const ElfLImplBase &) = delete;
+  ElfLImplBase &operator=(const ElfLImplBase &) = delete;
+  virtual ~ElfLImplBase() = default;
+  virtual uint16_t getEMachine() const = 0;
+  virtual uint16_t getEType() const = 0;
+
+  virtual ElfLNoteIteratorImplBase *create_section_note_iterator_impl(bool IsEnd) const = 0;
+  virtual ElfLNoteIteratorImplBase *create_segment_note_iterator_impl(bool IsEnd) const = 0;
+};
+
+template <class ELFT>
+class ElfLImpl : public ElfLImplBase {
+  std::unique_ptr<ELFObjectFile<ELFT>> File;
+  Error *Err = nullptr;
+
+  friend class ElfL;
+
+public:
+  ElfLImpl(std::unique_ptr<ObjectFile> F) {
+    ObjectFile *FPtr = F.release();
+    if (auto *Obj = dyn_cast<ELFObjectFile<ELFT>>(FPtr))
+      File = std::unique_ptr<ELFObjectFile<ELFT>>(Obj);
+    else
+      assert("Not an ELF object file, or ELF class is wrong.");
+
+    Err = new Error(std::move(Error::success()));
+  }
+  ElfLImpl(const ElfLImpl &) = delete;
+  ElfLImpl &operator=(const ElfLImpl &) = delete;
+  virtual ~ElfLImpl() {
+    if (!Err)
+      return;
+
+    if (*Err) {
+      auto ErrorString = toString(std::move(*Err));
+      DP("Destroying ELF object parsed with errors: %s\n",
+         ErrorString.c_str());
+    } else {
+      delete Err;
+    }
+    Err = nullptr;
+  }
+  uint16_t getEMachine() const override {
+    return cast<ELFObjectFileBase>(File.get())->getEMachine();
+  }
+  uint16_t getEType() const override {
+    return cast<ELFObjectFileBase>(File.get())->getEType();
+  }
+
+  ElfLNoteIteratorImplBase *create_section_note_iterator_impl(
+      bool IsEnd) const override {
+    return new ElfLSectionNoteIteratorImpl<ELFT>(File->getELFFile(), *Err, IsEnd);
+  }
+
+  ElfLNoteIteratorImplBase *create_segment_note_iterator_impl(
+      bool IsEnd) const override {
+    return new ElfLSegmentNoteIteratorImpl<ELFT>(File->getELFFile(), *Err, IsEnd);
+  }
+};
+
+ElfL::ElfL(char *Begin, size_t Size) {
+  StringRef StrBuf(Begin, Size);
+  std::unique_ptr<MemoryBuffer> MemBuf =
+      MemoryBuffer::getMemBuffer(StrBuf, "", false);
+  Expected<std::unique_ptr<ObjectFile>> BinOrErr =
+      ObjectFile::createELFObjectFile(MemBuf->getMemBufferRef(),
+                                      /*InitContent=*/false);
+  if (!BinOrErr)
+    return;
+
+  if (isa<ELF64LEObjectFile>(BinOrErr->get())) {
+    Impl = reinterpret_cast<void *>(new ElfLImpl<ELF64LE>(std::move(*BinOrErr)));
+  } else if (isa<ELF32LEObjectFile>(BinOrErr->get()))
+    Impl = reinterpret_cast<void *>(new ElfLImpl<ELF32LE>(std::move(*BinOrErr)));
+  else if (isa<ELF32BEObjectFile>(BinOrErr->get()))
+    Impl = reinterpret_cast<void *>(new ElfLImpl<ELF32BE>(std::move(*BinOrErr)));
+  else if (isa<ELF64BEObjectFile>(BinOrErr->get()))
+    Impl = reinterpret_cast<void *>(new ElfLImpl<ELF64BE>(std::move(*BinOrErr)));
+}
+
+ElfL::~ElfL() {
+  ElfLImplBase *EImpl = reinterpret_cast<ElfLImplBase *>(Impl);
+  delete EImpl;
+}
+
+bool ElfL::isValidElf() const {
+  return Impl;
+}
+
+const char *ElfL::getErrmsg(int N) const {
+  return "LLVM ELF error";
+}
+
+uint16_t ElfL::getEMachine() const {
+  assert(isValidElf() && "Invalid ELF.");
+  ElfLImplBase *EImpl = reinterpret_cast<ElfLImplBase *>(Impl);
+  return EImpl->getEMachine();
+}
+
+uint16_t ElfL::getEType() const {
+  assert(isValidElf() && "Invalid ELF.");
+  ElfLImplBase *EImpl = reinterpret_cast<ElfLImplBase *>(Impl);
+  return EImpl->getEType();
+}
+
+bool ElfL::isDynType(uint16_t Ty) {
+  return Ty == ET_DYN;
+}
+
+ElfLSectionNoteIterator::ElfLSectionNoteIterator(const void *I, bool IsEnd) {
+  const ElfLImplBase *EImpl = reinterpret_cast<const ElfLImplBase *>(I);
+  // Create new ElfLSectionNoteIteratorImpl<ELFT> object.
+  Impl = EImpl->create_section_note_iterator_impl(IsEnd);
+}
+
+ElfLSectionNoteIterator::~ElfLSectionNoteIterator() {
+  const ElfLNoteIteratorImplBase *IImpl =
+      reinterpret_cast<const ElfLNoteIteratorImplBase *>(Impl);
+  delete IImpl;
+}
+
+ElfLSectionNoteIterator::ElfLSectionNoteIterator(const ElfLSectionNoteIterator &Other) {
+  const ElfLNoteIteratorImplBase *IImpl =
+      reinterpret_cast<const ElfLNoteIteratorImplBase *>(Other.Impl);
+  Impl = IImpl->clone();
+}
+
+bool ElfLSectionNoteIterator::operator==(const ElfLSectionNoteIterator Other) const {
+  const ElfLNoteIteratorImplBase *Lhs =
+      reinterpret_cast<const ElfLNoteIteratorImplBase *>(Impl);
+  const ElfLNoteIteratorImplBase *Rhs =
+      reinterpret_cast<const ElfLNoteIteratorImplBase *>(Other.Impl);
+  return (*Lhs == *Rhs);
+}
+
+bool ElfLSectionNoteIterator::operator!=(const ElfLSectionNoteIterator Other) const {
+  return !(*this == Other);
+}
+
+ElfLSectionNoteIterator &ElfLSectionNoteIterator::operator++() {
+  ElfLNoteIteratorImplBase *EImpl =
+      reinterpret_cast<ElfLNoteIteratorImplBase *>(Impl);
+  ++(*EImpl);
+  return *this;
+}
+
+ElfLNote ElfLSectionNoteIterator::operator*() const {
+  return ElfLNote(Impl);
+}
+
+ElfLSectionNoteIterator ElfL::section_notes_begin() const {
+  assert(isValidElf() && "Invalid ELF.");
+  return ElfLSectionNoteIterator(reinterpret_cast<const ElfLImplBase *>(Impl));
+}
+
+ElfLSectionNoteIterator ElfL::section_notes_end() const {
+  assert(isValidElf() && "Invalid ELF.");
+  return ElfLSectionNoteIterator(reinterpret_cast<const ElfLImplBase *>(Impl), true);
+}
+
+ElfLSegmentNoteIterator::ElfLSegmentNoteIterator(const void *I, bool IsEnd) {
+  const ElfLImplBase *EImpl = reinterpret_cast<const ElfLImplBase *>(I);
+  // Create new ElfLSegmentNoteIteratorImpl<ELFT> object.
+  Impl = EImpl->create_segment_note_iterator_impl(IsEnd);
+}
+
+ElfLSegmentNoteIterator::~ElfLSegmentNoteIterator() {
+  const ElfLNoteIteratorImplBase *IImpl =
+      reinterpret_cast<const ElfLNoteIteratorImplBase *>(Impl);
+  delete IImpl;
+}
+
+ElfLSegmentNoteIterator::ElfLSegmentNoteIterator(const ElfLSegmentNoteIterator &Other) {
+  const ElfLNoteIteratorImplBase *IImpl =
+      reinterpret_cast<const ElfLNoteIteratorImplBase *>(Other.Impl);
+  Impl = IImpl->clone();
+}
+
+bool ElfLSegmentNoteIterator::operator==(const ElfLSegmentNoteIterator Other) const {
+  const ElfLNoteIteratorImplBase *Lhs =
+      reinterpret_cast<const ElfLNoteIteratorImplBase *>(Impl);
+  const ElfLNoteIteratorImplBase *Rhs =
+      reinterpret_cast<const ElfLNoteIteratorImplBase *>(Other.Impl);
+  return (*Lhs == *Rhs);
+}
+
+bool ElfLSegmentNoteIterator::operator!=(const ElfLSegmentNoteIterator Other) const {
+  return !(*this == Other);
+}
+
+ElfLSegmentNoteIterator &ElfLSegmentNoteIterator::operator++() {
+  ElfLNoteIteratorImplBase *EImpl =
+      reinterpret_cast<ElfLNoteIteratorImplBase *>(Impl);
+  ++(*EImpl);
+  return *this;
+}
+
+ElfLNote ElfLSegmentNoteIterator::operator*() const {
+  return ElfLNote(Impl);
+}
+
+ElfLSegmentNoteIterator ElfL::segment_notes_begin() const {
+  assert(isValidElf() && "Invalid ELF.");
+  return ElfLSegmentNoteIterator(reinterpret_cast<const ElfLImplBase *>(Impl));
+}
+
+ElfLSegmentNoteIterator ElfL::segment_notes_end() const {
+  assert(isValidElf() && "Invalid ELF.");
+  return ElfLSegmentNoteIterator(reinterpret_cast<const ElfLImplBase *>(Impl), true);
+}
+
+ElfLNote::ElfLNote(const void *IteratorImpl) {
+  const ElfLNoteIteratorImplBase *IImpl =
+      reinterpret_cast<const ElfLNoteIteratorImplBase *>(IteratorImpl);
+  Impl = **IImpl;
+}
+
+ElfLNote::ElfLNote(const ElfLNote &Other) {
+  const ElfLNoteImplBase *NImpl =
+      reinterpret_cast<const ElfLNoteImplBase *>(Impl);
+  Impl = NImpl->clone();
+}
+
+ElfLNote::~ElfLNote() {
+  const ElfLNoteImplBase *NImpl =
+      reinterpret_cast<const ElfLNoteImplBase *>(Impl);
+  delete NImpl;
+}
+
+uint64_t ElfLNote::getNameSize() const {
+  const ElfLNoteImplBase *NImpl =
+      reinterpret_cast<const ElfLNoteImplBase *>(Impl);
+  return NImpl->getNameSize();
+}
+
+const char *ElfLNote::getName() const {
+  const ElfLNoteImplBase *NImpl =
+      reinterpret_cast<const ElfLNoteImplBase *>(Impl);
+  return NImpl->getName();
+}
+
+uint64_t ElfLNote::getDescSize() const {
+  const ElfLNoteImplBase *NImpl =
+      reinterpret_cast<const ElfLNoteImplBase *>(Impl);
+  return NImpl->getDescSize();
+}
+
+const uint8_t *ElfLNote::getDesc() const {
+  const ElfLNoteImplBase *NImpl =
+      reinterpret_cast<const ElfLNoteImplBase *>(Impl);
+  return NImpl->getDesc();
+}
+
+uint64_t ElfLNote::getType() const {
+  const ElfLNoteImplBase *NImpl =
+      reinterpret_cast<const ElfLNoteImplBase *>(Impl);
+  return NImpl->getType();
+}
+#endif // MAY_USE_LIBELF
Index: openmp/libomptarget/plugins/common/elf_common/elf_constants.h
===================================================================
--- /dev/null
+++ openmp/libomptarget/plugins/common/elf_common/elf_constants.h
@@ -0,0 +1,28 @@
+//===-- elf_constants.h - ELF constants -------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Here we duplicate some ELF constants that may not be yet available
+// in elf.h or llvm/BinaryFormat/ELF.h (e.g. in an out-of-tree build).
+// Note that we use the same constant names as in llvm/BinaryFormat/ELF.h.
+//
+//===----------------------------------------------------------------------===//
+
+// ELF notes with "LLVMOMPOFFLOAD" name may be of either of these types.
+enum : unsigned {
+  NT_LLVM_OPENMP_OFFLOAD_VERSION = 1,
+  NT_LLVM_OPENMP_OFFLOAD_PRODUCER = 2,
+  NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION = 3,
+  NT_LLVM_OPENMP_OFFLOAD_LAST = NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION
+};
+
+constexpr const char *OMPNoteTypeNames[NT_LLVM_OPENMP_OFFLOAD_LAST + 1] = {
+  "NT_LLVM_OPENMP_OFFLOAD_UNKNOWN",
+  "NT_LLVM_OPENMP_OFFLOAD_VERSION",
+  "NT_LLVM_OPENMP_OFFLOAD_PRODUCER",
+  "NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION",
+};
Index: openmp/libomptarget/plugins/common/elf_common/elf_common.h
===================================================================
--- openmp/libomptarget/plugins/common/elf_common/elf_common.h
+++ openmp/libomptarget/plugins/common/elf_common/elf_common.h
@@ -1,4 +1,4 @@
-//===-- elf_common.h - Common ELF functionality -------------------*- C -*-===//
+//===-- elf_common.h - Common ELF functionality -----------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -7,105 +7,23 @@
 //===----------------------------------------------------------------------===//
 //
 // Common ELF functionality for target plugins.
-// Must be included in the plugin source file AFTER omptarget.h has been
-// included and macro DP(...) has been defined.
-// .
 //
 //===----------------------------------------------------------------------===//
 
-#if !(defined(_OMPTARGET_DEBUG_H))
-#error Include elf_common.h in the plugin source AFTER Debug.h has\
- been included.
-#endif
+#ifndef LIBOMPTARGET_PLUGINS_ELF_COMMON_H
+#define LIBOMPTARGET_PLUGINS_ELF_COMMON_H
 
-#include <elf.h>
-#include <libelf.h>
+#include <cstdint>
+#include "elf_constants.h"
+#include "omptargetplugin.h"
 
-// Check whether an image is valid for execution on target_id
-static inline int32_t elf_check_machine(__tgt_device_image *image,
-                                        uint16_t target_id) {
+/// Return non-zero, if the given \p image is an ELF object, which
+/// e_machine matches \p target_id; return zero otherwise.
+EXTERN int32_t elf_check_machine(__tgt_device_image *image,
+                                 uint16_t target_id);
 
-  // Is the library version incompatible with the header file?
-  if (elf_version(EV_CURRENT) == EV_NONE) {
-    DP("Incompatible ELF library!\n");
-    return 0;
-  }
+/// Return non-zero, if the given \p image is an ET_DYN ELF object;
+/// return zero otherwise.
+EXTERN int32_t elf_is_dynamic(__tgt_device_image *image);
 
-  char *img_begin = (char *)image->ImageStart;
-  char *img_end = (char *)image->ImageEnd;
-  size_t img_size = img_end - img_begin;
-
-  // Obtain elf handler
-  Elf *e = elf_memory(img_begin, img_size);
-  if (!e) {
-    DP("Unable to get ELF handle: %s!\n", elf_errmsg(-1));
-    return 0;
-  }
-
-  // Check if ELF is the right kind.
-  if (elf_kind(e) != ELF_K_ELF) {
-    DP("Unexpected ELF type!\n");
-    elf_end(e);
-    return 0;
-  }
-  Elf64_Ehdr *eh64 = elf64_getehdr(e);
-  Elf32_Ehdr *eh32 = elf32_getehdr(e);
-
-  if (!eh64 && !eh32) {
-    DP("Unable to get machine ID from ELF file!\n");
-    elf_end(e);
-    return 0;
-  }
-
-  uint16_t MachineID;
-  if (eh64 && !eh32)
-    MachineID = eh64->e_machine;
-  else if (eh32 && !eh64)
-    MachineID = eh32->e_machine;
-  else {
-    DP("Ambiguous ELF header!\n");
-    elf_end(e);
-    return 0;
-  }
-
-  elf_end(e);
-  return MachineID == target_id;
-}
-
-static inline int32_t elf_is_dynamic(__tgt_device_image *image) {
-
-  char *img_begin = (char *)image->ImageStart;
-  char *img_end = (char *)image->ImageEnd;
-  size_t img_size = img_end - img_begin;
-
-  // Obtain elf handler
-  Elf *e = elf_memory(img_begin, img_size);
-  if (!e) {
-    DP("Unable to get ELF handle: %s!\n", elf_errmsg(-1));
-    return 0;
-  }
-
-  Elf64_Ehdr *eh64 = elf64_getehdr(e);
-  Elf32_Ehdr *eh32 = elf32_getehdr(e);
-
-  if (!eh64 && !eh32) {
-    DP("Unable to get machine ID from ELF file!\n");
-    elf_end(e);
-    return 0;
-  }
-
-  uint16_t Type;
-  if (eh64 && !eh32)
-    Type = eh64->e_type;
-  else if (eh32 && !eh64)
-    Type = eh32->e_type;
-  else {
-    DP("Ambiguous ELF header!\n");
-    elf_end(e);
-    return 0;
-  }
-
-  elf_end(e);
-  DP("ELF Type: %d\n", Type);
-  return Type == ET_DYN;
-}
+#endif // LIBOMPTARGET_PLUGINS_ELF_COMMON_H
Index: openmp/libomptarget/plugins/common/elf_common/elf_common.cpp
===================================================================
--- /dev/null
+++ openmp/libomptarget/plugins/common/elf_common/elf_common.cpp
@@ -0,0 +1,92 @@
+//===-- elf_common.cpp - Common ELF functionality -------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Common ELF functionality for target plugins.
+//
+//===----------------------------------------------------------------------===//
+#include "Debug.h"
+#include "elf_common.h"
+#include "elf_light.h"
+
+#ifndef TARGET_NAME
+#define TARGET_NAME Common ELF
+#endif
+#define DEBUG_PREFIX "TARGET " GETNAME(TARGET_NAME)
+
+#ifdef ELFMAG
+// Subtle verification that libelf APIs are not used explicitly here.
+// Code here must use libelf independent APIs from elf_light.h.
+#error "LIBELF.H cannot be used explicitly here."
+#endif // ELFMAG
+
+EXTERN int32_t elf_check_machine(__tgt_device_image *image,
+                                 uint16_t target_id) {
+  char *img_begin = reinterpret_cast<char *>(image->ImageStart);
+  char *img_end = reinterpret_cast<char *>(image->ImageEnd);
+  size_t img_size = img_end - img_begin;
+  ElfL E(img_begin, img_size);
+  if (!E.isValidElf()) {
+    DP("Unable to get ELF handle: %s!\n", E.getErrmsg(-1));
+    return 0;
+  }
+
+  if (getDebugLevel() > 0) {
+    auto PrintOutNote = [](const ElfLNote &Note) {
+      if (Note.getNameSize() == 0)
+        return;
+
+      std::string NameStr(Note.getName(), Note.getNameSize());
+      // Check if this is a null-terminated "LLVMOMPOFFLOAD" string.
+      std::string LlvmName("LLVMOMPOFFLOAD");
+      LlvmName += '\0';
+      if (NameStr != LlvmName)
+        return;
+
+      uint64_t Type = Note.getType();
+      switch (Type) {
+      default:
+        DP("LLVMOMPOFFLOAD ELF note with unknown type %" PRIu64 ".\n", Type);
+        break;
+      case NT_LLVM_OPENMP_OFFLOAD_VERSION:
+      case NT_LLVM_OPENMP_OFFLOAD_PRODUCER:
+      case NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION: {
+        std::string DescStr(reinterpret_cast<const char *>(Note.getDesc()),
+                            Note.getDescSize());
+        DP("LLVMOMPOFFLOAD ELF note %s with value: '%s'\n",
+           OMPNoteTypeNames[Type], DescStr.c_str());
+        break;
+      }
+      }
+    };
+
+    for (auto I = E.section_notes_begin(), IE = E.section_notes_end();
+         I != IE; ++I)
+      PrintOutNote(*I);
+
+    for (auto I = E.segment_notes_begin(), IE = E.segment_notes_end();
+         I != IE; ++I)
+      PrintOutNote(*I);
+  }
+  uint16_t MachineID = E.getEMachine();
+  return MachineID == target_id;
+}
+
+EXTERN int32_t elf_is_dynamic(__tgt_device_image *image) {
+  char *img_begin = reinterpret_cast<char *>(image->ImageStart);
+  char *img_end = reinterpret_cast<char *>(image->ImageEnd);
+  size_t img_size = img_end - img_begin;
+  ElfL E(img_begin, img_size);
+  if (!E.isValidElf()) {
+    DP("Unable to get ELF handle: %s!\n", E.getErrmsg(-1));
+    return 0;
+  }
+
+  uint16_t Type = E.getEType();
+  DP("ELF Type: %" PRIu16 "\n", Type);
+  return ElfL::isDynType(Type);
+}
Index: openmp/libomptarget/plugins/common/elf_common/CMakeLists.txt
===================================================================
--- openmp/libomptarget/plugins/common/elf_common/CMakeLists.txt
+++ openmp/libomptarget/plugins/common/elf_common/CMakeLists.txt
@@ -10,6 +10,31 @@
 #
 ##===----------------------------------------------------------------------===##
 
-add_library(elf_common INTERFACE)
+# Use libelf, is possible.
+# Otherwise, use LLVM ELF (unless OPENMP_STANDALONE_BUILD).
+set(MAY_USE_LIBELF LIBOMPTARGET_DEP_LIBELF_FOUND)
 
+option(LIBOMPTARGET_FORCE_LLVM_ELF
+  "Use LLVM ELFObjectFile implementation for elf_common.\
+  This requires in-tree build." OFF)
+add_library(elf_common OBJECT elf_common.cpp elf_light.cpp)
+
+if(MAY_USE_LIBELF AND NOT LIBOMPTARGET_FORCE_LLVM_ELF)
+  target_compile_definitions(elf_common PRIVATE -DMAY_USE_LIBELF)
+  target_include_directories(elf_common PRIVATE
+    ${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR})
+  target_link_libraries(elf_common INTERFACE
+    ${LIBOMPTARGET_DEP_LIBELF_LIBRARIES})
+elseif(NOT OPENMP_STANDALONE_BUILD)
+  llvm_update_compile_flags(elf_common)
+  target_link_libraries(elf_common INTERFACE
+    LLVMBinaryFormat LLVMObject LLVMSupport)
+else(MAY_USE_LIBELF AND NOT LIBOMPTARGET_FORCE_LLVM_ELF)
+  libomptarget_say("Not building elf_common offload plugin library: libelf dependency not found.")
+endif(MAY_USE_LIBELF AND NOT LIBOMPTARGET_FORCE_LLVM_ELF)
+
+# The code uses Debug.h, which requires threads support.
+target_link_libraries(elf_common INTERFACE ${OPENMP_PTHREAD_LIB})
+
+# Expose elf_common.h directory to the users of this library.
 target_include_directories(elf_common INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
Index: openmp/libomptarget/plugins/amdgpu/CMakeLists.txt
===================================================================
--- openmp/libomptarget/plugins/amdgpu/CMakeLists.txt
+++ openmp/libomptarget/plugins/amdgpu/CMakeLists.txt
@@ -75,7 +75,9 @@
   PRIVATE
   elf_common
   hsa-runtime64::hsa-runtime64
-  pthread dl elf
+  dl
+  ${LIBOMPTARGET_DEP_LIBELF_LIBRARIES}
+  ${OPENMP_PTHREAD_LIB}
   "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exports"
   "-Wl,-z,defs"
   )
Index: llvm/tools/llvm-readobj/ELFDumper.cpp
===================================================================
--- llvm/tools/llvm-readobj/ELFDumper.cpp
+++ llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -4906,7 +4906,7 @@
   return OS.str();
 }
 
-static StringRef getGNUGoldVersion(ArrayRef<uint8_t> Desc) {
+static StringRef getDescAsStringRef(ArrayRef<uint8_t> Desc) {
   return StringRef(reinterpret_cast<const char *>(Desc.data()), Desc.size());
 }
 
@@ -4930,7 +4930,7 @@
     break;
   }
   case ELF::NT_GNU_GOLD_VERSION:
-    OS << "    Version: " << getGNUGoldVersion(Desc);
+    OS << "    Version: " << getDescAsStringRef(Desc);
     break;
   case ELF::NT_GNU_PROPERTY_TYPE_0:
     OS << "    Properties:";
@@ -4942,6 +4942,26 @@
   return true;
 }
 
+template <typename ELFT>
+static bool printLLVMOMPOFFLOADNote(raw_ostream &OS, uint32_t NoteType,
+                                    ArrayRef<uint8_t> Desc) {
+  switch (NoteType) {
+  default:
+    return false;
+  case ELF::NT_LLVM_OPENMP_OFFLOAD_VERSION:
+    OS << "    Version: " << getDescAsStringRef(Desc);
+    break;
+  case ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER:
+    OS << "    Producer: " << getDescAsStringRef(Desc);
+    break;
+  case ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION:
+    OS << "    Producer version: " << getDescAsStringRef(Desc);
+    break;
+  }
+  OS << '\n';
+  return true;
+}
+
 static const EnumEntry<unsigned> FreeBSDFeatureCtlFlags[] = {
     {"ASLR_DISABLE", NT_FREEBSD_FCTL_ASLR_DISABLE},
     {"PROTMAX_DISABLE", NT_FREEBSD_FCTL_PROTMAX_DISABLE},
@@ -5254,6 +5274,15 @@
     {ELF::NT_AMDGPU_METADATA, "NT_AMDGPU_METADATA (AMDGPU Metadata)"},
 };
 
+static const NoteType LLVMOMPOFFLOADNoteTypes[] = {
+    {ELF::NT_LLVM_OPENMP_OFFLOAD_VERSION,
+     "NT_LLVM_OPENMP_OFFLOAD_VERSION (image format version)"},
+    {ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER,
+     "NT_LLVM_OPENMP_OFFLOAD_PRODUCER (producing toolchain)"},
+    {ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION,
+     "NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION (producing toolchain version)"},
+};
+
 static const NoteType CoreNoteTypes[] = {
     {ELF::NT_PRSTATUS, "NT_PRSTATUS (prstatus structure)"},
     {ELF::NT_FPREGSET, "NT_FPREGSET (floating point registers)"},
@@ -5347,6 +5376,8 @@
     return FindNote(AMDNoteTypes);
   if (Name == "AMDGPU")
     return FindNote(AMDGPUNoteTypes);
+  if (Name == "LLVMOMPOFFLOAD")
+    return FindNote(LLVMOMPOFFLOADNoteTypes);
 
   if (ELFType == ELF::ET_CORE)
     return FindNote(CoreNoteTypes);
@@ -5482,6 +5513,9 @@
         OS << "    " << N.Type << ":\n        " << N.Value << '\n';
         return Error::success();
       }
+    } else if (Name == "LLVMOMPOFFLOAD") {
+      if (printLLVMOMPOFFLOADNote<ELFT>(OS, Type, Descriptor))
+        return Error::success();
     } else if (Name == "CORE") {
       if (Type == ELF::NT_FILE) {
         DataExtractor DescExtractor(Descriptor,
@@ -6728,7 +6762,7 @@
     break;
   }
   case ELF::NT_GNU_GOLD_VERSION:
-    W.printString("Version", getGNUGoldVersion(Desc));
+    W.printString("Version", getDescAsStringRef(Desc));
     break;
   case ELF::NT_GNU_PROPERTY_TYPE_0:
     ListScope D(W, "Property");
@@ -6739,6 +6773,26 @@
   return true;
 }
 
+template <typename ELFT>
+static bool printLLVMOMPOFFLOADNoteLLVMStyle(uint32_t NoteType,
+                                             ArrayRef<uint8_t> Desc,
+                                             ScopedPrinter &W) {
+  switch (NoteType) {
+  default:
+    return false;
+  case ELF::NT_LLVM_OPENMP_OFFLOAD_VERSION:
+    W.printString("Version", getDescAsStringRef(Desc));
+    break;
+  case ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER:
+    W.printString("Producer", getDescAsStringRef(Desc));
+    break;
+  case ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION:
+    W.printString("Producer version", getDescAsStringRef(Desc));
+    break;
+  }
+  return true;
+}
+
 static void printCoreNoteLLVMStyle(const CoreNote &Note, ScopedPrinter &W) {
   W.printNumber("Page Size", Note.PageSize);
   for (const CoreFileMapping &Mapping : Note.Mappings) {
@@ -6806,6 +6860,9 @@
         W.printString(N.Type, N.Value);
         return Error::success();
       }
+    } else if (Name == "LLVMOMPOFFLOAD") {
+      if (printLLVMOMPOFFLOADNoteLLVMStyle<ELFT>(Type, Descriptor, W))
+        return Error::success();
     } else if (Name == "CORE") {
       if (Type == ELF::NT_FILE) {
         DataExtractor DescExtractor(Descriptor,
Index: llvm/include/llvm/BinaryFormat/ELF.h
===================================================================
--- llvm/include/llvm/BinaryFormat/ELF.h
+++ llvm/include/llvm/BinaryFormat/ELF.h
@@ -1606,6 +1606,13 @@
   NT_AMDGPU_METADATA = 32
 };
 
+// LLVMOMPOFFLOAD specific notes.
+enum : unsigned {
+  NT_LLVM_OPENMP_OFFLOAD_VERSION = 1,
+  NT_LLVM_OPENMP_OFFLOAD_PRODUCER = 2,
+  NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION = 3
+};
+
 enum {
   GNU_ABI_TAG_LINUX = 0,
   GNU_ABI_TAG_HURD = 1,
Index: clang/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp
===================================================================
--- clang/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp
+++ clang/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp
@@ -17,26 +17,35 @@
 #include "clang/Basic/Version.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/BinaryFormat/ELF.h"
 #include "llvm/Bitcode/BitcodeWriter.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/EndianStream.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Program.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/VCSRevision.h"
 #include "llvm/Support/WithColor.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Transforms/Utils/ModuleUtils.h"
 #include <cassert>
 #include <cstdint>
 
+#define OPENMP_OFFLOAD_IMAGE_VERSION "1.0"
+
 using namespace llvm;
+using namespace llvm::object;
 
 static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
 
@@ -59,6 +68,11 @@
            cl::desc("Target triple for the output module"),
            cl::value_desc("triple"), cl::cat(ClangOffloadWrapperCategory));
 
+static cl::opt<bool> SaveTemps("save-temps",
+    cl::desc("Save temporary files that may be produced by the tool. "
+             "This option forces print-out of the temporary files' names."),
+    cl::Hidden);
+
 namespace {
 
 class BinaryWrapper {
@@ -69,6 +83,15 @@
   StructType *ImageTy = nullptr;
   StructType *DescTy = nullptr;
 
+  std::string ToolName;
+  std::string ObjcopyPath;
+  // Temporary file names that may be created during adding notes
+  // to ELF offload images. Use -save-temps to keep them and also
+  // see their names. A temporary file's name includes the name
+  // of the original input ELF image, so you can easily match
+  // them, if you have multiple inputs.
+  std::vector<std::string> TempFiles;
+
 private:
   IntegerType *getSizeTTy() {
     switch (M.getDataLayout().getPointerTypeSize(Type::getInt8PtrTy(C))) {
@@ -293,8 +316,48 @@
   }
 
 public:
-  BinaryWrapper(StringRef Target) : M("offload.wrapper.object", C) {
+  BinaryWrapper(StringRef Target, StringRef ToolName)
+    : M("offload.wrapper.object", C), ToolName(ToolName) {
     M.setTargetTriple(Target);
+    ErrorOr<std::string> ObjcopyPathOrErr =
+        sys::findProgramByName("llvm-objcopy");
+    if (!ObjcopyPathOrErr) {
+#ifdef _WIN32
+      // Look for llvm-objcopy.exe as well.
+      ObjcopyPathOrErr = sys::findProgramByName("llvm-objcopy.exe");
+      if (!ObjcopyPathOrErr) {
+#endif // _WIN32
+        WithColor::warning(errs(), ToolName) <<
+          "cannot find llvm-objcopy[.exe] in PATH; ELF notes cannot be added.\n";
+#ifdef _WIN32
+      }
+#endif // _WIN32
+    }
+
+    if (ObjcopyPathOrErr)
+      ObjcopyPath = *ObjcopyPathOrErr;
+  }
+
+  ~BinaryWrapper() {
+    if (TempFiles.empty())
+      return;
+
+    StringRef ToolNameRef(ToolName);
+    auto warningOS = [ToolNameRef]() -> raw_ostream & {
+      return WithColor::warning(errs(), ToolNameRef);
+    };
+
+    for (auto &F : TempFiles) {
+      if (SaveTemps) {
+        warningOS() << "keeping temporary file " << F << "\n";
+        continue;
+      }
+
+      auto EC = sys::fs::remove(F, false);
+      if (EC)
+        warningOS() << "cannot remove temporary file " << F <<
+            ": " << EC.message().c_str() << "\n";
+    }
   }
 
   const Module &wrapBinaries(ArrayRef<ArrayRef<char>> Binaries) {
@@ -304,6 +367,204 @@
     createUnregisterFunction(Desc);
     return M;
   }
+
+  std::unique_ptr<MemoryBuffer> addELFNotes(
+      std::unique_ptr<MemoryBuffer> Buf,
+      StringRef OriginalFileName) {
+    // Cannot add notes, if llvm-objcopy is not available.
+    //
+    // I did not find a clean way to add a new notes section into an existing
+    // ELF file. llvm-objcopy seems to recreate a new ELF from scratch,
+    // and we just try to use llvm-objcopy here.
+    if (ObjcopyPath.empty())
+      return std::move(Buf);
+
+    StringRef ToolNameRef(ToolName);
+
+    // Helpers to emit warnings.
+    auto warningOS = [ToolNameRef]() -> raw_ostream & {
+      return WithColor::warning(errs(), ToolNameRef);
+    };
+    auto handleErrorAsWarning = [ToolNameRef, &warningOS](Error E) {
+      logAllUnhandledErrors(std::move(E), warningOS());
+    };
+
+    Expected<std::unique_ptr<ObjectFile>> BinOrErr =
+        ObjectFile::createELFObjectFile(Buf->getMemBufferRef(),
+                                        /*InitContent=*/false);
+    if (Error E = BinOrErr.takeError()) {
+      consumeError(std::move(E));
+      // This warning is questionable, but let it be here,
+      // assuming that most OpenMP offload models use ELF offload images.
+      warningOS() << OriginalFileName <<
+          " is not an ELF image, so notes cannot be added to it.\n";
+      return std::move(Buf);
+    }
+
+    // If we fail to add the note section, we just pass through the original
+    // ELF image for wrapping. At some point we should enforce the note section
+    // and start emitting errors vs warnings.
+    support::endianness Endianness;
+    if (isa<ELF64LEObjectFile>(BinOrErr->get()) ||
+        isa<ELF32LEObjectFile>(BinOrErr->get())) {
+      Endianness = support::little;
+    } else if (isa<ELF64BEObjectFile>(BinOrErr->get()) ||
+               isa<ELF32BEObjectFile>(BinOrErr->get())) {
+      Endianness = support::big;
+    } else {
+      warningOS() << OriginalFileName <<
+          " is an ELF image of unrecognized format.\n";
+      return std::move(Buf);
+    }
+
+    // Create temporary file for the data of a new SHT_NOTE section.
+    // We fill it in with data and then pass to llvm-objcopy invocation
+    // for reading.
+    Twine NotesFileModel = OriginalFileName + Twine(".elfnotes.%%%%%%%.tmp");
+    Expected<sys::fs::TempFile> NotesTemp =
+        sys::fs::TempFile::create(NotesFileModel);
+    if (Error E = NotesTemp.takeError()) {
+      handleErrorAsWarning(createFileError(NotesFileModel, std::move(E)));
+      return std::move(Buf);
+    }
+    TempFiles.push_back(NotesTemp->TmpName);
+
+    // Create temporary file for the updated ELF image.
+    // This is an empty file that we pass to llvm-objcopy invocation
+    // for writing.
+    Twine ELFFileModel = OriginalFileName + Twine(".elfwithnotes.%%%%%%%.tmp");
+    Expected<sys::fs::TempFile> ELFTemp =
+        sys::fs::TempFile::create(ELFFileModel);
+    if (Error E = ELFTemp.takeError()) {
+      handleErrorAsWarning(createFileError(ELFFileModel, std::move(E)));
+      return std::move(Buf);
+    }
+    TempFiles.push_back(ELFTemp->TmpName);
+
+    // Keep the new ELF image file to reserve the name for the future
+    // llvm-objcopy invocation.
+    std::string ELFTmpFileName = ELFTemp->TmpName;
+    if (Error E = ELFTemp->keep(ELFTmpFileName)) {
+      handleErrorAsWarning(createFileError(ELFTmpFileName, std::move(E)));
+      return std::move(Buf);
+    }
+
+    // Write notes to the *elfnotes*.tmp file.
+    raw_fd_ostream NotesOS(NotesTemp->FD, false);
+
+    struct NoteTy {
+      // Note name is a null-terminated "LLVMOMPOFFLOAD".
+      std::string Name;
+      // Note type defined in llvm/include/llvm/BinaryFormat/ELF.h.
+      uint32_t Type = 0;
+      // Each note has type-specific associated data.
+      std::string Desc;
+
+      NoteTy(std::string &&Name, uint32_t Type, std::string &&Desc)
+        : Name(std::move(Name)), Type(Type), Desc(std::move(Desc)) {}
+    };
+
+    // So far we emit just three notes.
+    SmallVector<NoteTy, 3> Notes;
+    // Version of the offload image identifying the structure of the ELF image.
+    // Version 1.0 does not have any specific requirements.
+    // We may come up with some structure that has to be honored by all
+    // offload implementations in future (e.g. to let libomptarget
+    // get some information from the offload image).
+    Notes.emplace_back("LLVMOMPOFFLOAD", ELF::NT_LLVM_OPENMP_OFFLOAD_VERSION,
+        OPENMP_OFFLOAD_IMAGE_VERSION);
+    // This is a producer identification string. We are LLVM!
+    Notes.emplace_back("LLVMOMPOFFLOAD", ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER,
+        "LLVM");
+    // This is a producer version. Use the same format that is used
+    // by clang to report the LLVM version.
+    Notes.emplace_back("LLVMOMPOFFLOAD",
+        ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION, LLVM_VERSION_STRING
+#ifdef LLVM_REVISION
+        " " LLVM_REVISION
+#endif
+        );
+
+    // Return the amount of padding required for a blob of N bytes
+    // to be aligned to Alignment bytes.
+    auto getPadAmount = [](uint32_t N, uint32_t Alignment) -> uint32_t {
+      uint32_t Mod = (N % Alignment);
+      if (Mod == 0)
+        return 0;
+      return Alignment - Mod;
+    };
+    auto emitPadding = [&getPadAmount](raw_ostream &OS, uint32_t Size) {
+      for (uint32_t I = 0; I < getPadAmount(Size, 4); ++I)
+        OS << '\0';
+    };
+
+    // Put notes into the file.
+    for (auto &N : Notes) {
+      assert(!N.Name.empty() && "We should not create notes with empty names.");
+      // Name must be null-terminated.
+      if (N.Name.back() != '\0')
+        N.Name += '\0';
+      uint32_t NameSz = N.Name.size();
+      uint32_t DescSz = N.Desc.size();
+      // A note starts with three 4-byte values:
+      //   NameSz
+      //   DescSz
+      //   Type
+      // These three fields are endian-sensitive.
+      support::endian::write<uint32_t>(NotesOS, NameSz, Endianness);
+      support::endian::write<uint32_t>(NotesOS, DescSz, Endianness);
+      support::endian::write<uint32_t>(NotesOS, N.Type, Endianness);
+      // Next, we have a null-terminated Name padded to a 4-byte boundary.
+      NotesOS << N.Name;
+      emitPadding(NotesOS, NameSz);
+      if (DescSz == 0)
+        continue;
+      // Finally, we have a descriptor, which is an arbitrary flow of bytes.
+      NotesOS << N.Desc;
+      emitPadding(NotesOS, DescSz);
+    }
+    NotesOS.flush();
+
+    // Keep the notes file.
+    std::string NotesTmpFileName = NotesTemp->TmpName;
+    if (Error E = NotesTemp->keep(NotesTmpFileName)) {
+      handleErrorAsWarning(createFileError(NotesTmpFileName, std::move(E)));
+      return std::move(Buf);
+    }
+
+    // Run llvm-objcopy like this:
+    //   llvm-objcopy --add-section=.note.openmp=<notes-tmp-file-name> \
+    //       <orig-file-name> <elf-tmp-file-name>
+    //
+    // This will add a SHT_NOTE section on top of the original ELF.
+    std::vector<StringRef> Args;
+    Args.push_back(ObjcopyPath);
+    std::string Option("--add-section=.note.openmp=" + NotesTmpFileName);
+    Args.push_back(Option);
+    Args.push_back(OriginalFileName);
+    Args.push_back(ELFTmpFileName);
+    bool ExecutionFailed = false;
+    std::string ErrMsg;
+    (void)sys::ExecuteAndWait(ObjcopyPath, Args,
+        /*Env=*/llvm::None, /*Redirects=*/{}, /*SecondsToWait=*/0,
+        /*MemoryLimit=*/0, &ErrMsg, &ExecutionFailed);
+
+    if (ExecutionFailed) {
+      warningOS() << ErrMsg << "\n";
+      return std::move(Buf);
+    }
+
+    // Substitute the original ELF with new one.
+    ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+        MemoryBuffer::getFile(ELFTmpFileName);
+    if (!BufOrErr) {
+      handleErrorAsWarning(createFileError(ELFTmpFileName,
+                                           BufOrErr.getError()));
+      return std::move(Buf);
+    }
+
+    return std::move(*BufOrErr);
+  }
 };
 
 } // anonymous namespace
@@ -337,6 +598,8 @@
     return 1;
   }
 
+  BinaryWrapper Wrapper(Target, argv[0]);
+
   // Read device binaries.
   SmallVector<std::unique_ptr<MemoryBuffer>, 4u> Buffers;
   SmallVector<ArrayRef<char>, 4u> Images;
@@ -349,8 +612,13 @@
       reportError(createFileError(File, BufOrErr.getError()));
       return 1;
     }
+    std::unique_ptr<MemoryBuffer> Buffer(std::move(*BufOrErr));
+    if (File != "-") {
+      // Adding ELF notes for STDIN is not supported yet.
+      Buffer = Wrapper.addELFNotes(std::move(Buffer), File);
+    }
     const std::unique_ptr<MemoryBuffer> &Buf =
-        Buffers.emplace_back(std::move(*BufOrErr));
+        Buffers.emplace_back(std::move(Buffer));
     Images.emplace_back(Buf->getBufferStart(), Buf->getBufferSize());
   }
 
@@ -363,7 +631,7 @@
   }
 
   // Create a wrapper for device binaries and write its bitcode to the file.
-  WriteBitcodeToFile(BinaryWrapper(Target).wrapBinaries(
+  WriteBitcodeToFile(Wrapper.wrapBinaries(
                          makeArrayRef(Images.data(), Images.size())),
                      Out.os());
   if (Out.os().has_error()) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to