From 8c44cf4a524709ebd41af0e29101d9f557815b6d Mon Sep 17 00:00:00 2001 From: boykopovar Date: Wed, 5 Aug 2026 13:30:03 +0300 Subject: [PATCH] feat(cli): cli flag for amd to intel convertion --- .../include/codegen/IAmd64OnlyConverter.hpp | 25 ++++++ core/codegen/src/Amd64OnlyConverter.cpp | 81 +++++++++++++++++++ core/main.cpp | 13 ++- .../include/relinker/domain/IElfReader.hpp | 1 + .../include/relinker/parsing/ElfReader.hpp | 1 + core/relinker/src/parsing/ElfReader.cpp | 12 +++ 6 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 core/codegen/include/codegen/IAmd64OnlyConverter.hpp create mode 100644 core/codegen/src/Amd64OnlyConverter.cpp diff --git a/core/codegen/include/codegen/IAmd64OnlyConverter.hpp b/core/codegen/include/codegen/IAmd64OnlyConverter.hpp new file mode 100644 index 000000000..c2d28c602 --- /dev/null +++ b/core/codegen/include/codegen/IAmd64OnlyConverter.hpp @@ -0,0 +1,25 @@ +#ifndef CODEGEN_IAMD64ONLYCONVERTER_HPP +#define CODEGEN_IAMD64ONLYCONVERTER_HPP + +#include +#include +#include +#include + +namespace Codegen { + +class IAmd64OnlyConverter { +public: + virtual ~IAmd64OnlyConverter() = default; + + [[nodiscard]] virtual std::vector Convert( + std::vector fileBytes, + const std::vector& codeSegments + ) const = 0; +}; + +std::unique_ptr MakeAmd64OnlyConverter(); + +} + +#endif diff --git a/core/codegen/src/Amd64OnlyConverter.cpp b/core/codegen/src/Amd64OnlyConverter.cpp new file mode 100644 index 000000000..c29401550 --- /dev/null +++ b/core/codegen/src/Amd64OnlyConverter.cpp @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include + +namespace Codegen { + +namespace { + +class Amd64OnlyConverter : public IAmd64OnlyConverter { +public: + [[nodiscard]] std::vector Convert( + std::vector fileBytes, + const std::vector& codeSegments + ) const override; + +private: + X64InstructionRewriter _rewriter; + std::unique_ptr _matcher = MakeAmd64OnlyInstructionMatcher(); + std::unique_ptr _scanner = MakeInstructionScanner(); + + void _convertSegment( + std::vector& fileBytes, + const Domain::ProgramHeader& ph + ) const; +}; + +void Amd64OnlyConverter::_convertSegment( + std::vector& fileBytes, + const Domain::ProgramHeader& ph +) const { + const auto segOffset = static_cast(ph.Offset); + const auto segSize = static_cast(ph.FileSize); + + std::vector seg( + fileBytes.begin() + segOffset, + fileBytes.begin() + segOffset + segSize + ); + + const auto matches = _scanner->ScanCodeSection(seg, 0, seg.size()); + std::int64_t shift = 0; + + for (const auto& match : matches) { + const auto shiftedOffset = static_cast(match.Offset) + shift; + const auto offset = static_cast(shiftedOffset); + const auto result = _matcher->Match(seg.data() + offset, match.Length); + if (!result.has_value()) { + continue; + } + const RewriteRequest request{ + static_cast(offset), + result->ReplacementBytes + }; + auto rewriteResult = _rewriter.Rewrite(seg, request); + shift += static_cast(result->ReplacementBytes.size()) - + static_cast(match.Length); + seg = std::move(rewriteResult.Bytes); + } + + const auto copySize = std::min(seg.size(), segSize); + std::copy(seg.begin(), seg.begin() + copySize, fileBytes.begin() + segOffset); +} + +std::vector Amd64OnlyConverter::Convert( + std::vector fileBytes, + const std::vector& codeSegments +) const { + for (const auto& ph : codeSegments) { + _convertSegment(fileBytes, ph); + } + return fileBytes; +} + +} + +std::unique_ptr MakeAmd64OnlyConverter() { + return std::make_unique(); +} + +} diff --git a/core/main.cpp b/core/main.cpp index 356b62b0c..b93fa75f5 100644 --- a/core/main.cpp +++ b/core/main.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ int main(const int argc, char* argv[]) { bool skipSyscallCheck = false; + bool toIntel = false; std::string inputPath; std::string outputElfPath; std::optional registryPath; @@ -29,6 +31,8 @@ int main(const int argc, char* argv[]) { const std::string arg = argv[i]; if (arg == "--skip-syscall-check") { skipSyscallCheck = true; + } else if (arg == "--to-intel") { + toIntel = true; } else if (inputPath.empty()) { inputPath = arg; } else if (outputElfPath.empty()) { @@ -39,7 +43,7 @@ int main(const int argc, char* argv[]) { } if (inputPath.empty() || outputElfPath.empty()) { - std::cerr << "Usage: relinker [--skip-syscall-check] [output_registry.json]\n"; + std::cerr << "Usage: relinker [--skip-syscall-check] [--to-intel] [output_registry.json]\n"; return 1; } @@ -49,6 +53,13 @@ int main(const int argc, char* argv[]) { auto sourceBytes = fileReader.Read(inputPath); + if (toIntel) { + const Relinker::ElfReader elfReader(sourceBytes); + const auto converter = Codegen::MakeAmd64OnlyConverter(); + fileWriter.Write(outputElfPath, converter->Convert(std::move(sourceBytes), elfReader.ReadCodeSegments())); + return 0; + } + auto elfReader = std::make_shared(sourceBytes); auto syscallScanner = skipSyscallCheck diff --git a/core/relinker/include/relinker/domain/IElfReader.hpp b/core/relinker/include/relinker/domain/IElfReader.hpp index f528b3945..90ce34de3 100644 --- a/core/relinker/include/relinker/domain/IElfReader.hpp +++ b/core/relinker/include/relinker/domain/IElfReader.hpp @@ -18,6 +18,7 @@ public: [[nodiscard]] virtual FileByteOffset TranslateVirtualAddress(VirtualAddress address) const = 0; [[nodiscard]] virtual std::vector ReadSection(const SectionHeader& header) const = 0; [[nodiscard]] virtual std::vector ReadSegment(const ProgramHeader& header) const = 0; + [[nodiscard]] virtual std::vector ReadCodeSegments() const = 0; [[nodiscard]] virtual std::uint64_t GetFileSize() const = 0; [[nodiscard]] virtual const std::vector& GetRawBytes() const = 0; }; diff --git a/core/relinker/include/relinker/parsing/ElfReader.hpp b/core/relinker/include/relinker/parsing/ElfReader.hpp index e3c82900a..85540b25d 100644 --- a/core/relinker/include/relinker/parsing/ElfReader.hpp +++ b/core/relinker/include/relinker/parsing/ElfReader.hpp @@ -17,6 +17,7 @@ public: FileByteOffset TranslateVirtualAddress(VirtualAddress address) const override; std::vector ReadSection(const SectionHeader& header) const override; std::vector ReadSegment(const ProgramHeader& header) const override; + std::vector ReadCodeSegments() const override; std::uint64_t GetFileSize() const override; const std::vector& GetRawBytes() const override; diff --git a/core/relinker/src/parsing/ElfReader.cpp b/core/relinker/src/parsing/ElfReader.cpp index e45405402..efdc082f4 100644 --- a/core/relinker/src/parsing/ElfReader.cpp +++ b/core/relinker/src/parsing/ElfReader.cpp @@ -210,6 +210,18 @@ std::vector ElfReader::ReadSegment(const ProgramHeader& header) co _fileBuffer.begin() + header.Offset + header.FileSize); } +std::vector ElfReader::ReadCodeSegments() const { + static constexpr std::uint32_t kPtLoad = 1; + static constexpr std::uint32_t kPfX = 0x1; + std::vector result; + for (const auto& ph : ReadProgramHeaders()) { + if (ph.Type == kPtLoad && (ph.Flags & kPfX)) { + result.push_back(ph); + } + } + return result; +} + std::uint64_t ElfReader::GetFileSize() const { return _fileBuffer.size(); }