In this lab, I learned how to write a basic for loop and create if else conditions and I found a lot of fun.
During a previous class, professor taught me how the syntaxes of 2 architectures: x86_64 and aarch64. He showed me how to create a basic program that prints out the iteration index 10 times. My responsibility is to update the program and let it runs 30 times.
At first I thought it was easy (in JavaScript it takes only 3 lines to do so) and then I realized that this was Assembly and I still have PTSD about the time I worked on lab 1 and 2. However, I think because I worked with 6502 before, this was not as difficult as I think. Or maybe because I didn't have to work with a screen, I don't really know.
Anyways, here is the code:
Aarch64:
.text
.globl _start
min = 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) */
divider = 10
_start:
mov x19, min
mov x20, divider
loop:
/*convert loop counter to char*/
udiv x15, x19, x20 /* divide x19 by x20, store the result in x15 */
msub x9, x15, x20, x19 /* Calculate x19-(x15*x20) to get the remainder and store it in x9 */
adr x14, msg+6 /*Store the location of tens character in x14*/
adr x10, msg+7 /*Store the location ones character in x10*/
add x9, x9, 0x30 /* add 48 to convert to char */
strb w9, [x10] /*Update the value of in x10 with the value in w9*/
cmp x15, 0 /* Check if the value in tens is 0 */
b.eq changeToSpace /* Jump to setup if that's the case */
add x15, x15, 0x30 /* add 48 to convert to char */
cmp x15, 0
b.ne updateTens /*jump to another branch to update the tens*/
changeToSpace:
mov x15, 0x20 /*change 0 to space*/
updateTens:
strb w15, [x14] /*Update the value of in x13 with the value in w15*/
setup:
/* set up the loop */
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 */
/* Continue the loop */
add x19, x19, 1
cmp x19, max
b.ne loop
/* exit the 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:
.text
.globl _start
min = 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) */
divider = 10
_start:
mov $min, %r15
mov $divider, %r12 /* assign divider to r12 */
loop:
/*set up rdx and rax*/
mov $0, %rdx /* set rdx to be 0 */
mov %r15, %rax /* load rax with the index value in r15 */
div %r12 /* divide the counter by 10 */
mov %rax, %r10 /* assign the quotient to r10 */
mov %rdx, %r9 /* assign the remainder to r9 */
add $'0', %r9 /* convert to number */
mov %r9b, msg+7 /* assign r9 value to the ones */
cmp $0, %r10 /* compare r10 value with 0 */
jne addNumber /* if not then add '0' to update ascii */
mov $' ', %r10 /* else change it to space */
jmp updateTens /* jump to assignment */
addNumber:
add $'0', %r10 /* convert to number */
updateTens:
mov %r10b, msg+6 /* assign r10 value to the tens */
print:
/* Print the message */
movq $len,%rdx /* message length */
movq $msg,%rsi /* message location */
movq $1,%rdi /* file descriptor stdout */
movq $1,%rax /* syscall sys_write */
syscall
/* continue the loop */
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
Before we can run this code, we first need to compile it. To save us sometimes, we should create a script (a Makefile) that would run this for use when we call make. Here is the content of the file that my professor showed me:
Makefile:
loop: loop.s
as -g loop.s -o loop.o
ld -g loop.o -o loop
After we run this Makefile, we should have an executable file called loop. When we call the file, here is the result I have in both programs:
Result:
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
Lookback:
I found both architectures interesting, I like some syntaxes in both and hate some as well. For example, in aarch64, I don't like the fact that we don't have to ability to do branch without condition, I tried br label but it would requires me to assign the address of the label to another register to do so, which means I have to write another line, and I'm quite lazy. For x86_64 though, I'm not a big fan of their divide syntax. Since we have to share/use rax/rdx to access the quotient and remainder, I think that this could make someone who are new like make accidentally overwrite some existing values. I would have to transfer those values to some other register first, which means I would have to write another 2 lines if I have a bigger program.
Conclusion:
This lab is really fun, I find it interesting. Hopefully with this excitement, I can make some meaning contribution to the coming project. I really want to see how far I can go and how much I can contribute.
Comments
Post a Comment