ELF: Add AMDGPU ReaderWriter

This is a basic implementation that allows lld to emit binaries
consumable by the HSA runtime.

Differential Revision: http://reviews.llvm.org/D11267

llvm-svn: 246155
This commit is contained in:
Tom Stellard 2015-08-27 15:55:44 +00:00
parent dc8c48924a
commit 15d1fa1bcc
19 changed files with 489 additions and 4 deletions

View File

@ -56,7 +56,7 @@ public:
void setKindNamespace(KindNamespace ns) { _kindNamespace = (uint8_t)ns; }
// Which architecture the kind value is for.
enum class KindArch { all, AArch64, ARM, Hexagon, Mips, x86, x86_64 };
enum class KindArch { all, AArch64, AMDGPU, ARM, Hexagon, Mips, x86, x86_64 };
KindArch kindArch() const { return (KindArch)_kindArch; }
void setKindArch(KindArch a) { _kindArch = (uint8_t)a; }

View File

@ -44,6 +44,7 @@ using llvm::object::ELF64BE;
class ELFWriter;
std::unique_ptr<ELFLinkingContext> createAArch64LinkingContext(llvm::Triple);
std::unique_ptr<ELFLinkingContext> createAMDGPULinkingContext(llvm::Triple);
std::unique_ptr<ELFLinkingContext> createARMLinkingContext(llvm::Triple);
std::unique_ptr<ELFLinkingContext> createExampleLinkingContext(llvm::Triple);
std::unique_ptr<ELFLinkingContext> createHexagonLinkingContext(llvm::Triple);

View File

