ASM code blocks in Emacs Org Mode
Compilling Assembly on Org Mode Source Blocks.

Table of Contents

Introduction

I have recently started reading the book Programming from the Ground Up, which I saw recommended on various threads about learning low level programming and the fundamentals of computing.

The book starts off with some assembly programming. My initial approach to follow the various presented examples and exercises was to write each of them on a separate asm file. This, however, was not a satisfactory workflow for me, because I did not have a good way of structuring my notes.

More specifically, I want to have my source code and notes all on the same file, and I also want to run the source code and get the result on my document.

This is the perfect task for Org Mode, and I ended up hacking something that I feel improved my note taking process, which I am sharing in this post. Hope you enjoy.

Source code in Org files

In Org Mode it's possible to embed and run source code blocks in the org files. This is done via Org Babel, which out of the box supports quite a few languages.

For example, we could write some Python code and run it by pressing C-c on the code block. This will also display the result, as shown in the following example.

#+begin_src python :results output
a = 3
b = 4
print(a + b)
#+end_src

#+RESULTS:
: 7

The #+RESULTS: line, and the : 7 that follows it, get created automatically by Org Mode when the code of the preceding source block is run. There are quite a few customization options for this, feel free to read all about it here.

Org Mode with assembly code blocks

Unfortunately, asm does not seem to be part of the list of the official supported languages. For that reason, I ended up writing my own custom org babel executor, that is, the code that runs when I press C-c on a code block.

  (defun get-temp-file-path (file_name)
    "Returns the path to a tmp file"
    (concat temporary-file-directory file_name)
    )

  (defun org-babel-execute:asm (body params)
    "Compiles, links and runs a single asm file"
    (let (
          (tmp-src-path (get-temp-file-path "code.s"))
          (tmp-obj-path (get-temp-file-path "obj.o"))
          (tmp-exe-path (get-temp-file-path "exe"))
          )
      (with-temp-file tmp-src-path (insert body) )
      (shell-command (format "as %s -o %s" tmp-src-path tmp-obj-path))
      (shell-command (format "ld %s -o %s" tmp-obj-path tmp-exe-path))
      (shell-command tmp-exe-path)
      )
    )

The executor is a function with the name org-babel-execute:lang, where lang is the name of the language of the source block, in my case it's asm. The function should take the arguments body and params, where the first is the code of the source block and the latter it's parameters.

With this executor I can now run the following code on my org files and get the result.

#+begin_src asm
.section .data

data_items:
  .long 33,22,77,44,1,200,0

.section .text

.globl _start

_start:
  movl $0, %edi
  movl data_items(,%edi,4), %eax
  movl %eax, %ebx

start_loop:
  cmpl $0, %eax
  je loop_exit
  incl %edi
  movl data_items(,%edi,4), %eax
  cmpl %ebx, %eax
  jle start_loop

  movl %eax, %ebx
  jmp start_loop

loop_exit:
  movl $1, %eax
  int $0x80

#+end_src

#+RESULTS:
: 200

The result 200 is the exit code of the source block, after it get's compiled and run.

This executor will only compile and link a single code block. The functionality to compile and link various asm source code blocks and run the resulting program could probably be achieved via the params executor parameter, but I have not yet experimented with this.

Conclusion

In this post I wrote a simple (hacky) custom asm babel executor which ended up making my note taking much easier, faster and organized. I also got a better understanding on how code blocks get evaluated in Org Mode, and how can I customize this process. This is very valuable knowledge for me, because I will be making use of Org Mode for taking notes of the various programming books I will be reading in the future.

Thanks for reading!