Lab 4 - 64-bit Assembly Language Lab

 Today, I will discuss 64-bit Assembly Language Lab and modify the code to get the different results.

First, let's unpack the code examples to my home directory by using tar -xvf /public/spo600-assembler-lab-examples.tgz command.

Now I can find the directory in my home directory. Let's start the lab!

1. Review, build, and run the aarh64 assembly language programs. Take a look at the code using objdump -d objectfile and compare it to the source code.



Firstly, I ran the command so that it makes an object and the executable file.


Then I ran objdump -d hello so that it prints the object code.
 

$ objdump -d hello


hello:     file format elf64-littleaarch64



Disassembly of section .text:


00000000004000b0 <_start>:

  4000b0: d2800020 mov x0, #0x1                   // #1

  4000b4: 100800e1 adr x1, 4100d0 <msg>

  4000b8: d28001c2 mov x2, #0xe                   // #14

  4000bc: d2800808 mov x8, #0x40                  // #64

  4000c0: d4000001 svc #0x0

  4000c4: d2800000 mov x0, #0x0                   // #0

  4000c8: d2800ba8 mov x8, #0x5d                  // #93

  4000cc: d4000001 svc #0x0


The above is the result of object code and below is the source code. 

$ cat hello.s

.text

.globl _start

_start:

 

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 */

 

mov     x0, 0     /* status -> 0 */

mov     x8, 93    /* exit is syscall #93 */

svc     0          /* invoke syscall */

 

.data

msg: .ascii      "Hello, world!\n"

len= . - msg


When comparing the two, they are similar but have some differences, such as the object code printing numbers in hexadecimal format.



2. Fix the code to print a word each time it loops.

The basic code doesn't contain anything in the body of the loop so it does nothing while looping. 
.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     x19, min

loop:

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

    add     x19, x19, 1
    cmp     x19, max
    b.ne    loop

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

I added some code in the body of the loop and set the variable msg and the symbol len using .set
.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     x19, min

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 */ 
add x19, x19, 1 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" .set len , . - msg

Then, make the pure assembler source file be able to be run in an assembly program.
Below is the output I got.



Next, let's modify the code to make the message contains the index value as well.

.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     x19, min

loop:
    add    x18, x19, '0'   /* convert binary to digit char */
    adr    x17, msg+6      /* get a pointer to # position in msg */
    strb    w18, [x17]     /* write one byte only */

    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 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" .set len , . - msg

This is the output:

3.  Repeat the previous step for x86_64.


To do this, I moved to portugal server and run make command. Below is the output I got.



Then I ran objdump -d hello-gas for x86_64.    

$ objdump -d hello-gas


hello-gas:     file format elf64-x86-64



Disassembly of section .text:


0000000000401000 <_start>:

  401000: 48 c7 c2 0e 00 00 00 mov    $0xe,%rdx

  401007: 48 c7 c6 00 20 40 00 mov    $0x402000,%rsi

  40100e: 48 c7 c7 01 00 00 00 mov    $0x1,%rdi

  401015: 48 c7 c0 01 00 00 00 mov    $0x1,%rax

  40101c: 0f 05                syscall 

  40101e: 48 c7 c7 00 00 00 00 mov    $0x0,%rdi

  401025: 48 c7 c0 3c 00 00 00 mov    $0x3c,%rax

  40102c: 0f 05                syscall 




This is hello-gas.s file code.

$ cat hello-gas.s

/* 

   This is a 'hello world' program in x86_64 assembler using the 

   GNU assembler (gas) syntax. Note that this program runs in 64-bit

   mode.


   CTyler, Seneca College, 2014-01-20

   Licensed under GNU GPL v2+

*/


.text

.globl _start


_start:


movq $len,%rdx /* message length */

movq $msg,%rsi /* message location */

movq $1,%rdi /* file descriptor stdout */

movq $1,%rax /* syscall sys_write */

syscall


