From 5e49fbae54bd7dcbf2e893acaef699ce9f2587f3 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Tue, 21 May 2024 09:12:06 +0200 Subject: MHR-21: Refactor, WiP symbol support in mov. Signed-off-by: Amlal El Mahrouss --- Examples/ExampleAMD64.asm | 2 +- Examples/ExampleCPlusPlus.cxx | 2 +- Headers/AsmKit/AsmKit.hpp | 2 +- Headers/AsmKit/CPU/32x0.hpp | 2 +- Headers/AsmKit/CPU/64x0.hpp | 2 +- Headers/AsmKit/CPU/amd64.hpp | 2 +- Headers/AsmKit/CPU/ppc.hpp | 10 +- Headers/CompilerKit.hpp | 2 +- Headers/Defines.hpp | 2 +- Headers/ParserKit.hpp | 2 +- Headers/StdKit/AE.hpp | 32 +- Headers/StdKit/PEF.hpp | 2 +- Headers/StdKit/String.hpp | 12 +- Headers/StdKit/XCOFF.hxx | 10 +- SDK/__mpcc_alloca.hxx | 2 +- SDK/__mpcc_defines.hxx | 2 +- SDK/__mpcc_exception.hxx | 2 +- SDK/__mpcc_hint.hxx | 2 +- SDK/__mpcc_malloc.hxx | 2 +- Sources/AssemblyFactory.cc | 58 + Sources/AssemblyFactory.cxx | 58 - Sources/Detail/asmutils.h | 111 -- Sources/Detail/asmutils.hxx | 111 ++ Sources/Detail/compilerutils.h | 14 - Sources/Detail/compilerutils.hxx | 14 + Sources/i64asm.cc | 2381 +++++++++++++++++++++----------------- Sources/link.cc | 26 +- Sources/ppcasm.cc | 33 +- posix.make | 2 +- win64.make | 2 +- 30 files changed, 1571 insertions(+), 1333 deletions(-) create mode 100644 Sources/AssemblyFactory.cc delete mode 100644 Sources/AssemblyFactory.cxx delete mode 100644 Sources/Detail/asmutils.h create mode 100644 Sources/Detail/asmutils.hxx delete mode 100644 Sources/Detail/compilerutils.h create mode 100644 Sources/Detail/compilerutils.hxx diff --git a/Examples/ExampleAMD64.asm b/Examples/ExampleAMD64.asm index cc649be..781934c 100644 --- a/Examples/ExampleAMD64.asm +++ b/Examples/ExampleAMD64.asm @@ -2,5 +2,5 @@ export .code64 __ImageStart -mov rax, rdx +mov rax, 17 ret diff --git a/Examples/ExampleCPlusPlus.cxx b/Examples/ExampleCPlusPlus.cxx index 6012b52..3335e1e 100644 --- a/Examples/ExampleCPlusPlus.cxx +++ b/Examples/ExampleCPlusPlus.cxx @@ -5,7 +5,7 @@ int main(int argc, char const* argv[]) bar = 1; bool bar2 = bar; - bar2 = false; + bar2 = false; } return 0; diff --git a/Headers/AsmKit/AsmKit.hpp b/Headers/AsmKit/AsmKit.hpp index 23db830..d22ec21 100644 --- a/Headers/AsmKit/AsmKit.hpp +++ b/Headers/AsmKit/AsmKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/AsmKit/CPU/32x0.hpp b/Headers/AsmKit/CPU/32x0.hpp index 44ddaed..4d66da5 100644 --- a/Headers/AsmKit/CPU/32x0.hpp +++ b/Headers/AsmKit/CPU/32x0.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/AsmKit/CPU/64x0.hpp b/Headers/AsmKit/CPU/64x0.hpp index 58ab76d..974f346 100644 --- a/Headers/AsmKit/CPU/64x0.hpp +++ b/Headers/AsmKit/CPU/64x0.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/AsmKit/CPU/amd64.hpp b/Headers/AsmKit/CPU/amd64.hpp index be5a657..8f7e05c 100644 --- a/Headers/AsmKit/CPU/amd64.hpp +++ b/Headers/AsmKit/CPU/amd64.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/AsmKit/CPU/ppc.hpp b/Headers/AsmKit/CPU/ppc.hpp index c29286d..c4265da 100644 --- a/Headers/AsmKit/CPU/ppc.hpp +++ b/Headers/AsmKit/CPU/ppc.hpp @@ -242,7 +242,7 @@ inline CpuOpcodePPC kOpcodesPowerPC[] = { {0x4c800421, "bfctrl", {{16, 5, BCND}, {11, 2, NUM}}}, /* branch mnemonics incorporating conditions (assember extended mnemonics) - */ + */ {0x41800000, "blt", {{16, 5, CRF}, {2, 14, PCREL}}}, {0x41800000, "blt", {{2, 14, PCREL}}}, {0x41800001, "bltl", {{16, 5, CRF}, {2, 14, PCREL}}}, @@ -1548,10 +1548,10 @@ inline CpuOpcodePPC kOpcodesPowerPC[] = { {0x7c000426, "clcs", {{21, 5, GREG}, {16, 5, GREG}}, CPU601}, /* Added from the POWER 603 book. - * These are really 603 specific instructions but we mark them as OPTIONAL - * so that the -force_cpusubtype_ALL flag as to be used. This makes it so - * only 601 instructions will cause the cputype to be set to other an ALL. - */ + * These are really 603 specific instructions but we mark them as OPTIONAL + * so that the -force_cpusubtype_ALL flag as to be used. This makes it so + * only 601 instructions will cause the cputype to be set to other an ALL. + */ {0x7c0007a4, "tlbld", {{11, 5, GREG}}, OPTIONAL}, {0x7c0007e4, "tlbli", {{11, 5, GREG}}, OPTIONAL}, diff --git a/Headers/CompilerKit.hpp b/Headers/CompilerKit.hpp index 3d5cfc2..b9de089 100644 --- a/Headers/CompilerKit.hpp +++ b/Headers/CompilerKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/Defines.hpp b/Headers/Defines.hpp index ac8692b..d76620c 100644 --- a/Headers/Defines.hpp +++ b/Headers/Defines.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/ParserKit.hpp b/Headers/ParserKit.hpp index 6a53edc..f77dba9 100644 --- a/Headers/ParserKit.hpp +++ b/Headers/ParserKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/StdKit/AE.hpp b/Headers/StdKit/AE.hpp index 3075017..ebae770 100644 --- a/Headers/StdKit/AE.hpp +++ b/Headers/StdKit/AE.hpp @@ -95,9 +95,9 @@ std::ifstream& operator>>(std::ifstream& fp, namespace CompilerKit::Utils { /** - * @brief AE Reader protocol - * - */ + * @brief AE Reader protocol + * + */ class AEReadableProtocol final { public: @@ -110,12 +110,12 @@ namespace CompilerKit::Utils MPCC_COPY_DELETE(AEReadableProtocol); /** - * @brief Read AE record - * - * @param raw the containing buffer - * @param sz it's size (without sizeof(AERecordHeader) added to it.) - * @return AERecordHeaderPtr - */ + * @brief Read AE record + * + * @param raw the containing buffer + * @param sz it's size (without sizeof(AERecordHeader) added to it.) + * @return AERecordHeaderPtr + */ AERecordHeaderPtr Read(char* raw, std::size_t sz) { if (!raw) @@ -126,13 +126,13 @@ namespace CompilerKit::Utils private: /** - * @brief Implementation of Read for raw classes. - * - * @tparam TypeClass The class to read. - * @param raw the buffer - * @param sz the size - * @return TypeClass* the returning class. - */ + * @brief Implementation of Read for raw classes. + * + * @tparam TypeClass The class to read. + * @param raw the buffer + * @param sz the size + * @return TypeClass* the returning class. + */ template TypeClass* _Read(char* raw, std::size_t sz) { diff --git a/Headers/StdKit/PEF.hpp b/Headers/StdKit/PEF.hpp index ee01852..88c20ea 100644 --- a/Headers/StdKit/PEF.hpp +++ b/Headers/StdKit/PEF.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/StdKit/String.hpp b/Headers/StdKit/String.hpp index 20fd16f..d4048ee 100644 --- a/Headers/StdKit/String.hpp +++ b/Headers/StdKit/String.hpp @@ -15,9 +15,9 @@ namespace CompilerKit { /** - * @brief StringView class, contains a C string and manages it. - * @note No need to manage it it's getting deleted by default. - */ + * @brief StringView class, contains a C string and manages it. + * @note No need to manage it it's getting deleted by default. + */ class StringView final { @@ -76,9 +76,9 @@ namespace CompilerKit }; /** - * @brief StringBuilder class - * @note These results shall call delete[] after they're used. - */ + * @brief StringBuilder class + * @note These results shall call delete[] after they're used. + */ struct StringBuilder final { static StringView Construct(const CharType* data); diff --git a/Headers/StdKit/XCOFF.hxx b/Headers/StdKit/XCOFF.hxx index b9cc825..d339daa 100644 --- a/Headers/StdKit/XCOFF.hxx +++ b/Headers/StdKit/XCOFF.hxx @@ -1,13 +1,13 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs - File: XCOFF.hpp - Purpose: XCOFF for NewOS. + File: XCOFF.hpp + Purpose: XCOFF for NewOS. - Revision History: + Revision History: - 04/07/24: Added file (amlel) + 04/07/24: Added file (amlel) ------------------------------------------- */ diff --git a/SDK/__mpcc_alloca.hxx b/SDK/__mpcc_alloca.hxx index f15e059..a1c638e 100644 --- a/SDK/__mpcc_alloca.hxx +++ b/SDK/__mpcc_alloca.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/SDK/__mpcc_defines.hxx b/SDK/__mpcc_defines.hxx index ff91db1..5560410 100644 --- a/SDK/__mpcc_defines.hxx +++ b/SDK/__mpcc_defines.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/SDK/__mpcc_exception.hxx b/SDK/__mpcc_exception.hxx index d36aba6..9366102 100644 --- a/SDK/__mpcc_exception.hxx +++ b/SDK/__mpcc_exception.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/SDK/__mpcc_hint.hxx b/SDK/__mpcc_hint.hxx index d775f52..ee14711 100644 --- a/SDK/__mpcc_hint.hxx +++ b/SDK/__mpcc_hint.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/SDK/__mpcc_malloc.hxx b/SDK/__mpcc_malloc.hxx index 56989f8..2731868 100644 --- a/SDK/__mpcc_malloc.hxx +++ b/SDK/__mpcc_malloc.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Sources/AssemblyFactory.cc b/Sources/AssemblyFactory.cc new file mode 100644 index 0000000..d5c0da7 --- /dev/null +++ b/Sources/AssemblyFactory.cc @@ -0,0 +1,58 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include +#include + +/** + * @file AssemblyFactory.cxx + * @author Amlal El Mahrouss (amlal@mahrouss.com) + * @brief Assembler Kit + * @version 0.1 + * @date 2024-01-27 + * + * @copyright Copyright (c) 2024, SoftwareLabs + * + */ + +#include + +//! @file AsmKit.cpp +//! @brief AssemblyKit source implementation. + +namespace CompilerKit +{ + //! @brief Compile for specific format (ELF, PEF, ZBIN) + Int32 AssemblyFactory::Compile(std::string& sourceFile, + const Int32& arch) noexcept + { + if (sourceFile.length() < 1 || !fMounted) + return MPCC_UNIMPLEMENTED; + + return fMounted->CompileToFormat(sourceFile, arch); + } + + //! @brief mount assembly backend. + void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept + { + if (mountPtr) + { + fMounted = mountPtr; + } + } + + AssemblyInterface* AssemblyFactory::Unmount() noexcept + { + auto mount_prev = fMounted; + + if (mount_prev) + { + fMounted = nullptr; + } + + return mount_prev; + } +} // namespace CompilerKit diff --git a/Sources/AssemblyFactory.cxx b/Sources/AssemblyFactory.cxx deleted file mode 100644 index d5c0da7..0000000 --- a/Sources/AssemblyFactory.cxx +++ /dev/null @@ -1,58 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#include -#include - -/** - * @file AssemblyFactory.cxx - * @author Amlal El Mahrouss (amlal@mahrouss.com) - * @brief Assembler Kit - * @version 0.1 - * @date 2024-01-27 - * - * @copyright Copyright (c) 2024, SoftwareLabs - * - */ - -#include - -//! @file AsmKit.cpp -//! @brief AssemblyKit source implementation. - -namespace CompilerKit -{ - //! @brief Compile for specific format (ELF, PEF, ZBIN) - Int32 AssemblyFactory::Compile(std::string& sourceFile, - const Int32& arch) noexcept - { - if (sourceFile.length() < 1 || !fMounted) - return MPCC_UNIMPLEMENTED; - - return fMounted->CompileToFormat(sourceFile, arch); - } - - //! @brief mount assembly backend. - void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept - { - if (mountPtr) - { - fMounted = mountPtr; - } - } - - AssemblyInterface* AssemblyFactory::Unmount() noexcept - { - auto mount_prev = fMounted; - - if (mount_prev) - { - fMounted = nullptr; - } - - return mount_prev; - } -} // namespace CompilerKit diff --git a/Sources/Detail/asmutils.h b/Sources/Detail/asmutils.h deleted file mode 100644 index c0537ad..0000000 --- a/Sources/Detail/asmutils.h +++ /dev/null @@ -1,111 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include -#include - -using namespace CompilerKit; - -/// @brief Get Number from lineBuffer. -/// @param lineBuffer the lineBuffer to fetch from. -/// @param numberKey where to seek that number. -/// @return -static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) -{ - auto pos = lineBuffer.find(numberKey) + numberKey.size(); - - if (lineBuffer.find(",") != std::string::npos) - lineBuffer.erase(lineBuffer.find(","), 1); - - while (lineBuffer[pos] == ' ') - ++pos; - - switch (lineBuffer[pos + 1]) - { - case 'x': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 16); !res) - { - if (errno != 0) - { - detail::print_error("invalid hex number: " + lineBuffer, "ppcasm"); - throw std::runtime_error("invalid_hex"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 16)); - - if (kVerbose) - { - kStdOut << "ppcasm: found a base 16 number here: " << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - case 'b': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 2); !res) - { - if (errno != 0) - { - detail::print_error("invalid binary number:" + lineBuffer, "ppcasm"); - throw std::runtime_error("invalid_bin"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "ppcasm: found a base 2 number here:" << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - case 'o': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 7); !res) - { - if (errno != 0) - { - detail::print_error("invalid octal number: " + lineBuffer, "ppcasm"); - throw std::runtime_error("invalid_octal"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "ppcasm: found a base 8 number here:" << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - default: { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - detail::print_error("invalid hex number: " + lineBuffer, "ppcasm"); - throw std::runtime_error("invalid_hex"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 10)); - - if (kVerbose) - { - kStdOut << "ppcasm: found a base 10 number here:" << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - } -} diff --git a/Sources/Detail/asmutils.hxx b/Sources/Detail/asmutils.hxx new file mode 100644 index 0000000..36c5901 --- /dev/null +++ b/Sources/Detail/asmutils.hxx @@ -0,0 +1,111 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include +#include + +using namespace CompilerKit; + +/// @brief Get Number from lineBuffer. +/// @param lineBuffer the lineBuffer to fetch from. +/// @param numberKey where to seek that number. +/// @return +static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) +{ + auto pos = lineBuffer.find(numberKey) + numberKey.size(); + + if (lineBuffer.find(",") != std::string::npos) + lineBuffer.erase(lineBuffer.find(","), 1); + + while (lineBuffer[pos] == ' ') + ++pos; + + switch (lineBuffer[pos + 1]) + { + case 'x': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 16); !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + lineBuffer, "asm"); + throw std::runtime_error("invalid_hex"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 16)); + + if (kVerbose) + { + kStdOut << "asm: found a base 16 number here: " << lineBuffer.substr(pos) + << "\n"; + } + + return numOffset; + } + case 'b': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 2); !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number:" + lineBuffer, "asm"); + throw std::runtime_error("invalid_bin"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "asm: found a base 2 number here:" << lineBuffer.substr(pos) + << "\n"; + } + + return numOffset; + } + case 'o': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 7); !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + lineBuffer, "asm"); + throw std::runtime_error("invalid_octal"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "asm: found a base 8 number here:" << lineBuffer.substr(pos) + << "\n"; + } + + return numOffset; + } + default: { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + lineBuffer, "asm"); + throw std::runtime_error("invalid_hex"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 10)); + + if (kVerbose) + { + kStdOut << "asm: found a base 10 number here:" << lineBuffer.substr(pos) + << "\n"; + } + + return numOffset; + } + } +} diff --git a/Sources/Detail/compilerutils.h b/Sources/Detail/compilerutils.h deleted file mode 100644 index cde8d34..0000000 --- a/Sources/Detail/compilerutils.h +++ /dev/null @@ -1,14 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include -#include - -#define kZero64Section ".zero64" -#define kCode64Section ".code64" -#define kData64Section ".data64" diff --git a/Sources/Detail/compilerutils.hxx b/Sources/Detail/compilerutils.hxx new file mode 100644 index 0000000..bebdd7f --- /dev/null +++ b/Sources/Detail/compilerutils.hxx @@ -0,0 +1,14 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include +#include + +#define kZero64Section ".zero64" +#define kCode64Section ".code64" +#define kData64Section ".data64" diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc index 53ca13e..5f0812c 100644 --- a/Sources/i64asm.cc +++ b/Sources/i64asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ @@ -25,7 +25,7 @@ #define __ASM_NEED_AMD64__ 1 #define kAssemblerPragmaSymStr "#" -#define kAssemblerPragmaSym '#' +#define kAssemblerPragmaSym '#' #include #include @@ -45,25 +45,25 @@ ///////////////////// -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" #define kYellow "\e[0;33m" #define kStdOut (std::cout << kWhite) #define kStdErr (std::cout << kRed) -static char kOutputArch = CompilerKit::kPefArchAMD64; +static char kOutputArch = CompilerKit::kPefArchAMD64; static Boolean kOutputAsBinary = false; -static UInt32 kErrorLimit = 10; +static UInt32 kErrorLimit = 10; static UInt32 kAcceptableErrors = 0; constexpr auto cAMD64IPAlignment = 0x4U; static std::size_t kCounter = 1UL; -static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::uintptr_t kOrigin = kPefBaseOrigin; static std::vector> kOriginLabel; /// @brief keep it simple by default. @@ -74,44 +74,53 @@ static bool kVerbose = false; static std::vector kAppBytes; static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; + .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; static std::vector kRecords; -static std::vector kDefinedSymbols; -static std::vector kUndefinedSymbols; +static std::vector kDefinedSymbols; +static std::vector kUndefinedSymbols; static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; +static const std::string kRelocSymbol = ":RuntimeSymbol:"; // \brief forward decl. -static bool asm_read_attributes(std::string &line); +static bool asm_read_attributes(std::string& line); -namespace detail { -void print_error(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); +namespace detail +{ + void print_error(std::string reason, const std::string& file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); - kStdErr << kRed << "[ i64asm ] " << kWhite - << ((file == "i64asm") ? "internal assembler error " - : ("in file, " + file)) - << kBlank << std::endl; - kStdErr << kRed << "[ i64asm ] " << kWhite << reason << kBlank << std::endl; + kStdErr << kRed << "[ i64asm ] " << kWhite + << ((file == "i64asm") ? "internal assembler error " + : ("in file, " + file)) + << kBlank << std::endl; + kStdErr << kRed << "[ i64asm ] " << kWhite << reason << kBlank << std::endl; - if (kAcceptableErrors > kErrorLimit) std::exit(3); + if (kAcceptableErrors > kErrorLimit) + std::exit(3); - ++kAcceptableErrors; -} + ++kAcceptableErrors; + } -void print_warning(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); + void print_warning(std::string reason, const std::string& file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); - if (!file.empty()) { - kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; - } + if (!file.empty()) + { + kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; + } - kStdOut << kYellow << "[ i64asm ] " << kWhite << reason << kBlank - << std::endl; -} -} // namespace detail + kStdOut << kYellow << "[ i64asm ] " << kWhite << reason << kBlank + << std::endl; + } +} // namespace detail + +#include ///////////////////////////////////////////////////////////////////////////////////////// @@ -119,237 +128,277 @@ void print_warning(std::string reason, const std::string &file) noexcept { ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSAssemblerAMD64) { - //////////////// CPU OPCODES BEGIN //////////////// - - std::string opcodes_jump[kJumpLimit] = { - "ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge", "jl", "jle", - "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge", "jnl", "jnle", - "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz"}; - - for (i64_hword_t i = 0; i < kJumpLimit; i++) { - CpuOpcodeAMD64 code{ - .fName = opcodes_jump[i], - .fOpcode = static_cast(kAsmJumpOpcode + i)}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; - kOpcodesAMD64.push_back(code); - - for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) { - CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; - kOpcodesAMD64.push_back(lahf); - - CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; - kOpcodesAMD64.push_back(lds); - - CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; - kOpcodesAMD64.push_back(lea); - - CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; - kOpcodesAMD64.push_back(nop); - - //////////////// CPU OPCODES END //////////////// - - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { - kStdOut << "i64asm: AMD64 Assembler.\ni64asm: v1.10\ni64asm: Copyright " - "(c) 2024 SoftwareLabs.\n"; - return 0; - } else if (strcmp(argv[i], "-h") == 0) { - kStdOut << "i64asm: AMD64 Assembler.\ni64asm: Copyright (c) 2024 " - "SoftwareLabs.\n"; - kStdOut << "-version: Print program version.\n"; - kStdOut << "-verbose: Print verbose output.\n"; - kStdOut << "-binary: Output as flat binary.\n"; - - return 0; - } else if (strcmp(argv[i], "-binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "-verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "i64asm: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "i64asm: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto &ext : kAsmFileExts) { - if (object_output.find(ext) != std::string::npos) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "i64asm: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAEInvalidOpcode, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; +MPCC_MODULE(NewOSAssemblerAMD64) +{ + //////////////// CPU OPCODES BEGIN //////////////// + + std::string opcodes_jump[kJumpLimit] = { + "ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge", "jl", "jle", + "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge", "jnl", "jnle", + "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz"}; + + for (i64_hword_t i = 0; i < kJumpLimit; i++) + { + CpuOpcodeAMD64 code{ + .fName = opcodes_jump[i], + .fOpcode = static_cast(kAsmJumpOpcode + i)}; + kOpcodesAMD64.push_back(code); + } + + CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; + kOpcodesAMD64.push_back(code); + + for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) + { + CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; + kOpcodesAMD64.push_back(code); + } + + CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; + kOpcodesAMD64.push_back(lahf); + + CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; + kOpcodesAMD64.push_back(lds); + + CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; + kOpcodesAMD64.push_back(lea); + + CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; + kOpcodesAMD64.push_back(nop); + + //////////////// CPU OPCODES END //////////////// + + for (size_t i = 1; i < argc; ++i) + { + if (argv[i][0] == '-') + { + if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) + { + kStdOut << "i64asm: AMD64 Assembler.\ni64asm: v1.10\ni64asm: Copyright " + "(c) 2024 SoftwareLabs.\n"; + return 0; + } + else if (strcmp(argv[i], "-h") == 0) + { + kStdOut << "i64asm: AMD64 Assembler.\ni64asm: Copyright (c) 2024 " + "SoftwareLabs.\n"; + kStdOut << "-version: Print program version.\n"; + kStdOut << "-verbose: Print verbose output.\n"; + kStdOut << "-binary: Output as flat binary.\n"; + + return 0; + } + else if (strcmp(argv[i], "-binary") == 0) + { + kOutputAsBinary = true; + continue; + } + else if (strcmp(argv[i], "-verbose") == 0) + { + kVerbose = true; + continue; + } + + kStdOut << "i64asm: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) + { + kStdOut << "i64asm: can't open: " << argv[i] << std::endl; + goto asm_fail_exit; + } + + std::string object_output(argv[i]); + + for (auto& ext : kAsmFileExts) + { + if (object_output.find(ext) != std::string::npos) + { + object_output.erase(object_output.find(ext), std::strlen(ext)); + } + } + + object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; + + std::ifstream file_ptr(argv[i]); + std::ofstream file_ptr_out(object_output, std::ofstream::binary); + + if (file_ptr_out.bad()) + { + if (kVerbose) + { + kStdOut << "i64asm: error: " << strerror(errno) << "\n"; + } + } + + std::string line; + + CompilerKit::AEHeader hdr{0}; + + memset(hdr.fPad, kAEInvalidOpcode, kAEPad); + + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(CompilerKit::AEHeader); + hdr.fArch = kOutputArch; + + ///////////////////////////////////////////////////////////////////////////////////////// + + // COMPILATION LOOP + + ///////////////////////////////////////////////////////////////////////////////////////// + + CompilerKit::EncoderAMD64 asm64; + + while (std::getline(file_ptr, line)) + { + if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) + { + detail::print_error(ln, argv[i]); + continue; + } + + try + { + asm_read_attributes(line); + asm64.WriteLine(line, argv[i]); + } + catch (const std::exception& e) + { + if (kVerbose) + { + std::string what = e.what(); + detail::print_warning("exit because of: " + what, "i64asm"); + } + + try + { + std::filesystem::remove(object_output); + } + catch (...) + { + } + + goto asm_fail_exit; + } + } - ///////////////////////////////////////////////////////////////////////////////////////// + if (!kOutputAsBinary) + { + if (kVerbose) + { + kStdOut << "i64asm: Writing object file...\n"; + } - // COMPILATION LOOP + // this is the final step, write everything to the file. - ///////////////////////////////////////////////////////////////////////////////////////// + auto pos = file_ptr_out.tellp(); - CompilerKit::EncoderAMD64 asm64; + hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - detail::print_error(ln, argv[i]); - continue; - } + file_ptr_out << hdr; - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception &e) { - if (kVerbose) { - std::string what = e.what(); - detail::print_warning("exit because of: " + what, "i64asm"); - } + if (kRecords.empty()) + { + kStdErr << "i64asm: At least one record is needed to write an object " + "file.\ni64asm: Make one using `export .code64 foo_bar`.\n"; - try { - std::filesystem::remove(object_output); - } catch (...) { - } + std::filesystem::remove(object_output); + return -1; + } - goto asm_fail_exit; - } - } + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "i64asm: Writing object file...\n"; - } + std::size_t record_count = 0UL; - // this is the final step, write everything to the file. + for (auto& rec : kRecords) + { + if (kVerbose) + kStdOut << "i64asm: Wrote record " << rec.fName << " to file...\n"; - auto pos = file_ptr_out.tellp(); + rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; + rec.fOffset = record_count; + ++record_count; - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); + file_ptr_out << rec; + } - file_ptr_out << hdr; + // increment once again, so that we won't lie about the kUndefinedSymbols. + ++record_count; - if (kRecords.empty()) { - kStdErr << "i64asm: At least one record is needed to write an object " - "file.\ni64asm: Make one using `export .code64 foo_bar`.\n"; + for (auto& sym : kUndefinedSymbols) + { + CompilerKit::AERecordHeader _record_hdr{0}; - std::filesystem::remove(object_output); - return -1; - } + if (kVerbose) + kStdOut << "i64asm: Wrote symbol " << sym << " to file...\n"; - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + _record_hdr.fKind = kAEInvalidOpcode; + _record_hdr.fSize = sym.size(); + _record_hdr.fOffset = record_count; - std::size_t record_count = 0UL; + ++record_count; - for (auto &rec : kRecords) { - if (kVerbose) - kStdOut << "i64asm: Wrote record " << rec.fName << " to file...\n"; + memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); + memcpy(_record_hdr.fName, sym.c_str(), sym.size()); - rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; - rec.fOffset = record_count; - ++record_count; + file_ptr_out << _record_hdr; - file_ptr_out << rec; - } + ++kCounter; + } - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; + auto pos_end = file_ptr_out.tellp(); - for (auto &sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader _record_hdr{0}; + file_ptr_out.seekp(pos); - if (kVerbose) - kStdOut << "i64asm: Wrote symbol " << sym << " to file...\n"; + hdr.fStartCode = pos_end; + hdr.fCodeSize = kAppBytes.size(); - _record_hdr.fKind = kAEInvalidOpcode; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; + file_ptr_out << hdr; - ++record_count; + file_ptr_out.seekp(pos_end); + } + else + { + if (kVerbose) + { + kStdOut << "i64asm: Write raw binary...\n"; + } + } - memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); + // byte from byte, we write this. + for (auto& byte : kAppBytes) + { + if (byte == 0) + continue; - file_ptr_out << _record_hdr; + if (byte == 0xFF) + { + byte = 0; + } - ++kCounter; - } + file_ptr_out << reinterpret_cast(&byte)[0]; + } - auto pos_end = file_ptr_out.tellp(); + if (kVerbose) + kStdOut << "i64asm: Wrote file with program in it.\n"; - file_ptr_out.seekp(pos); + file_ptr_out.flush(); + file_ptr_out.close(); - hdr.fStartCode = pos_end; - hdr.fCodeSize = kAppBytes.size(); + if (kVerbose) + kStdOut << "i64asm: Exit succeeded.\n"; - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "i64asm: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto &byte : kAppBytes) { - if (byte == 0) continue; - - if (byte == 0xFF) { - byte = 0; - } - - file_ptr_out << reinterpret_cast(&byte)[0]; - } - - if (kVerbose) kStdOut << "i64asm: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "i64asm: Exit succeeded.\n"; - - return 0; - } + return 0; + } asm_fail_exit: - if (kVerbose) kStdOut << "i64asm: Exit failed.\n"; + if (kVerbose) + kStdOut << "i64asm: Exit failed.\n"; - return -1; + return -1; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -359,156 +408,182 @@ asm_fail_exit: ///////////////////////////////////////////////////////////////////////////////////////// -static bool asm_read_attributes(std::string &line) { - // import is the opposite of export, it signals to the ld - // that we need this symbol. - if (ParserKit::find_word(line, "import")) { - if (kOutputAsBinary) { - detail::print_error("Invalid directive in flat binary mode.", "i64asm"); - throw std::runtime_error("invalid_import_bin"); - } - - auto name = line.substr(line.find("import") + strlen("import") + 1); - - if (name.size() == 0) { - detail::print_error("Invalid import", "ppcasm"); - throw std::runtime_error("invalid_import"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char &j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; +static bool asm_read_attributes(std::string& line) +{ + // import is the opposite of export, it signals to the ld + // that we need this symbol. + if (ParserKit::find_word(line, "import")) + { + if (kOutputAsBinary) + { + detail::print_error("Invalid directive in flat binary mode.", "i64asm"); + throw std::runtime_error("invalid_import_bin"); + } + + auto name = line.substr(line.find("import") + strlen("import") + 1); + + if (name.size() == 0) + { + detail::print_error("Invalid import", "ppcasm"); + throw std::runtime_error("invalid_import"); + } + + std::string result = std::to_string(name.size()); + result += kUndefinedSymbol; + + // mangle this + for (char& j : name) + { + if (j == ' ' || j == ',') + j = '$'; + } + + result += name; + + if (name.find(".code64") != std::string::npos) + { + // data is treated as code. + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + else if (name.find(".data64") != std::string::npos) + { + // no code will be executed from here. + kCurrentRecord.fKind = CompilerKit::kPefData; + } + else if (name.find(".zero64") != std::string::npos) + { + // this is a bss section. + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) + { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, result.c_str(), result.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // export is a special keyword used by i64asm to tell the AE output stage to + // mark this section as a header. it currently supports .code64, .data64 and + // .zero64. + else if (ParserKit::find_word(line, "export")) + { + if (kOutputAsBinary) + { + detail::print_error("Invalid directive in flat binary mode.", "i64asm"); + throw std::runtime_error("invalid_export_bin"); + } + + auto name = line.substr(line.find("export") + strlen("export") + 1); + + std::string name_copy = name; + + for (char& j : name) + { + if (j == ' ') + j = '$'; + } + + if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) != + kDefinedSymbols.end()) + { + detail::print_error("Symbol already defined.", "i64asm"); + throw std::runtime_error("invalid_export_bin"); + } + + kDefinedSymbols.push_back(name); + + if (name.find(".code64") != std::string::npos) + { + // data is treated as code. + + name_copy.erase(name_copy.find(".code64"), strlen(".code64")); + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + else if (name.find(".data64") != std::string::npos) + { + // no code will be executed from here. + + name_copy.erase(name_copy.find(".data64"), strlen(".data64")); + kCurrentRecord.fKind = CompilerKit::kPefData; + } + else if (name.find(".zero64") != std::string::npos) + { + // this is a bss section. - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. - kRecords.emplace_back(kCurrentRecord); + if (name == kPefStart) + { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } - return true; - } - // export is a special keyword used by i64asm to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64 and - // .zero64. - else if (ParserKit::find_word(line, "export")) { - if (kOutputAsBinary) { - detail::print_error("Invalid directive in flat binary mode.", "i64asm"); - throw std::runtime_error("invalid_export_bin"); - } + while (name_copy.find(" ") != std::string::npos) + name_copy.erase(name_copy.find(" "), 1); - auto name = line.substr(line.find("export") + strlen("export") + 1); + kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); + ++kOrigin; - std::string name_copy = name; + // now we can tell the code size of the previous kCurrentRecord. - for (char &j : name) { - if (j == ' ') j = '$'; - } + if (!kRecords.empty()) + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) != - kDefinedSymbols.end()) { - detail::print_error("Symbol already defined.", "i64asm"); - throw std::runtime_error("invalid_export_bin"); - } + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - kDefinedSymbols.push_back(name); + ++kCounter; - if (name.find(".code64") != std::string::npos) { - // data is treated as code. + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. + kRecords.emplace_back(kCurrentRecord); - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. + return true; + } - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) - name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; + return false; } // \brief algorithms and helpers. -namespace detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_alnum_space(char c) { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || - (c == ',') || (c == '(') || (c == ')') || (c == '"') || - (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.') || (c == '#')); -} - -bool is_valid(const std::string &str) { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); -} -} // namespace detail::algorithm +namespace detail::algorithm +{ + // \brief authorize a brief set of characters. + static inline bool is_not_alnum_space(char c) + { + return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || + (c == ',') || (c == '(') || (c == ')') || (c == '"') || + (c == '\'') || (c == '[') || (c == ']') || (c == '+') || + (c == '_') || (c == ':') || (c == '@') || (c == '.') || (c == '#')); + } + + bool is_valid(const std::string& str) + { + return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); + } +} // namespace detail::algorithm ///////////////////////////////////////////////////////////////////////////////////////// @@ -516,491 +591,588 @@ bool is_valid(const std::string &str) { ///////////////////////////////////////////////////////////////////////////////////////// -std::string CompilerKit::EncoderAMD64::CheckLine(std::string &line, - const std::string &file) { - std::string err_str; - - if (line.empty() || ParserKit::find_word(line, "import") || - ParserKit::find_word(line, "export") || - ParserKit::find_word(line, kAssemblerPragmaSymStr) || - ParserKit::find_word(line, ";") || line[0] == kAssemblerPragmaSym) { - if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - // now check the line for validity - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non valid characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non alphanumeric characters.\nHere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto &ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - for (auto &opcodeAMD64 : kOpcodesAMD64) { - if (ParserKit::find_word(line, opcodeAMD64.fName)) { - return err_str; - } - } - - err_str += "\nUnrecognized instruction -> " + line; - - return err_str; +std::string CompilerKit::EncoderAMD64::CheckLine(std::string& line, + const std::string& file) +{ + std::string err_str; + + if (line.empty() || ParserKit::find_word(line, "import") || + ParserKit::find_word(line, "export") || + ParserKit::find_word(line, kAssemblerPragmaSymStr) || + ParserKit::find_word(line, ";") || line[0] == kAssemblerPragmaSym) + { + if (line.find(';') != std::string::npos) + { + line.erase(line.find(';')); + } + else + { + // now check the line for validity + if (!detail::algorithm::is_valid(line)) + { + err_str = "Line contains non valid characters.\nhere -> "; + err_str += line; + } + } + + return err_str; + } + + if (!detail::algorithm::is_valid(line)) + { + err_str = "Line contains non alphanumeric characters.\nHere -> "; + err_str += line; + + return err_str; + } + + // check for a valid instruction format. + + if (line.find(',') != std::string::npos) + { + if (line.find(',') + 1 == line.size()) + { + err_str += "\nInstruction lacks right register, here -> "; + err_str += line.substr(line.find(',')); + + return err_str; + } + else + { + bool nothing_on_right = true; + + if (line.find(',') + 1 > line.size()) + { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + + auto substr = line.substr(line.find(',') + 1); + + for (auto& ch : substr) + { + if (ch != ' ' && ch != '\t') + { + nothing_on_right = false; + } + } + + // this means we found nothing after that ',' . + if (nothing_on_right) + { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + } + } + for (auto& opcodeAMD64 : kOpcodesAMD64) + { + if (ParserKit::find_word(line, opcodeAMD64.fName)) + { + return err_str; + } + } + + err_str += "\nUnrecognized instruction -> " + line; + + return err_str; } -bool CompilerKit::EncoderAMD64::WriteNumber(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) { - if (errno != 0) { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) { - if (errno != 0) { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; +bool CompilerKit::EncoderAMD64::WriteNumber(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; } -bool CompilerKit::EncoderAMD64::WriteNumber32(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; +bool CompilerKit::EncoderAMD64::WriteNumber32(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; } -bool CompilerKit::EncoderAMD64::WriteNumber16(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) { - if (errno != 0) { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) { - if (errno != 0) { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; +bool CompilerKit::EncoderAMD64::WriteNumber16(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; } -bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - kAppBytes.push_back(num.number); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) { - if (errno != 0) { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) { - if (errno != 0) { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - kAppBytes.push_back(num.number); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; +bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + kAppBytes.push_back(num.number); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + kAppBytes.push_back(num.number); + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + kAppBytes.push_back(num.number); + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + kAppBytes.push_back(num.number); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -1009,239 +1181,304 @@ bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t &pos, ///////////////////////////////////////////////////////////////////////////////////////// -bool CompilerKit::EncoderAMD64::WriteLine(std::string &line, - const std::string &file) { - if (ParserKit::find_word(line, "export ")) return true; - - struct RegMapAMD64 { - std::string fName; - i64_byte_t fModRM; - }; - - std::vector REGISTER_LIST{ - {.fName = "ax", .fModRM = 0x0}, {.fName = "cx", .fModRM = 1}, - {.fName = "dx", .fModRM = 0x2}, {.fName = "bx", .fModRM = 3}, - {.fName = "sp", .fModRM = 0x4}, {.fName = "bp", .fModRM = 5}, - {.fName = "si", .fModRM = 0x6}, {.fName = "di", .fModRM = 7}, - {.fName = "r8", .fModRM = 8}, {.fName = "r13", .fModRM = 9}, - {.fName = "r9", .fModRM = 10}, {.fName = "r14", .fModRM = 11}, - {.fName = "r10", .fModRM = 12}, {.fName = "r15", .fModRM = 13}, - {.fName = "r11", .fModRM = 14}, - }; - - bool foundInstruction = false; - - for (auto &opcodeAMD64 : kOpcodesAMD64) { - // strict check here - if (ParserKit::find_word(line, opcodeAMD64.fName) && - detail::algorithm::is_valid(line)) { - foundInstruction = true; - std::string name(opcodeAMD64.fName); - - /// Move instruction handler. - if (name.find("mov") != std::string::npos) { - std::string substr = line.substr(line.find(name) + name.size()); - - uint64_t bits = kRegisterBitWidth; - - if (substr.find(",") == std::string::npos) { - detail::print_error("Syntax error.", "i64asm"); - throw std::runtime_error("syntax_err"); - } - - bool onlyOneReg = true; - - std::vector currentRegList; - - for (auto ® : REGISTER_LIST) { - std::vector regExt = {'e', 'r'}; - - for (auto &ext : regExt) { - std::string registerName; - - if (bits > 16) registerName.push_back(ext); - - registerName += reg.fName; - - while (line.find(registerName) != std::string::npos) { - line.erase(line.find(registerName), registerName.size()); - - if (bits == 16) { - if (registerName[0] == 'r') { - detail::print_error( - "invalid size for register, current bit width is: " + - std::to_string(kRegisterBitWidth), - file); - throw std::runtime_error("invalid_reg_size"); - } - } - - currentRegList.push_back( - {.fName = registerName, .fModRM = reg.fModRM}); - } - } - } - - if (currentRegList.size() > 1) onlyOneReg = false; - - bool hasRBasedRegs = false; - - if (!onlyOneReg) { - /// very tricky to understand. - /// this checks for a r8 through r15 register. - if (currentRegList[0].fName[0] == 'r' || - currentRegList[1].fName[0] == 'r') { - if (isdigit(currentRegList[0].fName[1]) && - isdigit(currentRegList[1].fName[1])) { - kAppBytes.emplace_back(0x4d); - hasRBasedRegs = true; - } else if (isdigit(currentRegList[0].fName[1]) || - isdigit(currentRegList[1].fName[1])) { - kAppBytes.emplace_back(0x4c); - hasRBasedRegs = true; - } - } - } - - if (bits == 64 || bits == 32) { - if (!hasRBasedRegs && bits >= 32) { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - } - - kAppBytes.emplace_back(0x89); - } else if (bits == 16) { - if (hasRBasedRegs) { - detail::print_error( - "Invalid combination of operands and registers.", "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - kAppBytes.emplace_back(0x66); - kAppBytes.emplace_back(0x89); - } - - if (currentRegList[1].fName[0] == 'r' && - currentRegList[0].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[0].fName[0] == 'r' && - currentRegList[1].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (bits == 16) { - if (currentRegList[0].fName[0] == 'r' || - currentRegList[0].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] == 'r' || - currentRegList[1].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - } else { - if (currentRegList[0].fName[0] != 'r' || - currentRegList[0].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] != 'r' || - currentRegList[1].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - } - - /// encode register using the modrm encoding. - - auto modrm = (0x3 << 6 | currentRegList[1].fModRM << 3 | - currentRegList[0].fModRM); - - kAppBytes.emplace_back(modrm); - - break; - } else if (name == "int" || name == "into" || name == "intd") { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - this->WriteNumber8(line.find(name) + name.size() + 1, line); - - break; - } else if (name == "jmp" || name == "call") { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - if (!this->WriteNumber32(line.find(name) + name.size() + 1, line)) { - throw std::runtime_error("BUG: WriteNumber32"); - } - - break; - } else { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - break; - } - } - } - - if (line[0] == kAssemblerPragmaSym) { - if (foundInstruction) { - detail::print_error("Syntax error.", "i64asm"); - throw std::runtime_error("syntax_err"); - } - - if (line.find("bits 64") != std::string::npos) { - kRegisterBitWidth = 64U; - } else if (line.find("bits 32") != std::string::npos) { - kRegisterBitWidth = 32U; - } else if (line.find("bits 16") != std::string::npos) { - kRegisterBitWidth = 16U; - } else if (line.find("org") != std::string::npos) { - size_t base[] = {10, 16, 2, 7}; - - for (size_t i = 0; i < 4; i++) { - if (kOrigin = strtol( - (line.substr(line.find("org") + strlen("org") + 1)).c_str(), - nullptr, base[i]); - kOrigin) { - if (errno != 0) { - continue; - } else { - if (kVerbose) { - kStdOut << "i64asm: origin set: " << kOrigin << std::endl; - } - - break; - } - } - } - } - } - /// write a dword - else if (line.find(".dword") != std::string::npos) { - this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line); - } - /// write a long - else if (line.find(".long") != std::string::npos) { - this->WriteNumber(line.find(".long") + strlen(".long") + 1, line); - } - /// write a 16-bit number - else if (line.find(".word") != std::string::npos) { - this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line); - } - - kOrigin += cAMD64IPAlignment; - - return true; +bool CompilerKit::EncoderAMD64::WriteLine(std::string& line, + const std::string& file) +{ + if (ParserKit::find_word(line, "export ")) + return true; + + struct RegMapAMD64 + { + std::string fName; + i64_byte_t fModRM; + }; + + std::vector REGISTER_LIST{ + {.fName = "ax", .fModRM = 0x0}, + {.fName = "cx", .fModRM = 1}, + {.fName = "dx", .fModRM = 0x2}, + {.fName = "bx", .fModRM = 3}, + {.fName = "sp", .fModRM = 0x4}, + {.fName = "bp", .fModRM = 5}, + {.fName = "si", .fModRM = 0x6}, + {.fName = "di", .fModRM = 7}, + {.fName = "r8", .fModRM = 8}, + {.fName = "r13", .fModRM = 9}, + {.fName = "r9", .fModRM = 10}, + {.fName = "r14", .fModRM = 11}, + {.fName = "r10", .fModRM = 12}, + {.fName = "r15", .fModRM = 13}, + {.fName = "r11", .fModRM = 14}, + }; + + bool foundInstruction = false; + + for (auto& opcodeAMD64 : kOpcodesAMD64) + { + // strict check here + if (ParserKit::find_word(line, opcodeAMD64.fName) && + detail::algorithm::is_valid(line)) + { + foundInstruction = true; + std::string name(opcodeAMD64.fName); + + /// Move instruction handler. + if (name.find("mov") != std::string::npos) + { + std::string substr = line.substr(line.find(name) + name.size()); + + uint64_t bits = kRegisterBitWidth; + + if (substr.find(",") == std::string::npos) + { + detail::print_error("Syntax error.", "i64asm"); + throw std::runtime_error("syntax_err"); + } + + bool onlyOneReg = true; + + std::vector currentRegList; + + for (auto& reg : REGISTER_LIST) + { + std::vector regExt = {'e', 'r'}; + + for (auto& ext : regExt) + { + std::string registerName; + + if (bits > 16) + registerName.push_back(ext); + + registerName += reg.fName; + + while (line.find(registerName) != std::string::npos) + { + line.erase(line.find(registerName), registerName.size()); + + if (bits == 16) + { + if (registerName[0] == 'r') + { + detail::print_error( + "invalid size for register, current bit width is: " + + std::to_string(kRegisterBitWidth), + file); + throw std::runtime_error("invalid_reg_size"); + } + } + + currentRegList.push_back( + {.fName = registerName, .fModRM = reg.fModRM}); + } + } + } + + if (currentRegList.size() > 1) + onlyOneReg = false; + + bool hasRBasedRegs = false; + + if (!onlyOneReg) + { + /// very tricky to understand. + /// but this checks for a r8 through r15 register. + if (currentRegList[0].fName[0] == 'r' || + currentRegList[1].fName[0] == 'r') + { + if (isdigit(currentRegList[0].fName[1]) && + isdigit(currentRegList[1].fName[1])) + { + kAppBytes.emplace_back(0x4d); + hasRBasedRegs = true; + } + else if (isdigit(currentRegList[0].fName[1]) || + isdigit(currentRegList[1].fName[1])) + { + kAppBytes.emplace_back(0x4c); + hasRBasedRegs = true; + } + } + } + + if (bits == 64 || bits == 32) + { + if (!hasRBasedRegs && bits >= 32) + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + } + + kAppBytes.emplace_back(0x89); + } + else if (bits == 16) + { + if (hasRBasedRegs) + { + detail::print_error( + "Invalid combination of operands and registers.", "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + kAppBytes.emplace_back(0x66); + kAppBytes.emplace_back(0x89); + } + + if (currentRegList[1].fName[0] == 'r' && + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[0].fName[0] == 'r' && + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (bits == 16) + { + if (currentRegList[0].fName[0] == 'r' || + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[1].fName[0] == 'r' || + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + } + else + { + if (currentRegList[0].fName[0] != 'r' || + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[1].fName[0] != 'r' || + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + } + + /// encode register using the modrm encoding. + + auto modrm = (0x3 << 6 | currentRegList[1].fModRM << 3 | + currentRegList[0].fModRM); + + kAppBytes.emplace_back(modrm); + + break; + } + else if (name == "int" || name == "into" || name == "intd") + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + this->WriteNumber8(line.find(name) + name.size() + 1, line); + + break; + } + else if (name == "jmp" || name == "call") + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + + if (!this->WriteNumber32(line.find(name) + name.size() + 1, line)) + { + throw std::runtime_error("BUG: WriteNumber32"); + } + + break; + } + else + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + + break; + } + } + } + + if (line[0] == kAssemblerPragmaSym) + { + if (foundInstruction) + { + detail::print_error("Syntax error: " + line, "i64asm"); + throw std::runtime_error("syntax_err"); + } + + if (line.find("bits 64") != std::string::npos) + { + kRegisterBitWidth = 64U; + } + else if (line.find("bits 32") != std::string::npos) + { + kRegisterBitWidth = 32U; + } + else if (line.find("bits 16") != std::string::npos) + { + kRegisterBitWidth = 16U; + } + else if (line.find("org") != std::string::npos) + { + size_t base[] = {10, 16, 2, 7}; + + for (size_t i = 0; i < 4; i++) + { + if (kOrigin = strtol( + (line.substr(line.find("org") + strlen("org") + 1)).c_str(), + nullptr, base[i]); + kOrigin) + { + if (errno != 0) + { + continue; + } + else + { + if (kVerbose) + { + kStdOut << "i64asm: origin set: " << kOrigin << std::endl; + } + + break; + } + } + } + } + } + /// write a dword + else if (line.find(".dword") != std::string::npos) + { + this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line); + } + /// write a long + else if (line.find(".long") != std::string::npos) + { + this->WriteNumber(line.find(".long") + strlen(".long") + 1, line); + } + /// write a 16-bit number + else if (line.find(".word") != std::string::npos) + { + this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line); + } + + kOrigin += cAMD64IPAlignment; + + return true; } // Last rev 13-1-24 diff --git a/Sources/link.cc b/Sources/link.cc index 13e1db1..d0d330e 100644 --- a/Sources/link.cc +++ b/Sources/link.cc @@ -84,13 +84,13 @@ MPCC_MODULE(NewOSLinker) { kStdOut << "-version: Show program version.\n"; kStdOut << "-verbose: Enable program trace.\n"; kStdOut << "-shared: Output as a shared PEF.\n"; - kStdOut << "-fat-bin: Output as FAT PEF.\n"; - kStdOut << "-32x0: Output as 32x0 PEF.\n"; - kStdOut << "-64x0: Output as 64x0 PEF.\n"; - kStdOut << "-amd64: Output as AMD64 PEF.\n"; - kStdOut << "-rv64: Output as RISC-V 64 PEF.\n"; - kStdOut << "-ppc64: Output as POWER 64 PEF.\n"; - kStdOut << "-output-file: Select output file name.\n"; + kStdOut << "-fat-bin: Output as a FAT PEF.\n"; + kStdOut << "-32x0: Output as a 32x0 PEF.\n"; + kStdOut << "-64x0: Output as a 64x0 PEF.\n"; + kStdOut << "-amd64: Output as a AMD64 PEF.\n"; + kStdOut << "-rv64: Output as a RISC-V PEF.\n"; + kStdOut << "-ppc64: Output as a POWER PEF.\n"; + kStdOut << "-output-file: Select the output file name.\n"; return 0; } else if (StringCompare(argv[i], "-v") == 0) { @@ -141,7 +141,7 @@ MPCC_MODULE(NewOSLinker) { } else { if (argv[i][0] == '-') { kStdOut << "link: unknown flag: " << argv[i] << "\n"; - return -MPCC_EXEC_ERROR; + return MPCC_EXEC_ERROR; } kObjectList.emplace_back(argv[i]); @@ -203,7 +203,7 @@ MPCC_MODULE(NewOSLinker) { kStdOut << "link: error: " << strerror(errno) << "\n"; } - return -MPCC_FILE_NOT_FOUND; + return MPCC_FILE_NOT_FOUND; } //! Read AE to convert as PEF. @@ -235,7 +235,7 @@ MPCC_MODULE(NewOSLinker) { << std::endl; std::remove(kOutput.c_str()); - return -MPCC_FAT_ERROR; + return MPCC_FAT_ERROR; } else { if (kVerbose) { kStdOut << "Yes.\n"; @@ -329,7 +329,7 @@ MPCC_MODULE(NewOSLinker) { std::remove(kOutput.c_str()); // don't continue, it is a fatal error. - return -MPCC_EXEC_ERROR; + return MPCC_EXEC_ERROR; } pef_container.Cpu = archs; @@ -596,7 +596,7 @@ MPCC_MODULE(NewOSLinker) { } std::remove(kOutput.c_str()); - return -MPCC_EXEC_ERROR; + return MPCC_EXEC_ERROR; } // step 2.5: write program bytes. @@ -632,7 +632,7 @@ MPCC_MODULE(NewOSLinker) { << ", is corrupt, removing file...\n"; std::remove(kOutput.c_str()); - return -MPCC_EXEC_ERROR; + return MPCC_EXEC_ERROR; } return 0; diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc index 6c1f367..5c444dd 100644 --- a/Sources/ppcasm.cc +++ b/Sources/ppcasm.cc @@ -17,6 +17,7 @@ #define __ASM_NEED_PPC__ 1 +#include #include #include #include @@ -100,7 +101,7 @@ void print_warning(std::string reason, const std::string &file) noexcept { } // namespace detail /// Do not move it on top! it uses the assembler detail namespace! -#include +#include ///////////////////////////////////////////////////////////////////////////////////////// @@ -224,36 +225,36 @@ MPCC_MODULE(NewOSAssemblerPowerPC) { std::size_t record_count = 0UL; - for (auto &rec : kRecords) { - if (kVerbose) - kStdOut << "ppcasm: Wrote record " << rec.fName << " to file...\n"; - - rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; - rec.fOffset = record_count; + for (auto &record_hdr : kRecords) { + record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime; + record_hdr.fOffset = record_count; ++record_count; - file_ptr_out << rec; + file_ptr_out << record_hdr; + + if (kVerbose) + kStdOut << "ppcasm: Wrote record " << record_hdr.fName << "...\n"; } // increment once again, so that we won't lie about the kUndefinedSymbols. ++record_count; for (auto &sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader _record_hdr{0}; + CompilerKit::AERecordHeader undefined_sym{0}; if (kVerbose) kStdOut << "ppcasm: Wrote symbol " << sym << " to file...\n"; - _record_hdr.fKind = kAEInvalidOpcode; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; + undefined_sym.fKind = kAEInvalidOpcode; + undefined_sym.fSize = sym.size(); + undefined_sym.fOffset = record_count; ++record_count; - memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); + memset(undefined_sym.fPad, kAEInvalidOpcode, kAEPad); + memcpy(undefined_sym.fName, sym.c_str(), sym.size()); - file_ptr_out << _record_hdr; + file_ptr_out << undefined_sym; ++kCounter; } @@ -293,7 +294,7 @@ asm_fail_exit: if (kVerbose) kStdOut << "ppcasm: Exit failed.\n"; - return -1; + return MPCC_EXEC_ERROR; } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/posix.make b/posix.make index 42e0ece..4e47c53 100644 --- a/posix.make +++ b/posix.make @@ -19,7 +19,7 @@ LINK_ALT_4_OUTPUT=Output/ppclink.exec PP_SRC=Sources/bpp.cc PP_OUTPUT=Output/bpp.exec -SRC_COMMON=Sources/String.cc Sources/AssemblyFactory.cxx +SRC_COMMON=Sources/String.cc Sources/AssemblyFactory.cc # C++ Compiler (AMD64) AMD64_CXX_SRC=Sources/cplusplus.cc $(SRC_COMMON) diff --git a/win64.make b/win64.make index 4abac3e..0d8482d 100644 --- a/win64.make +++ b/win64.make @@ -19,7 +19,7 @@ LINK_ALT_2_OUTPUT=Output/32link.exe PP_SRC=Sources/bpp.cc PP_OUTPUT=Output/bpp.exe -SRC_COMMON=Sources/String.cc Sources/AssemblyFactory.cxx +SRC_COMMON=Sources/String.cc Sources/AssemblyFactory.cc # C++ Compiler (AMD64) AMD64_CXX_SRC=Sources/cplusplus.cc $(SRC_COMMON) -- cgit v1.2.3