summary refs log tree commit diff
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2021-08-17 15:18:00 +0200
committerQuentin Carbonneaux <quentin@c9x.me>2021-08-23 10:03:13 +0200
commitf3414a492bf4623731f3850aaae5b4a7a2a83a4d (patch)
treeb2846c060327a421e5894527ca10225112daacf2
parent2bbfcf61b38edfe3c347cd270380e5117454c0cf (diff)
downloadroux-f3414a492bf4623731f3850aaae5b4a7a2a83a4d.tar.gz
parsefields: fix padding calculation
This was causing issues with aggregate types. A simple reproduction is:

type :type.1 = align 8 { 24 }
type :type.2 = align 8 { w 1, :type.1 1 }

The size of type.2 should be 32, adding only 4 bytes of padding between
the first and second field. Prior to this patch, 20 bytes of padding was
added instead, causing the type to have a size of 48.

Signed-off-by: Drew DeVault <sir@cmpwn.com>
-rw-r--r--parse.c4
-rw-r--r--test/abi7.ssa21
2 files changed, 23 insertions, 2 deletions
diff --git a/parse.c b/parse.c
index a7e4452..43ae23b 100644
--- a/parse.c
+++ b/parse.c
@@ -867,9 +867,9 @@ parsefields(Field *fld, Typ *ty, int t)
 		}
 		if (a > al)
 			al = a;
-		a = sz & (s-1);
+		a = (1 << a) - 1;
+		a = ((sz + a) & ~a) - sz;
 		if (a) {
-			a = s - a;
 			if (n < NField) {
 				/* padding */
 				fld[n].type = FPad;
diff --git a/test/abi7.ssa b/test/abi7.ssa
new file mode 100644
index 0000000..bf8ca1f
--- /dev/null
+++ b/test/abi7.ssa
@@ -0,0 +1,21 @@
+# test padding calculation with                                                                     
+# embedded struct                                                                                   
+                                                                                                    
+type :s1 = align 4 { w 3 }                                                                          
+type :s2 = align 4 { b 1, :s1 1 }                                                                   
+                                                                                                    
+export function :s2 $test() {                                                                       
+@start                                                                                              
+        ret $s                                                                                      
+}                                                                                                   
+                                                                                                    
+# >>> driver                                                                                        
+# struct s2 {                                                                                       
+#       char x;                                                                                     
+#       struct { int a[3]; } s1;                                                                    
+# } s = { .x = 123 };                                                                               
+# extern struct s2 test(void);                                                                      
+# int main(void) {                                                                                  
+#       return !(test().x == 123);                                                                  
+# }                                                                                                 
+# <<<