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:
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