Skip to content

Commit

Permalink
Rewrite CLI to drop Boost dependency (#73)
Browse files Browse the repository at this point in the history
* Rewrite CLI to drop Boost dependency

* Move `expected` into `vendor` subdirectory

* Use `tl::expected` for option parsing; fix typos, round-tripping issues

* Update README for new CLI

* Add `vendor` folder to include paths for static analysis tools

* Add vendor dir and update CI

* Improve README to show user-defined label usage

* Update bindings build script to include `vendor`

* Fix byte output formatting for CLI

Because the output stream was set to `std::left` and not reset back to
the default `std::right`, instruction bytes smaller then `0x10` would be
formatted wrong.

* Add `--bytes-only` flag and basic CLI sanity test

---------

Co-authored-by: Jon Palmisciano <[email protected]>
  • Loading branch information
stuxnot and jonpalmisc authored Sep 24, 2024
1 parent 217a3a6 commit ec1f398
Show file tree
Hide file tree
Showing 17 changed files with 777 additions and 177 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ jobs:
run: make test
working-directory: build/
- name: cli
run: ./nyxstone -A "mov rax, rbx" &&
./nyxstone -A "jmp label" --labels "label=0x1000"
run: |
./nyxstone "mov rax, rbx" &&
./nyxstone "jmp label" --labels "label=0x1000"
working-directory: build/
11 changes: 2 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ target_compile_features(nyxstone PUBLIC
)
target_include_directories(nyxstone PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/vendor>
)
target_link_libraries(nyxstone PUBLIC
LLVM-Wrapper
Expand All @@ -65,21 +66,12 @@ set_target_properties(nyxstone PROPERTIES
)

if(NYXSTONE_BUILD_EXAMPLES)
# Use -DBOOST_ROOT=C:/boost_1_80_0 to specify the boost root directory
if(WIN32)
set(Boost_USE_STATIC_LIBS ON) # only find static libs
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
endif()
find_package(Boost 1.40 COMPONENTS program_options REQUIRED)

add_executable(nyxstone-bin examples/nyxstone-cli.cpp)
set_target_properties(nyxstone-bin PROPERTIES
OUTPUT_NAME nyxstone
)
target_link_libraries(nyxstone-bin PRIVATE
nyxstone::nyxstone
Boost::program_options
)

add_executable(example examples/example.cpp)
Expand All @@ -89,4 +81,5 @@ if(NYXSTONE_BUILD_EXAMPLES)

include(CTest)
add_test(NAME TestExample COMMAND $<TARGET_FILE:example>)
add_test(NAME TestCLI COMMAND "${CMAKE_CURRENT_LIST_DIR}/tool/test-cli.sh")
endif()
94 changes: 49 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,9 @@ Also make sure to install any system dependent libraries needed by your LLVM ver

### CLI Tool

Nyxstone comes with a handy [CLI tool](examples/nyxstone-cli.cpp) for quick assembly and disassembly tasks. Install boost with your distribution's package manager, checkout the Nyxstone repository, and build the tool with cmake:
Nyxstone comes with a handy [CLI tool](examples/nyxstone-cli.cpp) for quick assembly and disassembly tasks. Checkout the Nyxstone repository, and build the tool with CMake:

```bash
# install boost on Ubuntu/Debian
apt install boost

# clone directory
git clone https://github.com/emproof-com/nyxstone
cd nyxstone
Expand All @@ -105,61 +102,68 @@ mkdir build && cd build && cmake .. && make
Then, `nyxstone` can be used from the command line. Here's an output of its help menu:

```
$ ./nyxstone --help
Allowed options:
--help Show this message
--arch arg (=x86_64) LLVM triple or architecture identifier of triple.
For the most common architectures, we recommend:
x86_32: `i686-linux-gnu`
x86_64: `x86_64-linux-gnu`
armv6m: `armv6m-none-eabi`
armv7m: `armv7m-none-eabi`
armv8m: `armv8m.main-none-eabi`
aarch64: `aarch64-linux-gnueabihf`
Using shorthand identifiers like `arm` can lead to
Nyxstone not being able to assemble certain
instructions.
--cpu arg LLVM cpu specifier, refer to `llc -mtriple=ARCH
-mcpu=help` for a comprehensive list
--features arg LLVM features to enable/disable, comma seperated
feature strings prepended by '+' or '-' to enable or
disable respectively. Refer to `llc -mtriple=ARCH
-mattr=help` for a comprehensive list
--address arg (=0) Address
Assembling:
--labels arg Labels, for example "label0=0x10,label1=0x20"
-A [ --assemble ] arg Assembly
Disassembling:
-D [ --disassemble ] arg Byte code in hex, for example: "0203"
$ ./nyxstone -h
Usage: nyxstone [-t=<triple>] [-p=<pc>] [-d] <input>
Examples:
# Assemble an instruction with the default architecture ('x86_64').
nyxstone 'push eax'
# Disassemble the bytes 'ffc300d1' as AArch64 code.
nyxstone -t aarch64 -d ffc300d1
Options:
-t, --triple=<triple> LLVM target triple or alias, e.g. 'aarch64'
-c, --cpu=<cpu> LLVM CPU specifier, e.g. 'cortex-a53'
-f, --features=<list> LLVM architecture/CPU feature list, e.g. '+mte,-neon'
-p, --address=<pc> Initial address to assemble/disassemble relative to
-l, --labels=<list> Label-to-address mappings (used when assembling only)
-d, --disassemble Treat <input> as bytes to disassemble instead of assembly
-h, --help Show this help and usage message
Notes:
The '--triple' parameter also supports aliases for common target triples:
'x86_32' -> 'i686-linux-gnu'
'x86_64' -> 'x86_64-linux-gnu'
'armv6m' -> 'armv6m-none-eabi'
'armv7m' -> 'armv7m-none-eabi'
'armv8m' -> 'armv8m.main-none-eabi'
'aarch64' -> 'aarch64-linux-gnueabihf'
The CPUs for a target can be found with 'llc -mtriple=<triple> -mcpu=help'.
The features for a target can be found with 'llc -mtriple=<triple> -mattr=help'.
```

Now, we can assemble an instruction for the x86_64 architecture:

```
$ ./nyxstone --arch "x86_64" -A "mov rax, rbx"
Assembled:
0x00000000: mov rax, rbx - [ 48 89 d8 ]
$ ./nyxstone -t x86_64 "mov rax, rbx"
0x00000000: mov rax, rbx ; 48 89 d8
```

We can also assemble a sequence of instructions. In the following, we make use of label-based addressing and assume the first instruction is mapped to address `0xdeadbeef`:

```
$ ./nyxstone --arch "x86_64" --address 0xdeadbeef -A "cmp rax, rbx; jz .exit ; inc rax ; .exit: ret"
0xdeadbeef: cmp rax, rbx - [ 48 39 d8 ]
0xdeadbef2: je .exit - [ 74 03 ]
0xdeadbef4: inc rax - [ 48 ff c0 ]
0xdeadbef7: ret - [ c3 ]
$ ./nyxstone -t x86_64 -p 0xdeadbeef "cmp rax, rbx; jz .exit; inc rax; .exit: ret"
0xdeadbeef: cmp rax, rbx ; 48 39 d8
0xdeadbef2: je .exit ; 74 03
0xdeadbef4: inc rax ; 48 ff c0
0xdeadbef7: ret ; c3
```

Furthermore, we can disassemble instructions for different instruction sets, here the ARM32 thumb instruction set:

```
$ ./nyxstone -t thumbv8 -d "13 37"
0x00000000: adds r7, #19 ; 13 37
```

We can also disassemble an instruction for the ARM32 thumb instruction set:
Using the support for user-defined labels, we can assemble this snippet which does not contain the label `.label` by specifying its memory location ourself.

```
$ ./nyxstone --arch "thumbv8" -D "13 37"
Disassembled:
0x00000000: adds r7, #19 - [ 13 37 ]
$ ./nyxstone -p "0x1000" -l ".label=0x1238" "jmp .label"
0x00001000: jmp .label ; e9 33 02 00 00
```

### C++ Library
Expand Down
1 change: 1 addition & 0 deletions bindings/python/nyxstone-cpp/vendor
2 changes: 1 addition & 1 deletion bindings/python/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def get_llvm_include_dir(self) -> str:
Pybind11Extension(
name="nyxstone_cpp",
sources=srcs,
include_dirs=["nyxstone-cpp/include/", "nyxstone-cpp/src/", llvm_inc_dir],
include_dirs=["nyxstone-cpp/include/", "nyxstone-cpp/vendor", "nyxstone-cpp/src/", llvm_inc_dir],
libraries=llvm_libs,
library_dirs=[llvm_lib_dir],
extra_link_args=[
Expand Down
1 change: 1 addition & 0 deletions bindings/rust/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ fn main() {
cxx_build::bridge("src/lib.rs")
.std("c++17")
.include("nyxstone/include")
.include("nyxstone/vendor")
.include(llvm_include_dir.trim())
// .include(cxxbridge_dir)
.files(sources)
Expand Down
1 change: 1 addition & 0 deletions bindings/rust/nyxstone/vendor
2 changes: 1 addition & 1 deletion bindings/rust/src/nyxstone_ffi.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "nyxstone_ffi.hpp"

#include "tl/expected.hpp"
#include <expected.hpp>

using namespace nyxstone;

Expand Down
Loading

0 comments on commit ec1f398

Please sign in to comment.