Skip to content

Instantly share code, notes, and snippets.

@pdxjohnny
Last active September 24, 2021 00:33
Show Gist options
  • Save pdxjohnny/3de9a9bdd38cacf3ea394207762f1002 to your computer and use it in GitHub Desktop.
Save pdxjohnny/3de9a9bdd38cacf3ea394207762f1002 to your computer and use it in GitHub Desktop.
ARM workflow with qemu and arm-none-eabi
target remote 127.0.0.1:1234
layout asm
focus cmd
file main.elf
break *_start
continue
a.out
main
qemu_*
*.o
*.swp
*.bin
*.elf

Sample ARM workflow

This repo should get you up and running writing ARM assembly without hardware.

Dependencies

The first step is to install the necessary packages. These are the arm-none-eabi tool chain and qemu with arm support.

Arch Linux

sudo pacman -S arm-none-eabi-gcc arm-none-eabi-binutils arm-none-eabi-gdb \
  arm-none-eabi-newlib qemu qemu-arch-extra

Ubuntu

sudo apt -y install \
    make \
    gcc-arm-none-eabi \
    binutils-arm-none-eabi \
    gdb-arm-none-eabi \
    libstdc++-arm-none-eabi-newlib \
    libnewlib-arm-none-eabi \
    qemu-system-arm

GDB

In .gdbinit we have placed commands which gdb will run on startup. But to make this work the .gdbinit file in our home directory needs to say its ok for gdb to load this .gdbinit file. To do that we just add the directory to the auto-load safe-path.

echo "set auto-load safe-path $PWD" >> ~/.gdbinit

Building

The Makefile should have plenty of comments to help you understand what is being done in it. It takes all the .s assembly files in the current directory and compiles them into object files. Then it runs the linker to create the ELF binary. All of this is done with arm-none-eabi-gcc rather than your regular gcc for host programs.

make

Will rebuild all the modified .s files into their object file forms and relink to the binary. Run make clean all if you are having really weird errors. That usually fixes things.

Running

To run you can do qemu-arm ./main. But hey why not put it in the Makefile right.

make all qemu

Will rebuild any changed files and run the created binary in qemu.

Debugging

Oh you ran the program and everything exploded? Time to debug.

make all gdb

Will rebuild all your source files and start the program in qemu with it as a gdb target on port 1234, so make sure nothing else is using that port or change it in the .gdbinit file and Makefile.

Help nothing works

Comment with the problem so we can figure it out on here and everyone else can see the solution.

FROM ubuntu:latest
MAINTAINER John Andersen <johnandersenpdx@gmail.com>
RUN apt update -y && \
apt install -y \
bash \
bash-completion \
vim \
tar \
tmux \
make \
gcc-arm-none-eabi \
binutils-arm-none-eabi \
gdb-arm-none-eabi \
libstdc++-arm-none-eabi-newlib \
libnewlib-arm-none-eabi \
qemu-system-arm \
openssh-server && \
apt clean && \
rm -rf /var/cache/apt/* && \
mkdir /var/run/sshd && \
/usr/sbin/useradd -m user && \
echo "user:userpass" | chpasswd
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
ENTRY(_start)
SECTIONS
{
. = 0x70010000;
.text : { *(.text) }
.data : { *(.data) }
. = ALIGN(8);
}
.text
.global _start
@ The purpose of _start / main is to set up the stack for the run procedure
_start:
@ Do stuff, jump to the rest of your program, whatever you want
B _start
.END
# The name of the output binary
SRC=main
# This sets the compiler to use. Most people use gcc clang is also another
# common compiler. It becomes the variable which can be accessed with $(CC)
AS=arm-none-eabi-as
LINKER=arm-none-eabi-ld
OBJCOPY=arm-none-eabi-objcopy
# Assembler flags
ASFLAGS=-g -mcpu=cortex-a8
# These are linker flags only needed if using external libraries but we are not
# in this
LDFLAGS=-T linker.ld
# This says to grab all the files with the c extension in this directory and
# make them the array called SRC_SOURCES
SRC_SOURCES=$(wildcard *.s)
# This makes an array of all the c files but replaces .c with .o
SRC_OBJECTS=$(SRC_SOURCES:.s=.o)
# When you run make then all is the default command to run. So running `make` is
# the same as running `make all`
all: $(SRC)
# This says to build $(SRC) then all the o files need to be present / up to
# date first. The way they get up to date is by compiling the c files in to
# their respective o files
$(SRC): $(SRC_OBJECTS)
@# The $@ variable gets replaced with $(SRC)
$(LINKER) $(LDFLAGS) $(SRC_OBJECTS) -o $@.elf
@# Make the elf a binary
$(OBJCOPY) -O binary $@.elf $@.bin
# This is the action that is run to create all the .o files, object files.
# Every c file in the array SRC_SOURCES is compiled to its object file for
# before being linked together
%.o:%.s
$(AS) $(ASFLAGS) $< -o $@
# Clean deletes everything that gets created when you run the build. This means
# all the .o files and the binary named $(SRC)
clean:
rm -f $(SRC) *.o *.tar.xz *.core *.elf *.bin
# This creates the tar file for submission
tar:
tar czvf $(SRC).tar.xz $(SRC_SOURCES) Makefile
# Run the binary in qemu
qemu:
qemu-system-arm -M realview-pb-a8 -m 128M -nographic -s -S -kernel $(SRC).bin
# Run the binary in qemu with gdb server then launch gdb
gdb:
qemu-system-arm -M realview-pb-a8 -m 128M -nographic -s -S -kernel $(SRC).bin &
arm-none-eabi-gdb
killall qemu-system-arm
@pdxjohnny
Copy link
Author

pdxjohnny commented Nov 4, 2016

It works now!

@bbqburrito
Copy link

bbqburrito commented Nov 4, 2016

Can you help translate this to ubuntu?
to be more specific: I think I've found all the necessary packages for unbuntu, but I'm not sure how to implement the make file.

Thanks!

@pdxjohnny
Copy link
Author

@bbqburrito you can just use this makefile sorry I'm not sure what you mean, try cloning this gist and then modifying it

@pdxjohnny
Copy link
Author

I will add dockerfile for Ubuntu when I get home

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment