Capstone, Intel XED, and Zydis, which is faster at decoding x86?

(Nov. 13 update: I was suggested to test Zydis, so I added the Zydis measurement.)

In order to do some binary analysis, the first step is decoding the binary instructions to recover some human-understandable semantics. Capstone is a popular diassembly framework which is used by many reverse engineering and debugging tools. It is based on LLVM MC, so the dissemebly results should be as precise as LLVM. Capstone also supports multiple platforms and architectures. However, if your goal is analyzing x86 binaries, there are other options. Intel recently open-sourced The X86 Encoder Decoder (XED). XED does similar things as Capstone in terms of decoding x86 instructions, and is used internally by Intel Pin, a dynamic binary instrumentation tool. Zydis promises to be a fast decoding tool for x86, and is also used by a feature-rich debugger. The question is, if you care about the speed of decoding, which tool should you use?

From high level, the decoding API of Capstone, XED, and Zydis takes an x86 binary instruction and returns a data structure which describes the instruction. The data structure contains opcode, operands, including register name, memory base and displacement, immediate value, and many other information. You can then implement your binary analysis logic based on the returned data structure. I conducted some experiments to empirically evaluate the decoding speed of the these APIs. The code is in https://github.com/qiuyuX/disasm_perf. I will explain the evaluation further in this post.

First, a python script (parse_elf.py) extracts x86 instructions from the ELF binary file. The extracted instructions are provided to disasm_perf.c which calls the decoding API of either Capstone, XED, or Zydis, and measures the average decoding time. For Capstone, I chose to measure cs_disasm_iter(), since it is designed to be a faster decoding API. Capstone can be specified to give either detailed decoding results or simplified results by using cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON) or cs_option(handle, CS_OPT_DETAIL, CS_OPT_OFF) correspondingly, which I measured both. For XED, I chose to measure the execution time of xed_decoded_inst_zero_set_mode() and xed_decode(). I have to include xed_decoded_inst_zero_set_mode(). Otherwise, XED gives wrong results. XED always gives detailed decoding results. For Zydis, ZydisDecoderDecodeBuffer() was measured, and it also gives detailed decoding results.

Below are the evaluation results. The time unit is CPU cycle.

dissasm_perf

 

XED, Capstone, and Zydis were all tested against the x86-64 instructions from Firefox, libc, and sshd. It turns out that Zydis is the fastest one! In conclusion, you might want to choose Zydis if you care more about the decoding speed of X86.

Leave a Reply

Your email address will not be published. Required fields are marked *