From 5e27c7f13e6a888484ccf144579ed2d3b676da89 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 3 Dec 2018 16:38:44 -0800 Subject: [PATCH] 4827 I was 'returning' a phantom value from 'write' when the underlying '_write' returns nothing. In general, returning counts of bytes written is not so useful for error checking when my primitives abstract away from that. We'll come back to error signalling later. --- html/subx/056write.subx.html | 98 +++++++++++++++++------------------ subx/056write.subx | 8 +-- subx/apps/crenshaw2-1 | Bin 6480 -> 6482 bytes subx/apps/crenshaw2-1b | Bin 7041 -> 7043 bytes subx/apps/factorial | Bin 5371 -> 5373 bytes 5 files changed, 53 insertions(+), 53 deletions(-) diff --git a/html/subx/056write.subx.html b/html/subx/056write.subx.html index 7ada1e78..727bda6b 100644 --- a/html/subx/056write.subx.html +++ b/html/subx/056write.subx.html @@ -92,55 +92,55 @@ if ('onhashchange' in window) { 27 b8/copy-to-EAX 1/imm32 28 cd/syscall 0x80/imm8 29 - 30 write: # f : fd or (address stream), s : (address array byte) -> bytes_written/EAX - 31 # (If we ever leave the Linux kernel behind, it may be better to return - 32 # the number of bytes *not* written. Success would then be signaled by - 33 # returning 0.) - 34 # . prolog - 35 55/push-EBP - 36 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 37 # if (f < 0x08000000) _write(f, s), return # f can't be a user-mode address, so treat it as a kernel file descriptor - 38 81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 0x08000000/imm32 # compare *(EBP+8) - 39 7d/jump-if-greater-or-equal $write:fake/disp8 - 40 # . . push args - 41 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) - 42 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) - 43 # . . call - 44 e8/call _write/disp32 - 45 # . . discard args - 46 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 47 eb/jump $write:end/disp8 - 48 $write:fake: - 49 # otherwise, treat 'f' as a stream to append to - 50 # . save registers - 51 51/push-ECX - 52 52/push-EDX - 53 53/push-EBX - 54 # ECX = f - 55 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX - 56 # EDX = f->write - 57 8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX - 58 # EBX = f->length - 59 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 3/r32/EBX 8/disp8 . # copy *(ECX+8) to EBX - 60 # EAX = _append-3(&f->data[f->write], &f->data[f->length], s) - 61 # . . push s - 62 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) - 63 # . . push &f->data[f->length] - 64 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 3/index/EBX . 3/r32/EBX 0xc/disp8 . # copy ECX+EBX+12 to EBX - 65 53/push-EBX - 66 # . . push &f->data[f->write] - 67 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 2/index/EDX . 3/r32/EBX 0xc/disp8 . # copy ECX+EDX+12 to EBX - 68 53/push-EBX - 69 # . . call - 70 e8/call _append-3/disp32 - 71 # . . discard args - 72 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 73 # f->write += EAX - 74 01/add 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # add EAX to *ECX - 75 # . restore registers - 76 5b/pop-to-EBX - 77 5a/pop-to-EDX - 78 59/pop-to-ECX + 30 # TODO: come up with a way to signal when a write to disk fails + 31 write: # f : fd or (address stream), s : (address array byte) -> <void> + 32 # . prolog + 33 55/push-EBP + 34 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 35 # if (f < 0x08000000) _write(f, s), return # f can't be a user-mode address, so treat it as a kernel file descriptor + 36 81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 0x08000000/imm32 # compare *(EBP+8) + 37 7d/jump-if-greater-or-equal $write:fake/disp8 + 38 # . . push args + 39 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) + 40 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) + 41 # . . call + 42 e8/call _write/disp32 + 43 # . . discard args + 44 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 45 eb/jump $write:end/disp8 + 46 $write:fake: + 47 # otherwise, treat 'f' as a stream to append to + 48 # . save registers + 49 50/push-EAX + 50 51/push-ECX + 51 52/push-EDX + 52 53/push-EBX + 53 # ECX = f + 54 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX + 55 # EDX = f->write + 56 8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX + 57 # EBX = f->length + 58 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 3/r32/EBX 8/disp8 . # copy *(ECX+8) to EBX + 59 # EAX = _append-3(&f->data[f->write], &f->data[f->length], s) + 60 # . . push s + 61 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) + 62 # . . push &f->data[f->length] + 63 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 3/index/EBX . 3/r32/EBX 0xc/disp8 . # copy ECX+EBX+12 to EBX + 64 53/push-EBX + 65 # . . push &f->data[f->write] + 66 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 2/index/EDX . 3/r32/EBX 0xc/disp8 . # copy ECX+EDX+12 to EBX + 67 53/push-EBX + 68 # . . call + 69 e8/call _append-3/disp32 + 70 # . . discard args + 71 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 72 # f->write += EAX + 73 01/add 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # add EAX to *ECX + 74 # . restore registers + 75 5b/pop-to-EBX + 76 5a/pop-to-EDX + 77 59/pop-to-ECX + 78 58/pop-to-EAX 79 $write:end: 80 # . epilog 81 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP diff --git a/subx/056write.subx b/subx/056write.subx index 3496d980..c76d0737 100644 --- a/subx/056write.subx +++ b/subx/056write.subx @@ -27,10 +27,8 @@ b8/copy-to-EAX 1/imm32 cd/syscall 0x80/imm8 -write: # f : fd or (address stream), s : (address array byte) -> bytes_written/EAX - # (If we ever leave the Linux kernel behind, it may be better to return - # the number of bytes *not* written. Success would then be signaled by - # returning 0.) +# TODO: come up with a way to signal when a write to disk fails +write: # f : fd or (address stream), s : (address array byte) -> # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP @@ -48,6 +46,7 @@ write: # f : fd or (address stream), s : (address array byte) -> bytes_written/ $write:fake: # otherwise, treat 'f' as a stream to append to # . save registers + 50/push-EAX 51/push-ECX 52/push-EDX 53/push-EBX @@ -76,6 +75,7 @@ $write:fake: 5b/pop-to-EBX 5a/pop-to-EDX 59/pop-to-ECX + 58/pop-to-EAX $write:end: # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP diff --git a/subx/apps/crenshaw2-1 b/subx/apps/crenshaw2-1 index 47762af79904224d024125a936847e1fe555d3d6..10003ae738827508194c04287542e07d37837a42 100755 GIT binary patch literal 6482 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 literal 7041 zcmbtY3vg6d8NORK$p#jZ@(vW-0_haXC82>%0)i}gz$ns=TTAl8m!9HdgB#5&>(V`pUQqjdzm8lXk{q}KKS{&V-7o3NR| zx-<9eJ^%gA|Nj4T?tP?jW0TM4)AGMNv$4@AhO5|pK5(VKw~|o@?=`OxAZJwuoTq7J|IY)2Sq%Z1$NOtgpzWlR9gBmo?P(rRL%ou*40#FGn$9vZk3X=d)P`0<is%3+VhQk3;N^5rhJSqQ-pwsCp7i+!(H1jmy5?TfwgR#&Bn4nWfMhmUY%Xv&# zV$9MRY+caN6;0wQ6m4-HSEOhXcVl8+#YBg!3WoDb}1fz0T z;`C3z!XQ0~G=F;YmKK}*Z1+|M?J~P1uz`HBam z>y0Vnx_+J1$ZN+ENfmb7rRHo$P|b^H=2Pf|)OM^L->2r}wc}ZYhx^4Xq3HX!w4)rH zYrJ+Gom|L{2MNdR;vT60+6-AK>!M z_lrSVp;6ZjRMUTN8Sd)n?vWyHlwjfPC(T8-Rn61flh>$IN|%anmn7BtniNecnV}ZR z5@r;T08L1dK;H~FgKgLVRe2*A`B=o$v`VrKCBcZj-Y@=}0@;RQniun*^9sis{lHi3 zTkqesGjF82x^Ay6(#GR_` zV=h+e)CAoe>IO30M!f}H5WVG5ZtQ5TLjt{5@nx1f)ci>)=WWu%WvS%+f_nknW*(Ku zUl&3?rI5!N+2GOWpWI|wBj@v^-PqtaZ{hu7Q()C5fA5lPlRx78n1#@wMRE@~EnMr+ zqyJqRv`on$c_24Zy6o(chAHK_rohf^2)wZOfL!Y>V?$ESA!x{(hQ>rTkehar9SgDM zO8|xGF5=v;^cTx2BrmUo36g65RZ934Z(vHoWF>(me!z}niC3|RB1sa@a!2*V@Pyn4 zy%N7HsbbIhfnqjk7BPd9B2HQ{bKa->vF4Fe|v3UJUawzmXCRTKvopBp6QsVaQM*vnP)&dA1MK8~t5spdLt z;<#;KB6}4eL0rbJWnvAGgdtaEh#-z8W(%lXD_DeD*(x8px$|))jipzqc~VOMl}txg zQAmGYRe&Xt-!6n4P{l>(6@*17zChdv*NoK(b!Wtb_^RG%dwT0x|t>j>(P&25A z-^6nA5jiQMq&k=Aer$?Fn(c$j0K5S{l3GuFHU74ThVg=8A}C?znAw(qpJ1+aN!TPuQ_ zv#oaqH#^5UKcJ=0=cX~g3Xr=3_6F+zf#5Jb)U@HX?63Z_z}Ee;Z;BxIp9Oj3y6~e2 z(P?%J=;rj<`M7P7-ZJNa2scHXC%NRn(p&@TsEy!&eCQ^3n_}D|8H)x4L(Nu6bX1l^ zLF5$8Z!ilLU*~&tKgydX-picHvM~)5oub?uUK@Cm&W{M8yGzn;%sl}w2wSqPv*6G& za%eMWGAt6U-U|6j>@wc>J*fL6%2%Sc)&Ixy&y$vp$MXkZHWN1}&-a5EZkwnL;t3ka zEDDq8E<*y{t$h3q$)ZTHI3|g2C?7uqV*SL1iIVTn*nx0^%QvL>z93ngR4mScNN}ZE zuVO)tK>?TBNJxKkc7vbaDY-CcKPC&%wYdociZ?hu$I&ZX!2S$%ZaP9z1x&B|P2c3Y z-}RLqng7H`);6sld7XXFWp$jSjY6AZ7d zAGyKpVx)*g%FW zfGGI>kzFPHykBBV6!xIv`*^6ZqX3hBoGYil-QcZHWS8Nj7 zVP#T@P-A#2ef=K8OJI~)x9S_C&|6W<*qwm;ZzhUDy3CCtJ6zd0^H#{HxQ$|ArK0Wmn2p0iKwK8YTN~v_@zm(- zvU>D*EMWkE-@SB6Mcb2|UD1@G3)udcWxBVNfuucp2-*hyMpa&cWhgztWzELk ztM_H1apXElN;9yd-Ni30q$C;PU7?Fv+(_)P%rtbwhIfl;iA+4M?=?~hBQHz$*cnZw zqCKwA+W%#_ve(O^st}7p!r2hDvZMV&tRz|5hgc?Zdf9Dinl`Dq8Y!K1MLVT@=%~KU h#qnf<_5!gM$!VY;qW!mwVs{@4Q#oVCR0{bDsBk zpYxn^zS-4ttM`?b9nLC+|D>Y77NtD;$v5+Vkl(+haL+`u3Zl1GHk$96l-hl=k>=Nd zv?F7#XOtRFj_*ITrEQW};Q+y9b2$wj4XS3|0b|)XO;%Ae`To;Ge}{kR4sVtBqkhg? z=`Xbeeb6uH&%I9XPd(*zSNf^I{7#m3pG;6$NQMG4A@3K_jlmZggeiUxxw0*aBI`7q z2D8|wR24JPwzS#9%V2w!{if)$_5$0WB zc9-fbO$UFGq54Q}ifG-WHjNMlsqkGS=0 zWRN2R$-3*{MKL%ECUIyHZxdjTcX$RUA1)N(aBX&zwXnZ}c13B&?K|ZCf@^<@F30@g zlJ-aC$Xs&Fg9|Z-gn1QAK3u)c73=92KQ>IBI04p>L`LMj_11XtYZhv>TpEebw1Bsx zoKm8gp7iN!5`PB%APd-@@kRaF4d5WkXj{UJ=?(t9Ew9C8AvINISnu>#__K@LmS(=7 zXPeK32g>@ipHCm+7;%d|Prs2W*}Xn4$8eup$y2h82jbpk^AX>A2!uZXz3Ce<=qBeQ z>l5KKPIy)pe)ds^{v+r)fH&Rr6(VfDq-TV3vGGoCuWm|}=#yAZy;K>-9@VX61}Y40 zl$Fc@EcOMeiWwZerL>{*d0X~?c+R!P5=oKBJMfZNF0?)Y&p|10!ee|L?FW->6hwHf z)A&j>)&rzq$(tSw2EB1T6Fgpd9%wHO=3DXbGC*v4*?j7Dv=)8{_yD+jg!?f-$d=9a zI_@dJzk$11xMu-c-5$%;Cz_JE8w}q@+;-tM>Zzu6sS%2Cs5^0dL@!V0$nu)>_S{-x zhTmg5hK0UfkEL^!oo=dErgj0e4pV%6Y-q;-S0VF|a8CfV4$o0ZymMC^*B9;$(f!79 z^Yl{-+ZM;dQ<8p%-kQm6dc{qR%GB!st-nomJx3h(1K}PPZd)C9N}tbkde`-m?EQ3H zi`gX<)w9{I_GkW$A~Se}hVvMHou*;cRT?ygfon8e#_-+@4Ly1y8+!dm+nXno{{!pt Bn$G|L delta 2201 zcmZuxe`s4(6n@VneQlZ_wa%2XA4ccIZFF;rrOJw}EjYwKf}k`l)wQ5L5OiUij+K!P zoe+j%xf2Fb8S0oIMd#cWHnv!@UpR{lVW?#={}8S?bhcaVDD!!~bCY{AXrVXnedjyh zIp@3gzT2x8R)5&L{9wXy@E>vLugP&-`e{w_f3$UMDE&Y==|qEVtLpW)jgGVXOg+Ur zLE0YIb8*Mn8!3%_Hq>^JSpE)zGy3lsc(gcW{WciOOB5_3XKM6?!tefXYJ>ZbdqVZO ztGs&+K^^eY>T|c<{Z&o7J^36Z=%1*i-Dkp-=2JsaU6%K2sK($+45BH1_c^mI2m;fo zKLcj>u;UaF3AV)ayF3QBXV|ZcE=vwX^0shuQ?<|>HB!+8%cP$D&lYO2%pVqGek{yo zVD|LZv@{bH$97VCA+k)}7fQRwRadCpxG}=2v^d2!svp5qM!#ZFzZ0@NzQZ7U0;+zK z?LdOx15!7qJ}N~`TC3Hntq=-}8=Gy3PeRrWE)ka!{C=Cq<&v)=i8g?`{jR~zX-Xbq z8PIA=j#<=)*c$z{sO^Co6$>(YtElM(dWLB@MyJD%yOZihxXT!K>Mj)JRtDk5guEZJ z^K4>}Ed$APw}FRZZ~{!?&=A`RFvr`!1e6aKl5n{CY_RO-@+kL|l;iU2<^2y^{(HI{ zmBS_FkI0ev%Q6ov#w-YP7EC@|gUP(<>6}+>n0jIdSVJ5cm-nW-tHXCJR_J~yBz?vN zOd*|IBAYTEeNC#LfuE@bY|muf)ga-c%UkK)sXVtt{+3k~Z5I?Z9yeJ#FuUb8$_w&7nhF=7F$5&#+ z1}mlwi|{2YY>qjfkjqb4REr_g0Pnc#D@9m;Nzbt5di^qYkBT?+(ns<6hRyi`cBy8P zn^0kJlT5MzuzNV_6cNGUYoRTzIBwWGq~|5gRf&j5v|8}Gw7jDEIrJRujauOnUr6)G z0t;UwmqZA?WUIf_W|z%_dVh6 z2MF1W&ed=)0R9o&e&JqLhZ|F=d4vLl)=8*NU1{u0kCSVKp72Th7W+wbYILA*ZLq9| zNE*BHWGt8JxQFtOVmtOq{zf$!OXauO(904U0cbjG;0t6-I}Z35WF8alX@F+(E0j{* zxqmFz6Yjj|9yZ*i^i%fNE~yGni~H+UE}qH`+t61M@&TIuvNbiwE%zPa9u#g{4fhvy zHQw&dsg}grmJ>7*-(|gm8TGUVk&?u9;Q<47xxWA$2