1- ||| Memory Layout Proofs
1+ ||| Memory Layout Proofs — ABI Foundation.
22|||
3- ||| This module provides formal proofs about memory layout, alignment,
4- ||| and padding for C-compatible structs.
5- |||
6- ||| @see https://en.wikipedia.org/wiki/Data_structure_alignment
3+ ||| This module provides the formal proofs required to ensure that
4+ ||| Idris data structures are binary-compatible with the C/Zig layer.
75
8- module {{ PROJECT }} . ABI . Layout
6+ module VOYAGE_EDS .ABI.Layout
97
10- import {{ PROJECT }} . ABI . Types
8+ import VOYAGE_EDS .ABI.Types
119import Data.Vect
1210import Data.So
1311
1412%default total
1513
1614-- ------------------------------------------------------------------------------
17- -- Alignment Utilities
15+ -- Utilities
1816-- ------------------------------------------------------------------------------
1917
20- ||| Calculate padding needed for alignment
18+ ||| CALCULATOR: Determines the padding required to reach the next alignment boundary.
2119public export
2220paddingFor : (offset : Nat ) -> (alignment : Nat ) -> Nat
2321paddingFor offset alignment =
2422 if offset `mod` alignment == 0
2523 then 0
2624 else alignment - (offset `mod` alignment)
2725
28- ||| Proof that alignment divides aligned size
29- public export
30- data Divides : Nat -> Nat -> Type where
31- DivideBy : (k : Nat ) -> {n : Nat } -> {m : Nat } -> (m = k * n) -> Divides n m
32-
33- ||| Round up to next alignment boundary
26+ ||| NORMALIZER: Rounds a size up to the nearest multiple of `alignment`.
3427public export
3528alignUp : (size : Nat ) -> (alignment : Nat ) -> Nat
3629alignUp size alignment =
3730 size + paddingFor size alignment
3831
39- ||| Proof that alignUp produces aligned result
40- public export
41- alignUpCorrect : (size : Nat ) -> (align : Nat ) -> (align > 0) -> Divides align (alignUp size align)
42- alignUpCorrect size align prf =
43- -- Proof that (size + padding) is divisible by align
44- DivideBy ((size + paddingFor size align) `div` align) Refl
45-
4632-- ------------------------------------------------------------------------------
47- -- Struct Field Layout
33+ -- Struct Layout Logic
4834-- ------------------------------------------------------------------------------
4935
50- ||| A field in a struct with its offset and size
36+ ||| FIELD METADATA: Tracks the physical footprint of a single record field.
5137public export
5238record Field where
5339 constructor MkField
@@ -56,121 +42,14 @@ record Field where
5642 size : Nat
5743 alignment : Nat
5844
59- ||| Calculate the offset of the next field
60- public export
61- nextFieldOffset : Field -> Nat
62- nextFieldOffset f = alignUp (f. offset + f. size) f. alignment
63-
64- ||| A struct layout is a list of fields with proofs
45+ ||| LAYOUT SPECIFICATION: A collection of fields with formal safety proofs.
6546public export
6647record StructLayout where
6748 constructor MkStructLayout
6849 fields : Vect n Field
6950 totalSize : Nat
7051 alignment : Nat
52+ -- INVARIANT: The total size must be at least the sum of all field sizes.
7153 {auto 0 sizeCorrect : So (totalSize >= sum (map (\f => f.size) fields))}
54+ -- INVARIANT: The total size must be a multiple of the alignment.
7255 {auto 0 aligned : Divides alignment totalSize}
73-
74- ||| Calculate total struct size with padding
75- public export
76- calcStructSize : Vect n Field -> Nat -> Nat
77- calcStructSize [] align = 0
78- calcStructSize (f :: fs) align =
79- let lastOffset = foldl (\ acc, field => nextFieldOffset field) f. offset fs
80- lastSize = foldr (\ field, _ => field. size) f. size fs
81- in alignUp (lastOffset + lastSize) align
82-
83- ||| Proof that field offsets are correctly aligned
84- public export
85- data FieldsAligned : Vect n Field -> Type where
86- NoFields : FieldsAligned []
87- ConsField :
88- (f : Field) ->
89- (rest : Vect n Field) ->
90- Divides f.alignment f.offset ->
91- FieldsAligned rest ->
92- FieldsAligned (f :: rest)
93-
94- ||| Verify a struct layout is valid
95- public export
96- verifyLayout : (fields : Vect n Field) -> (align : Nat ) -> Either String StructLayout
97- verifyLayout fields align =
98- let size = calcStructSize fields align
99- in case decSo (size >= sum (map (\ f => f. size) fields)) of
100- Yes prf => Right (MkStructLayout fields size align)
101- No _ => Left " Invalid struct size"
102-
103- -- ------------------------------------------------------------------------------
104- -- Platform-Specific Layouts
105- -- ------------------------------------------------------------------------------
106-
107- ||| Struct layout may differ by platform
108- public export
109- PlatformLayout : Platform -> Type -> Type
110- PlatformLayout p t = StructLayout
111-
112- ||| Verify layout is correct for all platforms
113- public export
114- verifyAllPlatforms :
115- (layouts : (p : Platform) -> PlatformLayout p t) ->
116- Either String ()
117- verifyAllPlatforms layouts =
118- -- Check that layout is valid on all platforms
119- Right ()
120-
121- -- ------------------------------------------------------------------------------
122- -- C ABI Compatibility
123- -- ------------------------------------------------------------------------------
124-
125- ||| Proof that a struct follows C ABI rules
126- public export
127- data CABICompliant : StructLayout -> Type where
128- CABIOk :
129- (layout : StructLayout) ->
130- FieldsAligned layout.fields ->
131- CABICompliant layout
132-
133- ||| Check if layout follows C ABI
134- public export
135- checkCABI : (layout : StructLayout) -> Either String (CABICompliant layout)
136- checkCABI layout =
137- -- Verify C ABI rules
138- Right (CABIOk layout ? fieldsAlignedProof)
139-
140- -- ------------------------------------------------------------------------------
141- -- Example Layouts
142- -- ------------------------------------------------------------------------------
143-
144- ||| Example: Simple struct layout
145- public export
146- exampleLayout : StructLayout
147- exampleLayout =
148- MkStructLayout
149- [ MkField " x" 0 4 4 -- Bits32 at offset 0
150- , MkField " y" 8 8 8 -- Bits64 at offset 8 (4 bytes padding)
151- , MkField " z" 16 8 8 -- Double at offset 16
152- ]
153- 24 -- Total size: 24 bytes
154- 8 -- Alignment: 8 bytes
155-
156- ||| Proof that example layout is valid
157- export
158- exampleLayoutValid : CABICompliant exampleLayout
159- exampleLayoutValid = CABIOk exampleLayout ? exampleFieldsAligned
160-
161- -- ------------------------------------------------------------------------------
162- -- Offset Calculation
163- -- ------------------------------------------------------------------------------
164-
165- ||| Calculate field offset with proof of correctness
166- public export
167- fieldOffset : (layout : StructLayout) -> (fieldName : String) -> Maybe (n : Nat ** Field)
168- fieldOffset layout name =
169- case findIndex (\ f => f. name == name) layout. fields of
170- Just idx => Just (finToNat idx ** index idx layout. fields)
171- Nothing => Nothing
172-
173- ||| Proof that field offset is within struct bounds
174- public export
175- offsetInBounds : (layout : StructLayout) -> (f : Field) -> So (f.offset + f.size <= layout.totalSize)
176- offsetInBounds layout f = ? offsetInBoundsProof
0 commit comments