ARM Assembly for Hackers, Part 2: Leveraging GDB to Understand the ADD Instruction
Welcome back, cyberwarriors!
In a previous article, we explored some of the ARM assembler commands. Today, we will delve into the practical application of the ADD instruction. By leveraging the power of the GNU Debugger (GDB), we will explore how to analyze and manipulate this instruction to gain deeper insights into ARM architecture.
Prepare an Environment
Before starting to learn assembly, we should prepare an environment. About possible ways to do so, you can check out this article. Iβll be using a Raspberry Pi with 32-bit Raspbian OS.
To check if your system is running a 32-bit userland, run:
raspberrypi> getconf LONG_BIT
Next, check what architecture your binaries are:
raspberrypi> file /bin/bash

In the case above, you can see a pretty common issue on modern Raspberry Pis: Raspbian OS is 32-bit, but uses a 64-bit kernel. This is an optimal installation, because you get 32-bit compatibility for all your applications and libraries, and better hardware support from a 64-bit kernel.
ADD Instruction
This instruction adds an immediate value to a register value and writes the result to the destination register.
The syntax is as follows:
ADD{S}{<c>}{<q>} {<Rd>,} <Rn>, #<const>
Where
S β if presented, the instruction updates the flags. Weβll talk about flags later;
<Rd> β destinations register;
<Rn> β first operand;
<const> β the immediate value to be added to the value obtained from <Rn>;
<c> and <q> β are optional assembler fields.
Letβs move on to the practical stage and write the code. Iβll create a file instructions.s and open it with Vim.
The beginning of the file is as usual β declare β_startβ value globally. Iβve explained this step in more detail in the following article. Also, Iβll add a comment with the add instruction syntax for ease of learning.

First of all, we need to have a register (<Rn>) that will be added to our constant value (#<const>). Weβre going to set up a general-purpose register with the mov instruction.
As you might already remember from my previous article, general-purpose registers are r0-r12.

To set up a general-purpose register with a value of our choice, we can use the following command:
mov r0, #7
Where
mov β instruction to copy the value to the register;
r0 β destination register, where weβre going to store a temporary value;
#7 β pound sign signifies that the following value is constant. For this example, Iβve used number 7; you can choose any you want.
After that, weβre good to go with our add instruction.
add r1, r0, #3

Where
r1 is the destination register where weβre going to store the sum of 7 + 3
r0 β our first operand with value 7.
#3 β constant value that will be added to r0. Iβve used value 3.
At this point, letβs assemble this code and see in gdb (GNU Debugger) what is happening.
To assemble, Iβll be using a GCC:
gcc -g -nostdlib -static -o instructions instructions.s

Where
-g β Include debugging information
-nostdlib β Donβt link with standard library (since weβre not using it)
-static β Create a static executable
Now, we can open the executable with GDB, but before that, Iβll install GEF (GDB Enhanced Features), which provides automatic register monitoring, color-code output, and more.
To install GEF, run:
raspberrypi> bash -c "$(curl -fsSL https://gef.blah.cat/sh)"
Now, letβs run GDB:
gdb ./instructions

First of all, Iβm going to disable displaced stepping to avoid some possible errors in GDB.
(gdb) set displaced-stepping off
After that, we can set a breakpoint at the _start label so execution stops there:
(gdb) break _start

Run our program:
(gdb) run

Here we can see that the program started execution but stopped in _start because of the breakpoint.
Letβs check the value of all registers:
(gdb) info registers

They are empty at this point. Letβs step through one assembly instruction:
(gdb) stepi
And check the value of only register r0 and r1
(gdb) info registers r0 r1

And here we can see that register r0 already stores the value 0x7 or 7 in decimal.
If we step through the next assembly instruction and check the register value again with the same commands, we can see the value of the r1 register.

Value of r1 is 0xa or 10 in decimal, just like we programmed.
Summary
In this article, we take a look at the ADD instruction in ARM assembly language. We walk through assembling the code with GCC and using GDB (GNU Debugger) to monitor execution and inspect register values, demonstrating how the results reflect the programmed additions. Understanding such low-level behavior is essential in exploit development, where manipulating register values and controlling program flowβsuch as redirecting execution or crafting return-oriented programming (ROP) chainsβdepends on precise knowledge of how instructions like ADD affect the system state.
The post ARM Assembly for Hackers, Part 2: Leveraging GDB to Understand the ADD Instruction first appeared on Hackers Arise.