Assembler Removing Zeros

This builds on the two previous posts about aarch64 and x86_64 assembly language.

Our target output is:

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

For aarch64 removing the leading zeros is a simple change. After calculating the division and remainder check if the quotient is zero. If it is jump over the tens stuffing to the ones stuffing.

X86_64 is also a similar change, the only difference is on x86_64 I had to move 0 into a register and then compare.

After all these examples my conclusion is that aarch64 is nicer to program in and typically is more flexible than x86_64. It also is more logical to read than x86_64 code is. Overall I personally really enjoy working in assembler, as I enjoy working close to the hardware, and writing the most efficient code I can.

Aarch64 code:


.text
.globl _start

start = 0
max = 30
offset = 48
divisor = 10

_start:
mov x19, start
mov x23, divisor
_loop:
adr x21, msg /* put msg into register 21 */

udiv x20, x19, x23 /* divide index by divisor, store into x20 */
msub x22, x20, x23, x19 /* calculate remainder and store into x22 */

cmp x20, 0 /* quotient is 0*/
b.eq _ones /* branch if quotient is zero */

/* tens */
add x24, x20 ,offset /*add offset to division result*/
strb w24, [x21, 6] /* move addition result into msg + 6*/

_ones:
/* ones */
add x24, x22, offset /*add offset to remainder */
strb w24, [x21, 7] /* move into msg+7 */

mov x0, 1 /* file descriptor: 1 is stdout */
adr x1, msg /*message location (memory address) */
mov x2, len /* message length (bytes) */

mov x8, 64 /* write is syscall #64 */
svc 0 /*invoke syscall */

add x19,x19,1 /*LOOP CHECKING STUFF*/
cmp x19,max
b.ne _loop

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

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

X86_64 Code


.text
.globl _start

start = 0 /* starting value for the loop index; note that this is a symbol (constant), not a variable */
max = 30 /* loop exits when the index hits this number (loop condition is i max) */
offset = 48
divisor = 10
zero = 0

_start:
mov $start,%r15 /* loop index */

loop:
/* ... body of the loop ... do something useful here ... */

movq $zero, %rdx /* move zero into %rdx, this is needed for the division*/
movq %r15, %rax /* move index into %rax */
movq $divisor, %r10 /* move divisor into register 10*/
div %r10 /* divide rax by register 10 */

movq $zero, %rcx
cmp %rax, %rcx
je ones

movb $offset, %bl /*mov offset into register b*/
/* tens digit */
add %rax, %rbx /* add offset and division result */
mov %bl, msg + 6 /* move into position */

ones:
/* ones digit */
movb $offset, %bl
add %rdx,%rbx /* add offset and division remainder */
mov %bl, msg + 7 /* move into position */

movq $len,%rdx
movq $msg,%rsi
movq $1,%rdi /* file descriptor stdout */
movq $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