feat(cli): cli flag for amd to intel convertion

This commit is contained in:
boykopovar 2026-08-05 13:30:03 +03:00
parent c4e4b6112a
commit 8c44cf4a52
6 changed files with 132 additions and 1 deletions

View File

@ -0,0 +1,25 @@
#ifndef CODEGEN_IAMD64ONLYCONVERTER_HPP
#define CODEGEN_IAMD64ONLYCONVERTER_HPP
#include <domain/Types.hpp>
#include <cstdint>
#include <memory>
#include <vector>
namespace Codegen {
class IAmd64OnlyConverter {
public:
virtual ~IAmd64OnlyConverter() = default;
[[nodiscard]] virtual std::vector<std::uint8_t> Convert(
std::vector<std::uint8_t> fileBytes,
const std::vector<Domain::ProgramHeader>& codeSegments
) const = 0;
};
std::unique_ptr<IAmd64OnlyConverter> MakeAmd64OnlyConverter();
}
#endif

View File

@ -0,0 +1,81 @@
#include <codegen/IAmd64OnlyConverter.hpp>
#include <codegen/IInstructionScanner.hpp>
#include <codegen/x86/X64InstructionRewriter.hpp>
#include <codegen/x86/IAmd64OnlyInstructionMatcher.hpp>
#include <memory>
namespace Codegen {
namespace {
class Amd64OnlyConverter : public IAmd64OnlyConverter {
public:
[[nodiscard]] std::vector<std::uint8_t> Convert(
std::vector<std::uint8_t> fileBytes,
const std::vector<Domain::ProgramHeader>& codeSegments
) const override;
private:
X64InstructionRewriter _rewriter;
std::unique_ptr<IAmd64OnlyInstructionMatcher> _matcher = MakeAmd64OnlyInstructionMatcher();
std::unique_ptr<IInstructionScanner> _scanner = MakeInstructionScanner();
void _convertSegment(
std::vector<std::uint8_t>& fileBytes,
const Domain::ProgramHeader& ph
) const;
};
void Amd64OnlyConverter::_convertSegment(
std::vector<std::uint8_t>& fileBytes,
const Domain::ProgramHeader& ph
) const {
const auto segOffset = static_cast<std::size_t>(ph.Offset);
const auto segSize = static_cast<std::size_t>(ph.FileSize);
std::vector<std::uint8_t> 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<std::int64_t>(match.Offset) + shift;
const auto offset = static_cast<std::size_t>(shiftedOffset);
const auto result = _matcher->Match(seg.data() + offset, match.Length);
if (!result.has_value()) {
continue;
}
const RewriteRequest request{
static_cast<Domain::FileByteOffset>(offset),
result->ReplacementBytes
};
auto rewriteResult = _rewriter.Rewrite(seg, request);
shift += static_cast<std::int64_t>(result->ReplacementBytes.size()) -
static_cast<std::int64_t>(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<std::uint8_t> Amd64OnlyConverter::Convert(
std::vector<std::uint8_t> fileBytes,
const std::vector<Domain::ProgramHeader>& codeSegments
) const {
for (const auto& ph : codeSegments) {
_convertSegment(fileBytes, ph);
}
return fileBytes;
}
}
std::unique_ptr<IAmd64OnlyConverter> MakeAmd64OnlyConverter() {
return std::make_unique<Amd64OnlyConverter>();
}
}

View File

@ -14,6 +14,7 @@
#include <relinker/output/SysVDynamicSectionBuilder.hpp>
#include <relinker/output/CallRegistryWriter.hpp>
#include <relinker/pipeline/RelinkerPipeline.hpp>
#include <codegen/IAmd64OnlyConverter.hpp>
#include <iostream>
#include <memory>
#include <string>
@ -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<std::string> 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] <input.elf> <output.elf> [output_registry.json]\n";
std::cerr << "Usage: relinker [--skip-syscall-check] [--to-intel] <input.elf> <output.elf> [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<Relinker::ElfReader>(sourceBytes);
auto syscallScanner = skipSyscallCheck

View File

@ -18,6 +18,7 @@ public:
[[nodiscard]] virtual FileByteOffset TranslateVirtualAddress(VirtualAddress address) const = 0;
[[nodiscard]] virtual std::vector<std::uint8_t> ReadSection(const SectionHeader& header) const = 0;
[[nodiscard]] virtual std::vector<std::uint8_t> ReadSegment(const ProgramHeader& header) const = 0;
[[nodiscard]] virtual std::vector<ProgramHeader> ReadCodeSegments() const = 0;
[[nodiscard]] virtual std::uint64_t GetFileSize() const = 0;
[[nodiscard]] virtual const std::vector<std::uint8_t>& GetRawBytes() const = 0;
};

View File

@ -17,6 +17,7 @@ public:
FileByteOffset TranslateVirtualAddress(VirtualAddress address) const override;
std::vector<std::uint8_t> ReadSection(const SectionHeader& header) const override;
std::vector<std::uint8_t> ReadSegment(const ProgramHeader& header) const override;
std::vector<ProgramHeader> ReadCodeSegments() const override;
std::uint64_t GetFileSize() const override;
const std::vector<std::uint8_t>& GetRawBytes() const override;

View File

@ -210,6 +210,18 @@ std::vector<std::uint8_t> ElfReader::ReadSegment(const ProgramHeader& header) co
_fileBuffer.begin() + header.Offset + header.FileSize);
}
std::vector<ProgramHeader> ElfReader::ReadCodeSegments() const {
static constexpr std::uint32_t kPtLoad = 1;
static constexpr std::uint32_t kPfX = 0x1;
std::vector<ProgramHeader> 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();
}