{"id":13797008,"url":"https://github.com/cirosantilli/arm-assembly-cheat","last_synced_at":"2026-02-14T09:06:22.431Z","repository":{"id":63593528,"uuid":"61829154","full_name":"cirosantilli/arm-assembly-cheat","owner":"cirosantilli","description":"MOVED TO: https://cirosantilli.com/linux-kernel-module-cheat/userland-assembly with code at https://github.com/cirosantilli/linux-kernel-module-cheat/tree/master/userland/arch/arm SEE README. ARMv7 and ARMv8 assembly userland minimal examples tutorial. Runnable asserts on x86 hosts with QEMU user mode or natively on ARM targets. Nice GDB step debug setup. Tested on Ubuntu 18.04 host and Raspberry Pi 2 and 3 targets. ","archived":false,"fork":false,"pushed_at":"2019-06-26T09:29:09.000Z","size":237,"stargazers_count":203,"open_issues_count":1,"forks_count":32,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-10-07T07:32:45.548Z","etag":null,"topics":["arm","armv7","armv8","assembly","assembly-arm","assembly-language-programming","raspberry-pi"],"latest_commit_sha":null,"homepage":"","language":"Makefile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cirosantilli.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-06-23T18:54:04.000Z","updated_at":"2025-10-04T16:39:24.000Z","dependencies_parsed_at":"2022-11-22T01:45:35.685Z","dependency_job_id":null,"html_url":"https://github.com/cirosantilli/arm-assembly-cheat","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cirosantilli/arm-assembly-cheat","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cirosantilli%2Farm-assembly-cheat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cirosantilli%2Farm-assembly-cheat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cirosantilli%2Farm-assembly-cheat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cirosantilli%2Farm-assembly-cheat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cirosantilli","download_url":"https://codeload.github.com/cirosantilli/arm-assembly-cheat/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cirosantilli%2Farm-assembly-cheat/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29441148,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T07:24:13.446Z","status":"ssl_error","status_checked_at":"2026-02-14T07:23:58.969Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arm","armv7","armv8","assembly","assembly-arm","assembly-language-programming","raspberry-pi"],"created_at":"2024-08-03T23:01:19.930Z","updated_at":"2026-02-14T09:06:22.415Z","avatar_url":"https://github.com/cirosantilli.png","language":"Makefile","readme":"= ARM Assembly Cheat\n:idprefix:\n:idseparator: -\n:sectanchors:\n:sectlinks:\n:sectnumlevels: 6\n:sectnums:\n:toc: macro\n:toclevels: 6\n:toc-title:\n\nAlmost all the content in this repository has been moved to: https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly\n\nOnly the core infrastructure of this repo was left here. No major new features are intended to be added here.\n\nNotable advantages of LKMC repository include:\n\n* a single unified cross arch setup for ARM and x86_64, with cross arch concepts all nicely factored out\n* gem5 support. This is because we have integration of QEMU / gem5 / buildroot setups already done there\n* parallel testing. Mostly because the build system there is Python, which is more flexible.\n* other stuff I can't remember right now. That setup just has a ton of features, and will continue to get more and more ;-)\n\nThere is only one use case left for this repository: since this is more minimal, it is easier to upgrdte to the latest binutils-gdb here without breaking unrelated stuff, in order to get very latest instructions.\n\nThe initial motivation for that was \u003c\u003csve\u003e\u003e although that specific case has already been moved to LKMC as well!\n\nI might however start taking some risks on LKMC and upgrading binutils-gdb to master when needed anyways, or just build the latest binutils-gdb myself over there for userland only.\n\n== Old README\n\nHere is the old README with only infrastructure sections left.\n\nARMv7 and \u003c\u003cARMv8\u003e\u003e assembly userland minimal examples tutorial. Runnable \u003c\u003casserts,asserts\u003e\u003e on x86 hosts with QEMU user mode or natively on ARM targets. Nice \u003c\u003cgdb-step-debug\u003e\u003e setup. Tested on Ubuntu 18.04 host and \u003c\u003crpi2,Raspberry Pi 2\u003e\u003e and \u003c\u003crpi3,3\u003e\u003e targets. Baremetal setup at: https://github.com/cirosantilli/linux-kernel-module-cheat#baremetal-setup x86 cheat at: https://github.com/cirosantilli/x86-assembly-cheat\n\ntoc::[]\n\n== Getting started\n\nOn Ubuntu, clone, configure, build QEMU and Binutils from source, run all ARMv7 and ARMv8 examples through QEMU user, and assert that they exit with status 0:\n\n....\ngit clone --recursive https://github.com/cirosantilli/arm-assembly-cheat\ncd arm-assembly-cheat\n./download-dependencies\nmake test\necho $?\n....\n\nExpected outcome: the exit status is successful:\n\n....\n0\n....\n\nFor other operating systems, see: \u003c\u003cgetting-started-on-non-ubuntu-operating-systems\u003e\u003e.\n\nWe compile our own Binutils and QEMU to be able to use the newest ISA features. Those projects build pretty fast (~10 minutes), so it is fine. The cleanest thing would be to also compile GCC with \u003c\u003ccrosstool-ng-toolchain\u003e\u003e.\n\nThe armv7 examples are all located under the link:v7[] directory. Run all of them:\n\n....\ncd v7\nmake test\necho $?\n....\n\nRun just one of them:\n\n....\ncd v7\nmake test-\u003cbasename-no-extension\u003e\necho $?\n....\n\nE.g.:\n\n....\nmake test-add\n....\n\nwill run link:userland/arch/arm/add.S[].\n\nThis just tests some assertions, but does not output anything. See: \u003c\u003casserts\u003e\u003e.\n\nAlternatively, to help with tab completion, the following shortcuts all do the same thing as `make test-add`:\n\n....\n./t add\n./t add.\n./t add.out\n....\n\n\u003c\u003carmv8\u003e\u003e examples are all located under the link:v8[] directory. They can be run in the same way as ARMv7 examples:\n\n....\ncd v8\nmake test-movk\n....\n\nJust build the examples without running:\n\n....\nmake\n....\n\nClean the examples:\n\n....\nmake clean\n....\n\nThis does not clean QEMU builds themselves. To do that run:\n\n....\nmake qemu-clean\n....\n\n=== Asserts\n\nAlmost all example don't output anything, they just assert that the computations are as expected and exit 0 is that was the case.\n\nFailures however output clear error messages.\n\nTry messing with the examples to see them fail, e.g. modify link:userland/arch/arm/add.S[] to contain:\n\n....\nmov r0, #1\nadd r1, r0, #2\nASSERT_EQ(r1, 4)\n....\n\nand then watch it fail:\n\n....\ncd v7\nmake test-add\n....\n\nwith:\n\n....\nerror 1 at line 12\nMakefile:138: recipe for target 'test-add' failed\nerror 1 at line 12\n....\n\nsince `1 + 2` tends to equal `3` and not `4`.\n\nSo look how nice we are: we even gave you the line number `12` of the failing assert!\n\n=== Getting started on non-Ubuntu operating systems\n\nIf you are not on an Ubuntu host machine, here are some ways in which you can use this repo.\n\n==== Other Linux distro hosts\n\nFor other Linux distros, you can either:\n\n* have a look at what `download-dependencies` does and adapt it to your distro. It should be easy, then proceed normally.\n+\nMight fail due to some incompatibility, but likely won't.\n* run this repo with \u003c\u003cdocker-host-setup,docker\u003e\u003e. Requires you to know some Docker boilerplate, but cannot (?) fail.\n\n===== Docker host setup\n\n....\nsudo apt install docker\nsudo docker create -it --name arm-assembly-cheat -w \"/host/$(pwd)\" -v \"/:/host\" ubuntu:18.04\nsudo docker exec -it arm-assembly-cheat /bin/bash\n....\n\nThen inside Docker just add the `--docker` flag to `./download-dependencies` and proceed otherwise normally:\n\n....\n./download-dependencies --docker\nmake test\n....\n\nThe `download-dependencies` takes a while because `build-dep binutils` is large.\n\nWe share the repository between Docker and host, so you can just edit the files on host with your favorite text editor, and then just run them from inside Docker.\n\nTODO: GDB TUI GUI is broken inside Docker due to terminal quirks. Forwarding the port and connecting from host will likely work, but I'm lazy to try it out now.\n\n==== Non-Linux host\n\nFor non-Linux systems, the easiest thing to do is to use an Ubuntu virtual machine such as VirtualBox: link:https://askubuntu.com/questions/142549/how-to-install-ubuntu-on-virtualbox[].\n\nPorting is not however impossible because we use the C standard library for portability, see: \u003c\u003carchitecture-of-this-repo\u003e\u003e. Pull requests are welcome.\n\n[[rpi2]]\n==== Raspberry Pi 2 native\n\nYay! Let's see if this actually works on real hardware, or if it is just an emulation pipe dream?\n\nTested on link:https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2018-11-15/2018-11-13-raspbian-stretch-lite.zip[Raspbian Lite 2018-11-13] with this repo at commit bcddf29c8e00b30afe7b3643558b25f22a64405b.\n\nFor now, we will just compile natively, since I'm not in the mood for cross compilation hell today.\n\nlink:https://en.wikipedia.org/wiki/Raspberry_Pi[According to Wikipedia] the Raspberry Pi 2 V 1.1 which I have has a link:https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/README.md[BCM2836] SoC, which has 4 link:https://en.wikipedia.org/wiki/ARM_Cortex-A7[ARM Cortex-A7] cores, which link:https://en.wikipedia.org/wiki/List_of_ARM_microarchitectures[implement ARMv7-A], \u003c\u003cvfp,VFPv4\u003e\u003e and \u003c\u003cneon\u003e\u003e.\n\nTherefore we will only be able to run `v7` examples on that board.\n\nFirst connect to your Pi through SSH as explained at: https://stackoverflow.com/revisions/39086537/10\n\nThen inside the Pi:\n\n....\nsudo apt-get update\nsudo apt-get install git make gcc gdb\ngit clone https://github.com/cirosantilli/arm-assembly-cheat\ncd arm-assembly-cheat/v7\nmake NATIVE=y test\nmake NATIVE=y gdb-add\n....\n\nGDB TUI is slightly buggier on the ancient 4.9 toolchain (current line gets different indentation, does not break on the right instruction after `asm_main_after_prologue`, link:https://superuser.com/questions/180512/how-to-turn-off-gdb-tui[cannot leave TUI]), but it might still be usable\n\nThe Pi 0 and 1 however have a link:https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835/[BCM2835] SoC, which has an ARM1176JZF-S core, which implements the ARMv6Z ISA, which we don't support yet on this repo.\n\nBibliography: https://raspberrypi.stackexchange.com/questions/1732/writing-arm-assembly-code/87260#87260\n\n[[rpi3]]\n==== Raspberry Pi 3 native\n\nThe Raspberry Pi 3 has a link:https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837/README.md[BCM2837] SoC, which has 4 link:https://en.wikipedia.org/wiki/ARM_Cortex-A53[Cortex A53] cores, which implement ARMv8-A.\n\nHowever, as of July 2018, there is no official \u003c\u003carmv8\u003e\u003e image for the Pi 3, the same ARMv7 image is provided for both: https://raspberrypi.stackexchange.com/questions/43921/raspbian-moving-to-64-bit-mode\n\nThen we look at the following threads:\n\n* https://raspberrypi.stackexchange.com/questions/49466/raspberry-pi-3-and-64-bit-kernel-differences-between-armv7-and-armv8\n* https://raspberrypi.stackexchange.com/questions/77693/enabling-armv8-on-raspberry-pi-3-b\n\nwhich lead us to this 64-bit Debian based distro for the Pi: https://github.com/bamarni/pi64\n\nSo first we flash pi64's link:https://github.com/bamarni/pi64/releases/download/2017-07-31/pi64-lite.zip[2017-07-31 release], and then do exactly the same as for the Raspberry Pi 2, except that you must go into the `v8` directory instead of `v7`.\n\nTODO: can we run the `v7` folder in ARMv8? First I can't even compile it. Related: https://stackoverflow.com/questions/21716800/does-gcc-arm-linux-gnueabi-build-for-a-64-bit-target For runtime: https://stackoverflow.com/questions/22460589/armv8-running-legacy-32-bit-applications-on-64-bit-os\n\n=== GDB step debug\n\nDebug one example with GDB:\n\n....\nmake gdb-add\n....\n\nShortcut:\n\n....\n./t -g add\n....\n\nThis leaves us right at the end of the prologue of `asm_main` in link:https://sourceware.org/gdb/onlinedocs/gdb/TUI.html[GDB TUI mode], which is at the start of the assembly code in the `.S` file.\n\nStop on a different symbol instead:\n\n....\nmake GDB_BREAK=main gdb-add\n....\n\nShortcut:\n\n....\n./t -b main -g add\n....\n\nIt is not possible to restart the running program from GDB as in `gdbserver --multi` unfortunately: https://stackoverflow.com/questions/51357124/how-to-restart-qemu-user-mode-programs-from-the-gdb-stub-as-in-gdbserver-multi\n\nQuick GDB tips:\n\n* print a register:\n+\n....\ni r r0\n....\n+\nBibliography: https://stackoverflow.com/questions/5429137/how-to-print-register-values-in-gdb\n* print floating point registers:\n+\n** https://reverseengineering.stackexchange.com/questions/8992/floating-point-registers-on-arm/20623#20623\n** https://stackoverflow.com/questions/35518673/gdb-print-aarch64-advanced-simd-vector-registers-is-it-possible/54711214#54711214\n* print an array of 4 32-bit integers in hex:\n+\n....\np/x (unsigned[4])my_array_0\n....\n+\nBibliography: https://stackoverflow.com/questions/32300718/printing-array-from-bss-in-gdb\n* print the address of a variable:\n+\n....\np \u0026my_array_0\n....\n\nBibliography: https://stackoverflow.com/questions/20590155/how-to-single-step-arm-assembler-in-gdb-on-qemu/51310791#51310791\n\n==== Advanced usage\n\nThe default setup is opinionated and assumes that your are a newb: it ignores your `.gdbinit` and puts you in TUI mode.\n\nHowever, you will sooner or later notice that TUI is crappy print on break Python scripts are the path of light, e.g. link:https://github.com/cyrus-and/gdb-dashboard[GDB dashboard].\n\nIn order to prevent our opinionated defaults get in the way of your perfect setup, use:\n\n....\nmake GDB_EXPERT=y gdb-add\n....\n\nor the shortcut:\n\n....\n./t -G add\n....\n\n=== Disassemble\n\nEven though \u003c\u003cgdb-step-debug\u003e\u003e can already disassemble instructions for us, it is sometimes useful to have the disassembly in a text file for further examination.\n\nDisassemble all examples:\n\n....\nmake -j `nproc` objdump\n....\n\nDisassemble one example:\n\n....\nmake add.objdump\n....\n\nExamine one disassembly:\n\n....\nless -p asm_main add.objdump\n....\n\nThis jumps directly to `asm_main`, which is what you likely want to see.\n\nDisassembly is still useful even though we are writing assembly because the assembler can do some non-obvious magic that we want to understand.\n\n=== crosstool-NG toolchain\n\nCurrently we build just Binutils from source, but use the host GCC to save time.\n\nThis could lead to incompatibilities, although we haven't observed any so far.\n\nlink:https://github.com/crosstool-ng/crosstool-ng[crosstool-NG] is a set of scripts that makes it easy to obtain a cross compiled GCC. Ideally we should track it here as a submodule and automate from there.\n\nYou can build the toolchain with crosstool-NG as explained at: https://stackoverflow.com/revisions/51310756/6\n\nThen run this repo with:\n\n....\nmake \\\n  CTNG=crosstool-ng/.build/ct_prefix \\\n  PREFIX=arm-cortex_a15-linux-gnueabihf \\\n  test \\\n;\n....\n\n=== Build the documentation\n\nIf you don't like reading on GitHub, the HTML documentation can be generated from the README with:\n\n....\nmake doc\nxdg-open out/README.html\n....\n\n=== Custom build flags\n\nE.g., to pass `-static` for an emulator that does not support dynamically linked executables like link:https://stackoverflow.com/questions/50542222/how-to-run-a-dynamically-linked-executable-syscall-emulation-mode-se-py-in-gem5[gem5]:\n\n....\nmake CCFLAGS_CLI=-static\n....\n\n== Theory\n\n=== Architecture of this repo\n\n`qemu-arm-static` is used for emulation on x86 hosts. It translates ARM to x86, and forwards system calls to the host kernel.\n\nOS portability is achieved with the C standard library which makes system calls for us: this would in theory work in operating systems other than Linux if you port the build system to them.\n\nUsing the standard library also allows us to use its convenient functionality such as `printf` formatting and `memcpy` to check memory.\n\nNon-OS portable examples will be clearly labeled with their OS.\n\nThese examples show how our infrastructure works:\n\n* link:fail.S[]\n* link:userland/arch/arm/hello_driver.S[]\n* link:hello_common.S[]\n\n==== C driver\n\nWe link all examples against a C program: link:main.c[]. Sample simplified commands:\n\n....\narm-linux-gnueabihf-gcc -c -o 'main.o' 'main.c'\narm-linux-gnueabihf-gcc -c -o 'sub.o' 'sub.S'\narm-linux-gnueabihf-gcc -o 'sub.out' 'sub.o' main.o\n....\n\nThe C driver then just calls `asm_main`, which each `.S` example implements.\n\nThis allows us to easily use the C standard library portably: from the point of view of GCC, everything looks like a regular C program, which does the required glibc initialization before `main()`.\n\n== CONTRIBUTING\n\n=== Update QEMU\n\nhttps://stackoverflow.com/questions/816370/how-do-you-force-a-makefile-to-rebuild-a-target\n\n....\ngit -C qemu pull\nmake -B -C v7 qemu\nmake -B -C v8 qemu\n....\n\nIf the build fails due to drastic QEMU changes, first do:\n\n....\nmake qemu-clean\n....\n\nThen make sure that the tests still pass:\n\n....\nmake test\n....\n\n=== Bare metal\n\nThis tutorial only covers userland concepts.\n\nHowever, certain instructions can only be used in higher privilege levels from an operating system itself.\n\nHere is a base setup ARM programming without an operating system, also known as \"Bare Metal Programming\": https://github.com/cirosantilli/linux-kernel-module-cheat/tree/7d6f8c3884a4b4170aa274b986caae55b1bebaaf#baremetal-setup\n\nFeatures:\n\n* clean crosstool-NG build for GCC\n* C standard library powevered by Newlib\n* works on both QEMU and gem5\n\nHere are further links:\n\n* generic:\n** https://stackoverflow.com/questions/38914019/how-to-make-bare-metal-arm-programs-and-run-them-on-qemu/50981397#50981397 generic QEMU question\n** link:https://github.com/freedomtan/aarch64-bare-metal-qemu/tree/2ae937a2b106b43bfca49eec49359b3e30eac1b1[]: `-M virt` UART bare metal hello world, nothing else, just works\n** https://github.com/bravegnu/gnu-eprog Not tested.\n** https://stackoverflow.com/questions/29837892/how-to-run-a-c-program-with-no-os-on-the-raspberry-pi/40063032#40063032 no QEMU restriction\n** https://github.com/cirosantilli/raspberry-pi-bare-metal-blinker minimal, but not very QEMU friendly however because hard to observe LED: https://raspberrypi.stackexchange.com/questions/56373/is-it-possible-to-get-the-state-of-the-leds-and-gpios-in-a-qemu-emulation-like-t\n* raspberry PI:\n** https://raspberrypi.stackexchange.com/questions/34733/how-to-do-qemu-emulation-for-bare-metal-raspberry-pi-images/85135#85135 RPI3 specific\n** link:https://github.com/bztsrc/raspi3-tutorial[], getting started: https://raspberrypi.stackexchange.com/questions/34733/how-to-do-qemu-emulation-for-bare-metal-raspberry-pi-images/85135#85135\n** https://github.com/dwelch67/raspberrypi\n** https://github.com/BrianSidebotham/arm-tutorial-rpi\n* gem5:\n** https://github.com/tukl-msd/gem5.bare-metal bare metal UART example. Tested with: https://stackoverflow.com/questions/43682311/uart-communication-in-gem5-with-arm-bare-metal/50983650#50983650\n* games:\n** https://github.com/kcsongor/arm-doom PI 1 model B https://www.youtube.com/watch?v=jeHtktKtGYQ\n** https://github.com/Tetris-Duel-Team/Tetris-Duel Demo: https://www.youtube.com/watch?v=hTqKRdcKZ9k\n** https://github.com/ICTeam28/PiFox rail shooter https://www.youtube.com/watch?v=-5n9IxSQH1M\n\nx86 bare metal tutorial at: https://github.com/cirosantilli/x86-bare-metal-examples\n","funding_links":[],"categories":["\u003ca id=\"8c5a692b5d26527ef346687e047c5c21\"\u003e\u003c/a\u003e收集","Makefile"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcirosantilli%2Farm-assembly-cheat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcirosantilli%2Farm-assembly-cheat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcirosantilli%2Farm-assembly-cheat/lists"}