#include #include #include #include #if defined(__linux__) || defined(__APPLE__) #include #include #endif #include namespace pslang::jit { namespace { std::size_t native_page_size() { #if defined(__linux__) || defined(__APPLE__) return getpagesize(); #else throw std::runtime_error("Native page size is not supported for this platform"); #endif } } host_executable_program make_host_executable(std::vector const & modules) { #if defined(__linux__) || defined(__APPLE__) auto const page_size = native_page_size(); auto const abi = host_abi(); for (auto const & module : modules) if (module.abi != abi) throw std::runtime_error("Internal error: wrong compiled module ABI for host-executable binary"); auto link_info = prepare_link(modules, {.section_alignment = page_size}); auto storage = (std::uint8_t *)mmap(nullptr, link_info.total_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); if (storage == MAP_FAILED) throw std::system_error(errno, std::generic_category()); host_executable_program result; result.mapping.reset(storage, [total_size = link_info.total_size](void * ptr){ munmap(ptr, total_size); }); link(modules, link_info, storage); for (auto const & relocation : link_info.relocation_offset) *(void **)(storage + relocation.second) = load_foreign(relocation.first); if (mprotect(storage + link_info.code.begin, link_info.code.size, PROT_READ | PROT_EXEC) != 0) throw std::system_error(errno, std::generic_category()); if (mprotect(storage + link_info.relocations.begin, link_info.relocations.size, PROT_READ) != 0) throw std::system_error(errno, std::generic_category()); result.functions = std::move(link_info.functions); result.globals = std::move(link_info.globals); result.entry_points = std::move(link_info.entry_points); return result; #else throw std::runtime_error("Host-executable modules are not supported for this platform"); #endif } }