movq $0,%rdi /* exit status */

movq $60,%rax /* syscall sys_exit */

syscall


.section .data


msg: .ascii      "Hello, world!\n"

len = . - msg


Below is the loop code in x86_64 assembler:
.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

I modified the code to make it print the message.
.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:

    movq	$len,%rdx	/* message length */
    movq 	$msg,%rsi	/* message location */
    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

This is the output:


Now, let's modify it again to print the message with the index.
.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

    movq	$len,%rdx	/* message length */
    movq 	$msg,%rsi	/* message location */
    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

This is the output:




4. Extend the AArch64 code to loop from 00-30, printing each value as a 2-digit decimal number.


I used the code I used above.
To make it loop until 30, these are what to consider:
    1. max value should be 31.
    2. Both digits should be printed. Consider the msg location increments 1 for the single digit
    3. The tens' digit can be the value divided by 10.

Below is the code that meets the requirements:
.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) */

_start:

    mov     x19, min
    mov     x20, 10  

loop:

    udiv    x21, x19, x20   
    msub    x22, x20, x21, x19

    add     x18, x21, '0'  
    adr     x17, msg+6     
    strb    w18, [x17]     

    add     x18, x22, '0'  
    adr     x17, msg+7     
    strb    w18, [x17] 

    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 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: 00\n" .set len , . - msg

And this is the output:



4-1. Repeat the step for x86_64.

I improved the code to make it print from 0 to 30.
Below is the entire code.

.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) */

_start:
    mov     $min,%r15           /* loop index */
    mov     $10, %r13           /* divisor */

loop:
    mov     $0, %rdx
    mov     %r15, %rax
    div     %r13
    mov     %rax, %r14
    add     $'0', %r14
    cmp     $'0', %r14

    movb    %r14b, msg+6
    mov     %rdx, %r14
    add     $'0', %r14
    movb    %r14b, msg+7

    movq	$len,%rdx	/* message length */
    movq 	$msg,%rsi	/* message location */
    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: 00\n"
	len = . - msg

After I run the code, I got this output:



5. Change the code as needed to suppress the leading zero (printing 0-30 instead of 00-30).

I modified the code that I used above for AArch64.
Here is the entire code to print the message without the leading zero.

.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) */

_start:

    mov     x19, min
    mov     x20, 10  

loop:

    udiv    x21, x19, x20   
    msub    x22, x20, x21, x19

    add     x18, x21, '0' 
    
    cmp     x18, '0'
    b.ne    single_digit
    mov     x18, ' '

single_digit:
    adr     x17, msg+6
    strb    w18, [x17]     
    add     x18, x22, '0'  
    adr     x17, msg+7     
    strb    w18, [x17] 

    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 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: 00\n" .set len , . - msg

The output is:




5-1. Repeat the step for x86_64.

I modified the code to make the leading zero a single space for single digit outputs.
This is the final code:

.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) */

_start:
    mov     $min,%r15           /* loop index */
    mov     $10, %r13           /* divisor */

loop:
    mov     $0, %rdx
    mov     %r15, %rax
    div     %r13
    mov     %rax, %r14
    add     $'0', %r14
    cmp     $'0', %r14
    jne     single_digit
    mov     $' ', %r14

single_digit:
    movb    %r14b, msg+6
    mov     %rdx, %r14
    add     $'0', %r14
    movb    %r14b, msg+7

    movq	$len,%rdx	/* message length */
    movq 	$msg,%rsi	/* message location */
    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: 00\n"
	len = . - msg

The output is:





Reflection

During this lab, I found it challenging to write and debug assembly code compared to other programming languages. While having reference code eased the process to some extent, in the final stages, I had to carefully modify the code and verify each change to identify where things went wrong.





Comments

Popular posts from this blog

Demystifying Machine Learning

Unveiling the World of Software Development Methodologies: Agile, Scrum, and DevOps Made Simple

Big Data Unveiled