summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal.elmahrouss@icloud.com>2024-01-27 22:08:08 +0100
committerAmlal El Mahrouss <amlal.elmahrouss@icloud.com>2024-01-27 22:08:08 +0100
commit5b49ce381c840a14b2e5a493d471bd2e378e5db6 (patch)
tree8478b62244d24e8507a08733bf65919b59e4ceb1
parentf37be20a2ac03d78faa30c1d1adcdd0dbd1f473e (diff)
Toolchain: Work in progress AMD64 support.
- We use the Mahrouss Logic x86 Standard: - Register is prefixed with 'r' and hols it's id. - Register Dest first, Source second, example: mov rd, rs - #code_<isa>_<features>, which will let select what instructions to use. Signed-off-by: Amlal El Mahrouss <amlal.elmahrouss@icloud.com>
-rw-r--r--Private/CompilerKit/AsmKit/Arch/32x0.hpp2
-rw-r--r--Private/CompilerKit/AsmKit/Arch/64x0.hpp50
-rw-r--r--Private/CompilerKit/AsmKit/Arch/amd64.hpp69
-rw-r--r--Private/CompilerKit/AsmKit/AsmKit.hpp18
l---------Private/External/AE.h (renamed from Private/External/ObjFormat.h)0
-rw-r--r--Private/Toolchain/.gitignore1
-rw-r--r--Private/Toolchain/64asm.cc25
-rw-r--r--Private/Toolchain/bin/Source/hello_amd64.masm510
-rw-r--r--Private/Toolchain/i64asm.cc875
-rw-r--r--Private/Toolchain/makefile4
10 files changed, 1517 insertions, 37 deletions
diff --git a/Private/CompilerKit/AsmKit/Arch/32x0.hpp b/Private/CompilerKit/AsmKit/Arch/32x0.hpp
index 28bf754..f9be82b 100644
--- a/Private/CompilerKit/AsmKit/Arch/32x0.hpp
+++ b/Private/CompilerKit/AsmKit/Arch/32x0.hpp
@@ -31,7 +31,7 @@
struct CpuCode32x0
{
- const char fName[16];
+ const char fName[32];
char fOpcode;
char fSize;
char fFunct3;
diff --git a/Private/CompilerKit/AsmKit/Arch/64x0.hpp b/Private/CompilerKit/AsmKit/Arch/64x0.hpp
index fde40fa..3052021 100644
--- a/Private/CompilerKit/AsmKit/Arch/64x0.hpp
+++ b/Private/CompilerKit/AsmKit/Arch/64x0.hpp
@@ -30,37 +30,37 @@ typedef uint8_t e64k_num_t;
struct CpuCode64x0
{
- const e64k_character_t fName[16];
+ const e64k_character_t fName[32];
e64k_num_t fOpcode;
e64k_num_t fFunct3;
e64k_num_t fFunct7;
};
inline std::vector<CpuCode64x0> kOpcodes64x0 = {
- kAsmOpcodeDecl("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation.
- kAsmOpcodeDecl("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation.
- kAsmOpcodeDecl("jlr", 0b1110011, 0b0000111, kAsmJump) // jump to linked return register
- kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111, kAsmJump) // jump from return register.
- kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg)
- kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg)
- kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg)
- kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg)
- kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg)
- kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg)
- kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg)
- kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate)
- kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate)
- kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate)
- kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate)
- // add/sub without carry flag
- kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate)
- kAsmOpcodeDecl("dec", 0b0101011, 0b101, kAsmImmediate)
- // add/sub with carry flag
- kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate)
- kAsmOpcodeDecl("decc", 0b0101011, 0b111, kAsmImmediate)
- kAsmOpcodeDecl("int", 0b1110011, 0b00, kAsmSyscall)
- kAsmOpcodeDecl("pha", 0b1110011, 0b00, kAsmNoArgs)
- kAsmOpcodeDecl("pla", 0b1110011, 0b01, kAsmNoArgs)
+ kAsmOpcodeDecl("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation.
+ kAsmOpcodeDecl("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation.
+ kAsmOpcodeDecl("jlr", 0b1110011, 0b0000111, kAsmJump) // jump to linked return register
+ kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111, kAsmJump) // jump from return register.
+ kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg)
+ kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg)
+ kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg)
+ kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg)
+ kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg)
+ kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg)
+ kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg)
+ kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate)
+ kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate)
+ kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate)
+ kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate)
+ // add/sub without carry flag
+ kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate)
+ kAsmOpcodeDecl("dec", 0b0101011, 0b101, kAsmImmediate)
+ // add/sub with carry flag
+ kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate)
+ kAsmOpcodeDecl("decc", 0b0101011, 0b111, kAsmImmediate)
+ kAsmOpcodeDecl("int", 0b1110011, 0b00, kAsmSyscall)
+ kAsmOpcodeDecl("pha", 0b1110011, 0b00, kAsmNoArgs)
+ kAsmOpcodeDecl("pla", 0b1110011, 0b01, kAsmNoArgs)
};
// \brief 64x0 register prefix
diff --git a/Private/CompilerKit/AsmKit/Arch/amd64.hpp b/Private/CompilerKit/AsmKit/Arch/amd64.hpp
new file mode 100644
index 0000000..78007b1
--- /dev/null
+++ b/Private/CompilerKit/AsmKit/Arch/amd64.hpp
@@ -0,0 +1,69 @@
+/*
+ * ========================================================
+ *
+ * MPCC
+ * Copyright 2024, Mahrouss Logic, all rights reserved.
+ *
+ * ========================================================
+ */
+
+#pragma once
+
+#include <CompilerKit/Defines.hpp>
+
+// @brief 64x0 support.
+// @file Arch/64x0.hpp
+
+#define kAsmOpcodeDecl(__NAME, __OPCODE) \
+ { .fName = __NAME, .fOpcode = __OPCODE },
+
+
+
+
+typedef char e64k_character_t;
+typedef uint8_t e64_byte_t;
+typedef uint16_t e64_hword_t;
+typedef uint32_t e64k_word_t;
+
+struct CpuCodeAMD64
+{
+ std::string fName;
+ e64_byte_t fPrefixBytes[4];
+ e64_hword_t fOpcode;
+ e64_hword_t fModReg;
+ e64k_word_t fDisplacment;
+ e64k_word_t fImmediate;
+};
+
+/// these two are edge cases
+#define kAsmIntOpcode 0xCC
+#define kasmIntOpcodeAlt 0xCD
+
+#define kAsmJumpOpcode 0x0F80
+#define kJumpLimit 30
+#define kJumpLimitStandard 0xE3
+#define kJumpLimitStandardLimit 0xEB
+
+inline std::vector<CpuCodeAMD64> kOpcodesAMD64 = {
+ kAsmOpcodeDecl("int", kAsmIntOpcode)
+ kAsmOpcodeDecl("int", kasmIntOpcodeAlt)
+ kAsmOpcodeDecl("into", 0xCE)
+ kAsmOpcodeDecl("iret", 0xCF)
+};
+
+// \brief 64x0 register prefix
+// example: r32, r0
+// r32 -> sp
+// r0 -> hw zero
+
+#define kAsmFloatZeroRegister -1
+#define kAsmZeroRegister -1
+
+#define kAsmRegisterPrefix "r"
+#define kAsmRegisterLimit 16
+#define kAsmPcRegister 8
+#define kAsmCrRegister -1
+#define kAsmSpRegister 9
+
+/* return address register */
+#define kAsmRetRegister 0
diff --git a/Private/CompilerKit/AsmKit/AsmKit.hpp b/Private/CompilerKit/AsmKit/AsmKit.hpp
index a159c05..e85b5d6 100644
--- a/Private/CompilerKit/AsmKit/AsmKit.hpp
+++ b/Private/CompilerKit/AsmKit/AsmKit.hpp
@@ -75,6 +75,24 @@ namespace CompilerKit
};
+#ifdef __ASM_NEED_AMD64__
+
+ class PlatformAssemblerAMD64 final : public PlatformAssembler
+ {
+ public:
+ explicit PlatformAssemblerAMD64() = default;
+ ~PlatformAssemblerAMD64() = default;
+
+ CXXKIT_COPY_DEFAULT(PlatformAssemblerAMD64);
+
+ virtual std::string CheckLine(std::string &line, const std::string &file) override;
+ virtual bool WriteLine(std::string &line, const std::string &file) override;
+ virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override;
+
+ };
+
+#endif // __ASM_NEED_AMD64__
+
#ifdef __ASM_NEED_64x0__
class PlatformAssembler64x0 final : public PlatformAssembler
diff --git a/Private/External/ObjFormat.h b/Private/External/AE.h
index 6781ba9..6781ba9 120000
--- a/Private/External/ObjFormat.h
+++ b/Private/External/AE.h
diff --git a/Private/Toolchain/.gitignore b/Private/Toolchain/.gitignore
index 323cdad..9e925a1 100644
--- a/Private/Toolchain/.gitignore
+++ b/Private/Toolchain/.gitignore
@@ -11,6 +11,7 @@ bin/mkcdfs
bin/ccplus
bin/cppfront
bin/bccl
+bin/i64asm
bin/Assembly.*
diff --git a/Private/Toolchain/64asm.cc b/Private/Toolchain/64asm.cc
index 4b9e25f..3bd0eda 100644
--- a/Private/Toolchain/64asm.cc
+++ b/Private/Toolchain/64asm.cc
@@ -307,13 +307,16 @@ MPCC_MODULE(MPUXAssembler64000)
}
// byte from byte, we write this.
- for (auto &byte : kBytes)
+ for (auto& byte : kBytes)
{
- file_ptr_out.write(reinterpret_cast<const char *>(&byte), sizeof(byte));
+ for (size_t i = 0; i < sizeof(byte); i++)
+ {
+ file_ptr_out << reinterpret_cast<const char*>(&byte)[i];
+ }
}
if (kVerbose)
- kStdOut << "64asm: Wrote file with program in it.";
+ kStdOut << "64asm: Wrote file with program in it.\n";
file_ptr_out.flush();
file_ptr_out.close();
@@ -347,7 +350,7 @@ static bool asm_read_attributes(std::string &line)
{
if (kOutputAsBinary)
{
- detail::print_error("invalid import directive in flat binary mode.", "64asm");
+ detail::print_error("Invalid import directive in flat binary mode.", "64asm");
throw std::runtime_error("invalid_import_bin");
}
@@ -412,7 +415,7 @@ static bool asm_read_attributes(std::string &line)
{
if (kOutputAsBinary)
{
- detail::print_error("invalid export directive in flat binary mode.", "64asm");
+ detail::print_error("Invalid export directive in flat binary mode.", "64asm");
throw std::runtime_error("invalid_export_bin");
}
@@ -550,7 +553,7 @@ std::string CompilerKit::PlatformAssembler64x0::CheckLine(std::string &line, con
{
if (line.find(',') + 1 == line.size())
{
- err_str += "\ninstruction lacks right register, here -> ";
+ err_str += "\nInstruction lacks right register, here -> ";
err_str += line.substr(line.find(','));
return err_str;
@@ -561,7 +564,7 @@ std::string CompilerKit::PlatformAssembler64x0::CheckLine(std::string &line, con
if (line.find(',') + 1 > line.size())
{
- err_str += "\ninstruction not complete, here -> ";
+ err_str += "\nInstruction not complete, here -> ";
err_str += line;
return err_str;
@@ -581,7 +584,7 @@ std::string CompilerKit::PlatformAssembler64x0::CheckLine(std::string &line, con
// this means we found nothing after that ',' .
if (nothing_on_right)
{
- err_str += "\ninstruction not complete, here -> ";
+ err_str += "\nInstruction not complete, here -> ";
err_str += line;
return err_str;
@@ -607,7 +610,7 @@ std::string CompilerKit::PlatformAssembler64x0::CheckLine(std::string &line, con
// if only the instruction was found.
if (line == op)
{
- err_str += "\nmalformed ";
+ err_str += "\nMalformed ";
err_str += op;
err_str += " instruction, here -> ";
err_str += line;
@@ -622,7 +625,7 @@ std::string CompilerKit::PlatformAssembler64x0::CheckLine(std::string &line, con
{
if (!isspace(line[line.find(opcode64x0.fName) + strlen(opcode64x0.fName)]))
{
- err_str += "\nmissing space between ";
+ err_str += "\nMissing space between ";
err_str += opcode64x0.fName;
err_str += " and operands.\nhere -> ";
err_str += line;
@@ -634,7 +637,7 @@ std::string CompilerKit::PlatformAssembler64x0::CheckLine(std::string &line, con
}
}
- err_str += "unrecognized instruction and operands: " + line;
+ err_str += "Unrecognized instruction and operands: " + line;
return err_str;
}
diff --git a/Private/Toolchain/bin/Source/hello_amd64.masm b/Private/Toolchain/bin/Source/hello_amd64.masm
new file mode 100644
index 0000000..4d3c349
--- /dev/null
+++ b/Private/Toolchain/bin/Source/hello_amd64.masm
@@ -0,0 +1,510 @@
+org 0x7c00
+
+nop
+
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+db 0x0
+
+db 0xAA
+db 0x55 \ No newline at end of file
diff --git a/Private/Toolchain/i64asm.cc b/Private/Toolchain/i64asm.cc
new file mode 100644
index 0000000..039cbfc
--- /dev/null
+++ b/Private/Toolchain/i64asm.cc
@@ -0,0 +1,875 @@
+/*
+ * ========================================================
+ *
+ * i64asm
+ * Copyright 2024, Mahrouss Logic, all rights reserved.
+ *
+ * ========================================================
+ */
+
+/// bugs: 0
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @file i64asm.cxx
+// @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.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define __ASM_NEED_AMD64__ 1
+
+#include <CompilerKit/AsmKit/Arch/amd64.hpp>
+#include <CompilerKit/ParserKit.hpp>
+#include <CompilerKit/StdKit/PEF.hpp>
+#include <CompilerKit/StdKit/AE.hpp>
+#include <filesystem>
+#include <iostream>
+#include <fstream>
+
+/////////////////////
+
+// ANSI ESCAPE CODES
+
+/////////////////////
+
+#define kBlank "\e[0;30m"
+#define kRed "\e[0;31m"
+#define kWhite "\e[0;97m"
+#define kYellow "\e[0;33m"
+
+#define kStdOut (std::cout << kWhite)
+#define kStdErr (std::cout << kRed)
+
+static char kOutputArch = CompilerKit::kPefArchAMD64;
+static Boolean kOutputAsBinary = false;
+
+static UInt32 kErrorLimit = 10;
+static UInt32 kAcceptableErrors = 0;
+
+static std::size_t kCounter = 1UL;
+
+static std::uintptr_t kOrigin = kPefBaseOrigin;
+static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel;
+
+static bool kVerbose = false;
+
+static std::vector<e64_byte_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 = ":ld:";
+static const std::string kRelocSymbol = ":mld:";
+
+// \brief forward decl.
+static bool asm_read_attributes(std::string &line);
+
+namespace detail
+{
+ void print_error(std::string reason, const std::string &file) noexcept
+ {
+ if (reason[0] == '\n')
+ reason.erase(0, 1);
+
+ kStdErr << kRed << "[ i64asm ] " << kWhite << ((file == "i64asm") ? "internal assembler error " : ("in file, " + file)) << kBlank << std::endl;
+ kStdErr << kRed << "[ i64asm ] " << kWhite << reason << kBlank << std::endl;
+
+ if (kAcceptableErrors > kErrorLimit)
+ std::exit(3);
+
+ ++kAcceptableErrors;
+ }
+
+ void print_warning(std::string reason, const std::string &file) noexcept
+ {
+ if (reason[0] == '\n')
+ reason.erase(0, 1);
+
+ if (!file.empty())
+ {
+ kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl;
+ }
+
+ kStdOut << kYellow << "[ i64asm ] " << kWhite << reason << kBlank << std::endl;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @brief AMD64 assembler entrypoint, the program/module starts here.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+MPCC_MODULE(MPUXAssemblerAMD64)
+{
+ //////////////// CPU OPCODES BEGIN ////////////////
+
+ std::string opcodes_jump[kJumpLimit] = {
+ "ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge",
+ "jl", "jle", "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge",
+ "jnl", "jnle", "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz"};
+
+ for (e64_hword_t i = 0; i < kJumpLimit; i++)
+ {
+ CpuCodeAMD64 code{.fName = opcodes_jump[i], .fOpcode = static_cast<e64_hword_t>(kAsmJumpOpcode + i)};
+ kOpcodesAMD64.push_back(code);
+ }
+
+ CpuCodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3};
+ kOpcodesAMD64.push_back(code);
+
+ for (e64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++)
+ {
+ CpuCodeAMD64 code{.fName = "jmp", .fOpcode = i};
+ kOpcodesAMD64.push_back(code);
+ }
+
+ CpuCodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F};
+ kOpcodesAMD64.push_back(lahf);
+
+ CpuCodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5};
+ kOpcodesAMD64.push_back(lds);
+
+ CpuCodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D};
+ kOpcodesAMD64.push_back(lea);
+
+ for (e64_hword_t i = 0xA0; i < 0xA3; i++)
+ {
+ CpuCodeAMD64 mov{.fName = "mov", .fOpcode = i};
+ kOpcodesAMD64.push_back(mov);
+ }
+
+ CpuCodeAMD64 mov{.fName = "nop", .fOpcode = 0x90};
+ kOpcodesAMD64.push_back(mov);
+
+ //////////////// CPU OPCODES END ////////////////
+
+ for (size_t i = 1; i < argc; ++i)
+ {
+ if (argv[i][0] == '-')
+ {
+ if (strcmp(argv[i], "-version") == 0 ||
+ strcmp(argv[i], "-v") == 0)
+ {
+ kStdOut << "i64asm: AMD64 Assembler.\ni64asm: v1.10\ni64asm: Copyright (c) 2024 Mahrouss Logic.\n";
+ return 0;
+ }
+ else if (strcmp(argv[i], "-h") == 0)
+ {
+ kStdOut << "i64asm: AMD64 Assembler.\ni64asm: 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], "-binary") == 0)
+ {
+ kOutputAsBinary = true;
+ continue;
+ }
+ else if (strcmp(argv[i], "-verbose") == 0)
+ {
+ kVerbose = true;
+ continue;
+ }
+
+ kStdOut << "i64asm: ignore " << argv[i] << "\n";
+ continue;
+ }
+
+ if (!std::filesystem::exists(argv[i]))
+ {
+ kStdOut << "i64asm: can't open: " << argv[i] << std::endl;
+ goto asm_fail_exit;
+ }
+
+ std::string object_output(argv[i]);
+
+ for (auto &ext : kAsmFileExts)
+ {
+ if (object_output.find(ext) != std::string::npos)
+ {
+ object_output.erase(object_output.find(ext), std::strlen(ext));
+ }
+ }
+
+ object_output += kObjectFileExt;
+
+ std::ifstream file_ptr(argv[i]);
+ std::ofstream file_ptr_out(object_output,
+ std::ofstream::binary);
+
+ if (file_ptr_out.bad())
+ {
+ if (kVerbose)
+ {
+ kStdOut << "i64asm: error: " << strerror(errno) << "\n";
+ }
+ }
+
+ std::string line;
+
+ CompilerKit::AEHeader hdr{0};
+
+ memset(hdr.fPad, kAEInvalidOpcode, kAEPad);
+
+ hdr.fMagic[0] = kAEMag0;
+ hdr.fMagic[1] = kAEMag1;
+ hdr.fSize = sizeof(CompilerKit::AEHeader);
+ hdr.fArch = kOutputArch;
+
+ /////////////////////////////////////////////////////////////////////////////////////////
+
+ // COMPILATION LOOP
+
+ /////////////////////////////////////////////////////////////////////////////////////////
+
+ CompilerKit::PlatformAssemblerAMD64 asm64;
+
+ while (std::getline(file_ptr, line))
+ {
+ if (auto ln = asm64.CheckLine(line, argv[i]);
+ !ln.empty())
+ {
+ detail::print_error(ln, argv[i]);
+ continue;
+ }
+
+ try
+ {
+ asm_read_attributes(line);
+ asm64.WriteLine(line, argv[i]);
+ }
+ catch (const std::exception &e)
+ {
+ if (kVerbose)
+ {
+ std::string what = e.what();
+ detail::print_warning("exit because of: " + what, "i64asm");
+ }
+
+ std::filesystem::remove(object_output);
+ goto asm_fail_exit;
+ }
+ }
+
+ if (!kOutputAsBinary)
+ {
+ if (kVerbose)
+ {
+ kStdOut << "i64asm: 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 << "i64asm: At least one record is needed to write an object file.\ni64asm: Make one using `export .text 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 << "i64asm: 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 << "i64asm: Wrote symbol " << sym << " to file...\n";
+
+ _record_hdr.fKind = kAEInvalidOpcode;
+ _record_hdr.fSize = sym.size();
+ _record_hdr.fOffset = record_count;
+
+ ++record_count;
+
+ memset(_record_hdr.fPad, kAEInvalidOpcode, 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 << "i64asm: Write raw binary...\n";
+ }
+ }
+
+ // byte from byte, we write this.
+ for (auto &byte : kBytes)
+ {
+ for (size_t i = 0; i < sizeof(byte); i++)
+ {
+ file_ptr_out << reinterpret_cast<const char *>(&byte)[i];
+ }
+ }
+
+ if (kVerbose)
+ kStdOut << "i64asm: Wrote file with program in it.\n";
+
+ file_ptr_out.flush();
+ file_ptr_out.close();
+
+ if (kVerbose)
+ kStdOut << "i64asm: Exit succeeded.\n";
+
+ return 0;
+ }
+
+asm_fail_exit:
+
+ if (kVerbose)
+ kStdOut << "i64asm: Exit failed.\n";
+
+ return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @brief Check for attributes
+// returns true if any was found.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static bool asm_read_attributes(std::string &line)
+{
+ // import is the opposite of export, it signals to the ld
+ // that we need this symbol.
+ if (ParserKit::find_word(line, "import "))
+ {
+ if (kOutputAsBinary)
+ {
+ detail::print_error("invalid import directive in flat binary mode.", "i64asm");
+ throw std::runtime_error("invalid_import_bin");
+ }
+
+ auto name = line.substr(line.find("import ") + strlen("import "));
+
+ std::string result = std::to_string(name.size());
+ result += kUndefinedSymbol;
+
+ // mangle this
+ for (char &j : name)
+ {
+ if (j == ' ' ||
+ j == ',')
+ j = '$';
+ }
+
+ result += name;
+
+ if (name.find(".text") != std::string::npos)
+ {
+ // data is treated as code.
+ kCurrentRecord.fKind = CompilerKit::kPefCode;
+ }
+ else if (name.find(".data") != std::string::npos)
+ {
+ // no code will be executed from here.
+ kCurrentRecord.fKind = CompilerKit::kPefData;
+ }
+ else if (name.find(".page_zero") != 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 == "__start")
+ {
+ 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, kAEInvalidOpcode, kAEPad);
+
+ kRecords.emplace_back(kCurrentRecord);
+
+ return true;
+ }
+ // export is a special keyword used by i64asm to tell the AE output stage to mark this section as a header.
+ // it currently supports .text, .data., page_zero
+ else if (ParserKit::find_word(line, "export "))
+ {
+ if (kOutputAsBinary)
+ {
+ detail::print_error("invalid export directive in flat binary mode.", "i64asm");
+ throw std::runtime_error("invalid_export_bin");
+ }
+
+ auto name = line.substr(line.find("export ") + strlen("export "));
+
+ std::string name_copy = name;
+
+ for (char &j : name)
+ {
+ if (j == ' ')
+ j = '$';
+ }
+
+ if (name.find(".text") != std::string::npos)
+ {
+ // data is treated as code.
+
+ name_copy.erase(name_copy.find(".text"), strlen(".text"));
+ kCurrentRecord.fKind = CompilerKit::kPefCode;
+ }
+ else if (name.find(".data") != std::string::npos)
+ {
+ // no code will be executed from here.
+
+ name_copy.erase(name_copy.find(".data"), strlen(".data"));
+ kCurrentRecord.fKind = CompilerKit::kPefData;
+ }
+ else if (name.find(".page_zero") != std::string::npos)
+ {
+ // this is a bss section.
+
+ name_copy.erase(name_copy.find(".page_zero"), strlen(".page_zero"));
+ kCurrentRecord.fKind = CompilerKit::kPefZero;
+ }
+
+ // this is a special case for the start stub.
+ // we want this so that ld can find it.
+
+ if (name == "__start")
+ {
+ 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, kAEInvalidOpcode, 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(const std::string &str)
+ {
+ return find_if(str.begin(), str.end(), is_not_alnum_space) == str.end();
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @brief Check for line (syntax check)
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+std::string CompilerKit::PlatformAssemblerAMD64::CheckLine(std::string &line, const std::string &file)
+{
+ std::string err_str;
+
+ if (line.empty() ||
+ ParserKit::find_word(line, "import") ||
+ ParserKit::find_word(line, "export") ||
+ ParserKit::find_word(line, "#") ||
+ ParserKit::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(line))
+ {
+ err_str = "Line contains non alphanumeric characters.\nhere -> ";
+ err_str += line;
+ }
+ }
+
+ return err_str;
+ }
+
+ if (!detail::algorithm::is_valid(line))
+ {
+ err_str = "Line contains non alphanumeric characters.\nhere -> ";
+ err_str += line;
+
+ return err_str;
+ }
+
+ // check for a valid instruction format.
+
+ if (line.find(',') != std::string::npos)
+ {
+ if (line.find(',') + 1 == line.size())
+ {
+ err_str += "\nInstruction lacks right register, here -> ";
+ err_str += line.substr(line.find(','));
+
+ return err_str;
+ }
+ else
+ {
+ bool nothing_on_right = true;
+
+ if (line.find(',') + 1 > line.size())
+ {
+ err_str += "\nInstruction not complete, here -> ";
+ err_str += line;
+
+ return err_str;
+ }
+
+ auto substr = line.substr(line.find(',') + 1);
+
+ for (auto &ch : substr)
+ {
+ if (ch != ' ' &&
+ ch != '\t')
+ {
+ nothing_on_right = false;
+ }
+ }
+
+ // this means we found nothing after that ',' .
+ if (nothing_on_right)
+ {
+ err_str += "\nInstruction not complete, here -> ";
+ err_str += line;
+
+ return err_str;
+ }
+ }
+ }
+
+ return err_str;
+}
+
+bool CompilerKit::PlatformAssemblerAMD64::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 = strtoq(jump_label.substr(pos + 2).c_str(),
+ nullptr, 16);
+ !res)
+ {
+ if (errno != 0)
+ {
+ detail::print_error("invalid hex number: " + jump_label, "i64asm");
+ throw std::runtime_error("invalid_hex");
+ }
+ }
+
+ CompilerKit::NumberCast num(strtoq(jump_label.substr(pos + 2).c_str(),
+ nullptr, 16));
+
+ for (char &i : num.number)
+ {
+ kBytes.push_back(i);
+ }
+
+ if (kVerbose)
+ {
+ kStdOut << "i64asm: found a base 16 number here: " << jump_label.substr(pos) << "\n";
+ }
+
+ return true;
+ }
+ case 'b':
+ {
+ if (auto res = strtoq(jump_label.substr(pos + 2).c_str(),
+ nullptr, 2);
+ !res)
+ {
+ if (errno != 0)
+ {
+ detail::print_error("invalid binary number: " + jump_label, "i64asm");
+ throw std::runtime_error("invalid_bin");
+ }
+ }
+
+ CompilerKit::NumberCast num(strtoq(jump_label.substr(pos + 2).c_str(),
+ nullptr, 2));
+
+ if (kVerbose)
+ {
+ kStdOut << "i64asm: found a base 2 number here: " << jump_label.substr(pos) << "\n";
+ }
+
+ for (char &i : num.number)
+ {
+ kBytes.push_back(i);
+ }
+
+ return true;
+ }
+ case 'o':
+ {
+ if (auto res = strtoq(jump_label.substr(pos + 2).c_str(),
+ nullptr, 7);
+ !res)
+ {
+ if (errno != 0)
+ {
+ detail::print_error("invalid octal number: " + jump_label, "i64asm");
+ throw std::runtime_error("invalid_octal");
+ }
+ }
+
+ CompilerKit::NumberCast num(strtoq(jump_label.substr(pos + 2).c_str(),
+ nullptr, 7));
+
+ if (kVerbose)
+ {
+ kStdOut << "i64asm: found a base 8 number here: " << jump_label.substr(pos) << "\n";
+ }
+
+ for (char &i : num.number)
+ {
+ kBytes.push_back(i);
+ }
+
+ return true;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ /* check for errno and stuff like that */
+ if (auto res = strtoq(jump_label.substr(pos).c_str(),
+ nullptr, 10);
+ !res)
+ {
+ if (errno != 0)
+ {
+ return false;
+ }
+ }
+
+ CompilerKit::NumberCast num(strtoq(jump_label.substr(pos).c_str(),
+ nullptr, 10));
+
+ for (char &i : num.number)
+ {
+ kBytes.push_back(i);
+ }
+
+ if (kVerbose)
+ {
+ kStdOut << "i64asm: 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::PlatformAssemblerAMD64::WriteLine(std::string &line, const std::string &file)
+{
+ if (ParserKit::find_word(line, "export "))
+ return true;
+
+ for (auto &opcodeAMD64 : kOpcodesAMD64)
+ {
+ // strict check here
+ if (ParserKit::find_word(line, opcodeAMD64.fName) &&
+ detail::algorithm::is_valid(line))
+ {
+ std::string name(opcodeAMD64.fName);
+
+ kBytes.emplace_back(opcodeAMD64.fOpcode);
+
+ if (name == "mov")
+ {
+ 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 = strtoq(
+ 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 << "64asm: Register found: " << register_syntax << "\n";
+ kStdOut << "64asm: Register amount in instruction: " << found_some << "\n";
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (line.find("db") != std::string::npos)
+ {
+ this->WriteNumber(line.find("db") + strlen("db") + 1, line);
+ }
+ 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 << "Origin: " << kOrigin << std::endl;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+// Last rev 13-1-24 \ No newline at end of file
diff --git a/Private/Toolchain/makefile b/Private/Toolchain/makefile
index e04a40b..8cbd608 100644
--- a/Private/Toolchain/makefile
+++ b/Private/Toolchain/makefile
@@ -31,6 +31,9 @@ CXX_OUTPUT=bin/ccplus
ASM_SRC=64asm.cc ../CompilerKit/StdKit/*.cc ../CompilerKit/AsmKit/*.cc
ASM_OUTPUT=bin/64asm
+IASM_SRC=i64asm.cc ../CompilerKit/StdKit/*.cc ../CompilerKit/AsmKit/*.cc
+IASM_OUTPUT=bin/i64asm
+
.PHONY: all
all: cl
@echo "[make] done build."
@@ -40,6 +43,7 @@ cl: ld
$(LINK_CC) $(COMMON_INC) $(PP_SRC) -o $(PP_OUTPUT)
$(LINK_CC) $(COMMON_INC) $(CC_SRC) -o $(CC_OUTPUT)
$(LINK_CC) $(COMMON_INC) $(CXX_SRC) -o $(CXX_OUTPUT)
+ $(LINK_CC) $(COMMON_INC) $(IASM_SRC) -o $(IASM_OUTPUT)
$(LINK_CC) $(COMMON_INC) $(ASM_SRC) -o $(ASM_OUTPUT)
.PHONY: ld