ARM32 Assembly on ARM64 Host

Posted on

Trying to get a ARM32 host to run 32bit assembly is harder than I expected. This is how to run 32bit assembly on a ARM64 bit host.

First install some cross compilation tools.

sudo apt install gcc-arm-linux-gnueabihf binutils-arm-linux-gnueabihf binutils-arm-linux-gnueabihf-dbg gcc gdb-multiarch

Now trying to assemble the following 32 bit example, that just prints “Hello World” will fail with the as command.

.section .text
.global _start

_start:
/* syscall write(int fd, const void *buf, size_t count) */
    mov r0, #1
    ldr r1, =msg
    ldr r2, =len
    mov r7, #4
    svc #0

/* syscall exit(int status) */
    mov r0, #0
    mov r7, #1
    svc #0

msg:
.ascii "Hello, World!\n"
len = . - msg
$ as asm32.s -o asm32.o
asm32.s: Assembler messages:
asm32.s:6: Error: operand 1 must be an integer register -- `mov r0,#1'
asm32.s:7: Error: operand 1 must be an integer register -- `ldr r1,=msg'
asm32.s:8: Error: operand 1 must be an integer register -- `ldr r2,=len'
asm32.s:9: Error: operand 1 must be an integer register -- `mov r7,#4'
asm32.s:13: Error: operand 1 must be an integer register -- `mov r0,#0'
asm32.s:14: Error: operand 1 must be an integer register -- `mov r7,#1'

But, using the new installed tools, it is possible to assemble the 32 bit assembly on a 64 bit host.

$ arm-linux-gnueabihf-as asm32.s -o asm32.o && arm-linux-gnueabihf-ld asm32.o -o asm32

$ file ./asm32 && ./asm32
./asm32: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, not stripped
Hello, ARM32!

And possible to debug the program using gdb-multiarch.

$ gdb-multiarch -q ./asm32
Reading symbols from ./asm32...(no debugging symbols found)...done.
(gdb) br _start
Breakpoint 1 at 0x10054
(gdb) r
Starting program: /home/debian/asm32

Breakpoint 1, 0x00010054 in _start ()
(gdb) disassemble
Dump of assembler code for function _start:
=> 0x00010054 <+0>: mov r0, #1
   0x00010058 <+4>: ldr r1, [pc, #36] ; 0x10084 <msg+16>
   0x0001005c <+8>: ldr r2, [pc, #36] ; 0x10088 <msg+20>
   0x00010060 <+12>: mov r7, #4
   0x00010064 <+16>: svc 0x00000000
   0x00010068 <+20>: mov r0, #0
   0x0001006c <+24>: mov r7, #1
   0x00010070 <+28>: svc 0x00000000
End of assembler dump.