@ -21,6 +21,7 @@ add_llvm_library(lldDriver
lldELF
lldELF2
lldAArch64ELFTarget
lldAMDGPUELFTarget
lldARMELFTarget
lldHexagonELFTarget
lldMipsELFTarget

View File

@ -329,6 +329,7 @@ std::unique_ptr<ELFLinkingContext>
GnuLdDriver::createELFLinkingContext(llvm::Triple triple) {
std::unique_ptr<ELFLinkingContext> p;
if ((p = elf::createAArch64LinkingContext(triple))) return p;
if ((p = elf::createAMDGPULinkingContext(triple))) return p;
if ((p = elf::createARMLinkingContext(triple))) return p;
if ((p = elf::createExampleLinkingContext(triple))) return p;
if ((p = elf::createHexagonLinkingContext(triple))) return p;

View File

@ -0,0 +1,33 @@
//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.cpp -------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "AMDGPUExecutableWriter.h"
using namespace lld::elf;
AMDGPUExecutableWriter::AMDGPUExecutableWriter(AMDGPULinkingContext &ctx,
AMDGPUTargetLayout &layout)
: ExecutableWriter(ctx, layout), _ctx(ctx), _targetLayout(layout) {}
void AMDGPUExecutableWriter::createImplicitFiles(
std::vector<std::unique_ptr<File>> &Result) {
// ExecutableWriter::createImplicitFiles() adds C runtime symbols that we
// don't need, so we use the OutputELFWriter implementation instead.
OutputELFWriter<ELF64LE>::createImplicitFiles(Result);
}
void AMDGPUExecutableWriter::finalizeDefaultAtomValues() {
// ExecutableWriter::finalizeDefaultAtomValues() assumes the presence of
// C runtime symbols. However, since we skip the call to
// ExecutableWriter::createImplicitFiles(), these symbols are never added
// and ExectuableWriter::finalizeDefaultAtomValues() will crash if we call
// it.
OutputELFWriter<ELF64LE>::finalizeDefaultAtomValues();
}

View File

@ -0,0 +1,42 @@
//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.h ---------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef AMDGPU_EXECUTABLE_WRITER_H
#define AMDGPU_EXECUTABLE_WRITER_H
#include "ExecutableWriter.h"
#include "AMDGPULinkingContext.h"
#include "AMDGPUSymbolTable.h"
#include "AMDGPUTargetHandler.h"
namespace lld {
namespace elf {
class AMDGPUTargetLayout;
class AMDGPUExecutableWriter : public ExecutableWriter<ELF64LE> {
public:
AMDGPUExecutableWriter(AMDGPULinkingContext &ctx, AMDGPUTargetLayout &layout);
unique_bump_ptr<SymbolTable<ELF64LE>> createSymbolTable() override {
return unique_bump_ptr<SymbolTable<ELF64LE>>(new (this->_alloc)
AMDGPUSymbolTable(_ctx));
}
void createImplicitFiles(std::vector<std::unique_ptr<File>> &Result) override;
void finalizeDefaultAtomValues() override;
private:
AMDGPULinkingContext &_ctx;
AMDGPUTargetLayout &_targetLayout;
};
} // namespace elf
} // namespace lld
#endif // AMDGPU_EXECUTABLE_WRITER_H

View File

@ -0,0 +1,41 @@
//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.cpp ---------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===------------------------------------------------------------------------===//
#include "AMDGPULinkingContext.h"
#include "AMDGPUTargetHandler.h"
namespace lld {
namespace elf {
std::unique_ptr<ELFLinkingContext>
createAMDGPULinkingContext(llvm::Triple triple) {
if (triple.getArch() == llvm::Triple::amdgcn)
return llvm::make_unique<AMDGPULinkingContext>(triple);
return nullptr;
}
AMDGPULinkingContext::AMDGPULinkingContext(llvm::Triple triple)
: ELFLinkingContext(triple, llvm::make_unique<AMDGPUTargetHandler>(*this)) {
}
static const Registry::KindStrings kindStrings[] = {LLD_KIND_STRING_END};
void AMDGPULinkingContext::registerRelocationNames(Registry &registry) {
registry.addKindTable(Reference::KindNamespace::ELF,
Reference::KindArch::AMDGPU, kindStrings);
}
void setAMDGPUELFHeader(ELFHeader<ELF64LE> &elfHeader) {
elfHeader.e_ident(llvm::ELF::EI_OSABI, ELFOSABI_AMDGPU_HSA);
}
StringRef AMDGPULinkingContext::entrySymbolName() const { return ""; }
} // namespace elf
} // namespace lld

View File

@ -0,0 +1,36 @@
//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.h ---------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_LINKING_CONTEXT_H
#define LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_LINKING_CONTEXT_H
#include "OutputELFWriter.h"
#include "lld/ReaderWriter/ELFLinkingContext.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/ELF.h"
namespace lld {
namespace elf {
class AMDGPULinkingContext final : public ELFLinkingContext {
public:
AMDGPULinkingContext(llvm::Triple triple);
int getMachineType() const override { return llvm::ELF::EM_AMDGPU; }
void registerRelocationNames(Registry &r) override;
StringRef entrySymbolName() const override;
};
void setAMDGPUELFHeader(ELFHeader<ELF64LE> &elfHeader);
} // elf
} // lld
#endif // LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_LINKING_CONTEXT_H

View File

@ -0,0 +1,18 @@
//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.cpp -----------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "AMDGPURelocationHandler.h"
using namespace lld::elf;
std::error_code AMDGPUTargetRelocationHandler::applyRelocation(
ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
const Reference &ref) const {
return std::error_code();
}

View File

@ -0,0 +1,33 @@
//===- lld/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.h --------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_RELOCATION_HANDLER_H
#define LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_RELOCATION_HANDLER_H
#include "lld/ReaderWriter/ELFLinkingContext.h"
namespace lld {
namespace elf {
class AMDGPUTargetHandler;
class AMDGPUTargetLayout;
class AMDGPUTargetRelocationHandler final : public TargetRelocationHandler {
public:
AMDGPUTargetRelocationHandler(AMDGPUTargetLayout &layout)
: _targetLayout(layout) {}
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
const AtomLayout &,
const Reference &) const override;
private:
AMDGPUTargetLayout &_targetLayout;
};
} // elf
} // lld
#endif

View File

@ -0,0 +1,31 @@
//===--------- lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.cpp ----------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "AMDGPUSymbolTable.h"
#include "ELFFile.h"
#include "Atoms.h"
#include "SectionChunks.h"
using namespace lld::elf;
AMDGPUSymbolTable::AMDGPUSymbolTable(const ELFLinkingContext &ctx)
: SymbolTable(ctx, ".symtab", TargetLayout<ELF64LE>::ORDER_SYMBOL_TABLE) {}
void AMDGPUSymbolTable::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
int64_t addr) {
SymbolTable::addDefinedAtom(sym, da, addr);
// FIXME: Only do this for kernel functions.
sym.setType(STT_AMDGPU_HSA_KERNEL);
// Make st_value section relative.
// FIXME: This is hack to give kernel symbols a section relative offset.
// Because of this hack only on kernel can be included in a binary file.
sym.st_value = 0;
}

