110 lines
3.2 KiB
C++
110 lines
3.2 KiB
C++
#include <pslang/jit/linker.hpp>
|
|
#include <pslang/jit/resolver.hpp>
|
|
|
|
namespace pslang::jit
|
|
{
|
|
|
|
namespace
|
|
{
|
|
|
|
std::size_t align(std::size_t value, std::size_t alignment)
|
|
{
|
|
return ((value + alignment - 1) / alignment) * alignment;
|
|
}
|
|
|
|
}
|
|
|
|
linked_program_info prepare_link(std::vector<compiled_module> const & modules, link_options const & options)
|
|
{
|
|
linked_program_info result;
|
|
|
|
std::size_t total_code_size = 0;
|
|
std::size_t total_data_size = 0;
|
|
std::size_t total_relo_size = options.reserved_relocations * 8;
|
|
|
|
for (auto const & module : modules)
|
|
{
|
|
for (auto const & function : module.functions)
|
|
result.functions[function.first] = total_code_size + function.second;
|
|
|
|
for (auto const & global : module.globals)
|
|
result.globals[global.first] = total_data_size + global.second;
|
|
|
|
for (auto const & relocation : module.external_function_resolve)
|
|
if (!result.relocation_offset.contains(relocation.name))
|
|
{
|
|
result.relocation_offset[relocation.name] = total_relo_size;
|
|
total_relo_size += 8;
|
|
}
|
|
|
|
if (module.entry_point)
|
|
result.entry_points.push_back(total_code_size + module.functions.at(*module.entry_point));
|
|
else
|
|
result.entry_points.push_back(std::nullopt);
|
|
|
|
total_code_size += module.code.size();
|
|
total_data_size += module.data.size();
|
|
}
|
|
|
|
total_code_size = align(total_code_size, options.section_alignment);
|
|
total_data_size = align(total_data_size, options.section_alignment);
|
|
total_relo_size = align(total_relo_size, options.section_alignment);
|
|
|
|
std::size_t const data_offset = total_code_size;
|
|
std::size_t const relo_offset = total_code_size + total_data_size;
|
|
result.total_size = total_code_size + total_data_size + total_relo_size;
|
|
|
|
for (auto & global : result.globals)
|
|
global.second += data_offset;
|
|
|
|
for (auto & relocation : result.relocation_offset)
|
|
relocation.second += relo_offset;
|
|
|
|
result.code = {0, total_code_size};
|
|
result.data = {total_code_size, total_data_size};
|
|
result.relocations = {total_code_size + total_data_size, total_relo_size};
|
|
|
|
return result;
|
|
}
|
|
|
|
void link(std::vector<compiled_module> const & modules, linked_program_info const & info, std::uint8_t * storage)
|
|
{
|
|
// TODO: resolve internal symbols (across different modules)
|
|
|
|
if (modules.empty())
|
|
return;
|
|
|
|
auto resolver = make_resolver(modules.front().abi.isa);
|
|
|
|
{
|
|
auto dst = storage + info.code.begin;
|
|
|
|
for (auto const & module : modules)
|
|
{
|
|
auto end = std::copy(module.code.data(), module.code.data() + module.code.size(), dst);
|
|
|
|
for (auto const & resolve : module.internal_global_resolve)
|
|
{
|
|
std::int32_t offset = info.globals.at(resolve.global) - (dst - storage + resolve.instruction_offset);
|
|
resolver->resolve(dst + resolve.instruction_offset, offset);
|
|
}
|
|
|
|
for (auto const & resolve : module.external_function_resolve)
|
|
{
|
|
std::int32_t offset = info.relocation_offset.at(resolve.name) - (dst - storage + resolve.instruction_offset);
|
|
resolver->resolve(dst + resolve.instruction_offset, offset);
|
|
}
|
|
|
|
dst = end;
|
|
}
|
|
}
|
|
|
|
{
|
|
auto dst = storage + info.data.begin;
|
|
|
|
for (auto const & module : modules)
|
|
dst = std::copy(module.data.data(), module.data.data() + module.data.size(), dst);
|
|
}
|
|
}
|
|
|
|
}
|