Writing Assembler code for x86_64 & Aarch64 architectures

Printing a loop message output on both x86_64 and Aarch64 architectures.

Output:

Loop: 00 
Loop: 01 
Loop: 02 
Loop: 03 
Loop: 04 
Loop: 05 
Loop: 06 
Loop: 07 
Loop: 08 
Loop: 09 
Loop: 10 
Loop: 11 
...
Loop: 30

x86_64

This is a reference guide to what our group followed in order to generate the output above on a x86_64 architecture.

Source code

.text                         /* or section.text - used for keeping the actual code */
.globl    _start              /* tells kernel where program execution begins */

start = 0                     /* starting value for the loop index; note that this is a symbol (constant), not a variable */
max = 31                      /* loop exits when the index hits this number (loop condition is i<max) */
zero = 48                     /* start of decimal notation for character 0 */

_start:
    mov     $start,%r15       /* loop index start is in register 15 */
    mov     $10,%r13          /* put value 10 into register 13 */

loop:
    mov     $zero,%r14        /* loop index */
    mov     %r15,%rax         /* move data from register 15 into accumulator register */
    mov     $0,%rdx           /* put value 0 into data register */

    div     %r13              /* divide rax by register 13 and put quotient into rax and remainder into rdx*/

    mov     $zero,%r14        /* loop index */
    add     %rax,%r14         /* add quotient(in rax) to register 14 */
    movb    %r14b,msg+6       /* add 6 bits to register 14 */

    mov     $zero,%r14        /* loop index */
    add     %rdx,%r14         /* add remainder(in rdx) to register 14 */
    movb    %r14b,msg+7       /* add 7 bits to register 14*/

    movq    $len,%rdx
    movq    $msg,%rsi
    movq    $1,%rax
    syscall

    inc     %r15              /* increment index */
    cmp     $max,%r15         /* see if we're done */
    jne     loop              /* loop if we're not */

    mov     $0,%rdi           /* exit status */
    mov     $60,%rax          /* syscall sys_exit */
    syscall

.data                         /* for SEGFAULT error, stores as read/write */

msg:    .ascii "Loop:    \n"
        len = . - msg

Our idea here was to leave some blank space in our msg string “Loop:    \n”, and have the quotient and remainder of 10 divided by the loop index added to the address of the msg + 6 bytes for the first digit and msg + 7 bytes for the second digit to produce the 2-digit decimal number after “Loop: “.

Layout asm

gdb’s layout asm was a useful debugging tool to help me figure out exactly what was going on in the memory and registers.

So for example, on the source code above(“lab3.s”), you could do:
as -g -o lab3.o lab3.s

  • -o: output filename
  • -g: request that symbol information be attached to the binary for debugging purposes

Run the linker:
ld -o lab3 lab3.s

Run GNU debugger:
gdb lab3

Some useful debugging commands:

  • Set a breakpoint: b 19
  • Start program: r
  • Switch to asm layout:layout asm
  • Step one line: s
  • Step over (don’t go into function call): n
  • Print value in register: info register 14 or i r 14
  • Print value in specific address: print "%s\n", 0x30
  • Add x number of bits to an address:

    print "%s\n", 0x30+4
    print "%s\n", 0x30+8
    etc.

Aarch64

Here is a reference to replicate the same output on the AArch64 architecture.

I was able to replicate a similar solution to the one for the x86_64 architecture.

.text
.globl _start

start = 0   /* loop index */
max = 31    /* number to stop loop at */
num = 48   /* starting ascii value for 0 number */
/* index = %r10 - to store register 10 into index macro */

_start:
    mov     x3,start

loop:
    mov     x4,10           /* for calculating quotient/remainder */

    /* calculate quotient - store in x6 */
    udiv    x6,x3,x4      /* x6 = x3 / 10 */

    /* calculate remainder - store in x7 */
    msub    x7,x4,x6,x3   /* x7 = x3 - (10 * x6) */

    adr     x1, msg         /* msg location memory address */
    add     x6,x6,num       /* atoi */
    add     x7,x7,num       /* atoi */
    strb    w6,[x1,6]       /* store in msg + 6 bytes memory location */
    strb    w7,[x1,7]       /* store in msg + 7 bytes memory location */

    /* print */
    mov     x0,1            /* file descriptor: 1 is stdout */
    mov     x2,len
    mov     x8,64           /* write is syscall #64 */
    svc     0               /* invoke syscall */

    add     x3,x3,1         /* increment index */
    cmp     x3,max          /* check for end of loop */
    bne     loop            /* loop if compare returns false */

    mov     x0,0            /* status -> 0 */
    mov     x8,93           /* exit is syscall #93 */
    svc     0               /* invoke syscall */
 
.data

msg:    .ascii  "Loop:    \n"
        len = . - msg

Differences between the x86_64 and Aarch64 architectures syntax:

  1. Register names:
    • x86_64: prefixed by %
    • Aarch64: not prefixed
  2. Immediate values:
    • x86_64: prefixed by $
    • Aarch64: not prefixed
  3. Functions:
    • x86_64:
    • div %r13 – calculates the quotient and remainder.  It takes one register argument (%r13), and divides value in rax from it, storing the quotient in rax, and remainder in rdx

    • Aarch64: two operator functions are required for this.
    • udiv x6,x3,x4 – divides x3 by x4 and stores quotient into x6
      msub x7,x4,x6,x3 – subtracts x3 by (x4 * x6) and stores remainder in x7

  4. Arguments:
    • x86_64: Data sources are given as first argument
    • Aarch64: Destination is given as first argument

Conclusion

Wrapping my head around how the different registers work, memory operations and overall syntax was difficult, but once I had a look at the disassembly, I was able to get a better view of what was going on in memory after analyzing each executed line of code.  After that, translating the syntax from one architecture to another was relatively simple, at least for what was required for generating this output.

More useful links:
ARM Instruction Set Overview

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s