View File

@ -0,0 +1,32 @@
//===--------- lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.h ------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_SYMBOL_TABLE_H
#define LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_SYMBOL_TABLE_H
#include "TargetLayout.h"
namespace lld {
namespace elf {
/// \brief The SymbolTable class represents the symbol table in a ELF file
class AMDGPUSymbolTable : public SymbolTable<ELF64LE> {
public:
typedef llvm::object::Elf_Sym_Impl<ELF64LE> Elf_Sym;
AMDGPUSymbolTable(const ELFLinkingContext &ctx);
void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
int64_t addr) override;
};
} // elf
} // lld
#endif

View File

@ -0,0 +1,65 @@
//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.cpp ----------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "TargetLayout.h"
#include "AMDGPUExecutableWriter.h"
#include "AMDGPULinkingContext.h"
#include "AMDGPUTargetHandler.h"
#include "llvm/Support/ELF.h"
namespace lld {
namespace elf {
AMDGPUTargetHandler::AMDGPUTargetHandler(AMDGPULinkingContext &ctx)
: _ctx(ctx), _targetLayout(new AMDGPUTargetLayout(ctx)),
_relocationHandler(new AMDGPUTargetRelocationHandler(*_targetLayout)) {}
std::unique_ptr<Writer> AMDGPUTargetHandler::getWriter() {
switch (_ctx.getOutputELFType()) {
case llvm::ELF::ET_EXEC:
return llvm::make_unique<AMDGPUExecutableWriter>(_ctx, *_targetLayout);
case llvm::ELF::ET_DYN:
llvm_unreachable("TODO: support dynamic libraries");
case llvm::ELF::ET_REL:
llvm_unreachable("TODO: support -r mode");
default:
llvm_unreachable("unsupported output type");
}
}
HSATextSection::HSATextSection(const ELFLinkingContext &ctx)
: AtomSection(ctx, ".text", DefinedAtom::typeCode, 0, 0) {
_type = SHT_PROGBITS;
_flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR | SHF_AMDGPU_HSA_AGENT |
SHF_AMDGPU_HSA_CODE;
// FIXME: What alignment should we use here?
_alignment = 4096;
}
void AMDGPUTargetLayout::assignSectionsToSegments() {
TargetLayout::assignSectionsToSegments();
for (OutputSection<ELF64LE> *osi : _outputSections) {
for (Section<ELF64LE> *section : osi->sections()) {
StringRef InputSectionName = section->inputSectionName();
if (InputSectionName != ".text")
continue;
Segment<ELF64LE> *segment = new (_allocator) Segment<ELF64LE>(
_ctx, "PT_AMDGPU_HSA_LOAD_CODE_AGENT", PT_AMDGPU_HSA_LOAD_CODE_AGENT);
_segments.push_back(segment);
assert(segment);
segment->append(section);
}
}
}
} // namespace elf
} // namespace lld

View File

@ -0,0 +1,80 @@
//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.h ------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef AMDGPU_TARGET_HANDLER_H
#define AMDGPU_TARGET_HANDLER_H
#include "ELFFile.h"
#include "ELFReader.h"
#include "AMDGPURelocationHandler.h"
#include "TargetLayout.h"
namespace lld {
namespace elf {
class AMDGPULinkingContext;
class HSATextSection : public AtomSection<ELF64LE> {
public:
HSATextSection(const ELFLinkingContext &ctx);
};
/// \brief TargetLayout for AMDGPU
class AMDGPUTargetLayout final : public TargetLayout<ELF64LE> {
public:
AMDGPUTargetLayout(AMDGPULinkingContext &ctx) : TargetLayout(ctx) {}
void assignSectionsToSegments() override;
/// \brief Gets or creates a section.
AtomSection<ELF64LE> *
createSection(StringRef name, int32_t contentType,
DefinedAtom::ContentPermissions contentPermissions,
TargetLayout::SectionOrder sectionOrder) override {
if (name == ".text")
return new (_allocator) HSATextSection(_ctx);
if (name == ".note")
contentType = DefinedAtom::typeRONote;
return TargetLayout::createSection(name, contentType, contentPermissions,
sectionOrder);
}
};
/// \brief TargetHandler for AMDGPU
class AMDGPUTargetHandler final : public TargetHandler {
public:
AMDGPUTargetHandler(AMDGPULinkingContext &targetInfo);
const TargetRelocationHandler &getRelocationHandler() const override {
return *_relocationHandler;
}
std::unique_ptr<Reader> getObjReader() override {
return llvm::make_unique<ELFReader<ELFFile<ELF64LE>>>(_ctx);
}
std::unique_ptr<Reader> getDSOReader() override {
return llvm::make_unique<ELFReader<DynamicFile<ELF64LE>>>(_ctx);
}
std::unique_ptr<Writer> getWriter() override;
private:
AMDGPULinkingContext &_ctx;
std::unique_ptr<AMDGPUTargetLayout> _targetLayout;
std::unique_ptr<AMDGPUTargetRelocationHandler> _relocationHandler;
};
void finalizeAMDGPURuntimeAtomValues(AMDGPUTargetLayout &layout);
} // end namespace elf
} // end namespace lld
#endif

