From 452bb0318babd54987252a5193ec475642527970 Mon Sep 17 00:00:00 2001 From: IgorCielniak Date: Thu, 18 Dec 2025 20:18:39 +0100 Subject: [PATCH] added io --- a.out | Bin 11432 -> 10968 bytes a.sl | 1 + build/call_syntax_parens.asm | 379 +++++++++++++---- build/call_syntax_parens.o | Bin 4176 -> 5440 bytes build/loops_and_cmp.asm | 379 +++++++++++++---- build/loops_and_cmp.o | Bin 4208 -> 5504 bytes build/override_dup_compile_time.asm | 379 +++++++++++++---- build/override_dup_compile_time.o | Bin 4016 -> 5296 bytes build/string_puts.asm | 379 +++++++++++++---- build/string_puts.o | Bin 4368 -> 5648 bytes build/test_read_stdin.asm | 614 ++++++++++++++++++++++++++++ build/test_read_stdin.o | Bin 0 -> 5520 bytes hello.sl | 1 + main.sl | 1 + readstdin | Bin 0 -> 11592 bytes stat_offset | Bin 15968 -> 0 bytes stat_offset.c | 8 - stdlib/io.sl | 146 +++++++ stdlib/stdlib.sl | 91 ----- t.sl | 1 + test.sl | 1 + test_read_stdin.sl | 13 + tests/run_tests.py | 4 + 23 files changed, 1950 insertions(+), 447 deletions(-) create mode 100644 build/test_read_stdin.asm create mode 100644 build/test_read_stdin.o create mode 100755 readstdin delete mode 100755 stat_offset delete mode 100644 stat_offset.c create mode 100644 test_read_stdin.sl diff --git a/a.out b/a.out index b6e3423fb9143f7d6e8ff84ac6b3cd1ca7670fec..8fc096a4f6cf1138c8437db97978404737161db2 100755 GIT binary patch literal 10968 zcmeI2Uu;uV9LG<$7Q2DA=v+o1p~S0#fjK&eE)whz^xn`VM0t<|y=m976}EP1Zy7Tq zkTf&gl<5m3;va;>_@r-220l3Ggs8Y6CWeGW7em4fn1C-cLNb59bAIRE_RNjMSMN=F z&hLDFf6h7Idv23;_t3WZ%XK~Bg0-ge% z0-ge%0-ge%0-ge%0-ge%0-ge%0{=$^;-gP43;S4?eKS6~E)=d~(}&C`|-)`_kAZfS~{qJ#>Z{wqL7Mq~9p7(2msOcpEcHw}VyQ@@_4tm;PeIuf<0L zM?;LoM<4zGyN=3mEZ*_`!54JFtU$tJk#|}2=GuJzL4uqeD@Uu{ib)IX476Xcl_1Vdbi`w+r^S4&$>#yqe zHDl(_!xsQd9%%*&<@Ay3#Ty2!+iKv!>i}Q$Khg+Y)oSeT4Et`}o(u(ODYSK?+@u+0 zOAF$z+;|A9pqvoA6@5-LsEj%p_6p6g!6mA3RE}$5!(Jk|Vei($bDWqI$Ly`r33KpU z!0!()Lvvw)>Oj{AMV$4(qSZ;tJGB+u?lME&Qk3=zJTw;1$-Yb;5)g1?<3cz zm&JqP>>k%;gH&(^bbCrK-MC|vhqcvsRw4#!+yzaz3y()v8E$%MqHU}JHyF_E3FijE zJ~xnFo3ydT+)s*a;+!7VT0KU_L&wg;xegt>08j9@@VTn5`VnvHgX0?9I34SZL-x3P z#PHUY{(ytEjX^E^4)~_(c*6iF-wod3%g#Prxb+A3dxN_#`8E7ePuh>e9;ZLOKRY{p z8X8FfvI;id=3Gn*dl%Vg7LF55RG=s-S`wM_VkVIoP< zsZ38sX7=TB15_i^lNHvUOg2;KH7SfQBvl*`vk&GoR@zJ!_lRLC59vH2w?Ca1R$(wf zET6LkGNTYkb~Zy^tJu9yxT8*aj3al{trK;No6)3GQW^s`CO zTLzHOW_x#)H|^R|e^bie-!FI9U(7l--Z)V*k);W9Bu7?m+-#Q$<-ruud3V1987W8J zHTx5pEK4PbDX}=&iiyd!=Qi4_K^~hqXdt&4czI2g@N3zuNe_idaKFcVQeb=DgP^ zhVu1B8ZovCEX=Q$BoY%=M0CxfbK2T>Fd2IqJVE%#eEB`p91$sp<@=FhIA?yG8y@vJ zS4%{oHrg1z!?_tgI2T?mqGR}zwVay}@ARj{=(JKC=c~S!!ra3Dt>*s& D8~Fzo literal 11432 zcmeI2e{2**6vwBfr7b_aLl8(x%#oam22Of~KqE12rDiwY5fc#o16i-VYq@Z}t9N_+ zkT!xBko9aN1WkyjiHXKP{D+um#i*4-8bmcsl2x_AkK@24zobS!N+1(o`fB2V) zyGeIuKJU$&neY5)c5k2Uh&)_fRmJ30%^qaDl=%g~Hfk|TWk&7E^zn(pPo~lj>v2;+*jb=eWGM9!-o>g#PR1whC7uGF z0-ge%0-ge%0-ge%0-ge%0-ge%0-gf@M+G8-cQyE{Sk(F@GPt1Zt7fBj!sGQ2N)c`O z+pO1%H9@^_s9v*1hL!>J)gsY+?=#)136@IIt{3M7cTT`^2h$7Z>Rr}iBv=n2{JJ$o zRw%9s)@y~!tbb)>uy!*%vquJ}Zo{Od)ZZFuIXduwW*yY5@3ES;{ggRn2%q~u#hb78 zaP4a7=OhPdgNr+W91v!^OPW<`;{(wOSJ^;=Hg>v=*8%re!2LrA#@Y@{f;&3oCu`;7 zhbJ!7%AfrNhoe{MYp;P}p&Kp~vA{dE4U4*fP8xbp(Qhih(|1c|FR))%^U zAz~f()lyeT4ZS!cs25EkhT{)zB~%!km!r-02H{aB-I^2BEij2_9D$@r^WjqYEg#p}-jtzp?{eh`a8!4^|&c<2QtyL5NL(S$R@nh#_i|Xz$ zw4U@TSUtQa*sXirg|Yb%kOQm-R$Op&S}MMd-)c& zeYdc^aSPk)x3InD*tDY9JND?YUlvFOYe2Jp&&5=yJX|XQ9W{=^%^$_(5iNq+ zg+mL68gPKMnsvyYAQ(8V ztyP)_ zMH_dBTEo$%BdBL7YMmXLAgV)o+tsS`<#MhadIuX0^o8|ZUveBGa7u6!Y}OH&pE6vf zi1k$kypB*C8AfA;;Tjsmyy4KIFzYbQDcm-P0x-T$+MxFb-iLFIj~M!cXJ)%@iQ^_> zorqZ1Bi6560ljdA^-rg+od5(oH)_G&xCufVpC~waAU9GI#P_H&kMCDU`>&SEqdTDM zqst*DO<;k^q&ju3I(1lQD%NSd0)s+7@A4Gz6z~-A6z~-A6z~-A6!;G+kTbKPT#9Yz z+VsqZo}TeLh|ktF>_S=f5Wlxqv3c_MdvXZ!w2Fll9wOeV@TJ5bRd_q`wF+NB{Aq_N#Z*c zewuhu;Xe`ItMEUFzpL=e#E&Sv1}7f+`Ln{O62GYMS;T#}xAKVcHkbIl3ZG9rr0^xg zA5(Zc@jit=LVQ5stBAj#@F$7Cs_<^&`xTxcKBDj~#Lp=FdE#Y-?;_qfy;7gO#Fr@i zE#fN`zMptT;ryW%=4*?>OXUBO!jBO@s_^fKpHcW3;ujTuj(FpY%5nWg{2_&3BfeVU zb=A0Hs#uT0rxD+z@HxZ>6n;1H-3o6a{*J<1i7&pRvj0yJU#0NP#FGl&O}wD+H;JE7 z_{YRADf}DaY-VMDek8s~;paGqTcFZ^Y#e@#^9yBs)^}fZ`0fL~ox*2(_cfLC3uS!H zcVDx}->3KoIG@1$3cttZZSF8EJPvQMd3%Nb@^SbI;=2Ns{^zUlQ!`j}$~nIV{QdAX zo7&HHoL4h-T#e+f#%G=RWGa3?{yUB3dYO?kV_7ql&KQYJNz>R6OXU-6VT7PK#$Oq&M$iDImiyyMB9q^z0B zWcnyZvL`Ka-N|$^x6U9p-l=%LPqeu)n=}(fXTDn$<5{TAJu({-S&_?aj1kLbOo5Cr zI8r{HB&(V4S})9DJ3RW4Iqbv&wQG|@8slg1%k(L8Dnx#Tn$O`YQGv2!(EFLpsVu3SUnG40;z=ezDCUNIw?wSD2;;C3xuh}*j&hAeSSP4mFHpr3-F3sB=)`Xn_9;10Sms>mi6U%=0 and next is a pointer in [data_start, data_end] - mov rax, [r12] ; len or int value - mov rbx, [r12 + 8] ; possible address - cmp rax, 0 - jl puts_print_int - lea r8, [rel data_start] - lea r9, [rel data_end] - cmp rbx, r8 - jl puts_print_int - cmp rbx, r9 - jge puts_print_int - ; treat as string: (addr below len) - mov rdx, rax ; len - mov rsi, rbx ; addr - add r12, 16 ; pop len + addr - test rdx, rdx - jz puts_str_newline_only - mov rax, 1 - mov rdi, 1 - syscall -puts_str_newline_only: - mov byte [rel print_buf], 10 - mov rax, 1 - mov rdi, 1 - lea rsi, [rel print_buf] - mov rdx, 1 - syscall +word_c_40: + mov rax, [r12] + movzx rax, byte [rax] + mov [r12], rax ret - -puts_print_int: + ret +word_c_21: mov rax, [r12] add r12, 8 - mov rbx, rax - mov r8, 0 - cmp rbx, 0 - jge puts_abs - neg rbx - mov r8, 1 -puts_abs: - lea rsi, [rel print_buf_end] - mov rcx, 0 - mov r10, 10 - cmp rbx, 0 - jne puts_digits - dec rsi - mov byte [rsi], '0' - inc rcx - jmp puts_sign -puts_digits: -puts_loop: - xor rdx, rdx - mov rax, rbx - div r10 - add dl, '0' - dec rsi - mov [rsi], dl - inc rcx - mov rbx, rax - test rbx, rbx - jne puts_loop -puts_sign: - cmp r8, 0 - je puts_finish_digits - dec rsi - mov byte [rsi], '-' - inc rcx -puts_finish_digits: - mov byte [rsi + rcx], 10 - inc rcx - mov rax, 1 - mov rdi, 1 - mov rdx, rcx - mov r9, rsi - mov rsi, r9 - syscall + mov rbx, [r12] + mov [rbx], al + ret + ret +word_r_40: + mov rax, [r13] + sub r12, 8 + mov [r12], rax + ret ret word_dup: mov rax, [r12] @@ -271,20 +213,22 @@ word__21: add r12, 8 ret word_mmap: - mov r9, [r12] - add r12, 8 - mov r8, [r12] - add r12, 8 - mov r10, [r12] - add r12, 8 - mov rdx, [r12] - add r12, 8 - mov rsi, [r12] - add r12, 8 - mov rdi, [r12] - mov rax, 9 - syscall - mov [r12], rax + ; Save rsp and align to 16 bytes for syscall ABI + mov rax, rsp + and rsp, -16 + mov rdi, [r12+40] ; addr + mov rsi, [r12+32] ; length + mov rdx, [r12+24] ; prot + mov r10, [r12+16] ; flags + mov r8, [r12+8] ; fd + mov r9, [r12] ; offset + add r12, 48 ; pop 6 args + mov rax, 9 ; syscall: mmap + syscall + mov rsp, rax ; restore rsp + sub r12, 8 + mov [r12], rax ; push result + ret ret word_munmap: mov rsi, [r12] @@ -362,6 +306,267 @@ word_rpick: sub r12, 8 mov [r12], rax ret +word_read_file: + ; stack: path_ptr (top), path_len (next) + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + add r12, 16 ; pop args + + ; open(path_ptr, O_RDONLY=0, mode=0) + mov rax, 2 ; syscall: open + mov rdi, rsi ; filename + xor rsi, rsi ; flags = O_RDONLY + xor rdx, rdx ; mode = 0 + syscall + mov r10, rax ; save open() result + cmp rax, 0 + jl .fail_open + mov r8, rax ; fd + + ; use lseek to determine file size: lseek(fd, 0, SEEK_END) + mov rax, 8 ; syscall: lseek + mov rdi, r8 ; fd + xor rsi, rsi ; offset = 0 + mov rdx, 2 ; SEEK_END + syscall + mov r11, rax ; save lseek() result + cmp rax, 0 + jl .close_fail_lseek + mov rsi, rax ; length = size + + ; mmap(NULL, size, PROT_READ=1, MAP_PRIVATE=2, fd, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + ; rsi already holds length + mov rdx, 1 ; PROT_READ + mov r10, 2 ; MAP_PRIVATE + mov r8, r8 ; fd + xor r9, r9 ; offset = 0 + syscall + mov rbx, rax ; addr + mov r12, r12 ; (no-op, for debug) + mov rax, 3 ; syscall: close + mov rdi, r8 ; fd + syscall + cmp rbx, -4095 + jae .fail_mmap + sub r12, 16 + mov [r12], rsi ; len (rsi held length across syscall) + mov [r12 + 8], rbx ; addr + ret + +.close_fail_lseek: + mov rax, 3 + mov rdi, r8 + syscall + mov rax, r11 ; return lseek() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -1 + ret + +.fail_open: + mov rax, r10 ; return open() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -2 + ret + +.fail_mmap: + mov rax, -1 ; return mmap() error + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -3 + ret + ret +word_write_file: + ; stack: path_ptr (top), path_len, buf_ptr, buf_len + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + mov r15, [r12 + 16] ; buf_ptr (save in callee-saved r15) + mov r13, [r12 + 24] ; buf_len (save in callee-saved r13) + add r12, 32 ; pop 4 args (we saved buf info) + + ; open(path_ptr, O_WRONLY|O_CREAT|O_TRUNC, 0666) + mov rdi, rsi ; filename + mov rsi, 577 ; flags = O_WRONLY|O_CREAT|O_TRUNC + mov rdx, 438 ; mode = 0o666 + mov rax, 2 ; syscall: open + syscall + cmp rax, 0 + jl .fail_open + mov r9, rax ; save fd + + ; write(fd, buf_ptr, buf_len) -- use preserved r15/r13 which survive syscalls + mov rax, 1 ; syscall: write + mov rdi, r9 ; fd + mov rsi, r15 ; buf_ptr + mov rdx, r13 ; buf_len + syscall + mov r10, rax ; save write result + cmp r10, 0 + jl .fail_write + + ; close(fd) + mov rax, 3 ; syscall: close + mov rdi, r9 + syscall + + sub r12, 8 + mov [r12], r10 + ret + +.fail_write: + mov rax, 3 + mov rdi, r9 + syscall + sub r12, 8 + mov [r12], r10 + ret + +.fail_open: + sub r12, 8 + mov [r12], rax + ret + ret +word_read_stdin: + ; stack: max_len + mov r14, [r12] ; max_len + add r12, 8 ; pop max_len + + ; mmap(NULL, max_len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + mov rsi, r14 ; length + mov rdx, 3 ; PROT_READ|PROT_WRITE + mov r10, 34 ; MAP_PRIVATE|MAP_ANONYMOUS + mov r8, -1 ; fd = -1 + xor r9, r9 ; offset = 0 + syscall + cmp rax, -4095 + jae .fail_mmap + mov rbx, rax ; buffer addr + xor rcx, rcx ; bytes_read = 0 + +.read_loop: + mov rax, 0 ; syscall: read + mov rdi, 0 ; fd = stdin + lea rsi, [rbx + rcx] ; buf + offset + mov rdx, r14 + sub rdx, rcx ; remaining = max_len - bytes_read + syscall + cmp rax, 0 + je .done_read + js .read_error + add rcx, rax + cmp rcx, r14 + jl .read_loop + +.done_read: + ; push len (rcx) then addr (rbx) + sub r12, 16 + mov [r12], rcx + mov [r12 + 8], rbx + ret + +.read_error: + ; return negative errno in rax, addr = 0 + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], 0 + ret + +.fail_mmap: + sub r12, 16 + mov qword [r12], -1 + mov qword [r12 + 8], 0 + ret + ret +word_puts: + ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] + mov rax, [r12] ; len or int value + mov rbx, [r12 + 8] ; possible address + cmp rax, 0 + jl puts_print_int + lea r8, [rel data_start] + lea r9, [rel data_end] + cmp rbx, r8 + jl puts_print_int + cmp rbx, r9 + jge puts_print_int + ; treat as string: (addr below len) + mov rdx, rax ; len + mov rsi, rbx ; addr + add r12, 16 ; pop len + addr + test rdx, rdx + jz puts_str_newline_only + mov rax, 1 + mov rdi, 1 + syscall +puts_str_newline_only: + mov byte [rel print_buf], 10 + mov rax, 1 + mov rdi, 1 + lea rsi, [rel print_buf] + mov rdx, 1 + syscall + ret +puts_print_int: + mov rax, [r12] + add r12, 8 + mov rbx, rax + mov r8, 0 + cmp rbx, 0 + jge puts_abs + neg rbx + mov r8, 1 +puts_abs: + lea rsi, [rel print_buf_end] + mov rcx, 0 + mov r10, 10 + cmp rbx, 0 + jne puts_digits + dec rsi + mov byte [rsi], '0' + inc rcx + jmp puts_sign +puts_digits: +puts_loop: + xor rdx, rdx + mov rax, rbx + div r10 + add dl, '0' + dec rsi + mov [rsi], dl + inc rcx + mov rbx, rax + test rbx, rbx + jne puts_loop +puts_sign: + cmp r8, 0 + je puts_finish_digits + dec rsi + mov byte [rsi], '-' + inc rcx +puts_finish_digits: + mov byte [rsi + rcx], 10 + inc rcx + mov rax, 1 + mov rdi, 1 + mov rdx, rcx + mov r9, rsi + mov rsi, r9 + syscall + ret +word_write_buf: + mov rdx, [r12] ; len + mov rsi, [r12 + 8] ; addr + add r12, 16 ; pop len + addr + mov rax, 1 ; syscall: write + mov rdi, 1 ; fd = stdout + syscall + ret + ret word_main: ; push 2 sub r12, 8 diff --git a/build/call_syntax_parens.o b/build/call_syntax_parens.o index 1c32cdf479c8a9767945fe161f3424548bb9b27f..5f6143ae670264047e6def211ae7d05fa647b4b1 100644 GIT binary patch literal 5440 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 diff --git a/build/loops_and_cmp.asm b/build/loops_and_cmp.asm index 4127d7b..0fa23ec 100644 --- a/build/loops_and_cmp.asm +++ b/build/loops_and_cmp.asm @@ -18,82 +18,24 @@ _start: mov rdi, rax mov rax, 60 syscall -word_puts: - ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] - mov rax, [r12] ; len or int value - mov rbx, [r12 + 8] ; possible address - cmp rax, 0 - jl puts_print_int - lea r8, [rel data_start] - lea r9, [rel data_end] - cmp rbx, r8 - jl puts_print_int - cmp rbx, r9 - jge puts_print_int - ; treat as string: (addr below len) - mov rdx, rax ; len - mov rsi, rbx ; addr - add r12, 16 ; pop len + addr - test rdx, rdx - jz puts_str_newline_only - mov rax, 1 - mov rdi, 1 - syscall -puts_str_newline_only: - mov byte [rel print_buf], 10 - mov rax, 1 - mov rdi, 1 - lea rsi, [rel print_buf] - mov rdx, 1 - syscall +word_c_40: + mov rax, [r12] + movzx rax, byte [rax] + mov [r12], rax ret - -puts_print_int: + ret +word_c_21: mov rax, [r12] add r12, 8 - mov rbx, rax - mov r8, 0 - cmp rbx, 0 - jge puts_abs - neg rbx - mov r8, 1 -puts_abs: - lea rsi, [rel print_buf_end] - mov rcx, 0 - mov r10, 10 - cmp rbx, 0 - jne puts_digits - dec rsi - mov byte [rsi], '0' - inc rcx - jmp puts_sign -puts_digits: -puts_loop: - xor rdx, rdx - mov rax, rbx - div r10 - add dl, '0' - dec rsi - mov [rsi], dl - inc rcx - mov rbx, rax - test rbx, rbx - jne puts_loop -puts_sign: - cmp r8, 0 - je puts_finish_digits - dec rsi - mov byte [rsi], '-' - inc rcx -puts_finish_digits: - mov byte [rsi + rcx], 10 - inc rcx - mov rax, 1 - mov rdi, 1 - mov rdx, rcx - mov r9, rsi - mov rsi, r9 - syscall + mov rbx, [r12] + mov [rbx], al + ret + ret +word_r_40: + mov rax, [r13] + sub r12, 8 + mov [r12], rax + ret ret word_dup: mov rax, [r12] @@ -271,20 +213,22 @@ word__21: add r12, 8 ret word_mmap: - mov r9, [r12] - add r12, 8 - mov r8, [r12] - add r12, 8 - mov r10, [r12] - add r12, 8 - mov rdx, [r12] - add r12, 8 - mov rsi, [r12] - add r12, 8 - mov rdi, [r12] - mov rax, 9 - syscall - mov [r12], rax + ; Save rsp and align to 16 bytes for syscall ABI + mov rax, rsp + and rsp, -16 + mov rdi, [r12+40] ; addr + mov rsi, [r12+32] ; length + mov rdx, [r12+24] ; prot + mov r10, [r12+16] ; flags + mov r8, [r12+8] ; fd + mov r9, [r12] ; offset + add r12, 48 ; pop 6 args + mov rax, 9 ; syscall: mmap + syscall + mov rsp, rax ; restore rsp + sub r12, 8 + mov [r12], rax ; push result + ret ret word_munmap: mov rsi, [r12] @@ -362,6 +306,267 @@ word_rpick: sub r12, 8 mov [r12], rax ret +word_read_file: + ; stack: path_ptr (top), path_len (next) + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + add r12, 16 ; pop args + + ; open(path_ptr, O_RDONLY=0, mode=0) + mov rax, 2 ; syscall: open + mov rdi, rsi ; filename + xor rsi, rsi ; flags = O_RDONLY + xor rdx, rdx ; mode = 0 + syscall + mov r10, rax ; save open() result + cmp rax, 0 + jl .fail_open + mov r8, rax ; fd + + ; use lseek to determine file size: lseek(fd, 0, SEEK_END) + mov rax, 8 ; syscall: lseek + mov rdi, r8 ; fd + xor rsi, rsi ; offset = 0 + mov rdx, 2 ; SEEK_END + syscall + mov r11, rax ; save lseek() result + cmp rax, 0 + jl .close_fail_lseek + mov rsi, rax ; length = size + + ; mmap(NULL, size, PROT_READ=1, MAP_PRIVATE=2, fd, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + ; rsi already holds length + mov rdx, 1 ; PROT_READ + mov r10, 2 ; MAP_PRIVATE + mov r8, r8 ; fd + xor r9, r9 ; offset = 0 + syscall + mov rbx, rax ; addr + mov r12, r12 ; (no-op, for debug) + mov rax, 3 ; syscall: close + mov rdi, r8 ; fd + syscall + cmp rbx, -4095 + jae .fail_mmap + sub r12, 16 + mov [r12], rsi ; len (rsi held length across syscall) + mov [r12 + 8], rbx ; addr + ret + +.close_fail_lseek: + mov rax, 3 + mov rdi, r8 + syscall + mov rax, r11 ; return lseek() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -1 + ret + +.fail_open: + mov rax, r10 ; return open() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -2 + ret + +.fail_mmap: + mov rax, -1 ; return mmap() error + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -3 + ret + ret +word_write_file: + ; stack: path_ptr (top), path_len, buf_ptr, buf_len + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + mov r15, [r12 + 16] ; buf_ptr (save in callee-saved r15) + mov r13, [r12 + 24] ; buf_len (save in callee-saved r13) + add r12, 32 ; pop 4 args (we saved buf info) + + ; open(path_ptr, O_WRONLY|O_CREAT|O_TRUNC, 0666) + mov rdi, rsi ; filename + mov rsi, 577 ; flags = O_WRONLY|O_CREAT|O_TRUNC + mov rdx, 438 ; mode = 0o666 + mov rax, 2 ; syscall: open + syscall + cmp rax, 0 + jl .fail_open + mov r9, rax ; save fd + + ; write(fd, buf_ptr, buf_len) -- use preserved r15/r13 which survive syscalls + mov rax, 1 ; syscall: write + mov rdi, r9 ; fd + mov rsi, r15 ; buf_ptr + mov rdx, r13 ; buf_len + syscall + mov r10, rax ; save write result + cmp r10, 0 + jl .fail_write + + ; close(fd) + mov rax, 3 ; syscall: close + mov rdi, r9 + syscall + + sub r12, 8 + mov [r12], r10 + ret + +.fail_write: + mov rax, 3 + mov rdi, r9 + syscall + sub r12, 8 + mov [r12], r10 + ret + +.fail_open: + sub r12, 8 + mov [r12], rax + ret + ret +word_read_stdin: + ; stack: max_len + mov r14, [r12] ; max_len + add r12, 8 ; pop max_len + + ; mmap(NULL, max_len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + mov rsi, r14 ; length + mov rdx, 3 ; PROT_READ|PROT_WRITE + mov r10, 34 ; MAP_PRIVATE|MAP_ANONYMOUS + mov r8, -1 ; fd = -1 + xor r9, r9 ; offset = 0 + syscall + cmp rax, -4095 + jae .fail_mmap + mov rbx, rax ; buffer addr + xor rcx, rcx ; bytes_read = 0 + +.read_loop: + mov rax, 0 ; syscall: read + mov rdi, 0 ; fd = stdin + lea rsi, [rbx + rcx] ; buf + offset + mov rdx, r14 + sub rdx, rcx ; remaining = max_len - bytes_read + syscall + cmp rax, 0 + je .done_read + js .read_error + add rcx, rax + cmp rcx, r14 + jl .read_loop + +.done_read: + ; push len (rcx) then addr (rbx) + sub r12, 16 + mov [r12], rcx + mov [r12 + 8], rbx + ret + +.read_error: + ; return negative errno in rax, addr = 0 + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], 0 + ret + +.fail_mmap: + sub r12, 16 + mov qword [r12], -1 + mov qword [r12 + 8], 0 + ret + ret +word_puts: + ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] + mov rax, [r12] ; len or int value + mov rbx, [r12 + 8] ; possible address + cmp rax, 0 + jl puts_print_int + lea r8, [rel data_start] + lea r9, [rel data_end] + cmp rbx, r8 + jl puts_print_int + cmp rbx, r9 + jge puts_print_int + ; treat as string: (addr below len) + mov rdx, rax ; len + mov rsi, rbx ; addr + add r12, 16 ; pop len + addr + test rdx, rdx + jz puts_str_newline_only + mov rax, 1 + mov rdi, 1 + syscall +puts_str_newline_only: + mov byte [rel print_buf], 10 + mov rax, 1 + mov rdi, 1 + lea rsi, [rel print_buf] + mov rdx, 1 + syscall + ret +puts_print_int: + mov rax, [r12] + add r12, 8 + mov rbx, rax + mov r8, 0 + cmp rbx, 0 + jge puts_abs + neg rbx + mov r8, 1 +puts_abs: + lea rsi, [rel print_buf_end] + mov rcx, 0 + mov r10, 10 + cmp rbx, 0 + jne puts_digits + dec rsi + mov byte [rsi], '0' + inc rcx + jmp puts_sign +puts_digits: +puts_loop: + xor rdx, rdx + mov rax, rbx + div r10 + add dl, '0' + dec rsi + mov [rsi], dl + inc rcx + mov rbx, rax + test rbx, rbx + jne puts_loop +puts_sign: + cmp r8, 0 + je puts_finish_digits + dec rsi + mov byte [rsi], '-' + inc rcx +puts_finish_digits: + mov byte [rsi + rcx], 10 + inc rcx + mov rax, 1 + mov rdi, 1 + mov rdx, rcx + mov r9, rsi + mov rsi, r9 + syscall + ret +word_write_buf: + mov rdx, [r12] ; len + mov rsi, [r12 + 8] ; addr + add r12, 16 ; pop len + addr + mov rax, 1 ; syscall: write + mov rdi, 1 ; fd = stdout + syscall + ret + ret word_main: ; push 0 sub r12, 8 diff --git a/build/loops_and_cmp.o b/build/loops_and_cmp.o index e0f75f3c327b76d4333aafe9ec99f61f3f2f510f..8ccf0a9adac621dce047b126d4750b8244599d59 100644 GIT binary patch literal 5504 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 literal 4208 zcmbW4YiJx*6oBuxo4RSM8?=^K0&VFEDrwB4p#*E2Kx$`ngV0t)C=8qIrd`a=Zf9rv zfYcV2K! z=)aipR#eP0SU7Pj*hJu}<$pv_Ary<}zkMEGG24k27=lPq#hW7;h#-sQv#A|92SO)s?{PFVLXwm2V5HGJs zX?g>M8_(wr~#nct6`12B1XB~Z<&Xd_n&-|JAfT`!H- z1HKTxZ7EEFYMc*s=UUvEjMh;pKSy*Y9IId-fb_;9deKGL9&Cp0G{tlWRLVu7Qask6 zJIfWA(Eqlp_w6){GY;P4H*c%> z3mmGg0%C0ydhxx$(S`+3wNtpem;6KK!QPL-$9)t~xERJ4nt~wXgYF(5d|fyi?BxOLgF5lK)yI3emmn^$lhlBG2)|)CyAe8JVX2o#t+uuMdE)j`!exG*r>pG zRmvf;n(^0(H#7bQ@ixZK65qo3MdI5Tzf3&K_*cZAX8bDg_)2zE))8OFxawC(v@+gF_C1VmCjL0%+lXfv-$C4A+#r5}@jb*R7~f0$ zYsL=|zrnae{7&|<^epkUjK4sQ?2Py8(7mxy0w{Bz>h8UL1e zJ-)L7<45AF82^*_YR3O2j$d!VQ7`)#5)U(e2k`@puOa?COk5y_9cc2DX~9mC5>Fc&I|kjOUp1*`-jqI%E+2S2Nlg(Y11~~Qp-d? zStrxG)2=6`r5NemrjiEJW;(yeATyaNS;(oJNek>H%I-^9O3Lp~5VNwjLPk3nl5D0) zYZnHdRO)sw9@>$*-H+4m2RGXLy^yYuaD_ov=p>;dX>=rA*yhU}1Fiw}&gd8jXj8tt zq1AI&LMG$xE>kc)8SjPC!!1)nmfB&u8#g-K4p|^7Bg@}!F739%^2JOdZHl-tn6(VN zHAX8fQgATZ1b#Env5+EAk%VIcfz)K!&`nDbHA$jQLVsaUc#?s>INT=$k1alObMyrv u|C@rf&(-tN3k(Nx^qs4!@d!c~obOZEi!)nQagH)RNBnKZhovV$nEnAIhXOnR diff --git a/build/override_dup_compile_time.asm b/build/override_dup_compile_time.asm index a8380b5..380f3a4 100644 --- a/build/override_dup_compile_time.asm +++ b/build/override_dup_compile_time.asm @@ -18,82 +18,24 @@ _start: mov rdi, rax mov rax, 60 syscall -word_puts: - ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] - mov rax, [r12] ; len or int value - mov rbx, [r12 + 8] ; possible address - cmp rax, 0 - jl puts_print_int - lea r8, [rel data_start] - lea r9, [rel data_end] - cmp rbx, r8 - jl puts_print_int - cmp rbx, r9 - jge puts_print_int - ; treat as string: (addr below len) - mov rdx, rax ; len - mov rsi, rbx ; addr - add r12, 16 ; pop len + addr - test rdx, rdx - jz puts_str_newline_only - mov rax, 1 - mov rdi, 1 - syscall -puts_str_newline_only: - mov byte [rel print_buf], 10 - mov rax, 1 - mov rdi, 1 - lea rsi, [rel print_buf] - mov rdx, 1 - syscall +word_c_40: + mov rax, [r12] + movzx rax, byte [rax] + mov [r12], rax ret - -puts_print_int: + ret +word_c_21: mov rax, [r12] add r12, 8 - mov rbx, rax - mov r8, 0 - cmp rbx, 0 - jge puts_abs - neg rbx - mov r8, 1 -puts_abs: - lea rsi, [rel print_buf_end] - mov rcx, 0 - mov r10, 10 - cmp rbx, 0 - jne puts_digits - dec rsi - mov byte [rsi], '0' - inc rcx - jmp puts_sign -puts_digits: -puts_loop: - xor rdx, rdx - mov rax, rbx - div r10 - add dl, '0' - dec rsi - mov [rsi], dl - inc rcx - mov rbx, rax - test rbx, rbx - jne puts_loop -puts_sign: - cmp r8, 0 - je puts_finish_digits - dec rsi - mov byte [rsi], '-' - inc rcx -puts_finish_digits: - mov byte [rsi + rcx], 10 - inc rcx - mov rax, 1 - mov rdi, 1 - mov rdx, rcx - mov r9, rsi - mov rsi, r9 - syscall + mov rbx, [r12] + mov [rbx], al + ret + ret +word_r_40: + mov rax, [r13] + sub r12, 8 + mov [r12], rax + ret ret word_dup: mov rax, [r12] @@ -271,20 +213,22 @@ word__21: add r12, 8 ret word_mmap: - mov r9, [r12] - add r12, 8 - mov r8, [r12] - add r12, 8 - mov r10, [r12] - add r12, 8 - mov rdx, [r12] - add r12, 8 - mov rsi, [r12] - add r12, 8 - mov rdi, [r12] - mov rax, 9 - syscall - mov [r12], rax + ; Save rsp and align to 16 bytes for syscall ABI + mov rax, rsp + and rsp, -16 + mov rdi, [r12+40] ; addr + mov rsi, [r12+32] ; length + mov rdx, [r12+24] ; prot + mov r10, [r12+16] ; flags + mov r8, [r12+8] ; fd + mov r9, [r12] ; offset + add r12, 48 ; pop 6 args + mov rax, 9 ; syscall: mmap + syscall + mov rsp, rax ; restore rsp + sub r12, 8 + mov [r12], rax ; push result + ret ret word_munmap: mov rsi, [r12] @@ -362,6 +306,267 @@ word_rpick: sub r12, 8 mov [r12], rax ret +word_read_file: + ; stack: path_ptr (top), path_len (next) + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + add r12, 16 ; pop args + + ; open(path_ptr, O_RDONLY=0, mode=0) + mov rax, 2 ; syscall: open + mov rdi, rsi ; filename + xor rsi, rsi ; flags = O_RDONLY + xor rdx, rdx ; mode = 0 + syscall + mov r10, rax ; save open() result + cmp rax, 0 + jl .fail_open + mov r8, rax ; fd + + ; use lseek to determine file size: lseek(fd, 0, SEEK_END) + mov rax, 8 ; syscall: lseek + mov rdi, r8 ; fd + xor rsi, rsi ; offset = 0 + mov rdx, 2 ; SEEK_END + syscall + mov r11, rax ; save lseek() result + cmp rax, 0 + jl .close_fail_lseek + mov rsi, rax ; length = size + + ; mmap(NULL, size, PROT_READ=1, MAP_PRIVATE=2, fd, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + ; rsi already holds length + mov rdx, 1 ; PROT_READ + mov r10, 2 ; MAP_PRIVATE + mov r8, r8 ; fd + xor r9, r9 ; offset = 0 + syscall + mov rbx, rax ; addr + mov r12, r12 ; (no-op, for debug) + mov rax, 3 ; syscall: close + mov rdi, r8 ; fd + syscall + cmp rbx, -4095 + jae .fail_mmap + sub r12, 16 + mov [r12], rsi ; len (rsi held length across syscall) + mov [r12 + 8], rbx ; addr + ret + +.close_fail_lseek: + mov rax, 3 + mov rdi, r8 + syscall + mov rax, r11 ; return lseek() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -1 + ret + +.fail_open: + mov rax, r10 ; return open() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -2 + ret + +.fail_mmap: + mov rax, -1 ; return mmap() error + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -3 + ret + ret +word_write_file: + ; stack: path_ptr (top), path_len, buf_ptr, buf_len + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + mov r15, [r12 + 16] ; buf_ptr (save in callee-saved r15) + mov r13, [r12 + 24] ; buf_len (save in callee-saved r13) + add r12, 32 ; pop 4 args (we saved buf info) + + ; open(path_ptr, O_WRONLY|O_CREAT|O_TRUNC, 0666) + mov rdi, rsi ; filename + mov rsi, 577 ; flags = O_WRONLY|O_CREAT|O_TRUNC + mov rdx, 438 ; mode = 0o666 + mov rax, 2 ; syscall: open + syscall + cmp rax, 0 + jl .fail_open + mov r9, rax ; save fd + + ; write(fd, buf_ptr, buf_len) -- use preserved r15/r13 which survive syscalls + mov rax, 1 ; syscall: write + mov rdi, r9 ; fd + mov rsi, r15 ; buf_ptr + mov rdx, r13 ; buf_len + syscall + mov r10, rax ; save write result + cmp r10, 0 + jl .fail_write + + ; close(fd) + mov rax, 3 ; syscall: close + mov rdi, r9 + syscall + + sub r12, 8 + mov [r12], r10 + ret + +.fail_write: + mov rax, 3 + mov rdi, r9 + syscall + sub r12, 8 + mov [r12], r10 + ret + +.fail_open: + sub r12, 8 + mov [r12], rax + ret + ret +word_read_stdin: + ; stack: max_len + mov r14, [r12] ; max_len + add r12, 8 ; pop max_len + + ; mmap(NULL, max_len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + mov rsi, r14 ; length + mov rdx, 3 ; PROT_READ|PROT_WRITE + mov r10, 34 ; MAP_PRIVATE|MAP_ANONYMOUS + mov r8, -1 ; fd = -1 + xor r9, r9 ; offset = 0 + syscall + cmp rax, -4095 + jae .fail_mmap + mov rbx, rax ; buffer addr + xor rcx, rcx ; bytes_read = 0 + +.read_loop: + mov rax, 0 ; syscall: read + mov rdi, 0 ; fd = stdin + lea rsi, [rbx + rcx] ; buf + offset + mov rdx, r14 + sub rdx, rcx ; remaining = max_len - bytes_read + syscall + cmp rax, 0 + je .done_read + js .read_error + add rcx, rax + cmp rcx, r14 + jl .read_loop + +.done_read: + ; push len (rcx) then addr (rbx) + sub r12, 16 + mov [r12], rcx + mov [r12 + 8], rbx + ret + +.read_error: + ; return negative errno in rax, addr = 0 + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], 0 + ret + +.fail_mmap: + sub r12, 16 + mov qword [r12], -1 + mov qword [r12 + 8], 0 + ret + ret +word_puts: + ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] + mov rax, [r12] ; len or int value + mov rbx, [r12 + 8] ; possible address + cmp rax, 0 + jl puts_print_int + lea r8, [rel data_start] + lea r9, [rel data_end] + cmp rbx, r8 + jl puts_print_int + cmp rbx, r9 + jge puts_print_int + ; treat as string: (addr below len) + mov rdx, rax ; len + mov rsi, rbx ; addr + add r12, 16 ; pop len + addr + test rdx, rdx + jz puts_str_newline_only + mov rax, 1 + mov rdi, 1 + syscall +puts_str_newline_only: + mov byte [rel print_buf], 10 + mov rax, 1 + mov rdi, 1 + lea rsi, [rel print_buf] + mov rdx, 1 + syscall + ret +puts_print_int: + mov rax, [r12] + add r12, 8 + mov rbx, rax + mov r8, 0 + cmp rbx, 0 + jge puts_abs + neg rbx + mov r8, 1 +puts_abs: + lea rsi, [rel print_buf_end] + mov rcx, 0 + mov r10, 10 + cmp rbx, 0 + jne puts_digits + dec rsi + mov byte [rsi], '0' + inc rcx + jmp puts_sign +puts_digits: +puts_loop: + xor rdx, rdx + mov rax, rbx + div r10 + add dl, '0' + dec rsi + mov [rsi], dl + inc rcx + mov rbx, rax + test rbx, rbx + jne puts_loop +puts_sign: + cmp r8, 0 + je puts_finish_digits + dec rsi + mov byte [rsi], '-' + inc rcx +puts_finish_digits: + mov byte [rsi + rcx], 10 + inc rcx + mov rax, 1 + mov rdi, 1 + mov rdx, rcx + mov r9, rsi + mov rsi, r9 + syscall + ret +word_write_buf: + mov rdx, [r12] ; len + mov rsi, [r12 + 8] ; addr + add r12, 16 ; pop len + addr + mov rax, 1 ; syscall: write + mov rdi, 1 ; fd = stdout + syscall + ret + ret word_main: ; push 6 sub r12, 8 diff --git a/build/override_dup_compile_time.o b/build/override_dup_compile_time.o index 85ecd1a07f981191f7cf41383313a9a41b3be7a3..9e335bb5f6c5c24b2660a7fec71fe114e8089a61 100644 GIT binary patch literal 5296 zcmbW4YiJx*6oBuVq)poD1}!B>v{hDYQP(_LG`4D@jm+q*_^5wG9XHu&J9M)fW@no! z=|h)@!#0RmMezyxqd!zcL1KKR-Pp9&KI|W>6%mP4tU_C)5gT34x%bS@5;zP>Sd6>22Blg8k6 zIQk_Gp$+FV~BWv8StW-YN9LZ?$15 z&Cm_V*T!lq3evjx5D>31rh6b#4kaoYv3lKGq`2-q6sw;mL?Z*O*ZM+OLoOY7reM%P zSWzw^W#GgQ7($%3NO4`PL4~o79H6TPnMu74ZW@$%*bNm;k3flJBpB9;@MPjz2weiS z11VPZC2ivTY;vPCnn?v?$Ak&JfK`Pl} zTppAPdO-7j)C%LL^0`K*dB=@Ysr48biSF8?4V;MX+6$d~06xdGE561}{cpXxKu<$IBVauev>0w( z;df}PP658K_rD0WH%x%aY;cFas^k&CwTFW9B9ntMfQQlgA$+W8-h|eCPHR2}=g!-! z75)^_olgSSy^$e2%7!-v@?lg(jS_0~cWT}~Sv#${JdB6FLnI?l{TM85m@3<1dqhJj7rwmug@QzM_{~*-HMo>6K@HYye z3g8!0OTezfHmC8}j4p%xKI?$!hd+ckWyTN>=5U+t?HR(@4eyBI{bP8)$_nU(zeN8f z6xtC$aB>qKoQ)X}%H&3s64W$)Q4H_gFs9!zd?kGADri-kn`J2ssFBuuKt2XP2Nj_W zu3Tt%XSEeys`%UmTb5{%Jx1G^{_j+__?*JBP01Zi6&b6J$;x2;BvqY8YURWG<~3>MJ*OI>^EBA~iL*QQ0yzBi z5};U{ffM<09rnqslgift-dBCm0=R{u@xIi(Glq9qhO!v8-=)sR@F@rA4BRFt556IP zISFm#1DK1Fh`ZJnSHx3EH!0#>xtxgSHs)N%O?JWPu^x4&xnrf1N*`_KyfB1nai%ep5xIv+-B*zhP3FC)} z-^BR0#2;Y%C*oa%YT~@*nus^D zR$N2;M#eSb>lnY6_@j(JNZe&SMf^R+dx`I7{Bh#P87~m$N2W-8Is3i4i}-5BUn6cX zzMJ^NjDJA9i}6p1_c5;aDIx|L|AzE0Wk0$nh_^9bFY}LxyBS|Wd?Vv+#P>6<_Aeq% zFrFd(pBdjq{4)8Dkj*N;UL<}y57zsGRWxW#nXM@wHV5O@ zZeM}YHCwwwQY#qyRWSV`^z``I_2e^^F_urcOlD}oER`eUCvLX-6>?yxw4ET|UfVB+ z6B=5{l(`8kIRVCS$|XIR7q0VjAi0H6k*5)y4SB@$cRPXn|E^pzo4HTGh_9o zZE%{+q#skX*ReCM2_H30c9C|<-eCKdGC1YK-jGp>>+Ou4+h~%SJP<1Tt~~WvPZE;F zpRjb2Pr=E8jZ`<&g~T02)J+l<7W%4;Oth7kJnk^UrvttMCg~Tg{1-8WtFyn8 kp0lWrwv+g;1g__1;h%*#`afS*evUFeNxaN>Kl=gmFKb{a)c^nh literal 4016 zcmbW4U1%It6oBuxN!_H;U8F5R1Esi%O1o{728|7xKq9ks^I{9W6o%RCq#e3{%+59~ zG+0;y9oC=^$wNS^FQN}VC|He^(zL5B^(Sf-TBr(wVxbCFkyJLYo^$V+pPVKU9N4|* ze&_d|duMj`#o_d`>mm{1T@mrL2xcA?VjvJn9uQH{5~BZ4#9a8u; zV2=Ll8Gn}tBs~i!?gbuQ!~dk9Ldc)zzkdZ^H1+a7L4MxAd)ozy6pXh=kY7ndP#b;2S}UhMd!0hT@P~B2W2H%wIL?jw8a~P(ud4H zLZ892?eL8Tm5o|+;nId(TJyrKE^YT!&Apyl{PW~R01KzK0M*>OHhH7+a|-Hq+NALg zz?WL?Ylk6Jjr&>3y`6R!Vy#rlZ_$+7lBi=JfD9#~sj7#tJ=lzt+m%SUpi(Xp)zXQ0 z%I#1*u8oh@+CFD@a{K%9G1B4A_3aNu2em&4{o}_jl(W%NfKmjmRr(8)K zi|Me>T>|t2Q?SxzwZ+D2bW*d2-OX!_W>abaz+BYvOI}IG zJm!dG)^H4w%#_O_Sw38LY{$rebUd#{n%id1Q1+hpsv|x+TEy+`=_7~fAk&$v$9W&8;7HyL+`UtoNK z_z#S`#Q$M@hWKXovT~aEHpbr~-plxV#Pf`wBR_Z72YE`D<15h^0_S7Pd&T} zPy1X7zP&ns7=Jl8$ezDP<6C2VrRQp~aX3{9< zg!#Y$@(wJ4S%7=9_lc}IUl{0IDy+l~NlFH)-F}vs}q<4cM$pwqF zPG$6nQg{3D(2msIL7eU&xZa)dLwbVY31gnnOF~ap@5y>_cOdtSdIr=xy=OF}H3NCi zF5g`V`MkHfe5K&axED%q6ewYl+EMTpuJ?EyvO!eVcCg-(<+Z~O#Jph@1pe&P?n}{x z6j?Y8V6O(*$96aWAK diff --git a/build/string_puts.asm b/build/string_puts.asm index d9d9ed8..c2882b4 100644 --- a/build/string_puts.asm +++ b/build/string_puts.asm @@ -18,82 +18,24 @@ _start: mov rdi, rax mov rax, 60 syscall -word_puts: - ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] - mov rax, [r12] ; len or int value - mov rbx, [r12 + 8] ; possible address - cmp rax, 0 - jl puts_print_int - lea r8, [rel data_start] - lea r9, [rel data_end] - cmp rbx, r8 - jl puts_print_int - cmp rbx, r9 - jge puts_print_int - ; treat as string: (addr below len) - mov rdx, rax ; len - mov rsi, rbx ; addr - add r12, 16 ; pop len + addr - test rdx, rdx - jz puts_str_newline_only - mov rax, 1 - mov rdi, 1 - syscall -puts_str_newline_only: - mov byte [rel print_buf], 10 - mov rax, 1 - mov rdi, 1 - lea rsi, [rel print_buf] - mov rdx, 1 - syscall +word_c_40: + mov rax, [r12] + movzx rax, byte [rax] + mov [r12], rax ret - -puts_print_int: + ret +word_c_21: mov rax, [r12] add r12, 8 - mov rbx, rax - mov r8, 0 - cmp rbx, 0 - jge puts_abs - neg rbx - mov r8, 1 -puts_abs: - lea rsi, [rel print_buf_end] - mov rcx, 0 - mov r10, 10 - cmp rbx, 0 - jne puts_digits - dec rsi - mov byte [rsi], '0' - inc rcx - jmp puts_sign -puts_digits: -puts_loop: - xor rdx, rdx - mov rax, rbx - div r10 - add dl, '0' - dec rsi - mov [rsi], dl - inc rcx - mov rbx, rax - test rbx, rbx - jne puts_loop -puts_sign: - cmp r8, 0 - je puts_finish_digits - dec rsi - mov byte [rsi], '-' - inc rcx -puts_finish_digits: - mov byte [rsi + rcx], 10 - inc rcx - mov rax, 1 - mov rdi, 1 - mov rdx, rcx - mov r9, rsi - mov rsi, r9 - syscall + mov rbx, [r12] + mov [rbx], al + ret + ret +word_r_40: + mov rax, [r13] + sub r12, 8 + mov [r12], rax + ret ret word_dup: mov rax, [r12] @@ -271,20 +213,22 @@ word__21: add r12, 8 ret word_mmap: - mov r9, [r12] - add r12, 8 - mov r8, [r12] - add r12, 8 - mov r10, [r12] - add r12, 8 - mov rdx, [r12] - add r12, 8 - mov rsi, [r12] - add r12, 8 - mov rdi, [r12] - mov rax, 9 - syscall - mov [r12], rax + ; Save rsp and align to 16 bytes for syscall ABI + mov rax, rsp + and rsp, -16 + mov rdi, [r12+40] ; addr + mov rsi, [r12+32] ; length + mov rdx, [r12+24] ; prot + mov r10, [r12+16] ; flags + mov r8, [r12+8] ; fd + mov r9, [r12] ; offset + add r12, 48 ; pop 6 args + mov rax, 9 ; syscall: mmap + syscall + mov rsp, rax ; restore rsp + sub r12, 8 + mov [r12], rax ; push result + ret ret word_munmap: mov rsi, [r12] @@ -362,6 +306,267 @@ word_rpick: sub r12, 8 mov [r12], rax ret +word_read_file: + ; stack: path_ptr (top), path_len (next) + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + add r12, 16 ; pop args + + ; open(path_ptr, O_RDONLY=0, mode=0) + mov rax, 2 ; syscall: open + mov rdi, rsi ; filename + xor rsi, rsi ; flags = O_RDONLY + xor rdx, rdx ; mode = 0 + syscall + mov r10, rax ; save open() result + cmp rax, 0 + jl .fail_open + mov r8, rax ; fd + + ; use lseek to determine file size: lseek(fd, 0, SEEK_END) + mov rax, 8 ; syscall: lseek + mov rdi, r8 ; fd + xor rsi, rsi ; offset = 0 + mov rdx, 2 ; SEEK_END + syscall + mov r11, rax ; save lseek() result + cmp rax, 0 + jl .close_fail_lseek + mov rsi, rax ; length = size + + ; mmap(NULL, size, PROT_READ=1, MAP_PRIVATE=2, fd, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + ; rsi already holds length + mov rdx, 1 ; PROT_READ + mov r10, 2 ; MAP_PRIVATE + mov r8, r8 ; fd + xor r9, r9 ; offset = 0 + syscall + mov rbx, rax ; addr + mov r12, r12 ; (no-op, for debug) + mov rax, 3 ; syscall: close + mov rdi, r8 ; fd + syscall + cmp rbx, -4095 + jae .fail_mmap + sub r12, 16 + mov [r12], rsi ; len (rsi held length across syscall) + mov [r12 + 8], rbx ; addr + ret + +.close_fail_lseek: + mov rax, 3 + mov rdi, r8 + syscall + mov rax, r11 ; return lseek() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -1 + ret + +.fail_open: + mov rax, r10 ; return open() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -2 + ret + +.fail_mmap: + mov rax, -1 ; return mmap() error + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -3 + ret + ret +word_write_file: + ; stack: path_ptr (top), path_len, buf_ptr, buf_len + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + mov r15, [r12 + 16] ; buf_ptr (save in callee-saved r15) + mov r13, [r12 + 24] ; buf_len (save in callee-saved r13) + add r12, 32 ; pop 4 args (we saved buf info) + + ; open(path_ptr, O_WRONLY|O_CREAT|O_TRUNC, 0666) + mov rdi, rsi ; filename + mov rsi, 577 ; flags = O_WRONLY|O_CREAT|O_TRUNC + mov rdx, 438 ; mode = 0o666 + mov rax, 2 ; syscall: open + syscall + cmp rax, 0 + jl .fail_open + mov r9, rax ; save fd + + ; write(fd, buf_ptr, buf_len) -- use preserved r15/r13 which survive syscalls + mov rax, 1 ; syscall: write + mov rdi, r9 ; fd + mov rsi, r15 ; buf_ptr + mov rdx, r13 ; buf_len + syscall + mov r10, rax ; save write result + cmp r10, 0 + jl .fail_write + + ; close(fd) + mov rax, 3 ; syscall: close + mov rdi, r9 + syscall + + sub r12, 8 + mov [r12], r10 + ret + +.fail_write: + mov rax, 3 + mov rdi, r9 + syscall + sub r12, 8 + mov [r12], r10 + ret + +.fail_open: + sub r12, 8 + mov [r12], rax + ret + ret +word_read_stdin: + ; stack: max_len + mov r14, [r12] ; max_len + add r12, 8 ; pop max_len + + ; mmap(NULL, max_len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + mov rsi, r14 ; length + mov rdx, 3 ; PROT_READ|PROT_WRITE + mov r10, 34 ; MAP_PRIVATE|MAP_ANONYMOUS + mov r8, -1 ; fd = -1 + xor r9, r9 ; offset = 0 + syscall + cmp rax, -4095 + jae .fail_mmap + mov rbx, rax ; buffer addr + xor rcx, rcx ; bytes_read = 0 + +.read_loop: + mov rax, 0 ; syscall: read + mov rdi, 0 ; fd = stdin + lea rsi, [rbx + rcx] ; buf + offset + mov rdx, r14 + sub rdx, rcx ; remaining = max_len - bytes_read + syscall + cmp rax, 0 + je .done_read + js .read_error + add rcx, rax + cmp rcx, r14 + jl .read_loop + +.done_read: + ; push len (rcx) then addr (rbx) + sub r12, 16 + mov [r12], rcx + mov [r12 + 8], rbx + ret + +.read_error: + ; return negative errno in rax, addr = 0 + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], 0 + ret + +.fail_mmap: + sub r12, 16 + mov qword [r12], -1 + mov qword [r12 + 8], 0 + ret + ret +word_puts: + ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] + mov rax, [r12] ; len or int value + mov rbx, [r12 + 8] ; possible address + cmp rax, 0 + jl puts_print_int + lea r8, [rel data_start] + lea r9, [rel data_end] + cmp rbx, r8 + jl puts_print_int + cmp rbx, r9 + jge puts_print_int + ; treat as string: (addr below len) + mov rdx, rax ; len + mov rsi, rbx ; addr + add r12, 16 ; pop len + addr + test rdx, rdx + jz puts_str_newline_only + mov rax, 1 + mov rdi, 1 + syscall +puts_str_newline_only: + mov byte [rel print_buf], 10 + mov rax, 1 + mov rdi, 1 + lea rsi, [rel print_buf] + mov rdx, 1 + syscall + ret +puts_print_int: + mov rax, [r12] + add r12, 8 + mov rbx, rax + mov r8, 0 + cmp rbx, 0 + jge puts_abs + neg rbx + mov r8, 1 +puts_abs: + lea rsi, [rel print_buf_end] + mov rcx, 0 + mov r10, 10 + cmp rbx, 0 + jne puts_digits + dec rsi + mov byte [rsi], '0' + inc rcx + jmp puts_sign +puts_digits: +puts_loop: + xor rdx, rdx + mov rax, rbx + div r10 + add dl, '0' + dec rsi + mov [rsi], dl + inc rcx + mov rbx, rax + test rbx, rbx + jne puts_loop +puts_sign: + cmp r8, 0 + je puts_finish_digits + dec rsi + mov byte [rsi], '-' + inc rcx +puts_finish_digits: + mov byte [rsi + rcx], 10 + inc rcx + mov rax, 1 + mov rdi, 1 + mov rdx, rcx + mov r9, rsi + mov rsi, r9 + syscall + ret +word_write_buf: + mov rdx, [r12] ; len + mov rsi, [r12 + 8] ; addr + add r12, 16 ; pop len + addr + mov rax, 1 ; syscall: write + mov rdi, 1 ; fd = stdout + syscall + ret + ret word_main: ; push str_0 sub r12, 8 diff --git a/build/string_puts.o b/build/string_puts.o index 4e953ac2727c6a9d49c4396d7cfc072ac5fdb5f5..9035e65f96635884c9a20c7119979c329c84544f 100644 GIT binary patch literal 5648 zcmbW5eQX?85y0OicI!By=YCLJa3NHONJV@2&Z)p8MRuFCyJ!!!YUm$TVLAIY@u}-O zYj3Z1kyFxILD^o7iU<`{d{v?XRTWf1RK`?^lXK&yA4wbakANvcB9!nYk_y#@m>x6p zW^eb#c92-fyYqfC^WMz7kKOZEcUrftOC(fyCDdnC)C#Fm1Chw`fa*|fG5Y_BI2Qh0 zBHRboY4Da%bP2mlp^g6Q1@GOU!8L-*h~EeL4)~M)cd-9H#er}?a{Mb+@kP_n|5NN2 zK4fisK+!sawtS4oe-;yj3(IgP{9&wkb?b*p!BfVLs)5V3!J9%U$G-v0WKGa>^ZT{` zIsH)W@I+rZzBT8uN(&JgQg_B+g4Tgsf8?=XUene9N6?MRH|bIJ_b zQuTVMH)}nq1M9K9Q<+nL>xgT)h24ODN2;S~K;E@`fdoA%GXRzDkWkG^b(z5?&CTH6 zRM!e6I$7wwBUHi|G<4K62ZJ5N4QU9{K__9r5aNnKYP(Y1I*eW10e00*nRJ=ZO}BQB zcf&<96Hp?G1jD*M-dMT;LMMQJpv9_w$5^_s7QHIg6V%%1um1`sDS5DtwTniH>%Mgn z-FGjd`@uzY-@l0Ndy&ql=>^iv9^(q2RImn&;P=MVnR8}sGPT95`Kiq&);I^Zt{g6p zTn#3DYQA>{_fWFk2>UZkz{*guy%c*NMhm^^qCR_<~5 zJ7s+Ib)3}yZMPw^Gq9gI@Scm77*5^P-(g|xRL~c${TE`(8yY|<8=T=+nt4QU$E(qP zq2!XCsJoYpEh z3Kn2~8gSLE;I$U`9ztVb4wWs6|DXb@0R3WWIhb{rW*4{3{AS4S&>%!V`y9kc8ACjn z!!2fTWCmlmf|FM8o)!FsDqv3iTTNccp`8Q-J2w}=-dF{pjwY&}<3$q|#R}e;#qhc#y0{!)^=GZJYvxVFPXu4 zD>y-+Tm{qb^UB8XIR{u7I89I{^8tEBx7(TD5h0TB+XcTM zzC_RHb`OaObzg)?Dli`tyu|!L!6%r1L-2=~|5Wg4<}VBWIP=qj|B(4V1%I0PWjH~x z>lY*^)RltIG5?I_#=E8BlraErMw_}$E(6KVv>FIGx$BzorF0&h{S^ANhY~-Y@t%%0Hn# zFZhR;j|lz=<}V6<8}miM_53B&9|a#{`)lc)6fKlTnBOY+kC@*n_+jS5g8!QNR|Nk9 z^XCQs7xUi=-a++EsAa(~XZ{iKd-d8i_{W)V6ZRSApA&os^F4y!#r$Ex^?ITtqGEzH zLiQ_piTL>jzB%L91lwwY?P2JDe z;PjnFo3}OR7n=61{3LVvyZ-|)QrBwl*`aFDEqoH*@Ws*|d#vhL()r4$vMYYx^ZAi3 zm2GFD=-c<_-KwMDDVx!f*JOq2m_`M!%u@M&$J4Abo@eHjeU0oa7_wX{ zvevH-->22tW`AhM>TJ|cHtO8Y4mG%x|tth>q2o)G4!P1bRWe%C2hF7SSnUVY&N3}p|c;V@){e>L$df0%{vLl?^SfS zU8p)r8GUcIv((N~n_L}OD+SnzF!B0f`%oxP6a65f)4;Ktl8wG_(QyDzJSFgzwaj1O z^ed}{>+|SQelMUs`Yz+IHn_eiIRAT19g1=6|3X9e^P1qx%o~DF@(0%=eE#G49mWiz P`mx~QIX*9VcwYY(`pH+v literal 4368 zcmbW4Z)jUp6u@t`c1yd?MA>GQ;x>(-($zNEkYd$VT6xhFbes5P@<^7n3rk)~^3ra& z;UpCI$O;a+4+EVaMEo`p{L@Xut#KP}T5$@BV}4QDKnL6W&`AsNoO{pBdp&I`c;V%q z`#b;cJ@>u)US1!FJ-5Q=6T11t)50BTDnzdgj*zlU5-zHk)gH6Wl zl|Jc1=BLo7?{qW#qCs(uQJp!zs?(^R{j<&Jx@NJEZSO*~eA%C=_5tavw5p~)^Q3q7Y zMWS*n6pT78ibtJYq2MAVI>petUn?PpN>+g%~!)5Eiqu#-6J4{^y^aE3{GL9RwbM@#tPo#2N$mp(ojvE-5 ztYGcjEMDEQWpr;ZqkDH5-HBy%@3=anEZlvN>w`HvP%5|w2FtLiAPiDv2FvTH2D;x$ zIz9yj#A?V4OW1LK?l z?=uURRk{H;)qsFl10q^F=ef0E0936McJ~|iCab~zZ^1`D3MgD?zynP|ka3OIFU?h} z(rPK?$vR4ma{VY%R)pA-%4Bkz#&Y>gQe@Irs;e1)!)UHrhn?DIi;iU6j*E^&p&&X6 zdkS{mjwe9cpH)4L^QlZ+*=z5*JswRB;#PGjgO&1RU94HThL#+|IO^n#8+UUJne*(ePScy9}sV6{3GIB zjLWkE>ii7j=g59L<1@r_jQ>LX2;;vIKhF3K;-4@+OZ+>=)%tznN5)E667V*uDt9|l`ZH&K1_F2Y1BtFjgDdNW%pCQ{5tct)v}I0@jT;qOU{Z6j%{`LgOcB>;)(5T?PTBLg&>FP*!PgV{=U_2 z&yu|!>pn*I{5$_;$yqVMX;+QQg6J?}xDK~!TnaV&{dIVWIRD>pFL(x*I_DF`bSC*Y zykXMTusKq+3mx%7R+t4lp0}y%uySTWB3{~b5>@* zq9YK`HsMmkc%q<$WO_Jllbp%rMkq#l*izC^+DaGpm}DkXC5s~}XEG1=66Hoyc_kIb z;>7YfTOl(Hh9p~Q(%Qw{dzCs|i-&fk4!d!}Zg4Z4sD;!*Tnj^5*hWGmX-1M7cDZt7 zw>F^KnUUQdZOWCmcGldLkj?7VWs6o##=TJbxJ3zbR1Qlo+>Gc7)y diff --git a/build/test_read_stdin.asm b/build/test_read_stdin.asm new file mode 100644 index 0000000..52d8069 --- /dev/null +++ b/build/test_read_stdin.asm @@ -0,0 +1,614 @@ +section .text +%define DSTK_BYTES 65536 +%define RSTK_BYTES 65536 +%define PRINT_BUF_BYTES 128 +global _start +_start: + ; initialize data/return stack pointers + lea r12, [rel dstack_top] + mov r15, r12 + lea r13, [rel rstack_top] + call word_main + mov rax, 0 + cmp r12, r15 + je .no_exit_value + mov rax, [r12] + add r12, 8 +.no_exit_value: + mov rdi, rax + mov rax, 60 + syscall +word_c_40: + mov rax, [r12] + movzx rax, byte [rax] + mov [r12], rax + ret + ret +word_c_21: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + mov [rbx], al + ret + ret +word_r_40: + mov rax, [r13] + sub r12, 8 + mov [r12], rax + ret + ret +word_puts: + ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] + mov rax, [r12] ; len or int value + mov rbx, [r12 + 8] ; possible address + cmp rax, 0 + jl puts_print_int + lea r8, [rel data_start] + lea r9, [rel data_end] + cmp rbx, r8 + jl puts_print_int + cmp rbx, r9 + jge puts_print_int + ; treat as string: (addr below len) + mov rdx, rax ; len + mov rsi, rbx ; addr + add r12, 16 ; pop len + addr + test rdx, rdx + jz puts_str_newline_only + mov rax, 1 + mov rdi, 1 + syscall +puts_str_newline_only: + mov byte [rel print_buf], 10 + mov rax, 1 + mov rdi, 1 + lea rsi, [rel print_buf] + mov rdx, 1 + syscall + ret + +puts_print_int: + mov rax, [r12] + add r12, 8 + mov rbx, rax + mov r8, 0 + cmp rbx, 0 + jge puts_abs + neg rbx + mov r8, 1 +puts_abs: + lea rsi, [rel print_buf_end] + mov rcx, 0 + mov r10, 10 + cmp rbx, 0 + jne puts_digits + dec rsi + mov byte [rsi], '0' + inc rcx + jmp puts_sign +puts_digits: +puts_loop: + xor rdx, rdx + mov rax, rbx + div r10 + add dl, '0' + dec rsi + mov [rsi], dl + inc rcx + mov rbx, rax + test rbx, rbx + jne puts_loop +puts_sign: + cmp r8, 0 + je puts_finish_digits + dec rsi + mov byte [rsi], '-' + inc rcx +puts_finish_digits: + mov byte [rsi + rcx], 10 + inc rcx + mov rax, 1 + mov rdi, 1 + mov rdx, rcx + mov r9, rsi + mov rsi, r9 + syscall + ret +word_dup: + mov rax, [r12] + sub r12, 8 + mov [r12], rax + ret +word_write_buf: + mov rdx, [r12] ; len + mov rsi, [r12 + 8] ; addr + add r12, 16 ; pop len + addr + mov rax, 1 ; syscall: write + mov rdi, 1 ; fd = stdout + syscall + ret + ret +word_drop: + add r12, 8 + ret +word_over: + mov rax, [r12 + 8] + sub r12, 8 + mov [r12], rax + ret +word_swap: + mov rax, [r12] + mov rbx, [r12 + 8] + mov [r12], rbx + mov [r12 + 8], rax + ret +word_rot: + mov rax, [r12] ; x3 + mov rbx, [r12 + 8] ; x2 + mov rcx, [r12 + 16] ; x1 + mov [r12], rcx ; top = x1 + mov [r12 + 8], rax ; next = x3 + mov [r12 + 16], rbx ; third = x2 + ret +word__2drot: + mov rax, [r12] ; x3 + mov rbx, [r12 + 8] ; x2 + mov rcx, [r12 + 16] ; x1 + mov [r12], rbx ; top = x2 + mov [r12 + 8], rcx ; next = x1 + mov [r12 + 16], rax ; third = x3 + ret +word_nip: + mov rax, [r12] + add r12, 8 ; drop lower element + mov [r12], rax ; keep original top + ret +word_tuck: + mov rax, [r12] ; x2 + mov rbx, [r12 + 8] ; x1 + sub r12, 8 ; make room + mov [r12], rax ; x2 + mov [r12 + 8], rbx ; x1 + mov [r12 + 16], rax ; x2 + ret +word_2dup: + mov rax, [r12] ; b + mov rbx, [r12 + 8] ; a + sub r12, 8 + mov [r12], rbx ; push a + sub r12, 8 + mov [r12], rax ; push b + ret +word_2drop: + add r12, 16 + ret +word_2swap: + mov rax, [r12] ; d + mov rbx, [r12 + 8] ; c + mov rcx, [r12 + 16] ; b + mov rdx, [r12 + 24] ; a + mov [r12], rcx ; top = b + mov [r12 + 8], rdx ; next = a + mov [r12 + 16], rax ; third = d + mov [r12 + 24], rbx ; fourth = c + ret +word_2over: + mov rax, [r12 + 16] ; b + mov rbx, [r12 + 24] ; a + sub r12, 8 + mov [r12], rbx ; push a + sub r12, 8 + mov [r12], rax ; push b + ret +word__2b: + mov rax, [r12] + add r12, 8 + add qword [r12], rax + ret +word__2d: + mov rax, [r12] + add r12, 8 + sub qword [r12], rax + ret +word__2a: + mov rax, [r12] + add r12, 8 + imul qword [r12] + mov [r12], rax + ret +word__2f: + mov rbx, [r12] + add r12, 8 + mov rax, [r12] + cqo + idiv rbx + mov [r12], rax + ret +word__25: + mov rbx, [r12] + add r12, 8 + mov rax, [r12] + cqo + idiv rbx + mov [r12], rdx + ret +word__3d_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + sete bl + mov [r12], rbx + ret +word__21_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setne bl + mov [r12], rbx + ret +word__3c: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setl bl + mov [r12], rbx + ret +word__3e: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setg bl + mov [r12], rbx + ret +word__3c_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setle bl + mov [r12], rbx + ret +word__3e_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setge bl + mov [r12], rbx + ret +word__40: + mov rax, [r12] + mov rax, [rax] + mov [r12], rax + ret +word__21: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + mov [rax], rbx + add r12, 8 + ret +word_mmap: + ; Save rsp and align to 16 bytes for syscall ABI + mov rax, rsp + and rsp, -16 + mov rdi, [r12+40] ; addr + mov rsi, [r12+32] ; length + mov rdx, [r12+24] ; prot + mov r10, [r12+16] ; flags + mov r8, [r12+8] ; fd + mov r9, [r12] ; offset + add r12, 48 ; pop 6 args + mov rax, 9 ; syscall: mmap + syscall + mov rsp, rax ; restore rsp + sub r12, 8 + mov [r12], rax ; push result + ret + ret +word_munmap: + mov rsi, [r12] + add r12, 8 + mov rdi, [r12] + mov rax, 11 + syscall + mov [r12], rax + ret +word_exit: + mov rdi, [r12] + add r12, 8 + mov rax, 60 + syscall + ret +word_and: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + test rax, rax + setz cl + test rbx, rbx + setz dl + movzx rcx, cl + movzx rdx, dl + and rcx, rdx + mov [r12], rcx + ret +word_or: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + test rax, rax + setz cl + test rbx, rbx + setz dl + movzx rcx, cl + movzx rdx, dl + or rcx, rdx + mov [r12], rcx + ret +word_not: + mov rax, [r12] + test rax, rax + setz al + movzx rax, al + mov [r12], rax + ret +word__3er: + mov rax, [r12] + add r12, 8 + sub r13, 8 + mov [r13], rax + ret +word_r_3e: + mov rax, [r13] + add r13, 8 + sub r12, 8 + mov [r12], rax + ret +word_rdrop: + add r13, 8 + ret +word_pick: + mov rcx, [r12] + add r12, 8 + mov rax, [r12 + rcx * 8] + sub r12, 8 + mov [r12], rax + ret +word_rpick: + mov rcx, [r12] + add r12, 8 + mov rax, [r13 + rcx * 8] + sub r12, 8 + mov [r12], rax + ret +word_read_file: + ; stack: path_ptr (top), path_len (next) + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + add r12, 16 ; pop args + + ; open(path_ptr, O_RDONLY=0, mode=0) + mov rax, 2 ; syscall: open + mov rdi, rsi ; filename + xor rsi, rsi ; flags = O_RDONLY + xor rdx, rdx ; mode = 0 + syscall + mov r10, rax ; save open() result + cmp rax, 0 + jl .fail_open + mov r8, rax ; fd + + ; use lseek to determine file size: lseek(fd, 0, SEEK_END) + mov rax, 8 ; syscall: lseek + mov rdi, r8 ; fd + xor rsi, rsi ; offset = 0 + mov rdx, 2 ; SEEK_END + syscall + mov r11, rax ; save lseek() result + cmp rax, 0 + jl .close_fail_lseek + mov rsi, rax ; length = size + + ; mmap(NULL, size, PROT_READ=1, MAP_PRIVATE=2, fd, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + ; rsi already holds length + mov rdx, 1 ; PROT_READ + mov r10, 2 ; MAP_PRIVATE + mov r8, r8 ; fd + xor r9, r9 ; offset = 0 + syscall + mov rbx, rax ; addr + mov r12, r12 ; (no-op, for debug) + mov rax, 3 ; syscall: close + mov rdi, r8 ; fd + syscall + cmp rbx, -4095 + jae .fail_mmap + sub r12, 16 + mov [r12], rsi ; len (rsi held length across syscall) + mov [r12 + 8], rbx ; addr + ret + +.close_fail_lseek: + mov rax, 3 + mov rdi, r8 + syscall + mov rax, r11 ; return lseek() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -1 + ret + +.fail_open: + mov rax, r10 ; return open() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -2 + ret + +.fail_mmap: + mov rax, -1 ; return mmap() error + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -3 + ret + ret +word_write_file: + ; stack: path_ptr (top), path_len, buf_ptr, buf_len + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + mov r15, [r12 + 16] ; buf_ptr (save in callee-saved r15) + mov r13, [r12 + 24] ; buf_len (save in callee-saved r13) + add r12, 32 ; pop 4 args (we saved buf info) + + ; open(path_ptr, O_WRONLY|O_CREAT|O_TRUNC, 0666) + mov rdi, rsi ; filename + mov rsi, 577 ; flags = O_WRONLY|O_CREAT|O_TRUNC + mov rdx, 438 ; mode = 0o666 + mov rax, 2 ; syscall: open + syscall + cmp rax, 0 + jl .fail_open + mov r9, rax ; save fd + + ; write(fd, buf_ptr, buf_len) -- use preserved r15/r13 which survive syscalls + mov rax, 1 ; syscall: write + mov rdi, r9 ; fd + mov rsi, r15 ; buf_ptr + mov rdx, r13 ; buf_len + syscall + mov r10, rax ; save write result + cmp r10, 0 + jl .fail_write + + ; close(fd) + mov rax, 3 ; syscall: close + mov rdi, r9 + syscall + + sub r12, 8 + mov [r12], r10 + ret + +.fail_write: + mov rax, 3 + mov rdi, r9 + syscall + sub r12, 8 + mov [r12], r10 + ret + +.fail_open: + sub r12, 8 + mov [r12], rax + ret + ret +word_read_stdin: + ; stack: max_len + mov r14, [r12] ; max_len + add r12, 8 ; pop max_len + + ; mmap(NULL, max_len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + mov rsi, r14 ; length + mov rdx, 3 ; PROT_READ|PROT_WRITE + mov r10, 34 ; MAP_PRIVATE|MAP_ANONYMOUS + mov r8, -1 ; fd = -1 + xor r9, r9 ; offset = 0 + syscall + cmp rax, -4095 + jae .fail_mmap + mov rbx, rax ; buffer addr + xor rcx, rcx ; bytes_read = 0 + +.read_loop: + mov rax, 0 ; syscall: read + mov rdi, 0 ; fd = stdin + lea rsi, [rbx + rcx] ; buf + offset + mov rdx, r14 + sub rdx, rcx ; remaining = max_len - bytes_read + syscall + cmp rax, 0 + je .done_read + js .read_error + add rcx, rax + cmp rcx, r14 + jl .read_loop + +.done_read: + ; push len (rcx) then addr (rbx) + sub r12, 16 + mov [r12], rcx + mov [r12 + 8], rbx + ret + +.read_error: + ; return negative errno in rax, addr = 0 + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], 0 + ret + +.fail_mmap: + sub r12, 16 + mov qword [r12], -1 + mov qword [r12 + 8], 0 + ret + ret +word_main: + ; push 1024 + sub r12, 8 + mov qword [r12], 1024 + call word_read_stdin + call word_dup + ; push 0 + sub r12, 8 + mov qword [r12], 0 + call word__3e + mov rax, [r12] + add r12, 8 + test rax, rax + jz L_if_false_0 + call word_write_buf + ; push 0 + sub r12, 8 + mov qword [r12], 0 + call word_exit +L_if_false_0: + ; push str_0 + sub r12, 8 + mov qword [r12], str_0 + ; push 17 + sub r12, 8 + mov qword [r12], 17 + call word_puts + call word_exit + ret +section .data +data_start: +str_0: db 114, 101, 97, 100, 95, 115, 116, 100, 105, 110, 32, 102, 97, 105, 108, 101, 100, 0 +str_0_len equ 17 +data_end: +section .bss +align 16 +dstack: resb DSTK_BYTES +dstack_top: +align 16 +rstack: resb RSTK_BYTES +rstack_top: +align 16 +print_buf: resb PRINT_BUF_BYTES +print_buf_end: \ No newline at end of file diff --git a/build/test_read_stdin.o b/build/test_read_stdin.o new file mode 100644 index 0000000000000000000000000000000000000000..05acd01766c59c3b9f5a94ec308d9dee22a1604d GIT binary patch literal 5520 zcmbW5Yitx%6oBvARu@pVDj`iIint_@z}g2y8_~1~Ium9MQGBD5ZFdTb+ude%mO@ek zQZY={8e=e~iKtQk81m(&~E7y=NXhwwO4{&fNQ* z$36Gl$K2Un>y5iEi$sKXMZ_H71 z6*~wQrr{p=VXSyHsE3HdbEfvi)k@(c6Y};~fEv#UT8=GH_GR@Db?`)6-o7!g6g86W z55~YsERAO&)FH`Qr<|x>s*UUYBT>yA9a;l4R)<839TK`*8?RJ6xn5cn-&ce6^+NAI z8x2WIo8wWf{}0i3pD}=82x9<8O&G0}zBZ%v<0o&^+@qTNEi_ZF?LFmOIfQ{8##^lJ zn6#K1AZ=hZ8V@V6-@fKn+GW&Q|DbhQ95Z6miJc_*v^g*qH=>+9&tt+nz2j%{pz1#=g)5|+Jq3E9h+kiB{d z*(;Zj9SCGvNi7t=_ZXK8se(D6xu>=MGr#GjzW6enD~ol^aT0FzNt_lc%V={MIQ&sL4?NTA>mXl4# zF`t#Bdu9kXSTKkBQR8CeYd`>-9NA3g;8+K}po?892!Roji>erC9T8}5%X z1A6~O(RVF{_8A~pxk(q+#taB$a-b?nnlxTg4EMq?cE5di3EXuRw93uxG8G2ygH6Zf z#(Ef3gf_5hp5dO?mY;xp;odlR$3iV~#ArR&_qFOR?o*hyX?;giMMi7mGBcPzNfAeN z!1x*)e*}c%?_HFsQxufO%_#u1m%!w67LFg_Dz%Va-xJt)Wqgf}7yksW-+_~gu&q?u zEI8>*ZgE#CleN+qMEFWL)(%G`(kUk;5*>wtNEEgf9NS5CKxt>UdQ#oCvMHq>_Ap}^ zUstu_Ty-X4&5S2DJQv_Z`1e&a!-)Y05a002n7TT@L_{;=?Xn&bZH#XqzLD|!i9gP` zN&Gd&i^R)}KTZ5J;{(KNFj1jvP?jTt^EZg!!1UiGo?yI8d;{ahi9f{nSHug9e@A== z<7bIK!}tZ_gN&<*5D~cE!`D1nkBBcAUqJjcv-NYYYe2{n#<8KikV|;}8_l$o_ z{Ab30A-9HP~g_nu*@Ad1TrFvL*vtAv=Og4S9 zV-*}Tc(*4~g>C__`IPO@BazFS){cy0Zck;4mgvpfX|vN@)##O)n^ej6Sx?a^2)uzG z+ss+L*-Xwd^SSI!MSJW_&N1Pqs;LgrPG`1cJj-l8-$On!TXL$@mC0oaTTN1vfuxH) zs`Xww<5*@#u}f9cHkeC|{C3M$r9y9tn4NbNGMhn>%DD_lonq$`O5E(bM?DfZ2Y#9Z z=Vo(<@6s!zyaEMfHm@eqk~Uk?p0p__w{&_6lxVZ1GbFWwvX_6;OMiE_*Sqdw&M)J@ zDVM1nHJGP#;2s0Uo_2|d8@LXKMq9P;JWix4i4&sSCPIz2r< dlU3#CAmdZSzh}HpdKBVI+L!UuTW(#X_YW;(Tju}( literal 0 HcmV?d00001 diff --git a/hello.sl b/hello.sl index c60fb3a..d08f7f3 100644 --- a/hello.sl +++ b/hello.sl @@ -1,4 +1,5 @@ import stdlib/stdlib.sl +import stdlib/io.sl : main "hello world" puts diff --git a/main.sl b/main.sl index 2779b0b..6861654 100644 --- a/main.sl +++ b/main.sl @@ -1,4 +1,5 @@ import stdlib/stdlib.sl +import stdlib/io.sl import fn.sl : main diff --git a/readstdin b/readstdin new file mode 100755 index 0000000000000000000000000000000000000000..6541ca6e9088c72b796ca3032961d42a9edd2af7 GIT binary patch literal 11592 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 -#include -#include - -int main() { - printf("st_size offset: %zu\n", offsetof(struct stat, st_size)); - return 0; -} diff --git a/stdlib/io.sl b/stdlib/io.sl index 02764c2..a480b15 100644 --- a/stdlib/io.sl +++ b/stdlib/io.sl @@ -131,4 +131,150 @@ mov [r12], rax ret } +; + +# : read_stdin ( max_len -- len addr | neg_errno 0 ) +:asm read_stdin { + ; stack: max_len + mov r14, [r12] ; max_len + add r12, 8 ; pop max_len + + ; mmap(NULL, max_len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + mov rsi, r14 ; length + mov rdx, 3 ; PROT_READ|PROT_WRITE + mov r10, 34 ; MAP_PRIVATE|MAP_ANONYMOUS + mov r8, -1 ; fd = -1 + xor r9, r9 ; offset = 0 + syscall + cmp rax, -4095 + jae .fail_mmap + mov rbx, rax ; buffer addr + xor rcx, rcx ; bytes_read = 0 + +.read_loop: + mov rax, 0 ; syscall: read + mov rdi, 0 ; fd = stdin + lea rsi, [rbx + rcx] ; buf + offset + mov rdx, r14 + sub rdx, rcx ; remaining = max_len - bytes_read + syscall + cmp rax, 0 + je .done_read + js .read_error + add rcx, rax + cmp rcx, r14 + jl .read_loop + +.done_read: + ; push len (rcx) then addr (rbx) + sub r12, 16 + mov [r12], rcx + mov [r12 + 8], rbx + ret + +.read_error: + ; return negative errno in rax, addr = 0 + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], 0 + ret + +.fail_mmap: + sub r12, 16 + mov qword [r12], -1 + mov qword [r12 + 8], 0 + ret +} +; + +:asm puts { + ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] + mov rax, [r12] ; len or int value + mov rbx, [r12 + 8] ; possible address + cmp rax, 0 + jl puts_print_int + lea r8, [rel data_start] + lea r9, [rel data_end] + cmp rbx, r8 + jl puts_print_int + cmp rbx, r9 + jge puts_print_int + ; treat as string: (addr below len) + mov rdx, rax ; len + mov rsi, rbx ; addr + add r12, 16 ; pop len + addr + test rdx, rdx + jz puts_str_newline_only + mov rax, 1 + mov rdi, 1 + syscall +puts_str_newline_only: + mov byte [rel print_buf], 10 + mov rax, 1 + mov rdi, 1 + lea rsi, [rel print_buf] + mov rdx, 1 + syscall + ret +puts_print_int: + mov rax, [r12] + add r12, 8 + mov rbx, rax + mov r8, 0 + cmp rbx, 0 + jge puts_abs + neg rbx + mov r8, 1 +puts_abs: + lea rsi, [rel print_buf_end] + mov rcx, 0 + mov r10, 10 + cmp rbx, 0 + jne puts_digits + dec rsi + mov byte [rsi], '0' + inc rcx + jmp puts_sign +puts_digits: +puts_loop: + xor rdx, rdx + mov rax, rbx + div r10 + add dl, '0' + dec rsi + mov [rsi], dl + inc rcx + mov rbx, rax + test rbx, rbx + jne puts_loop +puts_sign: + cmp r8, 0 + je puts_finish_digits + dec rsi + mov byte [rsi], '-' + inc rcx +puts_finish_digits: + mov byte [rsi + rcx], 10 + inc rcx + mov rax, 1 + mov rdi, 1 + mov rdx, rcx + mov r9, rsi + mov rsi, r9 + syscall +} +; + +# : write_buf ( len addr -- ) +:asm write_buf { + mov rdx, [r12] ; len + mov rsi, [r12 + 8] ; addr + add r12, 16 ; pop len + addr + mov rax, 1 ; syscall: write + mov rdi, 1 ; fd = stdout + syscall + ret +} ; \ No newline at end of file diff --git a/stdlib/stdlib.sl b/stdlib/stdlib.sl index e39df4c..b5d0a72 100644 --- a/stdlib/stdlib.sl +++ b/stdlib/stdlib.sl @@ -26,85 +26,6 @@ } ; -:asm puts { - ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] - mov rax, [r12] ; len or int value - mov rbx, [r12 + 8] ; possible address - cmp rax, 0 - jl puts_print_int - lea r8, [rel data_start] - lea r9, [rel data_end] - cmp rbx, r8 - jl puts_print_int - cmp rbx, r9 - jge puts_print_int - ; treat as string: (addr below len) - mov rdx, rax ; len - mov rsi, rbx ; addr - add r12, 16 ; pop len + addr - test rdx, rdx - jz puts_str_newline_only - mov rax, 1 - mov rdi, 1 - syscall -puts_str_newline_only: - mov byte [rel print_buf], 10 - mov rax, 1 - mov rdi, 1 - lea rsi, [rel print_buf] - mov rdx, 1 - syscall - ret - -puts_print_int: - mov rax, [r12] - add r12, 8 - mov rbx, rax - mov r8, 0 - cmp rbx, 0 - jge puts_abs - neg rbx - mov r8, 1 -puts_abs: - lea rsi, [rel print_buf_end] - mov rcx, 0 - mov r10, 10 - cmp rbx, 0 - jne puts_digits - dec rsi - mov byte [rsi], '0' - inc rcx - jmp puts_sign -puts_digits: -puts_loop: - xor rdx, rdx - mov rax, rbx - div r10 - add dl, '0' - dec rsi - mov [rsi], dl - inc rcx - mov rbx, rax - test rbx, rbx - jne puts_loop -puts_sign: - cmp r8, 0 - je puts_finish_digits - dec rsi - mov byte [rsi], '-' - inc rcx -puts_finish_digits: - mov byte [rsi + rcx], 10 - inc rcx - mov rax, 1 - mov rdi, 1 - mov rdx, rcx - mov r9, rsi - mov rsi, r9 - syscall -} -; - :asm dup { mov rax, [r12] sub r12, 8 @@ -112,18 +33,6 @@ puts_finish_digits: } ; -# : write_buf ( len addr -- ) -:asm write_buf { - mov rdx, [r12] ; len - mov rsi, [r12 + 8] ; addr - add r12, 16 ; pop len + addr - mov rax, 1 ; syscall: write - mov rdi, 1 ; fd = stdout - syscall - ret -} -; - :asm drop { add r12, 8 } diff --git a/t.sl b/t.sl index 998dad5..ff260ce 100644 --- a/t.sl +++ b/t.sl @@ -1,4 +1,5 @@ import stdlib/stdlib.sl +import stdlib/io.sl import fn.sl fn foo(int a, int b){ diff --git a/test.sl b/test.sl index 9b8fbf7..5aed637 100644 --- a/test.sl +++ b/test.sl @@ -1,4 +1,5 @@ import stdlib/stdlib.sl +import stdlib/io.sl import fn.sl :asm mem-slot { diff --git a/test_read_stdin.sl b/test_read_stdin.sl new file mode 100644 index 0000000..25d81f6 --- /dev/null +++ b/test_read_stdin.sl @@ -0,0 +1,13 @@ +import stdlib/stdlib.sl +import stdlib/io.sl + +: main + 1024 + read_stdin # returns (len addr) + dup 0 > if + write_buf + 0 exit + then + "read_stdin failed" puts + exit +; diff --git a/tests/run_tests.py b/tests/run_tests.py index 3a7f36b..662e139 100644 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -31,6 +31,7 @@ CASES: List[TestCase] = [ name="call_syntax_parens", source=f""" import {ROOT / 'stdlib/stdlib.sl'} +import {ROOT / 'stdlib/io.sl'} import {ROOT / 'fn.sl'} : main @@ -52,6 +53,7 @@ fn foo(int a, int b){{ name="loops_and_cmp", source=f""" import {ROOT / 'stdlib/stdlib.sl'} +import {ROOT / 'stdlib/io.sl'} : main 0 @@ -70,6 +72,7 @@ import {ROOT / 'stdlib/stdlib.sl'} name="override_dup_compile_time", source=f""" import {ROOT / 'stdlib/stdlib.sl'} +import {ROOT / 'stdlib/io.sl'} : dup 6 @@ -103,6 +106,7 @@ compile-only name="string_puts", source=f""" import {ROOT / 'stdlib/stdlib.sl'} +import {ROOT / 'stdlib/io.sl'} : main \"hello world\" puts