Setting Up the Toolchain and QEMU

1. TL;DR


2. Before we start

All the source files are available in GitHub RISC-V Experiments Repository.

3. Required tools

We need the RISC-V GCC cross-compiler, QEMU, GDB, and some standard build tools. On Ubuntu 24.04 (or similar Debian-based systems), install them with:

1
2
3
4
5
6
sudo apt update
sudo apt install build-essential \
  gcc-riscv64-unknown-elf \
  gdb-multiarch \
  qemu-system-riscv32 \
  binutils-riscv64-unknown-elf

3.1. Install Pwndbg

Pwndbg is a powerful GDB plug-in that provides a better interface for reverse engineering and debugging. It will be useful for inspecting registers and memory in later chapters.

1
2
3
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh

4. Project layout

1
2
3
git clone https://github.com/psylinux/riscv-experiments.git
cd riscv-experiments
mkdir -p build
1
2
3
4
riscv-experiments/
  docs/
  src/
  build/

5. Minimal UART “hello”

File: src/hello_uart.c

1
2
3
4
5
6
7
#include "types.h"
#include "uart.h"

int main(void) {
  uart_puts("Hello from RV32 in QEMU!\n");
  return 0;
}

Build and run:

1
2
3
4
5
riscv64-unknown-elf-gcc -O0 -g -ffreestanding -nostdlib \
  -march=rv32im -mabi=ilp32 -T src/link.ld \
  src/start.s src/uart.c src/hello_uart.c -o build/hello_uart.elf

qemu-system-riscv32 -M virt -nographic -bios none -kernel build/hello_uart.elf

You should see the greeting printed in your terminal.

6. Running with GDB

Start QEMU in halted mode:

1
2
qemu-system-riscv32 -S -M virt -nographic -bios none \
  -kernel build/hello_uart.elf -gdb tcp::1234

Connect from another terminal:

1
2
3
4
5
gdb-multiarch build/hello_uart.elf \
  -ex "set arch riscv:rv32" \
  -ex "target remote localhost:1234" \
  -ex "break main" \
  -ex "continue"

7. Exercises

  1. Confirm you can run qemu-system-riscv32 --version on your system.
  2. Confirm you can run riscv64-unknown-elf-gcc --version on your system.
  3. Verify you can use make by running make --version on your system.
  4. Verify you can run gdb-multiarch by running gdb-multiarch --version on your system.
  5. Change the string and verify it prints correctly.
  6. Add a second uart_puts line and step through it in GDB.

8. Summary