summaryrefslogtreecommitdiffhomepage
path: root/dev/CompilerKit/src/Backend
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal@nekernel.org>2025-11-24 03:05:29 +0100
committerAmlal El Mahrouss <amlal@nekernel.org>2025-11-24 03:05:29 +0100
commitbbe2c77243c541ca7e0075149f5be3262eb89523 (patch)
treeae5d59d299344fd19584a2c3642bacd788e841d4 /dev/CompilerKit/src/Backend
parentb5adf16a96b9cbb80c74cf30404ed5bcff03ac34 (diff)
feat! breaking changes on necti sources.
Signed-off-by: Amlal El Mahrouss <amlal@nekernel.org>
Diffstat (limited to 'dev/CompilerKit/src/Backend')
-rw-r--r--dev/CompilerKit/src/Backend/Assembler32x0.cc39
-rw-r--r--dev/CompilerKit/src/Backend/Assembler64x0.cc874
-rw-r--r--dev/CompilerKit/src/Backend/AssemblerAMD64.cc1204
-rw-r--r--dev/CompilerKit/src/Backend/AssemblerARM64.cc587
-rw-r--r--dev/CompilerKit/src/Backend/AssemblerPowerPC.cc911
5 files changed, 0 insertions, 3615 deletions
diff --git a/dev/CompilerKit/src/Backend/Assembler32x0.cc b/dev/CompilerKit/src/Backend/Assembler32x0.cc
deleted file mode 100644
index 6ffaa6e..0000000
--- a/dev/CompilerKit/src/Backend/Assembler32x0.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-/* ========================================
-
- Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license
-
-======================================== */
-
-/// bugs: 0
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @file 32asm.cc
-// @author Amlal El Mahrouss
-// @brief 32x0 Assembler.
-
-// REMINDER: when dealing with an undefined symbol use (string
-// size):LinkerFindSymbol:(string) so that ld will look for it.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#ifndef __ASM_NEED_32x0__
-#define __ASM_NEED_32x0__ 1
-#endif
-
-#include <CompilerKit/AE.h>
-#include <CompilerKit/Frontend.h>
-#include <CompilerKit/PEF.h>
-#include <CompilerKit/impl/32x0.h>
-#include <CompilerKit/utils/CompilerUtils.h>
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief 32x0 Assembler entrypoint, the program/module starts here.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-NECTI_MODULE(NEAssemblerMain32000) {
- CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler);
- return EXIT_SUCCESS;
-}
diff --git a/dev/CompilerKit/src/Backend/Assembler64x0.cc b/dev/CompilerKit/src/Backend/Assembler64x0.cc
deleted file mode 100644
index f9052d2..0000000
--- a/dev/CompilerKit/src/Backend/Assembler64x0.cc
+++ /dev/null
@@ -1,874 +0,0 @@
-/* ========================================
-
- Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license
-
-======================================== */
-
-/// bugs: 0
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @file Assembler64x0.cc
-// @author Amlal El Mahrouss
-// @brief 64x000 Assembler.
-
-// REMINDER: when dealing with an undefined symbol use (string
-// size):LinkerFindSymbol:(string) so that ld will look for it.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#ifndef __ASM_NEED_64x0__
-#define __ASM_NEED_64x0__ 1
-#endif
-
-#include <CompilerKit/AE.h>
-#include <CompilerKit/Frontend.h>
-#include <CompilerKit/PEF.h>
-#include <CompilerKit/impl/64x0.h>
-#include <CompilerKit/utils/CompilerUtils.h>
-#include <algorithm>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <vector>
-
-/////////////////////
-
-// ANSI ESCAPE CODES
-
-/////////////////////
-
-static char kOutputArch = CompilerKit::kPefArch64000;
-
-constexpr auto k64x0IPAlignment = 0x1U;
-
-static std::size_t kCounter = 1UL;
-
-static std::uintptr_t kOrigin = kPefBaseOrigin;
-static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel;
-
-static std::vector<e64k_num_t> kBytes;
-
-static CompilerKit::AERecordHeader kCurrentRecord{
- .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0};
-
-static std::vector<CompilerKit::AERecordHeader> kRecords;
-static std::vector<std::string> kUndefinedSymbols;
-
-static const std::string kUndefinedSymbol = ":UndefinedSymbol:";
-static const std::string kRelocSymbol = ":RuntimeSymbol:";
-
-// \brief forward decl.
-static bool asm_read_attributes(std::string line);
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief 64x0 assembler entrypoint, the program/module starts here.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-NECTI_MODULE(AssemblerMain64x0) {
- CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler);
-
- for (size_t i = 1; i < argc; ++i) {
- if (argv[i][0] == '-') {
- if (strcmp(argv[i], "-64x0-ver") == 0 || strcmp(argv[i], "-64x0-v") == 0) {
- kStdOut
- << "Assembler64x0: 64x0 Assembler.\nAssembler64x0: v1.10\nAssembler64x0: Copyright (c) "
- "Amlal El Mahrouss\n";
- return 0;
- } else if (strcmp(argv[i], "-64x0-h") == 0) {
- kStdOut << "Assembler64x0: 64x0 Assembler.\nAssembler64x0: Copyright (c) 2024 Mahrouss "
- "Logic.\n";
- kStdOut << "--version: Print program version.\n";
- kStdOut << "--verbose: Print verbose output.\n";
- kStdOut << "--binary: Output as flat binary.\n";
- kStdOut << "--64xxx: Compile for a subset of the X64000.\n";
-
- return 0;
- } else if (strcmp(argv[i], "-64x0-binary") == 0) {
- kOutputAsBinary = true;
- continue;
- } else if (strcmp(argv[i], "-64x0-verbose") == 0) {
- kVerbose = true;
- continue;
- }
-
- kStdOut << "Assembler64x0: ignore " << argv[i] << "\n";
- continue;
- }
-
- if (!std::filesystem::exists(argv[i])) {
- kStdOut << "Assembler64x0: 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 << "Assembler64x0: error: " << strerror(errno) << "\n";
- }
- }
-
- std::string line;
-
- CompilerKit::AEHeader hdr{0};
-
- memset(hdr.fPad, kAENullType, kAEPad);
-
- hdr.fMagic[0] = kAEMag0;
- hdr.fMagic[1] = kAEMag1;
- hdr.fSize = sizeof(CompilerKit::AEHeader);
- hdr.fArch = kOutputArch;
-
- /////////////////////////////////////////////////////////////////////////////////////////
-
- // COMPILATION LOOP
-
- /////////////////////////////////////////////////////////////////////////////////////////
-
- CompilerKit::Encoder64x0 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, "CompilerKit");
- }
-
- std::filesystem::remove(object_output);
- goto asm_fail_exit;
- }
- }
-
- if (!kOutputAsBinary) {
- if (kVerbose) {
- kStdOut << "Assembler64x0: Writing object file...\n";
- }
-
- // this is the final step, write everything to the file.
-
- auto pos = file_ptr_out.tellp();
-
- hdr.fCount = kRecords.size() + kUndefinedSymbols.size();
-
- file_ptr_out << hdr;
-
- if (kRecords.empty()) {
- kStdErr << "Assembler64x0: At least one record is needed to write an object "
- "file.\nAssembler64x0: Make one using `public_segment .code64 foo_bar`.\n";
-
- std::filesystem::remove(object_output);
- return 1;
- }
-
- kRecords[kRecords.size() - 1].fSize = kBytes.size();
-
- std::size_t record_count = 0UL;
-
- for (auto& rec : kRecords) {
- if (kVerbose) kStdOut << "Assembler64x0: Wrote record " << rec.fName << " to file...\n";
-
- rec.fFlags |= CompilerKit::kKindRelocationAtRuntime;
- rec.fOffset = record_count;
- ++record_count;
-
- file_ptr_out << rec;
- }
-
- // increment once again, so that we won't lie about the kUndefinedSymbols.
- ++record_count;
-
- for (auto& sym : kUndefinedSymbols) {
- CompilerKit::AERecordHeader _record_hdr{0};
-
- if (kVerbose) kStdOut << "Assembler64x0: Wrote symbol " << sym << " to file...\n";
-
- _record_hdr.fKind = kAENullType;
- _record_hdr.fSize = sym.size();
- _record_hdr.fOffset = record_count;
-
- ++record_count;
-
- memset(_record_hdr.fPad, kAENullType, kAEPad);
- memcpy(_record_hdr.fName, sym.c_str(), sym.size());
-
- file_ptr_out << _record_hdr;
-
- ++kCounter;
- }
-
- auto pos_end = file_ptr_out.tellp();
-
- file_ptr_out.seekp(pos);
-
- hdr.fStartCode = pos_end;
- hdr.fCodeSize = kBytes.size();
-
- file_ptr_out << hdr;
-
- file_ptr_out.seekp(pos_end);
- } else {
- if (kVerbose) {
- kStdOut << "Assembler64x0: Write raw binary...\n";
- }
- }
-
- // byte from byte, we write this.
- for (auto& byte : kBytes) {
- file_ptr_out.write(reinterpret_cast<const char*>(&byte), sizeof(byte));
- }
-
- if (kVerbose) kStdOut << "Assembler64x0: Wrote file with program in it.\n";
-
- file_ptr_out.flush();
- file_ptr_out.close();
-
- if (kVerbose) kStdOut << "Assembler64x0: Exit succeeded.\n";
-
- return 0;
- }
-
-asm_fail_exit:
-
- if (kVerbose) kStdOut << "Assembler64x0: Exit failed.\n";
-
- return 1;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief Check for attributes
-// returns true if any was found.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-static bool asm_read_attributes(std::string line) {
- // extern_segment is the opposite of public_segment, it signals to the ld
- // that we need this symbol.
- if (CompilerKit::find_word(line, "extern_segment")) {
- if (kOutputAsBinary) {
- Detail::print_error("Invalid extern_segment directive in flat binary mode.", "CompilerKit");
- throw std::runtime_error("invalid_extern_segment_bin");
- }
-
- auto name = line.substr(line.find("extern_segment") + strlen("extern_segment"));
-
- /// sanity check to avoid stupid linker errors.
- if (name.size() == 0) {
- Detail::print_error("Invalid extern_segment", "power-as");
- throw std::runtime_error("invalid_extern_segment");
- }
-
- 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 = kBytes.size();
-
- memset(kCurrentRecord.fName, 0, kAESymbolLen);
- memcpy(kCurrentRecord.fName, result.c_str(), result.size());
-
- ++kCounter;
-
- memset(kCurrentRecord.fPad, kAENullType, kAEPad);
-
- kRecords.emplace_back(kCurrentRecord);
-
- return true;
- }
- // public_segment is a special keyword used by Assembler64x0 to tell the AE output stage to
- // mark this section as a header. it currently supports .code64, .data64.,
- // .zero64
- else if (CompilerKit::find_word(line, "public_segment")) {
- if (kOutputAsBinary) {
- Detail::print_error("Invalid public_segment directive in flat binary mode.", "CompilerKit");
- throw std::runtime_error("invalid_public_segment_bin");
- }
-
- auto name = line.substr(line.find("public_segment") + strlen("public_segment"));
-
- std::string name_copy = name;
-
- for (char& j : name) {
- if (j == ' ') j = '$';
- }
-
- 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.
-
- 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 = kBytes.size();
-
- memset(kCurrentRecord.fName, 0, kAESymbolLen);
- memcpy(kCurrentRecord.fName, name.c_str(), name.size());
-
- ++kCounter;
-
- memset(kCurrentRecord.fPad, kAENullType, kAEPad);
-
- kRecords.emplace_back(kCurrentRecord);
-
- return true;
- }
-
- 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 == '.'));
-}
-
-bool is_valid_64x0(std::string str) {
- return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end();
-}
-} // namespace Detail::algorithm
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief Check for line (syntax check)
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-std::string CompilerKit::Encoder64x0::CheckLine(std::string line, std::string file) {
- std::string err_str;
-
- if (line.empty() || CompilerKit::find_word(line, "extern_segment") ||
- CompilerKit::find_word(line, "public_segment") || line.find('#') != std::string::npos ||
- CompilerKit::find_word(line, ";")) {
- if (line.find('#') != std::string::npos) {
- line.erase(line.find('#'));
- } else if (line.find(';') != std::string::npos) {
- line.erase(line.find(';'));
- } else {
- // now check the line for validity
- if (!Detail::algorithm::is_valid_64x0(line)) {
- err_str = "Line contains non alphanumeric characters.\nhere -> ";
- err_str += line;
- }
- }
-
- return err_str;
- }
-
- if (!Detail::algorithm::is_valid_64x0(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;
- }
- }
- }
-
- // these do take an argument.
- std::vector<std::string> operands_inst = {"stw", "ldw", "lda", "sta"};
-
- // these don't.
- std::vector<std::string> filter_inst = {"jlr", "jrl", "int"};
-
- for (auto& opcode64x0 : kOpcodes64x0) {
- if (line.find(opcode64x0.fName) != std::string::npos) {
- if (opcode64x0.fFunct7 == kAsmNoArgs) return err_str;
-
- for (auto& op : operands_inst) {
- // if only the instruction was found.
- if (line == op) {
- err_str += "\nMalformed ";
- err_str += op;
- err_str += " instruction, here -> ";
- err_str += line;
- }
- }
-
- // if it is like that -> addr1, 0x0
- if (auto it = std::find(filter_inst.begin(), filter_inst.end(), opcode64x0.fName);
- it == filter_inst.cend()) {
- if (CompilerKit::find_word(line, opcode64x0.fName)) {
- if (!isspace(line[line.find(opcode64x0.fName) + strlen(opcode64x0.fName)])) {
- err_str += "\nMissing space between ";
- err_str += opcode64x0.fName;
- err_str += " and operands.\nhere -> ";
- err_str += line;
- }
- }
- }
-
- return err_str;
- }
- }
-
- err_str += "Unrecognized instruction: " + line;
-
- return err_str;
-}
-
-bool CompilerKit::Encoder64x0::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, "CompilerKit");
- throw std::runtime_error("invalid_hex_number");
- }
- }
-
- CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16));
-
- for (char& i : num.number) {
- kBytes.push_back(i);
- }
-
- if (kVerbose) {
- kStdOut << "Assembler64x0: 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, "CompilerKit");
- throw std::runtime_error("invalid_bin");
- }
- }
-
- CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
-
- if (kVerbose) {
- kStdOut << "Assembler64x0: found a base 2 number here: " << jump_label.substr(pos) << "\n";
- }
-
- for (char& i : num.number) {
- kBytes.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, "CompilerKit");
- throw std::runtime_error("invalid_octal");
- }
- }
-
- CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
-
- if (kVerbose) {
- kStdOut << "Assembler64x0: found a base 8 number here: " << jump_label.substr(pos) << "\n";
- }
-
- for (char& i : num.number) {
- kBytes.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(strtol(jump_label.substr(pos).c_str(), nullptr, 10));
-
- for (char& i : num.number) {
- kBytes.push_back(i);
- }
-
- if (kVerbose) {
- kStdOut << "Assembler64x0: found a base 10 number here: " << jump_label.substr(pos) << "\n";
- }
-
- return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief Read and write an instruction to the output array.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-bool CompilerKit::Encoder64x0::WriteLine(std::string line, std::string file) {
- if (CompilerKit::find_word(line, "public_segment ")) return true;
-
- for (auto& opcode64x0 : kOpcodes64x0) {
- // strict check here
- if (CompilerKit::find_word(line, opcode64x0.fName) && Detail::algorithm::is_valid_64x0(line)) {
- std::string name(opcode64x0.fName);
- std::string jump_label, cpy_jump_label;
-
- kBytes.emplace_back(opcode64x0.fOpcode);
- kBytes.emplace_back(opcode64x0.fFunct3);
- kBytes.emplace_back(opcode64x0.fFunct7);
-
- // check funct7 type.
- switch (opcode64x0.fFunct7) {
- // reg to reg means register to register transfer operation.
- case kAsmRegToReg:
- case kAsmImmediate: {
- // \brief how many registers we found.
- std::size_t found_some = 0UL;
-
- for (size_t line_index = 0UL; line_index < line.size(); line_index++) {
- if (line[line_index] == kAsmRegisterPrefix[0] && isdigit(line[line_index + 1])) {
- std::string register_syntax = kAsmRegisterPrefix;
- register_syntax += line[line_index + 1];
-
- if (isdigit(line[line_index + 2])) register_syntax += line[line_index + 2];
-
- std::string reg_str;
- reg_str += line[line_index + 1];
-
- if (isdigit(line[line_index + 2])) reg_str += line[line_index + 2];
-
- // it ranges from r0 to r19
- // something like r190 doesn't exist in the instruction set.
- if (kOutputArch == CompilerKit::kPefArch64000) {
- if (isdigit(line[line_index + 3]) && isdigit(line[line_index + 2])) {
- reg_str += line[line_index + 3];
- Detail::print_error("invalid register index, r" + reg_str +
- "\nnote: The 64x0 accepts registers from r0 to r20.",
- file);
- throw std::runtime_error("invalid_register_index");
- }
- }
-
- // finally cast to a size_t
- std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10);
-
- if (reg_index > kAsmRegisterLimit) {
- Detail::print_error("invalid register index, r" + reg_str, file);
- throw std::runtime_error("invalid_register_index");
- }
-
- kBytes.emplace_back(reg_index);
- ++found_some;
-
- if (kVerbose) {
- kStdOut << "Assembler64x0: Register found: " << register_syntax << "\n";
- kStdOut << "Assembler64x0: Register amount in instruction: " << found_some << "\n";
- }
- }
- }
-
- // we're not in immediate addressing, reg to reg.
- if (opcode64x0.fFunct7 != kAsmImmediate) {
- // remember! register to register!
- if (found_some == 1) {
- Detail::print_error(
- "Too few registers.\ntip: each Assembler64x0 register "
- "starts with 'r'.\nline: " +
- line,
- file);
- throw std::runtime_error("not_a_register");
- }
- }
-
- if (found_some < 1 && name != "ldw" && name != "lda" && name != "stw") {
- Detail::print_error("invalid combination of opcode and registers.\nline: " + line,
- file);
- throw std::runtime_error("invalid_comb_op_reg");
- } else if (found_some == 1 && name == "add") {
- Detail::print_error("invalid combination of opcode and registers.\nline: " + line,
- file);
- throw std::runtime_error("invalid_comb_op_reg");
- } else if (found_some == 1 && name == "sub") {
- Detail::print_error("invalid combination of opcode and registers.\nline: " + line,
- file);
- throw std::runtime_error("invalid_comb_op_reg");
- }
-
- if (found_some > 0 && name == "pop") {
- Detail::print_error(
- "invalid combination for opcode 'pop'.\ntip: it expects "
- "nothing.\nline: " +
- line,
- file);
- throw std::runtime_error("invalid_comb_op_pop");
- }
- }
- default:
- break;
- }
-
- // try to fetch a number from the name
- if (name == "stw" || name == "ldw" || name == "lda" || name == "sta") {
- auto where_string = name;
-
- // if we load something, we'd need it's symbol/literal
- if (name == "stw" || name == "sta" || name == "ldw" || name == "lda" || name == "sta")
- where_string = ",";
-
- jump_label = line;
-
- auto found_sym = false;
-
- while (jump_label.find(where_string) != std::string::npos) {
- jump_label = jump_label.substr(jump_label.find(where_string) + where_string.size());
-
- while (jump_label.find(" ") != std::string::npos) {
- jump_label.erase(jump_label.find(" "), 1);
- }
-
- if (jump_label[0] != kAsmRegisterPrefix[0] && !isdigit(jump_label[1])) {
- if (found_sym) {
- Detail::print_error(
- "invalid combination of opcode and operands.\nhere -> " + jump_label, file);
- throw std::runtime_error("invalid_comb_op_ops");
- } else {
- // death trap installed.
- found_sym = true;
- }
- }
- }
-
- cpy_jump_label = jump_label;
-
- // replace any spaces with $
- if (jump_label[0] == ' ') {
- while (jump_label.find(' ') != std::string::npos) {
- if (isalnum(jump_label[0]) || isdigit(jump_label[0])) break;
-
- jump_label.erase(jump_label.find(' '), 1);
- }
- }
-
- if (!this->WriteNumber(0, jump_label)) {
- // sta expects this: sta 0x000000, r0
- if (name == "sta") {
- Detail::print_error("invalid combination of opcode and operands.\nHere ->" + line,
- file);
- throw std::runtime_error("invalid_comb_op_ops");
- }
- } else {
- if (name == "sta" && cpy_jump_label.find("extern_segment ") != std::string::npos) {
- Detail::print_error("invalid usage extern_segment on 'sta', here: " + line, file);
- throw std::runtime_error("invalid_sta_usage");
- }
- }
-
- goto asm_write_label;
- }
-
- // This is the case where we jump to a label, it is also used as a goto.
- if (name == "lda" || name == "sta") {
- asm_write_label:
- if (cpy_jump_label.find('\n') != std::string::npos)
- cpy_jump_label.erase(cpy_jump_label.find('\n'), 1);
-
- if (cpy_jump_label.find("extern_segment") != std::string::npos) {
- cpy_jump_label.erase(cpy_jump_label.find("extern_segment"), strlen("extern_segment"));
-
- if (name == "sta") {
- Detail::print_error("extern_segment is not allowed on a sta operation.", file);
- throw std::runtime_error("extern_segment_sta_op");
- } else {
- goto asm_end_label_cpy;
- }
- }
-
- if (name == "lda" || name == "sta") {
- for (auto& label : kOriginLabel) {
- if (cpy_jump_label == label.first) {
- if (kVerbose) {
- kStdOut << "Assembler64x0: Replace label " << cpy_jump_label
- << " to address: " << label.second << std::endl;
- }
-
- CompilerKit::NumberCast64 num(label.second);
-
- for (auto& num : num.number) {
- kBytes.push_back(num);
- }
-
- goto asm_end_label_cpy;
- }
- }
-
- if (cpy_jump_label[0] == '0') {
- switch (cpy_jump_label[1]) {
- case 'x':
- case 'o':
- case 'b':
- if (this->WriteNumber(0, cpy_jump_label)) goto asm_end_label_cpy;
-
- break;
- default:
- break;
- }
-
- if (isdigit(cpy_jump_label[0])) {
- if (this->WriteNumber(0, cpy_jump_label)) goto asm_end_label_cpy;
-
- break;
- }
- }
- }
-
- if (cpy_jump_label.size() < 1) {
- Detail::print_error("label is empty, can't jump on it.", file);
- throw std::runtime_error("label_empty");
- }
-
- /// don't go any further if:
- /// load word (ldw) or store word. (stw)
-
- if (name == "ldw" || name == "stw") break;
-
- auto mld_reloc_str = std::to_string(cpy_jump_label.size());
- mld_reloc_str += kUndefinedSymbol;
- mld_reloc_str += cpy_jump_label;
-
- bool ignore_back_slash = false;
-
- for (auto& reloc_chr : mld_reloc_str) {
- if (reloc_chr == '\\') {
- ignore_back_slash = true;
- continue;
- }
-
- if (ignore_back_slash) {
- ignore_back_slash = false;
- continue;
- }
-
- kBytes.push_back(reloc_chr);
- }
-
- kBytes.push_back('\0');
- goto asm_end_label_cpy;
- }
-
- asm_end_label_cpy:
- kOrigin += k64x0IPAlignment;
-
- break;
- }
- }
-
- return true;
-}
-
-// Last rev 13-1-24
diff --git a/dev/CompilerKit/src/Backend/AssemblerAMD64.cc b/dev/CompilerKit/src/Backend/AssemblerAMD64.cc
deleted file mode 100644
index 8c7e21c..0000000
--- a/dev/CompilerKit/src/Backend/AssemblerAMD64.cc
+++ /dev/null
@@ -1,1204 +0,0 @@
-/* ========================================
-
- Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license
-
-======================================== */
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-/// @file AssemblerAMD64.cc
-/// @author Amlal El Mahrouss
-/// @brief AMD64 Assembler.
-/// REMINDER: when dealing with an undefined symbol use (string
-/// size):LinkerFindSymbol:(string) so that ld will look for it.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-/// bugs: 0
-
-/// feature request: 1
-/// Encode registers in mov, add, xor...
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#ifndef __ASM_NEED_AMD64__
-#define __ASM_NEED_AMD64__ 1
-#endif
-
-#define kAssemblerPragmaSymStr "%%"
-#define kAssemblerPragmaSym '%'
-
-#include <CompilerKit/AE.h>
-#include <CompilerKit/Frontend.h>
-#include <CompilerKit/PEF.h>
-#include <CompilerKit/impl/X64.h>
-#include <algorithm>
-#include <cstdlib>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <vector>
-
-/////////////////////
-
-// ANSI ESCAPE CODES
-
-/////////////////////
-
-#define kBlank "\e[0;30m"
-#define kRed "\e[0;31m"
-#define kWhite "\e[0;97m"
-#define kYellow "\e[0;33m"
-
-static char kOutputArch = CompilerKit::kPefArchAMD64;
-
-static constexpr auto kIPAlignement = 0x1U;
-static auto kCounter = 0x1UL;
-
-static std::uintptr_t kOrigin = kPefBaseOrigin;
-static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel;
-
-/// @brief keep it simple by default.
-static std::int32_t kRegisterBitWidth = 16U;
-
-static std::vector<i64_byte_t> kAppBytes;
-
-static CompilerKit::AERecordHeader kCurrentRecord{
- .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0};
-
-static std::vector<CompilerKit::AERecordHeader> kRecords;
-static std::vector<std::string> kDefinedSymbols;
-static std::vector<std::string> kUndefinedSymbols;
-
-static const std::string kUndefinedSymbol = ":UndefinedSymbol:";
-
-// \brief forward decl.
-static bool asm_read_attributes(std::string line);
-
-#include <CompilerKit/utils/AsmUtils.h>
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief AMD64 assembler entrypoint, the program/module starts here.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-NECTI_MODULE(AssemblerMainAMD64) {
- //////////////// CPU OPCODES BEGIN ////////////////
-
- CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler);
-
- 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<i64_hword_t>(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], "--amd64:ver") == 0 || strcmp(argv[i], "--amd64:v") == 0) {
- kStdOut << "AssemblerAMD64: AMD64 Assembler Driver.\nAssemblerAMD64: "
- "v1.10\nAssemblerAMD64: Copyright "
- "(c) Amlal El Mahrouss\n";
- return 0;
- } else if (strcmp(argv[i], "--amd64:h") == 0) {
- kStdOut << "AssemblerAMD64: AMD64 Assembler Driver.\nAssemblerAMD64: Copyright (c) 2024 "
- "Amlal El Mahrouss\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], "--amd64:binary") == 0) {
- kOutputAsBinary = true;
- continue;
- } else if (strcmp(argv[i], "--amd64:verbose") == 0) {
- kVerbose = true;
- continue;
- }
-
- kStdOut << "AssemblerAMD64: ignore " << argv[i] << "\n";
- continue;
- }
-
- if (!std::filesystem::exists(argv[i])) {
- kStdOut << "AssemblerAMD64: can't open: " << argv[i] << std::endl;
- goto asm_fail_exit;
- }
-
- std::string object_output(argv[i]);
- std::string asm_input(argv[i]);
-
- for (auto& ext : kAsmFileExts) {
- if (object_output.ends_with(ext)) {
- object_output.erase(object_output.find(ext), std::strlen(ext));
- break;
- }
- }
-
- object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt;
-
- std::ifstream file_ptr(argv[i]);
- std::ofstream file_ptr_out(object_output, std::ofstream::binary);
-
- kStdOut << "AssemblerAMD64: Assembling: " << argv[i] << "\n";
-
- if (file_ptr_out.bad()) {
- if (kVerbose) {
- kStdOut << "AssemblerAMD64: error: " << strerror(errno) << "\n";
- }
-
- return 1;
- }
-
- std::string line;
-
- CompilerKit::AEHeader hdr{0};
-
- memset(hdr.fPad, kAENullType, kAEPad);
-
- hdr.fMagic[0] = kAEMag0;
- hdr.fMagic[1] = kAEMag1;
- hdr.fSize = sizeof(CompilerKit::AEHeader);
- hdr.fArch = kOutputArch;
-
- /////////////////////////////////////////////////////////////////////////////////////////
-
- // COMPILATION LOOP
-
- /////////////////////////////////////////////////////////////////////////////////////////
-
- CompilerKit::EncoderAMD64 asm64;
-
- if (kVerbose) {
- kStdOut << "Compiling: " + asm_input << "\n";
- kStdOut << "From: " + line << "\n";
- }
-
- 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, "CompilerKit");
- }
-
- try {
- std::filesystem::remove(object_output);
- } catch (...) {
- }
-
- goto asm_fail_exit;
- }
- }
-
- if (!kOutputAsBinary) {
- if (kVerbose) {
- kStdOut << "AssemblerAMD64: Writing object file...\n";
- }
-
- // this is the final step, write everything to the file.
-
- auto pos = file_ptr_out.tellp();
-
- hdr.fCount = kRecords.size() + kUndefinedSymbols.size();
-
- file_ptr_out << hdr;
-
- if (kRecords.empty()) {
- kStdErr << "AssemblerAMD64: At least one record is needed to write an object "
- "file.\nAssemblerAMD64: Make one using `public_segment .code64 foo_bar`.\n";
-
- std::filesystem::remove(object_output);
- return 1;
- }
-
- kRecords[kRecords.size() - 1].fSize = kAppBytes.size();
-
- std::size_t record_count = 0UL;
-
- for (auto& rec : kRecords) {
- if (kVerbose) kStdOut << "AssemblerAMD64: Wrote record " << rec.fName << " to file...\n";
-
- rec.fFlags |= CompilerKit::kKindRelocationAtRuntime;
- rec.fOffset = record_count;
- ++record_count;
-
- file_ptr_out << rec;
- }
-
- // increment once again, so that we won't lie about the kUndefinedSymbols.
- ++record_count;
-
- for (auto& sym : kUndefinedSymbols) {
- CompilerKit::AERecordHeader _record_hdr{0};
-
- if (kVerbose) kStdOut << "AssemblerAMD64: Wrote symbol " << sym << " to file...\n";
-
- _record_hdr.fKind = kAENullType;
- _record_hdr.fSize = sym.size();
- _record_hdr.fOffset = record_count;
-
- ++record_count;
-
- memset(_record_hdr.fPad, kAENullType, kAEPad);
- memcpy(_record_hdr.fName, sym.c_str(), sym.size());
-
- file_ptr_out << _record_hdr;
-
- ++kCounter;
- }
-
- auto pos_end = file_ptr_out.tellp();
-
- file_ptr_out.seekp(pos);
-
- hdr.fStartCode = pos_end;
- hdr.fCodeSize = kAppBytes.size();
-
- file_ptr_out << hdr;
-
- file_ptr_out.seekp(pos_end);
- } else {
- if (kVerbose) {
- kStdOut << "AssemblerAMD64: 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<const char*>(&byte)[0];
- }
-
- if (kVerbose) kStdOut << "AssemblerAMD64: Wrote file with program in it.\n";
-
- file_ptr_out.flush();
- file_ptr_out.close();
-
- if (kVerbose) kStdOut << "AssemblerAMD64: Exit succeeded.\n";
-
- return 0;
- }
-
-asm_fail_exit:
-
- if (kVerbose) kStdOut << "AssemblerAMD64: Exit failed.\n";
-
- return 1;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief Check for attributes
-// returns true if any was found.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-static bool asm_read_attributes(std::string line) {
- // extern_segment is the opposite of public_segment, it signals to the ld
- // that we need this symbol.
- if (CompilerKit::find_word(line, "extern_segment")) {
- if (kOutputAsBinary) {
- Detail::print_error("Invalid directive in flat binary mode.", "CompilerKit");
- throw std::runtime_error("invalid_extern_segment_bin");
- }
-
- auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1);
-
- if (name.size() == 0) {
- Detail::print_error("Invalid extern_segment", "power-as");
- throw std::runtime_error("invalid_extern_segment");
- }
-
- 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(kPefCode64) != std::string::npos) {
- // data is treated as code.
- kCurrentRecord.fKind = CompilerKit::kPefCode;
- } else if (name.find(kPefData64) != std::string::npos) {
- // no code will be executed from here.
- kCurrentRecord.fKind = CompilerKit::kPefData;
- } else if (name.find(kPefZero64) != 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, kAENullType, kAEPad);
-
- kRecords.emplace_back(kCurrentRecord);
-
- return true;
- }
- // public_segment is a special keyword used by AssemblerAMD64 to tell the AE output stage to
- // mark this section as a header. it currently supports .code64, .data64 and
- // .zero64.
- else if (CompilerKit::find_word(line, "public_segment")) {
- if (kOutputAsBinary) {
- Detail::print_error("Invalid directive in flat binary mode.", "CompilerKit");
- throw std::runtime_error("invalid_public_segment_bin");
- }
-
- auto name = line.substr(line.find("public_segment") + strlen("public_segment") + 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.", "CompilerKit");
- throw std::runtime_error("invalid_public_segment_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.
-
- 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, kAENullType, kAEPad);
-
- kRecords.emplace_back(kCurrentRecord);
-
- return true;
- }
-
- return false;
-}
-
-// \brief algorithms and helpers.
-
-namespace Detail::algorithm {
-// \brief authorize a brief set of characters.
-static inline bool is_not_valid(char c) {
- if ((isalpha(c) || isdigit(c)) ||
- ((c == ' ') || (c == '\t') || (c == ',') || (c == '(') || (c == ')') || (c == '"') ||
- (c == '*') || (c == '\'') || (c == '[') || (c == ']') || (c == '+') || (c == '_') ||
- (c == ':') || (c == '@') || (c == '.') || (c == '#') || (c == ';')))
- return false;
-
- return true;
-}
-
-bool is_valid_amd64(std::string str) {
- return std::find_if(str.begin(), str.end(), is_not_valid) == str.end();
-}
-} // namespace Detail::algorithm
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief Check for line (syntax check)
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-std::string CompilerKit::EncoderAMD64::CheckLine(std::string line, std::string file) {
- std::string err_str;
-
- if (line.empty() || CompilerKit::find_word(line, "extern_segment") ||
- CompilerKit::find_word(line, "public_segment") ||
- CompilerKit::find_word(line, kAssemblerPragmaSymStr) || CompilerKit::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_amd64(line)) {
- err_str = "Line contains non valid 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 (CompilerKit::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, "CompilerKit");
- 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 << "AssemblerAMD64: 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, "CompilerKit");
- throw std::runtime_error("invalid_bin");
- }
- }
-
- CompilerKit::NumberCast64 num =
- CompilerKit::NumberCast64(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
-
- if (kVerbose) {
- kStdOut << "AssemblerAMD64: 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, "CompilerKit");
- throw std::runtime_error("invalid_octal");
- }
- }
-
- CompilerKit::NumberCast64 num =
- CompilerKit::NumberCast64(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
-
- if (kVerbose) {
- kStdOut << "AssemblerAMD64: 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 << "AssemblerAMD64: 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 << "AssemblerAMD64: 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 << "AssemblerAMD64: 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 << "AssemblerAMD64: 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 << "AssemblerAMD64: 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, "CompilerKit");
- 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 << "AssemblerAMD64: 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, "CompilerKit");
- throw std::runtime_error("invalid_bin");
- }
- }
-
- CompilerKit::NumberCast16 num =
- CompilerKit::NumberCast16(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
-
- if (kVerbose) {
- kStdOut << "AssemblerAMD64: 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, "CompilerKit");
- throw std::runtime_error("invalid_octal");
- }
- }
-
- CompilerKit::NumberCast16 num =
- CompilerKit::NumberCast16(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
-
- if (kVerbose) {
- kStdOut << "AssemblerAMD64: 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 << "AssemblerAMD64: 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, "CompilerKit");
- 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 << "AssemblerAMD64: 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, "CompilerKit");
- throw std::runtime_error("invalid_bin");
- }
- }
-
- CompilerKit::NumberCast8 num =
- CompilerKit::NumberCast8(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
-
- if (kVerbose) {
- kStdOut << "AssemblerAMD64: 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, "CompilerKit");
- throw std::runtime_error("invalid_octal");
- }
- }
-
- CompilerKit::NumberCast8 num =
- CompilerKit::NumberCast8(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
-
- if (kVerbose) {
- kStdOut << "AssemblerAMD64: 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 << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) << "\n";
- }
-
- return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief Read and write an instruction to the output array.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-bool CompilerKit::EncoderAMD64::WriteLine(std::string line, std::string file) {
- if (CompilerKit::find_word(line, "public_segment ")) return true;
-
- struct RegMapAMD64 {
- CompilerKit::STLString fName;
- i64_byte_t fModRM;
- };
-
- std::vector<RegMapAMD64> kRegisterList{
- {.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},
- };
-
- Bool foundInstruction = false;
-
- for (auto& opcodeAMD64 : kOpcodesAMD64) {
- // strict check here
- if (CompilerKit::find_word(line, opcodeAMD64.fName) &&
- Detail::algorithm::is_valid_amd64(line)) {
- foundInstruction = true;
- std::string name(opcodeAMD64.fName);
-
- /// Move instruction handler.
- if (line.find(name) != std::string::npos) {
- if (name == "mov" || name == "xor") {
- 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: missing right operand.", "CompilerKit");
- throw std::runtime_error("syntax_err");
- }
-
- bool onlyOneReg = true;
-
- std::vector<RegMapAMD64> currentRegList;
-
- for (auto& reg : kRegisterList) {
- std::vector<char> 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 (name == "mov") {
- if (bits == 64 || bits == 32) {
- if (!hasRBasedRegs && bits >= 32) {
- kAppBytes.emplace_back(opcodeAMD64.fOpcode);
- }
-
- if (!onlyOneReg) kAppBytes.emplace_back(0x89);
- } else if (bits == 16) {
- if (hasRBasedRegs) {
- Detail::print_error("Invalid combination of operands and registers.",
- "CompilerKit");
- throw std::runtime_error("comb_op_reg");
- } else {
- kAppBytes.emplace_back(0x66);
- kAppBytes.emplace_back(0x89);
- }
- }
- } else {
- if (!hasRBasedRegs && bits >= 32) {
- kAppBytes.emplace_back(opcodeAMD64.fOpcode);
- }
-
- kAppBytes.emplace_back(0x31);
- }
-
- if (onlyOneReg) {
- auto num = GetNumber32(line, ",");
-
- for (auto& num_idx : num.number) {
- if (num_idx == 0) num_idx = 0xFF;
- }
-
- auto modrm = (0x3 << 6 | currentRegList[0].fModRM);
-
- kAppBytes.emplace_back(0xC7); // prefixed before placing the modrm and then the number.
- kAppBytes.emplace_back(modrm);
-
- if (name != "xor") {
- kAppBytes.emplace_back(num.number[0]);
- kAppBytes.emplace_back(num.number[1]);
- kAppBytes.emplace_back(num.number[2]);
- kAppBytes.emplace_back(num.number[3]);
- }
-
- break;
- }
-
- if (currentRegList[1].fName[0] == 'r' && currentRegList[0].fName[0] == 'e') {
- Detail::print_error("Invalid combination of operands and registers.", "CompilerKit");
- 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.", "CompilerKit");
- 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.", "CompilerKit");
- 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.", "CompilerKit");
- 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.", "CompilerKit");
- 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.", "CompilerKit");
- 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;
- }
- }
-
- 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 if (name == "syscall") {
- kAppBytes.emplace_back(opcodeAMD64.fOpcode);
- kAppBytes.emplace_back(0x05);
-
- break;
- } else {
- kAppBytes.emplace_back(opcodeAMD64.fOpcode);
-
- break;
- }
- }
- }
-
- if (line[0] == kAssemblerPragmaSym) {
- if (foundInstruction) {
- Detail::print_error("Syntax error: " + line, file);
- 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 << "AssemblerAMD64: 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 += kIPAlignement;
-
- return true;
-}
-
-// Last rev 13-1-24
diff --git a/dev/CompilerKit/src/Backend/AssemblerARM64.cc b/dev/CompilerKit/src/Backend/AssemblerARM64.cc
deleted file mode 100644
index 4961e61..0000000
--- a/dev/CompilerKit/src/Backend/AssemblerARM64.cc
+++ /dev/null
@@ -1,587 +0,0 @@
-/* ========================================
-
- Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license
-
-======================================== */
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-/// @file AssemblerARM64.cc
-/// @author Amlal El Mahrouss
-/// @brief 'ACORN' Assembler.
-
-/// REMINDER: when dealing with an undefined symbol use (string
-/// size):LinkerFindSymbol:(string) so that li will look for it.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#ifndef __ASM_NEED_ARM64__
-#define __ASM_NEED_ARM64__ 1
-#endif
-
-#include <CompilerKit/AE.h>
-#include <CompilerKit/ErrorID.h>
-#include <CompilerKit/Frontend.h>
-#include <CompilerKit/PEF.h>
-#include <CompilerKit/Version.h>
-#include <CompilerKit/impl/Aarch64.h>
-#include <CompilerKit/utils/AsmUtils.h>
-#include <algorithm>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <vector>
-
-/////////////////////
-
-// ANSI ESCAPE CODES
-
-/////////////////////
-
-#define kBlank "\e[0;30m"
-#define kRed "\e[0;31m"
-#define kWhite "\e[0;97m"
-#define kYellow "\e[0;33m"
-
-constexpr auto cPowerIPAlignment = 0x1U;
-
-static Char kOutputArch = CompilerKit::kPefArchARM64;
-
-static std::size_t kCounter = 1UL;
-
-static std::uintptr_t kOrigin = kPefBaseOrigin;
-static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel;
-
-static std::vector<uint8_t> kBytes;
-
-static CompilerKit::AERecordHeader kCurrentRecord{
- .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0};
-
-static std::vector<CompilerKit::AERecordHeader> kRecords;
-static std::vector<std::string> kUndefinedSymbols;
-
-static const std::string kUndefinedSymbol = ":UndefinedSymbol:";
-static const std::string kRelocSymbol = ":RuntimeSymbol:";
-
-// \brief forward decl.
-static bool asm_read_attributes(std::string line);
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-/// @brief POWER assembler entrypoint, the program/module starts here.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-NECTI_MODULE(AssemblerMainARM64) {
- CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler);
-
- for (size_t i = 1; i < argc; ++i) {
- if (argv[i][0] == '-') {
- if (strcmp(argv[i], "--ver") == 0 || strcmp(argv[i], "--v") == 0) {
- kStdOut << "AssemblerPower: AARCH64 Assembler Driver.\nAssemblerPower: " << kDistVersion
- << "\nAssemblerPower: "
- "Copyright (c) "
- "Amlal El Mahrouss\n";
- return 0;
- } else if (strcmp(argv[i], "--h") == 0) {
- kStdOut << "AssemblerPower: AARCH64 Assembler Driver.\nAssemblerPower: Copyright (c) 2024 "
- "Amlal El Mahrouss\n";
- kStdOut << "--version,/v: 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 << "AssemblerPower: ignore " << argv[i] << "\n";
- continue;
- }
-
- if (!std::filesystem::exists(argv[i])) {
- kStdOut << "AssemblerPower: 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 << "AssemblerPower: error: " << strerror(errno) << "\n";
- }
- }
-
- std::string line;
-
- CompilerKit::AEHeader hdr{0};
-
- memset(hdr.fPad, kAENullType, kAEPad);
-
- hdr.fMagic[0] = kAEMag0;
- hdr.fMagic[1] = kAEMag1;
- hdr.fSize = sizeof(CompilerKit::AEHeader);
- hdr.fArch = kOutputArch;
-
- /////////////////////////////////////////////////////////////////////////////////////////
-
- // COMPILATION LOOP
-
- /////////////////////////////////////////////////////////////////////////////////////////
-
- CompilerKit::EncoderARM64 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, "CompilerKit");
- }
-
- std::filesystem::remove(object_output);
- goto asm_fail_exit;
- }
- }
-
- if (!kOutputAsBinary) {
- if (kVerbose) {
- kStdOut << "AssemblerARM64: Writing object file...\n";
- }
-
- // this is the final step, write everything to the file.
-
- auto pos = file_ptr_out.tellp();
-
- hdr.fCount = kRecords.size() + kUndefinedSymbols.size();
-
- file_ptr_out << hdr;
-
- if (kRecords.empty()) {
- kStdErr << "AssemblerARM64: At least one record is needed to write an object "
- "file.\nAssemblerARM64: Make one using `public_segment .code64 foo_bar`.\n";
-
- std::filesystem::remove(object_output);
- return 1;
- }
-
- kRecords[kRecords.size() - 1].fSize = kBytes.size();
-
- std::size_t record_count = 0UL;
-
- for (auto& record_hdr : kRecords) {
- record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime;
- record_hdr.fOffset = record_count;
- ++record_count;
-
- file_ptr_out << record_hdr;
-
- if (kVerbose) kStdOut << "AssemblerARM64: 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 undefined_sym{0};
-
- if (kVerbose) kStdOut << "AssemblerARM64: Wrote symbol " << sym << " to file...\n";
-
- undefined_sym.fKind = kAENullType;
- undefined_sym.fSize = sym.size();
- undefined_sym.fOffset = record_count;
-
- ++record_count;
-
- memset(undefined_sym.fPad, kAENullType, kAEPad);
- memcpy(undefined_sym.fName, sym.c_str(), sym.size());
-
- file_ptr_out << undefined_sym;
-
- ++kCounter;
- }
-
- auto pos_end = file_ptr_out.tellp();
-
- file_ptr_out.seekp(pos);
-
- hdr.fStartCode = pos_end;
- hdr.fCodeSize = kBytes.size();
-
- file_ptr_out << hdr;
-
- file_ptr_out.seekp(pos_end);
- } else {
- if (kVerbose) {
- kStdOut << "AssemblerARM64: Write raw binary...\n";
- }
- }
-
- // byte from byte, we write this.
- for (auto& byte : kBytes) {
- file_ptr_out.write(reinterpret_cast<const char*>(&byte), sizeof(byte));
- }
-
- if (kVerbose) kStdOut << "AssemblerARM64: Wrote file with program in it.\n";
-
- file_ptr_out.flush();
- file_ptr_out.close();
-
- if (kVerbose) kStdOut << "AssemblerARM64: Exit succeeded.\n";
-
- return 0;
- }
-
-asm_fail_exit:
-
- if (kVerbose) kStdOut << "AssemblerARM64: Exit failed.\n";
-
- return NECTI_EXEC_ERROR;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief Check for attributes
-// returns true if any was found.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-static bool asm_read_attributes(std::string line) {
- // extern_segment is the opposite of public_segment, it signals to the li
- // that we need this symbol.
- if (CompilerKit::find_word(line, "extern_segment")) {
- if (kOutputAsBinary) {
- Detail::print_error("Invalid extern_segment directive in flat binary mode.", "CompilerKit");
- throw std::runtime_error("invalid_extern_segment_bin");
- }
-
- auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1);
-
- if (name.size() == 0) {
- Detail::print_error("Invalid extern_segment", "CompilerKit");
- throw std::runtime_error("invalid_extern_segment");
- }
-
- 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 li 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 = kBytes.size();
-
- memset(kCurrentRecord.fName, 0, kAESymbolLen);
- memcpy(kCurrentRecord.fName, result.c_str(), result.size());
-
- ++kCounter;
-
- memset(kCurrentRecord.fPad, kAENullType, kAEPad);
-
- kRecords.emplace_back(kCurrentRecord);
-
- return true;
- }
- // public_segment is a special keyword used by Assembler to tell the AE output stage to
- // mark this section as a header. it currently supports .code64, .data64.,
- // .zero64
- else if (CompilerKit::find_word(line, "public_segment")) {
- if (kOutputAsBinary) {
- Detail::print_error("Invalid public_segment directive in flat binary mode.", "CompilerKit");
- throw std::runtime_error("invalid_public_segment_bin");
- }
-
- auto name = line.substr(line.find("public_segment") + strlen("public_segment"));
-
- std::string name_copy = name;
-
- for (char& j : name) {
- if (j == ' ') j = '$';
- }
-
- 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.
-
- 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 li 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 = kBytes.size();
-
- memset(kCurrentRecord.fName, 0, kAESymbolLen);
- memcpy(kCurrentRecord.fName, name.c_str(), name.size());
-
- ++kCounter;
-
- memset(kCurrentRecord.fPad, kAENullType, kAEPad);
-
- kRecords.emplace_back(kCurrentRecord);
-
- return true;
- }
-
- 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 == '.'));
-}
-
-bool is_valid_arm64(std::string str) {
- return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end();
-}
-} // namespace Detail::algorithm
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief Check for line (syntax check)
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-std::string CompilerKit::EncoderARM64::CheckLine(std::string line, std::string file) {
- std::string err_str;
-
- if (line.empty() || CompilerKit::find_word(line, "extern_segment") ||
- CompilerKit::find_word(line, "public_segment") || line.find('#') != std::string::npos ||
- CompilerKit::find_word(line, ";")) {
- if (line.find('#') != std::string::npos) {
- line.erase(line.find('#'));
- } else if (line.find(';') != std::string::npos) {
- line.erase(line.find(';'));
- } else {
- /// does the line contains valid input?
- if (!Detail::algorithm::is_valid_arm64(line)) {
- err_str = "Line contains non alphanumeric characters.\nhere -> ";
- err_str += line;
- }
- }
-
- return err_str;
- }
-
- if (!Detail::algorithm::is_valid_arm64(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;
- }
- }
- }
-
- return err_str;
-}
-
-bool CompilerKit::EncoderARM64::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, "CompilerKit");
- throw std::runtime_error("invalid_hex");
- }
- }
-
- CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16));
-
- for (char& i : num.number) {
- kBytes.push_back(i);
- }
-
- if (kVerbose) {
- kStdOut << "AssemblerARM64: 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, "CompilerKit");
- throw std::runtime_error("invalid_bin");
- }
- }
-
- CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
-
- if (kVerbose) {
- kStdOut << "AssemblerARM64: found a base 2 number here: " << jump_label.substr(pos) << "\n";
- }
-
- for (char& i : num.number) {
- kBytes.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, "CompilerKit");
- throw std::runtime_error("invalid_octal");
- }
- }
-
- CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
-
- if (kVerbose) {
- kStdOut << "AssemblerARM64: found a base 8 number here: " << jump_label.substr(pos) << "\n";
- }
-
- for (char& i : num.number) {
- kBytes.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(strtol(jump_label.substr(pos).c_str(), nullptr, 10));
-
- for (char& i : num.number) {
- kBytes.push_back(i);
- }
-
- if (kVerbose) {
- kStdOut << "AssemblerARM64: found a base 10 number here: " << jump_label.substr(pos) << "\n";
- }
-
- return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-/// @brief Read and write an instruction to the output array.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-bool CompilerKit::EncoderARM64::WriteLine(std::string line, std::string file) {
- if (CompilerKit::find_word(line, "public_segment")) return false;
-
- if (!Detail::algorithm::is_valid_arm64(line)) return false;
-
- return true;
-}
-
-// Last rev 13-1-24
diff --git a/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc b/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc
deleted file mode 100644
index b4f14ea..0000000
--- a/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc
+++ /dev/null
@@ -1,911 +0,0 @@
-/* ========================================
-
- Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license
-
-======================================== */
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-/// @file AssemblerPower.cc
-/// @author Amlal El Mahrouss
-/// @brief POWER Assembler.
-
-/// REMINDER: when dealing with an undefined symbol use (string
-/// size):LinkerFindSymbol:(string) so that li will look for it.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#ifndef __ASM_NEED_PPC__
-#define __ASM_NEED_PPC__ 1
-#endif
-
-#include <CompilerKit/AE.h>
-#include <CompilerKit/ErrorID.h>
-#include <CompilerKit/Frontend.h>
-#include <CompilerKit/PEF.h>
-#include <CompilerKit/Version.h>
-#include <CompilerKit/impl/PowerPC.h>
-#include <CompilerKit/utils/AsmUtils.h>
-#include <algorithm>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <vector>
-
-/////////////////////
-
-// ANSI ESCAPE CODES
-
-/////////////////////
-
-#define kBlank "\e[0;30m"
-#define kRed "\e[0;31m"
-#define kWhite "\e[0;97m"
-#define kYellow "\e[0;33m"
-
-constexpr auto cPowerIPAlignment = 0x4U;
-
-static Char kOutputArch = CompilerKit::kPefArchPowerPC;
-
-static std::size_t kCounter = 1UL;
-
-static std::uintptr_t kOrigin = kPefBaseOrigin;
-static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel;
-
-static std::vector<uint8_t> kBytes;
-
-static CompilerKit::AERecordHeader kCurrentRecord{
- .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0};
-
-static std::vector<CompilerKit::AERecordHeader> kRecords;
-static std::vector<std::string> kUndefinedSymbols;
-
-static const std::string kUndefinedSymbol = ":UndefinedSymbol:";
-static const std::string kRelocSymbol = ":RuntimeSymbol:";
-
-// \brief forward decl.
-static bool asm_read_attributes(std::string line);
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-/// @brief POWER assembler entrypoint, the program/module starts here.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-NECTI_MODULE(AssemblerMainPower64) {
- CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler);
-
- for (size_t i = 1; i < argc; ++i) {
- if (argv[i][0] == '-') {
- if (strcmp(argv[i], "--ver") == 0 || strcmp(argv[i], "--v") == 0) {
- kStdOut << "AssemblerPower: POWER64 Assembler Driver.\nAssemblerPower: " << kDistVersion
- << "\nAssemblerPower: "
- "Copyright (c) "
- "Amlal El Mahrouss\n";
- return 0;
- } else if (strcmp(argv[i], "--h") == 0) {
- kStdOut << "AssemblerPower: POWER64 Assembler Driver.\nAssemblerPower: Copyright (c) 2024 "
- "Amlal El Mahrouss\n";
- kStdOut << "--version,/v: 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 << "AssemblerPower: ignore " << argv[i] << "\n";
- continue;
- }
-
- if (!std::filesystem::exists(argv[i])) {
- kStdOut << "AssemblerPower: 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 << "AssemblerPower: error: " << strerror(errno) << "\n";
- }
- }
-
- std::string line;
-
- CompilerKit::AEHeader hdr{0};
-
- memset(hdr.fPad, kAENullType, kAEPad);
-
- hdr.fMagic[0] = kAEMag0;
- hdr.fMagic[1] = kAEMag1;
- hdr.fSize = sizeof(CompilerKit::AEHeader);
- hdr.fArch = kOutputArch;
-
- /////////////////////////////////////////////////////////////////////////////////////////
-
- // COMPILATION LOOP
-
- /////////////////////////////////////////////////////////////////////////////////////////
-
- CompilerKit::EncoderPowerPC 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, "CompilerKit");
- }
-
- std::filesystem::remove(object_output);
- goto asm_fail_exit;
- }
- }
-
- if (!kOutputAsBinary) {
- if (kVerbose) {
- kStdOut << "AssemblerPower: Writing object file...\n";
- }
-
- // this is the final step, write everything to the file.
-
- auto pos = file_ptr_out.tellp();
-
- hdr.fCount = kRecords.size() + kUndefinedSymbols.size();
-
- file_ptr_out << hdr;
-
- if (kRecords.empty()) {
- kStdErr << "AssemblerPower: At least one record is needed to write an object "
- "file.\nAssemblerPower: Make one using `public_segment .code64 foo_bar`.\n";
-
- std::filesystem::remove(object_output);
- return 1;
- }
-
- kRecords[kRecords.size() - 1].fSize = kBytes.size();
-
- std::size_t record_count = 0UL;
-
- for (auto& record_hdr : kRecords) {
- record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime;
- record_hdr.fOffset = record_count;
- ++record_count;
-
- file_ptr_out << record_hdr;
-
- if (kVerbose) kStdOut << "AssemblerPower: 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 undefined_sym{0};
-
- if (kVerbose) kStdOut << "AssemblerPower: Wrote symbol " << sym << " to file...\n";
-
- undefined_sym.fKind = kAENullType;
- undefined_sym.fSize = sym.size();
- undefined_sym.fOffset = record_count;
-
- ++record_count;
-
- memset(undefined_sym.fPad, kAENullType, kAEPad);
- memcpy(undefined_sym.fName, sym.c_str(), sym.size());
-
- file_ptr_out << undefined_sym;
-
- ++kCounter;
- }
-
- auto pos_end = file_ptr_out.tellp();
-
- file_ptr_out.seekp(pos);
-
- hdr.fStartCode = pos_end;
- hdr.fCodeSize = kBytes.size();
-
- file_ptr_out << hdr;
-
- file_ptr_out.seekp(pos_end);
- } else {
- if (kVerbose) {
- kStdOut << "AssemblerPower: Write raw binary...\n";
- }
- }
-
- // byte from byte, we write this.
- for (auto& byte : kBytes) {
- file_ptr_out.write(reinterpret_cast<const char*>(&byte), sizeof(byte));
- }
-
- if (kVerbose) kStdOut << "AssemblerPower: Wrote file with program in it.\n";
-
- file_ptr_out.flush();
- file_ptr_out.close();
-
- if (kVerbose) kStdOut << "AssemblerPower: Exit succeeded.\n";
-
- return 0;
- }
-
-asm_fail_exit:
-
- if (kVerbose) kStdOut << "AssemblerPower: Exit failed.\n";
-
- return NECTI_EXEC_ERROR;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief Check for attributes
-// returns true if any was found.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-static bool asm_read_attributes(std::string line) {
- // extern_segment is the opposite of public_segment, it signals to the li
- // that we need this symbol.
- if (CompilerKit::find_word(line, "extern_segment")) {
- if (kOutputAsBinary) {
- Detail::print_error("Invalid extern_segment directive in flat binary mode.", "CompilerKit");
- throw std::runtime_error("invalid_extern_segment_bin");
- }
-
- auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1);
-
- if (name.size() == 0) {
- Detail::print_error("Invalid extern_segment", "CompilerKit");
- throw std::runtime_error("invalid_extern_segment");
- }
-
- 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 li 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 = kBytes.size();
-
- memset(kCurrentRecord.fName, 0, kAESymbolLen);
- memcpy(kCurrentRecord.fName, result.c_str(), result.size());
-
- ++kCounter;
-
- memset(kCurrentRecord.fPad, kAENullType, kAEPad);
-
- kRecords.emplace_back(kCurrentRecord);
-
- return true;
- }
- // public_segment is a special keyword used by AssemblerPower to tell the AE output stage to
- // mark this section as a header. it currently supports .code64, .data64.,
- // .zero64
- else if (CompilerKit::find_word(line, "public_segment")) {
- if (kOutputAsBinary) {
- Detail::print_error("Invalid public_segment directive in flat binary mode.", "CompilerKit");
- throw std::runtime_error("invalid_public_segment_bin");
- }
-
- auto name = line.substr(line.find("public_segment") + strlen("public_segment"));
-
- std::string name_copy = name;
-
- for (char& j : name) {
- if (j == ' ') j = '$';
- }
-
- 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.
-
- 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 li 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 = kBytes.size();
-
- memset(kCurrentRecord.fName, 0, kAESymbolLen);
- memcpy(kCurrentRecord.fName, name.c_str(), name.size());
-
- ++kCounter;
-
- memset(kCurrentRecord.fPad, kAENullType, kAEPad);
-
- kRecords.emplace_back(kCurrentRecord);
-
- return true;
- }
-
- 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 == '.'));
-}
-
-bool is_valid_power64(std::string str) {
- return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end();
-}
-} // namespace Detail::algorithm
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief Check for line (syntax check)
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-std::string CompilerKit::EncoderPowerPC::CheckLine(std::string line, std::string file) {
- std::string err_str;
-
- if (line.empty() || CompilerKit::find_word(line, "extern_segment") ||
- CompilerKit::find_word(line, "public_segment") || line.find('#') != std::string::npos ||
- CompilerKit::find_word(line, ";")) {
- if (line.find('#') != std::string::npos) {
- line.erase(line.find('#'));
- } else if (line.find(';') != std::string::npos) {
- line.erase(line.find(';'));
- } else {
- /// does the line contains valid input?
- if (!Detail::algorithm::is_valid_power64(line)) {
- err_str = "Line contains non alphanumeric characters.\nhere -> ";
- err_str += line;
- }
- }
-
- return err_str;
- }
-
- if (!Detail::algorithm::is_valid_power64(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;
- }
- }
- }
-
- // these do take an argument.
- std::vector<std::string> operands_inst = {"stw", "li"};
-
- // these don't.
- std::vector<std::string> filter_inst = {"blr", "bl", "sc"};
-
- for (auto& opcode_risc : kOpcodesPowerPC) {
- if (CompilerKit::find_word(line, opcode_risc.name)) {
- for (auto& op : operands_inst) {
- // if only the instruction was found.
- if (line == op) {
- err_str += "\nMalformed ";
- err_str += op;
- err_str += " instruction, here -> ";
- err_str += line;
- }
- }
-
- // if it is like that -> addr1, 0x0
- if (auto it = std::find(filter_inst.begin(), filter_inst.end(), opcode_risc.name);
- it == filter_inst.cend()) {
- if (CompilerKit::find_word(line, opcode_risc.name)) {
- if (!isspace(line[line.find(opcode_risc.name) + strlen(opcode_risc.name)])) {
- err_str += "\nMissing space between ";
- err_str += opcode_risc.name;
- err_str += " and operands.\nhere -> ";
- err_str += line;
- }
- }
- }
-
- return err_str;
- }
- }
-
- err_str += "Unrecognized instruction: " + line;
-
- return err_str;
-}
-
-bool CompilerKit::EncoderPowerPC::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, "CompilerKit");
- throw std::runtime_error("invalid_hex");
- }
- }
-
- CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16));
-
- for (char& i : num.number) {
- kBytes.push_back(i);
- }
-
- if (kVerbose) {
- kStdOut << "AssemblerPower: 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, "CompilerKit");
- throw std::runtime_error("invalid_bin");
- }
- }
-
- CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
-
- if (kVerbose) {
- kStdOut << "AssemblerPower: found a base 2 number here: " << jump_label.substr(pos) << "\n";
- }
-
- for (char& i : num.number) {
- kBytes.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, "CompilerKit");
- throw std::runtime_error("invalid_octal");
- }
- }
-
- CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
-
- if (kVerbose) {
- kStdOut << "AssemblerPower: found a base 8 number here: " << jump_label.substr(pos) << "\n";
- }
-
- for (char& i : num.number) {
- kBytes.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(strtol(jump_label.substr(pos).c_str(), nullptr, 10));
-
- for (char& i : num.number) {
- kBytes.push_back(i);
- }
-
- if (kVerbose) {
- kStdOut << "AssemblerPower: found a base 10 number here: " << jump_label.substr(pos) << "\n";
- }
-
- return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-/// @brief Read and write an instruction to the output array.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-bool CompilerKit::EncoderPowerPC::WriteLine(std::string line, std::string file) {
- if (CompilerKit::find_word(line, "public_segment")) return false;
- if (!Detail::algorithm::is_valid_power64(line)) return false;
-
- for (auto& opcode_risc : kOpcodesPowerPC) {
- // strict check here
- if (CompilerKit::find_word(line, opcode_risc.name)) {
- std::string name(opcode_risc.name);
- std::string jump_label, cpy_jump_label;
- std::vector<size_t> found_registers_index;
-
- // check funct7 type.
- switch (opcode_risc.ops->type) {
- default: {
- NumberCast32 num(opcode_risc.opcode);
-
- for (auto ch : num.number) {
- kBytes.emplace_back(ch);
- }
- break;
- }
- case BADDR:
- case PCREL: {
- auto num = GetNumber32(line, name);
-
- kBytes.emplace_back(num.number[0]);
- kBytes.emplace_back(num.number[1]);
- kBytes.emplace_back(num.number[2]);
- kBytes.emplace_back(0x48);
-
- break;
- }
- /// General purpose, float, vector operations. Everything that involve
- /// registers.
- case G0REG:
- case FREG:
- case VREG:
- case GREG: {
- // \brief how many registers we found.
- std::size_t found_some_count = 0UL;
- std::size_t register_count = 0UL;
- std::string opcodeName = opcode_risc.name;
- std::size_t register_sum = 0;
-
- NumberCast64 num(opcode_risc.opcode);
-
- for (size_t line_index = 0UL; line_index < line.size(); line_index++) {
- if (line[line_index] == kAsmRegisterPrefix[0] && isdigit(line[line_index + 1])) {
- std::string register_syntax = kAsmRegisterPrefix;
- register_syntax += line[line_index + 1];
-
- if (isdigit(line[line_index + 2])) register_syntax += line[line_index + 2];
-
- std::string reg_str;
- reg_str += line[line_index + 1];
-
- if (isdigit(line[line_index + 2])) reg_str += line[line_index + 2];
-
- // it ranges from r0 to r19
- // something like r190 doesn't exist in the instruction set.
- if (isdigit(line[line_index + 3]) && isdigit(line[line_index + 2])) {
- reg_str += line[line_index + 3];
- Detail::print_error("invalid register index, r" + reg_str +
- "\nnote: The POWER accepts registers from r0 to r32.",
- file);
- throw std::runtime_error("invalid_register_index");
- }
-
- // finally cast to a size_t
- std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10);
-
- if (reg_index > kAsmRegisterLimit) {
- Detail::print_error("invalid register index, r" + reg_str, file);
- throw std::runtime_error("invalid_register_index");
- }
-
- if (opcodeName == "li") {
- char numIndex = 0;
-
- for (size_t i = 0; i != reg_index; i++) {
- numIndex += 0x20;
- }
-
- auto num = GetNumber32(line, reg_str);
-
- kBytes.push_back(num.number[0]);
- kBytes.push_back(num.number[1]);
- kBytes.push_back(numIndex);
- kBytes.push_back(0x38);
-
- // check if bigger than two.
- for (size_t i = 2; i < 4; i++) {
- if (num.number[i] > 0) {
- Detail::print_warning("number overflow on li operation.", file);
- break;
- }
- }
-
- break;
- }
-
- if ((opcodeName[0] == 's' && opcodeName[1] == 't')) {
- if (register_sum == 0) {
- for (size_t indexReg = 0UL; indexReg < reg_index; ++indexReg) {
- register_sum += 0x20;
- }
- } else {
- register_sum += reg_index;
- }
- }
-
- if (opcodeName == "mr") {
- switch (register_count) {
- case 0: {
- kBytes.push_back(0x78);
-
- char numIndex = 0x3;
-
- for (size_t i = 0; i != reg_index; i++) {
- numIndex += 0x8;
- }
-
- kBytes.push_back(numIndex);
-
- break;
- }
- case 1: {
- char numIndex = 0x1;
-
- for (size_t i = 0; i != reg_index; i++) {
- numIndex += 0x20;
- }
-
- for (size_t i = 0; i != reg_index; i++) {
- kBytes[kBytes.size() - 1] += 0x8;
- }
-
- kBytes[kBytes.size() - 1] -= 0x8;
-
- kBytes.push_back(numIndex);
-
- if (reg_index >= 10 && reg_index < 20)
- kBytes.push_back(0x7d);
- else if (reg_index >= 20 && reg_index < 30)
- kBytes.push_back(0x7e);
- else if (reg_index >= 30)
- kBytes.push_back(0x7f);
- else
- kBytes.push_back(0x7c);
-
- break;
- }
- default:
- break;
- }
-
- ++register_count;
- ++found_some_count;
- }
-
- if (opcodeName == "addi") {
- if (found_some_count == 2 || found_some_count == 0)
- kBytes.emplace_back(reg_index);
- else if (found_some_count == 1)
- kBytes.emplace_back(0x00);
-
- ++found_some_count;
-
- if (found_some_count > 3) {
- Detail::print_error("Too much registers. -> " + line, file);
- throw std::runtime_error("too_much_regs");
- }
- }
-
- if (opcodeName.find("cmp") != std::string::npos) {
- ++found_some_count;
-
- if (found_some_count > 3) {
- Detail::print_error("Too much registers. -> " + line, file);
- throw std::runtime_error("too_much_regs");
- }
- }
-
- if (opcodeName.find("mf") != std::string::npos ||
- opcodeName.find("mt") != std::string::npos) {
- char numIndex = 0;
-
- for (size_t i = 0; i != reg_index; i++) {
- numIndex += 0x20;
- }
-
- num.number[2] += numIndex;
-
- ++found_some_count;
-
- if (found_some_count > 1) {
- Detail::print_error("Too much registers. -> " + line, file);
- throw std::runtime_error("too_much_regs");
- }
-
- if (kVerbose) {
- kStdOut << "AssemblerPower: Found register: " << register_syntax << "\n";
- kStdOut << "AssemblerPower: Amount of registers in instruction: "
- << found_some_count << "\n";
- }
-
- if (reg_index >= 10 && reg_index < 20)
- num.number[3] = 0x7d;
- else if (reg_index >= 20 && reg_index < 30)
- num.number[3] = 0x7e;
- else if (reg_index >= 30)
- num.number[3] = 0x7f;
- else
- num.number[3] = 0x7c;
-
- for (auto ch : num.number) {
- kBytes.emplace_back(ch);
- }
- }
-
- found_registers_index.push_back(reg_index);
- }
- }
-
- if (opcodeName == "addi") {
- kBytes.emplace_back(0x38);
- }
-
- if (opcodeName.find("cmp") != std::string::npos) {
- char rightReg = 0x0;
-
- for (size_t i = 0; i != found_registers_index[1]; i++) {
- rightReg += 0x08;
- }
-
- kBytes.emplace_back(0x00);
- kBytes.emplace_back(rightReg);
- kBytes.emplace_back(found_registers_index[0]);
- kBytes.emplace_back(0x7c);
- }
-
- if ((opcodeName[0] == 's' && opcodeName[1] == 't')) {
- size_t offset = 0UL;
-
- if (line.find('+') != std::string::npos) {
- auto number = GetNumber32(line.substr(line.find("+")), "+");
- offset = number.raw;
- }
-
- kBytes.push_back(offset);
- kBytes.push_back(0x00);
- kBytes.push_back(register_sum);
-
- kBytes.emplace_back(0x90);
- }
-
- if (opcodeName == "mr") {
- if (register_count == 1) {
- Detail::print_error("Too few registers. -> " + line, file);
- throw std::runtime_error("too_few_registers");
- }
- }
-
- // we're not in immediate addressing, reg to reg.
- if (opcode_risc.ops->type != GREG) {
- // remember! register to register!
- if (found_some_count == 1) {
- Detail::print_error(
- "Unrecognized register found.\ntip: each AssemblerPower register "
- "starts with 'r'.\nline: " +
- line,
- file);
-
- throw std::runtime_error("not_a_register");
- }
- }
-
- if (found_some_count < 1 && name[0] != 'l' && name[0] != 's') {
- Detail::print_error("invalid combination of opcode and registers.\nline: " + line,
- file);
- throw std::runtime_error("invalid_comb_op_reg");
- }
-
- break;
- }
- }
-
- kOrigin += cPowerIPAlignment;
- break;
- }
- }
-
- return true;
-}
-
-// Last rev 13-1-24