Skip to content

Commit 15d1fa1

Browse files
committedAug 27, 2015
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
1 parent dc8c489 commit 15d1fa1

19 files changed

+489
-4
lines changed
 

‎lld/include/lld/Core/Reference.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class Reference {
5656
void setKindNamespace(KindNamespace ns) { _kindNamespace = (uint8_t)ns; }
5757

5858
// Which architecture the kind value is for.
59-
enum class KindArch { all, AArch64, ARM, Hexagon, Mips, x86, x86_64 };
59+
enum class KindArch { all, AArch64, AMDGPU, ARM, Hexagon, Mips, x86, x86_64 };
6060

6161
KindArch kindArch() const { return (KindArch)_kindArch; }
6262
void setKindArch(KindArch a) { _kindArch = (uint8_t)a; }

‎lld/include/lld/ReaderWriter/ELFLinkingContext.h

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ using llvm::object::ELF64BE;
4444
class ELFWriter;
4545

4646
std::unique_ptr<ELFLinkingContext> createAArch64LinkingContext(llvm::Triple);
47+
std::unique_ptr<ELFLinkingContext> createAMDGPULinkingContext(llvm::Triple);
4748
std::unique_ptr<ELFLinkingContext> createARMLinkingContext(llvm::Triple);
4849
std::unique_ptr<ELFLinkingContext> createExampleLinkingContext(llvm::Triple);
4950
std::unique_ptr<ELFLinkingContext> createHexagonLinkingContext(llvm::Triple);

‎lld/lib/Driver/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ add_llvm_library(lldDriver
2121
lldELF
2222
lldELF2
2323
lldAArch64ELFTarget
24+
lldAMDGPUELFTarget
2425
lldARMELFTarget
2526
lldHexagonELFTarget
2627
lldMipsELFTarget

‎lld/lib/Driver/GnuLdDriver.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ std::unique_ptr<ELFLinkingContext>
329329
GnuLdDriver::createELFLinkingContext(llvm::Triple triple) {
330330
std::unique_ptr<ELFLinkingContext> p;
331331
if ((p = elf::createAArch64LinkingContext(triple))) return p;
332+
if ((p = elf::createAMDGPULinkingContext(triple))) return p;
332333
if ((p = elf::createARMLinkingContext(triple))) return p;
333334
if ((p = elf::createExampleLinkingContext(triple))) return p;
334335
if ((p = elf::createHexagonLinkingContext(triple))) return p;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.cpp -------------===//
2+
//
3+
// The LLVM Linker
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "AMDGPUExecutableWriter.h"
11+
12+
using namespace lld::elf;
13+
14+
AMDGPUExecutableWriter::AMDGPUExecutableWriter(AMDGPULinkingContext &ctx,
15+
AMDGPUTargetLayout &layout)
16+
: ExecutableWriter(ctx, layout), _ctx(ctx), _targetLayout(layout) {}
17+
18+
void AMDGPUExecutableWriter::createImplicitFiles(
19+
std::vector<std::unique_ptr<File>> &Result) {
20+
// ExecutableWriter::createImplicitFiles() adds C runtime symbols that we
21+
// don't need, so we use the OutputELFWriter implementation instead.
22+
OutputELFWriter<ELF64LE>::createImplicitFiles(Result);
23+
}
24+
25+
void AMDGPUExecutableWriter::finalizeDefaultAtomValues() {
26+
27+
// ExecutableWriter::finalizeDefaultAtomValues() assumes the presence of
28+
// C runtime symbols. However, since we skip the call to
29+
// ExecutableWriter::createImplicitFiles(), these symbols are never added
30+
// and ExectuableWriter::finalizeDefaultAtomValues() will crash if we call
31+
// it.
32+
OutputELFWriter<ELF64LE>::finalizeDefaultAtomValues();
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.h ---------------===//
2+
//
3+
// The LLVM Linker
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
#ifndef AMDGPU_EXECUTABLE_WRITER_H
10+
#define AMDGPU_EXECUTABLE_WRITER_H
11+
12+
#include "ExecutableWriter.h"
13+
#include "AMDGPULinkingContext.h"
14+
#include "AMDGPUSymbolTable.h"
15+
#include "AMDGPUTargetHandler.h"
16+
17+
namespace lld {
18+
namespace elf {
19+
20+
class AMDGPUTargetLayout;
21+
22+
class AMDGPUExecutableWriter : public ExecutableWriter<ELF64LE> {
23+
public:
24+
AMDGPUExecutableWriter(AMDGPULinkingContext &ctx, AMDGPUTargetLayout &layout);
25+
26+
unique_bump_ptr<SymbolTable<ELF64LE>> createSymbolTable() override {
27+
return unique_bump_ptr<SymbolTable<ELF64LE>>(new (this->_alloc)
28+
AMDGPUSymbolTable(_ctx));
29+
}
30+
31+
void createImplicitFiles(std::vector<std::unique_ptr<File>> &Result) override;
32+
void finalizeDefaultAtomValues() override;
33+
34+
private:
35+
AMDGPULinkingContext &_ctx;
36+
AMDGPUTargetLayout &_targetLayout;
37+
};
38+
39+
} // namespace elf
40+
} // namespace lld
41+
42+
#endif // AMDGPU_EXECUTABLE_WRITER_H
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.cpp ---------------===//
2+
//
3+
// The LLVM Linker
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===------------------------------------------------------------------------===//
9+
10+
#include "AMDGPULinkingContext.h"
11+
#include "AMDGPUTargetHandler.h"
12+
13+
namespace lld {
14+
namespace elf {
15+
16+
std::unique_ptr<ELFLinkingContext>
17+
createAMDGPULinkingContext(llvm::Triple triple) {
18+
if (triple.getArch() == llvm::Triple::amdgcn)
19+
return llvm::make_unique<AMDGPULinkingContext>(triple);
20+
return nullptr;
21+
}
22+
23+
AMDGPULinkingContext::AMDGPULinkingContext(llvm::Triple triple)
24+
: ELFLinkingContext(triple, llvm::make_unique<AMDGPUTargetHandler>(*this)) {
25+
}
26+
27+
static const Registry::KindStrings kindStrings[] = {LLD_KIND_STRING_END};
28+
29+
void AMDGPULinkingContext::registerRelocationNames(Registry &registry) {
30+
registry.addKindTable(Reference::KindNamespace::ELF,
31+
Reference::KindArch::AMDGPU, kindStrings);
32+
}
33+
34+
void setAMDGPUELFHeader(ELFHeader<ELF64LE> &elfHeader) {
35+
elfHeader.e_ident(llvm::ELF::EI_OSABI, ELFOSABI_AMDGPU_HSA);
36+
}
37+
38+
StringRef AMDGPULinkingContext::entrySymbolName() const { return ""; }
39+
40+
} // namespace elf
41+
} // namespace lld
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.h ---------------===//
2+
//
3+
// The LLVM Linker
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_LINKING_CONTEXT_H
11+
#define LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_LINKING_CONTEXT_H
12+
13+
#include "OutputELFWriter.h"
14+
#include "lld/ReaderWriter/ELFLinkingContext.h"
15+
#include "llvm/Object/ELF.h"
16+
#include "llvm/Support/ELF.h"
17+
18+
namespace lld {
19+
namespace elf {
20+
21+
class AMDGPULinkingContext final : public ELFLinkingContext {
22+
public:
23+
AMDGPULinkingContext(llvm::Triple triple);
24+
int getMachineType() const override { return llvm::ELF::EM_AMDGPU; }
25+
26+
void registerRelocationNames(Registry &r) override;
27+
28+
StringRef entrySymbolName() const override;
29+
};
30+
31+
void setAMDGPUELFHeader(ELFHeader<ELF64LE> &elfHeader);
32+
33+
} // elf
34+
} // lld
35+
36+
#endif // LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_LINKING_CONTEXT_H
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.cpp -----------===//
2+
//
3+
// The LLVM Linker
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "AMDGPURelocationHandler.h"
11+
12+
using namespace lld::elf;
13+
14+
std::error_code AMDGPUTargetRelocationHandler::applyRelocation(
15+
ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
16+
const Reference &ref) const {
17+
return std::error_code();
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===- lld/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.h --------------===//
2+
//
3+
// The LLVM Linker
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
#ifndef LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_RELOCATION_HANDLER_H
10+
#define LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_RELOCATION_HANDLER_H
11+
12+
#include "lld/ReaderWriter/ELFLinkingContext.h"
13+
14+
namespace lld {
15+
namespace elf {
16+
class AMDGPUTargetHandler;
17+
class AMDGPUTargetLayout;
18+
19+
class AMDGPUTargetRelocationHandler final : public TargetRelocationHandler {
20+
public:
21+
AMDGPUTargetRelocationHandler(AMDGPUTargetLayout &layout)
22+
: _targetLayout(layout) {}
23+
24+
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
25+
const AtomLayout &,
26+
const Reference &) const override;
27+
28+
private:
29+
AMDGPUTargetLayout &_targetLayout;
30+
};
31+
} // elf
32+
} // lld
33+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===--------- lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.cpp ----------===//
2+
//
3+
// The LLVM Linker
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "AMDGPUSymbolTable.h"
11+
#include "ELFFile.h"
12+
#include "Atoms.h"
13+
#include "SectionChunks.h"
14+
15+
using namespace lld::elf;
16+
17+
AMDGPUSymbolTable::AMDGPUSymbolTable(const ELFLinkingContext &ctx)
18+
: SymbolTable(ctx, ".symtab", TargetLayout<ELF64LE>::ORDER_SYMBOL_TABLE) {}
19+
20+
void AMDGPUSymbolTable::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
21+
int64_t addr) {
22+
SymbolTable::addDefinedAtom(sym, da, addr);
23+
24+
// FIXME: Only do this for kernel functions.
25+
sym.setType(STT_AMDGPU_HSA_KERNEL);
26+
27+
// Make st_value section relative.
28+
// FIXME: This is hack to give kernel symbols a section relative offset.
29+
// Because of this hack only on kernel can be included in a binary file.
30+
sym.st_value = 0;
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//===--------- lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.h ------------===//
2+
//
3+
// The LLVM Linker
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_SYMBOL_TABLE_H
11+
#define LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_SYMBOL_TABLE_H
12+
13+
#include "TargetLayout.h"
14+
15+
namespace lld {
16+
namespace elf {
17+
18+
/// \brief The SymbolTable class represents the symbol table in a ELF file
19+
class AMDGPUSymbolTable : public SymbolTable<ELF64LE> {
20+
public:
21+
typedef llvm::object::Elf_Sym_Impl<ELF64LE> Elf_Sym;
22+
23+
AMDGPUSymbolTable(const ELFLinkingContext &ctx);
24+
25+
void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
26+
int64_t addr) override;
27+
};
28+
29+
} // elf
30+
} // lld
31+
32+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.cpp ----------------===//
2+
//
3+
// The LLVM Linker
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "TargetLayout.h"
11+
#include "AMDGPUExecutableWriter.h"
12+
#include "AMDGPULinkingContext.h"
13+
#include "AMDGPUTargetHandler.h"
14+
#include "llvm/Support/ELF.h"
15+
16+
namespace lld {
17+
namespace elf {
18+
19+
AMDGPUTargetHandler::AMDGPUTargetHandler(AMDGPULinkingContext &ctx)
20+
: _ctx(ctx), _targetLayout(new AMDGPUTargetLayout(ctx)),
21+
_relocationHandler(new AMDGPUTargetRelocationHandler(*_targetLayout)) {}
22+
23+
std::unique_ptr<Writer> AMDGPUTargetHandler::getWriter() {
24+
switch (_ctx.getOutputELFType()) {
25+
case llvm::ELF::ET_EXEC:
26+
return llvm::make_unique<AMDGPUExecutableWriter>(_ctx, *_targetLayout);
27+
case llvm::ELF::ET_DYN:
28+
llvm_unreachable("TODO: support dynamic libraries");
29+
case llvm::ELF::ET_REL:
30+
llvm_unreachable("TODO: support -r mode");
31+
default:
32+
llvm_unreachable("unsupported output type");
33+
}
34+
}
35+
36+
HSATextSection::HSATextSection(const ELFLinkingContext &ctx)
37+
: AtomSection(ctx, ".text", DefinedAtom::typeCode, 0, 0) {
38+
_type = SHT_PROGBITS;
39+
_flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR | SHF_AMDGPU_HSA_AGENT |
40+
SHF_AMDGPU_HSA_CODE;
41+
42+
// FIXME: What alignment should we use here?
43+
_alignment = 4096;
44+
}
45+
46+
void AMDGPUTargetLayout::assignSectionsToSegments() {
47+
48+
TargetLayout::assignSectionsToSegments();
49+
for (OutputSection<ELF64LE> *osi : _outputSections) {
50+
for (Section<ELF64LE> *section : osi->sections()) {
51+
StringRef InputSectionName = section->inputSectionName();
52+
if (InputSectionName != ".text")
53+
continue;
54+
55+
Segment<ELF64LE> *segment = new (_allocator) Segment<ELF64LE>(
56+
_ctx, "PT_AMDGPU_HSA_LOAD_CODE_AGENT", PT_AMDGPU_HSA_LOAD_CODE_AGENT);
57+
_segments.push_back(segment);
58+
assert(segment);
59+
segment->append(section);
60+
}
61+
}
62+
}
63+
64+
} // namespace elf
65+
} // namespace lld

0 commit comments

Comments
 (0)
Please sign in to comment.