View File

@ -0,0 +1,13 @@
add_llvm_library(lldAMDGPUELFTarget
AMDGPUExecutableWriter.cpp
AMDGPULinkingContext.cpp
AMDGPURelocationHandler.cpp
AMDGPUSymbolTable.cpp
AMDGPUTargetHandler.cpp
LINK_LIBS
lldELF
lldReaderWriter
lldCore
LLVMObject
LLVMSupport
)

View File

@ -27,3 +27,4 @@ add_subdirectory(Mips)
add_subdirectory(Hexagon)
add_subdirectory(AArch64)
add_subdirectory(ARM)
add_subdirectory(AMDGPU)

View File

@ -196,12 +196,14 @@ protected:
/// Determines if the target wants to create an atom for a section that has no
/// symbol references.
bool handleSectionWithNoSymbols(const Elf_Shdr *shdr,
bool
handleSectionWithNoSymbols(const Elf_Shdr *shdr,
std::vector<const Elf_Sym *> &syms) const {
return shdr &&
(shdr->sh_type == llvm::ELF::SHT_PROGBITS ||
shdr->sh_type == llvm::ELF::SHT_INIT_ARRAY ||
shdr->sh_type == llvm::ELF::SHT_FINI_ARRAY) &&
shdr->sh_type == llvm::ELF::SHT_FINI_ARRAY ||
shdr->sh_type == llvm::ELF::SHT_NOTE) &&
syms.empty();
}

View File

@ -61,6 +61,8 @@ uint16_t ELFLinkingContext::getOutputMachine() const {
return llvm::ELF::EM_AARCH64;
case llvm::Triple::arm:
return llvm::ELF::EM_ARM;
case llvm::Triple::amdgcn:
return llvm::ELF::EM_AMDGPU;
default:
llvm_unreachable("Unhandled arch");
}

View File

@ -0,0 +1,53 @@
# RUN: yaml2obj -format=elf %s > %t.obj
# RUN: lld -flavor gnu -target amdgcn--hsa %t.obj -o %t.exe --noinhibit-exec
# RUN: llvm-readobj -h -program-headers -s -symbols %t.exe | FileCheck %s
# CHECK: ElfHeader {
# CHECK: Ident {
# CHECK: Class: 64-bit (0x2)
# CHECK: DataEncoding: LittleEndian (0x1)
# CHECK: Machine: EM_AMDGPU (0xE0)
# CHECK: Section {
# CHECK: Name: .text
# CHECK: Type: SHT_PROGBITS (0x1)
# CHECK: Flags [ (0xC00007
# CHECK: SHF_ALLOC (0x2)
# CHECK: SHF_AMDGPU_HSA_AGENT (0x800000)
# CHECK: SHF_AMDGPU_HSA_CODE (0x400000)
# CHECK: SHF_EXECINSTR (0x4)
# CHECK: SHF_WRITE (0x1)
#
# CHECK: Symbol {
# CHECK: Name: kernel
# CHECK: Value: 0x0
# CHECK: Binding: Local (0x0)
# CHECK: Type: AMDGPU_HSA_KERNEL (0xA)
# CHECK: ProgramHeader {
# CHECK: Type: PT_AMDGPU_HSA_LOAD_CODE_AGENT (0x60000003)
---
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
OSABI: ELFOSABI_GNU
Type: ET_REL
Machine: EM_AMDGPU
Sections:
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
AddressAlign: 0x0000000000000004
Content: ''
- Name: .note
Type: SHT_NOTE
AddressAlign: 0x0000000000000001
Content: '00'
Symbols:
Local:
- Name: kernel
Type: STT_GNU_IFUNC
Section: .text
...