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