feat(cli): cli flag for amd to intel convertion
This commit is contained in:
parent
c4e4b6112a
commit
8c44cf4a52
|
|
@ -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
|
||||
|
|
@ -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>();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue