1// Copyright 2017 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// linux/mkall.go - Generates all Linux zsysnum, zsyscall, zerror, and ztype
6// files for all Linux architectures supported by the go compiler. See
7// README.md for more information about the build system.
8
9// To run it you must have a git checkout of the Linux kernel and glibc. Once
10// the appropriate sources are ready, the program is run as:
11//     go run linux/mkall.go <linux_dir> <glibc_dir>
12
13// +build ignore
14
15package main
16
17import (
18	"bufio"
19	"bytes"
20	"debug/elf"
21	"encoding/binary"
22	"errors"
23	"fmt"
24	"io"
25	"io/ioutil"
26	"os"
27	"os/exec"
28	"path/filepath"
29	"runtime"
30	"strings"
31	"unicode"
32)
33
34// These will be paths to the appropriate source directories.
35var LinuxDir string
36var GlibcDir string
37
38const TempDir = "/tmp"
39const IncludeDir = TempDir + "/include" // To hold our C headers
40const BuildDir = TempDir + "/build"     // To hold intermediate build files
41
42const GOOS = "linux"       // Only for Linux targets
43const BuildArch = "amd64"  // Must be built on this architecture
44const MinKernel = "2.6.23" // https://golang.org/doc/install#requirements
45
46type target struct {
47	GoArch     string // Architecture name according to Go
48	LinuxArch  string // Architecture name according to the Linux Kernel
49	GNUArch    string // Architecture name according to GNU tools (https://wiki.debian.org/Multiarch/Tuples)
50	BigEndian  bool   // Default Little Endian
51	SignedChar bool   // Is -fsigned-char needed (default no)
52	Bits       int
53}
54
55// List of all Linux targets supported by the go compiler. Currently, riscv64
56// and sparc64 are not fully supported, but there is enough support already to
57// generate Go type and error definitions.
58var targets = []target{
59	{
60		GoArch:    "386",
61		LinuxArch: "x86",
62		GNUArch:   "i686-linux-gnu", // Note "i686" not "i386"
63		Bits:      32,
64	},
65	{
66		GoArch:    "amd64",
67		LinuxArch: "x86",
68		GNUArch:   "x86_64-linux-gnu",
69		Bits:      64,
70	},
71	{
72		GoArch:     "arm64",
73		LinuxArch:  "arm64",
74		GNUArch:    "aarch64-linux-gnu",
75		SignedChar: true,
76		Bits:       64,
77	},
78	{
79		GoArch:    "arm",
80		LinuxArch: "arm",
81		GNUArch:   "arm-linux-gnueabi",
82		Bits:      32,
83	},
84	{
85		GoArch:    "mips",
86		LinuxArch: "mips",
87		GNUArch:   "mips-linux-gnu",
88		BigEndian: true,
89		Bits:      32,
90	},
91	{
92		GoArch:    "mipsle",
93		LinuxArch: "mips",
94		GNUArch:   "mipsel-linux-gnu",
95		Bits:      32,
96	},
97	{
98		GoArch:    "mips64",
99		LinuxArch: "mips",
100		GNUArch:   "mips64-linux-gnuabi64",
101		BigEndian: true,
102		Bits:      64,
103	},
104	{
105		GoArch:    "mips64le",
106		LinuxArch: "mips",
107		GNUArch:   "mips64el-linux-gnuabi64",
108		Bits:      64,
109	},
110	{
111		GoArch:    "ppc64",
112		LinuxArch: "powerpc",
113		GNUArch:   "powerpc64-linux-gnu",
114		BigEndian: true,
115		Bits:      64,
116	},
117	{
118		GoArch:    "ppc64le",
119		LinuxArch: "powerpc",
120		GNUArch:   "powerpc64le-linux-gnu",
121		Bits:      64,
122	},
123	{
124		GoArch:    "riscv64",
125		LinuxArch: "riscv",
126		GNUArch:   "riscv64-linux-gnu",
127		Bits:      64,
128	},
129	{
130		GoArch:     "s390x",
131		LinuxArch:  "s390",
132		GNUArch:    "s390x-linux-gnu",
133		BigEndian:  true,
134		SignedChar: true,
135		Bits:       64,
136	},
137	{
138		GoArch:    "sparc64",
139		LinuxArch: "sparc",
140		GNUArch:   "sparc64-linux-gnu",
141		BigEndian: true,
142		Bits:      64,
143	},
144}
145
146// ptracePairs is a list of pairs of targets that can, in some cases,
147// run each other's binaries.
148var ptracePairs = []struct{ a1, a2 string }{
149	{"386", "amd64"},
150	{"arm", "arm64"},
151	{"mips", "mips64"},
152	{"mipsle", "mips64le"},
153}
154
155func main() {
156	if runtime.GOOS != GOOS || runtime.GOARCH != BuildArch {
157		fmt.Printf("Build system has GOOS_GOARCH = %s_%s, need %s_%s\n",
158			runtime.GOOS, runtime.GOARCH, GOOS, BuildArch)
159		return
160	}
161
162	// Check that we are using the new build system if we should
163	if os.Getenv("GOLANG_SYS_BUILD") != "docker" {
164		fmt.Println("In the new build system, mkall.go should not be called directly.")
165		fmt.Println("See README.md")
166		return
167	}
168
169	// Parse the command line options
170	if len(os.Args) != 3 {
171		fmt.Println("USAGE: go run linux/mkall.go <linux_dir> <glibc_dir>")
172		return
173	}
174	LinuxDir = os.Args[1]
175	GlibcDir = os.Args[2]
176
177	for _, t := range targets {
178		fmt.Printf("----- GENERATING: %s -----\n", t.GoArch)
179		if err := t.generateFiles(); err != nil {
180			fmt.Printf("%v\n***** FAILURE:    %s *****\n\n", err, t.GoArch)
181		} else {
182			fmt.Printf("----- SUCCESS:    %s -----\n\n", t.GoArch)
183		}
184	}
185
186	fmt.Printf("----- GENERATING ptrace pairs -----\n")
187	ok := true
188	for _, p := range ptracePairs {
189		if err := generatePtracePair(p.a1, p.a2); err != nil {
190			fmt.Printf("%v\n***** FAILURE: %s/%s *****\n\n", err, p.a1, p.a2)
191			ok = false
192		}
193	}
194	if ok {
195		fmt.Printf("----- SUCCESS ptrace pairs    -----\n\n")
196	}
197}
198
199// Makes an exec.Cmd with Stderr attached to os.Stderr
200func makeCommand(name string, args ...string) *exec.Cmd {
201	cmd := exec.Command(name, args...)
202	cmd.Stderr = os.Stderr
203	return cmd
204}
205
206// Set GOARCH for target and build environments.
207func (t *target) setTargetBuildArch(cmd *exec.Cmd) {
208	// Set GOARCH_TARGET so command knows what GOARCH is..
209	cmd.Env = append(os.Environ(), "GOARCH_TARGET="+t.GoArch)
210	// Set GOARCH to host arch for command, so it can run natively.
211	for i, s := range cmd.Env {
212		if strings.HasPrefix(s, "GOARCH=") {
213			cmd.Env[i] = "GOARCH=" + BuildArch
214		}
215	}
216}
217
218// Runs the command, pipes output to a formatter, pipes that to an output file.
219func (t *target) commandFormatOutput(formatter string, outputFile string,
220	name string, args ...string) (err error) {
221	mainCmd := makeCommand(name, args...)
222	if name == "mksyscall" {
223		args = append([]string{"run", "mksyscall.go"}, args...)
224		mainCmd = makeCommand("go", args...)
225		t.setTargetBuildArch(mainCmd)
226	} else if name == "mksysnum" {
227		args = append([]string{"run", "linux/mksysnum.go"}, args...)
228		mainCmd = makeCommand("go", args...)
229		t.setTargetBuildArch(mainCmd)
230	}
231
232	fmtCmd := makeCommand(formatter)
233	if formatter == "mkpost" {
234		fmtCmd = makeCommand("go", "run", "mkpost.go")
235		t.setTargetBuildArch(fmtCmd)
236	}
237
238	// mainCmd | fmtCmd > outputFile
239	if fmtCmd.Stdin, err = mainCmd.StdoutPipe(); err != nil {
240		return
241	}
242	if fmtCmd.Stdout, err = os.Create(outputFile); err != nil {
243		return
244	}
245
246	// Make sure the formatter eventually closes
247	if err = fmtCmd.Start(); err != nil {
248		return
249	}
250	defer func() {
251		fmtErr := fmtCmd.Wait()
252		if err == nil {
253			err = fmtErr
254		}
255	}()
256
257	return mainCmd.Run()
258}
259
260// Generates all the files for a Linux target
261func (t *target) generateFiles() error {
262	// Setup environment variables
263	os.Setenv("GOOS", GOOS)
264	os.Setenv("GOARCH", t.GoArch)
265
266	// Get appropriate compiler and emulator (unless on x86)
267	if t.LinuxArch != "x86" {
268		// Check/Setup cross compiler
269		compiler := t.GNUArch + "-gcc"
270		if _, err := exec.LookPath(compiler); err != nil {
271			return err
272		}
273		os.Setenv("CC", compiler)
274
275		// Check/Setup emulator (usually first component of GNUArch)
276		qemuArchName := t.GNUArch[:strings.Index(t.GNUArch, "-")]
277		if t.LinuxArch == "powerpc" {
278			qemuArchName = t.GoArch
279		}
280		// Fake uname for QEMU to allow running on Host kernel version < 4.15
281		if t.LinuxArch == "riscv" {
282			os.Setenv("QEMU_UNAME", "4.15")
283		}
284		os.Setenv("GORUN", "qemu-"+qemuArchName)
285	} else {
286		os.Setenv("CC", "gcc")
287	}
288
289	// Make the include directory and fill it with headers
290	if err := os.MkdirAll(IncludeDir, os.ModePerm); err != nil {
291		return err
292	}
293	defer os.RemoveAll(IncludeDir)
294	if err := t.makeHeaders(); err != nil {
295		return fmt.Errorf("could not make header files: %v", err)
296	}
297	fmt.Println("header files generated")
298
299	// Make each of the four files
300	if err := t.makeZSysnumFile(); err != nil {
301		return fmt.Errorf("could not make zsysnum file: %v", err)
302	}
303	fmt.Println("zsysnum file generated")
304
305	if err := t.makeZSyscallFile(); err != nil {
306		return fmt.Errorf("could not make zsyscall file: %v", err)
307	}
308	fmt.Println("zsyscall file generated")
309
310	if err := t.makeZTypesFile(); err != nil {
311		return fmt.Errorf("could not make ztypes file: %v", err)
312	}
313	fmt.Println("ztypes file generated")
314
315	if err := t.makeZErrorsFile(); err != nil {
316		return fmt.Errorf("could not make zerrors file: %v", err)
317	}
318	fmt.Println("zerrors file generated")
319
320	return nil
321}
322
323// Create the Linux, glibc and ABI (C compiler convention) headers in the include directory.
324func (t *target) makeHeaders() error {
325	// Make the Linux headers we need for this architecture
326	linuxMake := makeCommand("make", "headers_install", "ARCH="+t.LinuxArch, "INSTALL_HDR_PATH="+TempDir)
327	linuxMake.Dir = LinuxDir
328	if err := linuxMake.Run(); err != nil {
329		return err
330	}
331
332	// A Temporary build directory for glibc
333	if err := os.MkdirAll(BuildDir, os.ModePerm); err != nil {
334		return err
335	}
336	defer os.RemoveAll(BuildDir)
337
338	// Make the glibc headers we need for this architecture
339	confScript := filepath.Join(GlibcDir, "configure")
340	glibcConf := makeCommand(confScript, "--prefix="+TempDir, "--host="+t.GNUArch, "--enable-kernel="+MinKernel)
341	glibcConf.Dir = BuildDir
342	if err := glibcConf.Run(); err != nil {
343		return err
344	}
345	glibcMake := makeCommand("make", "install-headers")
346	glibcMake.Dir = BuildDir
347	if err := glibcMake.Run(); err != nil {
348		return err
349	}
350	// We only need an empty stubs file
351	stubsFile := filepath.Join(IncludeDir, "gnu/stubs.h")
352	if file, err := os.Create(stubsFile); err != nil {
353		return err
354	} else {
355		file.Close()
356	}
357
358	// ABI headers will specify C compiler behavior for the target platform.
359	return t.makeABIHeaders()
360}
361
362// makeABIHeaders generates C header files based on the platform's calling convention.
363// While many platforms have formal Application Binary Interfaces, in practice, whatever the
364// dominant C compilers generate is the de-facto calling convention.
365//
366// We generate C headers instead of a Go file, so as to enable references to the ABI from Cgo.
367func (t *target) makeABIHeaders() (err error) {
368	abiDir := filepath.Join(IncludeDir, "abi")
369	if err = os.Mkdir(abiDir, os.ModePerm); err != nil {
370		return err
371	}
372
373	cc := os.Getenv("CC")
374	if cc == "" {
375		return errors.New("CC (compiler) env var not set")
376	}
377
378	// Build a sacrificial ELF file, to mine for C compiler behavior.
379	binPath := filepath.Join(TempDir, "tmp_abi.o")
380	bin, err := t.buildELF(cc, cCode, binPath)
381	if err != nil {
382		return fmt.Errorf("cannot build ELF to analyze: %v", err)
383	}
384	defer bin.Close()
385	defer os.Remove(binPath)
386
387	// Right now, we put everything in abi.h, but we may change this later.
388	abiFile, err := os.Create(filepath.Join(abiDir, "abi.h"))
389	if err != nil {
390		return err
391	}
392	defer func() {
393		if cerr := abiFile.Close(); cerr != nil && err == nil {
394			err = cerr
395		}
396	}()
397
398	if err = t.writeBitFieldMasks(bin, abiFile); err != nil {
399		return fmt.Errorf("cannot write bitfield masks: %v", err)
400	}
401
402	return nil
403}
404
405func (t *target) buildELF(cc, src, path string) (*elf.File, error) {
406	// Compile the cCode source using the set compiler - we will need its .data section.
407	// Do not link the binary, so that we can find .data section offsets from the symbol values.
408	ccCmd := makeCommand(cc, "-o", path, "-gdwarf", "-x", "c", "-c", "-")
409	ccCmd.Stdin = strings.NewReader(src)
410	ccCmd.Stdout = os.Stdout
411	if err := ccCmd.Run(); err != nil {
412		return nil, fmt.Errorf("compiler error: %v", err)
413	}
414
415	bin, err := elf.Open(path)
416	if err != nil {
417		return nil, fmt.Errorf("cannot read ELF file %s: %v", path, err)
418	}
419
420	return bin, nil
421}
422
423func (t *target) writeBitFieldMasks(bin *elf.File, out io.Writer) error {
424	symbols, err := bin.Symbols()
425	if err != nil {
426		return fmt.Errorf("getting ELF symbols: %v", err)
427	}
428	var masksSym *elf.Symbol
429
430	for _, sym := range symbols {
431		if sym.Name == "masks" {
432			masksSym = &sym
433		}
434	}
435
436	if masksSym == nil {
437		return errors.New("could not find the 'masks' symbol in ELF symtab")
438	}
439
440	dataSection := bin.Section(".data")
441	if dataSection == nil {
442		return errors.New("ELF file has no .data section")
443	}
444
445	data, err := dataSection.Data()
446	if err != nil {
447		return fmt.Errorf("could not read .data section: %v\n", err)
448	}
449
450	var bo binary.ByteOrder
451	if t.BigEndian {
452		bo = binary.BigEndian
453	} else {
454		bo = binary.LittleEndian
455	}
456
457	// 64 bit masks of type uint64 are stored in the data section starting at masks.Value.
458	// Here we are running on AMD64, but these values may be big endian or little endian,
459	// depending on target architecture.
460	for i := uint64(0); i < 64; i++ {
461		off := masksSym.Value + i*8
462		// Define each mask in native by order, so as to match target endian.
463		fmt.Fprintf(out, "#define BITFIELD_MASK_%d %dULL\n", i, bo.Uint64(data[off:off+8]))
464	}
465
466	return nil
467}
468
469// makes the zsysnum_linux_$GOARCH.go file
470func (t *target) makeZSysnumFile() error {
471	zsysnumFile := fmt.Sprintf("zsysnum_linux_%s.go", t.GoArch)
472	unistdFile := filepath.Join(IncludeDir, "asm/unistd.h")
473
474	args := append(t.cFlags(), unistdFile)
475	return t.commandFormatOutput("gofmt", zsysnumFile, "mksysnum", args...)
476}
477
478// makes the zsyscall_linux_$GOARCH.go file
479func (t *target) makeZSyscallFile() error {
480	zsyscallFile := fmt.Sprintf("zsyscall_linux_%s.go", t.GoArch)
481	// Find the correct architecture syscall file (might end with x.go)
482	archSyscallFile := fmt.Sprintf("syscall_linux_%s.go", t.GoArch)
483	if _, err := os.Stat(archSyscallFile); os.IsNotExist(err) {
484		shortArch := strings.TrimSuffix(t.GoArch, "le")
485		archSyscallFile = fmt.Sprintf("syscall_linux_%sx.go", shortArch)
486	}
487
488	args := append(t.mksyscallFlags(), "-tags", "linux,"+t.GoArch,
489		"syscall_linux.go", archSyscallFile)
490	return t.commandFormatOutput("gofmt", zsyscallFile, "mksyscall", args...)
491}
492
493// makes the zerrors_linux_$GOARCH.go file
494func (t *target) makeZErrorsFile() error {
495	zerrorsFile := fmt.Sprintf("zerrors_linux_%s.go", t.GoArch)
496
497	return t.commandFormatOutput("gofmt", zerrorsFile, "./mkerrors.sh", t.cFlags()...)
498}
499
500// makes the ztypes_linux_$GOARCH.go file
501func (t *target) makeZTypesFile() error {
502	ztypesFile := fmt.Sprintf("ztypes_linux_%s.go", t.GoArch)
503
504	args := []string{"tool", "cgo", "-godefs", "--"}
505	args = append(args, t.cFlags()...)
506	args = append(args, "linux/types.go")
507	return t.commandFormatOutput("mkpost", ztypesFile, "go", args...)
508}
509
510// Flags that should be given to gcc and cgo for this target
511func (t *target) cFlags() []string {
512	// Compile statically to avoid cross-architecture dynamic linking.
513	flags := []string{"-Wall", "-Werror", "-static", "-I" + IncludeDir}
514
515	// Architecture-specific flags
516	if t.SignedChar {
517		flags = append(flags, "-fsigned-char")
518	}
519	if t.LinuxArch == "x86" {
520		flags = append(flags, fmt.Sprintf("-m%d", t.Bits))
521	}
522
523	return flags
524}
525
526// Flags that should be given to mksyscall for this target
527func (t *target) mksyscallFlags() (flags []string) {
528	if t.Bits == 32 {
529		if t.BigEndian {
530			flags = append(flags, "-b32")
531		} else {
532			flags = append(flags, "-l32")
533		}
534	}
535
536	// This flag means a 64-bit value should use (even, odd)-pair.
537	if t.GoArch == "arm" || (t.LinuxArch == "mips" && t.Bits == 32) {
538		flags = append(flags, "-arm")
539	}
540	return
541}
542
543// generatePtracePair takes a pair of GOARCH values that can run each
544// other's binaries, such as 386 and amd64. It extracts the PtraceRegs
545// type for each one. It writes a new file defining the types
546// PtraceRegsArch1 and PtraceRegsArch2 and the corresponding functions
547// Ptrace{Get,Set}Regs{arch1,arch2}. This permits debugging the other
548// binary on a native system.
549func generatePtracePair(arch1, arch2 string) error {
550	def1, err := ptraceDef(arch1)
551	if err != nil {
552		return err
553	}
554	def2, err := ptraceDef(arch2)
555	if err != nil {
556		return err
557	}
558	f, err := os.Create(fmt.Sprintf("zptrace%s_linux.go", arch1))
559	if err != nil {
560		return err
561	}
562	buf := bufio.NewWriter(f)
563	fmt.Fprintf(buf, "// Code generated by linux/mkall.go generatePtracePair(%s, %s). DO NOT EDIT.\n", arch1, arch2)
564	fmt.Fprintf(buf, "\n")
565	fmt.Fprintf(buf, "// +build linux\n")
566	fmt.Fprintf(buf, "// +build %s %s\n", arch1, arch2)
567	fmt.Fprintf(buf, "\n")
568	fmt.Fprintf(buf, "package unix\n")
569	fmt.Fprintf(buf, "\n")
570	fmt.Fprintf(buf, "%s\n", `import "unsafe"`)
571	fmt.Fprintf(buf, "\n")
572	writeOnePtrace(buf, arch1, def1)
573	fmt.Fprintf(buf, "\n")
574	writeOnePtrace(buf, arch2, def2)
575	if err := buf.Flush(); err != nil {
576		return err
577	}
578	if err := f.Close(); err != nil {
579		return err
580	}
581	return nil
582}
583
584// ptraceDef returns the definition of PtraceRegs for arch.
585func ptraceDef(arch string) (string, error) {
586	filename := fmt.Sprintf("ztypes_linux_%s.go", arch)
587	data, err := ioutil.ReadFile(filename)
588	if err != nil {
589		return "", fmt.Errorf("reading %s: %v", filename, err)
590	}
591	start := bytes.Index(data, []byte("type PtraceRegs struct"))
592	if start < 0 {
593		return "", fmt.Errorf("%s: no definition of PtraceRegs", filename)
594	}
595	data = data[start:]
596	end := bytes.Index(data, []byte("\n}\n"))
597	if end < 0 {
598		return "", fmt.Errorf("%s: can't find end of PtraceRegs definition", filename)
599	}
600	return string(data[:end+2]), nil
601}
602
603// writeOnePtrace writes out the ptrace definitions for arch.
604func writeOnePtrace(w io.Writer, arch, def string) {
605	uarch := string(unicode.ToUpper(rune(arch[0]))) + arch[1:]
606	fmt.Fprintf(w, "// PtraceRegs%s is the registers used by %s binaries.\n", uarch, arch)
607	fmt.Fprintf(w, "%s\n", strings.Replace(def, "PtraceRegs", "PtraceRegs"+uarch, 1))
608	fmt.Fprintf(w, "\n")
609	fmt.Fprintf(w, "// PtraceGetRegs%s fetches the registers used by %s binaries.\n", uarch, arch)
610	fmt.Fprintf(w, "func PtraceGetRegs%s(pid int, regsout *PtraceRegs%s) error {\n", uarch, uarch)
611	fmt.Fprintf(w, "\treturn ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))\n")
612	fmt.Fprintf(w, "}\n")
613	fmt.Fprintf(w, "\n")
614	fmt.Fprintf(w, "// PtraceSetRegs%s sets the registers used by %s binaries.\n", uarch, arch)
615	fmt.Fprintf(w, "func PtraceSetRegs%s(pid int, regs *PtraceRegs%s) error {\n", uarch, uarch)
616	fmt.Fprintf(w, "\treturn ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))\n")
617	fmt.Fprintf(w, "}\n")
618}
619
620// cCode is compiled for the target architecture, and the resulting data section is carved for
621// the statically initialized bit masks.
622const cCode = `
623// Bit fields are used in some system calls and other ABIs, but their memory layout is
624// implementation-defined [1]. Even with formal ABIs, bit fields are a source of subtle bugs [2].
625// Here we generate the offsets for all 64 bits in an uint64.
626// 1: http://en.cppreference.com/w/c/language/bit_field
627// 2: https://lwn.net/Articles/478657/
628
629#include <stdint.h>
630
631struct bitfield {
632	union {
633		uint64_t val;
634		struct {
635			uint64_t u64_bit_0 : 1;
636			uint64_t u64_bit_1 : 1;
637			uint64_t u64_bit_2 : 1;
638			uint64_t u64_bit_3 : 1;
639			uint64_t u64_bit_4 : 1;
640			uint64_t u64_bit_5 : 1;
641			uint64_t u64_bit_6 : 1;
642			uint64_t u64_bit_7 : 1;
643			uint64_t u64_bit_8 : 1;
644			uint64_t u64_bit_9 : 1;
645			uint64_t u64_bit_10 : 1;
646			uint64_t u64_bit_11 : 1;
647			uint64_t u64_bit_12 : 1;
648			uint64_t u64_bit_13 : 1;
649			uint64_t u64_bit_14 : 1;
650			uint64_t u64_bit_15 : 1;
651			uint64_t u64_bit_16 : 1;
652			uint64_t u64_bit_17 : 1;
653			uint64_t u64_bit_18 : 1;
654			uint64_t u64_bit_19 : 1;
655			uint64_t u64_bit_20 : 1;
656			uint64_t u64_bit_21 : 1;
657			uint64_t u64_bit_22 : 1;
658			uint64_t u64_bit_23 : 1;
659			uint64_t u64_bit_24 : 1;
660			uint64_t u64_bit_25 : 1;
661			uint64_t u64_bit_26 : 1;
662			uint64_t u64_bit_27 : 1;
663			uint64_t u64_bit_28 : 1;
664			uint64_t u64_bit_29 : 1;
665			uint64_t u64_bit_30 : 1;
666			uint64_t u64_bit_31 : 1;
667			uint64_t u64_bit_32 : 1;
668			uint64_t u64_bit_33 : 1;
669			uint64_t u64_bit_34 : 1;
670			uint64_t u64_bit_35 : 1;
671			uint64_t u64_bit_36 : 1;
672			uint64_t u64_bit_37 : 1;
673			uint64_t u64_bit_38 : 1;
674			uint64_t u64_bit_39 : 1;
675			uint64_t u64_bit_40 : 1;
676			uint64_t u64_bit_41 : 1;
677			uint64_t u64_bit_42 : 1;
678			uint64_t u64_bit_43 : 1;
679			uint64_t u64_bit_44 : 1;
680			uint64_t u64_bit_45 : 1;
681			uint64_t u64_bit_46 : 1;
682			uint64_t u64_bit_47 : 1;
683			uint64_t u64_bit_48 : 1;
684			uint64_t u64_bit_49 : 1;
685			uint64_t u64_bit_50 : 1;
686			uint64_t u64_bit_51 : 1;
687			uint64_t u64_bit_52 : 1;
688			uint64_t u64_bit_53 : 1;
689			uint64_t u64_bit_54 : 1;
690			uint64_t u64_bit_55 : 1;
691			uint64_t u64_bit_56 : 1;
692			uint64_t u64_bit_57 : 1;
693			uint64_t u64_bit_58 : 1;
694			uint64_t u64_bit_59 : 1;
695			uint64_t u64_bit_60 : 1;
696			uint64_t u64_bit_61 : 1;
697			uint64_t u64_bit_62 : 1;
698			uint64_t u64_bit_63 : 1;
699		};
700	};
701};
702
703struct bitfield masks[] = {
704	{.u64_bit_0 = 1},
705	{.u64_bit_1 = 1},
706	{.u64_bit_2 = 1},
707	{.u64_bit_3 = 1},
708	{.u64_bit_4 = 1},
709	{.u64_bit_5 = 1},
710	{.u64_bit_6 = 1},
711	{.u64_bit_7 = 1},
712	{.u64_bit_8 = 1},
713	{.u64_bit_9 = 1},
714	{.u64_bit_10 = 1},
715	{.u64_bit_11 = 1},
716	{.u64_bit_12 = 1},
717	{.u64_bit_13 = 1},
718	{.u64_bit_14 = 1},
719	{.u64_bit_15 = 1},
720	{.u64_bit_16 = 1},
721	{.u64_bit_17 = 1},
722	{.u64_bit_18 = 1},
723	{.u64_bit_19 = 1},
724	{.u64_bit_20 = 1},
725	{.u64_bit_21 = 1},
726	{.u64_bit_22 = 1},
727	{.u64_bit_23 = 1},
728	{.u64_bit_24 = 1},
729	{.u64_bit_25 = 1},
730	{.u64_bit_26 = 1},
731	{.u64_bit_27 = 1},
732	{.u64_bit_28 = 1},
733	{.u64_bit_29 = 1},
734	{.u64_bit_30 = 1},
735	{.u64_bit_31 = 1},
736	{.u64_bit_32 = 1},
737	{.u64_bit_33 = 1},
738	{.u64_bit_34 = 1},
739	{.u64_bit_35 = 1},
740	{.u64_bit_36 = 1},
741	{.u64_bit_37 = 1},
742	{.u64_bit_38 = 1},
743	{.u64_bit_39 = 1},
744	{.u64_bit_40 = 1},
745	{.u64_bit_41 = 1},
746	{.u64_bit_42 = 1},
747	{.u64_bit_43 = 1},
748	{.u64_bit_44 = 1},
749	{.u64_bit_45 = 1},
750	{.u64_bit_46 = 1},
751	{.u64_bit_47 = 1},
752	{.u64_bit_48 = 1},
753	{.u64_bit_49 = 1},
754	{.u64_bit_50 = 1},
755	{.u64_bit_51 = 1},
756	{.u64_bit_52 = 1},
757	{.u64_bit_53 = 1},
758	{.u64_bit_54 = 1},
759	{.u64_bit_55 = 1},
760	{.u64_bit_56 = 1},
761	{.u64_bit_57 = 1},
762	{.u64_bit_58 = 1},
763	{.u64_bit_59 = 1},
764	{.u64_bit_60 = 1},
765	{.u64_bit_61 = 1},
766	{.u64_bit_62 = 1},
767	{.u64_bit_63 = 1}
768};
769
770int main(int argc, char **argv) {
771	struct bitfield *mask_ptr = &masks[0];
772	return mask_ptr->val;
773}
774
775`
776