Skip to content

Commit

Permalink
[host] Add initial support for RISC-V relocations
Browse files Browse the repository at this point in the history
This adds support for RISC-V relocations - enough to permit the running
of UnitCL (in the default configuration). There are obviously many other
relocations for RISC-V but without test coverage those have been left
for future work.

Note that relocation support is still incomplete. There is no support
yet for the PLT or GOT sections, so if the executable is loaded too far
away from external symbols, the relocation process will fail at program
load time, complaining of an unreachable symbol. This situation is
entirely down to the in-process memory of the OpenCL location and the
machine it's running on, so cannot be easily pre-determined.

Locally, at least, all (offline) UnitCL tests pass in isolation but fail
when run together, because the binary is loaded too far away from some
symbols such as memcpy.

The ADD32 and SUB32 relocations only seem to appear for the PIC
relocation model, which is not being used in main nor in this PR, but
they are simple enough that including them should be fairly obviously
correct.
  • Loading branch information
frasercrmck committed Mar 5, 2024
1 parent 7cd729b commit f4e845c
Show file tree
Hide file tree
Showing 5 changed files with 298 additions and 78 deletions.
21 changes: 14 additions & 7 deletions modules/compiler/targets/host/source/target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@
namespace host {

// Create a target machine, `abi` is optional and may be empty
static llvm::TargetMachine *createTargetMachine(llvm::StringRef CPU,
llvm::StringRef Triple,
static llvm::TargetMachine *createTargetMachine(llvm::Triple TT,
llvm::StringRef CPU,
llvm::StringRef Features,
llvm::StringRef ABI) {
// Init the llvm target machine.
llvm::TargetOptions Options;
std::string Error;
const std::string TripleStr = Triple.str();
const std::string &TripleStr = TT.str();
const llvm::Target *LLVMTarget =
llvm::TargetRegistry::lookupTarget(TripleStr, Error);
if (nullptr == LLVMTarget) {
Expand All @@ -73,6 +73,14 @@ static llvm::TargetMachine *createTargetMachine(llvm::StringRef CPU,
Options.MCOptions.ABIName = ABI;
}

std::optional<llvm::CodeModel::Model> CM;
// RISC-V needs the 'medium' code model as we don't ensure that the code and
// its statically defined symbols are loaded somewhere in the range of
// absolute addresses -2GB and +2GB, which is a requirement of the 'low' code
// model.
if (TT.isRISCV()) {
CM = llvm::CodeModel::Medium;
}
// Aarch64 fails on UnitCL test
// Execution/Execution.Barrier_02_Barrier_No_Duplicates/OfflineOpenCLC if we
// don't set `JIT` to true. JIT for x86_64 and Aarch64 set the large code
Expand All @@ -83,8 +91,8 @@ static llvm::TargetMachine *createTargetMachine(llvm::StringRef CPU,
// TODO: Investigate whether we can use a loader that does not have this
// issue.
return LLVMTarget->createTargetMachine(
Triple, CPU, Features, Options, /*RM=*/std::nullopt,
/*CM=*/std::nullopt, multi_llvm::CodeGenOptLevel::Aggressive,
TripleStr, CPU, Features, Options, /*RM=*/std::nullopt, CM,
multi_llvm::CodeGenOptLevel::Aggressive,
/*JIT=*/true);
}

Expand Down Expand Up @@ -372,8 +380,7 @@ compiler::Result HostTarget::initWithBuiltins(
Features += '-' + FeatureName.str();
}
}
target_machine.reset(
createTargetMachine(CPUName, triple.str(), Features, ABI));
target_machine.reset(createTargetMachine(triple, CPUName, Features, ABI));
}

return compiler::Result::SUCCESS;
Expand Down
3 changes: 2 additions & 1 deletion modules/loader/include/loader/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ enum class Machine : uint16_t {
MIPS = 0x08,
ARM = 0x28,
X86_64 = 0x3E,
AARCH64 = 0xB7
AARCH64 = 0xB7,
RISCV = 0xF3,
};
/// @brief Type of code the file contains.
enum class Type : uint16_t {
Expand Down
17 changes: 17 additions & 0 deletions modules/loader/include/loader/relocation_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,23 @@ enum Type : uint32_t {
R_AARCH64_P32_IRELATIVE = 0x0bc,
};
}

// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#relocations
namespace RISCV {
enum Type : uint32_t {
R_RISCV_NONE = 0,
R_RISCV_64 = 2,
R_RISCV_CALL = 18,
R_RISCV_CALL_PLT = 19,
R_RISCV_PCREL_HI20 = 23,
R_RISCV_PCREL_LO12_I = 24,
R_RISCV_HI20 = 26,
R_RISCV_LO12_I = 27,
R_RISCV_ADD32 = 35,
R_RISCV_SUB32 = 39,
};
} // namespace RISCV

} // namespace RelocationTypes
} // namespace loader

Expand Down
13 changes: 12 additions & 1 deletion modules/loader/include/loader/relocations.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ struct Relocation {
uint64_t value;
uint64_t target;
};
void reset() { stubs.clear(); }
cargo::small_vector<Entry, 4> stubs;
cargo::optional<uint64_t> getTarget(uint64_t value) const;
};
Expand Down Expand Up @@ -78,7 +79,8 @@ struct Relocation {
/// @note @p map must contain host CPU addresses to writable memory.
///
/// @return Returns whether the relocation succeeded.
bool resolve(ElfFile &file, ElfMap &map, StubMap &stubs);
bool resolve(ElfFile &file, ElfMap &map, StubMap &stubs,
const std::vector<loader::Relocation> &relocations);
};

template <>
Expand All @@ -104,6 +106,15 @@ Relocation Relocation::fromElfEntry<Relocation::EntryType::Elf64RelA>(
/// @return Returns whether all the relocations succeeded.
bool resolveRelocations(ElfFile &file, ElfMap &map);

/// @brief Returns the relocations for the given section.

/// @return The (possibly empty) list of relocations from the section
template <loader::Relocation::EntryType ET32,
loader::Relocation::EntryType ET64>
std::vector<Relocation> collectSectionRelocations(
ElfFile &file, ElfMap &map, const loader::ElfFile::Section &section,
cargo::string_view prefix, ElfFields::SectionType type);

} // namespace loader

#endif
Loading

0 comments on commit f4e845c

Please sign in to comment.