Skip to content

Commit e0a8356

Browse files
Merge pull request #23 from Michal-Martinek/toolchain-gcc-only
removed nasm dependency for speed, now using only gcc
2 parents 1344005 + cf01e96 commit e0a8356

File tree

4 files changed

+142
-130
lines changed

4 files changed

+142
-130
lines changed

.github/workflows/tests.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,10 @@ jobs:
1414
- name: checkout repo
1515
uses: actions/checkout@v4
1616

17-
- name: Install nasm and mingw (Chocolatey)
17+
- name: Install gcc (Chocolatey)
1818
shell: cmd
1919
run: |
20-
nasm -v || choco install -y nasm
21-
gcc -v || choco install -y mingw
20+
gcc --version || choco install -y mingw
2221
2322
- name: Set up Python
2423
uses: actions/setup-python@v4

Masfix.cpp

Lines changed: 116 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1886,9 +1886,9 @@ void genInstrBody(ofstream& outFile, InstrNames instr, int instrNum, bool inputT
18861886
} else if (instr == Ijmp || instr == Ib) {
18871887
outFile <<
18881888
" mov rsi, " << instrNum << "\n"
1889-
" cmp rcx, instruction_count\n"
1889+
" cmp rcx, OFFSET FLAT:instruction_count\n"
18901890
" ja jmp_error\n"
1891-
" mov rbx, instruction_offsets\n"
1891+
" lea rbx, [rip + instruction_offsets]\n"
18921892
" jmp [rbx+8*rcx]\n";
18931893
} else if (instr == Il || instr == Is) { // handled in genCond
18941894
} else if (instr == Iswap) {
@@ -1900,7 +1900,7 @@ void genInstrBody(ofstream& outFile, InstrNames instr, int instrNum, bool inputT
19001900
" call print_unsigned\n";
19011901
} else if (instr == Ioutc) {
19021902
outFile <<
1903-
" mov rdx, stdout_buff\n"
1903+
" lea rdx, [rip + stdout_buff]\n"
19041904
" mov [rdx], cl\n"
19051905
" mov r8, 1\n"
19061906
" call stdout_write\n";
@@ -1950,121 +1950,115 @@ void genAssembly(ofstream& outFile, Instr instr, int instrNum) {
19501950

19511951
void generate(ofstream& outFile, vector<Instr>& instrs) {
19521952
outFile <<
1953-
"extern ExitProcess\n"
1954-
"extern GetStdHandle\n"
1955-
"extern WriteFile\n"
1956-
"extern ReadFile\n"
1953+
".intel_syntax noprefix\n"
19571954
"\n"
1958-
"section .text\n"
1959-
"exit: ; exits the program with code in rax\n"
1955+
".extern ExitProcess\n"
1956+
".extern GetStdHandle\n"
1957+
".extern WriteFile\n"
1958+
".extern ReadFile\n"
1959+
"\n"
1960+
".text\n"
1961+
"exit: # exits the program with code in rax\n"
19601962
" mov rcx, rax\n"
1961-
" and rsp, -16 ; force 16-byte alignment\n"
1963+
" and rsp, -16 # force 16-byte alignment\n"
19621964
" sub rsp, 32\n"
19631965
" call ExitProcess\n"
19641966
" hlt\n"
1965-
"error: ; prints ERROR template, instr number: rsi, message: rdx, r8, errorneous value: rcx, exit(1)\n"
1967+
"error: # prints ERROR template, instr number: rsi, message: rdx, r8, errorneous value: rcx, exit(1)\n"
19661968
" push rcx\n"
19671969
" push r8\n"
19681970
" push rdx\n"
19691971
" push rsi\n"
1970-
" mov rdx, ERROR_template\n"
1971-
" mov r8, ERROR_template_len\n"
1972+
" lea rdx, [rip + ERROR_template]\n"
1973+
" mov r8, OFFSET FLAT:ERROR_template_len\n"
19721974
" call stderr_write\n"
1973-
" pop rax ; print instr number\n"
1975+
" pop rax # print instr number\n"
19741976
" call print_unsigned_err\n"
1975-
" pop rdx ; error message\n"
1977+
" pop rdx # error message\n"
19761978
" pop r8\n"
19771979
" call stderr_write\n"
1978-
" pop rax ; errorneous value\n"
1980+
" pop rax # errorneous value\n"
19791981
" call print_unsigned_err\n"
1980-
" mov rdx, stdout_buff\n"
1981-
" mov BYTE [rdx], 10 ; '\\n'\n"
1982+
" lea rdx, [rip + stdout_buff]\n"
1983+
" mov BYTE PTR [rdx], 10 # '\\n'\n"
19821984
" mov r8, 1\n"
19831985
" call stderr_write\n"
1984-
" mov rax, 1 ; exit(1)\n"
1986+
" mov rax, 1 # exit(1)\n"
19851987
" call exit\n"
19861988
"\n"
1987-
"get_std_fds: ; prepares all std fds, regs unsafe!\n"
1988-
" sub rsp, 32 ; reserve shadow space\n"
1989-
" mov rcx, -10 ; stdin fd\n"
1989+
"get_std_fds: # prepares all std fds, regs unsafe!\n"
1990+
" sub rsp, 32 # reserve shadow space\n"
1991+
" mov rcx, -10 # stdin fd\n"
19901992
" call GetStdHandle\n"
1991-
" mov rcx, stdin_fd\n"
1992-
" mov [rcx], rax\n"
1993-
" mov rcx, -11 ; stdout fd\n"
1993+
" mov QWORD PTR [rip + stdin_fd], rax\n"
1994+
" mov rcx, -11 # stdout fd\n"
19941995
" call GetStdHandle\n"
1995-
" mov rcx, stdout_fd\n"
1996-
" mov [rcx], rax\n"
1997-
" mov rcx, -12 ; stderr fd\n"
1996+
" mov QWORD PTR [rip + stdout_fd], rax\n"
1997+
" mov rcx, -12 # stderr fd\n"
19981998
" call GetStdHandle\n"
1999-
" mov rcx, stderr_fd\n"
2000-
" mov [rcx], rax\n"
2001-
" add rsp, 32 ; remove shadow space\n"
1999+
" mov QWORD PTR [rip + stderr_fd], rax\n"
2000+
" add rsp, 32 # remove shadow space\n"
20022001
" ret\n"
20032002
"\n"
2004-
"; rdx - buff, r8 - number of bytes -> rax - number written\n"
2003+
"# rdx - buff, r8 - number of bytes -> rax - number written\n"
20052004
"stdout_write:\n"
2006-
" mov rcx, QWORD [rel stdout_fd]\n"
2005+
" mov rcx, QWORD PTR [rip + stdout_fd]\n"
20072006
" jmp write_file\n"
20082007
"stderr_write:\n"
2009-
" mov rcx, QWORD [rel stderr_fd]\n"
2010-
" ; fall through to write_file\n"
2008+
" mov rcx, QWORD PTR [rip + stderr_fd]\n"
2009+
" # fall through to write_file\n"
20112010
"\n"
2012-
"; rcx - fd, rdx - buff, r8 - chars / buffsize -> rax - number read/written\n"
2011+
"# rcx - fd, rdx - buff, r8 - chars / buffsize -> rax - number read/written\n"
20132012
"write_file:\n"
2014-
" mov rax, WriteFile\n"
2013+
" lea rax, [rip + WriteFile]\n"
20152014
" jmp call_winapi_file_op\n"
20162015
"read_file:\n"
2017-
" mov rax, ReadFile\n"
2016+
" lea rax, [rip + ReadFile]\n"
20182017
"call_winapi_file_op:\n"
2019-
" mov rbp, rsp ; save rsp @ retval\n"
2020-
" and rsp, -16 ; force 16-byte alignment\n"
2021-
" push 0 ; number of bytes written/read var\n"
2022-
" mov r9, rsp ; ptr to that var\n"
2023-
" push 0 ; OVERLAPPED struct null ptr (5th arg) & still aligned\n"
2024-
" sub rsp, 32 ; reserve shadow space\n"
2018+
" mov rbp, rsp # save rsp @ retval\n"
2019+
" and rsp, -16 # force 16-byte alignment\n"
2020+
" push 0 # number of bytes written/read var\n"
2021+
" mov r9, rsp # ptr to that var\n"
2022+
" push 0 # OVERLAPPED struct null ptr (5th arg) & still aligned\n"
2023+
" sub rsp, 32 # reserve shadow space\n"
20252024
" call rax\n"
2026-
" add rsp, 32+8 ; remove shadow space & overlapped\n"
2027-
" pop rax ; num written / read\n"
2025+
" add rsp, 32+8 # remove shadow space & overlapped\n"
2026+
" pop rax # num written / read\n"
20282027
" mov rsp, rbp\n"
20292028
" ret\n"
20302029
"stdin_read:\n"
2031-
" mov rcx, stdin_fd ; get chars into stdin_buff\n"
2032-
" mov rcx, [rcx]\n"
2033-
" mov rdx, stdin_buff\n"
2034-
" mov r8, STDIN_BUFF_SIZE\n"
2030+
" mov rcx, QWORD PTR [rip + stdin_fd] # get chars into stdin_buff\n"
2031+
" lea rdx, [rip + stdin_buff]\n"
2032+
" mov r8, OFFSET FLAT:STDIN_BUFF_SIZE\n"
20352033
" call read_file\n"
20362034
"\n"
2037-
" mov rcx, stdin_buff_char_count ; store how many were read\n"
2038-
" mov [rcx], rax\n"
2039-
" mov rcx, stdin_buff_chars_read ; 0 chars were processed\n"
2040-
" mov QWORD [rcx], 0\n"
2035+
" mov QWORD PTR [rip + stdin_buff_char_count], rax # store how many were read\n"
2036+
" mov QWORD PTR [rip + stdin_buff_chars_read], 0 # 0 chars were processed\n"
20412037
" ret\n"
20422038
"\n"
2043-
"stdin_peek: ; returns next raw stdin char, does not advance read ptr -> rdx char\n"
2044-
" mov rax, stdin_buff_char_count ; if (char_count == chars_read) fill the stdin_buff\n"
2045-
" mov rcx, [rax]\n"
2046-
" mov rax, stdin_buff_chars_read\n"
2047-
" cmp rcx, [rax]\n"
2039+
"stdin_peek: # returns next raw stdin char, does not advance read ptr -> rdx char\n"
2040+
" mov rcx, QWORD PTR [rip + stdin_buff_char_count] # if (char_count == chars_read) fill the stdin_buff\n"
2041+
" mov rdx, QWORD PTR [rip + stdin_buff_chars_read]\n"
2042+
" cmp rcx, rdx\n"
20482043
" jne stdin_peek_valid\n"
20492044
" call stdin_read\n"
20502045
"stdin_peek_valid:\n"
2051-
" mov rax, stdin_buff_chars_read ; char addr\n"
2052-
" mov rcx, stdin_buff\n"
2053-
" add rcx, [rax]\n"
2046+
" mov rax, [rip + stdin_buff_chars_read] # chars read\n"
2047+
" lea rcx, [rip + stdin_buff]\n"
2048+
" add rcx, rax\n"
20542049
"\n"
2055-
" xor rdx, rdx ; peek the char\n"
2050+
" xor rdx, rdx # peek the char\n"
20562051
" mov dl, [rcx]\n"
20572052
" ret\n"
2058-
"get_next_char: ; gets next char from stdin (buffered), advances read ptr -> rdx char\n"
2059-
" call stdin_peek ; peek the first unread char\n"
2060-
" mov rax, stdin_buff_chars_read ; eat the char\n"
2061-
" inc QWORD [rax]\n"
2053+
"get_next_char: # gets next char from stdin (buffered), advances read ptr -> rdx char\n"
2054+
" call stdin_peek # peek the first unread char\n"
2055+
" inc QWORD PTR [rip + stdin_buff_chars_read] # eat the char\n"
20622056
" ret\n"
20632057
"\n"
2064-
"utos: ; n - rax -> r8 char count, r9 - char* str\n"
2065-
" xor r8, r8 ; char count\n"
2066-
" mov r9, stdout_buff+STDOUT_BUFF_SIZE-1 ; curr buff pos\n"
2067-
" mov r10, 10 ; base\n"
2058+
"utos: # n - rax -> r8 char count, r9 - char* str\n"
2059+
" xor r8, r8 # char count\n"
2060+
" lea r9, [rip + stdout_buff+STDOUT_BUFF_SIZE-1] # curr buff pos\n"
2061+
" mov r10, 10 # base\n"
20682062
"utos_loop:\n"
20692063
" xor rdx, rdx\n"
20702064
" div r10\n"
@@ -2077,35 +2071,34 @@ void generate(ofstream& outFile, vector<Instr>& instrs) {
20772071
" cmp rax, 0\n"
20782072
" jne utos_loop\n"
20792073
" ret\n"
2080-
"print_unsigned: ; rax - n -> rax - num written\n"
2074+
"print_unsigned: # rax - n -> rax - num written\n"
20812075
" call utos\n"
2082-
" mov rdx, r9 ; str\n"
2076+
" mov rdx, r9 # str\n"
20832077
" call stdout_write\n"
20842078
" ret\n"
2085-
"print_unsigned_err: ; rax - n -> rax - num written\n"
2079+
"print_unsigned_err: # rax - n -> rax - num written\n"
20862080
" call utos\n"
2087-
" mov rcx, stderr_fd\n"
2088-
" mov rcx, [rcx]\n"
2089-
" mov rdx, r9 ; str\n"
2081+
" mov rcx, QWORD PTR [rip + stderr_fd]\n"
2082+
" mov rdx, r9 # str\n"
20902083
" call write_file\n"
20912084
" ret\n"
2092-
"input_unsigned: ; consumes all numeric chars, constructs uint out of them -> rax num\n"
2093-
" xor rax, rax ; out\n"
2085+
"input_unsigned: # consumes all numeric chars, constructs uint out of them -> rax num\n"
2086+
" xor rax, rax # out\n"
20942087
"input_unsigned_loop:\n"
20952088
" push rax\n"
2096-
" call stdin_peek ; get next char\n"
2097-
" sub rdx, '0' ; isdigit()\n"
2089+
" call stdin_peek # get next char\n"
2090+
" sub rdx, '0' # isdigit()\n"
20982091
" js input_unsigned_end\n"
20992092
" cmp rdx, 9\n"
21002093
" jg input_unsigned_end\n"
21012094
" push rdx\n"
21022095
"\n"
2103-
" call get_next_char ; eat the valid char\n"
2104-
" pop rcx ; add to parsed\n"
2096+
" call get_next_char # eat the valid char\n"
2097+
" pop rcx # add to parsed\n"
21052098
" pop rax\n"
21062099
" mov r10, 10\n"
21072100
" mul r10\n"
2108-
" add rax, rcx ; rax = 10 * rax + rcx\n"
2101+
" add rax, rcx # rax = 10 * rax + rcx\n"
21092102
"\n"
21102103
" mov r10, 65535\n"
21112104
" cmp rax, r10\n"
@@ -2115,16 +2108,14 @@ void generate(ofstream& outFile, vector<Instr>& instrs) {
21152108
" pop rax\n"
21162109
" ret\n"
21172110
"\n"
2118-
"global _start\n"
2111+
".global _start\n"
21192112
"_start:\n"
2120-
" ; initialization\n"
2113+
" # initialization\n"
21212114
" call get_std_fds\n"
2122-
" mov rcx, stdin_buff_char_count\n"
2123-
" mov QWORD [rcx], 0\n"
2124-
" mov rcx, stdin_buff_chars_read\n"
2125-
" mov QWORD [rcx], 0\n"
2115+
" mov QWORD PTR [rip + stdin_buff_char_count], 0\n"
2116+
" mov QWORD PTR [rip + stdin_buff_chars_read], 0\n"
21262117
"\n"
2127-
" mov r13, cells\n"
2118+
" lea r13, QWORD PTR [rip + cells]\n"
21282119
" xor r14, r14\n"
21292120
" xor r15, r15\n"
21302121
"\n";
@@ -2133,47 +2124,50 @@ void generate(ofstream& outFile, vector<Instr>& instrs) {
21332124
for (int i = 0; i < instrs.size(); ++i) {
21342125
instr = instrs[i];
21352126
outFile << "instr_" << i << ":\n";
2136-
outFile << " ; " << instr.toStr() << '\n';
2127+
outFile << " # " << instr.toStr() << '\n';
21372128
genAssembly(outFile, instr, i);
21382129
}
21392130
outFile <<
21402131
"instr_"<< instrs.size() << ":\n"
21412132
" jmp end\n"
21422133
"\n"
2143-
"; runtime errors, expect instr number in rsi, errorneous value in rcx\n"
2134+
"# runtime errors, expect instr number in rsi, errorneous value in rcx\n"
21442135
"jmp_error:\n"
2145-
" mov rdx, jmp_error_message\n"
2146-
" mov r8, jmp_error_message_len\n"
2136+
" lea rdx, [rip + jmp_error_message]\n"
2137+
" mov r8, OFFSET FLAT:jmp_error_message_len\n"
21472138
" call error\n"
21482139
"\n"
21492140
"end:\n"
2150-
" ; exit(0)\n"
2141+
" # exit(0)\n"
21512142
" mov rax, 0\n"
21522143
" call exit\n"
21532144
"\n"
2154-
"section .bss\n"
2155-
" cells: resw " << CELLS << "\n"
2156-
" stdin_fd: resq 1\n"
2157-
" stdout_fd: resq 1\n"
2158-
" stderr_fd: resq 1\n"
2159-
" stdout_buff: resb STDOUT_BUFF_SIZE\n"
2160-
" stdin_buff_chars_read: resq 1\n"
2161-
" stdin_buff_char_count: resq 1\n"
2162-
" stdin_buff: resb STDIN_BUFF_SIZE\n"
2145+
".bss\n"
2146+
" .balign 8\n"
2147+
"\n"
2148+
" cells: .skip 2 * " << CELLS << " # resw for memory\n"
2149+
" stdin_fd: .skip 8\n"
2150+
" stdout_fd: .skip 8\n"
2151+
" stderr_fd: .skip 8\n"
2152+
" stdout_buff: .skip STDOUT_BUFF_SIZE # resb\n"
2153+
" stdin_buff: .skip STDIN_BUFF_SIZE # resb\n"
2154+
" stdin_buff_chars_read: .skip 8\n"
2155+
" stdin_buff_char_count: .skip 8\n"
2156+
"\n"
2157+
".data\n"
2158+
" .equ STDOUT_BUFF_SIZE, " << STDOUT_BUFF_SIZE << "\n"
2159+
" .equ STDIN_BUFF_SIZE, " << STDIN_BUFF_SIZE << "\n"
21632160
"\n"
2164-
"section .data\n"
2165-
" STDOUT_BUFF_SIZE: EQU " << STDOUT_BUFF_SIZE << "\n"
2166-
" STDIN_BUFF_SIZE: EQU " << STDIN_BUFF_SIZE << "\n"
2161+
" # error messages\n"
2162+
" ERROR_template: .ascii \"\\nERROR: instr_\"\n"
2163+
" .equ ERROR_template_len, . - ERROR_template\n"
21672164
"\n"
2168-
" ; error messages\n"
2169-
" ERROR_template: db 10,\"ERROR: instr_\"\n"
2170-
" ERROR_template_len: EQU $-ERROR_template\n"
2171-
" jmp_error_message: db \": jmp destination out of bounds: \"\n"
2172-
" jmp_error_message_len: EQU $-jmp_error_message\n"
2165+
" jmp_error_message: .ascii \": jmp destination out of bounds: \"\n"
2166+
" .equ jmp_error_message_len, . - jmp_error_message\n"
21732167
"\n"
2174-
" ; instruction addresses\n"
2175-
" instruction_count: EQU " << instrs.size() << "\n"
2176-
" instruction_offsets: dq ";
2168+
" # instruction addresses\n"
2169+
" .equ instruction_count, " << instrs.size() << "\n"
2170+
" instruction_offsets: .quad ";
21772171

21782172
outFile << "instr_0";
21792173
for (int i = 1; i <= instrs.size(); ++i) {
@@ -2304,17 +2298,18 @@ void removeFile(fs::path file) {
23042298
}
23052299
int compileAndRun(Flags& flags) {
23062300
runCmdEchoed({
2307-
"nasm", "-fwin64", "-g", "-F cv8",
2308-
flags.filePathStr("asm")
2301+
"gcc", "-c",
2302+
"-o", flags.filePathStr("obj"),
2303+
flags.filePathStr("s")
23092304
}, flags);
23102305
runCmdEchoed({
23112306
"gcc", "-nostartfiles", "-Wl,-e,_start", "-lkernel32",
23122307
"-o", flags.filePathStr("exe"), "-g", flags.filePathStr("obj")
23132308
}, flags);
23142309
if (flags.keepAsm) {
2315-
cout << "[NOTE] asm file: " << flags.filePath("asm") << ":183:1\n";
2310+
cout << "[NOTE] asm file: " << flags.filePath("s") << ":183:1\n";
23162311
} else {
2317-
removeFile(flags.filePath("asm"));
2312+
removeFile(flags.filePath("s"));
23182313
}
23192314
removeFile(flags.filePath("obj"));
23202315
if (flags.run) return runCmdEchoed({flags.filePathStr("exe")}, flags, false);
@@ -2330,7 +2325,7 @@ void run(Flags& flags) {
23302325
globalVm = VM();
23312326
interpret();
23322327
} else {
2333-
ofstream outFile = openOutputFile(flags.filePath("asm"));
2328+
ofstream outFile = openOutputFile(flags.filePath("s"));
23342329
generate(outFile, parseCtx.instrs);
23352330

23362331
exitCode = compileAndRun(flags);

0 commit comments

Comments
 (0)