├── .github └── FUNDING.yml ├── .gitignore ├── .rustfmt.toml ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── misc ├── Disassembly1.png ├── Screenshot1.png ├── Spore.png └── Usage.png └── src ├── CLI.txt ├── argument.rs ├── bits.rs ├── instruction.rs ├── main.rs ├── natural_index.rs ├── opcode.rs ├── operand.rs ├── options.rs ├── tests └── mod.rs └── theme.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [pebaz] 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | # https://rust-lang.github.io/rustfmt/?version=v1.4.38&search= 2 | 3 | # indent_style = "Block" 4 | # reorder_imports = false 5 | 6 | use_small_heuristics = "Off" 7 | comment_width = 120 8 | max_width = 120 9 | fn_call_width = 120 10 | attr_fn_like_width = 120 11 | struct_lit_width = 120 12 | struct_variant_width = 120 13 | array_width = 120 14 | chain_width = 120 15 | single_line_if_else_max_width = 120 16 | 17 | reorder_impl_items = true 18 | reorder_imports = true 19 | group_imports = "StdExternalCrate" 20 | 21 | merge_derives = true 22 | indent_style = "Block" 23 | brace_style = "AlwaysNextLine" 24 | control_brace_style = "AlwaysNextLine" 25 | combine_control_expr = false 26 | fn_args_layout = "Tall" 27 | condense_wildcard_suffixes = true 28 | spaces_around_ranges = true 29 | wrap_comments = true 30 | blank_lines_upper_bound = 1 31 | newline_style = "Unix" 32 | overflow_delimited_expr = true 33 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "arrayvec" 7 | version = "0.7.6" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" 10 | 11 | [[package]] 12 | name = "colored" 13 | version = "2.1.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" 16 | dependencies = [ 17 | "lazy_static", 18 | "windows-sys", 19 | ] 20 | 21 | [[package]] 22 | name = "dataview" 23 | version = "0.1.2" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "47a802a2cad0ff4dfc4f3110da174b7a6928c315cae523e88638cfb72941b4d5" 26 | dependencies = [ 27 | "derive_pod", 28 | ] 29 | 30 | [[package]] 31 | name = "derive_pod" 32 | version = "0.1.2" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "c2ea6706d74fca54e15f1d40b5cf7fe7f764aaec61352a9fcec58fe27e042fc8" 35 | 36 | [[package]] 37 | name = "lazy_static" 38 | version = "1.5.0" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 41 | 42 | [[package]] 43 | name = "libc" 44 | version = "0.2.165" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "fcb4d3d38eab6c5239a362fa8bae48c03baf980a6e7079f063942d563ef3533e" 47 | 48 | [[package]] 49 | name = "no-std-compat" 50 | version = "0.4.1" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" 53 | 54 | [[package]] 55 | name = "pelite" 56 | version = "0.9.2" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "9a821dd5a5c4744099b50dc94a6a381c8b4b007f4d80da5334428e220945319b" 59 | dependencies = [ 60 | "dataview", 61 | "libc", 62 | "no-std-compat", 63 | "pelite-macros", 64 | "winapi", 65 | ] 66 | 67 | [[package]] 68 | name = "pelite-macros" 69 | version = "0.1.1" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "7a7cf3f8ecebb0f4895f4892a8be0a0dc81b498f9d56735cb769dc31bf00815b" 72 | 73 | [[package]] 74 | name = "spore-disassembler" 75 | version = "0.1.1" 76 | dependencies = [ 77 | "arrayvec", 78 | "colored", 79 | "pelite", 80 | ] 81 | 82 | [[package]] 83 | name = "winapi" 84 | version = "0.3.9" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 87 | dependencies = [ 88 | "winapi-i686-pc-windows-gnu", 89 | "winapi-x86_64-pc-windows-gnu", 90 | ] 91 | 92 | [[package]] 93 | name = "winapi-i686-pc-windows-gnu" 94 | version = "0.4.0" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 97 | 98 | [[package]] 99 | name = "winapi-x86_64-pc-windows-gnu" 100 | version = "0.4.0" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 103 | 104 | [[package]] 105 | name = "windows-sys" 106 | version = "0.48.0" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 109 | dependencies = [ 110 | "windows-targets", 111 | ] 112 | 113 | [[package]] 114 | name = "windows-targets" 115 | version = "0.48.5" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 118 | dependencies = [ 119 | "windows_aarch64_gnullvm", 120 | "windows_aarch64_msvc", 121 | "windows_i686_gnu", 122 | "windows_i686_msvc", 123 | "windows_x86_64_gnu", 124 | "windows_x86_64_gnullvm", 125 | "windows_x86_64_msvc", 126 | ] 127 | 128 | [[package]] 129 | name = "windows_aarch64_gnullvm" 130 | version = "0.48.5" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 133 | 134 | [[package]] 135 | name = "windows_aarch64_msvc" 136 | version = "0.48.5" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 139 | 140 | [[package]] 141 | name = "windows_i686_gnu" 142 | version = "0.48.5" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 145 | 146 | [[package]] 147 | name = "windows_i686_msvc" 148 | version = "0.48.5" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 151 | 152 | [[package]] 153 | name = "windows_x86_64_gnu" 154 | version = "0.48.5" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 157 | 158 | [[package]] 159 | name = "windows_x86_64_gnullvm" 160 | version = "0.48.5" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 163 | 164 | [[package]] 165 | name = "windows_x86_64_msvc" 166 | version = "0.48.5" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 169 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "spore-disassembler" 3 | version = "0.1.1" 4 | description = "UEFI Bytecode Disassembler" 5 | authors = ["https://github.com/Pebaz"] 6 | edition = "2021" 7 | license = "Zlib" 8 | keywords = ["disassembler", "UEFI", "bytecode", "assembly"] 9 | categories = ["compilers"] 10 | repository = "https://github.com/Pebaz/spore" 11 | homepage = "https://github.com/Pebaz/spore" 12 | readme = "README.md" 13 | 14 | [[bin]] 15 | name = "spore" 16 | path = "src/main.rs" 17 | 18 | [dependencies] 19 | colored = "2.0.0" 20 | arrayvec = "0.7.1" 21 | pelite = "0.9.0" 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | zlib License 2 | 3 | (C) Copyright 2021 Samuel Wilder 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spore - UEFI Bytecode Disassembler 2 | 3 | 4 | 5 | 8 | 11 | 12 |
6 | 7 | 9 | 10 |
13 | 14 | > 🍄 A disassembler for the UEFI Bytecode Virtual Machine. For details on the 15 | VM, see [section 22 of the UEFI Specification](https://uefi.org/sites/default/files/resources/UEFI_Spec_2_9_2021_03_18.pdf). 16 | 17 | ## Installation 18 | 19 | ```bash 20 | $ cargo install spore-disassembler 21 | 22 | # Or alternatively 23 | $ cargo install --git https://github.com/Pebaz/spore 24 | ``` 25 | 26 | ## Demo 27 | 28 | Although Spore will work with any EBC binary, users will most likely benefit 29 | from [fasmg-ebc-rs](https://github.com/Pebaz/fasmg-ebc-rs) which makes it much 30 | simpler to work with the [fasmg-ebc](https://github.com/pbatard/fasmg-ebc) 31 | assembler. 32 | 33 | Given the following fasmg-ebc UEFI Bytecode Assembly file: 34 | 35 | ```x86asm 36 | ;; Adapted from https://github.com/pbatard/fasmg-ebc/blob/master/hello.asm 37 | 38 | include 'ebc.inc' 39 | include 'efi.inc' 40 | include 'format.inc' 41 | include 'utf8.inc' 42 | 43 | format peebc efi ;; PE executable format, EFI Byte Code 44 | 45 | entry efi_main 46 | 47 | section '.text' code executable readable 48 | 49 | efi_main: 50 | MOVn R1, @R0(EFI_MAIN_PARAMETERS.SystemTable) 51 | MOVn R1, @R1(EFI_SYSTEM_TABLE.ConOut) 52 | MOVREL R2, string_hello 53 | PUSHn R2 54 | PUSHn R1 55 | CALLEX @R1(SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString) 56 | MOV R0, R0(+2,0) 57 | JMP efi_main 58 | RET 59 | 60 | section '.data' data readable writeable 61 | string_hello: du "Hello World!", 0x0A, 0x0 62 | ``` 63 | 64 | Compile it using [fasmg-ebc-rs](https://github.com/Pebaz/fasmg-ebc-rs) by using 65 | the below command: 66 | 67 | ```bash 68 | $ cargo install fasmg-ebc-rs 69 | $ fasmg-ebc-rs bc.asm bc.efi 70 | 71 | # This is a PE executable that contains UEFI Bytecode 72 | $ file bc.efi 73 | bc.efi: PE32+ executable (DLL) (EFI application) EFI byte code, for MS Windows 74 | ``` 75 | 76 | Now that we have a bootable PE executable, we can output the bytecode 77 | instructions inside of it: 78 | 79 | ```bash 80 | $ spore bc.efi 81 | ``` 82 | 83 | The disassembled bytecode instructions are then emitted by Spore: 84 | 85 | ```x86asm 86 | 72 81 41 10 MOVnw R1, @R0(+1, +16) 87 | 72 91 85 21 MOVnw R1, @R1(+5, +24) 88 | 79 02 F4 0F MOVRELw R2, 4084 89 | 35 02 PUSHn R2 90 | 35 01 PUSHn R1 91 | 83 29 01 00 00 10 CALL32EXa @R1(+1, +0) 92 | 60 00 02 10 MOVqw R0, R0(+2, +0) 93 | 02 F2 JMP8 -14 94 | 04 RET 95 | ``` 96 | 97 | ## Usage 98 | 99 |

100 | 101 |

102 | 103 | ## Why 104 | 105 | I am learning about making operating systems because I think it is fun. It is 106 | actually quite difficult, but the rewards are pretty satisfying. 107 | 108 | While learning about operating systems, I discovered the Unified Extensible 109 | Firmware Interface (UEFI). It's basically a set of C ABI interfaces that allow 110 | you to write pre-OS recovery software, OS installers, or boot managers. 111 | 112 | The UEFI Virtual Machine is literally preinstalled by default on most modern 113 | motherboards. Most of the time, you write applications that adhere to the UEFI 114 | API in C, and then you can boot into them directly. Astoundingly, you can also 115 | boot right into applications written with UEFI Bytecode (EBC)! 116 | 117 | The reason this is astonishing is that EBC is cross-platform, so it 118 | is truly like Java Bytecode in that regard. 119 | 120 | Even more surprising is that EBC has access to the same Boot & 121 | Runtime Services that normal UEFI applications have. *This means you can write 122 | a bootloader using EBC.* 123 | 124 | After I discovered this I set out to learn UEFI Bytecode, but didn't find very 125 | much on it. Thankfully, [Pete Batard](https://github.com/pbatard) built 126 | [FASMG-EBC](https://github.com/pbatard/fasmg-ebc), an assembler for EBC. 127 | 128 | I wanted to better understand the output of the assembler and to do that, I 129 | would need to work with it more. That's when I decided to build Spore. 😄 130 | 131 | ## How did I do it? 132 | 133 | I started out by perusing the [UEFI Specification](https://uefi.org/sites/default/files/resources/UEFI_Spec_2_9_2021_03_18.pdf) 134 | very carefully and found that all of the information I would need was contained 135 | in section 22. From there, I decided to use Rust to build the disassembler 136 | since it is my current favorite language for many reasons. 137 | 138 | I then created a Python script that would generate some specific bytecode 139 | sequences without having to deal with the PE file format. This was one of the 140 | most important steps in the entire project because I learned how to interpret 141 | the binary structure of a few of the instructions. 142 | 143 | Once I had some bytes to work with, I wrote some Rust code that would open the 144 | file and iterate through the bytes. Amazingly enough, the entire application 145 | runs by passing a single iterator to all the functions that parse out 146 | instructions! All the parsing functions just advance the iterator and return 147 | any errors. 148 | 149 | This really made the whole process easier because all I had to do was look at 150 | the first byte to determine the opcode of the instruction and route it to the 151 | appropriate parser function. Since many instructions have varying lengths of 152 | bytes, the iterator approach worked amazingly well. 153 | 154 | After I had written a fair bit, I noticed that many of the instructions were 155 | using the exact same parsing routines. I also noticed that I was implementing 1 156 | instruction at a time and there were 55 total instructions so this was not 157 | going to work well. I then had to step back and see what could be reused and 158 | what had to be kept. I then read through all 55 instructions in the 159 | specification and grouped each instruction type by how it was parsed. Once that 160 | was done, I just had to write 1 parsing function per type (total of 7)! 161 | 162 | At this point, I knew what I was getting myself into and determined that I 163 | needed to have some better unit testing to ensure I was not messing anything up 164 | during refactoring. I had been incrementally adding to the Python script to 165 | output each and every instruction as well as every combination of arguments but 166 | I knew that I would need to somehow verify that I was not breaking anything. 167 | 168 | The bytecode generator script looked like this: 169 | 170 | ```python 171 | bc = open('bc.bin') 172 | 173 | bc.write(0b00101010_00000001.to_bytes(2, 'big')) # $ STORESP R1, FLAGS 174 | 175 | # The rest of the instructions ... 176 | # This totaled 1162 lines of code 177 | ``` 178 | 179 | I wrote another Python script that would scrape out all of the assembly 180 | instructions from the bytecode generation script and write them to a file. 181 | 182 | It worked by looking for all the comments that contained the dollar sign `$` 183 | and writing them to a file. The result looked like this: 184 | 185 | ```x86asm 186 | STORESP R1, FLAGS 187 | 188 | ;; The rest of the instructions 189 | ``` 190 | 191 | Now that I had what I expected to come out of the disassembler, I could simply 192 | compare the output with this file to determine if I had any regressions! 193 | 194 | Once I had this, I could implement the rest of the instruction parsers and 195 | modify the existing ones at will and be sure that nothing would break. 196 | 197 | Implementing the rest of the parsers took a while, but once I was done, I 198 | needed to convert the Python test scripts to Rust unit tests. 199 | 200 | Again, I started by converting them one at a time by hand, but this soon became 201 | slightly ridiculous. 202 | 203 | I wrote another Python script that parsed the `bc.write(...)` directives from 204 | the bytecode generator script and converted them to Rust unit tests. This was 205 | immensely satisfying! 🙃 206 | 207 | Once I had working Rust unit tests, I went on to polish the CLI and fix bits 208 | and bobs of miscellaneous todo items. The rest is what you see in this README! 209 | 210 | 211 | 212 | **All in all, the project took me 20 days to complete.** 213 | 214 | Some things that I noticed while working on Spore: 215 | 216 | * Python was absolutely essential for rapid prototyping. I will continue to 217 | remember how well Rust + Python pair together for future projects. I used 218 | Python for: 219 | * Generating bytecode 220 | * Verifying disassembler output 221 | * Converting Python tests to Rust unit tests 222 | * Rust was amazing to use because it did not force me to think about 223 | structuring my code. It was just functions + structs + 1 trait 😛 224 | * One other thing that was amazing was that after I got the code to 225 | compile, very rarely was it incorrect. Rust's compiler is world-class. It 226 | also made refactoring fearless because I knew it would catch all the 227 | things. 228 | * The Rust ecosystem is amazing. I needed a PE file loader, so I used the 229 | [pelite](https://github.com/CasualX/pelite) crate, and it was a breeze. 230 | * The [colored](https://github.com/mackwic/colored) crate made outputting 231 | colored text very fun! 232 | * Rust doesn't have a Vec-like data structure that is allocated on the stack. I 233 | know this might be a strange requirement, but I don't like allocating 234 | everything on the heap all the time. The [arrayvec](https://github.com/bluss/arrayvec) 235 | crate allowed me to have a fixed-size buffer that had a Vec-like interface. 236 | * I used `include_str!()` for the CLI usage information and this was oddly 237 | satisfying! 😆 238 | * Strings. Let's talk about strings. I mean, why can't I stack allocate them 239 | very easily? I essentially want like a stack-allocated string builder to 240 | allow me to not make even a single allocation but implementing this would 241 | have taken forever. 😕 242 | 243 | ## Stargazers over time 244 | 245 | [![Stargazers over time](https://starchart.cc/Pebaz/Spore.svg)](https://starchart.cc/Pebaz/Spore) 246 | 247 | ## Notes 248 | 249 | * 🍄 Spore is named after mushroom spores. 250 | * 👏 Thank you to [Pete Batard](https://github.com/pbatard) for creating 251 | [FASMG-EBC](https://github.com/pbatard/fasmg-ebc) which is based on the Flat 252 | Assembler. Without this tool, I would not have had the assembly files to 253 | disassemble! 254 | * 🤯 The [UEFI Specification](https://uefi.org/sites/default/files/resources/UEFI_Spec_2_9_2021_03_18.pdf) 255 | is exceptionally well-written and contained all the information necessary to 256 | implement Spore. 257 | * 🤷‍♂️ Although Spore is cross-platform (Windows, MacOS, Linux), I have not tested 258 | whether FASMG-EBC works on other platforms. 259 | -------------------------------------------------------------------------------- /misc/Disassembly1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pebaz/spore/e5060714f216672ffd7f98d53d3a889c0e2ed50c/misc/Disassembly1.png -------------------------------------------------------------------------------- /misc/Screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pebaz/spore/e5060714f216672ffd7f98d53d3a889c0e2ed50c/misc/Screenshot1.png -------------------------------------------------------------------------------- /misc/Spore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pebaz/spore/e5060714f216672ffd7f98d53d3a889c0e2ed50c/misc/Spore.png -------------------------------------------------------------------------------- /misc/Usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pebaz/spore/e5060714f216672ffd7f98d53d3a889c0e2ed50c/misc/Usage.png -------------------------------------------------------------------------------- /src/CLI.txt: -------------------------------------------------------------------------------- 1 | Spore - Disassembler for UEFI Bytecode 2 | 3 | Usage: 4 | $ spore [OPTIONS] 5 | 6 | OPTIONS (default is first item in list): 7 | theme: [SPORE | INDUSTRIAL_COMPUTER | MATTERHORN_ZERMATT_VILLAGE | OFF] 8 | Color theme to output assembly in 9 | 10 | bytecode: [ON | OFF] 11 | Determines whether to also print out bytecode alongside assembly 12 | 13 | pe: [ON | OFF] 14 | ON = Windows PE file, OFF = binary file containing only UEFI Bytecode 15 | 16 | EXAMPLES: 17 | $ spore bytecode-file.efi 18 | $ spore bytecode: OFF bytecode-file.efi 19 | $ spore bytecode: OFF bytecode-file.efi 20 | $ spore theme: SPORE bytecode-file.efi 21 | $ spore bytecode: ON theme: SPORE bytecode-file.efi 22 | $ spore bytecode: ON theme: SPORE bytecode-file.efi 23 | $ spore pe: ON bytecode-file.efi 24 | $ spore pe: OFF bytecode-file.bin 25 | $ spore pe: OFF theme: SPORE bytecode-file.bin 26 | -------------------------------------------------------------------------------- /src/argument.rs: -------------------------------------------------------------------------------- 1 | use crate::natural_index::NaturalIndex; 2 | use crate::options::Options; 3 | use crate::theme::*; 4 | 5 | pub enum Argument 6 | { 7 | Index16(u16), 8 | Index32(u32), 9 | Index64(u64), 10 | ImmediateU16(u16), 11 | ImmediateU32(u32), 12 | ImmediateI16(i16), 13 | ImmediateI32(i32), 14 | ImmediateI64(i64), 15 | } 16 | 17 | impl Emit for Argument 18 | { 19 | fn emit(&self, options: &Options) -> String 20 | { 21 | match self 22 | { 23 | Self::Index16(index) => 24 | { 25 | let natural_index = NaturalIndex::from_u16(*index); 26 | 27 | format!("{}", natural_index.emit(options)) 28 | } 29 | 30 | Self::Index32(index) => 31 | { 32 | let natural_index = NaturalIndex::from_u32(*index); 33 | 34 | format!("{}", natural_index.emit(options)) 35 | } 36 | 37 | Self::Index64(index) => 38 | { 39 | let natural_index = NaturalIndex::from_u64(*index); 40 | 41 | format!("{}", natural_index.emit(options)) 42 | } 43 | 44 | Self::ImmediateU16(immediate) => color_immediate(immediate.to_string(), options), 45 | 46 | Self::ImmediateU32(immediate) => color_immediate(immediate.to_string(), options), 47 | 48 | Self::ImmediateI16(immediate) => color_immediate(immediate.to_string(), options), 49 | 50 | Self::ImmediateI32(immediate) => color_immediate(immediate.to_string(), options), 51 | 52 | Self::ImmediateI64(immediate) => color_immediate(immediate.to_string(), options), 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/bits.rs: -------------------------------------------------------------------------------- 1 | pub fn bits_u16(byte: u16) -> [bool; 16] 2 | { 3 | let mut bits = [false; 16]; 4 | 5 | for i in 0 .. 16 6 | { 7 | if byte & 2u16.pow(i) > 0 8 | { 9 | bits[(bits.len() - 1) - i as usize] = true; 10 | } 11 | } 12 | 13 | bits 14 | } 15 | 16 | pub fn bits_to_byte_u16(bits: &[bool]) -> u16 17 | { 18 | let mut byte = 0; 19 | 20 | for (i, bit) in bits.iter().rev().enumerate() 21 | { 22 | if *bit 23 | { 24 | byte += 2u16.pow((i) as u32); 25 | } 26 | } 27 | byte 28 | } 29 | 30 | pub fn bits_u32(byte: u32) -> [bool; 32] 31 | { 32 | let mut bits = [false; 32]; 33 | 34 | for i in 0 .. 32 35 | { 36 | if byte & 2u32.pow(i) > 0 37 | { 38 | bits[(bits.len() - 1) - i as usize] = true; 39 | } 40 | } 41 | 42 | bits 43 | } 44 | 45 | pub fn bits_to_byte_u32(bits: &[bool]) -> u32 46 | { 47 | let mut byte = 0; 48 | 49 | for (i, bit) in bits.iter().rev().enumerate() 50 | { 51 | if *bit 52 | { 53 | byte += 2u32.pow((i) as u32); 54 | } 55 | } 56 | byte 57 | } 58 | 59 | pub fn bits_u64(byte: u64) -> [bool; 64] 60 | { 61 | let mut bits = [false; 64]; 62 | 63 | for i in 0 .. 64 64 | { 65 | if byte & 2u64.pow(i) > 0 66 | { 67 | bits[(bits.len() - 1) - i as usize] = true; 68 | } 69 | } 70 | 71 | bits 72 | } 73 | 74 | pub fn bits_to_byte_u64(bits: &[bool]) -> u64 75 | { 76 | let mut byte = 0; 77 | 78 | for (i, bit) in bits.iter().rev().enumerate() 79 | { 80 | if *bit 81 | { 82 | byte += 2u64.pow((i) as u32); 83 | } 84 | } 85 | byte 86 | } 87 | 88 | /// Returns the bits of a byte in reverse so that indexing works as expected. 89 | pub fn bits_rev(byte: u8) -> [bool; 8] 90 | { 91 | let mut bits = [false; 8]; 92 | 93 | for i in 0 .. 8 94 | { 95 | if byte & 2u8.pow(i) > 0 96 | { 97 | bits[i as usize] = true; 98 | } 99 | } 100 | 101 | bits 102 | } 103 | 104 | /// Converts a slice of bits sorted in reverse to a byte. 105 | pub fn bits_to_byte_rev(bits: &[bool]) -> u8 106 | { 107 | let mut byte = 0; 108 | 109 | for (i, bit) in bits.iter().enumerate() 110 | { 111 | if *bit 112 | { 113 | byte += 2u8.pow((i) as u32); 114 | } 115 | } 116 | byte 117 | } 118 | 119 | #[cfg(test)] 120 | mod tests 121 | { 122 | use super::*; 123 | 124 | #[test] 125 | pub fn test_bits_to_byte() 126 | { 127 | assert_eq!(bits_to_byte_u32(&[true, false]), 2u32); 128 | assert_eq!(bits_to_byte_u32(&[false, true, false]), 2u32); 129 | assert_eq!(bits_to_byte_u32(&[true, false, false]), 4u32); 130 | assert_eq!(bits_to_byte_u32(&[true, false, false, false]), 8u32); 131 | assert_eq!(bits_to_byte_u32(&[true, false, false, true]), 9u32); 132 | assert_eq!(bits_to_byte_u32(&[true, false, true, true]), 11u32); 133 | 134 | assert_eq!(bits_to_byte_u64(&[true, false]), 2u64); 135 | assert_eq!(bits_to_byte_u64(&[false, true, false]), 2u64); 136 | assert_eq!(bits_to_byte_u64(&[true, false, false]), 4u64); 137 | assert_eq!(bits_to_byte_u64(&[true, false, false, false]), 8u64); 138 | assert_eq!(bits_to_byte_u64(&[true, false, false, true]), 9u64); 139 | assert_eq!(bits_to_byte_u64(&[true, false, true, true]), 11u64); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/instruction.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Instruction Type Breakdown: 3 | 4 | 7. ✅ INSTRUCTION OP1 ARGUMENT, OP2 ARGUMENT 5 | MOVnw 6 | MOVnd 7 | MOVbw 8 | MOVww 9 | MOVdw 10 | MOVqw 11 | MOVbd 12 | MOVwd 13 | MOVdd 14 | MOVqd 15 | MOVqq 16 | MOVsnw 17 | MOVsnd 18 | 19 | 6. ✅ INSTRUCTION OP1, OP2 ARGUMENT (16 bit optional index/immediate) 20 | ADD 21 | AND 22 | ASHR 23 | CMP 24 | DIV 25 | DIVU 26 | EXTENDB 27 | EXTENDD 28 | EXTENDW 29 | MOD 30 | MODU 31 | MUL 32 | MULU 33 | NEG 34 | NOT 35 | OR 36 | SHL 37 | SHR 38 | SUB 39 | XOR 40 | 41 | 5. ✅ INSTRUCTION OP1 ARGUMENT, ARGUMENT 42 | CMPI 43 | MOVI 44 | MOVIn 45 | MOVREL 46 | 47 | 4. ✅ INSTRUCTION OP1, OP2 48 | STORESP 49 | LOADSP 50 | 51 | 3. ✅ INSTRUCTION OP1 ARGUMENT 52 | CALL32 53 | JMP32 54 | PUSH 55 | PUSHn 56 | POP 57 | POPn 58 | JMP64 59 | CALL64 60 | 61 | 2. ✅ INSTRUCTION ARGUMENT 62 | JMP8 63 | BREAK 64 | JMP64 65 | CALL64 66 | 67 | 1. ✅ INSTRUCTION 68 | RET 69 | */ 70 | 71 | use arrayvec::ArrayVec; 72 | 73 | use crate::argument::*; 74 | use crate::bits::*; 75 | use crate::opcode::*; 76 | use crate::operand::*; 77 | use crate::options::Options; 78 | use crate::theme::*; 79 | 80 | fn read_value, const WIDTH: usize>(bytes: &mut T) -> Result<[u8; WIDTH], String> 81 | { 82 | let mut value = [0u8; WIDTH]; 83 | 84 | for i in 0 .. value.len() 85 | { 86 | value[i] = bytes.next().ok_or("Unexpected end of byte stream")?; 87 | } 88 | 89 | Ok(value) 90 | } 91 | 92 | pub fn parse_instruction1>( 93 | writer: &mut W, 94 | options: &Options, 95 | _bytes: &mut T, 96 | byte0: u8, 97 | _byte0_bits: [bool; 8], 98 | op: OpCode, 99 | ) -> Result<(), String> 100 | { 101 | let bytecode = [byte0]; 102 | disassemble_instruction(writer, options, &bytecode, op.emit(options), None, None, None, None, None); 103 | 104 | Ok(()) 105 | } 106 | 107 | pub fn parse_instruction2>( 108 | writer: &mut W, 109 | options: &Options, 110 | bytes: &mut T, 111 | byte0: u8, 112 | byte0_bits: [bool; 8], 113 | op: OpCode, 114 | ) -> Result<(), String> 115 | { 116 | let mut name = op.emit(options); 117 | 118 | let byte1 = bytes.next().ok_or("Unexpected end of bytes")?; 119 | 120 | let arg1 = match op 121 | { 122 | OpCode::BREAK => 123 | { 124 | if byte1 == 0 125 | { 126 | let msg = String::from("Runaway program break (found 2 zeros in a row, BREAK 0)"); 127 | 128 | return Err(color_error(msg, options)); 129 | } 130 | 131 | Argument::ImmediateU16(byte1 as u16) 132 | } 133 | 134 | OpCode::JMP8 => 135 | { 136 | let conditional = byte0_bits[7]; 137 | 138 | if conditional 139 | { 140 | let condition_bit_set = byte0_bits[6]; 141 | let postfix = if condition_bit_set 142 | { 143 | color_opcode(String::from("cs"), options) 144 | } 145 | else 146 | { 147 | color_opcode(String::from("cc"), options) 148 | }; 149 | 150 | name += &postfix; 151 | } 152 | 153 | Argument::ImmediateI16((byte1 as i8) as i16) 154 | } 155 | 156 | _ => unreachable!(), 157 | }; 158 | 159 | let bytecode = [byte0, byte1]; 160 | disassemble_instruction(writer, options, &bytecode, name, None, Some(arg1), None, None, None); 161 | 162 | Ok(()) 163 | } 164 | 165 | pub fn parse_instruction3>( 166 | writer: &mut W, 167 | options: &Options, 168 | bytes: &mut T, 169 | byte0: u8, 170 | byte0_bits: [bool; 8], 171 | op: OpCode, 172 | ) -> Result<(), String> 173 | { 174 | let mut name = op.emit(options); 175 | let mut postfix = String::with_capacity(5); 176 | let immediate_data_present = byte0_bits[7]; 177 | let is_64_bit = byte0_bits[6]; // Not used by PUSHn & POPn 178 | 179 | let byte1 = bytes.next().ok_or("Unexpected end of bytes")?; 180 | let byte1_bits = bits_rev(byte1); 181 | 182 | let mut bytecode = ArrayVec::<_, 18>::new(); 183 | bytecode.push(byte0); 184 | bytecode.push(byte1); 185 | 186 | match op 187 | { 188 | OpCode::CALL | OpCode::JMP | OpCode::PUSH | OpCode::POP => 189 | { 190 | let width_postfix = 191 | if is_64_bit { color_x64(String::from("64"), options) } else { color_x32(String::from("32"), options) }; 192 | 193 | postfix += &width_postfix; 194 | } 195 | 196 | _ => (), 197 | } 198 | 199 | let (op1, arg1, op2, arg2, comment) = match op 200 | { 201 | OpCode::CALL => 202 | { 203 | let is_native_call = byte1_bits[5]; 204 | postfix += if is_native_call { "EX" } else { "" }; 205 | 206 | let is_relative_address = byte1_bits[4]; 207 | let operand1_is_indirect = byte1_bits[3]; 208 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]); 209 | let op1 = if !is_64_bit 210 | { 211 | Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect)) 212 | } 213 | else 214 | { 215 | None 216 | }; 217 | 218 | let arg1 = if is_64_bit 219 | { 220 | postfix += "a"; // CALL64 is always an absolute address 221 | 222 | let value = read_value::(bytes)?; 223 | bytecode.extend(value.iter().cloned()); 224 | 225 | Some(Argument::ImmediateI64(i64::from_le_bytes(value))) 226 | } 227 | else 228 | { 229 | postfix += if is_relative_address { "" } else { "a" }; 230 | 231 | let arg = if immediate_data_present 232 | { 233 | let value = read_value::(bytes)?; 234 | 235 | bytecode.extend(value.iter().cloned()); 236 | 237 | if operand1_is_indirect 238 | { 239 | Some(Argument::Index32(u32::from_le_bytes(value))) 240 | } 241 | else 242 | { 243 | Some(Argument::ImmediateI32(i32::from_le_bytes(value))) 244 | } 245 | } 246 | else 247 | { 248 | None 249 | }; 250 | 251 | arg 252 | }; 253 | 254 | (op1, arg1, None, None, None) 255 | } 256 | 257 | OpCode::JMP => 258 | { 259 | let conditional_jump = byte1_bits[7]; 260 | let jump_if_condition_bit_set = byte1_bits[6]; 261 | 262 | if conditional_jump 263 | { 264 | postfix += if jump_if_condition_bit_set { "cs" } else { "cc" }; 265 | } 266 | 267 | let relative_address = byte1_bits[4]; 268 | let operand1_is_indirect = byte1_bits[3]; 269 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]); 270 | let op1 = if !is_64_bit 271 | { 272 | Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect)) 273 | } 274 | else 275 | { 276 | None 277 | }; 278 | 279 | let arg1 = if is_64_bit 280 | { 281 | let value = read_value::(bytes)?; 282 | bytecode.extend(value.iter().cloned()); 283 | 284 | Some(Argument::ImmediateI64(i64::from_le_bytes(value))) 285 | } 286 | else 287 | { 288 | let arg = if immediate_data_present 289 | { 290 | let value = read_value::(bytes)?; 291 | bytecode.extend(value.iter().cloned()); 292 | 293 | if operand1_is_indirect 294 | { 295 | Some(Argument::Index32(u32::from_le_bytes(value))) 296 | } 297 | else 298 | { 299 | Some(Argument::ImmediateI32(i32::from_le_bytes(value))) 300 | } 301 | } 302 | else 303 | { 304 | None 305 | }; 306 | 307 | arg 308 | }; 309 | 310 | let comment = if relative_address 311 | { 312 | Some(String::from("Relative Address")) 313 | } 314 | else 315 | { 316 | Some(String::from("Absolute Address")) 317 | }; 318 | 319 | (op1, arg1, None, None, comment) 320 | } 321 | 322 | OpCode::PUSH | OpCode::POP | OpCode::PUSHn | OpCode::POPn => 323 | { 324 | let operand1_is_indirect = byte1_bits[3]; 325 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]); 326 | let arg1 = if immediate_data_present 327 | { 328 | let value = read_value::(bytes)?; 329 | bytecode.extend(value.iter().cloned()); 330 | 331 | let arg = if operand1_is_indirect 332 | { 333 | Argument::Index16(u16::from_le_bytes(value)) 334 | } 335 | else 336 | { 337 | Argument::ImmediateI16(i16::from_le_bytes(value)) 338 | }; 339 | 340 | Some(arg) 341 | } 342 | else 343 | { 344 | None 345 | }; 346 | 347 | (Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect)), arg1, None, None, None) 348 | } 349 | 350 | _ => unreachable!(), 351 | }; 352 | 353 | name += &postfix; 354 | 355 | disassemble_instruction(writer, options, &bytecode, name, op1, arg1, op2, arg2, comment); 356 | 357 | Ok(()) 358 | } 359 | 360 | pub fn parse_instruction4>( 361 | writer: &mut W, 362 | options: &Options, 363 | bytes: &mut T, 364 | byte0: u8, 365 | _byte0_bits: [bool; 8], 366 | op: OpCode, 367 | ) -> Result<(), String> 368 | { 369 | let name = op.emit(options); 370 | 371 | let byte1 = bytes.next().ok_or("Unexpected end of bytes")?; 372 | let byte1_bits = bits_rev(byte1); 373 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]); 374 | let operand2_value = bits_to_byte_rev(&byte1_bits[4 ..= 6]); 375 | 376 | let mut bytecode = ArrayVec::<_, 18>::new(); 377 | bytecode.push(byte0); 378 | bytecode.push(byte1); 379 | 380 | let (op1, op2) = match op 381 | { 382 | OpCode::STORESP => 383 | { 384 | (Operand::new_general_purpose(operand1_value, false), Operand::new_dedicated(operand2_value, false)) 385 | } 386 | 387 | OpCode::LOADSP => 388 | { 389 | (Operand::new_dedicated(operand1_value, false), Operand::new_general_purpose(operand2_value, false)) 390 | } 391 | 392 | _ => unreachable!(), 393 | }; 394 | 395 | disassemble_instruction(writer, options, &bytecode, name, Some(op1), None, Some(op2), None, None); 396 | 397 | Ok(()) 398 | } 399 | 400 | pub fn parse_instruction5>( 401 | writer: &mut W, 402 | options: &Options, 403 | bytes: &mut T, 404 | byte0: u8, 405 | byte0_bits: [bool; 8], 406 | op: OpCode, 407 | ) -> Result<(), String> 408 | { 409 | let mut name = op.emit(options); 410 | let mut postfixes = String::with_capacity(7); 411 | let byte1 = bytes.next().ok_or("Unexpected end of byte stream")?; 412 | let byte1_bits = bits_rev(byte1); 413 | 414 | let mut bytecode = ArrayVec::<_, 18>::new(); 415 | bytecode.push(byte0); 416 | bytecode.push(byte1); 417 | 418 | let (op1, arg1, arg2) = match op 419 | { 420 | OpCode::MOVI => 421 | { 422 | let move_width = bits_to_byte_rev(&byte1_bits[4 ..= 5]); 423 | let postfix = match move_width 424 | { 425 | 0 => color_x8(String::from("b"), options), 426 | 1 => color_x16(String::from("w"), options), 427 | 2 => color_x32(String::from("d"), options), 428 | 3 => color_x64(String::from("q"), options), 429 | _ => unreachable!(), 430 | }; 431 | 432 | postfixes += &postfix; 433 | 434 | let immediate_data_width = bits_to_byte_rev(&byte0_bits[6 ..= 7]); 435 | let postfix = match immediate_data_width 436 | { 437 | 1 => color_x16(String::from("w"), options), 438 | 2 => color_x32(String::from("d"), options), 439 | 3 => color_x64(String::from("q"), options), 440 | _ => unreachable!(), 441 | }; 442 | 443 | postfixes += &postfix; 444 | 445 | let operand1_index_present = byte1_bits[6]; 446 | let operand1_is_indirect = byte1_bits[3]; 447 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]); 448 | 449 | let op1 = Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect)); 450 | 451 | let arg1 = if operand1_index_present 452 | { 453 | let value = read_value::(bytes)?; 454 | bytecode.extend(value.iter().cloned()); 455 | 456 | let arg = if operand1_is_indirect 457 | { 458 | Argument::Index16(u16::from_le_bytes(value)) 459 | } 460 | else 461 | { 462 | let msg = format!("Immediate data not supported for {}", op.emit(options)); 463 | 464 | return Err(color_error(msg, options)); 465 | }; 466 | 467 | Some(arg) 468 | } 469 | else 470 | { 471 | None 472 | }; 473 | 474 | let arg2 = { 475 | match immediate_data_width 476 | { 477 | 1 => 478 | // 16 bit 479 | { 480 | let value = read_value::(bytes)?; 481 | bytecode.extend(value.iter().cloned()); 482 | 483 | Some(Argument::ImmediateI16(i16::from_le_bytes(value))) 484 | } 485 | 486 | 2 => 487 | // 32 bit 488 | { 489 | let value = read_value::(bytes)?; 490 | bytecode.extend(value.iter().cloned()); 491 | 492 | Some(Argument::ImmediateI32(i32::from_le_bytes(value))) 493 | } 494 | 495 | 3 => 496 | // 64 bit 497 | { 498 | let value = read_value::(bytes)?; 499 | bytecode.extend(value.iter().cloned()); 500 | 501 | Some(Argument::ImmediateI64(i64::from_le_bytes(value))) 502 | } 503 | 504 | _ => unreachable!(), 505 | } 506 | }; 507 | 508 | name += &postfixes; 509 | 510 | (op1, arg1, arg2) 511 | } 512 | 513 | OpCode::CMPIeq | OpCode::CMPIlte | OpCode::CMPIgte | OpCode::CMPIulte | OpCode::CMPIugte => 514 | { 515 | let immediate_data_is_32_bit = byte0_bits[7]; 516 | let comparison_is_64_bit = byte0_bits[6]; 517 | 518 | // Have to obliterate name due to the reordering below: 519 | name = color_opcode(String::from("CMPI"), options); 520 | 521 | let postfix = if comparison_is_64_bit 522 | { 523 | color_x64(String::from("64"), options) 524 | } 525 | else 526 | { 527 | color_x32(String::from("32"), options) 528 | }; 529 | 530 | name += &postfix; 531 | 532 | let postfix = if immediate_data_is_32_bit 533 | { 534 | color_x32(String::from("d"), options) 535 | } 536 | else 537 | { 538 | color_x16(String::from("w"), options) 539 | }; 540 | 541 | name += &postfix; 542 | 543 | let postfix = match op 544 | { 545 | OpCode::CMPIeq => color_opcode(String::from("eq"), options), 546 | OpCode::CMPIlte => color_opcode(String::from("lte"), options), 547 | OpCode::CMPIgte => color_opcode(String::from("gte"), options), 548 | OpCode::CMPIulte => color_opcode(String::from("ulte"), options), 549 | 550 | OpCode::CMPIugte => color_opcode(String::from("ugte"), options), 551 | 552 | _ => unreachable!(), 553 | }; 554 | 555 | name += &postfix; 556 | 557 | let operand1_index_present = byte1_bits[4]; 558 | let operand1_is_indirect = byte1_bits[3]; 559 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]); 560 | 561 | let op1 = Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect)); 562 | 563 | let arg1 = if operand1_index_present 564 | { 565 | let value = read_value::(bytes)?; 566 | bytecode.extend(value.iter().cloned()); 567 | 568 | let arg = if operand1_is_indirect 569 | { 570 | Argument::Index16(u16::from_le_bytes(value)) 571 | } 572 | else 573 | { 574 | let msg = format!("Immediate data not supported for {}", op.emit(options)); 575 | 576 | return Err(color_error(msg, options)); 577 | }; 578 | 579 | Some(arg) 580 | } 581 | else 582 | { 583 | None 584 | }; 585 | 586 | let arg2 = { 587 | if immediate_data_is_32_bit 588 | { 589 | let value = read_value::(bytes)?; 590 | bytecode.extend(value.iter().cloned()); 591 | 592 | match op 593 | { 594 | OpCode::CMPIulte | OpCode::CMPIugte => Some(Argument::ImmediateU32(u32::from_le_bytes(value))), 595 | 596 | _ => Some(Argument::ImmediateI32(i32::from_le_bytes(value))), 597 | } 598 | } 599 | else 600 | { 601 | let value = read_value::(bytes)?; 602 | bytecode.extend(value.iter().cloned()); 603 | 604 | match op 605 | { 606 | OpCode::CMPIulte | OpCode::CMPIugte => Some(Argument::ImmediateU16(u16::from_le_bytes(value))), 607 | 608 | _ => Some(Argument::ImmediateI16(i16::from_le_bytes(value))), 609 | } 610 | } 611 | }; 612 | 613 | (op1, arg1, arg2) 614 | } 615 | 616 | OpCode::MOVIn => 617 | { 618 | let operand2_index_width = bits_to_byte_rev(&byte0_bits[6 ..= 7]); 619 | let postfix = match operand2_index_width 620 | { 621 | 1 => color_x16(String::from("w"), options), 622 | 2 => color_x32(String::from("d"), options), 623 | 3 => color_x64(String::from("q"), options), 624 | _ => unreachable!(), 625 | }; 626 | 627 | postfixes += &postfix; 628 | 629 | let operand1_index_present = byte1_bits[6]; 630 | let operand1_is_indirect = byte1_bits[3]; 631 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]); 632 | 633 | let op1 = Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect)); 634 | 635 | let arg1 = if operand1_index_present 636 | { 637 | let value = read_value::(bytes)?; 638 | bytecode.extend(value.iter().cloned()); 639 | 640 | let arg = if operand1_is_indirect 641 | { 642 | Argument::Index16(u16::from_le_bytes(value)) 643 | } 644 | else 645 | { 646 | let msg = format!("Immediate data not supported for {}", op.emit(options)); 647 | 648 | return Err(color_error(msg, options)); 649 | }; 650 | 651 | Some(arg) 652 | } 653 | else 654 | { 655 | None 656 | }; 657 | 658 | let arg2 = { 659 | match operand2_index_width 660 | { 661 | 1 => 662 | // 16 bit 663 | { 664 | let value = read_value::(bytes)?; 665 | bytecode.extend(value.iter().cloned()); 666 | 667 | Some(Argument::Index16(u16::from_le_bytes(value))) 668 | } 669 | 670 | 2 => 671 | // 32 bit 672 | { 673 | let value = read_value::(bytes)?; 674 | bytecode.extend(value.iter().cloned()); 675 | 676 | Some(Argument::Index32(u32::from_le_bytes(value))) 677 | } 678 | 679 | 3 => 680 | // 64 bit 681 | { 682 | let value = read_value::(bytes)?; 683 | bytecode.extend(value.iter().cloned()); 684 | 685 | Some(Argument::Index64(u64::from_le_bytes(value))) 686 | } 687 | 688 | _ => unreachable!(), 689 | } 690 | }; 691 | 692 | name += &postfixes; 693 | 694 | (op1, arg1, arg2) 695 | } 696 | 697 | OpCode::MOVREL => 698 | { 699 | let immediate_data_width = bits_to_byte_rev(&byte0_bits[6 ..= 7]); 700 | let postfix = match immediate_data_width 701 | { 702 | 1 => color_x16(String::from("w"), options), 703 | 2 => color_x32(String::from("d"), options), 704 | 3 => color_x64(String::from("q"), options), 705 | _ => unreachable!(), 706 | }; 707 | 708 | postfixes += &postfix; 709 | 710 | let operand1_index_present = byte1_bits[6]; 711 | let operand1_is_indirect = byte1_bits[3]; 712 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]); 713 | 714 | let op1 = Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect)); 715 | 716 | let arg1 = if operand1_index_present 717 | { 718 | let value = read_value::(bytes)?; 719 | bytecode.extend(value.iter().cloned()); 720 | 721 | let arg = if operand1_is_indirect 722 | { 723 | Argument::Index16(u16::from_le_bytes(value)) 724 | } 725 | else 726 | { 727 | let msg = format!("Immediate data not supported for {}", op.emit(options)); 728 | 729 | return Err(color_error(msg, options)); 730 | }; 731 | 732 | Some(arg) 733 | } 734 | else 735 | { 736 | None 737 | }; 738 | 739 | let arg2 = { 740 | match immediate_data_width 741 | { 742 | 1 => 743 | // 16 bit 744 | { 745 | let value = read_value::(bytes)?; 746 | bytecode.extend(value.iter().cloned()); 747 | 748 | Some(Argument::ImmediateI16(i16::from_le_bytes(value))) 749 | } 750 | 751 | 2 => 752 | // 32 bit 753 | { 754 | let value = read_value::(bytes)?; 755 | bytecode.extend(value.iter().cloned()); 756 | 757 | Some(Argument::ImmediateI32(i32::from_le_bytes(value))) 758 | } 759 | 760 | 3 => 761 | // 64 bit 762 | { 763 | let value = read_value::(bytes)?; 764 | bytecode.extend(value.iter().cloned()); 765 | 766 | Some(Argument::ImmediateI64(i64::from_le_bytes(value))) 767 | } 768 | 769 | _ => unreachable!(), 770 | } 771 | }; 772 | 773 | name += &postfixes; 774 | 775 | (op1, arg1, arg2) 776 | } 777 | 778 | _ => unreachable!(), 779 | }; 780 | 781 | disassemble_instruction(writer, options, &bytecode, name, op1, arg1, None, arg2, None); 782 | 783 | Ok(()) 784 | } 785 | 786 | pub fn parse_instruction6>( 787 | writer: &mut W, 788 | options: &Options, 789 | bytes: &mut T, 790 | byte0: u8, 791 | byte0_bits: [bool; 8], 792 | op: OpCode, 793 | ) -> Result<(), String> 794 | { 795 | let mut name = op.emit(options); 796 | let immediate_data_present = byte0_bits[7]; 797 | let is_64_bit = byte0_bits[6]; 798 | let postfix = 799 | if is_64_bit { color_x64(String::from("64"), options) } else { color_x32(String::from("32"), options) }; 800 | 801 | name += &postfix; 802 | 803 | let byte1 = bytes.next().ok_or("Unexpected end of bytes")?; 804 | let byte1_bits = bits_rev(byte1); 805 | let operand1_is_indirect = byte1_bits[3]; 806 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]); 807 | let operand2_is_indirect = byte1_bits[7]; 808 | let operand2_value = bits_to_byte_rev(&byte1_bits[4 ..= 6]); 809 | 810 | let mut bytecode = ArrayVec::<_, 18>::new(); 811 | bytecode.push(byte0); 812 | bytecode.push(byte1); 813 | 814 | let op1_x16_index_or_immediate = { 815 | if immediate_data_present 816 | { 817 | let value = read_value::(bytes)?; 818 | bytecode.extend(value.iter().cloned()); 819 | 820 | let arg = if operand2_is_indirect 821 | { 822 | Argument::Index16(u16::from_le_bytes(value)) 823 | } 824 | else 825 | { 826 | Argument::ImmediateI16(i16::from_le_bytes(value)) 827 | }; 828 | 829 | Some(arg) 830 | } 831 | else 832 | { 833 | None 834 | } 835 | }; 836 | 837 | disassemble_instruction( 838 | writer, 839 | options, 840 | &bytecode, 841 | name, 842 | Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect)), 843 | None, 844 | Some(Operand::new_general_purpose(operand2_value, operand2_is_indirect)), 845 | op1_x16_index_or_immediate, 846 | None, 847 | ); 848 | 849 | Ok(()) 850 | } 851 | 852 | pub fn parse_instruction7>( 853 | writer: &mut W, 854 | options: &Options, 855 | bytes: &mut T, 856 | byte0: u8, 857 | byte0_bits: [bool; 8], 858 | op: OpCode, 859 | ) -> Result<(), String> 860 | { 861 | let operand1_index_present = byte0_bits[7]; 862 | let operand2_index_present = byte0_bits[6]; 863 | 864 | let byte1 = bytes.next().ok_or("Unexpected end of bytes")?; 865 | let byte1_bits = bits_rev(byte1); 866 | let operand1_is_indirect = byte1_bits[3]; 867 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]); 868 | let operand2_is_indirect = byte1_bits[7]; 869 | let operand2_value = bits_to_byte_rev(&byte1_bits[4 ..= 6]); 870 | 871 | let mut bytecode = ArrayVec::<_, 18>::new(); 872 | bytecode.push(byte0); 873 | bytecode.push(byte1); 874 | 875 | let op1 = Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect)); 876 | 877 | let op2 = Some(Operand::new_general_purpose(operand2_value, operand2_is_indirect)); 878 | 879 | let (arg1, arg2) = match op 880 | { 881 | OpCode::MOVsnw | OpCode::MOVsnd => 882 | { 883 | let arg1 = { 884 | if operand1_index_present 885 | { 886 | let arg = match op 887 | { 888 | OpCode::MOVsnw => 889 | // 16 bit 890 | { 891 | let value = read_value::(bytes)?; 892 | bytecode.extend(value.iter().cloned()); 893 | 894 | Argument::Index16(u16::from_le_bytes(value)) 895 | } 896 | 897 | OpCode::MOVsnd => 898 | // 32 bit 899 | { 900 | let value = read_value::(bytes)?; 901 | bytecode.extend(value.iter().cloned()); 902 | 903 | Argument::Index32(u32::from_le_bytes(value)) 904 | } 905 | 906 | _ => unreachable!(), 907 | }; 908 | 909 | Some(arg) 910 | } 911 | else 912 | { 913 | None 914 | } 915 | }; 916 | 917 | let arg2 = { 918 | if operand2_index_present 919 | { 920 | let arg = match op 921 | { 922 | OpCode::MOVsnw => 923 | // 16 bit 924 | { 925 | let value = read_value::(bytes)?; 926 | bytecode.extend(value.iter().cloned()); 927 | 928 | if operand2_is_indirect 929 | { 930 | Argument::Index16(u16::from_le_bytes(value)) 931 | } 932 | else 933 | { 934 | Argument::ImmediateI16(i16::from_le_bytes(value)) 935 | } 936 | } 937 | 938 | OpCode::MOVsnd => 939 | // 32 bit 940 | { 941 | let value = read_value::(bytes)?; 942 | bytecode.extend(value.iter().cloned()); 943 | 944 | if operand2_is_indirect 945 | { 946 | Argument::Index32(u32::from_le_bytes(value)) 947 | } 948 | else 949 | { 950 | Argument::ImmediateI32(i32::from_le_bytes(value)) 951 | } 952 | } 953 | 954 | _ => unreachable!(), 955 | }; 956 | 957 | Some(arg) 958 | } 959 | else 960 | { 961 | None 962 | } 963 | }; 964 | 965 | (arg1, arg2) 966 | } 967 | 968 | // Try to combine this with MOVsnw and MOVsnd 969 | OpCode::MOVnw | OpCode::MOVnd => 970 | { 971 | let arg1 = { 972 | if operand1_index_present 973 | { 974 | let arg = match op 975 | { 976 | OpCode::MOVnw => 977 | // 16 bit 978 | { 979 | let value = read_value::(bytes)?; 980 | bytecode.extend(value.iter().cloned()); 981 | 982 | Argument::Index16(u16::from_le_bytes(value)) 983 | } 984 | 985 | OpCode::MOVnd => 986 | // 32 bit 987 | { 988 | let value = read_value::(bytes)?; 989 | bytecode.extend(value.iter().cloned()); 990 | 991 | Argument::Index32(u32::from_le_bytes(value)) 992 | } 993 | 994 | _ => unreachable!(), 995 | }; 996 | 997 | Some(arg) 998 | } 999 | else 1000 | { 1001 | None 1002 | } 1003 | }; 1004 | 1005 | let arg2 = { 1006 | if operand2_index_present 1007 | { 1008 | let arg = match op 1009 | { 1010 | OpCode::MOVnw => 1011 | // 16 bit 1012 | { 1013 | let value = read_value::(bytes)?; 1014 | bytecode.extend(value.iter().cloned()); 1015 | 1016 | if operand2_is_indirect 1017 | { 1018 | Argument::Index16(u16::from_le_bytes(value)) 1019 | } 1020 | else 1021 | { 1022 | Argument::ImmediateI16(i16::from_le_bytes(value)) 1023 | } 1024 | } 1025 | 1026 | OpCode::MOVnd => 1027 | // 32 bit 1028 | { 1029 | let value = read_value::(bytes)?; 1030 | bytecode.extend(value.iter().cloned()); 1031 | 1032 | if operand2_is_indirect 1033 | { 1034 | Argument::Index32(u32::from_le_bytes(value)) 1035 | } 1036 | else 1037 | { 1038 | Argument::ImmediateI32(i32::from_le_bytes(value)) 1039 | } 1040 | } 1041 | 1042 | _ => unreachable!(), 1043 | }; 1044 | 1045 | Some(arg) 1046 | } 1047 | else 1048 | { 1049 | None 1050 | } 1051 | }; 1052 | 1053 | (arg1, arg2) 1054 | } 1055 | 1056 | _ => 1057 | // MOV 1058 | { 1059 | let arg1 = { 1060 | if operand1_index_present 1061 | { 1062 | let arg = match op 1063 | { 1064 | OpCode::MOVbw | OpCode::MOVww | OpCode::MOVdw | OpCode::MOVqw => 1065 | // 16 bit 1066 | { 1067 | let value = read_value::(bytes)?; 1068 | bytecode.extend(value.iter().cloned()); 1069 | 1070 | Argument::Index16(u16::from_le_bytes(value)) 1071 | } 1072 | 1073 | OpCode::MOVbd | OpCode::MOVwd | OpCode::MOVdd | OpCode::MOVqd => 1074 | // 32 bit 1075 | { 1076 | let value = read_value::(bytes)?; 1077 | bytecode.extend(value.iter().cloned()); 1078 | 1079 | Argument::Index32(u32::from_le_bytes(value)) 1080 | } 1081 | 1082 | OpCode::MOVqq => 1083 | // 64 bit 1084 | { 1085 | let value = read_value::(bytes)?; 1086 | bytecode.extend(value.iter().cloned()); 1087 | 1088 | Argument::Index64(u64::from_le_bytes(value)) 1089 | } 1090 | 1091 | _ => unreachable!(), 1092 | }; 1093 | 1094 | Some(arg) 1095 | } 1096 | else 1097 | { 1098 | None 1099 | } 1100 | }; 1101 | 1102 | let arg2 = { 1103 | if operand2_index_present 1104 | { 1105 | let arg = match op 1106 | { 1107 | OpCode::MOVbw | OpCode::MOVww | OpCode::MOVdw | OpCode::MOVqw => 1108 | // 16 bit 1109 | { 1110 | let value = read_value::(bytes)?; 1111 | bytecode.extend(value.iter().cloned()); 1112 | 1113 | Argument::Index16(u16::from_le_bytes(value)) 1114 | } 1115 | 1116 | OpCode::MOVbd | OpCode::MOVwd | OpCode::MOVdd | OpCode::MOVqd => 1117 | // 32 bit 1118 | { 1119 | let value = read_value::(bytes)?; 1120 | bytecode.extend(value.iter().cloned()); 1121 | 1122 | Argument::Index32(u32::from_le_bytes(value)) 1123 | } 1124 | 1125 | OpCode::MOVqq => 1126 | // 64 bit 1127 | { 1128 | let value = read_value::(bytes)?; 1129 | bytecode.extend(value.iter().cloned()); 1130 | 1131 | Argument::Index64(u64::from_le_bytes(value)) 1132 | } 1133 | 1134 | _ => unreachable!(), 1135 | }; 1136 | 1137 | Some(arg) 1138 | } 1139 | else 1140 | { 1141 | None 1142 | } 1143 | }; 1144 | 1145 | (arg1, arg2) 1146 | } 1147 | }; 1148 | 1149 | let mut name = format!("{:?}", op); 1150 | let mut chars = name.chars(); 1151 | let indices_present = operand1_index_present || operand2_index_present; 1152 | 1153 | let postfix = match op 1154 | { 1155 | OpCode::MOVnw | OpCode::MOVsnw => 1156 | { 1157 | // If indices are present, keep them 1158 | let move_width = if indices_present 1159 | { 1160 | String::from(chars.next_back().unwrap()) 1161 | } 1162 | else 1163 | // Remove it to get to the guaranteed move width 1164 | { 1165 | chars.next_back().unwrap(); 1166 | String::from("") 1167 | }; 1168 | 1169 | // COLOR IT 1170 | color_x16(move_width, options) 1171 | } 1172 | 1173 | OpCode::MOVnd | OpCode::MOVsnd => 1174 | { 1175 | // If indices are present, keep them 1176 | let move_width = if indices_present 1177 | { 1178 | String::from(chars.next_back().unwrap()) 1179 | } 1180 | else 1181 | // Remove it to get to the guaranteed move width 1182 | { 1183 | chars.next_back().unwrap(); 1184 | String::from("") 1185 | }; 1186 | 1187 | // COLOR IT 1188 | 1189 | color_x32(move_width, options) 1190 | } 1191 | 1192 | OpCode::MOVbw 1193 | | OpCode::MOVww 1194 | | OpCode::MOVdw 1195 | | OpCode::MOVqw 1196 | | OpCode::MOVbd 1197 | | OpCode::MOVwd 1198 | | OpCode::MOVdd 1199 | | OpCode::MOVqd 1200 | | OpCode::MOVqq => 1201 | { 1202 | // If indices are present, keep them 1203 | let index_width = if indices_present 1204 | { 1205 | let width = String::from(chars.next_back().unwrap()); 1206 | 1207 | match op 1208 | { 1209 | OpCode::MOVbw | OpCode::MOVww | OpCode::MOVdw | OpCode::MOVqw => color_x16(width, options), 1210 | 1211 | OpCode::MOVbd | OpCode::MOVwd | OpCode::MOVdd | OpCode::MOVqd => color_x32(width, options), 1212 | 1213 | OpCode::MOVqq => color_x64(width, options), 1214 | 1215 | _ => unreachable!(), 1216 | } 1217 | } 1218 | else 1219 | // Remove it to get to the guaranteed move width 1220 | { 1221 | chars.next_back().unwrap(); 1222 | String::from("") 1223 | }; 1224 | 1225 | let move_width = String::from(chars.next_back().unwrap()); 1226 | let move_width = match op 1227 | { 1228 | OpCode::MOVbw | OpCode::MOVbd => color_x8(move_width, options), 1229 | 1230 | OpCode::MOVww | OpCode::MOVwd => color_x16(move_width, options), 1231 | 1232 | OpCode::MOVdw | OpCode::MOVdd => color_x32(move_width, options), 1233 | 1234 | OpCode::MOVqw | OpCode::MOVqd | OpCode::MOVqq => color_x64(move_width, options), 1235 | 1236 | _ => unreachable!(), 1237 | }; 1238 | 1239 | move_width + &index_width 1240 | } 1241 | 1242 | _ => unreachable!(), 1243 | }; 1244 | 1245 | let postfixes_removed = chars.as_str().to_string(); 1246 | name = color_opcode(postfixes_removed, options); 1247 | name += &postfix; 1248 | 1249 | disassemble_instruction(writer, options, &bytecode, name, op1, arg1, op2, arg2, None); 1250 | 1251 | Ok(()) 1252 | } 1253 | 1254 | pub fn disassemble_instruction( 1255 | writer: &mut W, 1256 | options: &Options, 1257 | bytecode: &[u8], 1258 | instruction: String, // Must concatenate postfixes manually 1259 | operand1: Option, 1260 | argument1: Option, 1261 | operand2: Option, 1262 | argument2: Option, 1263 | comment: Option, 1264 | ) 1265 | { 1266 | if options.bytecode 1267 | { 1268 | const TWO_CHARS_AND_A_SPACE: usize = 3; 1269 | let mut bytecode_output = String::with_capacity(bytecode.len() * TWO_CHARS_AND_A_SPACE); 1270 | 1271 | for byte in bytecode.iter() 1272 | { 1273 | bytecode_output += format!("{:<02X?} ", byte).as_str(); 1274 | } 1275 | 1276 | bytecode_output = color_bytecode(bytecode_output, options); 1277 | 1278 | write!(writer, "{:>84} ", bytecode_output).unwrap(); 1279 | } 1280 | 1281 | if options.pad_output 1282 | { 1283 | write!(writer, "{}", instruction).unwrap(); 1284 | } 1285 | else 1286 | { 1287 | write!(writer, "{}", instruction).unwrap(); 1288 | } 1289 | 1290 | if let Some(op1) = operand1 1291 | { 1292 | write!(writer, " {}", op1.emit(options)).unwrap(); 1293 | } 1294 | 1295 | if let Some(arg1) = argument1 1296 | { 1297 | let text = arg1.emit(options); 1298 | 1299 | match arg1 1300 | { 1301 | Argument::Index16(_index) => write!(writer, "{}", text).unwrap(), 1302 | Argument::Index32(_index) => write!(writer, "{}", text).unwrap(), 1303 | Argument::Index64(_index) => write!(writer, "{}", text).unwrap(), 1304 | _ => write!(writer, " {}", text).unwrap(), 1305 | } 1306 | } 1307 | 1308 | if operand2.is_some() || argument2.is_some() 1309 | { 1310 | write!(writer, ",").unwrap(); 1311 | } 1312 | 1313 | if let Some(ref op2) = operand2 1314 | { 1315 | write!(writer, " {}", op2.emit(options)).unwrap(); 1316 | } 1317 | 1318 | if let Some(arg2) = argument2 1319 | { 1320 | match arg2 1321 | { 1322 | Argument::Index16(_index) => 1323 | { 1324 | if operand2.is_none() 1325 | { 1326 | write!(writer, " ").unwrap(); 1327 | } 1328 | write!(writer, "{}", arg2.emit(options)).unwrap(); 1329 | } 1330 | 1331 | Argument::Index32(_index) => 1332 | { 1333 | if operand2.is_none() 1334 | { 1335 | write!(writer, " ").unwrap(); 1336 | } 1337 | write!(writer, "{}", arg2.emit(options)).unwrap(); 1338 | } 1339 | 1340 | Argument::Index64(_index) => 1341 | { 1342 | if operand2.is_none() 1343 | { 1344 | write!(writer, " ").unwrap(); 1345 | } 1346 | write!(writer, "{}", arg2.emit(options)).unwrap(); 1347 | } 1348 | 1349 | _ => write!(writer, " {}", arg2.emit(options)).unwrap(), 1350 | } 1351 | } 1352 | 1353 | if let Some(line_comment) = comment 1354 | { 1355 | let the_comment = color_comment(format!(" ;; {}", line_comment), options); 1356 | 1357 | write!(writer, "{}", the_comment).unwrap(); 1358 | } 1359 | 1360 | writeln!(writer, "").unwrap(); 1361 | } 1362 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod argument; 2 | mod bits; 3 | mod instruction; 4 | mod natural_index; 5 | mod opcode; 6 | mod operand; 7 | mod options; 8 | mod theme; 9 | 10 | #[cfg(test)] 11 | mod tests; // Integration tests 12 | 13 | use pelite::pe64::{Pe, PeFile}; 14 | use pelite::FileMap; 15 | 16 | use crate::opcode::OpCode; 17 | use crate::options::Options; 18 | use crate::theme::*; 19 | 20 | const CODE_SECTION: u32 = pelite::image::IMAGE_SCN_CNT_CODE; 21 | const HELP: &'static str = include_str!("CLI.txt"); 22 | 23 | /// Reads in an EFI Bytecode filename from STDIN and prints the disassembly. 24 | fn main() 25 | { 26 | let mut args = std::env::args().skip(1).collect::>(); 27 | 28 | if args.len() == 0 29 | { 30 | return println!("{}", HELP); 31 | } 32 | 33 | let filename = args.pop().unwrap(); 34 | 35 | if args.len() % 2 != 0 36 | { 37 | return println!("{}", HELP); 38 | } 39 | 40 | let mut options = Options { theme: Some(SPORE), bytecode: true, pe: true, pad_output: true }; 41 | 42 | for i in (0 .. args.len()).step_by(2) 43 | { 44 | let option = args[i].clone(); 45 | let value = args[i + 1].clone(); 46 | 47 | match option.as_str() 48 | { 49 | "theme:" => 50 | { 51 | if !"SPORE INDUSTRIAL_COMPUTER MATTERHORN_ZERMATT_VILLAGE OFF".contains(&value) 52 | { 53 | println!("{}", color_error(format!("Unknown theme: {}", value), &options),); 54 | return println!("{}", HELP); 55 | } 56 | 57 | options.theme = match value.as_str() 58 | { 59 | "SPORE" => Some(SPORE), 60 | "INDUSTRIAL_COMPUTER" => Some(INDUSTRIAL_COMPUTER), 61 | "MATTERHORN_ZERMATT_VILLAGE" => Some(MATTERHORN_ZERMATT_VILLAGE), 62 | "OFF" => None, 63 | 64 | _ => unreachable!(), 65 | }; 66 | } 67 | 68 | "bytecode:" => 69 | { 70 | if value != "ON".to_string() && value != "OFF".to_string() 71 | { 72 | return println!("{}", color_error(format!("Invalid bytecode setting: {}", value), &options),); 73 | } 74 | 75 | options.bytecode = value == "ON"; 76 | } 77 | 78 | "pe:" => 79 | { 80 | if value != "ON".to_string() && value != "OFF".to_string() 81 | { 82 | return println!("{}", color_error(format!("Invalid pe setting: {}", value), &options),); 83 | } 84 | 85 | options.pe = value == "ON"; 86 | } 87 | 88 | _ => 89 | { 90 | return println!("{}", color_error(format!("Invalid setting: {}", option), &options),); 91 | } 92 | } 93 | } 94 | 95 | match FileMap::open(filename.as_str()) 96 | { 97 | Ok(file_bytes) => 98 | { 99 | let byte_slice = if options.pe 100 | { 101 | let file = PeFile::from_bytes(&file_bytes); 102 | 103 | if let Err(msg) = file 104 | { 105 | let err_msg = format!( 106 | "Failed to open PE executable: {}\n{}", 107 | msg, 108 | ["Are you trying to load a binary file as a PE ", "executable (try pe: OFF)?"].join("") 109 | ); 110 | 111 | return println!("{}", color_error(err_msg, &options)); 112 | } 113 | 114 | let file = file.unwrap(); 115 | let mut bytecode_section = None; 116 | 117 | // Find the section header for code 118 | for section_header in file.section_headers() 119 | { 120 | if section_header.Characteristics & CODE_SECTION != 0 121 | { 122 | bytecode_section = Some(file.get_section_bytes(section_header).unwrap()); 123 | 124 | break; 125 | } 126 | } 127 | 128 | match bytecode_section 129 | { 130 | Some(bytecode) => bytecode, 131 | None => 132 | { 133 | return println!("{}", color_error("PE file is missing code section".to_string(), &options)); 134 | } 135 | } 136 | } 137 | else 138 | { 139 | file_bytes.as_ref() 140 | }; 141 | 142 | let mut bytes = byte_slice.iter().cloned().peekable(); 143 | 144 | loop 145 | { 146 | let result = OpCode::disassemble(&options, &mut std::io::stdout(), &mut bytes); 147 | 148 | match result 149 | { 150 | Ok(_) => (), 151 | 152 | Err(msg) => 153 | { 154 | println!("{}", msg); 155 | break; 156 | } 157 | } 158 | } 159 | } 160 | 161 | Err(msg) => 162 | { 163 | return println!("{}", color_error(format!("Error opening file: {}", msg), &options)); 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/natural_index.rs: -------------------------------------------------------------------------------- 1 | use crate::bits::*; 2 | use crate::options::Options; 3 | use crate::theme::*; 4 | 5 | const SIZE_OF_VOID_PTR: u16 = 8; 6 | const HEADER_SIZE: usize = 4; 7 | 8 | pub struct NaturalIndex 9 | { 10 | pub value: u64, 11 | pub sign: i8, 12 | pub constant: u64, 13 | pub natural: u64, 14 | pub offset: i64, 15 | } 16 | 17 | impl NaturalIndex 18 | { 19 | /// It is critical that the right method be selected per index size. 20 | /// Do not use `from_u64()` for a 16 bit value. 21 | pub fn from_u16(value: u16) -> Self 22 | { 23 | const ENCODING_SIZE: u16 = 2; 24 | 25 | let bits = bits_u16(value); 26 | let sign = if bits[0] { -1i64 } else { 1i64 }; 27 | let width_base = bits_to_byte_u16(&bits[1 .. 4]); 28 | let actual_width = width_base * ENCODING_SIZE; 29 | let natural = bits_to_byte_u16(&bits[bits.len() - actual_width as usize ..]); 30 | let constant = bits_to_byte_u16(&bits[HEADER_SIZE .. bits.len() - actual_width as usize]); 31 | let offset = sign * (constant + natural * SIZE_OF_VOID_PTR) as i64; 32 | 33 | Self { 34 | value: value as u64, 35 | sign: sign as i8, 36 | constant: constant as u64, 37 | natural: natural as u64, 38 | offset: offset as i64, 39 | } 40 | } 41 | 42 | /// It is critical that the right method be selected per index size. 43 | /// Do not use `from_u64()` for a 16 bit value. 44 | pub fn from_u32(value: u32) -> Self 45 | { 46 | const ENCODING_SIZE: u32 = 4; 47 | 48 | let bits = bits_u32(value); 49 | let sign = if bits[0] { -1i64 } else { 1i64 }; 50 | let width_base = bits_to_byte_u32(&bits[1 .. 4]); 51 | let actual_width = width_base * ENCODING_SIZE; 52 | let natural = bits_to_byte_u32(&bits[bits.len() - actual_width as usize ..]); 53 | let constant = bits_to_byte_u32(&bits[HEADER_SIZE .. bits.len() - actual_width as usize]); 54 | let offset = { sign * (constant + natural * SIZE_OF_VOID_PTR as u32) as i64 }; 55 | 56 | Self { 57 | value: value as u64, 58 | sign: sign as i8, 59 | constant: constant as u64, 60 | natural: natural as u64, 61 | offset: offset as i64, 62 | } 63 | } 64 | 65 | /// It is critical that the right method be selected per index size. 66 | /// Do not use `from_u64()` for a 16 bit value. 67 | pub fn from_u64(value: u64) -> Self 68 | { 69 | const ENCODING_SIZE: u64 = 8; 70 | 71 | let bits = bits_u64(value); 72 | let sign = if bits[0] { -1i64 } else { 1i64 }; 73 | let width_base = bits_to_byte_u64(&bits[1 .. 4]); 74 | let actual_width = width_base * ENCODING_SIZE; 75 | let natural = bits_to_byte_u64(&bits[bits.len() - actual_width as usize ..]); 76 | let constant = bits_to_byte_u64(&bits[HEADER_SIZE .. bits.len() - actual_width as usize]); 77 | let offset = { sign * (constant + natural * SIZE_OF_VOID_PTR as u64) as i64 }; 78 | 79 | Self { value: value, sign: sign as i8, constant: constant, natural: natural, offset: offset as i64 } 80 | } 81 | } 82 | 83 | impl Emit for NaturalIndex 84 | { 85 | fn emit(&self, options: &Options) -> String 86 | { 87 | format!( 88 | "({}{}, {}{})", 89 | if self.sign < 0 { "-" } else { "+" }, 90 | color_index(self.natural.to_string(), options), 91 | if self.sign < 0 { "-" } else { "+" }, 92 | color_index(self.constant.to_string(), options) 93 | ) 94 | } 95 | } 96 | 97 | #[cfg(test)] 98 | mod tests 99 | { 100 | use super::*; 101 | 102 | #[test] 103 | pub fn test_natural_indexing() 104 | { 105 | let index = NaturalIndex::from_u16(4161); 106 | assert_eq!(index.constant, 16u64); 107 | assert_eq!(index.natural, 1u64); 108 | assert_eq!(index.offset, 24i64); 109 | 110 | let index = NaturalIndex::from_u16(4114); 111 | assert_eq!(index.constant, 4u64); 112 | assert_eq!(index.natural, 2u64); 113 | assert_eq!(index.offset, 20i64); 114 | 115 | let index = NaturalIndex::from_u16(8581); 116 | assert_eq!(index.constant, 24u64); 117 | assert_eq!(index.natural, 5u64); 118 | assert_eq!(index.offset, 64i64); 119 | 120 | let index = NaturalIndex::from_u32(805324752); 121 | assert_eq!(index.constant, 4u64); 122 | assert_eq!(index.natural, 2000u64); 123 | assert_eq!(index.offset, 16004i64); 124 | 125 | let index = NaturalIndex::from_u32(111111); 126 | assert_eq!(index.constant, 111111u64); 127 | assert_eq!(index.natural, 0u64); 128 | assert_eq!(index.offset, 111111i64); 129 | 130 | let index = NaturalIndex::from_u64(2305843035428095952); 131 | assert_eq!(index.constant, 400000u64); 132 | assert_eq!(index.natural, 2000u64); 133 | assert_eq!(index.offset, 416000i64); 134 | 135 | let index = NaturalIndex::from_u32(591751049); 136 | assert_eq!(index.constant, 214375u64); 137 | assert_eq!(index.natural, 137u64); 138 | assert_eq!(index.offset, 215471i64); 139 | 140 | let index = NaturalIndex::from_u64(11529215072282871760); 141 | assert_eq!(index.sign, -1i8); 142 | assert_eq!(index.constant, 400000u64); 143 | assert_eq!(index.natural, 2000u64); 144 | assert_eq!(index.offset, -416000i64); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/opcode.rs: -------------------------------------------------------------------------------- 1 | use crate::bits::*; 2 | use crate::instruction::*; 3 | use crate::options::Options; 4 | use crate::theme::*; 5 | 6 | #[derive(Debug)] 7 | pub enum OpCode 8 | { 9 | ADD = 0x0C, 10 | AND = 0x14, 11 | ASHR = 0x19, 12 | BREAK = 0x00, 13 | CALL = 0x03, 14 | CMPeq = 0x05, 15 | CMPlte = 0x06, 16 | CMPgte = 0x07, 17 | CMPulte = 0x08, 18 | CMPugte = 0x09, 19 | CMPIeq = 0x2D, 20 | CMPIlte = 0x2E, 21 | CMPIgte = 0x2F, 22 | CMPIulte = 0x30, 23 | CMPIugte = 0x31, 24 | DIV = 0x10, 25 | DIVU = 0x11, 26 | EXTNDB = 0x1A, 27 | EXTNDD = 0x1C, 28 | EXTNDW = 0x1B, 29 | JMP = 0x01, 30 | JMP8 = 0x02, 31 | LOADSP = 0x29, 32 | MOD = 0x12, 33 | MODU = 0x13, 34 | MOVbw = 0x1D, 35 | MOVww = 0x1E, 36 | MOVdw = 0x1F, 37 | MOVqw = 0x20, 38 | MOVbd = 0x21, 39 | MOVwd = 0x22, 40 | MOVdd = 0x23, 41 | MOVqd = 0x24, 42 | MOVqq = 0x28, 43 | MOVI = 0x37, 44 | MOVIn = 0x38, 45 | MOVnw = 0x32, 46 | MOVnd = 0x33, 47 | MOVREL = 0x39, 48 | MOVsnw = 0x25, 49 | MOVsnd = 0x26, 50 | MUL = 0x0E, 51 | MULU = 0x0F, 52 | NEG = 0x0B, 53 | NOT = 0x0A, 54 | OR = 0x15, 55 | POP = 0x2C, 56 | POPn = 0x36, 57 | PUSH = 0x2B, 58 | PUSHn = 0x35, 59 | RET = 0x04, 60 | SHL = 0x17, 61 | SHR = 0x18, 62 | STORESP = 0x2A, 63 | SUB = 0x0D, 64 | XOR = 0x16, 65 | } 66 | 67 | impl std::convert::TryFrom for u8 68 | { 69 | type Error = (); 70 | 71 | fn try_from(v: OpCode) -> Result 72 | { 73 | match v 74 | { 75 | OpCode::ADD => Ok(0x0C), 76 | OpCode::AND => Ok(0x14), 77 | OpCode::ASHR => Ok(0x19), 78 | OpCode::BREAK => Ok(0x00), 79 | OpCode::CALL => Ok(0x03), 80 | OpCode::CMPeq => Ok(0x05), 81 | OpCode::CMPlte => Ok(0x06), 82 | OpCode::CMPgte => Ok(0x07), 83 | OpCode::CMPulte => Ok(0x08), 84 | OpCode::CMPugte => Ok(0x09), 85 | OpCode::CMPIeq => Ok(0x2D), 86 | OpCode::CMPIlte => Ok(0x2E), 87 | OpCode::CMPIgte => Ok(0x2F), 88 | OpCode::CMPIulte => Ok(0x30), 89 | OpCode::CMPIugte => Ok(0x31), 90 | OpCode::DIV => Ok(0x10), 91 | OpCode::DIVU => Ok(0x11), 92 | OpCode::EXTNDB => Ok(0x1A), 93 | OpCode::EXTNDD => Ok(0x1C), 94 | OpCode::EXTNDW => Ok(0x1B), 95 | OpCode::JMP => Ok(0x01), 96 | OpCode::JMP8 => Ok(0x02), 97 | OpCode::LOADSP => Ok(0x29), 98 | OpCode::MOD => Ok(0x12), 99 | OpCode::MODU => Ok(0x13), 100 | OpCode::MOVbw => Ok(0x1D), 101 | OpCode::MOVww => Ok(0x1E), 102 | OpCode::MOVdw => Ok(0x1F), 103 | OpCode::MOVqw => Ok(0x20), 104 | OpCode::MOVbd => Ok(0x21), 105 | OpCode::MOVwd => Ok(0x22), 106 | OpCode::MOVdd => Ok(0x23), 107 | OpCode::MOVqd => Ok(0x24), 108 | OpCode::MOVqq => Ok(0x28), 109 | OpCode::MOVI => Ok(0x37), 110 | OpCode::MOVIn => Ok(0x38), 111 | OpCode::MOVnw => Ok(0x32), 112 | OpCode::MOVnd => Ok(0x33), 113 | OpCode::MOVREL => Ok(0x39), 114 | OpCode::MOVsnw => Ok(0x25), 115 | OpCode::MOVsnd => Ok(0x26), 116 | OpCode::MUL => Ok(0x0E), 117 | OpCode::MULU => Ok(0x0F), 118 | OpCode::NEG => Ok(0x0B), 119 | OpCode::NOT => Ok(0x0A), 120 | OpCode::OR => Ok(0x15), 121 | OpCode::POP => Ok(0x2C), 122 | OpCode::POPn => Ok(0x36), 123 | OpCode::PUSH => Ok(0x2B), 124 | OpCode::PUSHn => Ok(0x35), 125 | OpCode::RET => Ok(0x04), 126 | OpCode::SHL => Ok(0x17), 127 | OpCode::SHR => Ok(0x18), 128 | OpCode::STORESP => Ok(0x2A), 129 | OpCode::SUB => Ok(0x0D), 130 | OpCode::XOR => Ok(0x16), 131 | } 132 | } 133 | } 134 | 135 | impl std::convert::TryFrom for OpCode 136 | { 137 | type Error = (); 138 | 139 | fn try_from(v: u8) -> Result 140 | { 141 | match v 142 | { 143 | x if x == Self::ADD as u8 => Ok(Self::ADD), 144 | x if x == Self::AND as u8 => Ok(Self::AND), 145 | x if x == Self::ASHR as u8 => Ok(Self::ASHR), 146 | x if x == Self::BREAK as u8 => Ok(Self::BREAK), 147 | x if x == Self::CALL as u8 => Ok(Self::CALL), 148 | x if x == Self::CMPeq as u8 => Ok(Self::CMPeq), 149 | x if x == Self::CMPlte as u8 => Ok(Self::CMPlte), 150 | x if x == Self::CMPgte as u8 => Ok(Self::CMPgte), 151 | x if x == Self::CMPulte as u8 => Ok(Self::CMPulte), 152 | x if x == Self::CMPugte as u8 => Ok(Self::CMPugte), 153 | x if x == Self::CMPIeq as u8 => Ok(Self::CMPIeq), 154 | x if x == Self::CMPIlte as u8 => Ok(Self::CMPIlte), 155 | x if x == Self::CMPIgte as u8 => Ok(Self::CMPIgte), 156 | x if x == Self::CMPIulte as u8 => Ok(Self::CMPIulte), 157 | x if x == Self::CMPIugte as u8 => Ok(Self::CMPIugte), 158 | x if x == Self::DIV as u8 => Ok(Self::DIV), 159 | x if x == Self::DIVU as u8 => Ok(Self::DIVU), 160 | x if x == Self::EXTNDB as u8 => Ok(Self::EXTNDB), 161 | x if x == Self::EXTNDD as u8 => Ok(Self::EXTNDD), 162 | x if x == Self::EXTNDW as u8 => Ok(Self::EXTNDW), 163 | x if x == Self::JMP as u8 => Ok(Self::JMP), 164 | x if x == Self::JMP8 as u8 => Ok(Self::JMP8), 165 | x if x == Self::LOADSP as u8 => Ok(Self::LOADSP), 166 | x if x == Self::MOD as u8 => Ok(Self::MOD), 167 | x if x == Self::MODU as u8 => Ok(Self::MODU), 168 | x if x == Self::MOVbw as u8 => Ok(Self::MOVbw), 169 | x if x == Self::MOVww as u8 => Ok(Self::MOVww), 170 | x if x == Self::MOVdw as u8 => Ok(Self::MOVdw), 171 | x if x == Self::MOVqw as u8 => Ok(Self::MOVqw), 172 | x if x == Self::MOVbd as u8 => Ok(Self::MOVbd), 173 | x if x == Self::MOVwd as u8 => Ok(Self::MOVwd), 174 | x if x == Self::MOVdd as u8 => Ok(Self::MOVdd), 175 | x if x == Self::MOVqd as u8 => Ok(Self::MOVqd), 176 | x if x == Self::MOVqq as u8 => Ok(Self::MOVqq), 177 | x if x == Self::MOVI as u8 => Ok(Self::MOVI), 178 | x if x == Self::MOVIn as u8 => Ok(Self::MOVIn), 179 | x if x == Self::MOVnw as u8 => Ok(Self::MOVnw), 180 | x if x == Self::MOVnd as u8 => Ok(Self::MOVnd), 181 | x if x == Self::MOVREL as u8 => Ok(Self::MOVREL), 182 | x if x == Self::MOVsnw as u8 => Ok(Self::MOVsnw), 183 | x if x == Self::MOVsnd as u8 => Ok(Self::MOVsnd), 184 | x if x == Self::MUL as u8 => Ok(Self::MUL), 185 | x if x == Self::MULU as u8 => Ok(Self::MULU), 186 | x if x == Self::NEG as u8 => Ok(Self::NEG), 187 | x if x == Self::NOT as u8 => Ok(Self::NOT), 188 | x if x == Self::OR as u8 => Ok(Self::OR), 189 | x if x == Self::POP as u8 => Ok(Self::POP), 190 | x if x == Self::POPn as u8 => Ok(Self::POPn), 191 | x if x == Self::PUSH as u8 => Ok(Self::PUSH), 192 | x if x == Self::PUSHn as u8 => Ok(Self::PUSHn), 193 | x if x == Self::RET as u8 => Ok(Self::RET), 194 | x if x == Self::SHL as u8 => Ok(Self::SHL), 195 | x if x == Self::SHR as u8 => Ok(Self::SHR), 196 | x if x == Self::STORESP as u8 => Ok(Self::STORESP), 197 | x if x == Self::SUB as u8 => Ok(Self::SUB), 198 | x if x == Self::XOR as u8 => Ok(Self::XOR), 199 | _ => Err(()), 200 | } 201 | } 202 | } 203 | 204 | impl OpCode 205 | { 206 | /// Bytes are read from left to right. Bits are read from right to left. 207 | // pub fn disassemble, W: std::io::Write>( 208 | // options: &Options, 209 | // writer: &mut W, 210 | // bytes: &mut T 211 | // ) -> Result<(), String> 212 | pub fn disassemble, W: std::io::Write>( 213 | options: &Options, 214 | writer: &mut W, 215 | bytes: &mut std::iter::Peekable, 216 | ) -> Result<(), String> 217 | { 218 | let byte0 = if let Some(byte) = bytes.next() 219 | { 220 | byte 221 | } 222 | else 223 | { 224 | return Err(String::from("Completed Disassembly")); 225 | }; 226 | 227 | // * Using reverse number parsing to make indexing the individual bits 228 | // * easier since the UEFI spec specifies them in reverse. 229 | 230 | let byte0_bits = bits_rev(byte0); 231 | let op_value = bits_to_byte_rev(&byte0_bits[0 ..= 5]); 232 | let op: OpCode = op_value.try_into().expect(format!("Invalid OpCode: {}", op_value).as_str()); 233 | 234 | match op 235 | { 236 | OpCode::BREAK => 237 | { 238 | if let Some(byte) = bytes.peek() 239 | { 240 | if *byte == 0 241 | { 242 | bytes.next(); // Skip this and the next zero 243 | Ok(()) 244 | } 245 | else if *byte > 6 246 | // 1-6 are valid break codes 247 | { 248 | Ok(()) // Only skip this zero 249 | } 250 | else 251 | { 252 | // 2. INSTRUCTION ARGUMENT (BREAK) 253 | parse_instruction2(writer, options, bytes, byte0, byte0_bits, op) 254 | } 255 | } 256 | else 257 | { 258 | Ok(()) 259 | } 260 | } 261 | 262 | // 1. INSTRUCTION (RET) 263 | OpCode::RET => parse_instruction1(writer, options, bytes, byte0, byte0_bits, op), 264 | 265 | OpCode::JMP8 => 266 | { 267 | // 2. INSTRUCTION ARGUMENT (BREAK) 268 | parse_instruction2(writer, options, bytes, byte0, byte0_bits, op) 269 | } 270 | 271 | OpCode::CALL | OpCode::JMP | OpCode::PUSH | OpCode::PUSHn | OpCode::POP | OpCode::POPn => 272 | { 273 | // 3. INSTRUCTION OP1 ARGUMENT (CALL) 274 | parse_instruction3(writer, options, bytes, byte0, byte0_bits, op) 275 | } 276 | 277 | OpCode::LOADSP | OpCode::STORESP => 278 | { 279 | // 4. INSTRUCTION OP1, OP2 (STORESP) 280 | parse_instruction4(writer, options, bytes, byte0, byte0_bits, op) 281 | } 282 | 283 | OpCode::CMPIeq 284 | | OpCode::CMPIlte 285 | | OpCode::CMPIgte 286 | | OpCode::CMPIulte 287 | | OpCode::CMPIugte 288 | | OpCode::MOVI 289 | | OpCode::MOVIn 290 | | OpCode::MOVREL => 291 | { 292 | // 5. INSTRUCTION OP1 ARGUMENT, ARGUMENT (CMPI) 293 | parse_instruction5(writer, options, bytes, byte0, byte0_bits, op) 294 | } 295 | 296 | OpCode::ADD 297 | | OpCode::AND 298 | | OpCode::ASHR 299 | | OpCode::CMPeq 300 | | OpCode::CMPlte 301 | | OpCode::CMPgte 302 | | OpCode::CMPulte 303 | | OpCode::CMPugte 304 | | OpCode::DIV 305 | | OpCode::DIVU 306 | | OpCode::EXTNDB 307 | | OpCode::EXTNDD 308 | | OpCode::EXTNDW 309 | | OpCode::MOD 310 | | OpCode::MODU 311 | | OpCode::MUL 312 | | OpCode::MULU 313 | | OpCode::NEG 314 | | OpCode::NOT 315 | | OpCode::OR 316 | | OpCode::SHL 317 | | OpCode::SHR 318 | | OpCode::SUB 319 | | OpCode::XOR => 320 | { 321 | // 6. INSTRUCTION OP1, OP2 ARGUMENT 322 | parse_instruction6(writer, options, bytes, byte0, byte0_bits, op) 323 | } 324 | 325 | OpCode::MOVnw 326 | | OpCode::MOVnd 327 | | OpCode::MOVbw 328 | | OpCode::MOVww 329 | | OpCode::MOVdw 330 | | OpCode::MOVqw 331 | | OpCode::MOVbd 332 | | OpCode::MOVwd 333 | | OpCode::MOVdd 334 | | OpCode::MOVqd 335 | | OpCode::MOVqq 336 | | OpCode::MOVsnw 337 | | OpCode::MOVsnd => 338 | { 339 | // 7. INSTRUCTION OP1 ARGUMENT, OP2 ARGUMENT (MOV) 340 | parse_instruction7(writer, options, bytes, byte0, byte0_bits, op) 341 | } 342 | } 343 | } 344 | 345 | pub fn to(self) -> u8 346 | { 347 | self.try_into().unwrap() 348 | } 349 | } 350 | 351 | impl Emit for OpCode 352 | { 353 | fn emit(&self, options: &Options) -> String 354 | { 355 | color_opcode(format!("{:?}", self), options) 356 | } 357 | } 358 | -------------------------------------------------------------------------------- /src/operand.rs: -------------------------------------------------------------------------------- 1 | use crate::options::Options; 2 | use crate::theme::*; 3 | 4 | pub enum Operand 5 | { 6 | GeneralPurpose 7 | { 8 | register_index: u8, indirect: bool 9 | }, 10 | 11 | Dedicated 12 | { 13 | register_index: u8, indirect: bool 14 | }, 15 | } 16 | 17 | impl Operand 18 | { 19 | pub fn new_general_purpose(register_index: u8, indirect: bool) -> Self 20 | { 21 | assert!((0u8 ..= 7u8).contains(®ister_index)); 22 | 23 | Self::GeneralPurpose { register_index, indirect } 24 | } 25 | 26 | pub fn new_dedicated(register_index: u8, indirect: bool) -> Self 27 | { 28 | assert!((0u8 ..= 1u8).contains(®ister_index)); 29 | 30 | Self::Dedicated { register_index, indirect } 31 | } 32 | } 33 | 34 | impl Emit for Operand 35 | { 36 | fn emit(&self, options: &Options) -> String 37 | { 38 | match self 39 | { 40 | Self::GeneralPurpose { register_index: index, indirect: at } => 41 | { 42 | let at_sym = if *at { color_indirect("@".to_string(), options) } else { "".to_string() }; 43 | 44 | assert!((0u8 ..= 7u8).contains(&index)); 45 | 46 | color_operand(format!("{}R{}", at_sym, index), options) 47 | } 48 | 49 | Self::Dedicated { register_index: index, indirect: at } => 50 | { 51 | let at_sym = if *at { color_indirect("@".to_string(), options) } else { "".to_string() }; 52 | 53 | assert!((0u8 ..= 1u8).contains(&index)); 54 | 55 | let result = if *index == 0 { format!("{}FLAGS", at_sym) } else { format!("{}IP", at_sym) }; 56 | 57 | color_operand(result, options) 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/options.rs: -------------------------------------------------------------------------------- 1 | use crate::theme::Theme; 2 | 3 | pub struct Options 4 | { 5 | pub pad_output: bool, // Padding is great for output but not for testing 6 | pub theme: Option, // Colorize assembly output (optional for pipes) 7 | pub bytecode: bool, // Output bytecode in hex notation beside assembly 8 | pub pe: bool, // Load a Windows PE file rather than a binary file 9 | } 10 | -------------------------------------------------------------------------------- /src/tests/mod.rs: -------------------------------------------------------------------------------- 1 | use std::io::Cursor; 2 | 3 | use super::*; 4 | 5 | fn dis(options: &Options, cursor: &mut Cursor>, bytecode: &[u8]) -> String 6 | { 7 | let result = OpCode::disassemble(&options, cursor, &mut bytecode.into_iter().cloned().peekable()); 8 | 9 | match result 10 | { 11 | Ok(_) => assert!(true), 12 | Err(msg) => assert!(false, "{}", msg.to_string()), 13 | } 14 | 15 | let disassembly = String::from_utf8(cursor.get_ref().clone()).unwrap(); 16 | cursor.get_mut().clear(); 17 | cursor.set_position(0); 18 | 19 | // Remove last character since that will always be a "\n" 20 | let mut chars = disassembly.chars(); 21 | chars.next_back(); 22 | chars.as_str().to_string() 23 | } 24 | 25 | fn byte(bit8: u8, bit7: u8, op: OpCode) -> u8 26 | { 27 | let mut byte = op.to(); 28 | if bit8 > 0 29 | { 30 | byte |= 1 << 7; 31 | } 32 | if bit7 > 0 33 | { 34 | byte |= 1 << 6; 35 | } 36 | byte 37 | } 38 | 39 | #[test] 40 | pub fn test_instruction_disassembly() 41 | { 42 | let opts = &Options { theme: None, bytecode: false, pad_output: false, pe: false }; 43 | 44 | let cur = &mut Cursor::new(Vec::with_capacity(50)); 45 | 46 | assert_eq!("RET", dis(opts, cur, &[OpCode::RET.to()])); 47 | assert_eq!("STORESP R1, FLAGS", dis(opts, cur, &[OpCode::STORESP.to(), 0b00000001])); 48 | assert_eq!("STORESP R1, IP", dis(opts, cur, &[OpCode::STORESP.to(), 0b00010001])); 49 | assert_eq!("LOADSP FLAGS, R1", dis(opts, cur, &[OpCode::LOADSP.to(), 0b00010000])); 50 | assert_eq!("LOADSP IP, R1", dis(opts, cur, &[OpCode::LOADSP.to(), 0b00010001])); 51 | assert_eq!("BREAK 3", dis(opts, cur, &[OpCode::BREAK.to(), 0b00000011])); 52 | 53 | assert_eq!("JMP8 -3", dis(opts, cur, &[&[byte(0, 0, OpCode::JMP8)][..], &(-3i8).to_le_bytes()[..],].concat())); 54 | 55 | assert_eq!( 56 | "JMP8 -3", 57 | dis( 58 | opts, 59 | cur, 60 | &[ 61 | // Test that CC or CS have not effect on unconditional jump 62 | &[byte(0, 1, OpCode::JMP8)][..], 63 | &(-3i8).to_le_bytes()[..], 64 | ] 65 | .concat() 66 | ) 67 | ); 68 | 69 | assert_eq!("JMP8cc -3", dis(opts, cur, &[&[byte(1, 0, OpCode::JMP8)][..], &(-3i8).to_le_bytes()[..],].concat())); 70 | 71 | assert_eq!("JMP8cs -3", dis(opts, cur, &[&[byte(1, 1, OpCode::JMP8)][..], &(-3i8).to_le_bytes()[..],].concat())); 72 | 73 | assert_eq!("POPn R1", dis(opts, cur, &[OpCode::POPn.to(), 0b00000001])); 74 | 75 | assert_eq!("PUSHn R1", dis(opts, cur, &[OpCode::PUSHn.to(), 0b00000001])); 76 | 77 | assert_eq!("POPn @R1", dis(opts, cur, &[OpCode::POPn.to(), 0b00001001])); 78 | 79 | assert_eq!("PUSHn @R1", dis(opts, cur, &[OpCode::PUSHn.to(), 0b00001001])); 80 | 81 | assert_eq!( 82 | "POPn R1 -3", 83 | dis(opts, cur, &[&[byte(1, 0, OpCode::POPn), 0b00000001][..], &(-3i16).to_le_bytes()[..],].concat()) 84 | ); 85 | 86 | assert_eq!( 87 | "PUSHn R1 -3", 88 | dis(opts, cur, &[&[byte(1, 0, OpCode::PUSHn), 0b00000001][..], &(-3i16).to_le_bytes()[..],].concat()) 89 | ); 90 | 91 | assert_eq!( 92 | "POPn @R1(-3, -3)", 93 | dis(opts, cur, &[&[byte(1, 0, OpCode::POPn), 0b00001001][..], &(36879u16).to_le_bytes()[..],].concat()) 94 | ); 95 | 96 | assert_eq!( 97 | "PUSHn @R1(-3, -3)", 98 | dis(opts, cur, &[&[byte(1, 0, OpCode::PUSHn), 0b00001001][..], &(36879u16).to_le_bytes()[..],].concat()) 99 | ); 100 | 101 | assert_eq!("POP32 R1", dis(opts, cur, &[OpCode::POP.to(), 0b00000001])); 102 | assert_eq!("PUSH32 R1", dis(opts, cur, &[OpCode::PUSH.to(), 0b00000001])); 103 | assert_eq!("POP32 @R1", dis(opts, cur, &[OpCode::POP.to(), 0b00001001])); 104 | assert_eq!("PUSH32 @R1", dis(opts, cur, &[OpCode::PUSH.to(), 0b00001001])); 105 | 106 | assert_eq!( 107 | "POP32 R1 -3", 108 | dis(opts, cur, &[&[byte(1, 0, OpCode::POP), 0b00000001][..], &(-3i16).to_le_bytes()[..],].concat()) 109 | ); 110 | 111 | assert_eq!( 112 | "PUSH32 R1 -3", 113 | dis(opts, cur, &[&[byte(1, 0, OpCode::PUSH), 0b00000001][..], &(-3i16).to_le_bytes()[..],].concat()) 114 | ); 115 | 116 | assert_eq!( 117 | "POP32 @R1(-3, -3)", 118 | dis(opts, cur, &[&[byte(1, 0, OpCode::POP), 0b00001001][..], &(36879u16).to_le_bytes()[..],].concat()) 119 | ); 120 | 121 | assert_eq!( 122 | "PUSH32 @R1(-3, -3)", 123 | dis(opts, cur, &[&[byte(1, 0, OpCode::PUSH), 0b00001001][..], &(36879u16).to_le_bytes()[..],].concat()) 124 | ); 125 | 126 | assert_eq!("POP64 R1", dis(opts, cur, &[byte(0, 1, OpCode::POP), 0b00000001])); 127 | 128 | assert_eq!("PUSH64 R1", dis(opts, cur, &[byte(0, 1, OpCode::PUSH), 0b00000001])); 129 | 130 | assert_eq!("POP64 @R1", dis(opts, cur, &[byte(0, 1, OpCode::POP), 0b00001001])); 131 | 132 | assert_eq!("PUSH64 @R1", dis(opts, cur, &[byte(0, 1, OpCode::PUSH), 0b00001001])); 133 | 134 | assert_eq!( 135 | "POP64 R1 -3", 136 | dis(opts, cur, &[&[byte(1, 1, OpCode::POP), 0b00000001][..], &(-3i16).to_le_bytes()[..],].concat()) 137 | ); 138 | 139 | assert_eq!( 140 | "PUSH64 R1 -3", 141 | dis(opts, cur, &[&[byte(1, 1, OpCode::PUSH), 0b00000001][..], &(-3i16).to_le_bytes()[..],].concat()) 142 | ); 143 | 144 | assert_eq!( 145 | "POP64 @R1(-3, -3)", 146 | dis(opts, cur, &[&[byte(1, 1, OpCode::POP), 0b00001001][..], &(36879u16).to_le_bytes()[..],].concat()) 147 | ); 148 | 149 | assert_eq!( 150 | "PUSH64 @R1(-3, -3)", 151 | dis(opts, cur, &[&[byte(1, 1, OpCode::PUSH), 0b00001001][..], &(36879u16).to_le_bytes()[..],].concat()) 152 | ); 153 | 154 | assert_eq!("CALL32 R1", dis(opts, cur, &[OpCode::CALL.to(), 0b00010001])); 155 | assert_eq!("CALL32a R1", dis(opts, cur, &[OpCode::CALL.to(), 0b00000001])); 156 | 157 | assert_eq!( 158 | "CALL32 R1 -3", 159 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00010001][..], &(-3i32).to_le_bytes()[..],].concat()) 160 | ); 161 | 162 | assert_eq!( 163 | "CALL32a R1 -3", 164 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00000001][..], &(-3i32).to_le_bytes()[..],].concat()) 165 | ); 166 | 167 | assert_eq!( 168 | "CALL32 @R1(-300, -300)", 169 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00011001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 170 | ); 171 | 172 | assert_eq!("CALL32 @R1", dis(opts, cur, &[OpCode::CALL.to(), 0b00011001])); 173 | 174 | assert_eq!( 175 | "CALL32a @R1(-300, -300)", 176 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00001001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 177 | ); 178 | 179 | assert_eq!("CALL32EX R1", dis(opts, cur, &[OpCode::CALL.to(), 0b00110001])); 180 | assert_eq!("CALL32EXa R1", dis(opts, cur, &[OpCode::CALL.to(), 0b00100001])); 181 | assert_eq!("CALL32EX @R1", dis(opts, cur, &[OpCode::CALL.to(), 0b00111001])); 182 | assert_eq!("CALL32EXa @R1", dis(opts, cur, &[OpCode::CALL.to(), 0b00101001])); 183 | 184 | assert_eq!( 185 | "CALL32EX R1 -3", 186 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00110001][..], &(-3i32).to_le_bytes()[..],].concat()) 187 | ); 188 | 189 | assert_eq!( 190 | "CALL32EXa R1 -3", 191 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00100001][..], &(-3i32).to_le_bytes()[..],].concat()) 192 | ); 193 | 194 | assert_eq!( 195 | "CALL32EX @R1(-300, -300)", 196 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00111001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 197 | ); 198 | 199 | assert_eq!( 200 | "CALL32EXa @R1(-300, -300)", 201 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00101001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 202 | ); 203 | 204 | assert_eq!( 205 | "CALL64EXa -3", 206 | dis(opts, cur, &[&[byte(1, 1, OpCode::CALL), 0b00110001][..], &(-3i64).to_le_bytes()[..],].concat()) 207 | ); 208 | 209 | assert_eq!("JMP32 R1 ;; Absolute Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b00000001])); 210 | 211 | assert_eq!("JMP32cc R1 ;; Absolute Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b10000001])); 212 | 213 | assert_eq!("JMP32cs R1 ;; Absolute Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b11000001])); 214 | 215 | assert_eq!("JMP32 R1 ;; Relative Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b00010001])); 216 | 217 | assert_eq!("JMP32cc R1 ;; Relative Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b10010001])); 218 | 219 | assert_eq!("JMP32cs R1 ;; Relative Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b11010001])); 220 | 221 | assert_eq!("JMP32 @R1 ;; Relative Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b00011001])); 222 | 223 | assert_eq!("JMP32 @R1 ;; Absolute Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b00001001])); 224 | 225 | assert_eq!("MOVb R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVbw), 0b00100001])); 226 | 227 | assert_eq!("MOVw R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVww), 0b00100001])); 228 | 229 | assert_eq!("MOVd R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVdw), 0b00100001])); 230 | 231 | assert_eq!("MOVq R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVqw), 0b00100001])); 232 | 233 | assert_eq!("MOVb @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVbw), 0b00101001])); 234 | 235 | assert_eq!("MOVw @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVww), 0b00101001])); 236 | 237 | assert_eq!("MOVd @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVdw), 0b00101001])); 238 | 239 | assert_eq!("MOVq @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVqw), 0b00101001])); 240 | 241 | assert_eq!("MOVb R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVbw), 0b10100001])); 242 | 243 | assert_eq!("MOVw R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVww), 0b10100001])); 244 | 245 | assert_eq!("MOVd R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVdw), 0b10100001])); 246 | 247 | assert_eq!("MOVq R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVqw), 0b10100001])); 248 | 249 | assert_eq!("MOVb @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVbw), 0b10101001])); 250 | 251 | assert_eq!("MOVw @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVww), 0b10101001])); 252 | 253 | assert_eq!("MOVd @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVdw), 0b10101001])); 254 | 255 | assert_eq!("MOVq @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVqw), 0b10101001])); 256 | 257 | assert_eq!("ADD32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::ADD), 0b00100001])); 258 | 259 | assert_eq!("ADD32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::ADD), 0b00101001])); 260 | 261 | assert_eq!("ADD32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::ADD), 0b10100001])); 262 | 263 | assert_eq!("ADD32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::ADD), 0b10101001])); 264 | 265 | assert_eq!("ADD64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::ADD), 0b00100001])); 266 | 267 | assert_eq!("ADD64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::ADD), 0b00101001])); 268 | 269 | assert_eq!("ADD64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::ADD), 0b10100001])); 270 | 271 | assert_eq!("ADD64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::ADD), 0b10101001])); 272 | 273 | assert_eq!("AND32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::AND), 0b00100001])); 274 | 275 | assert_eq!("AND32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::AND), 0b00101001])); 276 | 277 | assert_eq!("AND32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::AND), 0b10100001])); 278 | 279 | assert_eq!("AND32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::AND), 0b10101001])); 280 | 281 | assert_eq!("AND64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::AND), 0b00100001])); 282 | 283 | assert_eq!("AND64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::AND), 0b00101001])); 284 | 285 | assert_eq!("AND64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::AND), 0b10100001])); 286 | 287 | assert_eq!("AND64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::AND), 0b10101001])); 288 | 289 | assert_eq!("ASHR32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::ASHR), 0b00100001])); 290 | 291 | assert_eq!("ASHR32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::ASHR), 0b00101001])); 292 | 293 | assert_eq!("ASHR32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::ASHR), 0b10100001])); 294 | 295 | assert_eq!("ASHR32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::ASHR), 0b10101001])); 296 | 297 | assert_eq!("ASHR64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::ASHR), 0b00100001])); 298 | 299 | assert_eq!("ASHR64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::ASHR), 0b00101001])); 300 | 301 | assert_eq!("ASHR64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::ASHR), 0b10100001])); 302 | 303 | assert_eq!("ASHR64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::ASHR), 0b10101001])); 304 | 305 | assert_eq!("DIV32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::DIV), 0b00100001])); 306 | 307 | assert_eq!("DIV32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::DIV), 0b00101001])); 308 | 309 | assert_eq!("DIV32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::DIV), 0b10100001])); 310 | 311 | assert_eq!("DIV32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::DIV), 0b10101001])); 312 | 313 | assert_eq!("DIV64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::DIV), 0b00100001])); 314 | 315 | assert_eq!("DIV64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::DIV), 0b00101001])); 316 | 317 | assert_eq!("DIV64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::DIV), 0b10100001])); 318 | 319 | assert_eq!("DIV64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::DIV), 0b10101001])); 320 | 321 | assert_eq!("DIVU32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::DIVU), 0b00100001])); 322 | 323 | assert_eq!("DIVU32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::DIVU), 0b00101001])); 324 | 325 | assert_eq!("DIVU32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::DIVU), 0b10100001])); 326 | 327 | assert_eq!("DIVU32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::DIVU), 0b10101001])); 328 | 329 | assert_eq!("DIVU64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::DIVU), 0b00100001])); 330 | 331 | assert_eq!("DIVU64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::DIVU), 0b00101001])); 332 | 333 | assert_eq!("DIVU64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::DIVU), 0b10100001])); 334 | 335 | assert_eq!("DIVU64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::DIVU), 0b10101001])); 336 | 337 | assert_eq!("EXTNDB32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDB), 0b00100001])); 338 | 339 | assert_eq!("EXTNDB32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDB), 0b00101001])); 340 | 341 | assert_eq!("EXTNDB32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDB), 0b10100001])); 342 | 343 | assert_eq!("EXTNDB32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDB), 0b10101001])); 344 | 345 | assert_eq!("EXTNDB64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDB), 0b00100001])); 346 | 347 | assert_eq!("EXTNDB64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDB), 0b00101001])); 348 | 349 | assert_eq!("EXTNDB64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDB), 0b10100001])); 350 | 351 | assert_eq!("EXTNDB64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDB), 0b10101001])); 352 | 353 | assert_eq!("EXTNDD32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDD), 0b00100001])); 354 | 355 | assert_eq!("EXTNDD32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDD), 0b00101001])); 356 | 357 | assert_eq!("EXTNDD32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDD), 0b10100001])); 358 | 359 | assert_eq!("EXTNDD32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDD), 0b10101001])); 360 | 361 | assert_eq!("EXTNDD64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDD), 0b00100001])); 362 | 363 | assert_eq!("EXTNDD64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDD), 0b00101001])); 364 | 365 | assert_eq!("EXTNDD64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDD), 0b10100001])); 366 | 367 | assert_eq!("EXTNDD64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDD), 0b10101001])); 368 | 369 | assert_eq!("EXTNDW32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDW), 0b00100001])); 370 | 371 | assert_eq!("EXTNDW32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDW), 0b00101001])); 372 | 373 | assert_eq!("EXTNDW32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDW), 0b10100001])); 374 | 375 | assert_eq!("EXTNDW32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDW), 0b10101001])); 376 | 377 | assert_eq!("EXTNDW64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDW), 0b00100001])); 378 | 379 | assert_eq!("EXTNDW64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDW), 0b00101001])); 380 | 381 | assert_eq!("EXTNDW64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDW), 0b10100001])); 382 | 383 | assert_eq!("EXTNDW64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDW), 0b10101001])); 384 | 385 | assert_eq!("MOD32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOD), 0b00100001])); 386 | 387 | assert_eq!("MOD32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOD), 0b00101001])); 388 | 389 | assert_eq!("MOD32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOD), 0b10100001])); 390 | 391 | assert_eq!("MOD32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOD), 0b10101001])); 392 | 393 | assert_eq!("MOD64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MOD), 0b00100001])); 394 | 395 | assert_eq!("MOD64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MOD), 0b00101001])); 396 | 397 | assert_eq!("MOD64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MOD), 0b10100001])); 398 | 399 | assert_eq!("MOD64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MOD), 0b10101001])); 400 | 401 | assert_eq!("MODU32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MODU), 0b00100001])); 402 | 403 | assert_eq!("MODU32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MODU), 0b00101001])); 404 | 405 | assert_eq!("MODU32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MODU), 0b10100001])); 406 | 407 | assert_eq!("MODU32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MODU), 0b10101001])); 408 | 409 | assert_eq!("MODU64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MODU), 0b00100001])); 410 | 411 | assert_eq!("MODU64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MODU), 0b00101001])); 412 | 413 | assert_eq!("MODU64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MODU), 0b10100001])); 414 | 415 | assert_eq!("MODU64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MODU), 0b10101001])); 416 | 417 | assert_eq!("SHL32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::SHL), 0b00100001])); 418 | 419 | assert_eq!("SHL32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::SHL), 0b00101001])); 420 | 421 | assert_eq!("SHL32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::SHL), 0b10100001])); 422 | 423 | assert_eq!("SHL32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::SHL), 0b10101001])); 424 | 425 | assert_eq!("SHL64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::SHL), 0b00100001])); 426 | 427 | assert_eq!("SHL64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::SHL), 0b00101001])); 428 | 429 | assert_eq!("SHL64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::SHL), 0b10100001])); 430 | 431 | assert_eq!("SHL64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::SHL), 0b10101001])); 432 | 433 | assert_eq!("SHR32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::SHR), 0b00100001])); 434 | 435 | assert_eq!("SHR32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::SHR), 0b00101001])); 436 | 437 | assert_eq!("SHR32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::SHR), 0b10100001])); 438 | 439 | assert_eq!("SHR32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::SHR), 0b10101001])); 440 | 441 | assert_eq!("SHR64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::SHR), 0b00100001])); 442 | 443 | assert_eq!("SHR64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::SHR), 0b00101001])); 444 | 445 | assert_eq!("SHR64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::SHR), 0b10100001])); 446 | 447 | assert_eq!("SHR64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::SHR), 0b10101001])); 448 | 449 | assert_eq!("SUB32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::SUB), 0b00100001])); 450 | 451 | assert_eq!("SUB32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::SUB), 0b00101001])); 452 | 453 | assert_eq!("SUB32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::SUB), 0b10100001])); 454 | 455 | assert_eq!("SUB32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::SUB), 0b10101001])); 456 | 457 | assert_eq!("SUB64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::SUB), 0b00100001])); 458 | 459 | assert_eq!("SUB64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::SUB), 0b00101001])); 460 | 461 | assert_eq!("SUB64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::SUB), 0b10100001])); 462 | 463 | assert_eq!("SUB64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::SUB), 0b10101001])); 464 | 465 | assert_eq!("XOR32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::XOR), 0b00100001])); 466 | 467 | assert_eq!("XOR32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::XOR), 0b00101001])); 468 | 469 | assert_eq!("XOR32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::XOR), 0b10100001])); 470 | 471 | assert_eq!("XOR32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::XOR), 0b10101001])); 472 | 473 | assert_eq!("XOR64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::XOR), 0b00100001])); 474 | 475 | assert_eq!("XOR64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::XOR), 0b00101001])); 476 | 477 | assert_eq!("XOR64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::XOR), 0b10100001])); 478 | 479 | assert_eq!("XOR64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::XOR), 0b10101001])); 480 | 481 | assert_eq!("CMPeq32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPeq), 0b00100001])); 482 | 483 | assert_eq!("CMPeq32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPeq), 0b00101001])); 484 | 485 | assert_eq!("CMPeq32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPeq), 0b10100001])); 486 | 487 | assert_eq!("CMPeq32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPeq), 0b10101001])); 488 | 489 | assert_eq!("CMPeq64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPeq), 0b00100001])); 490 | 491 | assert_eq!("CMPeq64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPeq), 0b00101001])); 492 | 493 | assert_eq!("CMPeq64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPeq), 0b10100001])); 494 | 495 | assert_eq!("CMPeq64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPeq), 0b10101001])); 496 | 497 | assert_eq!("CMPlte32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPlte), 0b00100001])); 498 | 499 | assert_eq!("CMPlte32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPlte), 0b00101001])); 500 | 501 | assert_eq!("CMPlte32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPlte), 0b10100001])); 502 | 503 | assert_eq!("CMPlte32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPlte), 0b10101001])); 504 | 505 | assert_eq!("CMPlte64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPlte), 0b00100001])); 506 | 507 | assert_eq!("CMPlte64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPlte), 0b00101001])); 508 | 509 | assert_eq!("CMPlte64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPlte), 0b10100001])); 510 | 511 | assert_eq!("CMPlte64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPlte), 0b10101001])); 512 | 513 | assert_eq!("CMPgte32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPgte), 0b00100001])); 514 | 515 | assert_eq!("CMPgte32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPgte), 0b00101001])); 516 | 517 | assert_eq!("CMPgte32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPgte), 0b10100001])); 518 | 519 | assert_eq!("CMPgte32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPgte), 0b10101001])); 520 | 521 | assert_eq!("CMPgte64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPgte), 0b00100001])); 522 | 523 | assert_eq!("CMPgte64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPgte), 0b00101001])); 524 | 525 | assert_eq!("CMPgte64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPgte), 0b10100001])); 526 | 527 | assert_eq!("CMPgte64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPgte), 0b10101001])); 528 | 529 | assert_eq!("CMPulte32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPulte), 0b00100001])); 530 | 531 | assert_eq!("CMPulte32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPulte), 0b00101001])); 532 | 533 | assert_eq!("CMPulte32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPulte), 0b10100001])); 534 | 535 | assert_eq!("CMPulte32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPulte), 0b10101001])); 536 | 537 | assert_eq!("CMPulte64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPulte), 0b00100001])); 538 | 539 | assert_eq!("CMPulte64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPulte), 0b00101001])); 540 | 541 | assert_eq!("CMPulte64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPulte), 0b10100001])); 542 | 543 | assert_eq!("CMPulte64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPulte), 0b10101001])); 544 | 545 | assert_eq!("CMPugte32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPugte), 0b00100001])); 546 | 547 | assert_eq!("CMPugte32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPugte), 0b00101001])); 548 | 549 | assert_eq!("CMPugte32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPugte), 0b10100001])); 550 | 551 | assert_eq!("CMPugte32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPugte), 0b10101001])); 552 | 553 | assert_eq!("CMPugte64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPugte), 0b00100001])); 554 | 555 | assert_eq!("CMPugte64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPugte), 0b00101001])); 556 | 557 | assert_eq!("CMPugte64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPugte), 0b10100001])); 558 | 559 | assert_eq!("CMPugte64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPugte), 0b10101001])); 560 | 561 | assert_eq!("MUL32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MUL), 0b00100001])); 562 | 563 | assert_eq!("MUL32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MUL), 0b00101001])); 564 | 565 | assert_eq!("MUL32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MUL), 0b10100001])); 566 | 567 | assert_eq!("MUL32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MUL), 0b10101001])); 568 | 569 | assert_eq!("MUL64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MUL), 0b00100001])); 570 | 571 | assert_eq!("MUL64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MUL), 0b00101001])); 572 | 573 | assert_eq!("MUL64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MUL), 0b10100001])); 574 | 575 | assert_eq!("MUL64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MUL), 0b10101001])); 576 | 577 | assert_eq!("MULU32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MULU), 0b00100001])); 578 | 579 | assert_eq!("MULU32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MULU), 0b00101001])); 580 | 581 | assert_eq!("MULU32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MULU), 0b10100001])); 582 | 583 | assert_eq!("MULU32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MULU), 0b10101001])); 584 | 585 | assert_eq!("MULU64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MULU), 0b00100001])); 586 | 587 | assert_eq!("MULU64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MULU), 0b00101001])); 588 | 589 | assert_eq!("MULU64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MULU), 0b10100001])); 590 | 591 | assert_eq!("MULU64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MULU), 0b10101001])); 592 | 593 | assert_eq!("NEG32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::NEG), 0b00100001])); 594 | 595 | assert_eq!("NEG32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::NEG), 0b00101001])); 596 | 597 | assert_eq!("NEG32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::NEG), 0b10100001])); 598 | 599 | assert_eq!("NEG32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::NEG), 0b10101001])); 600 | 601 | assert_eq!("NEG64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::NEG), 0b00100001])); 602 | 603 | assert_eq!("NEG64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::NEG), 0b00101001])); 604 | 605 | assert_eq!("NEG64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::NEG), 0b10100001])); 606 | 607 | assert_eq!("NEG64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::NEG), 0b10101001])); 608 | 609 | assert_eq!("NOT32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::NOT), 0b00100001])); 610 | 611 | assert_eq!("NOT32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::NOT), 0b00101001])); 612 | 613 | assert_eq!("NOT32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::NOT), 0b10100001])); 614 | 615 | assert_eq!("NOT32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::NOT), 0b10101001])); 616 | 617 | assert_eq!("NOT64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::NOT), 0b00100001])); 618 | 619 | assert_eq!("NOT64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::NOT), 0b00101001])); 620 | 621 | assert_eq!("NOT64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::NOT), 0b10100001])); 622 | 623 | assert_eq!("NOT64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::NOT), 0b10101001])); 624 | 625 | assert_eq!("OR32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::OR), 0b00100001])); 626 | 627 | assert_eq!("OR32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::OR), 0b00101001])); 628 | 629 | assert_eq!("OR32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::OR), 0b10100001])); 630 | 631 | assert_eq!("OR32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::OR), 0b10101001])); 632 | 633 | assert_eq!("OR64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::OR), 0b00100001])); 634 | 635 | assert_eq!("OR64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::OR), 0b00101001])); 636 | 637 | assert_eq!("OR64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::OR), 0b10100001])); 638 | 639 | assert_eq!("OR64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::OR), 0b10101001])); 640 | 641 | assert_eq!( 642 | "JMP32 R1 -3 ;; Absolute Address", 643 | dis(opts, cur, &[&[byte(1, 0, OpCode::JMP), 0b00000001][..], &(-3i32).to_le_bytes()[..],].concat()) 644 | ); 645 | 646 | assert_eq!( 647 | "JMP32 R1 -3 ;; Relative Address", 648 | dis(opts, cur, &[&[byte(1, 0, OpCode::JMP), 0b00010001][..], &(-3i32).to_le_bytes()[..],].concat()) 649 | ); 650 | 651 | assert_eq!( 652 | "JMP32 @R1(-300, -300) ;; Absolute Address", 653 | dis(opts, cur, &[&[byte(1, 0, OpCode::JMP), 0b00001001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 654 | ); 655 | 656 | assert_eq!( 657 | "JMP32 @R1(-300, -300) ;; Relative Address", 658 | dis(opts, cur, &[&[byte(1, 0, OpCode::JMP), 0b00011001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 659 | ); 660 | 661 | assert_eq!( 662 | "JMP64 1000 ;; Absolute Address", 663 | dis(opts, cur, &[&[byte(0, 1, OpCode::JMP), 0b00000001][..], &(1000u64).to_le_bytes()[..],].concat()) 664 | ); 665 | 666 | assert_eq!( 667 | "JMP64 1000 ;; Relative Address", 668 | dis(opts, cur, &[&[byte(0, 1, OpCode::JMP), 0b00010001][..], &(1000u64).to_le_bytes()[..],].concat()) 669 | ); 670 | 671 | assert_eq!( 672 | "MOVIbw R1, 1000", 673 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVI), 0b00000001][..], &(1000u16).to_le_bytes()[..],].concat()) 674 | ); 675 | 676 | assert_eq!( 677 | "MOVIww R1, 1000", 678 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVI), 0b00010001][..], &(1000u16).to_le_bytes()[..],].concat()) 679 | ); 680 | 681 | assert_eq!( 682 | "MOVIdw R1, 1000", 683 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVI), 0b00100001][..], &(1000u16).to_le_bytes()[..],].concat()) 684 | ); 685 | 686 | assert_eq!( 687 | "MOVIqw R1, 1000", 688 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVI), 0b00110001][..], &(1000u16).to_le_bytes()[..],].concat()) 689 | ); 690 | 691 | assert_eq!( 692 | "MOVIbd R1, 1000", 693 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVI), 0b00000001][..], &(1000u32).to_le_bytes()[..],].concat()) 694 | ); 695 | 696 | assert_eq!( 697 | "MOVIwd R1, 1000", 698 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVI), 0b00010001][..], &(1000u32).to_le_bytes()[..],].concat()) 699 | ); 700 | 701 | assert_eq!( 702 | "MOVIdd R1, 1000", 703 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVI), 0b00100001][..], &(1000u32).to_le_bytes()[..],].concat()) 704 | ); 705 | 706 | assert_eq!( 707 | "MOVIqd R1, 1000", 708 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVI), 0b00110001][..], &(1000u32).to_le_bytes()[..],].concat()) 709 | ); 710 | 711 | assert_eq!( 712 | "MOVIbq R1, 1000", 713 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOVI), 0b00000001][..], &(1000u64).to_le_bytes()[..],].concat()) 714 | ); 715 | 716 | assert_eq!( 717 | "MOVIwq R1, 1000", 718 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOVI), 0b00010001][..], &(1000u64).to_le_bytes()[..],].concat()) 719 | ); 720 | 721 | assert_eq!( 722 | "MOVIdq R1, 1000", 723 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOVI), 0b00100001][..], &(1000u64).to_le_bytes()[..],].concat()) 724 | ); 725 | 726 | assert_eq!( 727 | "MOVIqq R1, 1000", 728 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOVI), 0b00110001][..], &(1000u64).to_le_bytes()[..],].concat()) 729 | ); 730 | 731 | assert_eq!( 732 | "CMPI32weq R1, -1000", 733 | dis(opts, cur, &[&[byte(0, 0, OpCode::CMPIeq), 0b00000001][..], &(-1000i16).to_le_bytes()[..],].concat()) 734 | ); 735 | 736 | assert_eq!( 737 | "CMPI64weq R1, -1000", 738 | dis(opts, cur, &[&[byte(0, 1, OpCode::CMPIeq), 0b00000001][..], &(-1000i16).to_le_bytes()[..],].concat()) 739 | ); 740 | 741 | assert_eq!( 742 | "CMPI32wlte R1, -1000", 743 | dis(opts, cur, &[&[byte(0, 0, OpCode::CMPIlte), 0b00000001][..], &(-1000i16).to_le_bytes()[..],].concat()) 744 | ); 745 | 746 | assert_eq!( 747 | "CMPI64wlte R1, -1000", 748 | dis(opts, cur, &[&[byte(0, 1, OpCode::CMPIlte), 0b00000001][..], &(-1000i16).to_le_bytes()[..],].concat()) 749 | ); 750 | 751 | assert_eq!( 752 | "CMPI32wgte R1, -1000", 753 | dis(opts, cur, &[&[byte(0, 0, OpCode::CMPIgte), 0b00000001][..], &(-1000i16).to_le_bytes()[..],].concat()) 754 | ); 755 | 756 | assert_eq!( 757 | "CMPI64wgte R1, -1000", 758 | dis(opts, cur, &[&[byte(0, 1, OpCode::CMPIgte), 0b00000001][..], &(-1000i16).to_le_bytes()[..],].concat()) 759 | ); 760 | 761 | assert_eq!( 762 | "CMPI32wulte R1, 1000", 763 | dis(opts, cur, &[&[byte(0, 0, OpCode::CMPIulte), 0b00000001][..], &(1000u16).to_le_bytes()[..],].concat()) 764 | ); 765 | 766 | assert_eq!( 767 | "CMPI64wulte R1, 1000", 768 | dis(opts, cur, &[&[byte(0, 1, OpCode::CMPIulte), 0b00000001][..], &(1000u16).to_le_bytes()[..],].concat()) 769 | ); 770 | 771 | assert_eq!( 772 | "CMPI32wugte R1, 1000", 773 | dis(opts, cur, &[&[byte(0, 0, OpCode::CMPIugte), 0b00000001][..], &(1000u16).to_le_bytes()[..],].concat()) 774 | ); 775 | 776 | assert_eq!( 777 | "CMPI64wugte R1, 1000", 778 | dis(opts, cur, &[&[byte(0, 1, OpCode::CMPIugte), 0b00000001][..], &(1000u16).to_le_bytes()[..],].concat()) 779 | ); 780 | 781 | assert_eq!( 782 | "CMPI32deq R1, -1000", 783 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPIeq), 0b00000001][..], &(-1000i32).to_le_bytes()[..],].concat()) 784 | ); 785 | 786 | assert_eq!( 787 | "CMPI64deq R1, -1000", 788 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPIeq), 0b00000001][..], &(-1000i32).to_le_bytes()[..],].concat()) 789 | ); 790 | 791 | assert_eq!( 792 | "CMPI32dlte R1, -1000", 793 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPIlte), 0b00000001][..], &(-1000i32).to_le_bytes()[..],].concat()) 794 | ); 795 | 796 | assert_eq!( 797 | "CMPI64dlte R1, -1000", 798 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPIlte), 0b00000001][..], &(-1000i32).to_le_bytes()[..],].concat()) 799 | ); 800 | 801 | assert_eq!( 802 | "CMPI32dgte R1, -1000", 803 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPIgte), 0b00000001][..], &(-1000i32).to_le_bytes()[..],].concat()) 804 | ); 805 | 806 | assert_eq!( 807 | "CMPI64dgte R1, -1000", 808 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPIgte), 0b00000001][..], &(-1000i32).to_le_bytes()[..],].concat()) 809 | ); 810 | 811 | assert_eq!( 812 | "CMPI32dulte R1, 1000", 813 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPIulte), 0b00000001][..], &(1000u32).to_le_bytes()[..],].concat()) 814 | ); 815 | 816 | assert_eq!( 817 | "CMPI64dulte R1, 1000", 818 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPIulte), 0b00000001][..], &(1000u32).to_le_bytes()[..],].concat()) 819 | ); 820 | 821 | assert_eq!( 822 | "CMPI32dugte R1, 1000", 823 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPIugte), 0b00000001][..], &(1000u32).to_le_bytes()[..],].concat()) 824 | ); 825 | 826 | assert_eq!( 827 | "CMPI64dugte R1, 1000", 828 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPIugte), 0b00000001][..], &(1000u32).to_le_bytes()[..],].concat()) 829 | ); 830 | 831 | assert_eq!( 832 | "CMPI32weq @R1(-3, -3), -1000", 833 | dis( 834 | opts, 835 | cur, 836 | &[ 837 | &[byte(0, 0, OpCode::CMPIeq), 0b00011001][..], 838 | &(36879u16).to_le_bytes()[..], 839 | &(-1000i16).to_le_bytes()[..], 840 | ] 841 | .concat() 842 | ) 843 | ); 844 | 845 | assert_eq!( 846 | "CMPI64weq @R1(-3, -3), -1000", 847 | dis( 848 | opts, 849 | cur, 850 | &[ 851 | &[byte(0, 1, OpCode::CMPIeq), 0b00011001][..], 852 | &(36879u16).to_le_bytes()[..], 853 | &(-1000i16).to_le_bytes()[..], 854 | ] 855 | .concat() 856 | ) 857 | ); 858 | 859 | assert_eq!( 860 | "CMPI32wlte @R1(-3, -3), -1000", 861 | dis( 862 | opts, 863 | cur, 864 | &[ 865 | &[byte(0, 0, OpCode::CMPIlte), 0b00011001][..], 866 | &(36879u16).to_le_bytes()[..], 867 | &(-1000i16).to_le_bytes()[..], 868 | ] 869 | .concat() 870 | ) 871 | ); 872 | 873 | assert_eq!( 874 | "CMPI64wlte @R1(-3, -3), -1000", 875 | dis( 876 | opts, 877 | cur, 878 | &[ 879 | &[byte(0, 1, OpCode::CMPIlte), 0b00011001][..], 880 | &(36879u16).to_le_bytes()[..], 881 | &(-1000i16).to_le_bytes()[..], 882 | ] 883 | .concat() 884 | ) 885 | ); 886 | 887 | assert_eq!( 888 | "CMPI32wgte @R1(-3, -3), -1000", 889 | dis( 890 | opts, 891 | cur, 892 | &[ 893 | &[byte(0, 0, OpCode::CMPIgte), 0b00011001][..], 894 | &(36879u16).to_le_bytes()[..], 895 | &(-1000i16).to_le_bytes()[..], 896 | ] 897 | .concat() 898 | ) 899 | ); 900 | 901 | assert_eq!( 902 | "CMPI64wgte @R1(-3, -3), -1000", 903 | dis( 904 | opts, 905 | cur, 906 | &[ 907 | &[byte(0, 1, OpCode::CMPIgte), 0b00011001][..], 908 | &(36879u16).to_le_bytes()[..], 909 | &(-1000i16).to_le_bytes()[..], 910 | ] 911 | .concat() 912 | ) 913 | ); 914 | 915 | assert_eq!( 916 | "CMPI32wulte @R1(-3, -3), 1000", 917 | dis( 918 | opts, 919 | cur, 920 | &[ 921 | &[byte(0, 0, OpCode::CMPIulte), 0b00011001][..], 922 | &(36879u16).to_le_bytes()[..], 923 | &(1000u16).to_le_bytes()[..], 924 | ] 925 | .concat() 926 | ) 927 | ); 928 | 929 | assert_eq!( 930 | "CMPI64wulte @R1(-3, -3), 1000", 931 | dis( 932 | opts, 933 | cur, 934 | &[ 935 | &[byte(0, 1, OpCode::CMPIulte), 0b00011001][..], 936 | &(36879u16).to_le_bytes()[..], 937 | &(1000u16).to_le_bytes()[..], 938 | ] 939 | .concat() 940 | ) 941 | ); 942 | 943 | assert_eq!( 944 | "CMPI32wugte @R1(-3, -3), 1000", 945 | dis( 946 | opts, 947 | cur, 948 | &[ 949 | &[byte(0, 0, OpCode::CMPIugte), 0b00011001][..], 950 | &(36879u16).to_le_bytes()[..], 951 | &(1000u16).to_le_bytes()[..], 952 | ] 953 | .concat() 954 | ) 955 | ); 956 | 957 | assert_eq!( 958 | "CMPI64wugte @R1(-3, -3), 1000", 959 | dis( 960 | opts, 961 | cur, 962 | &[ 963 | &[byte(0, 1, OpCode::CMPIugte), 0b00011001][..], 964 | &(36879u16).to_le_bytes()[..], 965 | &(1000u16).to_le_bytes()[..], 966 | ] 967 | .concat() 968 | ) 969 | ); 970 | 971 | assert_eq!( 972 | "CMPI32deq @R1(-3, -3), -1000", 973 | dis( 974 | opts, 975 | cur, 976 | &[ 977 | &[byte(1, 0, OpCode::CMPIeq), 0b00011001][..], 978 | &(36879u16).to_le_bytes()[..], 979 | &(-1000i32).to_le_bytes()[..], 980 | ] 981 | .concat() 982 | ) 983 | ); 984 | 985 | assert_eq!( 986 | "CMPI64deq @R1(-3, -3), -1000", 987 | dis( 988 | opts, 989 | cur, 990 | &[ 991 | &[byte(1, 1, OpCode::CMPIeq), 0b00011001][..], 992 | &(36879u16).to_le_bytes()[..], 993 | &(-1000i32).to_le_bytes()[..], 994 | ] 995 | .concat() 996 | ) 997 | ); 998 | 999 | assert_eq!( 1000 | "CMPI32dlte @R1(-3, -3), -1000", 1001 | dis( 1002 | opts, 1003 | cur, 1004 | &[ 1005 | &[byte(1, 0, OpCode::CMPIlte), 0b00011001][..], 1006 | &(36879u16).to_le_bytes()[..], 1007 | &(-1000i32).to_le_bytes()[..], 1008 | ] 1009 | .concat() 1010 | ) 1011 | ); 1012 | 1013 | assert_eq!( 1014 | "CMPI64dlte @R1(-3, -3), -1000", 1015 | dis( 1016 | opts, 1017 | cur, 1018 | &[ 1019 | &[byte(1, 1, OpCode::CMPIlte), 0b00011001][..], 1020 | &(36879u16).to_le_bytes()[..], 1021 | &(-1000i32).to_le_bytes()[..], 1022 | ] 1023 | .concat() 1024 | ) 1025 | ); 1026 | 1027 | assert_eq!( 1028 | "CMPI32dgte @R1(-3, -3), -1000", 1029 | dis( 1030 | opts, 1031 | cur, 1032 | &[ 1033 | &[byte(1, 0, OpCode::CMPIgte), 0b00011001][..], 1034 | &(36879u16).to_le_bytes()[..], 1035 | &(-1000i32).to_le_bytes()[..], 1036 | ] 1037 | .concat() 1038 | ) 1039 | ); 1040 | 1041 | assert_eq!( 1042 | "CMPI64dgte @R1(-3, -3), -1000", 1043 | dis( 1044 | opts, 1045 | cur, 1046 | &[ 1047 | &[byte(1, 1, OpCode::CMPIgte), 0b00011001][..], 1048 | &(36879u16).to_le_bytes()[..], 1049 | &(-1000i32).to_le_bytes()[..], 1050 | ] 1051 | .concat() 1052 | ) 1053 | ); 1054 | 1055 | assert_eq!( 1056 | "CMPI32dulte @R1(-3, -3), 1000", 1057 | dis( 1058 | opts, 1059 | cur, 1060 | &[ 1061 | &[byte(1, 0, OpCode::CMPIulte), 0b00011001][..], 1062 | &(36879u16).to_le_bytes()[..], 1063 | &(1000u32).to_le_bytes()[..], 1064 | ] 1065 | .concat() 1066 | ) 1067 | ); 1068 | 1069 | assert_eq!( 1070 | "CMPI64dulte @R1(-3, -3), 1000", 1071 | dis( 1072 | opts, 1073 | cur, 1074 | &[ 1075 | &[byte(1, 1, OpCode::CMPIulte), 0b00011001][..], 1076 | &(36879u16).to_le_bytes()[..], 1077 | &(1000u32).to_le_bytes()[..], 1078 | ] 1079 | .concat() 1080 | ) 1081 | ); 1082 | 1083 | assert_eq!( 1084 | "CMPI32dugte @R1(-3, -3), 1000", 1085 | dis( 1086 | opts, 1087 | cur, 1088 | &[ 1089 | &[byte(1, 0, OpCode::CMPIugte), 0b00011001][..], 1090 | &(36879u16).to_le_bytes()[..], 1091 | &(1000u32).to_le_bytes()[..], 1092 | ] 1093 | .concat() 1094 | ) 1095 | ); 1096 | 1097 | assert_eq!( 1098 | "CMPI64dugte @R1(-3, -3), 1000", 1099 | dis( 1100 | opts, 1101 | cur, 1102 | &[ 1103 | &[byte(1, 1, OpCode::CMPIugte), 0b00011001][..], 1104 | &(36879u16).to_le_bytes()[..], 1105 | &(1000u32).to_le_bytes()[..], 1106 | ] 1107 | .concat() 1108 | ) 1109 | ); 1110 | 1111 | assert_eq!( 1112 | "MOVInw R1, (-3, -3)", 1113 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVIn), 0b00000001][..], &(36879u16).to_le_bytes()[..],].concat()) 1114 | ); 1115 | 1116 | assert_eq!( 1117 | "MOVInd R1, (-300, -300)", 1118 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVIn), 0b00000001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1119 | ); 1120 | 1121 | assert_eq!( 1122 | "MOVInq R1, (-30000, -30000)", 1123 | dis( 1124 | opts, 1125 | cur, 1126 | &[&[byte(1, 1, OpCode::MOVIn), 0b00000001][..], &(11529215048034579760u64).to_le_bytes()[..],].concat() 1127 | ) 1128 | ); 1129 | 1130 | assert_eq!( 1131 | "MOVInw @R1(-3, -3), (-3, -3)", 1132 | dis( 1133 | opts, 1134 | cur, 1135 | &[ 1136 | &[byte(0, 1, OpCode::MOVIn), 0b01001001][..], 1137 | &(36879u16).to_le_bytes()[..], 1138 | &(36879u16).to_le_bytes()[..], 1139 | ] 1140 | .concat() 1141 | ) 1142 | ); 1143 | 1144 | assert_eq!( 1145 | "MOVInd @R1(-3, -3), (-300, -300)", 1146 | dis( 1147 | opts, 1148 | cur, 1149 | &[ 1150 | &[byte(1, 0, OpCode::MOVIn), 0b01001001][..], 1151 | &(36879u16).to_le_bytes()[..], 1152 | &(2954019116u32).to_le_bytes()[..], 1153 | ] 1154 | .concat() 1155 | ) 1156 | ); 1157 | 1158 | assert_eq!( 1159 | "MOVInq @R1(-3, -3), (-30000, -30000)", 1160 | dis( 1161 | opts, 1162 | cur, 1163 | &[ 1164 | &[byte(1, 1, OpCode::MOVIn), 0b01001001][..], 1165 | &(36879u16).to_le_bytes()[..], 1166 | &(11529215048034579760u64).to_le_bytes()[..], 1167 | ] 1168 | .concat() 1169 | ) 1170 | ); 1171 | 1172 | assert_eq!( 1173 | "MOVRELw R1, -1000", 1174 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVREL), 0b00000001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1175 | ); 1176 | 1177 | assert_eq!( 1178 | "MOVRELd R1, -1000", 1179 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVREL), 0b00000001][..], &(-1000i32).to_le_bytes()[..],].concat()) 1180 | ); 1181 | 1182 | assert_eq!( 1183 | "MOVRELq R1, -1000", 1184 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOVREL), 0b00000001][..], &(-1000i64).to_le_bytes()[..],].concat()) 1185 | ); 1186 | 1187 | assert_eq!( 1188 | "MOVRELw @R1(-3, -3), -1000", 1189 | dis( 1190 | opts, 1191 | cur, 1192 | &[ 1193 | &[byte(0, 1, OpCode::MOVREL), 0b01001001][..], 1194 | &(36879u16).to_le_bytes()[..], 1195 | &(-1000i16).to_le_bytes()[..], 1196 | ] 1197 | .concat() 1198 | ) 1199 | ); 1200 | 1201 | assert_eq!( 1202 | "MOVRELd @R1(-3, -3), -1000", 1203 | dis( 1204 | opts, 1205 | cur, 1206 | &[ 1207 | &[byte(1, 0, OpCode::MOVREL), 0b01001001][..], 1208 | &(36879u16).to_le_bytes()[..], 1209 | &(-1000i32).to_le_bytes()[..], 1210 | ] 1211 | .concat() 1212 | ) 1213 | ); 1214 | 1215 | assert_eq!( 1216 | "MOVRELq @R1(-3, -3), -1000", 1217 | dis( 1218 | opts, 1219 | cur, 1220 | &[ 1221 | &[byte(1, 1, OpCode::MOVREL), 0b01001001][..], 1222 | &(36879u16).to_le_bytes()[..], 1223 | &(-1000i64).to_le_bytes()[..], 1224 | ] 1225 | .concat() 1226 | ) 1227 | ); 1228 | 1229 | assert_eq!( 1230 | "MOVnw R1, R2 -1000", 1231 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVnw), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1232 | ); 1233 | 1234 | assert_eq!( 1235 | "MOVnd R1, R2 -1000", 1236 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVnd), 0b00100001][..], &(-1000i32).to_le_bytes()[..],].concat()) 1237 | ); 1238 | 1239 | assert_eq!( 1240 | "MOVnw @R1, R2 -1000", 1241 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVnw), 0b00101001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1242 | ); 1243 | 1244 | assert_eq!( 1245 | "MOVnd @R1, R2 -1000", 1246 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVnd), 0b00101001][..], &(-1000i32).to_le_bytes()[..],].concat()) 1247 | ); 1248 | 1249 | assert_eq!( 1250 | "MOVnw @R1, @R2(-3, -3)", 1251 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVnw), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1252 | ); 1253 | 1254 | assert_eq!( 1255 | "MOVnd @R1, @R2(-300, -300)", 1256 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVnd), 0b10101001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1257 | ); 1258 | 1259 | assert_eq!( 1260 | "MOVnw @R1(-3, -3), R2 -1000", 1261 | dis( 1262 | opts, 1263 | cur, 1264 | &[ 1265 | &[byte(1, 1, OpCode::MOVnw), 0b00101001][..], 1266 | &(36879u16).to_le_bytes()[..], 1267 | &(-1000i16).to_le_bytes()[..], 1268 | ] 1269 | .concat() 1270 | ) 1271 | ); 1272 | 1273 | assert_eq!( 1274 | "MOVnd @R1(-300, -300), R2 -1000", 1275 | dis( 1276 | opts, 1277 | cur, 1278 | &[ 1279 | &[byte(1, 1, OpCode::MOVnd), 0b00101001][..], 1280 | &(2954019116u32).to_le_bytes()[..], 1281 | &(-1000i32).to_le_bytes()[..], 1282 | ] 1283 | .concat() 1284 | ) 1285 | ); 1286 | 1287 | assert_eq!( 1288 | "MOVnw @R1(-3, -3), @R2(-3, -3)", 1289 | dis( 1290 | opts, 1291 | cur, 1292 | &[ 1293 | &[byte(1, 1, OpCode::MOVnw), 0b10101001][..], 1294 | &(36879u16).to_le_bytes()[..], 1295 | &(36879u16).to_le_bytes()[..], 1296 | ] 1297 | .concat() 1298 | ) 1299 | ); 1300 | 1301 | assert_eq!( 1302 | "MOVnd @R1(-300, -300), @R2(-300, -300)", 1303 | dis( 1304 | opts, 1305 | cur, 1306 | &[ 1307 | &[byte(1, 1, OpCode::MOVnd), 0b10101001][..], 1308 | &(2954019116u32).to_le_bytes()[..], 1309 | &(2954019116u32).to_le_bytes()[..], 1310 | ] 1311 | .concat() 1312 | ) 1313 | ); 1314 | 1315 | assert_eq!( 1316 | "MOVsnw R1, R2 -1000", 1317 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVsnw), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1318 | ); 1319 | 1320 | assert_eq!( 1321 | "MOVsnd R1, R2 -1000", 1322 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVsnd), 0b00100001][..], &(-1000i32).to_le_bytes()[..],].concat()) 1323 | ); 1324 | 1325 | assert_eq!( 1326 | "MOVsnw @R1, R2 -1000", 1327 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVsnw), 0b00101001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1328 | ); 1329 | 1330 | assert_eq!( 1331 | "MOVsnd @R1, R2 -1000", 1332 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVsnd), 0b00101001][..], &(-1000i32).to_le_bytes()[..],].concat()) 1333 | ); 1334 | 1335 | assert_eq!( 1336 | "MOVsnw @R1, @R2(-3, -3)", 1337 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVsnw), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1338 | ); 1339 | 1340 | assert_eq!( 1341 | "MOVsnd @R1, @R2(-300, -300)", 1342 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVsnd), 0b10101001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1343 | ); 1344 | 1345 | assert_eq!( 1346 | "MOVsnw @R1(-3, -3), R2 -1000", 1347 | dis( 1348 | opts, 1349 | cur, 1350 | &[ 1351 | &[byte(1, 1, OpCode::MOVsnw), 0b00101001][..], 1352 | &(36879u16).to_le_bytes()[..], 1353 | &(-1000i16).to_le_bytes()[..], 1354 | ] 1355 | .concat() 1356 | ) 1357 | ); 1358 | 1359 | assert_eq!( 1360 | "MOVsnd @R1(-300, -300), R2 -1000", 1361 | dis( 1362 | opts, 1363 | cur, 1364 | &[ 1365 | &[byte(1, 1, OpCode::MOVsnd), 0b00101001][..], 1366 | &(2954019116u32).to_le_bytes()[..], 1367 | &(-1000i32).to_le_bytes()[..], 1368 | ] 1369 | .concat() 1370 | ) 1371 | ); 1372 | 1373 | assert_eq!( 1374 | "MOVsnw @R1(-3, -3), @R2(-3, -3)", 1375 | dis( 1376 | opts, 1377 | cur, 1378 | &[ 1379 | &[byte(1, 1, OpCode::MOVsnw), 0b10101001][..], 1380 | &(36879u16).to_le_bytes()[..], 1381 | &(36879u16).to_le_bytes()[..], 1382 | ] 1383 | .concat() 1384 | ) 1385 | ); 1386 | 1387 | assert_eq!( 1388 | "MOVsnd @R1(-300, -300), @R2(-300, -300)", 1389 | dis( 1390 | opts, 1391 | cur, 1392 | &[ 1393 | &[byte(1, 1, OpCode::MOVsnd), 0b10101001][..], 1394 | &(2954019116u32).to_le_bytes()[..], 1395 | &(2954019116u32).to_le_bytes()[..], 1396 | ] 1397 | .concat() 1398 | ) 1399 | ); 1400 | 1401 | assert_eq!( 1402 | "MOVbw @R1(-3, -3), R2", 1403 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVbw), 0b00101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1404 | ); 1405 | 1406 | assert_eq!( 1407 | "MOVww @R1(-3, -3), R2", 1408 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVww), 0b00101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1409 | ); 1410 | 1411 | assert_eq!( 1412 | "MOVdw @R1(-3, -3), R2", 1413 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVdw), 0b00101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1414 | ); 1415 | 1416 | assert_eq!( 1417 | "MOVqw @R1(-3, -3), R2", 1418 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVqw), 0b00101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1419 | ); 1420 | 1421 | assert_eq!( 1422 | "MOVbw @R1(-3, -3), @R2", 1423 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVbw), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1424 | ); 1425 | 1426 | assert_eq!( 1427 | "MOVww @R1(-3, -3), @R2", 1428 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVww), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1429 | ); 1430 | 1431 | assert_eq!( 1432 | "MOVdw @R1(-3, -3), @R2", 1433 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVdw), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1434 | ); 1435 | 1436 | assert_eq!( 1437 | "MOVqw @R1(-3, -3), @R2", 1438 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVqw), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1439 | ); 1440 | 1441 | assert_eq!( 1442 | "MOVbw R1, @R2(-3, -3)", 1443 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVbw), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1444 | ); 1445 | 1446 | assert_eq!( 1447 | "MOVww R1, @R2(-3, -3)", 1448 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVww), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1449 | ); 1450 | 1451 | assert_eq!( 1452 | "MOVdw R1, @R2(-3, -3)", 1453 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVdw), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1454 | ); 1455 | 1456 | assert_eq!( 1457 | "MOVqw R1, @R2(-3, -3)", 1458 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVqw), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1459 | ); 1460 | 1461 | assert_eq!( 1462 | "MOVbw @R1(-3, -3), @R2(-3, -3)", 1463 | dis( 1464 | opts, 1465 | cur, 1466 | &[ 1467 | &[byte(1, 1, OpCode::MOVbw), 0b10101001][..], 1468 | &(36879u16).to_le_bytes()[..], 1469 | &(36879u16).to_le_bytes()[..], 1470 | ] 1471 | .concat() 1472 | ) 1473 | ); 1474 | 1475 | assert_eq!( 1476 | "MOVww @R1(-3, -3), @R2(-3, -3)", 1477 | dis( 1478 | opts, 1479 | cur, 1480 | &[ 1481 | &[byte(1, 1, OpCode::MOVww), 0b10101001][..], 1482 | &(36879u16).to_le_bytes()[..], 1483 | &(36879u16).to_le_bytes()[..], 1484 | ] 1485 | .concat() 1486 | ) 1487 | ); 1488 | 1489 | assert_eq!( 1490 | "MOVdw @R1(-3, -3), @R2(-3, -3)", 1491 | dis( 1492 | opts, 1493 | cur, 1494 | &[ 1495 | &[byte(1, 1, OpCode::MOVdw), 0b10101001][..], 1496 | &(36879u16).to_le_bytes()[..], 1497 | &(36879u16).to_le_bytes()[..], 1498 | ] 1499 | .concat() 1500 | ) 1501 | ); 1502 | 1503 | assert_eq!( 1504 | "MOVqw @R1(-3, -3), @R2(-3, -3)", 1505 | dis( 1506 | opts, 1507 | cur, 1508 | &[ 1509 | &[byte(1, 1, OpCode::MOVqw), 0b10101001][..], 1510 | &(36879u16).to_le_bytes()[..], 1511 | &(36879u16).to_le_bytes()[..], 1512 | ] 1513 | .concat() 1514 | ) 1515 | ); 1516 | 1517 | assert_eq!( 1518 | "MOVbd @R1(-300, -300), R2", 1519 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVbd), 0b00101001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1520 | ); 1521 | 1522 | assert_eq!( 1523 | "MOVwd @R1(-300, -300), R2", 1524 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVwd), 0b00101001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1525 | ); 1526 | 1527 | assert_eq!( 1528 | "MOVdd @R1(-300, -300), R2", 1529 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVdd), 0b00101001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1530 | ); 1531 | 1532 | assert_eq!( 1533 | "MOVqd @R1(-300, -300), R2", 1534 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVqd), 0b00101001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1535 | ); 1536 | 1537 | assert_eq!( 1538 | "MOVbd @R1(-300, -300), @R2", 1539 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVbd), 0b10101001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1540 | ); 1541 | 1542 | assert_eq!( 1543 | "MOVwd @R1(-300, -300), @R2", 1544 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVwd), 0b10101001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1545 | ); 1546 | 1547 | assert_eq!( 1548 | "MOVdd @R1(-300, -300), @R2", 1549 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVdd), 0b10101001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1550 | ); 1551 | 1552 | assert_eq!( 1553 | "MOVqd @R1(-300, -300), @R2", 1554 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVqd), 0b10101001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1555 | ); 1556 | 1557 | assert_eq!( 1558 | "MOVbd R1, @R2(-300, -300)", 1559 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVbd), 0b10100001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1560 | ); 1561 | 1562 | assert_eq!( 1563 | "MOVwd R1, @R2(-300, -300)", 1564 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVwd), 0b10100001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1565 | ); 1566 | 1567 | assert_eq!( 1568 | "MOVdd R1, @R2(-300, -300)", 1569 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVdd), 0b10100001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1570 | ); 1571 | 1572 | assert_eq!( 1573 | "MOVqd R1, @R2(-300, -300)", 1574 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVqd), 0b10100001][..], &(2954019116u32).to_le_bytes()[..],].concat()) 1575 | ); 1576 | 1577 | assert_eq!( 1578 | "MOVbd @R1(-300, -300), @R2(-300, -300)", 1579 | dis( 1580 | opts, 1581 | cur, 1582 | &[ 1583 | &[byte(1, 1, OpCode::MOVbd), 0b10101001][..], 1584 | &(2954019116u32).to_le_bytes()[..], 1585 | &(2954019116u32).to_le_bytes()[..], 1586 | ] 1587 | .concat() 1588 | ) 1589 | ); 1590 | 1591 | assert_eq!( 1592 | "MOVwd @R1(-300, -300), @R2(-300, -300)", 1593 | dis( 1594 | opts, 1595 | cur, 1596 | &[ 1597 | &[byte(1, 1, OpCode::MOVwd), 0b10101001][..], 1598 | &(2954019116u32).to_le_bytes()[..], 1599 | &(2954019116u32).to_le_bytes()[..], 1600 | ] 1601 | .concat() 1602 | ) 1603 | ); 1604 | 1605 | assert_eq!( 1606 | "MOVdd @R1(-300, -300), @R2(-300, -300)", 1607 | dis( 1608 | opts, 1609 | cur, 1610 | &[ 1611 | &[byte(1, 1, OpCode::MOVdd), 0b10101001][..], 1612 | &(2954019116u32).to_le_bytes()[..], 1613 | &(2954019116u32).to_le_bytes()[..], 1614 | ] 1615 | .concat() 1616 | ) 1617 | ); 1618 | 1619 | assert_eq!( 1620 | "MOVqd @R1(-300, -300), @R2(-300, -300)", 1621 | dis( 1622 | opts, 1623 | cur, 1624 | &[ 1625 | &[byte(1, 1, OpCode::MOVqd), 0b10101001][..], 1626 | &(2954019116u32).to_le_bytes()[..], 1627 | &(2954019116u32).to_le_bytes()[..], 1628 | ] 1629 | .concat() 1630 | ) 1631 | ); 1632 | 1633 | assert_eq!( 1634 | "MOVqq @R1(-30000, -30000), R2", 1635 | dis( 1636 | opts, 1637 | cur, 1638 | &[&[byte(1, 0, OpCode::MOVqq), 0b00101001][..], &(11529215048034579760u64).to_le_bytes()[..],].concat() 1639 | ) 1640 | ); 1641 | 1642 | assert_eq!( 1643 | "MOVqq @R1(-30000, -30000), @R2", 1644 | dis( 1645 | opts, 1646 | cur, 1647 | &[&[byte(1, 0, OpCode::MOVqq), 0b10101001][..], &(11529215048034579760u64).to_le_bytes()[..],].concat() 1648 | ) 1649 | ); 1650 | 1651 | assert_eq!( 1652 | "MOVqq R1, @R2(-30000, -30000)", 1653 | dis( 1654 | opts, 1655 | cur, 1656 | &[&[byte(0, 1, OpCode::MOVqq), 0b10100001][..], &(11529215048034579760u64).to_le_bytes()[..],].concat() 1657 | ) 1658 | ); 1659 | 1660 | assert_eq!( 1661 | "MOVqq @R1(-30000, -30000), @R2(-30000, -30000)", 1662 | dis( 1663 | opts, 1664 | cur, 1665 | &[ 1666 | &[byte(1, 1, OpCode::MOVqq), 0b10101001][..], 1667 | &(11529215048034579760u64).to_le_bytes()[..], 1668 | &(11529215048034579760u64).to_le_bytes()[..], 1669 | ] 1670 | .concat() 1671 | ) 1672 | ); 1673 | 1674 | assert_eq!( 1675 | "ADD32 R1, R2 -1000", 1676 | dis(opts, cur, &[&[byte(1, 0, OpCode::ADD), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1677 | ); 1678 | 1679 | assert_eq!( 1680 | "ADD32 R1, @R2(-3, -3)", 1681 | dis(opts, cur, &[&[byte(1, 0, OpCode::ADD), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1682 | ); 1683 | 1684 | assert_eq!( 1685 | "ADD32 @R1, @R2(-3, -3)", 1686 | dis(opts, cur, &[&[byte(1, 0, OpCode::ADD), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1687 | ); 1688 | 1689 | assert_eq!( 1690 | "ADD64 R1, R2 -1000", 1691 | dis(opts, cur, &[&[byte(1, 1, OpCode::ADD), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1692 | ); 1693 | 1694 | assert_eq!( 1695 | "ADD64 R1, @R2(-3, -3)", 1696 | dis(opts, cur, &[&[byte(1, 1, OpCode::ADD), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1697 | ); 1698 | 1699 | assert_eq!( 1700 | "ADD64 @R1, @R2(-3, -3)", 1701 | dis(opts, cur, &[&[byte(1, 1, OpCode::ADD), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1702 | ); 1703 | 1704 | assert_eq!( 1705 | "AND32 R1, R2 -1000", 1706 | dis(opts, cur, &[&[byte(1, 0, OpCode::AND), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1707 | ); 1708 | 1709 | assert_eq!( 1710 | "AND32 R1, @R2(-3, -3)", 1711 | dis(opts, cur, &[&[byte(1, 0, OpCode::AND), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1712 | ); 1713 | 1714 | assert_eq!( 1715 | "AND32 @R1, @R2(-3, -3)", 1716 | dis(opts, cur, &[&[byte(1, 0, OpCode::AND), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1717 | ); 1718 | 1719 | assert_eq!( 1720 | "AND64 R1, R2 -1000", 1721 | dis(opts, cur, &[&[byte(1, 1, OpCode::AND), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1722 | ); 1723 | 1724 | assert_eq!( 1725 | "AND64 R1, @R2(-3, -3)", 1726 | dis(opts, cur, &[&[byte(1, 1, OpCode::AND), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1727 | ); 1728 | 1729 | assert_eq!( 1730 | "AND64 @R1, @R2(-3, -3)", 1731 | dis(opts, cur, &[&[byte(1, 1, OpCode::AND), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1732 | ); 1733 | 1734 | assert_eq!( 1735 | "ASHR32 R1, R2 -1000", 1736 | dis(opts, cur, &[&[byte(1, 0, OpCode::ASHR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1737 | ); 1738 | 1739 | assert_eq!( 1740 | "ASHR32 R1, @R2(-3, -3)", 1741 | dis(opts, cur, &[&[byte(1, 0, OpCode::ASHR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1742 | ); 1743 | 1744 | assert_eq!( 1745 | "ASHR32 @R1, @R2(-3, -3)", 1746 | dis(opts, cur, &[&[byte(1, 0, OpCode::ASHR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1747 | ); 1748 | 1749 | assert_eq!( 1750 | "ASHR64 R1, R2 -1000", 1751 | dis(opts, cur, &[&[byte(1, 1, OpCode::ASHR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1752 | ); 1753 | 1754 | assert_eq!( 1755 | "ASHR64 R1, @R2(-3, -3)", 1756 | dis(opts, cur, &[&[byte(1, 1, OpCode::ASHR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1757 | ); 1758 | 1759 | assert_eq!( 1760 | "ASHR64 @R1, @R2(-3, -3)", 1761 | dis(opts, cur, &[&[byte(1, 1, OpCode::ASHR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1762 | ); 1763 | 1764 | assert_eq!( 1765 | "DIV32 R1, R2 -1000", 1766 | dis(opts, cur, &[&[byte(1, 0, OpCode::DIV), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1767 | ); 1768 | 1769 | assert_eq!( 1770 | "DIV32 R1, @R2(-3, -3)", 1771 | dis(opts, cur, &[&[byte(1, 0, OpCode::DIV), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1772 | ); 1773 | 1774 | assert_eq!( 1775 | "DIV32 @R1, @R2(-3, -3)", 1776 | dis(opts, cur, &[&[byte(1, 0, OpCode::DIV), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1777 | ); 1778 | 1779 | assert_eq!( 1780 | "DIV64 R1, R2 -1000", 1781 | dis(opts, cur, &[&[byte(1, 1, OpCode::DIV), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1782 | ); 1783 | 1784 | assert_eq!( 1785 | "DIV64 R1, @R2(-3, -3)", 1786 | dis(opts, cur, &[&[byte(1, 1, OpCode::DIV), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1787 | ); 1788 | 1789 | assert_eq!( 1790 | "DIV64 @R1, @R2(-3, -3)", 1791 | dis(opts, cur, &[&[byte(1, 1, OpCode::DIV), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1792 | ); 1793 | 1794 | assert_eq!( 1795 | "DIVU32 R1, R2 -1000", 1796 | dis(opts, cur, &[&[byte(1, 0, OpCode::DIVU), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1797 | ); 1798 | 1799 | assert_eq!( 1800 | "DIVU32 R1, @R2(-3, -3)", 1801 | dis(opts, cur, &[&[byte(1, 0, OpCode::DIVU), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1802 | ); 1803 | 1804 | assert_eq!( 1805 | "DIVU32 @R1, @R2(-3, -3)", 1806 | dis(opts, cur, &[&[byte(1, 0, OpCode::DIVU), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1807 | ); 1808 | 1809 | assert_eq!( 1810 | "DIVU64 R1, R2 -1000", 1811 | dis(opts, cur, &[&[byte(1, 1, OpCode::DIVU), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1812 | ); 1813 | 1814 | assert_eq!( 1815 | "DIVU64 R1, @R2(-3, -3)", 1816 | dis(opts, cur, &[&[byte(1, 1, OpCode::DIVU), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1817 | ); 1818 | 1819 | assert_eq!( 1820 | "DIVU64 @R1, @R2(-3, -3)", 1821 | dis(opts, cur, &[&[byte(1, 1, OpCode::DIVU), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1822 | ); 1823 | 1824 | assert_eq!( 1825 | "EXTNDB32 R1, R2 -1000", 1826 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDB), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1827 | ); 1828 | 1829 | assert_eq!( 1830 | "EXTNDB32 R1, @R2(-3, -3)", 1831 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDB), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1832 | ); 1833 | 1834 | assert_eq!( 1835 | "EXTNDB32 @R1, @R2(-3, -3)", 1836 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDB), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1837 | ); 1838 | 1839 | assert_eq!( 1840 | "EXTNDB64 R1, R2 -1000", 1841 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDB), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1842 | ); 1843 | 1844 | assert_eq!( 1845 | "EXTNDB64 R1, @R2(-3, -3)", 1846 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDB), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1847 | ); 1848 | 1849 | assert_eq!( 1850 | "EXTNDB64 @R1, @R2(-3, -3)", 1851 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDB), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1852 | ); 1853 | 1854 | assert_eq!( 1855 | "EXTNDD32 R1, R2 -1000", 1856 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDD), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1857 | ); 1858 | 1859 | assert_eq!( 1860 | "EXTNDD32 R1, @R2(-3, -3)", 1861 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDD), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1862 | ); 1863 | 1864 | assert_eq!( 1865 | "EXTNDD32 @R1, @R2(-3, -3)", 1866 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDD), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1867 | ); 1868 | 1869 | assert_eq!( 1870 | "EXTNDD64 R1, R2 -1000", 1871 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDD), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1872 | ); 1873 | 1874 | assert_eq!( 1875 | "EXTNDD64 R1, @R2(-3, -3)", 1876 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDD), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1877 | ); 1878 | 1879 | assert_eq!( 1880 | "EXTNDD64 @R1, @R2(-3, -3)", 1881 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDD), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1882 | ); 1883 | 1884 | assert_eq!( 1885 | "EXTNDW32 R1, R2 -1000", 1886 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDW), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1887 | ); 1888 | 1889 | assert_eq!( 1890 | "EXTNDW32 R1, @R2(-3, -3)", 1891 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDW), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1892 | ); 1893 | 1894 | assert_eq!( 1895 | "EXTNDW32 @R1, @R2(-3, -3)", 1896 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDW), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1897 | ); 1898 | 1899 | assert_eq!( 1900 | "EXTNDW64 R1, R2 -1000", 1901 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDW), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1902 | ); 1903 | 1904 | assert_eq!( 1905 | "EXTNDW64 R1, @R2(-3, -3)", 1906 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDW), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1907 | ); 1908 | 1909 | assert_eq!( 1910 | "EXTNDW64 @R1, @R2(-3, -3)", 1911 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDW), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1912 | ); 1913 | 1914 | assert_eq!( 1915 | "MOD32 R1, R2 -1000", 1916 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOD), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1917 | ); 1918 | 1919 | assert_eq!( 1920 | "MOD32 R1, @R2(-3, -3)", 1921 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOD), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1922 | ); 1923 | 1924 | assert_eq!( 1925 | "MOD32 @R1, @R2(-3, -3)", 1926 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOD), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1927 | ); 1928 | 1929 | assert_eq!( 1930 | "MOD64 R1, R2 -1000", 1931 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOD), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1932 | ); 1933 | 1934 | assert_eq!( 1935 | "MOD64 R1, @R2(-3, -3)", 1936 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOD), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1937 | ); 1938 | 1939 | assert_eq!( 1940 | "MOD64 @R1, @R2(-3, -3)", 1941 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOD), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1942 | ); 1943 | 1944 | assert_eq!( 1945 | "MODU32 R1, R2 -1000", 1946 | dis(opts, cur, &[&[byte(1, 0, OpCode::MODU), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1947 | ); 1948 | 1949 | assert_eq!( 1950 | "MODU32 R1, @R2(-3, -3)", 1951 | dis(opts, cur, &[&[byte(1, 0, OpCode::MODU), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1952 | ); 1953 | 1954 | assert_eq!( 1955 | "MODU32 @R1, @R2(-3, -3)", 1956 | dis(opts, cur, &[&[byte(1, 0, OpCode::MODU), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1957 | ); 1958 | 1959 | assert_eq!( 1960 | "MODU64 R1, R2 -1000", 1961 | dis(opts, cur, &[&[byte(1, 1, OpCode::MODU), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1962 | ); 1963 | 1964 | assert_eq!( 1965 | "MODU64 R1, @R2(-3, -3)", 1966 | dis(opts, cur, &[&[byte(1, 1, OpCode::MODU), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1967 | ); 1968 | 1969 | assert_eq!( 1970 | "MODU64 @R1, @R2(-3, -3)", 1971 | dis(opts, cur, &[&[byte(1, 1, OpCode::MODU), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1972 | ); 1973 | 1974 | assert_eq!( 1975 | "SHL32 R1, R2 -1000", 1976 | dis(opts, cur, &[&[byte(1, 0, OpCode::SHL), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1977 | ); 1978 | 1979 | assert_eq!( 1980 | "SHL32 R1, @R2(-3, -3)", 1981 | dis(opts, cur, &[&[byte(1, 0, OpCode::SHL), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1982 | ); 1983 | 1984 | assert_eq!( 1985 | "SHL32 @R1, @R2(-3, -3)", 1986 | dis(opts, cur, &[&[byte(1, 0, OpCode::SHL), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 1987 | ); 1988 | 1989 | assert_eq!( 1990 | "SHL64 R1, R2 -1000", 1991 | dis(opts, cur, &[&[byte(1, 1, OpCode::SHL), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 1992 | ); 1993 | 1994 | assert_eq!( 1995 | "SHL64 R1, @R2(-3, -3)", 1996 | dis(opts, cur, &[&[byte(1, 1, OpCode::SHL), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 1997 | ); 1998 | 1999 | assert_eq!( 2000 | "SHL64 @R1, @R2(-3, -3)", 2001 | dis(opts, cur, &[&[byte(1, 1, OpCode::SHL), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2002 | ); 2003 | 2004 | assert_eq!( 2005 | "SHR32 R1, R2 -1000", 2006 | dis(opts, cur, &[&[byte(1, 0, OpCode::SHR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2007 | ); 2008 | 2009 | assert_eq!( 2010 | "SHR32 R1, @R2(-3, -3)", 2011 | dis(opts, cur, &[&[byte(1, 0, OpCode::SHR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2012 | ); 2013 | 2014 | assert_eq!( 2015 | "SHR32 @R1, @R2(-3, -3)", 2016 | dis(opts, cur, &[&[byte(1, 0, OpCode::SHR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2017 | ); 2018 | 2019 | assert_eq!( 2020 | "SHR64 R1, R2 -1000", 2021 | dis(opts, cur, &[&[byte(1, 1, OpCode::SHR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2022 | ); 2023 | 2024 | assert_eq!( 2025 | "SHR64 R1, @R2(-3, -3)", 2026 | dis(opts, cur, &[&[byte(1, 1, OpCode::SHR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2027 | ); 2028 | 2029 | assert_eq!( 2030 | "SHR64 @R1, @R2(-3, -3)", 2031 | dis(opts, cur, &[&[byte(1, 1, OpCode::SHR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2032 | ); 2033 | 2034 | assert_eq!( 2035 | "SUB32 R1, R2 -1000", 2036 | dis(opts, cur, &[&[byte(1, 0, OpCode::SUB), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2037 | ); 2038 | 2039 | assert_eq!( 2040 | "SUB32 R1, @R2(-3, -3)", 2041 | dis(opts, cur, &[&[byte(1, 0, OpCode::SUB), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2042 | ); 2043 | 2044 | assert_eq!( 2045 | "SUB32 @R1, @R2(-3, -3)", 2046 | dis(opts, cur, &[&[byte(1, 0, OpCode::SUB), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2047 | ); 2048 | 2049 | assert_eq!( 2050 | "SUB64 R1, R2 -1000", 2051 | dis(opts, cur, &[&[byte(1, 1, OpCode::SUB), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2052 | ); 2053 | 2054 | assert_eq!( 2055 | "SUB64 R1, @R2(-3, -3)", 2056 | dis(opts, cur, &[&[byte(1, 1, OpCode::SUB), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2057 | ); 2058 | 2059 | assert_eq!( 2060 | "SUB64 @R1, @R2(-3, -3)", 2061 | dis(opts, cur, &[&[byte(1, 1, OpCode::SUB), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2062 | ); 2063 | 2064 | assert_eq!( 2065 | "XOR32 R1, R2 -1000", 2066 | dis(opts, cur, &[&[byte(1, 0, OpCode::XOR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2067 | ); 2068 | 2069 | assert_eq!( 2070 | "XOR32 R1, @R2(-3, -3)", 2071 | dis(opts, cur, &[&[byte(1, 0, OpCode::XOR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2072 | ); 2073 | 2074 | assert_eq!( 2075 | "XOR32 @R1, @R2(-3, -3)", 2076 | dis(opts, cur, &[&[byte(1, 0, OpCode::XOR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2077 | ); 2078 | 2079 | assert_eq!( 2080 | "XOR64 R1, R2 -1000", 2081 | dis(opts, cur, &[&[byte(1, 1, OpCode::XOR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2082 | ); 2083 | 2084 | assert_eq!( 2085 | "XOR64 R1, @R2(-3, -3)", 2086 | dis(opts, cur, &[&[byte(1, 1, OpCode::XOR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2087 | ); 2088 | 2089 | assert_eq!( 2090 | "XOR64 @R1, @R2(-3, -3)", 2091 | dis(opts, cur, &[&[byte(1, 1, OpCode::XOR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2092 | ); 2093 | 2094 | assert_eq!( 2095 | "CMPeq32 R1, R2 -1000", 2096 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPeq), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2097 | ); 2098 | 2099 | assert_eq!( 2100 | "CMPeq32 R1, @R2(-3, -3)", 2101 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPeq), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2102 | ); 2103 | 2104 | assert_eq!( 2105 | "CMPeq32 @R1, @R2(-3, -3)", 2106 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPeq), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2107 | ); 2108 | 2109 | assert_eq!( 2110 | "CMPeq64 R1, R2 -1000", 2111 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPeq), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2112 | ); 2113 | 2114 | assert_eq!( 2115 | "CMPeq64 R1, @R2(-3, -3)", 2116 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPeq), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2117 | ); 2118 | 2119 | assert_eq!( 2120 | "CMPeq64 @R1, @R2(-3, -3)", 2121 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPeq), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2122 | ); 2123 | 2124 | assert_eq!( 2125 | "CMPlte32 R1, R2 -1000", 2126 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPlte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2127 | ); 2128 | 2129 | assert_eq!( 2130 | "CMPlte32 R1, @R2(-3, -3)", 2131 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPlte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2132 | ); 2133 | 2134 | assert_eq!( 2135 | "CMPlte32 @R1, @R2(-3, -3)", 2136 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPlte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2137 | ); 2138 | 2139 | assert_eq!( 2140 | "CMPlte64 R1, R2 -1000", 2141 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPlte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2142 | ); 2143 | 2144 | assert_eq!( 2145 | "CMPlte64 R1, @R2(-3, -3)", 2146 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPlte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2147 | ); 2148 | 2149 | assert_eq!( 2150 | "CMPlte64 @R1, @R2(-3, -3)", 2151 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPlte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2152 | ); 2153 | 2154 | assert_eq!( 2155 | "CMPgte32 R1, R2 -1000", 2156 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPgte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2157 | ); 2158 | 2159 | assert_eq!( 2160 | "CMPgte32 R1, @R2(-3, -3)", 2161 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPgte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2162 | ); 2163 | 2164 | assert_eq!( 2165 | "CMPgte32 @R1, @R2(-3, -3)", 2166 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPgte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2167 | ); 2168 | 2169 | assert_eq!( 2170 | "CMPgte64 R1, R2 -1000", 2171 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPgte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2172 | ); 2173 | 2174 | assert_eq!( 2175 | "CMPgte64 R1, @R2(-3, -3)", 2176 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPgte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2177 | ); 2178 | 2179 | assert_eq!( 2180 | "CMPgte64 @R1, @R2(-3, -3)", 2181 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPgte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2182 | ); 2183 | 2184 | assert_eq!( 2185 | "CMPulte32 R1, R2 -1000", 2186 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPulte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2187 | ); 2188 | 2189 | assert_eq!( 2190 | "CMPulte32 R1, @R2(-3, -3)", 2191 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPulte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2192 | ); 2193 | 2194 | assert_eq!( 2195 | "CMPulte32 @R1, @R2(-3, -3)", 2196 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPulte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2197 | ); 2198 | 2199 | assert_eq!( 2200 | "CMPulte64 R1, R2 -1000", 2201 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPulte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2202 | ); 2203 | 2204 | assert_eq!( 2205 | "CMPulte64 R1, @R2(-3, -3)", 2206 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPulte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2207 | ); 2208 | 2209 | assert_eq!( 2210 | "CMPulte64 @R1, @R2(-3, -3)", 2211 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPulte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2212 | ); 2213 | 2214 | assert_eq!( 2215 | "CMPugte32 R1, R2 -1000", 2216 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPugte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2217 | ); 2218 | 2219 | assert_eq!( 2220 | "CMPugte32 R1, @R2(-3, -3)", 2221 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPugte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2222 | ); 2223 | 2224 | assert_eq!( 2225 | "CMPugte32 @R1, @R2(-3, -3)", 2226 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPugte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2227 | ); 2228 | 2229 | assert_eq!( 2230 | "CMPugte64 R1, R2 -1000", 2231 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPugte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2232 | ); 2233 | 2234 | assert_eq!( 2235 | "CMPugte64 R1, @R2(-3, -3)", 2236 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPugte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2237 | ); 2238 | 2239 | assert_eq!( 2240 | "CMPugte64 @R1, @R2(-3, -3)", 2241 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPugte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2242 | ); 2243 | 2244 | assert_eq!( 2245 | "MUL32 R1, R2 -1000", 2246 | dis(opts, cur, &[&[byte(1, 0, OpCode::MUL), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2247 | ); 2248 | 2249 | assert_eq!( 2250 | "MUL32 R1, @R2(-3, -3)", 2251 | dis(opts, cur, &[&[byte(1, 0, OpCode::MUL), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2252 | ); 2253 | 2254 | assert_eq!( 2255 | "MUL32 @R1, @R2(-3, -3)", 2256 | dis(opts, cur, &[&[byte(1, 0, OpCode::MUL), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2257 | ); 2258 | 2259 | assert_eq!( 2260 | "MUL64 R1, R2 -1000", 2261 | dis(opts, cur, &[&[byte(1, 1, OpCode::MUL), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2262 | ); 2263 | 2264 | assert_eq!( 2265 | "MUL64 R1, @R2(-3, -3)", 2266 | dis(opts, cur, &[&[byte(1, 1, OpCode::MUL), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2267 | ); 2268 | 2269 | assert_eq!( 2270 | "MUL64 @R1, @R2(-3, -3)", 2271 | dis(opts, cur, &[&[byte(1, 1, OpCode::MUL), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2272 | ); 2273 | 2274 | assert_eq!( 2275 | "MULU32 R1, R2 -1000", 2276 | dis(opts, cur, &[&[byte(1, 0, OpCode::MULU), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2277 | ); 2278 | 2279 | assert_eq!( 2280 | "MULU32 R1, @R2(-3, -3)", 2281 | dis(opts, cur, &[&[byte(1, 0, OpCode::MULU), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2282 | ); 2283 | 2284 | assert_eq!( 2285 | "MULU32 @R1, @R2(-3, -3)", 2286 | dis(opts, cur, &[&[byte(1, 0, OpCode::MULU), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2287 | ); 2288 | 2289 | assert_eq!( 2290 | "MULU64 R1, R2 -1000", 2291 | dis(opts, cur, &[&[byte(1, 1, OpCode::MULU), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2292 | ); 2293 | 2294 | assert_eq!( 2295 | "MULU64 R1, @R2(-3, -3)", 2296 | dis(opts, cur, &[&[byte(1, 1, OpCode::MULU), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2297 | ); 2298 | 2299 | assert_eq!( 2300 | "MULU64 @R1, @R2(-3, -3)", 2301 | dis(opts, cur, &[&[byte(1, 1, OpCode::MULU), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2302 | ); 2303 | 2304 | assert_eq!( 2305 | "NEG32 R1, R2 -1000", 2306 | dis(opts, cur, &[&[byte(1, 0, OpCode::NEG), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2307 | ); 2308 | 2309 | assert_eq!( 2310 | "NEG32 R1, @R2(-3, -3)", 2311 | dis(opts, cur, &[&[byte(1, 0, OpCode::NEG), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2312 | ); 2313 | 2314 | assert_eq!( 2315 | "NEG32 @R1, @R2(-3, -3)", 2316 | dis(opts, cur, &[&[byte(1, 0, OpCode::NEG), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2317 | ); 2318 | 2319 | assert_eq!( 2320 | "NEG64 R1, R2 -1000", 2321 | dis(opts, cur, &[&[byte(1, 1, OpCode::NEG), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2322 | ); 2323 | 2324 | assert_eq!( 2325 | "NEG64 R1, @R2(-3, -3)", 2326 | dis(opts, cur, &[&[byte(1, 1, OpCode::NEG), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2327 | ); 2328 | 2329 | assert_eq!( 2330 | "NEG64 @R1, @R2(-3, -3)", 2331 | dis(opts, cur, &[&[byte(1, 1, OpCode::NEG), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2332 | ); 2333 | 2334 | assert_eq!( 2335 | "NOT32 R1, R2 -1000", 2336 | dis(opts, cur, &[&[byte(1, 0, OpCode::NOT), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2337 | ); 2338 | 2339 | assert_eq!( 2340 | "NOT32 R1, @R2(-3, -3)", 2341 | dis(opts, cur, &[&[byte(1, 0, OpCode::NOT), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2342 | ); 2343 | 2344 | assert_eq!( 2345 | "NOT32 @R1, @R2(-3, -3)", 2346 | dis(opts, cur, &[&[byte(1, 0, OpCode::NOT), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2347 | ); 2348 | 2349 | assert_eq!( 2350 | "NOT64 R1, R2 -1000", 2351 | dis(opts, cur, &[&[byte(1, 1, OpCode::NOT), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2352 | ); 2353 | 2354 | assert_eq!( 2355 | "NOT64 R1, @R2(-3, -3)", 2356 | dis(opts, cur, &[&[byte(1, 1, OpCode::NOT), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2357 | ); 2358 | 2359 | assert_eq!( 2360 | "NOT64 @R1, @R2(-3, -3)", 2361 | dis(opts, cur, &[&[byte(1, 1, OpCode::NOT), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2362 | ); 2363 | 2364 | assert_eq!( 2365 | "OR32 R1, R2 -1000", 2366 | dis(opts, cur, &[&[byte(1, 0, OpCode::OR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2367 | ); 2368 | 2369 | assert_eq!( 2370 | "OR32 R1, @R2(-3, -3)", 2371 | dis(opts, cur, &[&[byte(1, 0, OpCode::OR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2372 | ); 2373 | 2374 | assert_eq!( 2375 | "OR32 @R1, @R2(-3, -3)", 2376 | dis(opts, cur, &[&[byte(1, 0, OpCode::OR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2377 | ); 2378 | 2379 | assert_eq!( 2380 | "OR64 R1, R2 -1000", 2381 | dis(opts, cur, &[&[byte(1, 1, OpCode::OR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat()) 2382 | ); 2383 | 2384 | assert_eq!( 2385 | "OR64 R1, @R2(-3, -3)", 2386 | dis(opts, cur, &[&[byte(1, 1, OpCode::OR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat()) 2387 | ); 2388 | 2389 | assert_eq!( 2390 | "OR64 @R1, @R2(-3, -3)", 2391 | dis(opts, cur, &[&[byte(1, 1, OpCode::OR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat()) 2392 | ); 2393 | } 2394 | -------------------------------------------------------------------------------- /src/theme.rs: -------------------------------------------------------------------------------- 1 | use colored::*; 2 | 3 | use crate::options::Options; 4 | 5 | pub const SPORE: Theme = Theme { 6 | opcode: color(217, 207, 199), 7 | error: color(207, 66, 31), 8 | bytecode: color(84, 71, 52), 9 | indirect: color(227, 202, 113), 10 | operand: color(135, 75, 41), 11 | index: color(217, 182, 130), 12 | immediate: color(191, 151, 169), 13 | comment: color(135, 107, 55), 14 | x8: color(173, 152, 169), 15 | x16: color(221, 217, 159), 16 | x32: color(168, 132, 88), 17 | x64: color(125, 95, 102), 18 | }; 19 | 20 | pub const INDUSTRIAL_COMPUTER: Theme = Theme { 21 | opcode: color(161, 156, 148), 22 | error: color(255, 0, 0), 23 | bytecode: color(77, 75, 73), 24 | indirect: color(255, 153, 0), 25 | operand: color(161, 156, 148), 26 | index: color(255, 153, 0), 27 | immediate: color(255, 153, 0), 28 | comment: color(82, 214, 0), 29 | x8: color(0, 45, 122), 30 | x16: color(161, 78, 0), 31 | x32: color(3, 99, 0), 32 | x64: color(110, 18, 0), 33 | }; 34 | 35 | pub const MATTERHORN_ZERMATT_VILLAGE: Theme = Theme { 36 | opcode: color(173, 185, 201), 37 | error: color(255, 153, 0), 38 | bytecode: color(211, 195, 212), 39 | indirect: color(107, 129, 138), 40 | operand: color(115, 131, 153), 41 | index: color(140, 135, 128), 42 | immediate: color(199, 131, 64), 43 | comment: color(97, 93, 88), 44 | x8: color(110, 73, 35), 45 | x16: color(156, 103, 50), 46 | x32: color(199, 131, 64), 47 | x64: color(237, 156, 76), 48 | }; 49 | 50 | pub struct Theme 51 | { 52 | pub opcode: Color, 53 | pub error: Color, 54 | pub bytecode: Color, 55 | pub indirect: Color, 56 | pub operand: Color, 57 | pub index: Color, 58 | pub immediate: Color, 59 | pub comment: Color, 60 | pub x8: Color, 61 | pub x16: Color, 62 | pub x32: Color, 63 | pub x64: Color, 64 | } 65 | 66 | pub const fn color(r: u8, g: u8, b: u8) -> Color 67 | { 68 | Color::TrueColor { r, g, b } 69 | } 70 | 71 | pub fn colored_string(string: String, color: Color) -> String 72 | { 73 | if let Color::TrueColor { r, g, b } = color 74 | { 75 | string.truecolor(r, g, b).to_string() 76 | } 77 | else 78 | { 79 | string 80 | } 81 | } 82 | 83 | pub fn color_opcode(string: String, options: &Options) -> String 84 | { 85 | if let Some(color_theme) = &options.theme 86 | { 87 | colored_string(string, color_theme.opcode) 88 | } 89 | else 90 | { 91 | string 92 | } 93 | } 94 | 95 | pub fn color_error(string: String, options: &Options) -> String 96 | { 97 | if let Some(color_theme) = &options.theme 98 | { 99 | colored_string(string, color_theme.error) 100 | } 101 | else 102 | { 103 | string 104 | } 105 | } 106 | 107 | pub fn color_bytecode(string: String, options: &Options) -> String 108 | { 109 | if let Some(color_theme) = &options.theme 110 | { 111 | colored_string(string, color_theme.bytecode) 112 | } 113 | else 114 | { 115 | string 116 | } 117 | } 118 | 119 | pub fn color_indirect(string: String, options: &Options) -> String 120 | { 121 | if let Some(color_theme) = &options.theme 122 | { 123 | colored_string(string, color_theme.indirect) 124 | } 125 | else 126 | { 127 | string 128 | } 129 | } 130 | 131 | pub fn color_operand(string: String, options: &Options) -> String 132 | { 133 | if let Some(color_theme) = &options.theme 134 | { 135 | colored_string(string, color_theme.operand) 136 | } 137 | else 138 | { 139 | string 140 | } 141 | } 142 | 143 | pub fn color_index(string: String, options: &Options) -> String 144 | { 145 | if let Some(color_theme) = &options.theme 146 | { 147 | colored_string(string, color_theme.index) 148 | } 149 | else 150 | { 151 | string 152 | } 153 | } 154 | 155 | pub fn color_immediate(string: String, options: &Options) -> String 156 | { 157 | if let Some(color_theme) = &options.theme 158 | { 159 | colored_string(string, color_theme.immediate) 160 | } 161 | else 162 | { 163 | string 164 | } 165 | } 166 | 167 | pub fn color_comment(string: String, options: &Options) -> String 168 | { 169 | if let Some(color_theme) = &options.theme 170 | { 171 | colored_string(string, color_theme.comment) 172 | } 173 | else 174 | { 175 | string 176 | } 177 | } 178 | 179 | pub fn color_x8(string: String, options: &Options) -> String 180 | { 181 | if let Some(color_theme) = &options.theme 182 | { 183 | colored_string(string, color_theme.x8) 184 | } 185 | else 186 | { 187 | string 188 | } 189 | } 190 | 191 | pub fn color_x16(string: String, options: &Options) -> String 192 | { 193 | if let Some(color_theme) = &options.theme 194 | { 195 | colored_string(string, color_theme.x16) 196 | } 197 | else 198 | { 199 | string 200 | } 201 | } 202 | 203 | pub fn color_x32(string: String, options: &Options) -> String 204 | { 205 | if let Some(color_theme) = &options.theme 206 | { 207 | colored_string(string, color_theme.x32) 208 | } 209 | else 210 | { 211 | string 212 | } 213 | } 214 | 215 | pub fn color_x64(string: String, options: &Options) -> String 216 | { 217 | if let Some(color_theme) = &options.theme 218 | { 219 | colored_string(string, color_theme.x64) 220 | } 221 | else 222 | { 223 | string 224 | } 225 | } 226 | 227 | pub trait Emit 228 | { 229 | fn emit(&self, options: &Options) -> String; 230 | } 231 | --------------------------------------------------------------------------------