Using Assembler To Build A Program in Linux(x86_64 and Arm aarch64)

This blog will be about the Assembler language designed for two systems. (arm aarch64 and the x86_64 systems)

I will be using the objdump program in Linux for analyzing the assembly language in a compiled C language program.

Command: objdump -d program_1

First, I will be analyzing an assembly language code for “Hello World!” written by CTyler of Seneca College.

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

msg: .ascii "Hello, world!\n"
len = . - msg

Note: The assembly language source code has the declaration of variables at the end of the script (msg and len).

The program first loads the variable len into register x and loads the variable msg into the register i.

Note: Variable len is for removing the spacing when converting from assembly language code to ASCII(American Standard Code for Information Interchange). This is similar to human languages where one language is not understood by another language and require a translator.

The program then returns control of the system to the user using the syscall command.

 

 

Here is a basic program written in assembly language for the x86_64 system provided by CTyler of Seneca College (https://wiki.cdot.senecacollege.ca/wiki/SPO600_Assembler_Lab):

.text
.globl _start

start = 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 $start,%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

This program will require a custom file called a “Makefile”

Note: This “Makefile” can be used for both x86_64 and arm aarch64 systems

Code:

BINARIES=hello-world

all: ${BINARIES}
AS_ARGS=-g

hello-world: hello-world.s
     world -g -o hello-world.o -f elf64 hello-world.s
     ld -o hello-world hello-world.o

clean:
rm ${BINARIES} *.o || true

Command: make hello-world

Note: All this program does is loop and do nothing.

The basic code and the hello world code will have to be combined together to make the program do something.

Task: Make it have an output like:

Loop:
Loop:
Loop:
Loop:
Loop:
Loop:
Loop:
Loop:
Loop:
Loop:

Code(x86_64):

.text
.globl _start

start = 0
max = 10

_start:

      movq $len,%rdx
      movq $msg,%rsi

      movq $start,%r15    #load %r15 with 0

loop:       
      movq $1,%rdi
      movq $1,%rax

      syscall             #Send output to host
      inc %r15            #Increment the value of %r15
      cmp $max,%r15       #Compares %r15 with the value at $max
      jne loop            #jump to loop if not equal to $max

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

      syscall

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

Now to make it more complex with it count with numbers up to a maximum

Task: Make it have an output like:

Loop:     01
Loop:     02
Loop:     03
Loop:     04
Loop:     05
Loop:     06
Loop:     07
Loop:     08
Loop:     09
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

Code(x86_64):

.text
.globl _start

start = 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) */
cvt = 48

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

loop:
/* ... body of the loop ... do something useful here ... */
/* rdx must be zero before div */

     movq $msg,%rsi
     movq $d,%r10
     movq %r15,%rax /*putting increment into rax because div divides by rax*/
     xor %rdx, %rdx /* makes rdx 0*/
     div %r10 /*rax div 10 (increment/10) */
     movq %rax,%r9 /*store quotient to r9 */
     add $cvt,%r9
     movq %rdx,%r8 /* storing remainder, needed to display 2nd digit */
     add $cvt,%r8
     movq $len,%rdx
     movb %r9b, msg+6 #Shift the 1st digit right 6 positions
     movb %r8b, msg+7 #Shift the 2nd digit right 7 positions

     movq $1,%rdi
     movq $1,%rax

     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

Code(arm aarch64):

.text
.globl _start
start = 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) */
ten = 10

_start:
     mov x19, start              #Moves r19 with start
     mov x22, ten                #Moves r22 with ten

loop:                            #The start of the loop
     adr x1, msg                 #Loads r1 with msg
     mov x2, len                 #Moves value of len into r2
     mov x0, 1                   #Moves value of 1 into r0
     mov x8, 64                  #Moves value of 64 into r8
     svc 0                       #Invokes syscall
     adr x23, msg                #Loads r23 with msg  
     add x19, x19, 1             #Adds the value in r19 with 1 and stores it in r19
     udiv x20, x19, x22          #Unsigned divide using value in r20 and r19 then store quotient/reminder in r19
     msub x21, x22, x20, x19     #For calculating reminder
                                 #Multiply r22 with r20 then subtracts r19 with the result and stores it in r21
                                 #Mathematically: r21=r19-(r22*r20)
     cmp x20, 0                  #Compare value in r20 if it is 0
     beq skip                    #If it is equal to 0 then jump to skip loop
     add x20, x20, '0'           #Adds the value in r20 with 0 and stores it in r20
     strb w20, [x23,6]           #Writes a byte string into r20 from r23 with 6 bytes
                                 #(Note:w20 instead of x20 for writing into registry)
skip:
     add x21, x21, '0'           #Adds r21 with 0 and store into r21
     strb w21, [x23,7]           #Writes a byte into r21 from r23 with 7 bytes
     cmp x19, max                #Compares r19 if it is the value of max
     bne loop                    #Jump to loop if it is not the value of max

     mov x0, 0                   #Moves the value of 0 into r0
     mov x8, 93                  #Moves value of 93 into r8
     svc 0                       #Invoke syscall
.data
msg: .ascii "Loop: 0\n"          #Display of Loop in ASCII to host
len = . - msg                    #Get positional parameter to host

Comment: This is way too complicated to figure out the ASCII, the loop logic, and the mathematics using registries for either x86_64 or arm aarch64. Also the formatting of WordPress is bad, cannot insert a tab(5 spaces) right away.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s