DEV Community

gus
gus

Posted on

x86_64 Assembly Language

In my last post we went through writing a program for printing a message with a 2 digit incrementing value in AArch64 assembly. This time, we're going to tackle the same thing on an x86_64 architecture system.

Starting with the original code we're given:

.text .globl _start min = 0 /* starting value for the loop index; note that this is a symbol (constant), not a variable */ max = 10 /* loop exits when the index hits this number (loop condition is i<max) */ _start: mov $min,%r15 /* loop index */ loop: /* ... body of the loop ... do something useful here ... */ 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 
Enter fullscreen mode Exit fullscreen mode

First we need to add logic to print a message, like so:

.text .globl _start min = 0 /* starting value for the loop index; note that this is a symbol (constant), not a variable */ max = 10 /* loop exits when the index hits this number (loop condition is i<max) */ _start: mov $min,%r15 /* loop index */ loop: mov $len,%rdx /* message length */ mov $msg,%rsi /* message location */ mov $1,%rdi /* file descriptor stdout */ mov $1,%rax /* syscall sys_write */ 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 .section .data msg: .ascii "Loop\n" len = . - msg 
Enter fullscreen mode Exit fullscreen mode

By adding the provided text output code as above we get the following output:

Loop Loop Loop Loop Loop Loop Loop Loop Loop Loop 
Enter fullscreen mode Exit fullscreen mode

Now by adding logic to iterate an index and add it to the msg string, we get the following:

.text .globl _start min = 0 /* starting value for the loop index; note that this is a symbol (constant), not a variable */ max = 10 /* loop exits when the index hits this number (loop condition is i<max) */ _start: mov $min,%r15 /* loop index */ loop: mov %r15,%r14 add $'0',%r14 movb %r14b,msg+6 mov $len,%rdx /* message length */ mov $msg,%rsi /* message location */ mov $1,%rdi /* file descriptor stdout */ mov $1,%rax /* syscall sys_write */ 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 .section .data msg: .ascii "Loop: #\n" 
Enter fullscreen mode Exit fullscreen mode

With the resulting output:

Loop: 0 Loop: 1 Loop: 2 Loop: 3 Loop: 4 Loop: 5 Loop: 6 Loop: 7 Loop: 8 Loop: 9 
Enter fullscreen mode Exit fullscreen mode

Finally, we'll move to printing a 2 digit index along with our loop by making the following changes:

.text .globl _start min = 0 /* starting value for the loop index; note that this is a symbol (constant), not a variable */ max = 15 /* loop exits when the index hits this number (loop condition is i<max) */ _start: mov $min,%r15 mov $10,%r13 loop: mov %r15,%rax mov $0,%rdx div %r13 cmp $0,%rax je secondDigit add $'0',%rax mov %rax,%r12 movb %r12b,msg+6 secondDigit: add $'0',%rdx mov %rdx,%r12 movb %r12b,msg+7 mov $len,%rdx /* message length */ mov $msg,%rsi /* message location */ mov $1,%rdi /* file descriptor stdout */ mov $1,%rax /* syscall sys_write */ 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 .section .data msg: .ascii "Loop: #\n" len = . - msg 
Enter fullscreen mode Exit fullscreen mode

Which gets us the appropriate output:

Loop: #0 Loop: #1 Loop: #2 Loop: #3 Loop: #4 Loop: #5 Loop: #6 Loop: #7 Loop: #8 Loop: #9 Loop: #10 Loop: #11 Loop: #12 Loop: #13 Loop: #14 Loop: #15 Loop: #16 Loop: #17 Loop: #18 Loop: #19 Loop: #20 Loop: #21 Loop: #22 Loop: #23 Loop: #24 Loop: #25 Loop: #26 Loop: #27 Loop: #28 Loop: #29 Loop: #30 
Enter fullscreen mode Exit fullscreen mode

Again this looks like the output we're looking for, so I'll break down how we got here and leave some parting thoughts on writing assembly programs for x86_64 vs my experience writing for AArch64.

_start: mov $min,%r15 mov $10,%r13 
Enter fullscreen mode Exit fullscreen mode

Starting off with the start section, we move the value of min to r15 and set r13 to 10, which we'll use to divide and split our 2 digits. Remember in this syntax the destination register is placed on the right, contrary to how it was arranged in the AArch64 program.

loop: mov %r15,%rax mov $0,%rdx div %r13 cmp $0,%rax je secondDigit 
Enter fullscreen mode Exit fullscreen mode

Next we place the value to be divided into rax and clear rdx to accept the remainder, before using the div instruction to divide what's in the rax register. We compare the value placed in rax, our "tens" column, to zero and branch to the secondDigit section if there's no tens column.

 add $'0',%rax mov %rax,%r12 movb %r12b,msg+6 
Enter fullscreen mode Exit fullscreen mode

In the first line here we add an ascii 0 to the result of the division, after which we move that to r12 and finally move a byte of that with movb to the address of the pound sign in msg.

secondDigit: add $'0',%rdx mov %rdx,%r12 movb %r12b,msg+7 
Enter fullscreen mode Exit fullscreen mode

Again here we add an ascii 0, this time to the remainder from the previous division, and then move that to r12 to have a byte moved to the pound sign address in msg. Like the last program, I'll end my breakdown here as the rest is pretty self evident and discuss my experience with x86_64.

This was pretty similar to assembly in AArch64 in a lot of ways, there were some minor syntactical differences like the precedence of operands listed above, and $ and % symbols being used to denote immediate values and registers, respectively. I'd be hard pressed to pick one I prefer, but if I had to I'd lean toward the AArch64 for its syntax, which I find slightly more readable. The difference is pretty negligible though. I also like the philosophy of improvement and not being weighed down by legacy features and nomenclature that comes with x86_64, but that hasn't affected my coding on either to any great extent thus far.

Overall this was a good challenge and I'm looking forward to diving deeper into these architectures.

Top comments (0)