aboutsummaryrefslogtreecommitdiff
path: root/src/fasm/linker
diff options
context:
space:
mode:
authorA404M <ahmadmahmoudiprogrammer@gmail.com>2024-10-08 04:16:27 +0330
committerA404M <ahmadmahmoudiprogrammer@gmail.com>2024-10-08 04:17:08 +0330
commitaddd54dc31603dc204773d3108dba4e000cd7657 (patch)
tree621620c4ca5634680d7655e3474cf0b0bcec8e01 /src/fasm/linker
parentbf84010e01bb11874689ce53ea4df853b2e41c2b (diff)
added fasm support
added compiler options tried to compile to fasm first
Diffstat (limited to 'src/fasm/linker')
-rw-r--r--src/fasm/linker/linker.c870
-rw-r--r--src/fasm/linker/linker.h78
2 files changed, 948 insertions, 0 deletions
diff --git a/src/fasm/linker/linker.c b/src/fasm/linker/linker.c
new file mode 100644
index 0000000..faa3cd8
--- /dev/null
+++ b/src/fasm/linker/linker.c
@@ -0,0 +1,870 @@
+#include "linker.h"
+
+#include <compiler/error_helper/error_helper.h>
+#include <compiler/source_code/source_code.h>
+#include <fasm/lexer/lexer.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utils/memory/memory.h>
+
+void fasmVariablePrint(FasmVariable variable) {
+ printf(" {name='%.*s',value=0x%ld}\n", (int)(variable.end - variable.begin),
+ variable.begin, variable.value);
+}
+
+void fasmLinkedLinePrint(FasmLinkedLine line) {
+ printf(" {instruction='%s',operands=[\n",
+ FASM_TOKEN_STRINGS[line.instruction]);
+ for (size_t i = 0; i < line.operands_size; ++i) {
+ printf(" 0x%x,\n", line.operands[i]);
+ }
+ printf(" ]}\n");
+}
+
+void fasmLinkedLinesPrint(FasmLinkedLines lines) {
+ printf("{lines=[\n");
+ for (size_t i = 0; i < lines.lines_size; ++i) {
+ fasmLinkedLinePrint(lines.lines[i]);
+ }
+ printf("],\ndata=[\n");
+ for (size_t i = 0; i < lines.data_size; ++i) {
+ printf(" 0x%.2x,\n", lines.data[i]);
+ }
+ printf("],\nvariable=[\n");
+ for (size_t i = 0; i < lines.variables_size; ++i) {
+ fasmVariablePrint(lines.variables[i]);
+ }
+ printf("]}\n");
+}
+
+void fasmLinkedLineDeleteInner(FasmLinkedLine line) { free(line.operands); }
+
+void fasmLinkedLinesDeleteInner(FasmLinkedLines lines) {
+ for (size_t i = 0; i < lines.lines_size; ++i) {
+ fasmLinkedLineDeleteInner(lines.lines[i]);
+ }
+ free(lines.lines);
+ free(lines.variables);
+ free(lines.data);
+}
+
+FasmLinkedLines fasmLinker(const FasmLines *lines, SourceCode *sourceCode) {
+ FasmLinkedLines linkedLines = {
+ .lines = a404m_malloc(0),
+ .lines_size = 0,
+ .variables = a404m_malloc(0),
+ .variables_size = 0,
+ .data = a404m_malloc(0),
+ .data_size = 0,
+ };
+
+ fasmLinesSetVariables(&linkedLines, lines, sourceCode);
+ fasmLinesSetLines(&linkedLines, lines, sourceCode);
+ fasmLinesSetData(&linkedLines, lines, sourceCode);
+
+ return linkedLines;
+
+ // RETURN_ERROR:
+ const FasmLinkedLines ERROR = {
+ .lines = NULL,
+ .lines_size = ERROR_SIZE,
+ .variables = NULL,
+ .variables_size = ERROR_SIZE,
+ .data = NULL,
+ .data_size = ERROR_SIZE,
+ };
+
+ return ERROR;
+}
+
+void fasmLinesSetVariables(FasmLinkedLines *linkedLines, const FasmLines *lines,
+ SourceCode *sourceCode) {
+ size_t inserted = 0;
+
+ for (size_t i = 0; i < sourceCode->size; ++i) {
+ const FasmLines linesHolder = lines[i];
+ for (size_t j = 0; j < linesHolder.lines_size; ++j) {
+ const FasmLine line = lines->lines[j];
+ if (line.labelBegin != line.labelEnd) {
+ const FasmVariable variable = {
+ .begin = line.labelBegin,
+ .end = line.labelEnd,
+ .value = inserted,
+ };
+ fasmLinesPushVariable(linkedLines, variable);
+ }
+ inserted += getSizeOfLine(line);
+ }
+ }
+
+ inserted = 0;
+
+ for (size_t i = 0; i < sourceCode->size; ++i) {
+ const FasmLines linesHolder = lines[i];
+ for (size_t j = 0; j < linesHolder.data_size; ++j) {
+ const FasmLine line = lines->data[j];
+ if (line.labelBegin != line.labelEnd) {
+ const FasmVariable variable = {
+ .begin = line.labelBegin,
+ .end = line.labelEnd,
+ .value = inserted,
+ };
+ fasmLinesPushVariable(linkedLines, variable);
+ }
+ inserted += getSizeOfLine(line);
+ }
+ }
+}
+
+void fasmLinesSetLines(FasmLinkedLines *linkedLines, const FasmLines *lines,
+ SourceCode *sourceCode) {
+ for (size_t i = 0; i < sourceCode->size; ++i) {
+ const FasmLines linesHolder = lines[i];
+ for (size_t j = 0; j < linesHolder.lines_size; ++j) {
+ const FasmLine line = lines->lines[j];
+ fasmLinesPushLine(linkedLines,
+ fasmLinesParseLine(linkedLines, line, sourceCode));
+ }
+ }
+}
+
+extern void fasmLinesSetData(FasmLinkedLines *linkedLines,
+ const FasmLines *lines, SourceCode *sourceCode) {
+ for (size_t i = 0; i < sourceCode->size; ++i) {
+ const FasmLines linesHolder = lines[i];
+ for (size_t j = 0; j < linesHolder.data_size; ++j) {
+ const FasmLine line = lines->data[j];
+ FasmLinkedLine linkedLine =
+ fasmLinesParseLine(linkedLines, line, sourceCode);
+ fasmLinesPushData(linkedLines, linkedLine.operands,
+ linkedLine.operands_size);
+ fasmLinkedLineDeleteInner(linkedLine);
+ }
+ }
+}
+
+FasmLinkedLine fasmLinesParseLine(FasmLinkedLines *linkedLines, FasmLine line,
+ SourceCode *sourceCode) {
+ const FasmLinkedLine linkedLine = {
+ .begin = line.begin,
+ .end = line.end,
+ .instruction = line.instruction,
+ .operands = a404m_malloc(getSizeOfLineOperands(line)),
+ .operands_size = getSizeOfLineOperands(line),
+ };
+
+ const size_t elementSize = getSizeOfLineOperandElementSize(line);
+
+ size_t inserted = 0;
+
+ for (size_t i = 0; i < line.operands_size; ++i) {
+ const FasmOperand operand = line.operands[i];
+ if (isOperandString(operand)) {
+ for (char *iter = operand.begin + 1; iter + 1 < operand.end; ++iter) {
+ switch (elementSize) {
+ case 1:
+ ((uint8_t *)linkedLine.operands)[inserted] = *iter;
+ break;
+ case 2:
+ ((uint16_t *)linkedLine.operands)[inserted] = *iter;
+ break;
+ case 4:
+ ((uint32_t *)linkedLine.operands)[inserted] = *iter;
+ break;
+ case 8:
+ ((uint64_t *)linkedLine.operands)[inserted] = *iter;
+ break;
+ }
+ inserted += 1;
+ }
+ } else {
+ switch (elementSize) {
+ case 1:
+ ((uint8_t *)linkedLine.operands)[inserted] =
+ getOperandValue(linkedLines, operand, sourceCode);
+ break;
+ case 2:
+ ((uint16_t *)linkedLine.operands)[inserted] =
+ getOperandValue(linkedLines, operand, sourceCode);
+ break;
+ case 4:
+ ((uint32_t *)linkedLine.operands)[inserted] =
+ getOperandValue(linkedLines, operand, sourceCode);
+ break;
+ case 8:
+ ((uint64_t *)linkedLine.operands)[inserted] =
+ getOperandValue(linkedLines, operand, sourceCode);
+ break;
+ }
+ inserted += 1;
+ }
+ }
+
+ return linkedLine;
+}
+
+bool fasmLinkerOperandSizeCorrect(FasmToken token, int size) {
+ switch (token) {
+ case FASM_TOKEN_NOOP:
+ return size == 0;
+ case FASM_TOKEN_PUSH8:
+ case FASM_TOKEN_PUSH16:
+ case FASM_TOKEN_PUSH32:
+ case FASM_TOKEN_PUSH64:
+ return size == 1;
+ case FASM_TOKEN_LOAD8:
+ case FASM_TOKEN_LOAD16:
+ case FASM_TOKEN_LOAD32:
+ case FASM_TOKEN_LOAD64:
+ case FASM_TOKEN_POP8:
+ case FASM_TOKEN_POP16:
+ case FASM_TOKEN_POP32:
+ case FASM_TOKEN_POP64:
+ case FASM_TOKEN_DUP8:
+ case FASM_TOKEN_DUP16:
+ case FASM_TOKEN_DUP32:
+ case FASM_TOKEN_DUP64:
+ case FASM_TOKEN_SWAP8:
+ case FASM_TOKEN_SWAP16:
+ case FASM_TOKEN_SWAP32:
+ case FASM_TOKEN_SWAP64:
+ case FASM_TOKEN_DROP8:
+ case FASM_TOKEN_DROP16:
+ case FASM_TOKEN_DROP32:
+ case FASM_TOKEN_DROP64:
+ case FASM_TOKEN_ADD_I8:
+ case FASM_TOKEN_ADD_I16:
+ case FASM_TOKEN_ADD_I32:
+ case FASM_TOKEN_ADD_I64:
+ case FASM_TOKEN_ADD_F32:
+ case FASM_TOKEN_ADD_F64:
+ case FASM_TOKEN_SUB_I8:
+ case FASM_TOKEN_SUB_I16:
+ case FASM_TOKEN_SUB_I32:
+ case FASM_TOKEN_SUB_I64:
+ case FASM_TOKEN_SUB_F32:
+ case FASM_TOKEN_SUB_F64:
+ case FASM_TOKEN_NEG_I8:
+ case FASM_TOKEN_NEG_I16:
+ case FASM_TOKEN_NEG_I32:
+ case FASM_TOKEN_NEG_I64:
+ case FASM_TOKEN_NEG_F32:
+ case FASM_TOKEN_NEG_F64:
+ case FASM_TOKEN_MUL_I8:
+ case FASM_TOKEN_MUL_I16:
+ case FASM_TOKEN_MUL_I32:
+ case FASM_TOKEN_MUL_I64:
+ case FASM_TOKEN_MUL_U8:
+ case FASM_TOKEN_MUL_U16:
+ case FASM_TOKEN_MUL_U32:
+ case FASM_TOKEN_MUL_U64:
+ case FASM_TOKEN_MUL_F32:
+ case FASM_TOKEN_MUL_F64:
+ case FASM_TOKEN_DIV_I8:
+ case FASM_TOKEN_DIV_I16:
+ case FASM_TOKEN_DIV_I32:
+ case FASM_TOKEN_DIV_I64:
+ case FASM_TOKEN_DIV_U8:
+ case FASM_TOKEN_DIV_U16:
+ case FASM_TOKEN_DIV_U32:
+ case FASM_TOKEN_DIV_U64:
+ case FASM_TOKEN_DIV_F32:
+ case FASM_TOKEN_DIV_F64:
+ case FASM_TOKEN_REM_I8:
+ case FASM_TOKEN_REM_I16:
+ case FASM_TOKEN_REM_I32:
+ case FASM_TOKEN_REM_I64:
+ case FASM_TOKEN_REM_U8:
+ case FASM_TOKEN_REM_U16:
+ case FASM_TOKEN_REM_U32:
+ case FASM_TOKEN_REM_U64:
+ case FASM_TOKEN_CAST_I8_I64:
+ case FASM_TOKEN_CAST_I16_I64:
+ case FASM_TOKEN_CAST_I32_I64:
+ case FASM_TOKEN_CAST_I64_I8:
+ case FASM_TOKEN_CAST_I64_I16:
+ case FASM_TOKEN_CAST_I64_I32:
+ case FASM_TOKEN_CAST_F64_I64:
+ case FASM_TOKEN_CAST_I64_F64:
+ case FASM_TOKEN_CAST_U8_U64:
+ case FASM_TOKEN_CAST_U16_U64:
+ case FASM_TOKEN_CAST_U32_U64:
+ case FASM_TOKEN_CAST_U64_U8:
+ case FASM_TOKEN_CAST_U64_U16:
+ case FASM_TOKEN_CAST_U64_U32:
+ case FASM_TOKEN_CAST_F64_U64:
+ case FASM_TOKEN_CAST_U64_F64:
+ case FASM_TOKEN_CAST_F32_F64:
+ case FASM_TOKEN_CAST_F64_F32:
+ case FASM_TOKEN_JUMP:
+ case FASM_TOKEN_JZ_I8:
+ case FASM_TOKEN_JNZ_I8:
+ case FASM_TOKEN_JN_I8:
+ case FASM_TOKEN_JNN_I8:
+ case FASM_TOKEN_JP_I8:
+ case FASM_TOKEN_JNP_I8:
+ case FASM_TOKEN_JZ_I16:
+ case FASM_TOKEN_JNZ_I16:
+ case FASM_TOKEN_JN_I16:
+ case FASM_TOKEN_JNN_I16:
+ case FASM_TOKEN_JP_I16:
+ case FASM_TOKEN_JNP_I16:
+ case FASM_TOKEN_JZ_I32:
+ case FASM_TOKEN_JNZ_I32:
+ case FASM_TOKEN_JN_I32:
+ case FASM_TOKEN_JNN_I32:
+ case FASM_TOKEN_JP_I32:
+ case FASM_TOKEN_JNP_I32:
+ case FASM_TOKEN_JZ_I64:
+ case FASM_TOKEN_JNZ_I64:
+ case FASM_TOKEN_JN_I64:
+ case FASM_TOKEN_JNN_I64:
+ case FASM_TOKEN_JP_I64:
+ case FASM_TOKEN_JNP_I64:
+ case FASM_TOKEN_JZ_F32:
+ case FASM_TOKEN_JNZ_F32:
+ case FASM_TOKEN_JN_F32:
+ case FASM_TOKEN_JNN_F32:
+ case FASM_TOKEN_JP_F32:
+ case FASM_TOKEN_JNP_F32:
+ case FASM_TOKEN_JZ_F64:
+ case FASM_TOKEN_JNZ_F64:
+ case FASM_TOKEN_JN_F64:
+ case FASM_TOKEN_JNN_F64:
+ case FASM_TOKEN_JP_F64:
+ case FASM_TOKEN_JNP_F64:
+ case FASM_TOKEN_ALLOC_HEAP:
+ case FASM_TOKEN_ALLOC_STACK:
+ case FASM_TOKEN_FREE_HEAP:
+ case FASM_TOKEN_GET_STACK_ADDRESS:
+ case FASM_TOKEN_GET_GLOBAL_ADDRESS:
+ case FASM_TOKEN_CALL:
+ case FASM_TOKEN_RET:
+ return size == 0;
+ case FASM_TOKEN_SYSCALL:
+ return size == 1;
+ case FASM_TOKEN_DEFINE_BYTE:
+ case FASM_TOKEN_DEFINE_WORD:
+ case FASM_TOKEN_DEFINE_DWORD:
+ case FASM_TOKEN_DEFINE_QWORD:
+ return size > 1;
+ case FASM_TOKEN_NONE:
+ return false;
+ }
+ fprintf(stderr, "Bad fasm token '%d' at %s:%d", token, __FILE_NAME__,
+ __LINE__);
+ exit(1);
+}
+
+size_t getSizeOfLine(const FasmLine line) {
+ return sizeof(line.instruction) + getSizeOfLineOperands(line);
+}
+
+size_t getSizeOfLineOperands(const FasmLine line) {
+ switch (line.instruction) {
+ case FASM_TOKEN_PUSH8:
+ return 1;
+ case FASM_TOKEN_PUSH16:
+ return 2;
+ case FASM_TOKEN_PUSH32:
+ return 4;
+ case FASM_TOKEN_PUSH64:
+ return 8;
+ case FASM_TOKEN_LOAD8:
+ case FASM_TOKEN_LOAD16:
+ case FASM_TOKEN_LOAD32:
+ case FASM_TOKEN_LOAD64:
+ case FASM_TOKEN_POP8:
+ case FASM_TOKEN_POP16:
+ case FASM_TOKEN_POP32:
+ case FASM_TOKEN_POP64:
+ case FASM_TOKEN_DUP8:
+ case FASM_TOKEN_DUP16:
+ case FASM_TOKEN_DUP32:
+ case FASM_TOKEN_DUP64:
+ case FASM_TOKEN_SWAP8:
+ case FASM_TOKEN_SWAP16:
+ case FASM_TOKEN_SWAP32:
+ case FASM_TOKEN_SWAP64:
+ case FASM_TOKEN_DROP8:
+ case FASM_TOKEN_DROP16:
+ case FASM_TOKEN_DROP32:
+ case FASM_TOKEN_DROP64:
+ case FASM_TOKEN_ADD_I8:
+ case FASM_TOKEN_ADD_I16:
+ case FASM_TOKEN_ADD_I32:
+ case FASM_TOKEN_ADD_I64:
+ case FASM_TOKEN_ADD_F32:
+ case FASM_TOKEN_ADD_F64:
+ case FASM_TOKEN_SUB_I8:
+ case FASM_TOKEN_SUB_I16:
+ case FASM_TOKEN_SUB_I32:
+ case FASM_TOKEN_SUB_I64:
+ case FASM_TOKEN_SUB_F32:
+ case FASM_TOKEN_SUB_F64:
+ case FASM_TOKEN_NEG_I8:
+ case FASM_TOKEN_NEG_I16:
+ case FASM_TOKEN_NEG_I32:
+ case FASM_TOKEN_NEG_I64:
+ case FASM_TOKEN_NEG_F32:
+ case FASM_TOKEN_NEG_F64:
+ case FASM_TOKEN_MUL_I8:
+ case FASM_TOKEN_MUL_I16:
+ case FASM_TOKEN_MUL_I32:
+ case FASM_TOKEN_MUL_I64:
+ case FASM_TOKEN_MUL_U8:
+ case FASM_TOKEN_MUL_U16:
+ case FASM_TOKEN_MUL_U32:
+ case FASM_TOKEN_MUL_U64:
+ case FASM_TOKEN_MUL_F32:
+ case FASM_TOKEN_MUL_F64:
+ case FASM_TOKEN_DIV_I8:
+ case FASM_TOKEN_DIV_I16:
+ case FASM_TOKEN_DIV_I32:
+ case FASM_TOKEN_DIV_I64:
+ case FASM_TOKEN_DIV_U8:
+ case FASM_TOKEN_DIV_U16:
+ case FASM_TOKEN_DIV_U32:
+ case FASM_TOKEN_DIV_U64:
+ case FASM_TOKEN_DIV_F32:
+ case FASM_TOKEN_DIV_F64:
+ case FASM_TOKEN_REM_I8:
+ case FASM_TOKEN_REM_I16:
+ case FASM_TOKEN_REM_I32:
+ case FASM_TOKEN_REM_I64:
+ case FASM_TOKEN_REM_U8:
+ case FASM_TOKEN_REM_U16:
+ case FASM_TOKEN_REM_U32:
+ case FASM_TOKEN_REM_U64:
+ case FASM_TOKEN_CAST_I8_I64:
+ case FASM_TOKEN_CAST_I16_I64:
+ case FASM_TOKEN_CAST_I32_I64:
+ case FASM_TOKEN_CAST_I64_I8:
+ case FASM_TOKEN_CAST_I64_I16:
+ case FASM_TOKEN_CAST_I64_I32:
+ case FASM_TOKEN_CAST_F64_I64:
+ case FASM_TOKEN_CAST_I64_F64:
+ case FASM_TOKEN_CAST_U8_U64:
+ case FASM_TOKEN_CAST_U16_U64:
+ case FASM_TOKEN_CAST_U32_U64:
+ case FASM_TOKEN_CAST_U64_U8:
+ case FASM_TOKEN_CAST_U64_U16:
+ case FASM_TOKEN_CAST_U64_U32:
+ case FASM_TOKEN_CAST_F64_U64:
+ case FASM_TOKEN_CAST_U64_F64:
+ case FASM_TOKEN_CAST_F32_F64:
+ case FASM_TOKEN_CAST_F64_F32:
+ case FASM_TOKEN_JUMP:
+ case FASM_TOKEN_JZ_I8:
+ case FASM_TOKEN_JNZ_I8:
+ case FASM_TOKEN_JN_I8:
+ case FASM_TOKEN_JNN_I8:
+ case FASM_TOKEN_JP_I8:
+ case FASM_TOKEN_JNP_I8:
+ case FASM_TOKEN_JZ_I16:
+ case FASM_TOKEN_JNZ_I16:
+ case FASM_TOKEN_JN_I16:
+ case FASM_TOKEN_JNN_I16:
+ case FASM_TOKEN_JP_I16:
+ case FASM_TOKEN_JNP_I16:
+ case FASM_TOKEN_JZ_I32:
+ case FASM_TOKEN_JNZ_I32:
+ case FASM_TOKEN_JN_I32:
+ case FASM_TOKEN_JNN_I32:
+ case FASM_TOKEN_JP_I32:
+ case FASM_TOKEN_JNP_I32:
+ case FASM_TOKEN_JZ_I64:
+ case FASM_TOKEN_JNZ_I64:
+ case FASM_TOKEN_JN_I64:
+ case FASM_TOKEN_JNN_I64:
+ case FASM_TOKEN_JP_I64:
+ case FASM_TOKEN_JNP_I64:
+ case FASM_TOKEN_JZ_F32:
+ case FASM_TOKEN_JNZ_F32:
+ case FASM_TOKEN_JN_F32:
+ case FASM_TOKEN_JNN_F32:
+ case FASM_TOKEN_JP_F32:
+ case FASM_TOKEN_JNP_F32:
+ case FASM_TOKEN_JZ_F64:
+ case FASM_TOKEN_JNZ_F64:
+ case FASM_TOKEN_JN_F64:
+ case FASM_TOKEN_JNN_F64:
+ case FASM_TOKEN_JP_F64:
+ case FASM_TOKEN_JNP_F64:
+ case FASM_TOKEN_ALLOC_HEAP:
+ case FASM_TOKEN_ALLOC_STACK:
+ case FASM_TOKEN_FREE_HEAP:
+ case FASM_TOKEN_GET_STACK_ADDRESS:
+ case FASM_TOKEN_GET_GLOBAL_ADDRESS:
+ case FASM_TOKEN_CALL:
+ case FASM_TOKEN_RET:
+ case FASM_TOKEN_NOOP:
+ case FASM_TOKEN_SYSCALL:
+ return 0;
+ case FASM_TOKEN_DEFINE_BYTE:
+ case FASM_TOKEN_DEFINE_WORD:
+ case FASM_TOKEN_DEFINE_DWORD:
+ case FASM_TOKEN_DEFINE_QWORD: {
+ size_t elementSize;
+
+ switch (line.instruction) {
+ case FASM_TOKEN_DEFINE_BYTE:
+ elementSize = 1;
+ break;
+ case FASM_TOKEN_DEFINE_WORD:
+ elementSize = 2;
+ break;
+ case FASM_TOKEN_DEFINE_DWORD:
+ elementSize = 4;
+ break;
+ case FASM_TOKEN_DEFINE_QWORD:
+ elementSize = 8;
+ break;
+ default:
+ }
+
+ size_t size = 0;
+
+ for (size_t i = 0; i < line.operands_size; ++i) {
+ const FasmOperand operand = line.operands[i];
+ if (isOperandString(operand)) {
+ size += (operand.end - operand.begin - 2) * elementSize;
+ } else {
+ size += elementSize;
+ }
+ }
+
+ return size;
+ }
+ case FASM_TOKEN_NONE:
+ }
+ fprintf(stderr, "Bad fasm token '%d' at %s:%d", line.instruction,
+ __FILE_NAME__, __LINE__);
+ exit(1);
+}
+
+size_t getSizeOfLineOperandElementSize(const FasmLine line) {
+ switch (line.instruction) {
+ case FASM_TOKEN_NOOP:
+ return 0;
+ case FASM_TOKEN_PUSH8:
+ return 1;
+ case FASM_TOKEN_PUSH16:
+ return 2;
+ case FASM_TOKEN_PUSH32:
+ return 4;
+ case FASM_TOKEN_PUSH64:
+ return 8;
+ case FASM_TOKEN_LOAD8:
+ case FASM_TOKEN_LOAD16:
+ case FASM_TOKEN_LOAD32:
+ case FASM_TOKEN_LOAD64:
+ case FASM_TOKEN_POP8:
+ case FASM_TOKEN_POP16:
+ case FASM_TOKEN_POP32:
+ case FASM_TOKEN_POP64:
+ case FASM_TOKEN_DUP8:
+ case FASM_TOKEN_DUP16:
+ case FASM_TOKEN_DUP32:
+ case FASM_TOKEN_DUP64:
+ case FASM_TOKEN_SWAP8:
+ case FASM_TOKEN_SWAP16:
+ case FASM_TOKEN_SWAP32:
+ case FASM_TOKEN_SWAP64:
+ case FASM_TOKEN_DROP8:
+ case FASM_TOKEN_DROP16:
+ case FASM_TOKEN_DROP32:
+ case FASM_TOKEN_DROP64:
+ case FASM_TOKEN_ADD_I8:
+ case FASM_TOKEN_ADD_I16:
+ case FASM_TOKEN_ADD_I32:
+ case FASM_TOKEN_ADD_I64:
+ case FASM_TOKEN_ADD_F32:
+ case FASM_TOKEN_ADD_F64:
+ case FASM_TOKEN_SUB_I8:
+ case FASM_TOKEN_SUB_I16:
+ case FASM_TOKEN_SUB_I32:
+ case FASM_TOKEN_SUB_I64:
+ case FASM_TOKEN_SUB_F32:
+ case FASM_TOKEN_SUB_F64:
+ case FASM_TOKEN_NEG_I8:
+ case FASM_TOKEN_NEG_I16:
+ case FASM_TOKEN_NEG_I32:
+ case FASM_TOKEN_NEG_I64:
+ case FASM_TOKEN_NEG_F32:
+ case FASM_TOKEN_NEG_F64:
+ case FASM_TOKEN_MUL_I8:
+ case FASM_TOKEN_MUL_I16:
+ case FASM_TOKEN_MUL_I32:
+ case FASM_TOKEN_MUL_I64:
+ case FASM_TOKEN_MUL_U8:
+ case FASM_TOKEN_MUL_U16:
+ case FASM_TOKEN_MUL_U32:
+ case FASM_TOKEN_MUL_U64:
+ case FASM_TOKEN_MUL_F32:
+ case FASM_TOKEN_MUL_F64:
+ case FASM_TOKEN_DIV_I8:
+ case FASM_TOKEN_DIV_I16:
+ case FASM_TOKEN_DIV_I32:
+ case FASM_TOKEN_DIV_I64:
+ case FASM_TOKEN_DIV_U8:
+ case FASM_TOKEN_DIV_U16:
+ case FASM_TOKEN_DIV_U32:
+ case FASM_TOKEN_DIV_U64:
+ case FASM_TOKEN_DIV_F32:
+ case FASM_TOKEN_DIV_F64:
+ case FASM_TOKEN_REM_I8:
+ case FASM_TOKEN_REM_I16:
+ case FASM_TOKEN_REM_I32:
+ case FASM_TOKEN_REM_I64:
+ case FASM_TOKEN_REM_U8:
+ case FASM_TOKEN_REM_U16:
+ case FASM_TOKEN_REM_U32:
+ case FASM_TOKEN_REM_U64:
+ case FASM_TOKEN_CAST_I8_I64:
+ case FASM_TOKEN_CAST_I16_I64:
+ case FASM_TOKEN_CAST_I32_I64:
+ case FASM_TOKEN_CAST_I64_I8:
+ case FASM_TOKEN_CAST_I64_I16:
+ case FASM_TOKEN_CAST_I64_I32:
+ case FASM_TOKEN_CAST_F64_I64:
+ case FASM_TOKEN_CAST_I64_F64:
+ case FASM_TOKEN_CAST_U8_U64:
+ case FASM_TOKEN_CAST_U16_U64:
+ case FASM_TOKEN_CAST_U32_U64:
+ case FASM_TOKEN_CAST_U64_U8:
+ case FASM_TOKEN_CAST_U64_U16:
+ case FASM_TOKEN_CAST_U64_U32:
+ case FASM_TOKEN_CAST_F64_U64:
+ case FASM_TOKEN_CAST_U64_F64:
+ case FASM_TOKEN_CAST_F32_F64:
+ case FASM_TOKEN_CAST_F64_F32:
+ case FASM_TOKEN_JUMP:
+ case FASM_TOKEN_JZ_I8:
+ case FASM_TOKEN_JNZ_I8:
+ case FASM_TOKEN_JN_I8:
+ case FASM_TOKEN_JNN_I8:
+ case FASM_TOKEN_JP_I8:
+ case FASM_TOKEN_JNP_I8:
+ case FASM_TOKEN_JZ_I16:
+ case FASM_TOKEN_JNZ_I16:
+ case FASM_TOKEN_JN_I16:
+ case FASM_TOKEN_JNN_I16:
+ case FASM_TOKEN_JP_I16:
+ case FASM_TOKEN_JNP_I16:
+ case FASM_TOKEN_JZ_I32:
+ case FASM_TOKEN_JNZ_I32:
+ case FASM_TOKEN_JN_I32:
+ case FASM_TOKEN_JNN_I32:
+ case FASM_TOKEN_JP_I32:
+ case FASM_TOKEN_JNP_I32:
+ case FASM_TOKEN_JZ_I64:
+ case FASM_TOKEN_JNZ_I64:
+ case FASM_TOKEN_JN_I64:
+ case FASM_TOKEN_JNN_I64:
+ case FASM_TOKEN_JP_I64:
+ case FASM_TOKEN_JNP_I64:
+ case FASM_TOKEN_JZ_F32:
+ case FASM_TOKEN_JNZ_F32:
+ case FASM_TOKEN_JN_F32:
+ case FASM_TOKEN_JNN_F32:
+ case FASM_TOKEN_JP_F32:
+ case FASM_TOKEN_JNP_F32:
+ case FASM_TOKEN_JZ_F64:
+ case FASM_TOKEN_JNZ_F64:
+ case FASM_TOKEN_JN_F64:
+ case FASM_TOKEN_JNN_F64:
+ case FASM_TOKEN_JP_F64:
+ case FASM_TOKEN_JNP_F64:
+ case FASM_TOKEN_ALLOC_HEAP:
+ case FASM_TOKEN_ALLOC_STACK:
+ case FASM_TOKEN_FREE_HEAP:
+ case FASM_TOKEN_GET_STACK_ADDRESS:
+ case FASM_TOKEN_GET_GLOBAL_ADDRESS:
+ case FASM_TOKEN_CALL:
+ case FASM_TOKEN_RET:
+ case FASM_TOKEN_SYSCALL:
+ return 0;
+ case FASM_TOKEN_DEFINE_BYTE:
+ return 1;
+ case FASM_TOKEN_DEFINE_WORD:
+ return 2;
+ case FASM_TOKEN_DEFINE_DWORD:
+ return 4;
+ case FASM_TOKEN_DEFINE_QWORD:
+ return 8;
+ case FASM_TOKEN_NONE:
+ }
+
+ fprintf(stderr, "Bad fasm token '%d' at %s:%d", line.instruction,
+ __FILE_NAME__, __LINE__);
+ exit(1);
+}
+
+void fasmLinesPushVariable(FasmLinkedLines *linkedLines,
+ FasmVariable variable) {
+ const size_t size = a404m_malloc_usable_size(linkedLines->variables) /
+ sizeof(*linkedLines->variables);
+ if (size == linkedLines->variables_size) {
+ linkedLines->variables =
+ a404m_realloc(linkedLines->variables,
+ (size + size / 2 + 1) * sizeof(*linkedLines->variables));
+ }
+ linkedLines->variables[linkedLines->variables_size] = variable;
+ linkedLines->variables_size += 1;
+}
+
+void fasmLinesPushLine(FasmLinkedLines *linkedLines, FasmLinkedLine line) {
+ const size_t size = a404m_malloc_usable_size(linkedLines->lines) /
+ sizeof(*linkedLines->lines);
+ if (size == linkedLines->lines_size) {
+ linkedLines->lines =
+ a404m_realloc(linkedLines->lines,
+ (size + size / 2 + 1) * sizeof(*linkedLines->lines));
+ }
+ linkedLines->lines[linkedLines->lines_size] = line;
+ linkedLines->lines_size += 1;
+}
+
+void fasmLinesPushData(FasmLinkedLines *linkedLines, uint8_t *data,
+ size_t size) {
+ linkedLines->data =
+ a404m_realloc(linkedLines->data, (linkedLines->data_size + size) *
+ sizeof(*linkedLines->data));
+ memcpy(linkedLines->data + linkedLines->data_size, data, size);
+ linkedLines->data_size += size;
+}
+
+FasmVariable fasmLinesGetVariable(const FasmLinkedLines *linkedLines,
+ char const *nameBegin, char const *nameEnd) {
+ const size_t size = nameEnd - nameBegin;
+ for (size_t i = 0; i < linkedLines->variables_size; ++i) {
+ const FasmVariable variable = linkedLines->variables[i];
+ const size_t variable_str_size = variable.end - variable.begin;
+ if (size == variable_str_size &&
+ strncmp(variable.begin, nameBegin, size) == 0) {
+ return variable;
+ }
+ }
+
+ FasmVariable ERROR = {
+ .begin = NULL,
+ .end = NULL,
+ .value = 0,
+ };
+
+ return ERROR;
+}
+
+bool isOperandString(FasmOperand operand) { return *(operand.begin) == '"'; }
+
+uint64_t getOperandValue(FasmLinkedLines *linkedLines, FasmOperand operand,
+ SourceCode *sourceCode) {
+ char c = *(operand.begin);
+
+ if (c == '"') {
+ fprintf(stderr, "It shoulden't be here");
+ exit(1);
+ } else if (c == '0') {
+ ++(operand.begin);
+ if (operand.begin == operand.end) {
+ return 0;
+ }
+ c = *(operand.begin);
+ if (c == 'x') {
+ return hexStrToInt(operand.begin + 1, operand.end, sourceCode);
+ } else if (c == 'b') {
+ return binStrToInt(operand.begin + 1, operand.end, sourceCode);
+ } else {
+ return strToInt(operand.begin + 1, operand.end, sourceCode);
+ }
+ } else if (c == '-') {
+ ++(operand.begin);
+ if (operand.begin == operand.end) {
+ printError("Expected value after -", sourceCode, operand.begin,
+ operand.end);
+ exit(1);
+ }
+ c = *(operand.begin);
+ if (c == '0') {
+ ++(operand.begin);
+ if (operand.begin == operand.end) {
+ return 0;
+ }
+ c = *(operand.begin);
+ if (c == 'x') {
+ return -hexStrToInt(operand.begin + 1, operand.end, sourceCode);
+ } else if (c == 'b') {
+ return -binStrToInt(operand.begin + 1, operand.end, sourceCode);
+ } else {
+ return -strToInt(operand.begin + 1, operand.end, sourceCode);
+ }
+ }
+ } else if ('0' <= c && c <= '9') {
+ return strToInt(operand.begin, operand.end, sourceCode);
+ } else {
+ const FasmVariable variable =
+ fasmLinesGetVariable(linkedLines, operand.begin, operand.end);
+ if (variable.begin == NULL) {
+ printError("Label '%.*s' not found", sourceCode, operand.begin,
+ operand.end, (int)(operand.end - operand.begin),
+ operand.begin);
+ exit(1);
+ }
+ return variable.value;
+ }
+ printError("Should not come here %s:%d", sourceCode, operand.begin,
+ operand.end, __FILE_NAME__, __LINE__);
+ exit(1);
+}
+
+uint64_t strToInt(const char *begin, const char *end, SourceCode *sourceCode) {
+ uint64_t result = 0;
+ for (char const *iter = begin; iter < end; ++iter) {
+ const char c = *iter;
+ result *= 10;
+ if ('0' <= c && c <= '9') {
+ result += c - '0';
+ } else {
+ printError("Unexpected character", sourceCode, iter, iter + 1);
+ exit(1);
+ }
+ }
+ return result;
+}
+uint64_t hexStrToInt(const char *begin, const char *end,
+ SourceCode *sourceCode) {
+ uint64_t result = 0;
+ for (char const *iter = begin; iter < end; ++iter) {
+ const char c = *iter;
+ result *= 16;
+ if ('0' <= c && c <= '9') {
+ result += c - '0';
+ } else if ('A' <= c && c < 'F') {
+ result += c - 'A' + 10;
+ } else if ('a' <= c && c < 'f') {
+ result += c - 'a' + 10;
+ } else {
+ printError("Unexpected character", sourceCode, iter, iter + 1);
+ exit(1);
+ }
+ }
+ return result;
+}
+uint64_t binStrToInt(const char *begin, const char *end,
+ SourceCode *sourceCode) {
+ uint64_t result = 0;
+ for (char const *iter = begin; iter < end; ++iter) {
+ const char c = *iter;
+ result *= 2;
+ if ('0' <= c && c <= '1') {
+ result += c - '0';
+ } else {
+ printError("Unexpected character", sourceCode, iter, iter + 1);
+ exit(1);
+ }
+ }
+ return result;
+}
diff --git a/src/fasm/linker/linker.h b/src/fasm/linker/linker.h
new file mode 100644
index 0000000..fd7813b
--- /dev/null
+++ b/src/fasm/linker/linker.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include <fasm/lexer/lexer.h>
+#include <stdint.h>
+
+typedef struct FasmLinkedLine {
+ char const *begin;
+ char const *end;
+ FasmToken instruction;
+ uint8_t *operands;
+ size_t operands_size;
+} FasmLinkedLine;
+
+typedef struct FasmVariable {
+ char const *begin;
+ char const *end;
+ uint64_t value;
+} FasmVariable;
+
+typedef struct FasmLinkedLines {
+ FasmLinkedLine *lines;
+ size_t lines_size;
+
+ FasmVariable *variables;
+ size_t variables_size;
+
+ uint8_t *data;
+ size_t data_size;
+} FasmLinkedLines;
+
+extern void fasmVariablePrint(FasmVariable variable);
+extern void fasmLinkedLinePrint(FasmLinkedLine line);
+extern void fasmLinkedLinesPrint(FasmLinkedLines lines);
+
+extern void fasmLinkedLineDeleteInner(FasmLinkedLine line);
+extern void fasmLinkedLinesDeleteInner(FasmLinkedLines lines);
+
+extern FasmLinkedLines fasmLinker(const FasmLines *lines,
+ SourceCode *sourceCode);
+
+extern void fasmLinesSetVariables(FasmLinkedLines *linkedLines,
+ const FasmLines *lines,
+ SourceCode *sourceCode);
+extern void fasmLinesSetLines(FasmLinkedLines *linkedLines,
+ const FasmLines *lines, SourceCode *sourceCode);
+extern void fasmLinesSetData(FasmLinkedLines *linkedLines,
+ const FasmLines *lines, SourceCode *sourceCode);
+
+extern FasmLinkedLine fasmLinesParseLine(FasmLinkedLines *linkedLines,
+ FasmLine line, SourceCode *sourceCode);
+
+extern bool fasmLinkerOperandSizeCorrect(FasmToken token, int size);
+
+extern size_t getSizeOfLine(const FasmLine line);
+extern size_t getSizeOfLineOperands(const FasmLine line);
+extern size_t getSizeOfLineOperandElementSize(const FasmLine line);
+
+extern void fasmLinesPushVariable(FasmLinkedLines *linkedLines,
+ FasmVariable variable);
+extern void fasmLinesPushLine(FasmLinkedLines *linkedLines,
+ FasmLinkedLine line);
+extern void fasmLinesPushData(FasmLinkedLines *linkedLines, uint8_t *data,
+ size_t size);
+extern FasmVariable fasmLinesGetVariable(const FasmLinkedLines *linkedLines,
+ char const *nameBegin,
+ char const *nameEnd);
+
+extern bool isOperandString(FasmOperand operand);
+
+extern uint64_t getOperandValue(FasmLinkedLines *linkedLines,
+ FasmOperand operand, SourceCode *sourceCode);
+
+extern uint64_t strToInt(const char *begin, const char *end,
+ SourceCode *sourceCode);
+extern uint64_t hexStrToInt(const char *begin, const char *end,
+ SourceCode *sourceCode);
+extern uint64_t binStrToInt(const char *begin, const char *end,
+ SourceCode *sourceCode);