├── .github └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── cmd └── myaot │ ├── compile.go │ └── main.go ├── examples ├── README.md ├── hello-c │ ├── hello.c │ └── make.sh └── hello-s │ ├── hello-riscv32 │ ├── hello-riscv32.s │ ├── hello-riscv64 │ ├── hello-riscv64.s │ └── make.sh ├── go.mod ├── go.sum └── pkg ├── ccutil └── ccutil.go ├── compile ├── compile.go └── rt_c ├── iomisc └── iomisc.go └── signext ├── signext.go └── signext_test.go /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: CI 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - 'release/**' 8 | pull_request: 9 | jobs: 10 | main: 11 | strategy: 12 | matrix: 13 | platform: [ubuntu-22.04, macos-12] 14 | runs-on: ${{ matrix.platform }} 15 | steps: 16 | - uses: actions/setup-go@v3 17 | with: 18 | go-version: 1.20.x 19 | - uses: actions/checkout@v3 20 | - run: go install ./cmd/myaot 21 | - name: examples/hello-s/hello-riscv32 22 | run: | 23 | set -eux 24 | myaot compile ./examples/hello-s/hello-riscv32 25 | [ "$(./a.out)" = "Hello World!" ] 26 | - name: examples/hello-s/hello-riscv64 27 | run: | 28 | set -eux 29 | myaot compile ./examples/hello-s/hello-riscv32 30 | [ "$(./a.out)" = "Hello World!" ] 31 | - name: examples/hello-c/hello-riscv64 32 | if: runner.os == 'Linux' 33 | run: | 34 | set -eux 35 | sudo apt-get update 36 | sudo apt-get install -y gcc-riscv64-linux-gnu 37 | ( cd ./examples/hello-c && ./make.sh ) 38 | myaot compile ./examples/hello-c/hello-riscv64 39 | [ "$(./a.out)" = "Hello, C." ] 40 | 41 | wasm: 42 | runs-on: ubuntu-22.04 43 | steps: 44 | - name: "Install Emscripten" 45 | run: | 46 | set -eux 47 | git clone https://github.com/emscripten-core/emsdk.git ~/emsdk 48 | cd ~/emsdk 49 | ./emsdk install latest 50 | ./emsdk activate latest 51 | - uses: actions/setup-go@v3 52 | with: 53 | go-version: 1.20.x 54 | - uses: actions/checkout@v3 55 | - run: go install ./cmd/myaot 56 | - run: | 57 | set -eux 58 | myaot compile -o a.c ./examples/hello-s/hello-riscv32 59 | source ~/emsdk/emsdk_env.sh 60 | emcc -o a.wasm a.c 61 | # TODO: wasi 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | a.* 2 | 3 | # examples/hello-s/hello-riscv32 is small enough to put in the repo, 4 | # but examples/hello-c/hello-riscv32 is too big 5 | examples/hello-c/hello-riscv* 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MyAOT: An experimental AOT(-ish) compiler (Linux/riscv ELF -> Linux/x86\_64 ELF, Darwin/arm64 Mach-O, WASM, ...) 2 | 3 | MyAOT is an experimental AOT(-ish) compiler that translates a Linux/riscv ELF binary to: 4 | - Linux ELF (x86\_64, aarch64, and other little-endian architectures) 5 | - Darwin Mach-O (x86\_64, arm64) 6 | - WASM 7 | 8 | ## Status 9 | Only trivial programs work. 10 | 11 | - No support for shared objects 12 | - No support for memory protection 13 | - No support for threading 14 | - Incomplete support for "A", "F", "D", and "C" instructions 15 | - Lots of syscalls are still unimplemented 16 | - Generated code is not optimized 17 | 18 | ## Usage 19 | 20 | For Linux, Darwin, etc: 21 | ```console 22 | $ file examples/hello-s/hello-riscv32 23 | examples/hello-s/hello-riscv32: ELF 32-bit LSB executable, UCB RISC-V, soft-float ABI, version 1 (SYSV), statically linked, stripped 24 | 25 | $ go install ./cmd/myaot 26 | 27 | $ myaot compile ./examples/hello-s/hello-riscv32 28 | INFO[0000] Compiling ./examples/hello-s/hello-riscv32 --> a.out.c 29 | INFO[0000] Compiling a.out.c --> a.out 30 | INFO[0000] Removing a.out.c 31 | INFO[0000] Done: a.out 32 | 33 | $ file a.out 34 | a.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=2d7a7211b6b8be795a2a9837bd39a8e1130df642, for GNU/Linux 3.2.0, not stripped 35 | 36 | $ ./a.out 37 | Hello World! 38 | ``` 39 | 40 | For WASM: 41 | ```console 42 | $ myaot compile -o a.out.c ./examples/hello-s/hello-riscv32 43 | INFO[0000] Compiling ./examples/hello-s/hello-riscv32 --> a.out.c 44 | INFO[0000] Done: a.out.c 45 | 46 | $ emcc -o a.wasm a.out.c 47 | 48 | $ file a.wasm 49 | a.wasm: WebAssembly (wasm) binary module version 0x1 (MVP) 50 | 51 | $ emcc -o a.html -sWASM -sALLOW_MEMORY_GROWTH a.out.c 52 | 53 | $ emrun a.html 54 | ``` 55 | -------------------------------------------------------------------------------- /cmd/myaot/compile.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "path/filepath" 8 | 9 | "github.com/AkihiroSuda/myaot/pkg/ccutil" 10 | "github.com/AkihiroSuda/myaot/pkg/compile" 11 | "github.com/sirupsen/logrus" 12 | "github.com/spf13/cobra" 13 | ) 14 | 15 | func newCompileCommand() *cobra.Command { 16 | cmd := &cobra.Command{ 17 | Use: "compile FILE", 18 | Aliases: []string{"c"}, 19 | Short: "Compile an riscv32 ELF binary to a native binary", 20 | Args: cobra.MinimumNArgs(1), 21 | RunE: compileAction, 22 | 23 | DisableFlagsInUseLine: true, 24 | } 25 | 26 | flags := cmd.Flags() 27 | flags.StringP("output", "o", "a.out", "Output file, like \"a.out\", or \"a.c\"") 28 | 29 | return cmd 30 | } 31 | 32 | func compileAction(cmd *cobra.Command, args []string) error { 33 | 34 | flags := cmd.Flags() 35 | outFilePath, err := flags.GetString("output") 36 | if err != nil { 37 | return err 38 | } 39 | 40 | inFilePath := args[0] 41 | inFile, err := os.Open(inFilePath) 42 | if err != nil { 43 | return err 44 | } 45 | defer inFile.Close() 46 | 47 | outCPath := outFilePath + ".c" 48 | outIsC := filepath.Ext(outFilePath) == ".c" 49 | if outIsC { 50 | outCPath = outFilePath 51 | } 52 | outC, err := os.Create(outCPath) 53 | if err != nil { 54 | return err 55 | } 56 | defer outC.Close() 57 | 58 | logrus.Infof("Compiling %s --> %s", inFilePath, outCPath) 59 | if err = compile.Compile(outC, inFile); err != nil { 60 | return err 61 | } 62 | if err = outC.Close(); err != nil { 63 | return err 64 | } 65 | 66 | if !outIsC { 67 | logrus.Infof("Compiling %s --> %s", outCPath, outFilePath) 68 | cc, err := ccutil.CC() 69 | if err != nil { 70 | return err 71 | } 72 | // Use -O0 by default to shorten the compilation time 73 | ccCmd := exec.Command(cc, "-O0", "-o", outFilePath, outCPath) 74 | ccCmd.Stdout = os.Stdout 75 | ccCmd.Stderr = os.Stderr 76 | logrus.Debugf("Running %v", ccCmd.Args) 77 | if err = ccCmd.Run(); err != nil { 78 | return fmt.Errorf("failed to run %v: %w", ccCmd.Args, err) 79 | } 80 | 81 | logrus.Infof("Removing %s", outCPath) 82 | if err = os.RemoveAll(outCPath); err != nil { 83 | return err 84 | } 85 | } 86 | logrus.Infof("Done: %s", outFilePath) 87 | return nil 88 | } 89 | -------------------------------------------------------------------------------- /cmd/myaot/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | "github.com/spf13/cobra" 6 | ) 7 | 8 | func main() { 9 | if err := newRootCommand().Execute(); err != nil { 10 | logrus.Fatal(err) 11 | } 12 | } 13 | 14 | func newRootCommand() *cobra.Command { 15 | cmd := &cobra.Command{ 16 | Use: "myaot", 17 | Short: "An experimental AOT(-ish) compiler", 18 | Args: cobra.NoArgs, 19 | SilenceUsage: true, 20 | SilenceErrors: true, 21 | } 22 | flags := cmd.PersistentFlags() 23 | flags.Bool("debug", false, "debug mode") 24 | 25 | cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { 26 | if debug, _ := cmd.Flags().GetBool("debug"); debug { 27 | logrus.SetLevel(logrus.DebugLevel) 28 | } 29 | return nil 30 | } 31 | 32 | cmd.AddCommand( 33 | newCompileCommand(), 34 | ) 35 | return cmd 36 | } 37 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | - [`hello-s`](./hello-s): Hello world, in an assembly. Works perfectly. 4 | - [`hello-c`](./hello-c): Hello world, in C. Works perfectly. 5 | -------------------------------------------------------------------------------- /examples/hello-c/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main(int argc, char *argv[]) { 3 | printf("Hello, C.\n"); 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /examples/hello-c/make.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eux 3 | 4 | riscv64-linux-gnu-gcc -static -O3 -o hello-riscv64 hello.c 5 | 6 | # # To build hello-riscv32: 7 | # git clone https://github.com/riscv/riscv-gnu-toolchain.git 8 | # ( 9 | # cd riscv-gnu-toolchain 10 | # ./configure --prefix=/opt/riscv --with-arch=rv32ia --with-abi=ilp32 11 | # make linux 12 | # ) 13 | 14 | # /opt/riscv/bin/riscv32-unknown-linux-gnu-gcc -march=rv32i -mabi=ilp32 -O3 -static -o hello-riscv32 hello.c 15 | # /opt/riscv/bin/riscv32-unknown-linux-gnu-strip hello-riscv32 16 | -------------------------------------------------------------------------------- /examples/hello-s/hello-riscv32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AkihiroSuda/myaot/768a1779699cf61fb806cad4586883b5df2bb711/examples/hello-s/hello-riscv32 -------------------------------------------------------------------------------- /examples/hello-s/hello-riscv32.s: -------------------------------------------------------------------------------- 1 | hello-riscv64.s -------------------------------------------------------------------------------- /examples/hello-s/hello-riscv64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AkihiroSuda/myaot/768a1779699cf61fb806cad4586883b5df2bb711/examples/hello-s/hello-riscv64 -------------------------------------------------------------------------------- /examples/hello-s/hello-riscv64.s: -------------------------------------------------------------------------------- 1 | # From https://smist08.wordpress.com/2019/09/07/risc-v-assembly-language-hello-world/ 2 | # 3 | # Risc-V Assembler program to print "Hello World!" 4 | # to stdout. 5 | # 6 | # a0-a2 - parameters to linux function services 7 | # a7 - linux function number 8 | # 9 | 10 | .global _start # Provide program starting address to linker 11 | 12 | # Setup the parameters to print hello world 13 | # and then call Linux to do it. 14 | 15 | _start: addi a0, x0, 1 # 1 = StdOut 16 | la a1, helloworld # load address of helloworld 17 | addi a2, x0, 13 # length of our string 18 | addi a7, x0, 64 # linux write system call 19 | ecall # Call linux to output the string 20 | 21 | # Setup the parameters to exit the program 22 | # and then call Linux to do it. 23 | 24 | addi a0, x0, 0 # Use 0 return code 25 | addi a7, x0, 93 # Service command code 93 terminates 26 | ecall # Call linux to terminate the program 27 | 28 | .data 29 | helloworld: .ascii "Hello World!\n" 30 | -------------------------------------------------------------------------------- /examples/hello-s/make.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eux 3 | riscv64-linux-gnu-as -o hello-riscv64.o hello-riscv64.s 4 | riscv64-linux-gnu-ld -o hello-riscv64 hello-riscv64.o 5 | rm -f hello-riscv64.o 6 | riscv64-linux-gnu-strip hello-riscv64 7 | 8 | riscv64-linux-gnu-as -march=rv32i -mabi=ilp32 -o hello-riscv32.o hello-riscv32.s 9 | riscv64-linux-gnu-ld -melf32lriscv -o hello-riscv32 hello-riscv32.o 10 | rm -f hello-riscv32.o 11 | riscv64-linux-gnu-strip hello-riscv32 12 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/AkihiroSuda/myaot 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/sirupsen/logrus v1.9.0 7 | github.com/spf13/cobra v1.6.1 8 | gitlab.com/knipegp/vemu v0.1.1 9 | gotest.tools/v3 v3.4.0 10 | ) 11 | 12 | require ( 13 | github.com/google/go-cmp v0.5.5 // indirect 14 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 15 | github.com/spf13/pflag v1.0.5 // indirect 16 | golang.org/x/sys v0.5.0 // indirect 17 | ) 18 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | 9fans.net/go v0.0.0-20181112161441-237454027057/go.mod h1:diCsxrliIURU9xsYtjCp5AbpQKqdhKmf0ujWDUSkfoY= 2 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 4 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 5 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 6 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 7 | github.com/cosiner/argv v0.1.0/go.mod h1:EusR6TucWKX+zFgtdUsKT2Cvg45K5rtpCcWz4hK06d8= 8 | github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 9 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 10 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 11 | github.com/cweill/gotests v1.5.3/go.mod h1:XZYOJkGVkCRoymaIzmp9Wyi3rUgfA3oOnkuljYrjFV8= 12 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 13 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 14 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 15 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 16 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 17 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 18 | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= 19 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 20 | github.com/go-delve/delve v1.5.0/go.mod h1:c6b3a1Gry6x8a4LGCe/CWzrocrfaHvkUxCj3k4bvSUQ= 21 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 22 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 23 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 24 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 25 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 26 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 27 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 28 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 29 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 30 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 31 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 32 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 33 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 34 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 35 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 36 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 37 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 38 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 39 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 40 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 41 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 42 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 43 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 44 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 45 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 46 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 47 | github.com/google/go-dap v0.2.0/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ= 48 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 49 | github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= 50 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 51 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 52 | github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 53 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 54 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 55 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 56 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 57 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 58 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 59 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 60 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 61 | github.com/mattn/go-colorable v0.0.0-20170327083344-ded68f7a9561/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 62 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 63 | github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 64 | github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 65 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 66 | github.com/motemen/go-quickfix v0.0.0-20200103095207-27e35cdee537/go.mod h1:gvrjti7wRl8ugSgQE1qdEJFNyZt0S0KvkIt91ZTh/dM= 67 | github.com/motemen/go-quickfix v0.0.0-20200118031250-2a6e54e79a50/go.mod h1:8l73QMUlCqIlm+7YUTMwzUS4UH4gQqigx7toFASjmu0= 68 | github.com/motemen/gore v0.5.0/go.mod h1:nbfBnUpb4GL2AnSAWGV70C1B2M1/mYnzPpuOXlQ+2VY= 69 | github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= 70 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 71 | github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= 72 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 73 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 74 | github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 75 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 76 | github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= 77 | github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= 78 | github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 79 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 80 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 81 | github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= 82 | github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 83 | github.com/peterh/liner v0.0.0-20170317030525-88609521dc4b/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= 84 | github.com/peterh/liner v1.1.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= 85 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 86 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 87 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 88 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 89 | github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 90 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 91 | github.com/rogpeppe/godef v1.1.2/go.mod h1:WtY9A/ovuQ+UakAJ1/CEqwwulX/WJjb2kgkokCHi/GY= 92 | github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= 93 | github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 94 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 95 | github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 96 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 97 | github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= 98 | github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 99 | github.com/spf13/cobra v0.0.0-20170417170307-b6cb39589372/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 100 | github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= 101 | github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= 102 | github.com/spf13/pflag v0.0.0-20170417173400-9e4c21054fa1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 103 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 104 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 105 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 106 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 107 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 108 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 109 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 110 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 111 | github.com/tebeka/atexit v0.1.0/go.mod h1:fX+4yxf82RGgrtTehYiDck22z8Hi/1ccyCaeAQfBvlQ= 112 | github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= 113 | github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= 114 | github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= 115 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 116 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 117 | gitlab.com/akita/akita v1.10.0/go.mod h1:bGwhy0YF3Is29i+gnV8zTEeRC8XoHKd2p70vnmrSBJo= 118 | gitlab.com/akita/mem v1.8.1/go.mod h1:DvcohkcXvnnDVCud/IGkI7CNsRdMPa2AK2ntbcp4jmc= 119 | gitlab.com/akita/util v0.3.0/go.mod h1:2MtukqfcPK+bcy3sP1Y2h6DnuQASRlIqJz7X2wTXFGo= 120 | gitlab.com/akita/util v0.6.4/go.mod h1:2MtukqfcPK+bcy3sP1Y2h6DnuQASRlIqJz7X2wTXFGo= 121 | gitlab.com/knipegp/vemu v0.1.1 h1:TQXGG90d/vy+j2YK3jbtweKHqfxXZg7HK+3UQ2enAfk= 122 | gitlab.com/knipegp/vemu v0.1.1/go.mod h1:UYhiL4Gk35fWHYDxaPm98kPPQJxrX74F5LWerAalgUY= 123 | go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= 124 | go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= 125 | go.starlark.net v0.0.0-20190702223751-32f345186213/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg= 126 | golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= 127 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 128 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 129 | golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 130 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 131 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 132 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 133 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 134 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 135 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 136 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 137 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 138 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 139 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 140 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 141 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 142 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 143 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 144 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 145 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 146 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 147 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 148 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 149 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 150 | golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= 151 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 152 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 153 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 154 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 155 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 156 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 157 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 158 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 159 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 160 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 161 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 162 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 163 | golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 164 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 165 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 166 | golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 167 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 168 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 169 | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 170 | golang.org/x/sys v0.0.0-20200915084602-288bc346aa39/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 171 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 172 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 173 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 174 | golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= 175 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 176 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 177 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 178 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 179 | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= 180 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 181 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 182 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 183 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 184 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 185 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 186 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 187 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 188 | golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 189 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 190 | golang.org/x/tools v0.0.0-20191230220329-2aa90c603ae3/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 191 | golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 192 | golang.org/x/tools v0.0.0-20200226224502-204d844ad48d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 193 | golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 194 | golang.org/x/tools v0.0.0-20200914163123-ea50a3c84940/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 195 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 196 | golang.org/x/tools/gopls v0.5.0/go.mod h1:bm7s/5W/faSLxWyOWFtTI+5lZQQVdtksvEXdIfkFE74= 197 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 198 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 199 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 200 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 201 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 202 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 203 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 204 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 205 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 206 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 207 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 208 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 209 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 210 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 211 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 212 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 213 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 214 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 215 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 216 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 217 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 218 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 219 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 220 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 221 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 222 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 223 | gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 224 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 225 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 226 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 227 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 228 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 229 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 230 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 231 | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= 232 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 233 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 234 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 235 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 236 | gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= 237 | gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= 238 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 239 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 240 | honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 241 | mvdan.cc/gofumpt v0.0.0-20200802201014-ab5a8192947d/go.mod h1:bzrjFmaD6+xqohD3KYP0H2FEuxknnBmyyOxdhLdaIws= 242 | mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8= 243 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 244 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 245 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 246 | -------------------------------------------------------------------------------- /pkg/ccutil/ccutil.go: -------------------------------------------------------------------------------- 1 | package ccutil 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | "os/exec" 7 | ) 8 | 9 | func CC() (string, error) { 10 | cands := []string{ 11 | os.Getenv("CLANG"), 12 | os.Getenv("CC"), 13 | // clang seems better for a large C source 14 | "clang", 15 | "cc", 16 | "gcc", 17 | } 18 | for _, f := range cands { 19 | if f == "" { 20 | continue 21 | } 22 | exe, err := exec.LookPath(f) 23 | if err == nil { 24 | return exe, nil 25 | } 26 | } 27 | 28 | return "", errors.New("no C compiler was found") 29 | } 30 | -------------------------------------------------------------------------------- /pkg/compile/compile.go: -------------------------------------------------------------------------------- 1 | package compile 2 | 3 | import ( 4 | "bytes" 5 | "debug/elf" 6 | _ "embed" 7 | "encoding/binary" 8 | "errors" 9 | "fmt" 10 | "io" 11 | 12 | "github.com/AkihiroSuda/myaot/pkg/iomisc" 13 | "github.com/AkihiroSuda/myaot/pkg/signext" 14 | "github.com/sirupsen/logrus" 15 | "gitlab.com/knipegp/vemu/decoder" 16 | ) 17 | 18 | //go:embed rt_c 19 | var rtC []byte 20 | 21 | func Compile(w io.Writer, r io.ReaderAt) error { 22 | w = iomisc.ForceWriter(w) // For code readability 23 | 24 | f, err := elf.NewFile(r) 25 | if err != nil { 26 | return err 27 | } 28 | defer f.Close() 29 | 30 | logrus.Debugf("ELF: %+v", f.FileHeader) 31 | if f.ByteOrder != binary.LittleEndian { 32 | return fmt.Errorf("expected ByteOrder=LittleEndian, got %v", f.ByteOrder) 33 | } 34 | if f.Type != elf.ET_EXEC { 35 | return fmt.Errorf("expected Type=ET_EXEC, got %v", f.Type) 36 | } 37 | if f.Machine != elf.EM_RISCV { 38 | return fmt.Errorf("expected Machine=EM_RISCV, got %v", f.Machine) 39 | } 40 | 41 | var textSec *elf.Section 42 | for i, sec := range f.Sections { 43 | i, sec := i, sec 44 | logrus.Debugf("ELF: Section %d: %+v", i, sec.SectionHeader) 45 | switch sec.SectionHeader.Type { 46 | case elf.SHT_PROGBITS: 47 | switch sec.Name { 48 | case ".text": 49 | if textSec != nil { 50 | return errors.New("multiple .text sections were found") 51 | } 52 | textSec = sec 53 | } 54 | } 55 | } 56 | 57 | if textSec == nil { 58 | return errors.New("loader: no .text section was found") 59 | } 60 | logrus.Debugf("ELF: Text size=%d, begins at 0x%08X", textSec.Size, textSec.Addr) 61 | 62 | // Set constants 63 | fmt.Fprintln(w, "/* Generated by MyAOT */") 64 | if logrus.GetLevel() >= logrus.DebugLevel { 65 | fmt.Fprintln(w, "#define _MA_DEBUG") 66 | } 67 | switch f.Class { 68 | case elf.ELFCLASS32: 69 | fmt.Fprintln(w, "#define _MA_REG_WIDTH 32") 70 | case elf.ELFCLASS64: 71 | fmt.Fprintln(w, "#define _MA_REG_WIDTH 64") 72 | default: 73 | return fmt.Errorf("unknown ELF class %v", f.Class) 74 | } 75 | fmt.Fprintln(w, "") 76 | 77 | // Copy rt_c 78 | io.Copy(w, bytes.NewReader(rtC)) 79 | fmt.Fprintln(w, "") 80 | 81 | // Generate AT_PHDR 82 | if err = generatePH(w, r, f); err != nil { 83 | return err 84 | } 85 | 86 | // Generate VMA entries 87 | vmaEntryIdx := 0 88 | for _, sec := range f.Sections { 89 | if sec.Addr == 0 { 90 | continue 91 | } 92 | var hasBytes bool 93 | switch { 94 | case sec.Name == ".text", sec.Type == elf.SHT_NOBITS: 95 | // NOP 96 | default: 97 | hasBytes = true 98 | dat, err := sec.Data() 99 | if err != nil { 100 | return err 101 | } 102 | fmt.Fprintf(w, "uint8_t _ma_vma_entry_%d_bytes[] = {\n", vmaEntryIdx) 103 | for i, b := range dat { 104 | fmt.Fprintf(w, "0x%02X, ", b) 105 | if i%16 == 15 { 106 | fmt.Fprintln(w, "") 107 | } 108 | } 109 | fmt.Fprintf(w, "}; /* _ma_vma_entry_%d_bytes */\n", vmaEntryIdx) 110 | } 111 | fmt.Fprintf(w, "/* %+v */\n", sec.SectionHeader) 112 | fmt.Fprintf(w, "struct _ma_vma_entry _ma_vma_entry_%d = {\n", vmaEntryIdx) 113 | fmt.Fprintf(w, ".addr = %d,\n", sec.Addr) 114 | fmt.Fprintf(w, ".len = %d,\n", sec.Size) 115 | if hasBytes { 116 | fmt.Fprintf(w, ".bytes = _ma_vma_entry_%d_bytes,\n", vmaEntryIdx) 117 | } 118 | fmt.Fprintf(w, "}; /* _ma_vma_entry_%d */\n", vmaEntryIdx) 119 | fmt.Fprintln(w, "") 120 | vmaEntryIdx++ 121 | } 122 | fmt.Fprintln(w, "") 123 | 124 | // Generate heap VMA entry 125 | fmt.Fprintln(w, "/* HEAP */") 126 | fmt.Fprintf(w, "struct _ma_vma_entry _ma_vma_entry_%d = {\n", vmaEntryIdx) 127 | fmt.Fprintln(w, "/* Fulfilled in _ma_vma_heap_entry_init() */") 128 | fmt.Fprintf(w, "}; /* _ma_vma_entry_%d */\n", vmaEntryIdx) 129 | fmt.Fprintln(w, "") 130 | fmt.Fprintf(w, "struct _ma_vma_entry *_ma_vma_heap_entry = &_ma_vma_entry_%d;\n", vmaEntryIdx) 131 | fmt.Fprintln(w, "") 132 | vmaEntryIdx++ 133 | 134 | // Generate stack VMA entry 135 | fmt.Fprintln(w, "/* STACK */") 136 | fmt.Fprintf(w, "struct _ma_vma_entry _ma_vma_entry_%d = {\n", vmaEntryIdx) 137 | fmt.Fprintln(w, "/* Fulfilled in _ma_vma_stack_entry_init() */") 138 | fmt.Fprintf(w, "}; /* _ma_vma_entry_%d */\n", vmaEntryIdx) 139 | fmt.Fprintln(w, "") 140 | fmt.Fprintf(w, "struct _ma_vma_entry *_ma_vma_stack_entry = &_ma_vma_entry_%d;\n", vmaEntryIdx) 141 | fmt.Fprintln(w, "") 142 | vmaEntryIdx++ 143 | 144 | // Generate VMA table in the descending order, 145 | // to support overwrapping https://stackoverflow.com/questions/25501044/gcc-ld-overlapping-sections-tbss-init-array-in-statically-linked-elf-bin 146 | fmt.Fprintln(w, "struct _ma_vma_entry *_ma_vma_entries[] = {") 147 | for i := vmaEntryIdx - 1; i >= 0; i-- { 148 | fmt.Fprintf(w, "&_ma_vma_entry_%d,\n", i) 149 | } 150 | fmt.Fprintln(w, "NULL,") 151 | fmt.Fprintln(w, "}; /* _ma_vma_entries */") 152 | fmt.Fprintln(w, "") 153 | 154 | // Generate the main state machine 155 | if err = generateMain(w, f, textSec); err != nil { 156 | return err 157 | } 158 | 159 | return nil 160 | } 161 | 162 | func generatePH(w io.Writer, r io.ReaderAt, elfFile *elf.File) error { 163 | sr := io.NewSectionReader(r, 0, 1<<63-1) 164 | if _, err := sr.Seek(0, io.SeekStart); err != nil { 165 | return err 166 | } 167 | var ( 168 | phent, phnum int 169 | phoff int64 170 | ) 171 | switch elfFile.Class { 172 | case elf.ELFCLASS32: 173 | var hdr elf.Header32 174 | if err := binary.Read(sr, elfFile.ByteOrder, &hdr); err != nil { 175 | return err 176 | } 177 | phent, phnum, phoff = int(hdr.Phentsize), int(hdr.Phnum), int64(hdr.Phoff) 178 | case elf.ELFCLASS64: 179 | var hdr elf.Header64 180 | if err := binary.Read(sr, elfFile.ByteOrder, &hdr); err != nil { 181 | return err 182 | } 183 | phent, phnum, phoff = int(hdr.Phentsize), int(hdr.Phnum), int64(hdr.Phoff) 184 | default: 185 | return fmt.Errorf("unsupported ELF class %+v", elfFile.Class) 186 | } 187 | fmt.Fprintf(w, "_ma_reg_t _ma_at_phent=%d;\n", phent) 188 | fmt.Fprintf(w, "_ma_reg_t _ma_at_phnum=%d;\n", phnum) 189 | fmt.Fprintf(w, "_ma_reg_t _ma_at_entry=%d;\n", elfFile.Entry) 190 | fmt.Fprintln(w, "uint8_t _ma_at_ph[] = {") 191 | phSz := phent * phnum 192 | ph := make([]byte, phSz) 193 | n, err := r.ReadAt(ph, phoff) 194 | if err != nil { 195 | return err 196 | } 197 | if n != phSz { 198 | return errors.New("partial PH") 199 | } 200 | for i, b := range ph { 201 | fmt.Fprintf(w, "0x%02X, ", b) 202 | if i%16 == 15 { 203 | fmt.Fprintln(w, "") 204 | } 205 | } 206 | fmt.Fprintln(w, "}; /* _ma_at_ph */") 207 | fmt.Fprintln(w, "") 208 | return nil 209 | } 210 | 211 | // TODO: support non-32 bit instructions 212 | func generateMain(w io.Writer, elfFile *elf.File, textSec *elf.Section) error { 213 | fmt.Fprintln(w, "typedef _ma_reg_t (*_ma_code_func_t)(_ma_reg_t pc);") 214 | fmt.Fprintln(w, "") 215 | 216 | var codeFuncsTableBuf bytes.Buffer 217 | // The instructions are split to small "segments" to shorten the compilation time 218 | const defaultSegSize uint64 = 1024 219 | textReader := textSec.Open() 220 | segNum := 0 221 | for segHead, segFirstInstAddr := textSec.Addr, textSec.Addr; segHead < textSec.Addr+textSec.Size && segHead != 0; { 222 | if expectedSegHead := textSec.Addr + uint64(segNum)*defaultSegSize; expectedSegHead != segHead { 223 | panic(fmt.Errorf("expected seg head 0x%08X, got 0x%08X", expectedSegHead, segHead)) 224 | } 225 | if _, err := textReader.Seek(int64(segFirstInstAddr-textSec.Addr), io.SeekStart); err != nil { 226 | return err 227 | } 228 | logrus.Debugf("Segment %d: addr=0x%08X", segNum, segHead) 229 | nextSegHead, nextSegFirstInstAddr, err := generateCodeFunc(w, textReader, &elfFile.FileHeader, textSec.Addr, segHead, segFirstInstAddr, defaultSegSize) 230 | if err != nil { 231 | return fmt.Errorf("failed to generate the function (segment %d addr=0x%08X): %w", segNum, segHead, err) 232 | } 233 | fmt.Fprintf(&codeFuncsTableBuf, "&_ma_code_func_0x%08X, /* %d */\n", segHead, segNum) 234 | segHead, segFirstInstAddr = nextSegHead, nextSegFirstInstAddr 235 | segNum++ 236 | } 237 | 238 | fmt.Fprintln(w, "_ma_code_func_t _ma_code_funcs[] = {") 239 | if _, err := io.Copy(w, &codeFuncsTableBuf); err != nil { 240 | return err 241 | } 242 | fmt.Fprintln(w, "}; /* _ma_code_funcs */") 243 | fmt.Fprintln(w, "") 244 | 245 | fmt.Fprintln(w, "int main(int argc, char *argv[]) {") 246 | fmt.Fprintln(w, "/* Init */") 247 | fmt.Fprintln(w, "_ma_vma_heap_entry_init();") 248 | fmt.Fprintln(w, "_ma_vma_stack_entry_init(argc, argv);") 249 | fmt.Fprintf(w, "_ma_reg_t pc = 0x%08X;\n", elfFile.Entry) 250 | fmt.Fprintln(w, "while(1) {") 251 | fmt.Fprintf(w, "int f_idx = (pc - 0x%08X) / %d;\n", textSec.Addr, defaultSegSize) 252 | if logrus.GetLevel() >= logrus.DebugLevel { 253 | w.Write([]byte("_MA_DEBUGF(\"===== Segment %d (for PC=0x%08\"_MA_PRIx\") =====\", f_idx, pc);")) 254 | fmt.Fprintf(w, "if (f_idx >= %d) {\n", segNum) 255 | fmt.Fprintln(w, "_MA_FATALF(\"invalid f_idx\");") 256 | fmt.Fprintln(w, "} /* if */") 257 | } 258 | fmt.Fprintln(w, "_ma_code_func_t f = _ma_code_funcs[f_idx];") 259 | fmt.Fprintln(w, "pc = f(pc);") 260 | if logrus.GetLevel() >= logrus.DebugLevel { 261 | w.Write([]byte("_MA_DEBUGF(\"The next segment will begin for PC=0x%08\"_MA_PRIx, pc);")) 262 | } 263 | fmt.Fprintln(w, "} /* while(1) */") 264 | fmt.Fprintln(w, "} /* main */") 265 | fmt.Fprintln(w, "") 266 | 267 | return nil 268 | } 269 | 270 | func generateReadRegExpr(reg decoder.RegisterIndex) string { 271 | if reg == 0 { 272 | // Hard-wired zero 273 | return "0" 274 | } 275 | return fmt.Sprintf("_ma_regs.x[%d]", reg) 276 | } 277 | 278 | func generateStaticJumpStmt(addr, segHead, segSize uint64) string { 279 | var stmt string 280 | if (addr - segHead) < segSize { 281 | if logrus.GetLevel() >= logrus.DebugLevel { 282 | stmt += fmt.Sprintf("_MA_DEBUGF(\"JUMP NEAR STATIC 0x%08X\");", addr) 283 | } 284 | stmt += fmt.Sprintf("goto L_0x%08X;", addr) 285 | } else { 286 | stmt += fmt.Sprintf("_MA_DEBUGF(\"JUMP FAR STATIC 0x%08X\");", addr) 287 | stmt += fmt.Sprintf("return 0x%08X;", addr) 288 | } 289 | return stmt 290 | } 291 | 292 | func generateCodeFunc(w io.Writer, r io.Reader, elfHeader *elf.FileHeader, textHead, segHead, segFirstInstAddr, defaultSegSize uint64) (nextSegHead, nextSegFirstInstAddr uint64, err error) { 293 | fmt.Fprintf(w, "_ma_reg_t static _ma_code_func_0x%08X(_ma_reg_t pc_initial){\n", segHead) 294 | 295 | fmt.Fprintln(w, "/* Temp variables */") 296 | fmt.Fprintln(w, "_ma_reg_t tmp;") 297 | fmt.Fprintln(w, "uint8_t u8;") 298 | fmt.Fprintln(w, "uint16_t u16;") 299 | fmt.Fprintln(w, "uint32_t u32, u32_x, u32_y;") 300 | fmt.Fprintln(w, "uint64_t u64, u64_x, u64_y;") 301 | fmt.Fprintln(w, "void *p;") 302 | 303 | var ( 304 | labelsBuf, codeBuf bytes.Buffer 305 | eof bool 306 | ) 307 | 308 | if segHead > segFirstInstAddr { 309 | panic(fmt.Errorf("segHead 0x%08X must be <= segFirstInstAddr 0x%08X", segHead, segFirstInstAddr)) 310 | } 311 | for i := segHead; i < segFirstInstAddr; i += 2 { 312 | fmt.Fprintln(&labelsBuf, "NULL,") // padding 313 | } 314 | 315 | instAddr := segFirstInstAddr 316 | for instAddr < segHead+defaultSegSize { 317 | var inst16l uint16 318 | if err = binary.Read(r, binary.LittleEndian, &inst16l); err != nil { 319 | if errors.Is(err, io.EOF) { 320 | eof = true 321 | } else { 322 | return 323 | } 324 | } 325 | uncompressed := inst16l&0b11 == 0b11 326 | var ( 327 | inst32 uint32 328 | lastInstLen int 329 | ) 330 | if uncompressed { 331 | // Instruction length: 4 bytes 332 | lastInstLen = 4 333 | var inst16h uint16 334 | if err = binary.Read(r, binary.LittleEndian, &inst16h); err != nil { 335 | return 336 | } 337 | inst32 = uint32(inst16h)<<16 | uint32(inst16l) 338 | } else { 339 | // Instruction length: 2 bytes 340 | lastInstLen = 2 341 | inst32 = uint32(inst16l) 342 | } 343 | inst := decoder.NewRawInstruction(inst32) 344 | if err := generateCodeEntry(&codeBuf, elfHeader, segHead, defaultSegSize, instAddr, inst); err != nil { 345 | errS := fmt.Sprintf("%v (addr=0x%08X, instruction=0x%08X)", err, instAddr, inst32) 346 | logrus.Error(errS) 347 | fmt.Fprintf(&codeBuf, "_MA_FATALF(%q);\n", errS) 348 | } 349 | fmt.Fprintf(&labelsBuf, "&&L_0x%08X,\n", instAddr) 350 | if uncompressed { 351 | fmt.Fprintln(&labelsBuf, "NULL,") // padding 352 | } 353 | instAddr += uint64(lastInstLen) 354 | } 355 | 356 | actualSegSize := instAddr - segHead 357 | logrus.Debugf("actual segment size=%d", actualSegSize) 358 | if !eof { 359 | nextSegHead = segHead + defaultSegSize 360 | nextSegFirstInstAddr = instAddr 361 | } 362 | 363 | fmt.Fprintln(w, "const static void *addr_labels[] = {") 364 | if _, err = io.Copy(w, &labelsBuf); err != nil { 365 | return 366 | } 367 | fmt.Fprintln(w, "}; /* addr_labels */") 368 | 369 | fmt.Fprintf(w, "#define _MA_JUMP(addr) __MA_JUMP((addr), 0x%08X, %d, addr_labels)\n", segHead, actualSegSize) 370 | fmt.Fprintf(w, "#define _MA_JUMP_NEAR(addr) __MA_JUMP_NEAR((addr), 0x%08X, addr_labels)\n", segHead) 371 | fmt.Fprintln(w, "_MA_JUMP_NEAR(pc_initial);") 372 | if _, err = io.Copy(w, &codeBuf); err != nil { 373 | return 374 | } 375 | 376 | fmt.Fprintln(w, "#undef _MA_JUMP") 377 | fmt.Fprintln(w, "#undef _MA_JUMP_NEAR") 378 | if eof { 379 | fmt.Fprintln(w, "_MA_FATALF(\"EOF\");") 380 | } 381 | fmt.Fprintf(w, "return 0x%08X;\n", nextSegFirstInstAddr) 382 | fmt.Fprintf(w, "} /* _ma_code_func_0x%08X */\n", segHead) 383 | fmt.Fprintln(w, "") 384 | return 385 | } 386 | 387 | func generateCodeEntry(w io.Writer, elfHeader *elf.FileHeader, segHead, segSize, instAddr uint64, inst decoder.RawInstruction) error { 388 | fmt.Fprintf(w, "L_0x%08X: /* 0x%08X */\n", instAddr, inst.BinWord) 389 | if logrus.GetLevel() >= logrus.DebugLevel { 390 | fmt.Fprintf(w, "_ma_regs_dump(0x%08X);\n", instAddr) 391 | } 392 | f3 := inst.GetFunct3() 393 | f7 := inst.GetFunct7() 394 | bit12 := decoder.Bit12((inst.BinWord >> 12) & 0b1) 395 | switch inst.MajOp { 396 | case decoder.Std: 397 | switch minorOp := inst.GetMinorOpcode(); minorOp { 398 | case decoder.IntRegReg: 399 | rd, rs1, rs2 := inst.GetRd(), inst.GetRs1(), inst.GetRs2() 400 | if rd == 0 { 401 | break 402 | } 403 | switch f7 { 404 | case decoder.MulDiv: 405 | switch f3 { 406 | case decoder.Mul: // mul rd,rs1,rs2: x[rd] = x[rs1] * x[rs2] 407 | fmt.Fprintf(w, "_ma_regs.x[%d] = (_ma_signed_reg_t)%s * (_ma_signed_reg_t)%s;\n", rd, generateReadRegExpr(rs1), generateReadRegExpr(rs2)) 408 | case decoder.Div: // div rd,rs1,rs2: x[rd] = x[rs1] /s x[rs2] 409 | fmt.Fprintf(w, "_ma_regs.x[%d] = (_ma_signed_reg_t)%s / (_ma_signed_reg_t)%s;\n", rd, generateReadRegExpr(rs1), generateReadRegExpr(rs2)) 410 | case decoder.Divu: // divu rd,rs1,rs2: x[rd] = x[rs1] /u x[rs2] 411 | fmt.Fprintf(w, "_ma_regs.x[%d] = %s / %s;\n", rd, generateReadRegExpr(rs1), generateReadRegExpr(rs2)) 412 | case decoder.Rem: // rem rd,rs1,rs2: x[rd] = x[rs1] %s x[rs2] 413 | fmt.Fprintf(w, "_ma_regs.x[%d] = (_ma_signed_reg_t)%s %% (_ma_signed_reg_t)%s;\n", rd, generateReadRegExpr(rs1), generateReadRegExpr(rs2)) 414 | case decoder.Remu: // remu rd,rs1,rs2: x[rd] = x[rs1] %u x[rs2] 415 | fmt.Fprintf(w, "_ma_regs.x[%d] = %s %% %s;\n", rd, generateReadRegExpr(rs1), generateReadRegExpr(rs2)) 416 | default: 417 | return fmt.Errorf("unsupported MulDiv %+v", f3) 418 | } 419 | default: 420 | switch f3 { 421 | case decoder.RegDiff: 422 | switch f7 { 423 | case decoder.Add: // add rd,rs1,rs2: x[rd] = x[rs1] + x[rs2] 424 | fmt.Fprintf(w, "_ma_regs.x[%d] = %s + %s;\n", rd, generateReadRegExpr(rs1), generateReadRegExpr(rs2)) 425 | case decoder.Sub: // sub rd,rs1,rs2: x[rd] = x[rs1] - x[rs2] 426 | fmt.Fprintf(w, "_ma_regs.x[%d] = %s - %s;\n", rd, generateReadRegExpr(rs1), generateReadRegExpr(rs2)) 427 | default: 428 | return fmt.Errorf("unsupported RegReg funct7 %+v", f7) 429 | } 430 | case decoder.Sll: // sll rd,rs1,rs2: x[rd] = x[rs1] << x[rs2] 431 | fmt.Fprintf(w, "_ma_regs.x[%d] = %s << %s;\n", rd, generateReadRegExpr(rs1), generateReadRegExpr(rs2)) 432 | case decoder.Slt: // slt rd,rs1,rs2: x[rd] = x[rs1] >u x[rs2] 441 | fmt.Fprintf(w, "_ma_regs.x[%d] = (%s >> (%s & 0x1f));\n", rd, generateReadRegExpr(rs1), generateReadRegExpr(rs2)) 442 | case decoder.Sra: // sra rd,rs1,rs2: x[rd] = x[rs1] >>s x[rs2] 443 | fmt.Fprintf(w, "_ma_regs.x[%d] = ((_ma_signed_reg_t)%s >> (%s & 0x1f));\n", rd, generateReadRegExpr(rs1), generateReadRegExpr(rs2)) 444 | default: 445 | return fmt.Errorf("unsupported RegReg funct7 %+v", f7) 446 | } 447 | case decoder.Or: // or rd,rs1,rs2: x[rd] = x[rs1] | x[rs2] 448 | fmt.Fprintf(w, "_ma_regs.x[%d] = %s | %s;\n", rd, generateReadRegExpr(rs1), generateReadRegExpr(rs2)) 449 | case decoder.And: // and rd,rs1,rs2: x[rd] = x[rs1] & x[rs2] 450 | fmt.Fprintf(w, "_ma_regs.x[%d] = %s & %s;\n", rd, generateReadRegExpr(rs1), generateReadRegExpr(rs2)) 451 | default: 452 | return fmt.Errorf("unsupported RegReg funct3 %+v", f3) 453 | } 454 | } 455 | case decoder.IntRegReg32: 456 | rd, rs1, rs2 := inst.GetRd(), inst.GetRs1(), inst.GetRs2() 457 | if rd == 0 { 458 | break 459 | } 460 | switch f3 { 461 | case 0: 462 | switch f7 { 463 | case decoder.Add: /* addw rd,rs1,rs2: x[rd] = sext((x[rs1] + x[rs2])[31:0]) */ 464 | if elfHeader.Class == elf.ELFCLASS32 { 465 | return errors.New("addw: invalid for RV32") 466 | } 467 | fmt.Fprintf(w, "u32 = ((uint32_t)%s + (uint32_t)%s);\n", generateReadRegExpr(rs1), generateReadRegExpr(rs2)) 468 | fmt.Fprintf(w, "_ma_regs.x[%d] = _MA_SIGN_EXT(u32, 32);\n", rd) 469 | case decoder.Sub: /* subw rd,rs1,rs2: x[rd] = sext((x[rs1] - x[rs2])[31:0]) */ 470 | if elfHeader.Class == elf.ELFCLASS32 { 471 | return errors.New("subw: invalid for RV32") 472 | } 473 | fmt.Fprintf(w, "u32 = ((uint32_t)%s - (uint32_t)%s);\n", generateReadRegExpr(rs1), generateReadRegExpr(rs2)) 474 | fmt.Fprintf(w, "_ma_regs.x[%d] = _MA_SIGN_EXT(u32, 32);\n", rd) 475 | default: 476 | return fmt.Errorf("unsupported IntRegReg32 funct3 %+v funct7 %+v", f3, f7) 477 | } 478 | case 1: 479 | switch f7 { 480 | case 0: /* sllw rd,rs1,rs2: x[rd] = sext((x[rs1] << x[rs2][4:0])[31:0]) */ 481 | if elfHeader.Class == elf.ELFCLASS32 { 482 | return errors.New("sllw: invalid for RV32") 483 | } 484 | shamtExpr := fmt.Sprintf("%s & 0x%x", generateReadRegExpr(rs2), 0b11111) // 5 bits 485 | fmt.Fprintf(w, "u32 = ((uint32_t)%s << (%s));\n", generateReadRegExpr(rs1), shamtExpr) 486 | fmt.Fprintf(w, "_ma_regs.x[%d] = _MA_SIGN_EXT(u32, 32);\n", rd) 487 | default: 488 | return fmt.Errorf("unsupported IntRegReg32 funct3 %+v funct7 %+v", f3, f7) 489 | } 490 | default: 491 | return fmt.Errorf("unsupported IntRegReg32 funct3 %+v", f3) 492 | } 493 | case decoder.IntRegImm: 494 | rd, rs1, imm := inst.GetRd(), inst.GetRs1(), inst.GetImmediate() 495 | if rd == 0 { 496 | break 497 | } 498 | shamt := imm & 0b11111 499 | switch f3 { 500 | case decoder.Addi: // addi rd,rs1,imm: x[rd] = x[rs1] + sext(immediate) 501 | fmt.Fprintf(w, "_ma_regs.x[%d] = %s + (_ma_signed_reg_t)%d;\n", rd, generateReadRegExpr(rs1), signext.SignExt(int(imm), 12)) 502 | case decoder.Slli: // slli rd,rs1,shamt: x[rd] = x[rs1] << shamt 503 | fmt.Fprintf(w, "_ma_regs.x[%d] = %s << %d;\n", rd, generateReadRegExpr(rs1), shamt) 504 | case decoder.Sr: 505 | switch f7 { 506 | case 1: // srli with shamt[5] == 1 (RV64 only) 507 | if elfHeader.Class == elf.ELFCLASS64 { 508 | shamt |= 0b100000 509 | } 510 | fallthrough 511 | case decoder.Srl: // srli rd,rs1,shamt: x[rd] = x[rs1] >>u shamt // logical shift 512 | fmt.Fprintf(w, "_ma_regs.x[%d] = (%s >> %d);\n", rd, generateReadRegExpr(rs1), shamt) 513 | case 33: // srai with shamt[5] == 1 (RV64 only) 514 | if elfHeader.Class == elf.ELFCLASS64 { 515 | shamt |= 0b100000 516 | } 517 | fallthrough 518 | case decoder.Sra: // srai rd,rs1,shamt: x[rd] = x[rs1] >>s shamt // arithmetic shift 519 | fmt.Fprintf(w, "_ma_regs.x[%d] = ((_ma_signed_reg_t)%s >> %d);\n", rd, generateReadRegExpr(rs1), shamt) 520 | default: 521 | return fmt.Errorf("unsupported IntRegImm funct7 %+v", f7) 522 | } 523 | case decoder.Slti: // slti rd,rs1,imm: x[rd] = x[rs1] >u shamt) 561 | if elfHeader.Class == elf.ELFCLASS32 { 562 | return errors.New("srliw: invalid for RV32") 563 | } 564 | if shamt&0b11111 != shamt { // 5 bits 565 | return fmt.Errorf("srliw: expected shamt to be <= 0b11111, got %b", shamt) 566 | } 567 | fmt.Fprintf(w, "u32 = ((uint32_t)%s >> %d);\n", generateReadRegExpr(rs1), shamt) 568 | fmt.Fprintf(w, "_ma_regs.x[%d] = _MA_SIGN_EXT(u32, 32);\n", rd) 569 | case decoder.Sra: // sraiw rd,rs1,shamt: x[rd] = sext(x[rs1][31:0] >>s shamt) 570 | if elfHeader.Class == elf.ELFCLASS32 { 571 | return errors.New("sraiw: invalid for RV32") 572 | } 573 | if shamt&0b11111 != shamt { // 5 bits 574 | return fmt.Errorf("sraiw: expected shamt to be <= 0b11111, got %b", shamt) 575 | } 576 | fmt.Fprintf(w, "u32 = ((int32_t)%s >> %d);\n", generateReadRegExpr(rs1), shamt) 577 | fmt.Fprintf(w, "_ma_regs.x[%d] = _MA_SIGN_EXT(u32, 32);\n", rd) 578 | default: 579 | return fmt.Errorf("unsupported IntRegImm32 funct7 %+v", f7) 580 | } 581 | default: 582 | return fmt.Errorf("unsupported IntRegImm32 funct3 %+v", f3) 583 | } 584 | case decoder.Load: 585 | rd, rs1, imm := inst.GetRd(), inst.GetRs1(), inst.GetImmediate() 586 | if rd == 0 { 587 | break 588 | } 589 | fmt.Fprintf(w, "p = _ma_translate_ptr(%s + (_ma_signed_reg_t)%d);\n", generateReadRegExpr(rs1), signext.SignExt(int(imm), 12)) 590 | switch f3 { 591 | case decoder.Lb: // lb rd,offset(rs1): x[rd] = sext(M[x[rs1] + sext(offset)][7:0]) 592 | fmt.Fprintln(w, "u8 = *(uint8_t*)p;") 593 | fmt.Fprintf(w, "_ma_regs.x[%d] = (_ma_reg_t)_MA_SIGN_EXT((_ma_reg_t)u8, 8);\n", rd) 594 | case decoder.Lbu: // lbu rd,offset(rs1): x[rd] = M[x[rs1] + sext(offset)][7:0] 595 | fmt.Fprintln(w, "u8 = *(uint8_t*)p;") 596 | fmt.Fprintf(w, "_ma_regs.x[%d] = u8;\n", rd) 597 | case decoder.Lh: // lh rd,offset(rs1): x[rd] = sext(M[x[rs1] + sext(offset)][15:0]) 598 | fmt.Fprintln(w, "u16 = *(uint16_t*)p;") 599 | fmt.Fprintf(w, "_ma_regs.x[%d] = (_ma_reg_t)_MA_SIGN_EXT((_ma_reg_t)u16, 16);\n", rd) 600 | case decoder.Lhu: // lhu rd,offset(rs1): x[rd] = M[x[rs1] + sext(offset)][15:0] 601 | fmt.Fprintln(w, "u16 = *(uint16_t*)p;") 602 | fmt.Fprintf(w, "_ma_regs.x[%d] = u16;\n", rd) 603 | case decoder.Lw: // lw rd,offset(rs1): x[rd] = sext(M[x[rs1] + sext(offset)][31:0]) 604 | fmt.Fprintln(w, "u32 = *(uint32_t*)p;") 605 | fmt.Fprintf(w, "_ma_regs.x[%d] = (_ma_reg_t)_MA_SIGN_EXT((_ma_reg_t)u32, 32);\n", rd) 606 | case decoder.Lwu: // lwu rd,offset(rs1): x[rd] = M[x[rs1] + sext(offset)][31:0] 607 | if elfHeader.Class == elf.ELFCLASS32 { 608 | return errors.New("lwu: invalid for RV32") 609 | } 610 | fmt.Fprintln(w, "u32 = *(uint32_t*)p;") 611 | fmt.Fprintf(w, "_ma_regs.x[%d] = u32;\n", rd) 612 | case decoder.Ld: // ld rd,offset(rs1): x[rd] = M[x[rs1] + sext(offset)][63:0] 613 | if elfHeader.Class == elf.ELFCLASS32 { 614 | return errors.New("ld: invalid for RV32") 615 | } 616 | fmt.Fprintln(w, "u64 = *(uint64_t*)p;") 617 | fmt.Fprintf(w, "_ma_regs.x[%d] = u64;\n", rd) 618 | default: 619 | return fmt.Errorf("unsupported Load funct3 %+v", f3) 620 | } 621 | case decoder.Store: 622 | rs1, rs2, imm := inst.GetRs1(), inst.GetRs2(), inst.GetImmediate() 623 | fmt.Fprintf(w, "p = _ma_translate_ptr(%s + (_ma_signed_reg_t)%d);\n", generateReadRegExpr(rs1), signext.SignExt(int(imm), 12)) 624 | switch f3 { 625 | case decoder.Sb: // sb rs2,offset(rs1): M[x[rs1] + sext(offset)] = x[rs2][7:0]] 626 | fmt.Fprintf(w, "u8 = %s & 0xFF;\n", generateReadRegExpr(rs2)) 627 | fmt.Fprintln(w, "*(uint8_t*)p = u8;") 628 | case decoder.Sh: // sh rs2,offset(rs1): M[x[rs1] + sext(offset)] = x[rs2][15:0]] 629 | fmt.Fprintf(w, "u16 = %s & 0xFFFF;\n", generateReadRegExpr(rs2)) 630 | fmt.Fprintln(w, "*(uint16_t*)p = u16;") 631 | case decoder.Sw: // sw rs2,offset(rs1): M[x[rs1] + sext(offset)] = x[rs2][31:0]] 632 | fmt.Fprintf(w, "u32 = %s & 0xFFFFFFFF;\n", generateReadRegExpr(rs2)) 633 | fmt.Fprintln(w, "*(uint32_t*)p = u32;") 634 | case decoder.Sd: // sd rs2,offset(rs1): M[x[rs1] + sext(offset)] = x[rs2][63:0] 635 | if elfHeader.Class == elf.ELFCLASS32 { 636 | return errors.New("sd: invalid for RV32") 637 | } 638 | fmt.Fprintf(w, "u64 = %s;\n", generateReadRegExpr(rs2)) 639 | fmt.Fprintln(w, "*(uint64_t*)p = u64;") 640 | default: 641 | return fmt.Errorf("unsupported Store funct3 %+v", f3) 642 | } 643 | case decoder.Branch: 644 | rs1, rs2, imm := inst.GetRs1(), inst.GetRs2(), inst.GetImmediate() 645 | stmt := generateStaticJumpStmt(instAddr+uint64(signext.SignExt(int(imm), 13)), segHead, segSize) 646 | switch f3 { 647 | case decoder.Beq: // beq rs1,rs2,offset: if (x[rs1] == x[rs2]) pc += sext(offset) 648 | fmt.Fprintf(w, "if (%s == %s) { %s }\n", generateReadRegExpr(rs1), generateReadRegExpr(rs2), stmt) 649 | case decoder.Bne: // bne rs1,rs2,offset: if (x[rs1] != x[rs2]) pc += sext(offset) 650 | fmt.Fprintf(w, "if (%s != %s) { %s }\n", generateReadRegExpr(rs1), generateReadRegExpr(rs2), stmt) 651 | case decoder.Blt: // blt rs1,rs2,offset: if (x[rs1] =s x[rs2]) pc += sext(offset) // signed 656 | fmt.Fprintf(w, "if ((_ma_signed_reg_t)%s >= (_ma_signed_reg_t)%s) { %s }\n", generateReadRegExpr(rs1), generateReadRegExpr(rs2), stmt) 657 | case decoder.Bgeu: // bgeu rs1,rs2,offset: if (x[rs1] >=u x[rs2]) pc += sext(offset) // unsigned 658 | fmt.Fprintf(w, "if (%s >= %s) { %s }\n", generateReadRegExpr(rs1), generateReadRegExpr(rs2), stmt) 659 | default: 660 | return fmt.Errorf("unsupported Branch funct3 %+v", f3) 661 | } 662 | case decoder.Lui: // lui rd,imm: x[rd] = sext(immediate[31:12] << 12) 663 | rd, imm := inst.GetRd(), inst.GetImmediate() 664 | if rd == 0 { 665 | break 666 | } 667 | fmt.Fprintf(w, "_ma_regs.x[%d] = (_ma_signed_reg_t)%d;\n", rd, signext.SignExt(int(imm), 32)) 668 | case decoder.Auipc: // auipc rd,imm: x[rd] = pc + sext(immediate[31:12] << 12) 669 | rd, imm := inst.GetRd(), inst.GetImmediate() 670 | if rd == 0 { 671 | break 672 | } 673 | fmt.Fprintf(w, "_ma_regs.x[%d] = 0x%08X;\n", rd, instAddr+uint64(signext.SignExt(int(imm), 32))) 674 | case decoder.Jal: // jal rd,offset: x[rd] = pc+4; pc += sext(offset) 675 | rd, imm := inst.GetRd(), inst.GetImmediate() 676 | if rd != 0 { 677 | fmt.Fprintf(w, "_ma_regs.x[%d] = 0x%08X;\n", rd, instAddr+4) 678 | } 679 | fmt.Fprintf(w, "%s;\n", generateStaticJumpStmt(instAddr+uint64(signext.SignExt(int(imm), 21)), segHead, segSize)) 680 | case decoder.Jalr: // jalr rd,rs1,offset: t =pc+4; pc=(x[rs1]+sext(offset))&∼1; x[rd]=t 681 | rd, rs1, imm := inst.GetRd(), inst.GetRs1(), inst.GetImmediate() 682 | fmt.Fprintf(w, "tmp = %s;\n", generateReadRegExpr(rs1)) 683 | if rd != 0 { 684 | fmt.Fprintf(w, "_ma_regs.x[%d] = 0x%08X;\n", rd, instAddr+4) 685 | } 686 | fmt.Fprintf(w, "_MA_JUMP((tmp + (_ma_signed_reg_t)%d)&~1);\n", signext.SignExt(int(imm), 12)) 687 | case decoder.Sys: 688 | switch bit20 := (inst.BinWord >> 20) & 0b1; bit20 { 689 | case 0: // ebreak: RaiseException(Breakpoint) 690 | fmt.Fprintln(w, "_ma_ecall();") 691 | case 1: // ecall: RaiseException(EnvironmentCall) 692 | fmt.Fprintf(w, "_MA_RAISE_BREAK(0x%08X);\n", instAddr) 693 | } 694 | case decoder.FenceOp: // WIP, probably wrong 695 | fmt.Fprintln(w, "/* NOP */;") 696 | case decoder.Atomic: 697 | rd, rs1, rs2 := inst.GetRd(), inst.GetRs1(), inst.GetRs2() // often rd == rs2 698 | fmt.Fprintf(w, "p = _ma_translate_ptr(%s);\n", generateReadRegExpr(rs1)) 699 | f5head, f5tail := decoder.Funct5Head(inst.BinWord>>29), decoder.Funct5Tail((inst.BinWord>>27)&0x3) 700 | switch f3 { 701 | case decoder.Atomic32: // WIP, needs mutex 702 | switch f5head { 703 | case decoder.CommonAtomic: 704 | switch f5tail { 705 | case decoder.ArithAtomic: // amoadd.w rd,rs2,(rs1): x[rd] = AMO32(M[x[rs1]] + x[rs2]) 706 | fmt.Fprintln(w, "u32_x = *(uint32_t*)p;") 707 | fmt.Fprintf(w, "u32_y = u32_x + %s\n;", generateReadRegExpr(rs2)) 708 | if rd != 0 { 709 | fmt.Fprintf(w, "_ma_regs.x[%d] = u32_x;\n", rd) 710 | } 711 | fmt.Fprintln(w, "*(uint32_t*)p = u32_y;") 712 | case decoder.Amoswap: // amoswap.w rd,rs2,(rs1): x[rd] = AMO32(M[x[rs1]] SWAP x[rs2]) 713 | fmt.Fprintln(w, "u32_x = *(uint32_t*)p;") 714 | fmt.Fprintf(w, "u32_y = %s\n;", generateReadRegExpr(rs2)) 715 | if rd != 0 { 716 | fmt.Fprintf(w, "_ma_regs.x[%d] = u32_x;\n", rd) 717 | } 718 | fmt.Fprintln(w, "*(uint32_t*)p = u32_y;") 719 | case decoder.Lr: // lr.w rd,rs1: x[rd] = LoadReserved32(M[x[rs1]]) 720 | if rd == 0 { 721 | break 722 | } 723 | fmt.Fprintln(w, "u32_x = *(uint32_t*)p;") 724 | fmt.Fprintf(w, "_ma_regs.x[%d] = u32_x;\n", rd) 725 | // TODO: implement reservation set 726 | case decoder.Sc: // sc.w rd,rs1,rs2: x[rd] = StoreConditional32(M[x[rs1]], x[rs2]) 727 | fmt.Fprintf(w, "u32_y = %s;", generateReadRegExpr(rs2)) 728 | fmt.Fprintln(w, "*(uint32_t*)p = u32_y;") 729 | if rd != 0 { 730 | fmt.Fprintf(w, "_ma_regs.x[%d] = 0;\n", rd) 731 | } 732 | default: 733 | return fmt.Errorf("unsupported Atomic32 CommonAtomic funct5tail %+v", f5tail) 734 | } 735 | case decoder.Amoor: // amoor.w rd,rs2,(rs1): x[rd] = AMO32(M[x[rs1]] | x[rs2]) 736 | fmt.Fprintln(w, "u32_x = *(uint32_t*)p;") 737 | fmt.Fprintf(w, "u32_y = u32_x | %s\n;", generateReadRegExpr(rs2)) 738 | if rd != 0 { 739 | fmt.Fprintf(w, "_ma_regs.x[%d] = u32_x;\n", rd) 740 | } 741 | fmt.Fprintln(w, "*(uint32_t*)p = u32_y;") 742 | case decoder.Amomaxu: // amomaxu.w rd,rs2,(rs1): x[rd] = AMO32(M[x[rs1]] MAXU x[rs2]) 743 | fmt.Fprintln(w, "u32_x = *(uint32_t*)p;") 744 | fmt.Fprintf(w, "u32_y = MAX(u32_x, %s)\n;", generateReadRegExpr(rs2)) 745 | if rd != 0 { 746 | fmt.Fprintf(w, "_ma_regs.x[%d] = u32_x;\n", rd) 747 | } 748 | fmt.Fprintln(w, "*(uint32_t*)p = u32_y;") 749 | default: 750 | return fmt.Errorf("unsupported Atomic32 funct5head %+v", f5head) 751 | } 752 | case decoder.Atomic64: // WIP, needs mutex 753 | switch f5head { 754 | case decoder.CommonAtomic: 755 | switch f5tail { 756 | case decoder.ArithAtomic: // amoadd.d rd,rs2,(rs1): x[rd] = AMO64(M[x[rs1]] + x[rs2]) 757 | fmt.Fprintln(w, "u64_x = *(uint64_t*)p;") 758 | fmt.Fprintf(w, "u64_y = u64_x + %s\n;", generateReadRegExpr(rs2)) 759 | if rd != 0 { 760 | fmt.Fprintf(w, "_ma_regs.x[%d] = u64_x;\n", rd) 761 | } 762 | fmt.Fprintln(w, "*(uint64_t*)p = u64_y;") 763 | case decoder.Amoswap: // amoswap.d rd,rs2,(rs1): x[rd] = AMO64(M[x[rs1]] SWAP x[rs2]) 764 | fmt.Fprintln(w, "u64_x = *(uint64_t*)p;") 765 | fmt.Fprintf(w, "u64_y = %s\n;", generateReadRegExpr(rs2)) 766 | if rd != 0 { 767 | fmt.Fprintf(w, "_ma_regs.x[%d] = u64_x;\n", rd) 768 | } 769 | fmt.Fprintln(w, "*(uint64_t*)p = u64_y;") 770 | case decoder.Lr: // lr.d rd,rs1: x[rd] = LoadReserved64(M[x[rs1]]) 771 | if rd == 0 { 772 | break 773 | } 774 | fmt.Fprintln(w, "u64_x = *(uint64_t*)p;") 775 | fmt.Fprintf(w, "_ma_regs.x[%d] = u64_x;\n", rd) 776 | // TODO: implement reservation set 777 | case decoder.Sc: // sc.d rd,rs1,rs2: x[rd] = StoreConditional64(M[x[rs1]], x[rs2]) 778 | fmt.Fprintf(w, "u64_y = %s;", generateReadRegExpr(rs2)) 779 | fmt.Fprintln(w, "*(uint64_t*)p = u64_y;") 780 | if rd != 0 { 781 | fmt.Fprintf(w, "_ma_regs.x[%d] = 0;\n", rd) 782 | } 783 | default: 784 | return fmt.Errorf("unsupported Atomic64 CommonAtomic funct5tail %+v", f5tail) 785 | } 786 | case decoder.Amoor: // amoor.d rd,rs2,(rs1): x[rd] = AMO64(M[x[rs1]] | x[rs2]) 787 | fmt.Fprintln(w, "u64_x = *(uint64_t*)p;") 788 | fmt.Fprintf(w, "u64_y = u64_x | %s\n;", generateReadRegExpr(rs2)) 789 | if rd != 0 { 790 | fmt.Fprintf(w, "_ma_regs.x[%d] = u64_x;\n", rd) 791 | } 792 | fmt.Fprintln(w, "*(uint64_t*)p = u64_y;") 793 | case decoder.Amomaxu: // amomaxu.d rd,rs2,(rs1): x[rd] = AMO64(M[x[rs1]] MAXU x[rs2]) 794 | fmt.Fprintln(w, "u64_x = *(uint64_t*)p;") 795 | fmt.Fprintf(w, "u64_y = MAX(u64_x, %s)\n;", generateReadRegExpr(rs2)) 796 | if rd != 0 { 797 | fmt.Fprintf(w, "_ma_regs.x[%d] = u64_x;\n", rd) 798 | } 799 | fmt.Fprintln(w, "*(uint64_t*)p = u64_y;") 800 | default: 801 | return fmt.Errorf("unsupported Atomic64 funct5head %+v", f5head) 802 | } 803 | default: 804 | return fmt.Errorf("unsupported Atomic funct3 %+v", f3) 805 | } 806 | case decoder.Flw: 807 | return errors.New("unsupported: flw") 808 | case decoder.Fsw: // fsw rs2,offset(rs1): M[x[rs1] + sext(offset)] = f[rs2][31:0] 809 | rs1, rs2, imm := inst.GetRs1(), inst.GetRs2(), inst.GetImmediate() 810 | fmt.Fprintf(w, "p = _ma_translate_ptr(%s + (_ma_signed_reg_t)%d);\n", generateReadRegExpr(rs1), signext.SignExt(int(imm), 12)) 811 | fmt.Fprintf(w, "*(float*)p = (float)_ma_regs.f[%d];\n", rs2) 812 | default: 813 | return fmt.Errorf("unsupported minor opcode 0x%02X", minorOp) 814 | } 815 | case decoder.C0: 816 | switch cf3 := inst.CFunct3(); cf3 { 817 | case decoder.Caddi4spn: 818 | if inst.BinWord == 0 { 819 | fmt.Fprintln(w, "/* NOTREACHED */") 820 | fmt.Fprintln(w, "_MA_FATALF(\"null instruction\");") 821 | } else { 822 | rd, uimm := inst.CRdShort(), inst.CADDI4Imm() 823 | switch rd { 824 | case 0: // reserved 825 | return errors.New("reserved instruction") 826 | default: // c.addi4spn rd’,uimm: x[8+rd’] = x[2] + nzuimm 827 | if uimm == 0 { 828 | return errors.New("c.addi4spn: uimm must not be zero") 829 | } 830 | fmt.Fprintf(w, "_ma_regs.x[%d] = _ma_regs.x[2] + (_ma_reg_t)%d;\n", rd, uimm) 831 | } 832 | } 833 | case decoder.Cfld: // c.fld rd’,uimm(rs1’): f[8+rd’] = M[x[8+rs1’] + uimm][63:0] 834 | return errors.New("unsupported: c.fld") 835 | case decoder.Clw: // c.lw rd’,uimm(rs1’): x[8+rd’] = sext(M[x[8+rs1’] + uimm][31:0]) 836 | rd, rs1, uimm := inst.CRdShort(), inst.CRdRs1Short(), inst.CWImm() 837 | fmt.Fprintf(w, "p = _ma_translate_ptr(_ma_regs.x[%d] + (_ma_reg_t)%d);\n", rs1, uimm) 838 | fmt.Fprintln(w, "u32 = *(uint32_t*)p;") 839 | fmt.Fprintf(w, "_ma_regs.x[%d] = _MA_SIGN_EXT(u32,32);\n", rd) 840 | case decoder.Cflw: // c.flw (32-bit ABI) or c.ld (64-bit ABI) 841 | switch elfHeader.Class { 842 | case elf.ELFCLASS32: // c.flw rd’,uimm(rs1’): f[8+rd’] = M[x[8+rs1’] + uimm][31:0] 843 | return errors.New("unsupported: c.flw") 844 | case elf.ELFCLASS64: // c.ld rd’,uimm(rs1’): x[8+rd’] = M[x[8+rs1’] + uimm][63:0] 845 | rd, rs1, uimm := inst.CRdShort(), inst.CRdRs1Short(), inst.CDImm() 846 | fmt.Fprintf(w, "p = _ma_translate_ptr(_ma_regs.x[%d] + (_ma_reg_t)%d);\n", rs1, uimm) 847 | fmt.Fprintln(w, "u64 = *(uint64_t*)p;") 848 | fmt.Fprintf(w, "_ma_regs.x[%d] = u64;\n", rd) 849 | } 850 | case decoder.Cfsd: // c.fsd rd’,uimm(rs1’): M[x[8+rs1’] + uimm][63:0] = f[8+rs2’] 851 | rs1, rs2, uimm := inst.CRdRs1Short(), inst.CRs2Short(), inst.CWImm() 852 | fmt.Fprintf(w, "p = _ma_translate_ptr(_ma_regs.x[%d] + (_ma_reg_t)%d);\n", rs1, uimm) 853 | fmt.Fprintf(w, "*(double*)p = _ma_regs.f[%d];\n", rs2) 854 | case decoder.Csw: // c.sw rd’,uimm(rs1’): M[x[8+rs1’] + uimm][31:0] = x[8+rs2’] 855 | rs1, rs2, uimm := inst.CRdRs1Short(), inst.CRs2Short(), inst.CWImm() 856 | fmt.Fprintf(w, "p = _ma_translate_ptr(_ma_regs.x[%d] + (_ma_reg_t)%d);\n", rs1, uimm) 857 | fmt.Fprintf(w, "u32 = (uint32_t)_ma_regs.x[%d];\n", rs2) 858 | fmt.Fprintln(w, "*(uint32_t*)p = u32;") 859 | case decoder.Cfsw: // c.fsw (32-bit ABI) or c.sd (64-bit ABI) 860 | switch elfHeader.Class { 861 | case elf.ELFCLASS32: 862 | return errors.New("unsupported: c.fsw") 863 | case elf.ELFCLASS64: // c.sd rd’,uimm(rs1’): M[x[8+rs1’] + uimm][63:0] = x[8+rs2’] 864 | rs1, rs2, uimm := inst.CRdRs1Short(), inst.CRs2Short(), inst.CDImm() 865 | fmt.Fprintf(w, "p = _ma_translate_ptr(_ma_regs.x[%d] + (_ma_reg_t)%d);\n", rs1, uimm) 866 | fmt.Fprintf(w, "u64 = (uint64_t)_ma_regs.x[%d];\n", rs2) 867 | fmt.Fprintln(w, "*(uint64_t*)p = u64;") 868 | } 869 | default: 870 | return fmt.Errorf("unsupported C0 cfunct3 %+v", cf3) 871 | } 872 | case decoder.C1: 873 | switch cf3 := inst.CFunct3(); cf3 { 874 | case decoder.Caddi: // c.addi or c.nop 875 | rd, imm := inst.CRdRs1(), inst.CIImm() 876 | switch rd { 877 | case 0: // c.nop 878 | fmt.Fprintln(w, "/* NOP */") 879 | default: // c.addi rd,u[12:12]|u[6:2]: x[rd] = x[rd] + sext(imm) 880 | switch imm { 881 | case 0: 882 | logrus.Warn("unsupported: HINT for c.addi") 883 | fallthrough 884 | default: 885 | fmt.Fprintf(w, "_ma_regs.x[%d] += (_ma_signed_reg_t)%d;\n", rd, signext.SignExt(int(imm), 6)) 886 | } 887 | } 888 | case decoder.Cjal: // c.jal (32-bit ABI) or c.addiw (64-bit ABI) 889 | switch elfHeader.Class { 890 | case elf.ELFCLASS32: 891 | return errors.New("unsupported: c.jal") 892 | case elf.ELFCLASS64: 893 | rd, imm := inst.CRdRs1(), inst.CIImm() 894 | switch rd { 895 | case 0: // reserved 896 | return errors.New("reserved instruction") 897 | default: // c.addiw rd,imm: x[rd] = sext((x[rd] + sext(imm))[31:0]) 898 | fmt.Fprintf(w, "u32 = (uint32_t)(_ma_regs.x[%d] + (_ma_signed_reg_t)%d);\n", rd, signext.SignExt(int(imm), 6)) 899 | fmt.Fprintf(w, "_ma_regs.x[%d] = _MA_SIGN_EXT(u32, 32);\n", rd) 900 | } 901 | } 902 | case decoder.Cli: // c.li rd,imm: x[rd] = sext(imm) 903 | rd, imm := inst.CRdRs1(), inst.CIImm() 904 | switch rd { 905 | case 0: 906 | logrus.Warn("unsupported: HINT for c.li") 907 | fallthrough 908 | default: 909 | fmt.Fprintf(w, "_ma_regs.x[%d] = (_ma_signed_reg_t)%d;\n", rd, signext.SignExt(int(imm), 6)) 910 | } 911 | case decoder.Clui: // c.lui or c.addi16sp 912 | switch rdMaybe := inst.CRdRs1(); rdMaybe { 913 | case 2: // c.addi16sp imm: x[2] = x[2] + sext(imm) 914 | imm := inst.CADDI16Imm() 915 | if imm == 0 { 916 | return errors.New("c.addi16sp: imm must not be zero") 917 | } 918 | fmt.Fprintf(w, "_ma_regs.x[2] += (_ma_signed_reg_t)%d;\n", signext.SignExt(int(imm), 10)) 919 | case 0: 920 | logrus.Warn("unsupported: HINT for c.lui") 921 | fallthrough 922 | default: // c.lui rd,imm: x[rd] = sext(imm[17:12] << 12) 923 | imm := inst.CLUIImm() 924 | fmt.Fprintf(w, "_ma_regs.x[%d] = (_ma_signed_reg_t)%d;\n", rdMaybe, signext.SignExt(int(imm), 18)) 925 | } 926 | case decoder.Extend6: 927 | cf6tail := decoder.Funct6Tail((inst.BinWord >> 10) & 0b11) 928 | switch cf6tail { 929 | case decoder.Csrli: 930 | if elfHeader.Class == elf.ELFCLASS32 && bit12 != 0 { 931 | return errors.New("c.srli: bit12 must be zero for RV32C") 932 | } 933 | rd, uimm := inst.CRdRs1Short(), inst.CIImm() 934 | switch uimm { 935 | case 0: 936 | logrus.Warn("unsupported: HINT for c.srli") 937 | fallthrough 938 | default: // c.srli rd’,uimm: x[8+rd’] = x[8+rd’] >>u uimm 939 | fmt.Fprintf(w, "_ma_regs.x[%d] = (_ma_regs.x[%d] >> %d);\n", rd, rd, uimm) 940 | } 941 | case decoder.Csrai: 942 | if elfHeader.Class == elf.ELFCLASS32 && bit12 != 0 { 943 | return errors.New("c.srai: bit12 must be zero for RV32C") 944 | } 945 | rd, uimm := inst.CRdRs1Short(), inst.CIImm() 946 | switch uimm { 947 | case 0: 948 | logrus.Warn("unsupported: HINT for c.srai") 949 | fallthrough 950 | default: // c.srai rd’,uimm: x[8+rd’] = x[8+rd’] >>s uimm 951 | fmt.Fprintf(w, "_ma_regs.x[%d] = ((_ma_signed_reg_t)_ma_regs.x[%d] >> %d);\n", rd, rd, uimm) 952 | } 953 | case decoder.Candi: // c.andi rd’,imm: x[8+rd’] = x[8+rd’] & sext(imm) 954 | rd, imm := inst.CRdRs1Short(), inst.CIImm() 955 | fmt.Fprintf(w, "_ma_regs.x[%d] &= %d;\n", rd, signext.SignExt(int(imm), 6)) 956 | case decoder.RegGroupTail: 957 | switch bit12 { 958 | case decoder.RegGroupMid: 959 | rd, rs2 := inst.CRdRs1Short(), inst.CRs2Short() 960 | switch cf2 := decoder.Funct2((inst.BinWord >> 5) & 0b11); cf2 { 961 | case decoder.Csub: // c.sub rd’,rs2’: x[8+rd’] = x[8+rd’] - x[8+rs2’] 962 | fmt.Fprintf(w, "_ma_regs.x[%d] -= _ma_regs.x[%d];\n", rd, rs2) 963 | case decoder.Cxor: // c.xor rd’,rs2’: x[8+rd’] = x[8+rd’] ^ x[8+rs2’] 964 | fmt.Fprintf(w, "_ma_regs.x[%d] ^= _ma_regs.x[%d];\n", rd, rs2) 965 | case decoder.Cor: // c.or rd’,rs2’: x[8+rd’] = x[8+rd’] | x[8+rs2’] 966 | fmt.Fprintf(w, "_ma_regs.x[%d] |= _ma_regs.x[%d];\n", rd, rs2) 967 | case decoder.Cand: // c.and rd’,rs2’: x[8+rd’] = x[8+rd’] & x[8+rs2’] 968 | fmt.Fprintf(w, "_ma_regs.x[%d] &= _ma_regs.x[%d];\n", rd, rs2) 969 | } 970 | case 1: 971 | rd, rs2 := inst.CRdRs1Short(), inst.CRs2Short() 972 | switch cf2 := decoder.Funct2((inst.BinWord >> 5) & 0b11); cf2 { 973 | case 0: // c.subw rd’,rs2’: x[8+rd’] = sext((x[8+rd’] - x[8+rs2’])[31:0]) 974 | if elfHeader.Class == elf.ELFCLASS32 { 975 | return errors.New("c.subw: invalid for RV32") 976 | } 977 | fmt.Fprintf(w, "u32 = (uint32_t)(_ma_regs.x[%d] - _ma_regs.x[%d]);\n", rd, rs2) 978 | fmt.Fprintf(w, "_ma_regs.x[%d] = _MA_SIGN_EXT(u32, 32);\n", rd) 979 | case 1: // c.addw rd’,rs2’: x[8+rd’] = sext((x[8+rd’] + x[8+rs2’])[31:0]) 980 | if elfHeader.Class == elf.ELFCLASS32 { 981 | return errors.New("c.addw: invalid for RV32") 982 | } 983 | fmt.Fprintf(w, "u32 = (uint32_t)(_ma_regs.x[%d] + _ma_regs.x[%d]);\n", rd, rs2) 984 | fmt.Fprintf(w, "_ma_regs.x[%d] = _MA_SIGN_EXT(u32, 32);\n", rd) 985 | default: 986 | return fmt.Errorf("unsupported C1 Extend6 cf2 %+v", cf2) 987 | } 988 | } 989 | } 990 | case decoder.Cj: // c.j offset: pc += sext(offset) 991 | imm := inst.CJImm() 992 | stmt := generateStaticJumpStmt(instAddr+uint64(signext.SignExt(int(imm), 12)), segHead, segSize) 993 | fmt.Fprintln(w, stmt) 994 | case decoder.Cbeqz: // c.beqz rs1’,offset: if (x[8+rs1’] == 0) pc += sext(offset) 995 | rs1, imm := inst.CRdRs1Short(), inst.CBImm() 996 | stmt := generateStaticJumpStmt(instAddr+uint64(signext.SignExt(int(imm), 9)), segHead, segSize) 997 | fmt.Fprintf(w, "if (_ma_regs.x[%d] == 0) { %s }\n", rs1, stmt) 998 | case decoder.Cbnez: // c.bnez rs1’,offset: if (x[8+rs1’] != 0) pc += sext(offset) 999 | rs1, imm := inst.CRdRs1Short(), inst.CBImm() 1000 | stmt := generateStaticJumpStmt(instAddr+uint64(signext.SignExt(int(imm), 9)), segHead, segSize) 1001 | fmt.Fprintf(w, "if (_ma_regs.x[%d] != 0) { %s }\n", rs1, stmt) 1002 | default: 1003 | return fmt.Errorf("unsupported C1 cfunct3 %+v", cf3) 1004 | } 1005 | case decoder.C2: 1006 | switch cf3 := inst.CFunct3(); cf3 { 1007 | case decoder.Cslli: 1008 | if elfHeader.Class == elf.ELFCLASS32 && bit12 != 0 { 1009 | return errors.New("c.slli: bit12 must be zero for RV32C") 1010 | } 1011 | rd, uimm := inst.CRdRs1(), inst.CIImm() 1012 | switch uimm { 1013 | case 0: 1014 | logrus.Warn("unsupported: HINT for c.slli") 1015 | fallthrough 1016 | default: // c.slli rd,uimm: x[rd] = x[rd] << uimm 1017 | fmt.Fprintf(w, "_ma_regs.x[%d] <<= %d;\n", rd, uimm) 1018 | } 1019 | case decoder.Cfldsp: // c.fldsp rd,uimm(x2): f[rd] = M[x[2] + uimm][63:0] 1020 | return errors.New("unsupported: c.fldsp") 1021 | case decoder.Clwsp: 1022 | rd, uimm := inst.CRdRs1(), inst.CLWSPImm() 1023 | switch rd { 1024 | case 0: // reserved 1025 | return errors.New("reserved instruction") 1026 | default: // c.lwsp rd,uimm(x2): x[rd] = sext(M[x[2] + uimm][31:0]) 1027 | fmt.Fprintf(w, "p = _ma_translate_ptr(_ma_regs.x[2] + (_ma_reg_t)%d);\n", uimm) 1028 | fmt.Fprintln(w, "u32 = *(uint32_t*)p;") 1029 | fmt.Fprintf(w, "_ma_regs.x[%d] = (_ma_reg_t)_MA_SIGN_EXT((_ma_reg_t)u32, 32);\n", rd) 1030 | } 1031 | case decoder.Cswsp: // c.swsp rs2,uimm(x2): M[x[2] + uimm][31:0] = x[rs2] 1032 | rs2, uimm := inst.CRs2(), inst.CSWSPImm() 1033 | fmt.Fprintf(w, "p = _ma_translate_ptr(_ma_regs.x[2] + (_ma_reg_t)%d);\n", uimm) 1034 | fmt.Fprintf(w, "u32 = %s & 0xFFFFFFFF;\n", generateReadRegExpr(rs2)) 1035 | fmt.Fprintln(w, "*(uint32_t*)p = u32;") 1036 | case decoder.Cflwsp: // c.flwsp (32-bit ABI) or c.ldsp (64-bit ABI) 1037 | switch elfHeader.Class { 1038 | case elf.ELFCLASS32: // c.flwsp rd,uimm(x2): f[rd] = M[x[2] + uimm][31:0] 1039 | return errors.New("unsupported: c.flwsp") 1040 | case elf.ELFCLASS64: 1041 | rd, uimm := inst.CRdRs1(), inst.CLDSPImm() 1042 | switch rd { 1043 | case 0: // reserved 1044 | return errors.New("reserved instruction") 1045 | default: // c.ldsp rd,uimm(x2): x[rd] = M[x[2] + uimm][63:0] 1046 | fmt.Fprintf(w, "p = _ma_translate_ptr(_ma_regs.x[2] + (_ma_reg_t)%d);\n", uimm) 1047 | fmt.Fprintln(w, "u64 = *(uint64_t*)p;") 1048 | fmt.Fprintf(w, "_ma_regs.x[%d] = u64;\n", rd) 1049 | } 1050 | } 1051 | case decoder.CMvAdd: 1052 | bit12 := decoder.Bit12((inst.BinWord >> 12) & 0b1) 1053 | switch bit12 { 1054 | case decoder.Cmv: // c.mv or c.jr 1055 | if rs2Maybe := inst.CRs2(); rs2Maybe != 0 { 1056 | rd := inst.CRdRs1() 1057 | switch rd { 1058 | case 0: 1059 | logrus.Warn("unsupported: HINT for c.mv") 1060 | fallthrough 1061 | default: // c.mv rd,rs2: x[rd] = x[rs2] 1062 | fmt.Fprintf(w, "_ma_regs.x[%d] = _ma_regs.x[%d];\n", rd, rs2Maybe) 1063 | } 1064 | } else { 1065 | switch rs1 := inst.CRdRs1(); rs1 { 1066 | case 0: // reserved 1067 | return errors.New("reserved instruction") 1068 | default: // c.jr rs1: pc = x[rs1] 1069 | fmt.Fprintf(w, "_MA_JUMP(_ma_regs.x[%d]);\n", rs1) 1070 | } 1071 | } 1072 | case decoder.Cadd: // c.add, c.jalr, or c.ebreak 1073 | rdOrRs1, rs2 := inst.CRdRs1(), inst.CRs2() 1074 | switch rs2 { 1075 | case 0: 1076 | switch rdOrRs1 { 1077 | case 0: // c.ebreak: RaiseException(Breakpoint) 1078 | fmt.Fprintf(w, "_MA_RAISE_BREAK(0x%08X);\n", instAddr) 1079 | default: // c.jalr rs1: t = pc+2; pc = x[rs1]; x[1] = t 1080 | fmt.Fprintf(w, "tmp = _ma_regs.x[%d];\n", rdOrRs1) 1081 | fmt.Fprintf(w, "_ma_regs.x[1] = 0x%08X;\n", instAddr+2) 1082 | fmt.Fprintln(w, "_MA_JUMP(tmp);") 1083 | } 1084 | default: // c.add rd,rs2: x[rd] = x[rd] + x[rs2] 1085 | switch rdOrRs1 { 1086 | case 0: 1087 | logrus.Warn("unsupported: HINT for c.add") 1088 | fallthrough 1089 | default: 1090 | fmt.Fprintf(w, "_ma_regs.x[%d] += _ma_regs.x[%d];\n", rdOrRs1, rs2) 1091 | } 1092 | } 1093 | } 1094 | case decoder.Cfsdsp: // c.fsdsp rs2,uimm(x2): M[x[2] + uimm][63:0] = f[rs2] 1095 | return errors.New("unsupported: c.fsdsp") 1096 | case decoder.Cfswsp: // c.fswsp (32-bit ABI) or c.sdsp (64-bit ABI) 1097 | switch elfHeader.Class { 1098 | case elf.ELFCLASS32: // c.fswsp rs2,uimm(rs2): M[x[2] + uimm][31:0] = f[rs2] 1099 | return errors.New("unsupported: c.fswsp") 1100 | case elf.ELFCLASS64: // c.sdsp rs2,uimm(x2): M[x[2] + uimm][63:0] = x[rs2] 1101 | rs2, uimm := inst.CRs2(), inst.CSDSPImm() 1102 | fmt.Fprintf(w, "p = _ma_translate_ptr(_ma_regs.x[2] + (_ma_reg_t)%d);\n", uimm) 1103 | fmt.Fprintf(w, "u64 = _ma_regs.x[%d];\n", rs2) 1104 | fmt.Fprintln(w, "*(uint64_t*)p = u64;") 1105 | } 1106 | default: 1107 | return fmt.Errorf("unsupported C2 cfunct3 %+v", cf3) 1108 | } 1109 | default: 1110 | return fmt.Errorf("unsupported major opcode 0x%02X", inst.MajOp) 1111 | } 1112 | return nil 1113 | } 1114 | -------------------------------------------------------------------------------- /pkg/compile/rt_c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #if defined(__linux__) 14 | #include 15 | #endif /* __linux__ */ 16 | #if defined(__APPLE__) 17 | #include 18 | #endif /* __APPLE__ */ 19 | #include 20 | #include 21 | 22 | #if !defined(_MA_REG_WIDTH) 23 | #define _MA_REG_WIDTH 32 24 | #endif /* _MA_REG_WIDTH */ 25 | #if _MA_REG_WIDTH == 64 26 | typedef uint64_t _ma_reg_t; 27 | typedef int64_t _ma_signed_reg_t; 28 | #if defined(__linux__) 29 | #define _MA_PRId "ld" 30 | #define _MA_PRIx "lx" 31 | #else /* defined(__linux__) */ 32 | #define _MA_PRId "lld" 33 | #define _MA_PRIx "llx" 34 | #endif /* defined(__linux__) */ 35 | #else 36 | typedef uint32_t _ma_reg_t; 37 | typedef int32_t _ma_signed_reg_t; 38 | #define _MA_PRId "d" 39 | #define _MA_PRIx "x" 40 | #endif /* _MA_REG_WIDTH == 64 */ 41 | 42 | #if defined(_MA_DEBUG) 43 | static bool _ma_debug = true; 44 | #define _MA_DEBUGF(fmt, ...) \ 45 | do { \ 46 | if (_ma_debug) { \ 47 | fprintf(stderr, "MyAOT| " fmt "\n", ## __VA_ARGS__); \ 48 | } \ 49 | } while (0) 50 | #else /* _MA_DEBUG */ 51 | #define _MA_DEBUGF(fmt, ...) 52 | #endif /* _MA_DEBUG */ 53 | 54 | #define _MA_FATALF(fmt, ...) \ 55 | do { \ 56 | fprintf(stderr, "MyAOT| " fmt "\n", ## __VA_ARGS__); \ 57 | abort(); \ 58 | } while (0) 59 | 60 | #define _MA_RAISE_BREAK(pc) \ 61 | do { \ 62 | fprintf(stderr, "MyAOT| Breakpoint: PC=0x%08"_MA_PRIx"\n", (_ma_reg_t)(pc)); \ 63 | abort(); \ 64 | } while (0) 65 | 66 | #if !defined(MAX) 67 | #define MAX(a,b) ((a) > (b) ? a : b) 68 | #endif /* MAX */ 69 | 70 | #if !defined(MIN) 71 | #define MIN(a,b) ((a) < (b) ? a : b) 72 | #endif /* MIN */ 73 | 74 | /* _MA_SIGN_BIT(4) = 0b0000'1000 */ 75 | #define _MA_SIGN_BIT(bits) (1LL << ((bits)-1)) 76 | /* _MA_SIGN_MASK(4) = 0b1111'1000 */ 77 | #if _MA_REG_WIDTH == 64 78 | /* To avoid overflow */ 79 | #define _MA_SIGN_MASK(bits) (~((unsigned __int128)_MA_SIGN_BIT((bits))-1)) 80 | #else 81 | #define _MA_SIGN_MASK(bits) (~(_MA_SIGN_BIT((bits))-1)) 82 | #endif 83 | #define _MA_SIGN_EXT(val, bits) ((val) & _MA_SIGN_BIT((bits)) ? ((val) | _MA_SIGN_MASK((bits))) : (val)) 84 | 85 | #define _MA_MIN_INST_LEN 2 86 | #if defined(_MA_DEBUG) 87 | #define __MA_JUMP_NEAR(addr, seg_head, addr_labels) \ 88 | do { \ 89 | _MA_DEBUGF("JUMP NEAR 0x%08"_MA_PRIx, addr); \ 90 | int __ma_jump_near_idx = (int)((_ma_reg_t)((addr) - (seg_head)) / _MA_MIN_INST_LEN); \ 91 | int __ma_jump_near_nlabels = sizeof((addr_labels)) / sizeof((addr_labels[0])); \ 92 | if (__ma_jump_near_idx >= __ma_jump_near_nlabels) { \ 93 | _MA_FATALF("JUMP NEAR: idx %d must not be >= nlabels %d", __ma_jump_near_idx, __ma_jump_near_nlabels);\ 94 | } \ 95 | const void *__ma_jump_near_p = (addr_labels)[__ma_jump_near_idx]; \ 96 | if (__ma_jump_near_p == NULL) { _MA_FATALF("JUMP NEAR: NULL"); } \ 97 | goto *__ma_jump_near_p; \ 98 | } while(0) 99 | #define __MA_JUMP_FAR(addr) \ 100 | do { \ 101 | _MA_DEBUGF("JUMP FAR 0x%08"_MA_PRIx, addr); \ 102 | return (addr); \ 103 | } while(0) 104 | #else 105 | #define __MA_JUMP_NEAR(addr, seg_head, addr_labels) goto *(addr_labels)[((addr) - (seg_head))/_MA_MIN_INST_LEN] 106 | #define __MA_JUMP_FAR(addr) return (addr) 107 | #endif 108 | #define __MA_JUMP(addr, seg_head, seg_size, addr_labels) \ 109 | if ((_ma_reg_t)((addr) - (seg_head)) < (seg_size)) { __MA_JUMP_NEAR((addr), (seg_head), (addr_labels)); } else { __MA_JUMP_FAR((addr)); } 110 | 111 | #define _MA_REG_ZERO 0 /* Hard-wired zero */ 112 | #define _MA_REG_RA 1 /* Return address */ 113 | #define _MA_REG_SP 2 /* Stack pointer */ 114 | #define _MA_REG_GP 3 /* Global pointer */ 115 | #define _MA_REG_TP 4 /* Thread pointer */ 116 | #define _MA_REG_T0 5 /* Temporary / alternate link register */ 117 | #define _MA_REG_T1 6 118 | #define _MA_REG_T2 7 119 | #define _MA_REG_S0 8 /* Save register / frame pointer */ 120 | #define _MA_REG_FP 8 /* Save register / frame pointer */ 121 | #define _MA_REG_S1 9 122 | #define _MA_REG_A0 10 123 | #define _MA_REG_A1 11 124 | #define _MA_REG_A2 12 125 | #define _MA_REG_A3 13 126 | #define _MA_REG_A4 14 127 | #define _MA_REG_A5 15 128 | #define _MA_REG_A6 16 129 | #define _MA_REG_A7 17 130 | #define _MA_REG_S2 18 131 | #define _MA_REG_S3 19 132 | #define _MA_REG_S4 20 133 | #define _MA_REG_S5 21 134 | #define _MA_REG_S6 22 135 | #define _MA_REG_S7 23 136 | #define _MA_REG_S8 24 137 | #define _MA_REG_S9 25 138 | #define _MA_REG_S10 26 139 | #define _MA_REG_S11 27 140 | #define _MA_REG_T3 28 141 | #define _MA_REG_T4 29 142 | #define _MA_REG_T5 30 143 | #define _MA_REG_T6 31 144 | 145 | struct _ma_regs { 146 | _ma_reg_t x[32]; 147 | double f[32]; 148 | } _ma_regs; 149 | 150 | struct _ma_regs _ma_regs; 151 | 152 | void _ma_regs_dump(_ma_reg_t pc) { 153 | _MA_DEBUGF("=== PC=%08"_MA_PRIx" ===", pc); 154 | _MA_DEBUGF("X0=%08"_MA_PRIx" X1(RA)=%08"_MA_PRIx" X2(SP)=%08"_MA_PRIx" X3(GP)=%08"_MA_PRIx" X4(TP)=%08"_MA_PRIx" X5(T0)=%08"_MA_PRIx" X6=%08"_MA_PRIx" X7=%08"_MA_PRIx"", 155 | _ma_regs.x[0], _ma_regs.x[1], _ma_regs.x[2], _ma_regs.x[3], _ma_regs.x[4], _ma_regs.x[5], _ma_regs.x[6], _ma_regs.x[7]); 156 | _MA_DEBUGF("X8(S0/FP)=%08"_MA_PRIx" X9(S1)=%08"_MA_PRIx" X10(A0)=%08"_MA_PRIx" X11=%08"_MA_PRIx" X12=%08"_MA_PRIx", X13=%08"_MA_PRIx", X14=%08"_MA_PRIx", X15=%08"_MA_PRIx"", 157 | _ma_regs.x[8], _ma_regs.x[9], _ma_regs.x[10], _ma_regs.x[11], _ma_regs.x[12], _ma_regs.x[13], _ma_regs.x[14], _ma_regs.x[15]); 158 | _MA_DEBUGF("X16=%08"_MA_PRIx" X17=%08"_MA_PRIx" X18(S2)=%08"_MA_PRIx" X19=%08"_MA_PRIx" X20=%08"_MA_PRIx" X21=%08"_MA_PRIx" X22=%08"_MA_PRIx" X23=%08"_MA_PRIx"", 159 | _ma_regs.x[16], _ma_regs.x[17], _ma_regs.x[18], _ma_regs.x[19], _ma_regs.x[20], _ma_regs.x[21], _ma_regs.x[22], _ma_regs.x[23]); 160 | _MA_DEBUGF("X24=%08"_MA_PRIx" X25=%08"_MA_PRIx" X26=%08"_MA_PRIx" X27=%08"_MA_PRIx" X28(T3)=%08"_MA_PRIx" X29=%08"_MA_PRIx" X30=%08"_MA_PRIx" X31=%08"_MA_PRIx"", 161 | _ma_regs.x[24], _ma_regs.x[25], _ma_regs.x[26], _ma_regs.x[27], _ma_regs.x[28], _ma_regs.x[29], _ma_regs.x[30], _ma_regs.x[31]); 162 | } 163 | 164 | struct _ma_vma_entry { 165 | _ma_reg_t addr; 166 | _ma_reg_t len; 167 | void *bytes; /* Optional */ 168 | } _ma_vma_entry; 169 | 170 | struct _ma_vma_entry *_ma_vma_entries[]; 171 | struct _ma_vma_entry *_ma_vma_heap_entry; 172 | struct _ma_vma_entry *_ma_vma_stack_entry; 173 | _ma_reg_t _ma_vma_heap_cur; 174 | 175 | uint8_t _ma_at_ph[]; 176 | _ma_reg_t _ma_at_phent, _ma_at_phnum, _ma_at_entry; 177 | 178 | void _ma_vma_heap_entry_init(void) { 179 | _ma_vma_heap_entry->addr = 0x40000000; /* 1GiB */ /* FIXME */ 180 | _ma_vma_heap_cur = _ma_vma_heap_entry->addr; 181 | _ma_vma_heap_entry->len = 1 * 1024 * 1024 * 1024; /* 1 GiB */ /* FIXME */ 182 | _MA_DEBUGF("Heap begin=0x%"_MA_PRIx" len=%"_MA_PRId, _ma_vma_heap_entry->addr, _ma_vma_heap_entry->len); 183 | _ma_vma_heap_entry->bytes = malloc(_ma_vma_heap_entry->len); 184 | } 185 | 186 | void _ma_vma_stack_entry_init(int argc, char *argv[]) { 187 | _ma_reg_t argc_dummy = 1; /* FIXME: proper argc */ 188 | _ma_reg_t sp; 189 | #if _MA_REG_WIDTH == 32 190 | _ma_vma_stack_entry->addr = 0xc0000000; /* 3 GiB */ /* FIXME */ 191 | #else 192 | _ma_vma_stack_entry->addr = 0x7ffffffff000; /* 128 TiB */ /* FIXME */ 193 | #endif 194 | _ma_vma_stack_entry->len = 4 * 1024 * 1024; /* 4 MiB */ /* FIXME */ 195 | _ma_vma_stack_entry->addr -= _ma_vma_stack_entry->len; 196 | _MA_DEBUGF("Stack begin=0x%"_MA_PRIx" len=%"_MA_PRId, _ma_vma_stack_entry->addr, _ma_vma_stack_entry->len); 197 | _ma_vma_stack_entry->bytes = malloc(_ma_vma_stack_entry->len); 198 | memset(_ma_vma_stack_entry->bytes, 0, _ma_vma_stack_entry->len); 199 | /* Initialize the stack */ 200 | sp = _ma_vma_stack_entry->addr + _ma_vma_stack_entry->len; 201 | _ma_regs.x[_MA_REG_FP]= sp; 202 | 203 | /* Initialize AT_RANDOM */ 204 | /* FIXME: this shouldn't be on the stack? */ 205 | sp -= 16; 206 | getentropy(_ma_vma_stack_entry->bytes + sp - _ma_vma_stack_entry->addr, 16); 207 | _ma_reg_t randomp = sp; 208 | 209 | /* Initialize AT_PHDR */ 210 | /* FIXME: this shouldn't be on the stack? */ 211 | sp -= _ma_at_phent * _ma_at_phnum; 212 | memcpy(_ma_vma_stack_entry->bytes + sp - _ma_vma_stack_entry->addr, _ma_at_ph, _ma_at_phent * _ma_at_phnum); 213 | _ma_reg_t phdr = sp; 214 | 215 | /* Initialize auxv */ 216 | struct { 217 | _ma_reg_t k; 218 | _ma_reg_t v; 219 | } auxv[] = { 220 | {3 /* AT_PHDR */, phdr}, 221 | {4 /* AT_PHENT */, _ma_at_phent}, 222 | {5 /* AT_PHNUM */, _ma_at_phnum}, 223 | {6 /* AT_PAGESZ */, 4096}, 224 | {9 /* AT_ENTRY */, _ma_at_entry}, 225 | {11 /* AT_UID */, getuid()}, 226 | {12 /* AT_EUID */, geteuid()}, 227 | {13 /* AT_GID */, getgid()}, 228 | {14 /* AT_EGID */, getegid()}, 229 | {23 /* AT_SECURE */, 0}, 230 | {25 /* AT_RANDOM */, randomp}, 231 | {0 /* AT_NULL */, 0}, 232 | }; 233 | sp -= sizeof(auxv); 234 | memcpy(_ma_vma_stack_entry->bytes + sp - _ma_vma_stack_entry->addr, auxv, sizeof(auxv)); 235 | 236 | /* TODO: envp */ 237 | sp -= sizeof(_ma_reg_t); 238 | 239 | /* TODO: argv */ 240 | sp -= sizeof(_ma_reg_t) * (argc_dummy + 1); 241 | 242 | /* TODO: argc */ 243 | sp -= sizeof(_ma_reg_t); 244 | memcpy(_ma_vma_stack_entry->bytes + sp - _ma_vma_stack_entry->addr, &argc_dummy, sizeof(_ma_reg_t)); 245 | 246 | _ma_regs.x[_MA_REG_SP]= sp; 247 | } 248 | 249 | void* _ma_translate_ptr(_ma_reg_t r) { 250 | void *ret = (void*)(long)r; 251 | int i = 0; 252 | for (;;) { 253 | struct _ma_vma_entry *ent = _ma_vma_entries[i]; 254 | if (ent == NULL) break; 255 | if (ent->addr <= r && r <= ent->addr + ent->len -1) { 256 | if (ent->bytes == NULL) { 257 | _MA_DEBUGF("Mapping VMA address 0x%08"_MA_PRIx, r); 258 | ent->bytes = malloc(ent->len); 259 | memset(ent->bytes, 0, ent->len); 260 | } 261 | ret = ent->bytes + r - ent->addr; 262 | break; 263 | } 264 | i++; 265 | } 266 | _MA_DEBUGF("_ma_translate_ptr(0x%08"_MA_PRIx") --> 0x%08llx", r, (long long)ret); 267 | return ret; 268 | } 269 | 270 | #define _MA_EACCES 13 271 | #define _MA_ENOSYS 38 272 | 273 | #define _MA_TCGETS 0x5401 274 | typedef _ma_reg_t _ma_tcflag_t; 275 | typedef uint8_t _ma_cc_t; 276 | #define _MA_NCCS 19 277 | struct _ma_termios { 278 | _ma_tcflag_t c_iflag; 279 | _ma_tcflag_t c_oflag; 280 | _ma_tcflag_t c_cflag; 281 | _ma_tcflag_t c_lflag; 282 | _ma_cc_t c_line; 283 | _ma_cc_t c_cc[_MA_NCCS]; 284 | }; 285 | 286 | #define _MA_AT_EMPTY_PATH 0x1000 287 | 288 | struct _ma_statx_timestamp { 289 | int64_t tv_sec; 290 | uint32_t tv_nsec; 291 | }; 292 | struct _ma_statx { 293 | uint32_t stx_mask; 294 | uint32_t stx_blksize; 295 | uint64_t stx_attributes; 296 | uint32_t stx_nlink; 297 | uint32_t stx_uid; 298 | uint32_t stx_gid; 299 | uint16_t stx_mode; 300 | uint64_t stx_ino; 301 | uint64_t stx_size; 302 | uint64_t stx_blocks; 303 | uint64_t stx_attributes_mask; 304 | struct _ma_statx_timestamp stx_atime; 305 | struct _ma_statx_timestamp stx_btime; 306 | struct _ma_statx_timestamp stx_ctime; 307 | struct _ma_statx_timestamp stx_mtime; 308 | uint32_t stx_rdev_major; 309 | uint32_t stx_rdev_minor; 310 | uint32_t stx_dev_major; 311 | uint32_t stx_dev_minor; 312 | uint64_t stx_mnt_id; 313 | uint32_t stx_dio_mem_align; 314 | uint32_t stx_dio_offset_align; 315 | uint64_t __spare3[12]; 316 | }; 317 | #define _MA_STATX_TYPE 0x00000001U 318 | #define _MA_STATX_MODE 0x00000002U 319 | #define _MA_STATX_NLINK 0x00000004U 320 | #define _MA_STATX_UID 0x00000008U 321 | #define _MA_STATX_GID 0x00000010U 322 | #define _MA_STATX_ATIME 0x00000020U 323 | #define _MA_STATX_MTIME 0x00000040U 324 | #define _MA_STATX_CTIME 0x00000080U 325 | #define _MA_STATX_INO 0x00000100U 326 | #define _MA_STATX_SIZE 0x00000200U 327 | #define _MA_STATX_BLOCKS 0x00000400U 328 | #define _MA_STATX_BASIC_STATS 0x000007ffU 329 | #define _MA_STATX_BTIME 0x00000800U 330 | #define _MA_STATX_MNT_ID 0x00001000U 331 | #define _MA_STATX_DIOALIGN 0x00002000U 332 | #define _MA_STATX__RESERVED 0x80000000U 333 | #define _MA_STATX_ATTR_COMPRESSED 0x00000004 334 | #define _MA_STATX_ATTR_IMMUTABLE 0x00000010 335 | #define _MA_STATX_ATTR_APPEND 0x00000020 336 | #define _MA_STATX_ATTR_NODUMP 0x00000040 337 | #define _MA_STATX_ATTR_ENCRYPTED 0x00000800 338 | #define _MA_STATX_ATTR_AUTOMOUNT 0x00001000 339 | #define _MA_STATX_ATTR_MOUNT_ROOT 0x00002000 340 | #define _MA_STATX_ATTR_VERITY 0x00100000 341 | #define _MA_STATX_ATTR_DAX 0x00200000 342 | 343 | void _ma_ecall(void) { 344 | _MA_DEBUGF("Syscall %"_MA_PRId" (%"_MA_PRId", %"_MA_PRId",%"_MA_PRId", %"_MA_PRId", %"_MA_PRId", %"_MA_PRId")", 345 | _ma_regs.x[_MA_REG_A7], 346 | _ma_regs.x[_MA_REG_A0], _ma_regs.x[_MA_REG_A1], _ma_regs.x[_MA_REG_A2], _ma_regs.x[_MA_REG_A3], _ma_regs.x[_MA_REG_A4], _ma_regs.x[_MA_REG_A5]); 347 | errno = 0; 348 | /* Syscall table: https://jborza.com/post/2021-05-11-riscv-linux-syscalls/ */ 349 | switch (_ma_regs.x[_MA_REG_A7]){ 350 | case 29: /* asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); */ 351 | { 352 | /* TODO */ 353 | _ma_reg_t fd = _ma_regs.x[_MA_REG_A0]; 354 | _ma_reg_t cmd = _ma_regs.x[_MA_REG_A1]; 355 | _ma_reg_t arg = _ma_regs.x[_MA_REG_A2]; 356 | switch (cmd) { 357 | case _MA_TCGETS: 358 | { 359 | struct termios t_host; 360 | int rc = tcgetattr(fd, &t_host); 361 | if (rc == 0) { 362 | struct _ma_termios t; 363 | memset(&t, 0, sizeof(t)); 364 | t.c_iflag = t_host.c_iflag; 365 | t.c_oflag = t_host.c_oflag; 366 | t.c_cflag = t_host.c_cflag; 367 | t.c_lflag = t_host.c_lflag; 368 | memcpy(t.c_cc, t_host.c_cc, MIN(NCCS, _MA_NCCS)); 369 | memcpy(_ma_translate_ptr(arg), &t, sizeof(t)); 370 | _ma_regs.x[_MA_REG_A0] = 0; 371 | } else { 372 | _ma_regs.x[_MA_REG_A0] = -1; 373 | } 374 | } 375 | break; 376 | default: 377 | _ma_regs.x[_MA_REG_A0] = -1; 378 | errno = _MA_EACCES; 379 | _MA_FATALF("Unsupported ioctl(%"_MA_PRId", 0x%08"_MA_PRIx", 0x%08"_MA_PRIx")", fd, cmd, arg); 380 | break; 381 | } 382 | } 383 | break; 384 | case 48: /* asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode); */ 385 | /* TODO */ 386 | _ma_regs.x[_MA_REG_A0] = -1; 387 | errno = _MA_EACCES; 388 | break; 389 | case 63: /* asmlinkage long sys_read(unsigned int fd, const char __user *buf, size_t count); */ 390 | _ma_regs.x[_MA_REG_A0] = read((int)_ma_regs.x[_MA_REG_A0], _ma_translate_ptr(_ma_regs.x[_MA_REG_A1]), (size_t)_ma_regs.x[_MA_REG_A2]); 391 | break; 392 | case 64: /* asmlinkage long sys_write(unsigned int fd, const char __user *buf, size_t count); */ 393 | _ma_regs.x[_MA_REG_A0] = write((int)_ma_regs.x[_MA_REG_A0], _ma_translate_ptr(_ma_regs.x[_MA_REG_A1]), (size_t)_ma_regs.x[_MA_REG_A2]); 394 | break; 395 | case 66: /* asmlinkage long sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen); */ 396 | { 397 | _ma_reg_t fd = _ma_regs.x[_MA_REG_A0]; 398 | _ma_reg_t iovcnt = _ma_regs.x[_MA_REG_A2]; 399 | struct _ma_iovec { 400 | _ma_reg_t iov_base; 401 | _ma_reg_t iov_len; 402 | } _ma_iovec; 403 | struct _ma_iovec *iov_g = malloc(sizeof(struct _ma_iovec)*iovcnt); 404 | memcpy(iov_g, _ma_translate_ptr(_ma_regs.x[_MA_REG_A1]), sizeof(_ma_iovec)*iovcnt); 405 | struct iovec *iov_h = malloc(sizeof(struct iovec)*iovcnt); 406 | int i; 407 | for (i = 0; i < iovcnt; i++) { 408 | iov_h[i].iov_base = _ma_translate_ptr(iov_g[i].iov_base); 409 | iov_h[i].iov_len = iov_g[i].iov_len; 410 | } 411 | _ma_regs.x[_MA_REG_A0] = writev(fd, iov_h, iovcnt); 412 | free(iov_g); 413 | free(iov_h); 414 | } 415 | case 78: /* asmlinkage long sys_readlinkat(int dfd, const char __user *path, char __user *buf, int bufsiz); */ 416 | /* TODO */ 417 | _ma_regs.x[_MA_REG_A0] = -1; 418 | errno = _MA_EACCES; 419 | break; 420 | case 93: /* asmlinkage long sys_exit(int error_code); */ 421 | exit((int)_ma_regs.x[_MA_REG_A0]); 422 | break; 423 | case 94: /* asmlinkage long sys_exit_group(int error_code); */ 424 | #if defined(__linux__) 425 | syscall(SYS_exit_group, _ma_regs.x[_MA_REG_A0]); 426 | #else 427 | exit(_ma_regs.x[_MA_REG_A0]); 428 | #endif 429 | break; 430 | case 79: /* asmlinkage long sys_newfstatat(int dfd, const char __user *filename, struct stat __user *statbuf, int flag); */ 431 | /* TODO */ 432 | _ma_regs.x[_MA_REG_A0] = -1; 433 | errno = _MA_ENOSYS; 434 | break; 435 | case 96: /* asmlinkage long sys_set_tid_address(int __user *tidptr); */ 436 | #if defined(__linux__) 437 | /* TODO */ 438 | _ma_regs.x[_MA_REG_A0] = gettid(); 439 | #else 440 | _ma_regs.x[_MA_REG_A0] = 0; /* STUB */ 441 | #endif 442 | case 99: /* asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, size_t len); */ 443 | /* TODO */ 444 | _ma_regs.x[_MA_REG_A0] = -1; 445 | errno = _MA_ENOSYS; 446 | case 131: /* asmlinkage long sys_tgkill(pid_t tgid, pid_t pid, int sig); */ 447 | #if defined(__linux__) 448 | _ma_regs.x[_MA_REG_A0] = tgkill(_ma_regs.x[_MA_REG_A0], _ma_regs.x[_MA_REG_A1], _ma_regs.x[_MA_REG_A2]); 449 | #else 450 | /* TODO */ 451 | _ma_regs.x[_MA_REG_A0] = kill(_ma_regs.x[_MA_REG_A1], _ma_regs.x[_MA_REG_A2]); 452 | #endif 453 | break; 454 | case 135: /* asmlinkage long sys_rt_sigprocmask(int how, sigset_t __user *set, sigset_t __user *oset, size_t sigsetsize); */ 455 | /* TODO */ 456 | _ma_regs.x[_MA_REG_A0] = 0; 457 | break; 458 | case 160: /* asmlinkage long sys_newuname(struct new_utsname __user *name); */ 459 | { 460 | struct { 461 | char sysname[65]; 462 | char nodename[65]; 463 | char release[65]; 464 | char version[65]; 465 | char machine[65]; 466 | char domainname[65]; 467 | } u = { 468 | .sysname = "Linux", 469 | .nodename = "myaot", 470 | .release = "6.0.0-0-myaot", 471 | .version = "#0-MyAOT", 472 | #if _MA_REG_WIDTH == 32 473 | .machine = "riscv32", 474 | #else 475 | .machine = "riscv64", 476 | #endif 477 | }; 478 | memcpy(_ma_translate_ptr(_ma_regs.x[_MA_REG_A0]), &u, sizeof(u)); 479 | _ma_regs.x[_MA_REG_A0] = 0; 480 | } 481 | break; 482 | case 172: /* asmlinkage long sys_getpid(void); */ 483 | _ma_regs.x[_MA_REG_A0] = getpid(); 484 | break; 485 | case 173: /* asmlinkage long sys_getppid(void); */ 486 | _ma_regs.x[_MA_REG_A0] = getppid(); 487 | break; 488 | case 174: /* asmlinkage long sys_getuid(void); */ 489 | _ma_regs.x[_MA_REG_A0] = getuid(); 490 | break; 491 | case 175: /* asmlinkage long sys_geteuid(void); */ 492 | _ma_regs.x[_MA_REG_A0] = geteuid(); 493 | break; 494 | case 176: /* asmlinkage long sys_getgid(void); */ 495 | _ma_regs.x[_MA_REG_A0] = getgid(); 496 | break; 497 | case 177: /* asmlinkage long sys_getegid(void); */ 498 | _ma_regs.x[_MA_REG_A0] = getegid(); 499 | break; 500 | case 178: /* asmlinkage long sys_gettid(void); */ 501 | #if defined(__linux__) 502 | _ma_regs.x[_MA_REG_A0] = gettid(); 503 | #else 504 | _ma_regs.x[_MA_REG_A0] = 0; /* STUB */ 505 | #endif /* __linux__ */ 506 | break; 507 | case 214: /* asmlinkage long sys_brk(unsigned long brk); */ 508 | if (_ma_regs.x[_MA_REG_A0] == 0) { 509 | _ma_regs.x[_MA_REG_A0] = _ma_vma_heap_cur; 510 | } else if (_ma_vma_heap_entry->addr <= _ma_regs.x[_MA_REG_A0] && 511 | _ma_regs.x[_MA_REG_A0] <= _ma_vma_heap_entry->addr + _ma_vma_heap_entry->len - 1) { 512 | _ma_vma_heap_cur = _ma_regs.x[_MA_REG_A0]; 513 | } else { 514 | _MA_FATALF("Unsupported brk(0x%08"_MA_PRIx")", _ma_regs.x[_MA_REG_A0]); 515 | } 516 | break; 517 | case 215: /* asmlinkage long sys_munmap(unsigned long addr, size_t len); */ 518 | /* TODO */ 519 | _ma_regs.x[_MA_REG_A0] = 0; 520 | break; 521 | case 222: /* void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); */ 522 | /* TODO */ 523 | if (_ma_regs.x[_MA_REG_A4] != -1) { 524 | _MA_FATALF("Unsupported mmap(A4=0x%08"_MA_PRIx")", _ma_regs.x[_MA_REG_A4]); 525 | } 526 | if (_ma_regs.x[_MA_REG_A5] != 0) { 527 | _MA_FATALF("Unsupported mmap(A5=0x%08"_MA_PRIx")", _ma_regs.x[_MA_REG_A5]); 528 | } 529 | if (_ma_regs.x[_MA_REG_A0] == 0) { 530 | _ma_regs.x[_MA_REG_A0] = _ma_vma_heap_cur; 531 | _ma_vma_heap_cur += _ma_regs.x[_MA_REG_A1]; 532 | } else { 533 | _MA_FATALF("Unsupported mmap(A0=0x%08"_MA_PRIx")", _ma_regs.x[_MA_REG_A0]); 534 | } 535 | break; 536 | case 226: /* asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot); */ 537 | /* TODO */ 538 | _ma_regs.x[_MA_REG_A0] = 0; 539 | break; 540 | case 261: /* asmlinkage long sys_prlimit64(pid_t pid, unsigned int resource, const struct rlimit64 __user *new_rlim, struct rlimit64 __user *old_rlim); */ 541 | /* TODO */ 542 | _ma_regs.x[_MA_REG_A0] = 0; 543 | break; 544 | case 278: /* asmlinkage long sys_getrandom(char __user *buf, size_t count, unsigned int flags); */ 545 | { 546 | _ma_reg_t buf = _ma_regs.x[_MA_REG_A0]; 547 | _ma_reg_t count = _ma_regs.x[_MA_REG_A1]; 548 | _ma_regs.x[_MA_REG_A0] = getentropy(_ma_translate_ptr(buf), count); 549 | } 550 | break; 551 | case 291: /* asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags, unsigned mask, struct statx __user *buffer); */ 552 | { 553 | _ma_reg_t dfd = _ma_regs.x[_MA_REG_A0]; 554 | _ma_reg_t flags = _ma_regs.x[_MA_REG_A2]; 555 | if ((flags & _MA_AT_EMPTY_PATH) == 0) { 556 | _MA_FATALF("Unsupported statx(flags=0x%08"_MA_PRIx")", flags); 557 | } 558 | struct stat st; 559 | errno = fstat(dfd, &st); 560 | if (errno == 0) { 561 | struct _ma_statx stx; 562 | memset(&stx, 0, sizeof(stx)); 563 | stx.stx_mask = _MA_STATX_BASIC_STATS; 564 | stx.stx_blksize = st.st_blksize; 565 | stx.stx_attributes = 0; 566 | stx.stx_nlink = st.st_nlink; 567 | stx.stx_uid = st.st_uid; 568 | stx.stx_gid = st.st_gid; 569 | stx.stx_mode = st.st_mode; 570 | stx.stx_ino = st.st_ino; 571 | stx.stx_size = st.st_size; 572 | stx.stx_blocks = st.st_blocks; 573 | memcpy(_ma_translate_ptr(_ma_regs.x[_MA_REG_A4]), &stx, sizeof(stx)); 574 | _ma_regs.x[_MA_REG_A0] = 0; 575 | } else { 576 | _ma_regs.x[_MA_REG_A0] = -1; 577 | } 578 | } 579 | break; 580 | case 113: 581 | /* fallthrough */ 582 | case 403: /* asmlinkage long sys_clock_gettime(clockid_t which_clock, struct __kernel_timespec __user *tp); */ 583 | { 584 | /* TODO: check which_clock */ 585 | struct timespec tp_host; 586 | int ret = clock_gettime(CLOCK_REALTIME, &tp_host); 587 | struct { 588 | uint64_t tv_sec; /* time_t */ 589 | _ma_reg_t tv_nsec; /* long */ 590 | } tp = { 591 | .tv_sec = (uint64_t)tp_host.tv_sec, 592 | .tv_nsec = (_ma_reg_t)tp_host.tv_nsec, 593 | }; 594 | memcpy(_ma_translate_ptr(_ma_regs.x[_MA_REG_A1]), &tp, sizeof(tp)); 595 | _ma_regs.x[_MA_REG_A0] = (_ma_reg_t)ret; 596 | } 597 | break; 598 | case 422: /* asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val, struct __kernel_timespec __user *utime, u32 __user *uaddr2, u32 val3); */ 599 | /* TODO */ 600 | if ((_ma_regs.x[_MA_REG_A1] & 0x7F) == 0) { 601 | /* FUTEX_WAIT */ 602 | _ma_regs.x[_MA_REG_A0] = 0; 603 | } else { 604 | _MA_FATALF("Unknown futex op 0%08"_MA_PRIx, _ma_regs.x[_MA_REG_A1]); 605 | } 606 | break; 607 | default: 608 | _MA_FATALF("Unknown syscall number %"_MA_PRId, _ma_regs.x[_MA_REG_A7]); 609 | break; 610 | } 611 | if (errno != 0) { 612 | _ma_regs.x[_MA_REG_A1] = errno; 613 | } 614 | } 615 | -------------------------------------------------------------------------------- /pkg/iomisc/iomisc.go: -------------------------------------------------------------------------------- 1 | package iomisc 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | // ForceWriter panics on an error. 8 | func ForceWriter(w io.Writer) io.Writer { 9 | return &forceWriter{ 10 | Writer: w, 11 | } 12 | } 13 | 14 | type forceWriter struct { 15 | io.Writer 16 | } 17 | 18 | func (w *forceWriter) Write(p []byte) (int, error) { 19 | n, err := w.Writer.Write(p) 20 | if err != nil { 21 | panic(err) 22 | } 23 | return n, nil 24 | } 25 | -------------------------------------------------------------------------------- /pkg/signext/signext.go: -------------------------------------------------------------------------------- 1 | package signext 2 | 3 | // signBit(4) = 0b0000'1000 4 | func signBit(bits int) int { 5 | return 1 << (bits - 1) 6 | } 7 | 8 | // signMask(4) = 0b1111'1000 9 | func signMask(bits int) int { 10 | return ^(signBit(bits) - 1) 11 | } 12 | 13 | func SignExt(val, bits int) int { 14 | if val&signBit(bits) != 0 { 15 | return val | signMask(bits) 16 | } 17 | return val 18 | } 19 | -------------------------------------------------------------------------------- /pkg/signext/signext_test.go: -------------------------------------------------------------------------------- 1 | package signext 2 | 3 | import ( 4 | "gotest.tools/v3/assert" 5 | "testing" 6 | ) 7 | 8 | func TestSignExt(t *testing.T) { 9 | assert.Equal(t, 305419896, SignExt(0x12345678, 2)) 10 | assert.Equal(t, -8, SignExt(0x12345678, 4)) 11 | } 12 | --------------------------------------------------------------------------------