Skip to content

Latest commit

 

History

History
163 lines (120 loc) · 5.47 KB

disassembler.rst

File metadata and controls

163 lines (120 loc) · 5.47 KB

Disassembler

micropython-esp32-ulp contains a disassembler for disassembling code for the ESP32 ULP (Ultra Low-Power) Co-Processor.

The main purpose of this tool is to inspect what instructions our assembler created, what value each field is set to, and to compare this with the output created by the assembler from Espressif (part of their binutils-gdb fork), which we use as our reference implementation.

Usage

To disassemble a ULP binary, simply run:

micropython -m tools.disassemble path/to/binary.ulp

You can also specify additional options to disassemble.py as follows:

OptionDescription
-c or --mcpuChoose ULP variant: either esp32 or esp32s2
-hShow help text
-m <bytes sequence>

Disassemble a provided sequence of hex bytes
(in this case any filename specified is ignored)
-vVerbose mode (shows ULP header and fields of each instruction)

Disassembling a file

The simplest and default mode of the disassembler is to disassemble the specified file.

Note that the ULP header is validates and files with unknown magic bytes will be rejected. The correct 4 magic bytes at the start of a ULP binary are ulp\x00.

Example disassembling an ESP32 ULP binary:

$ micropython -m tools.disassemble path/to/binary.ulp .text 0000 040000d0 LD r0, r1, 0 0004 0e0000d0 LD r2, r3, 0 0008 04000068 ST r0, r1, 0 000c 0b000068 ST r3, r2, 0 .data 0010 00000000 <empty>

Example disassembling an ESP32-S2 ULP binary:

$ micropython -m tools.disassemble -c esp32s2 path/to/binary.ulp .text 0000 040000d0 LD r0, r1, 0 0004 0e0000d0 LD r2, r3, 0 0008 84010068 ST r0, r1, 0 000c 8b010068 ST r3, r2, 0 .data 0010 00000000 <empty>

Disassembling a byte sequence

The -m option allows disassembling a sequences hex letters representing ULP instructions.

This option expects the actual instructions directly, without any ULP header.

The sequence must contain a number of hex letters exactly divisible by 8, i.e. 8, 16, 24, etc, because each 32-bit word is made up of 8 hex letters. Spaces can be included in the sequence and they are ignored.

The typical use case for this feature is to copy/paste some instructions from a hexdump (e.g. xxd output) for analysis.

Example:

# hexdump binary.ulp $ xxd path/to/binary.ulp 00000000: 756c 7000 0c00 2400 0400 0000 9300 8074 ulp...$........t 00000010: 2a80 0488 2004 8074 1c00 0084 0000 0040 *... ..t.......@ (...) # analyse the last 2 instructions $ micropython -m tools.disassemble -m "1c00 0084 0000 0040" 0000 1c000084 JUMPS 0, 28, LT 0004 00000040 NOP

Verbose mode

In verbose mode the following extra outputs are enabled:

  • ULP header (except when using -m)
  • The fields of each instruction and their values

For example:

header ULP magic : b'ulp\x00' (0x00706c75) .text offset : 12 (0x0c) .text size : 36 (0x24) .data offset : 48 (0x30) .data size : 4 (0x04) .bss size : 0 (0x00) ---------------------------------------- .text 0000 93008072 MOVE r3, 9 dreg = 3 imm = 9 opcode = 7 sel = 4 (MOV) sreg = 0 sub_opcode = 1 unused = 0 (...detail truncated...) 0020 000000b0 HALT opcode = 11 (0x0b) unused = 0 ---------------------------------------- .data 0000 00000000 <empty> 

Disassembling on device

The disassembler also works when used on an ESP32 device.

To use the disassembler on a real device:

  • ensure micropython-esp32-ulp is installed on the device (see docs/index.rst).

  • upload tools/disassemble.pytools/decode.py and tools/decode_s2.py to the device (any directory will do, as long as those 3 files are in the same directory)

  • the following example code assumes you placed the 3 files into the device's "root" directory

  • run the following (note, we must specify which the cpu the binary is for):

    fromdisassembleimportdisassemble_file# then either:disassemble_file('path/to/file.ulp', cpu='esp32s2') # normal mode# or:disassemble_file('path/to/file.ulp', cpu='esp32s2', verbose=True) # verbose mode
close