---
# System prepended metadata

title: How to use nanomips libopcode

---

# How to use nanomips libopcode

https://blog.yossarian.net/2019/05/18/Basic-disassembly-with-libopcodes

- Download binutil source from https://github.com/MediaTek-Labs/nanomips-gnu-toolchain/releases

```bash
cd <binutils src root>
./configure --target=nanomips-gcc-elf CFLAGS="-Wno-maybe-uninitialized"
make all-opcodes

gcc main.c -Iinclude -Ibfd -Lopcodes -lopcodes -Lbfd -lbfd -Llibiberty -liberty -Lzlib -lz
./a.out
```

- Sample code
```c=
#define _GNU_SOURCE /* asprintf, vasprintf */
#include <config.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <dis-asm.h>

typedef struct {
  char *insn_buffer;
  bool reenter;
} stream_state;

/* This approach isn't very memory efficient or clear,
 * but it avoids external size/buffer tracking in this
 * example.
 */
static int dis_fprintf(void *stream, const char *fmt, ...) {
  stream_state *ss = (stream_state *)stream;

  va_list arg;
  va_start(arg, fmt);
  if (!ss->reenter) {
    vasprintf(&ss->insn_buffer, fmt, arg);
    ss->reenter = true;
  } else {
    char *tmp;
    vasprintf(&tmp, fmt, arg);

    char *tmp2;
    asprintf(&tmp2, "%s%s", ss->insn_buffer, tmp);
    free(ss->insn_buffer);
    free(tmp);
    ss->insn_buffer = tmp2;
  }
  va_end(arg);

  return 0;
}

char *disassemble_raw(uint8_t *input_buffer, size_t input_buffer_size) {
  char *disassembled = NULL;
  stream_state ss = {};

  disassemble_info disasm_info = {};
  init_disassemble_info(&disasm_info, &ss, dis_fprintf);
  disasm_info.arch = bfd_arch_nanomips;
  disasm_info.mach = bfd_mach_nanomipsisa32r6;
  disasm_info.read_memory_func = buffer_read_memory;
  disasm_info.buffer = input_buffer;
  disasm_info.buffer_vma = 0;
  disasm_info.buffer_length = input_buffer_size;
  disassemble_init_for_target(&disasm_info);

  disassembler_ftype disasm;
  disasm = disassembler(bfd_arch_nanomips, false, bfd_mach_nanomipsisa32r6, NULL);

  size_t pc = 0;
  while (pc < input_buffer_size) {
    size_t insn_size = disasm(pc, &disasm_info);
    pc += insn_size;

    if (disassembled == NULL) {
      asprintf(&disassembled, "%s", ss.insn_buffer);
    } else {
      char *tmp;
      asprintf(&tmp, "%s\n%s", disassembled, ss.insn_buffer);
      free(disassembled);
      disassembled = tmp;
    }

    /* Reset the stream state after each instruction decode.
     */
    free(ss.insn_buffer);
    ss.reenter = false;
  }

  return disassembled;
}

int main(int argc, char const *argv[]) {
  uint8_t input_buffer[] = {
      0x1c, 0x12, // move    s0,gp
      0x12, 0x1c, // save    16,fp,ra
  };
  size_t input_buffer_size = sizeof(input_buffer);

  char *disassembled = disassemble_raw(input_buffer, input_buffer_size);
  puts(disassembled);
  free(disassembled);

  return 0;
}

```