SPO 600 - Lab 3

In Lab 3, I'll be looking at Assembler and Assembly Language. For this lab, I will write a program that prints a message and its loop count for each iteration - in Assembly Language.

Here's the expected output:
Loop: 0
Loop: 1
Loop: 2
Loop: 3
Loop: 4
Loop: 5
Loop: 6
Loop: 7
Loop: 8
Loop: 9


Looks quite simple, isn't it? Well, in C that would get the job done:

#include <stdio.h>

int main(){
    for(int i = 0; i < 10; i++){
        printf("Loop: %d\n", i);
    }
    return 0;
}

But in Assembly Language, it is much more complicated. In fact, you actually have to manually convert the number into ASCII, concatenate it into the string, and then print it out:

.text
.globl    _start

start = 0                       
max = 10                        

_start:
    mov     $start,%r15         

loop:
    mov     %r15,%r14
    add     $48,%r14
    mov     %r14b,msg+6
    movq    $len,%rdx
    movq    $msg,%rsi
 
    mov     $1,%rdi                    
    mov     $1,%rax                         
    syscall

    inc     %r15                
    cmp     $max,%r15           
    jne     loop                

    mov     $0,%rdi             
    mov     $60,%rax            
    syscall

.section .data
msg: .ascii "Loop:  \n"
.set len , . - msg

The next part of this lab can be quite tricky, if not confusing - I have to print 0 to 30 (with leading zeros), like this:

Loop: 00
Loop: 01
Loop: 02
Loop: 03
Loop: 04
Loop: 05
...
Loop: 29
Loop: 30
 

Once again, a simple job in high-level programming languages like C, but not in Assembly Language. To print a double-digit number in Assembly, I will have to do some math first - more specifically, division. In x86_64 assembly, idiv takes one operand, but it uses the value stored in rax as dividend. The quotient and remainder is stored in rax and rdx, respectively. 

After doing all that math, all I have to do is to concatenate the 2 digits I extracted into the string. 

Next, I have to write the same program for the aarch64 architecture. The logic is pretty much the same, but in aarch64 architecture I have to use msub instead.

msub takes four operands and does a multiply and subtract operation. This is useful for calculating the remainder of an integer division, for example:

msub r0,r1,r2,r3 

means "load r0 with r3-(r1*r2)".

Conclusion

Overall my experience with assembler is positive. Although it is so low-level I can't even print a number out without converting it ASCII by myself, I do found programming in Assembly Language very amusing. On a side note, after writing programs in Assembly Language, I finally understand why C was a high-level programming language in the 1980s.

Regarding x86_64 and aarch64 assembler, I personally doesn't found too much differences between them, only in aarch64, I don't have to put a percentage and dollar sign before the registers and Immediate values, respectively like x86_64 did - which makes my life a bit easier.

On the other hand, instructions in x86_64 are read from left to right, while in aarch64 some instructions are read from left to right (e.g. ldr, str and strb), some instructions are read from right to left (e.g. add, mov and cmp). Since I have been reading things from left to right throughout my entire life, instructions in aarch64 can be quite difficult to read. (I know, Classical Chinese are read from right to left, but by the time I am learning Chinese, it is already read from left to right.)

In general, I am fine with writing programs on either architecture.

If anyone is interested in the source code of programs I wrote, you can find it at here:
https://github.com/wu-geoff/SPO600/blob/master/xerxes/lab3/step8/lab3.s 
https://github.com/wu-geoff/SPO600/blob/master/aarchie/lab3/step9/hello.s

Comments

Popular posts from this blog

SPO 600 Project - Stage 1

SPO 600 - Lab 5

SPO 600 - Lab 1