aboutsummaryrefslogtreecommitdiffstats
path: root/sys/align.go
blob: 1b1ea66ac38ac6931b093e130b7caea6ddfb8df3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package sys

func initAlign() {
	var rec func(t Type)
	rec = func(t Type) {
		switch t1 := t.(type) {
		case *PtrType:
			rec(t1.Type)
		case *ArrayType:
			rec(t1.Type)
		case *StructType:
			if !t1.padded {
				t1.padded = true
				for _, f := range t1.Fields {
					rec(f)
				}
				addAlignment(t1)
			}
		case *UnionType:
			for _, opt := range t1.Options {
				rec(opt)
			}
		}
	}

	for _, s := range Structs {
		rec(s)
	}
}

func addAlignment(t *StructType) {
	if t.packed {
		return
	}
	var fields []Type
	var off, align uintptr
	varLen := false
	for i, f := range t.Fields {
		a := f.Align()
		if align < a {
			align = a
		}
		if off%a != 0 {
			pad := a - off%a
			off += pad
			fields = append(fields, makePad(pad))
		}
		fields = append(fields, f)
		if at, ok := f.(*ArrayType); ok && (at.Kind == ArrayRandLen || (at.Kind == ArrayRangeLen && at.RangeBegin != at.RangeEnd)) {
			varLen = true
		}
		if at, ok := f.(*BufferType); ok && (at.Kind == BufferBlobRand || (at.Kind == BufferBlobRange && at.RangeBegin != at.RangeEnd)) {
			varLen = true
		}
		if varLen && i != len(t.Fields)-1 {
			panic("embed array in middle of a struct")
		}
		if !varLen {
			off += f.Size()
		}
	}
	if align != 0 && off%align != 0 && !varLen {
		pad := align - off%align
		off += pad
		fields = append(fields, makePad(pad))
	}
	t.Fields = fields
}

func makePad(sz uintptr) Type {
	return &ConstType{
		TypeCommon: TypeCommon{TypeName: "pad", IsOptional: false},
		TypeSize:   sz,
		Val:        0,
		IsPad:      true,
	}
}