duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit 6cd8c6e587341b2d13b4620c8dcb17582b200a14
parent 178dbfff2434cfc83d10b8de6269be6549eb53ab
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Tue,  4 Jul 2023 12:33:05 -0400

Have structs enforce alignment discipline

There wasn't that many fixes to make!

Diffstat:
Mfs/asm/uxntal.c | 2+-
Mfs/comp/c/ptype.fs | 3+--
Mfs/comp/c/type.fs | 17++++++++++++++---
Mfs/doc/dict.txt | 3+++
Mfs/doc/usage.txt | 8++++++++
Mfs/emul/uxn/vm.c | 2+-
Mfs/tests/kernel.fs | 11++++++-----
Mfs/tests/lib/struct.fs | 3++-
Mfs/xcomp/bootlo.fs | 11+++++++++--
Mfs/xcomp/i386/pc/init.fs | 6++++++
10 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/fs/asm/uxntal.c b/fs/asm/uxntal.c @@ -28,7 +28,7 @@ struct Label { struct Reference { Reference *next; - char name[LINESZ], rune; + char name[LINESZ], rune, pad[3]; ushort addr; }; diff --git a/fs/comp/c/ptype.fs b/fs/comp/c/ptype.fs @@ -72,8 +72,7 @@ alias _err parseDeclarator ( type -- cdecl ) \ forward declaration '}' readChar? not while ( eop prev tok ) parseType _assert parseDeclarator begin ( eop prev new ) tuck swap to CDecl nexttype ( eop new ) - V2 over to CDecl offset - dup typesize to+ V2 + V2 over CDecl :offset! to V2 ';' readChar? not while ( eop prev tok ) ',' expectChar dup CDecl type parseDeclarator repeat ( eop prev ) repeat ( eop prev ) rdrop drop r> to curstorage ; diff --git a/fs/comp/c/type.fs b/fs/comp/c/type.fs @@ -98,19 +98,30 @@ struct[ CDecl _err endcase ( self operand ) swap :reference? if &) then ; + : :typesize ( self -- size ) dup lvl if drop 4 else type typesize then ; + \ Combined size of all fields in the LL. : :size ( self -- size ) dup :isarg? over :funcsig? or if drop CELLSZ exit then 0 swap begin ( res cdecl ) ?dup while - tuck dup lvl if 4 else dup type typesize then ( cdecl res cdecl n ) + tuck dup :typesize ( cdecl res cdecl n ) swap nbelem 1 max * + swap llnext repeat ( res ) ; \ When the CDecl is an array, return the size of a single element. : :elemsize ( self -- size ) - dup nbelem _assert dup lvl if drop 4 else type typesize then ; + dup nbelem _assert :typesize ; : :argssize ( self -- size ) dup :funcsig? _assert args llcnt CELLSZ * ; - : :offset! ( off self -- off+size ) 2dup to offset :size + ; + + \ Set CDecl's offset to "off", after applying alignment checks. Then, return + \ offset + size. + : :offset! ( off self -- off+size ) + dup :typesize case + 4 = of over align4# endof + 2 = of over align2# endof + drop + endcase + 2dup to offset :size + ; \ Find "name" in CDecl's LL. return 0 if not found : _ 2dup name s= not if llnext dup if _ then then ; diff --git a/fs/doc/dict.txt b/fs/doc/dict.txt @@ -149,7 +149,10 @@ width", a value that can be 1, 2 or 4 depending of the width of the operation. 8b -- *I* Set binary width to 8-bit 16b -- *I* Set binary width to 16-bit +align2 a -- a Add 0 or 1 to "a" so that it's divisible by 2. align4 a -- a Add 0, 1, 2 or 3 to "a" so that it's divisible by 4. +align2# a -- Abort with error if a is not divisible by 2 +align4# a -- Abort with error if a is not divisible by 4 alignhere -- Align here to 4b. allot u -- Increase here by u. allot0 u -- Allot u and fill this space with zeroes. diff --git a/fs/doc/usage.txt b/fs/doc/usage.txt @@ -523,6 +523,14 @@ then yield it. Therefore, the general rule of thumb is: use "here#" instead of "here". +For structs, (which includes C structs), you have to arrange your fields +accordingly. By principle, no auto-alignment takes place on structure. The idea +is that looking at a structure's definition should always tell the reader the +exact structure without them having to second guess. + +To help, there are alignment checks built in. When a structure's definition +results in misaligned fields, Dusk aborts with "alignment error". + ## What now? This document covers Dusk's basic functionalities. You can try a few things in diff --git a/fs/emul/uxn/vm.c b/fs/emul/uxn/vm.c @@ -8,9 +8,9 @@ struct Stack { }; struct Device { - uchar port, dat[$10]; uchar (*dei)(Device*, uchar); void (*deo)(Device*, uchar); + uchar dat[$10], port; }; typedef void (*VMOP) (); diff --git a/fs/tests/kernel.fs b/fs/tests/kernel.fs @@ -109,7 +109,7 @@ foo 55 #eq 44 #eq : inc5 >r 5 for 1 to+ V1 next V1 rdrop ; 42 inc5 47 #eq -create _ 4 c, 5 c, -1 , +create _ 4 c, 5 c, 3 allot -1 , : foo _ >r 8b to@+ V1 8b to@+ V1 rdrop ; foo 5 #eq 4 #eq @@ -117,12 +117,13 @@ foo 5 #eq 4 #eq struct[ Foo sfield bar sfieldb baz + 3 sallot smethod :bleh ]struct \ ' Foo structsize 12 #eq : mybleh ( 'data -- n ) dup Foo bar swap Foo baz + ; -create data1 1 , 2 c, ' mybleh , -create data2 3 , 4 c, ' mybleh , +create data1 1 , 2 c, 3 allot ' mybleh , +create data2 3 , 4 c, 3 allot ' mybleh , data1 Foo bar 1 #eq data2 Foo baz 4 #eq data1 Foo :bleh 3 #eq @@ -141,14 +142,14 @@ data2 ' MyData1 rebind myword 7 #eq data1 ' MyData1 rebind : bleh2 dup Foo bar swap Foo baz + 1+ ; -' bleh2 data1 5 + ! +' bleh2 data1 8 + ! data1 Foo :bleh 46 #eq myword 46 #eq extends Foo struct[ Bazooka sconst bling ]struct -create data3 7 , 9 c, ' mybleh , 999 , +create data3 7 , 9 c, 3 allot ' mybleh , 999 , data3 Bazooka bling 999 #eq data3 Bazooka baz 9 #eq diff --git a/fs/tests/lib/struct.fs b/fs/tests/lib/struct.fs @@ -5,6 +5,7 @@ testbegin struct[ Foo sfield bar sfieldb baz + 3 sallot ssmethod :bleh sfield bling ]struct @@ -19,7 +20,7 @@ does' Field next 0 #eq : bleh1 42 ; : bleh2 54 ; -create data 0 , 0 c, ' bleh1 , 0 , +create data 0 , 0 c, 3 allot ' bleh1 , 0 , data Foo :bleh 42 #eq ' bleh2 data structfind Foo :bleh sfield! diff --git a/fs/xcomp/bootlo.fs b/fs/xcomp/bootlo.fs @@ -189,6 +189,7 @@ _to to' noop _addr, : _toexec ( a -- ) compiling if m) then toptr@ execute ; : value doer , immediate does> _toexec ; : here HERE _toexec ; immediate +: align2 ( a -- a ) dup 1 and + ; : align4 ( a -- a ) dup 4 mod ?dup if 4 -^ + then ; : alignhere here align4 to here ; : here# alignhere here ; @@ -265,6 +266,10 @@ create _repl 3 nc, LF CR 0 : [if] not if S" [then]" begin word over s= until drop then ; alias noop [then] +: _ <> if abort" alignment error" then ; +: align2# dup align2 _ ; +: align4# dup align4 _ ; + : move, ( src u -- ) here swap dup allot move ; : -move, ( src u -- ) here over - swap move ; @@ -321,9 +326,11 @@ does> ( 'struct ) : sallot ( n -- ) _cur e>w structsz' +! ; create _ 0 , EMETA_8B , EMETA_16B , : _szmeta dup 3 < if CELLSZ * _ + @ else drop 0 then ; +: _cursz _cur e>w structsz ; : _sfield ( sz -- ) + dup case 4 = of _cursz align4# endof 2 = of _cursz align2# endof drop endcase current _cur e>w structlastfield' @! ( next ) , - _cur e>w structsz , ( sz ) dup , ( sz ) sallot ; + _cursz , ( sz ) dup , ( sz ) sallot ; : _svalue ( sz -- ) doer immediate _sfield does> CELLSZ + @+ dip @ | ( a? sz off ) compiling if ( sz off ) @@ -333,7 +340,7 @@ create _ 0 , EMETA_8B , EMETA_16B , : sfield CELLSZ _svalue ; : sfieldw 2 _svalue ; : sfieldb 1 _svalue ; -: sfield' ( sz -- ) doer _sfield +: sfield' ( sz -- ) doer 0 _sfield sallot does> [ W) CELLSZ +) @, ] + ; : sconst doer CELLSZ _sfield does> [ W) CELLSZ +) @, ] + @ ; diff --git a/fs/xcomp/i386/pc/init.fs b/fs/xcomp/i386/pc/init.fs @@ -3,6 +3,12 @@ \ You need to adapt to your own machine. : ARCH S" i386" ; +\ i386 can access unaligned memory just fine and some PC-specific drivers have +\ fuzzy alignment. Rather than artificially complicating them, we disable +\ alignment checks on i386 +:realias align2# drop ; +:realias align4# drop ; + f<< /drv/pc/acpi.fs \ Serial communication \ f<< /drv/pc/com.fs