SPO600 Lab5 64-Bit Assembly Language Lab Pt.2 ---x86_64 part
In the part 2 of this Lab , I am going to experiment with assembler on the x86_64 platforms, similar to the Lab part 1.
Task 1 Observe the difference between source code and the object file of the x86 assembly language
Source code (gas / AT&T ):
Source code (nasm / Intel):
object file (gas):
Before that, I want to modifty the Makefile so that it can make file for the loop-gas.s
Revised Makefile:
code:
BINARIES=hello-nasm hello-gas loop-gas
all: ${BINARIES}
AS_ARGS=-g
hello-nasm: hello-nasm.s
nasm -g -o hello-nasm.o -f elf64 hello-nasm.s
ld -o hello-nasm hello-nasm.o
hello-gas: hello-gas.s
as ${AS_ARGS} -o hello-gas.o hello-gas.s
ld -o hello-gas hello-gas.o
loop-gas: loop-gas.s
as ${AS_ARGS} -o loop-gas.o loop-gas.s
ld -o loop-gas loop-gas.o
clean:
rm ${BINARIES} *.o || true
Modified Code of loop-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
min = 0 /* starting value for the loop index; **note that this is a symbol (constant)**, not a variable */
max = 6 /* 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 the loop index */
cmp $max,%r15 /* see if we've hit the max */
jne loop /* if not, then continue the loop */
movq $0,%rdi /* exit status */
movq $60,%rax /* syscall sys_exit */
syscall
.section .data
msg: .ascii "loop\n"
output:
Task 3: Modify the code so that the output show the iteration number also.
Modified Code:
/*
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
min = 0 /* starting value for the loop index; **note that this is a symbol (constant)**, not a variable */
max = 6 /* 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
/*update the iteration number to be displayed*/
mov %r15, %r10
add $'0', %r10
mov %r10b, num
/* print iteration number*/
movq $len2,%rdx
movq $num,%rsi
movq $1,%rdi
movq $1,%rax
syscall
inc %r15 /* increment the loop index */
cmp $max,%r15 /* see if we've hit the max */
jne loop /* if not, then continue the loop */
movq $0,%rdi /* exit status */
movq $60,%rax /* syscall sys_exit */
syscall
.section .data
msg: .ascii "loop: "
len = . - msg
num: .byte '0'
.byte 10
len2 = . - num
Output:
In part of AArch64, I used the method just to set up a ten digits and units digit. This time, I would like
to use another method. I will calculate the loop number from the iteration count directly.
Modified code:
/*
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
min = 0 /* starting value for the loop index; **note that this is a symbol (constant)**, not a variable */
max = 6 /* 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
/*div the iteration number*/
mov %r15, %rax /* the value to be divided must be moved to %rax*/
xor %rdx, %rdx
mov $10, %r10
div %r10 /* after division, quotient will be in rax and remainder will be in rdx*/
/*update the iteration number to be displayed*/
mov %rax, %r10
add $'0', %r10
mov %r10b, num
mov %rdx, %r11
add $'0', %r11
mov %r11b, num+1
/* print iteration number*/
movq $len2,%rdx
movq $num,%rsi
movq $1,%rdi
movq $1,%rax
syscall
inc %r15 /* increment the loop index */
cmp $max,%r15 /* see if we've hit the max */
jne loop /* if not, then continue the loop */
movq $0,%rdi /* exit status */
movq $60,%rax /* syscall sys_exit */
syscall
.section .data
msg: .ascii "loop: "
len = . - msg
num: .ascii "00\n"
len2 = . - num
Yellow highlighted code: divide the iteration counter by 10 and get the units digit and tens digit.
Red highlighted code: update the display value.
Output:
Modified code:
/*
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
min = 0 /* starting value for the loop index; **note that this is a symbol (constant)**, not a variable */
max = 33 /* 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
/*div the iteration number*/
mov %r15, %rax /* the value to be divided must be moved to %rax*/
xor %rdx, %rdx
mov $10, %r10
div %r10 /* after division, quotient will be in rax and remainder will be in rdx*/
/*update the iteration number to be displayed*/
cmp $0, %rax
je space
mov %rax, %r10
add $'0', %r10
jmp update
space: mov $' ', %r10
update: mov %r10b, num
mov %rdx, %r11
add $'0', %r11
mov %r11b, num+1
/* print iteration number*/
movq $len2,%rdx
movq $num,%rsi
movq $1,%rdi
movq $1,%rax
syscall
inc %r15 /* increment the loop index */
cmp $max,%r15 /* see if we've hit the max */
jne loop /* if not, then continue the loop */
movq $0,%rdi /* exit status */
movq $60,%rax /* syscall sys_exit */
syscall
.section .data
msg: .ascii "loop: "
len = . - msg
num: .ascii "00\n"
len2 = . - num
Yellow highlighted code: check if the quotient is zero, if yes, replace the first digit to be displayed by space.
output:
Task 6. Modify the code so that it show the counter as hexadecimal
Modified code:
/* 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 min = 0 /* starting value for the loop index; **note that this is a symbol (constant)**, not a variable */ max = 33 /* 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 /*div the iteration number*/ mov %r15, %rax /* the value to be divided must be moved to %rax*/ xor %rdx, %rdx mov $16, %r10 div %r10 /* after division, quotient will be in rax and remainder will be in rdx*/ /*update the iteration number to be displayed*/ cmp $0, %rax je space mov %rax, %r10 add $'0', %r10 jmp check space: mov $' ', %r10 //check if the unit digits greater than 9 check: cmp $9, %rdx jg add jmp update add: add $7, %rdx update: mov %r10b, num mov %rdx, %r11 add $'0', %r11 mov %r11b, num+1 /* print iteration number*/ movq $len2,%rdx movq $num,%rsi movq $1,%rdi movq $1,%rax syscall inc %r15 /* increment the loop index */ cmp $max,%r15 /* see if we've hit the max */ jne loop /* if not, then continue the loop */ movq $0,%rdi /* exit status */ movq $60,%rax /* syscall sys_exit */ syscall .section .data msg: .ascii "loop: " len = . - msg num: .ascii "00\n" len2 = . - num
Yellow highlighted code: check if the remainder is greater than 9. if yes, add 7 so that the value after 9 is A.
output:
Reflection:
In this lab, I experienced on writing and debugging in assembler. Since the program is quit simple, I did not face too many difficulties. I have different experience on 6502, x86_64 and aarch64 assembler. 6502 is the one with the most limited resources. With only x, y and accumulator register and only 16 bit for each register, we are forced to keep reading variable from the memory even performing very simple task. Since I learn 6502 in a simulator, I can easily check the machine code, status of the processor or even use the step-by-step debugger, I have more confident to coding with 6502 assembler.
As for the x86 and AArch64, their program structure are quite similar. Gratefully, both of them have more register available to use. Although the instructions of each system are not exactly the same, that of both system are quite well-rounded. More useful instruction are provided. for example the div instruction in x86 gas syntax. Without that, we may have to iterate the number deduction by 10 until it is smaller than 10.
Finally, Coding in assembly language really take a lot of time and exhausting. It's hard to imagine I spend multiple hours just to write a few for-loop. It is 3am now. I need some sleep.
Comments
Post a Comment