I’m trying to write some basic ARM shell code that loads up the r0 register with 0. I cannot use null characters. I can see that

subs r2, r2, r2

sets r2 to 0 without using any null bytes.

However, any attempts to move r2 to r0, results in shell code that uses null bytes. Any advice on what I could do?

  • Just a quick idea that i can't verify right now - can't you push r2 and pop r0 ? IIrc, the register sets to be pushed and popped are bitfields in these instructions. If this doesn't work, maybe something like push r2,r3 then pop r0,r3 works. Commented Oct 15, 2015 at 14:09
  • arm, thumb or thumb2 ? And which processor model are you targeting exactly ?
    – w s
    Commented Oct 15, 2015 at 14:10
  • you can push/pop (str/ldr) as Guntram suggests, or you can store/load from memory (stm/ldm) by using non-zero offsets, but you can't move it directly. Commented Oct 15, 2015 at 15:35
  • @GuntramBlohm subs r2, r2, r2;push {r2, r3};pop {r0, r3}; seems to assemble to "\x02\x20\x52\xe0\x0c\x00\x2d\xe9\x09\x00\xbd\xe8" and is hence not usable. Same case with push r2; pop r0;
    – user1743
    Commented Oct 16, 2015 at 5:54
  • 1
    You're right, the 1st byte of the 2nd and 3rd instruction is a bit field for registers 0-7, the 2nd byte (which is zero) is r8-r15. So you can use push {r2.r8}; pop{r0,r8} which assembles to 02 20 52 e0 04 01 2d e9 01 01 bd e8. Commented Oct 16, 2015 at 6:28

1 Answer 1


Copy/pasted from the online disassembler:

.data :00000000  e0522002 subs r2, r2, r2
.data :00000004  e92d0104 push {r2, r8}       
.data :00000008  e8bd0101 pop {r0, r8}

Or, in thumb mode (the push/pop instructions are actually the same, seemingly being byte-swapped due to endianness):

.data :00000000 1a92 subs r2, r2, r2
.data :00000002 0104e92d stmdb r13!, {r2, r8}
.data :00000006 0101e8bd ldmia.w r13!, {r0, r8}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.