Lab 5 - 64-Bit Assembly Language - x86_64
64-Bit Assembly Language
Get code example
The first step is to retrieve the code example from the server. The example is located in /public/spo600-assembler-lab-examples.tgz
, which is a compressed file. To extract the file and store it in the desired location, navigate to that location. For me, it's the home directory:
cd ~ tar xvf /public/spo600-assembler-lab-examples.tgz
After running the command, the files will be extracted to your current location. You will see a folder named spo600.
x86_64 platform
Same as what I did inAarch64, we have source code below that contains a loop, but the loop does not perform any actions. Now, I'm trying to modify the source code to make it print something.
.text .globl _start min = 0 /* starting value for the loop index; **note that this is a symbol (constant)**, not a variable */ max = 5 /* 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 the loop index */ cmp $max,%r15 /* see if we've hit the max */ jne loop /* if not, then continue the loop */ mov $0,%rdi /* set exit status to 0 */ mov $60,%rax /* exit is syscall #60 */ syscall /* invoke syscall */
Print out the word "Loop" each time it loops:
.text .globl _start min = 0 /* starting value for the loop index; **note that this is a symbol (constant)**, not a variable */ max = 5 /* 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 ... */ /* ============== Start ============== */ mov $len,%rdx /* message length */ mov $msg,%rsi /* message location */ mov $1,%rdi /* file descriptor stdout */ mov $1,%rax /* syscall sys_write */ syscall /* =============== End =============== */ inc %r15 /* increment the loop index */ cmp $max,%r15 /* see if we've hit the max */ jne loop /* if not, then continue the loop */ mov $0,%rdi /* set exit status to 0 */ mov $60,%rax /* exit is syscall #60 */ syscall /* invoke syscall */ .section .data msg: .ascii "Loop\n" len= .-msg
Result:
Print out the word "Loop" with the loop number each time it loops:
.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:
/* ... body of the loop ... do something useful here ... */
/* ============== Start ============== */
mov $len,%rdx /* message length */
mov $msg,%rsi /* message location */
mov $1,%rdi /* file descriptor stdout */
mov $1,%rax /* syscall sys_write */
syscall
lea buffer(%rip),%r9 /* load the buffer addres to r9 */
mov %r15,%r8 /* store r15(loop count) to r8 register */
add $48,%r8 /* convert number to character */
movb %r8b,(%r9) /* store character into buffer */
add $1,%r9 /* move to next byte in buffer */
movb $10,(%r9) /* 10 in ASCII is newline character. Store newline character to buffer */
mov $2,%rdx /* message length */
mov $buffer,%rsi /* message location */
mov $1,%rdi /* file descriptor stdout */
mov $1,%rax /* syscall sys_write */
syscall
/* =============== End =============== */
inc %r15 /* increment the loop index */
cmp $max,%r15 /* see if we've hit the max */
jne loop /* if not, then continue the loop */
mov $0,%rdi /* set exit status to 0 */
mov $60,%rax /* exit is syscall #60 */
syscall /* invoke syscall */
.section .data
msg: .ascii "Loop: "
len= .-msg
buffer: .space 2
Result:
Print out the loop number with 2 digits until 32. For example, 0 is 00.
.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:
/* ... body of the loop ... do something useful here ... */
/* ============== Start ============== */
mov $len,%rdx /* message length */
mov $msg,%rsi /* message location */
mov $1,%rdi /* file descriptor stdout */
mov $1,%rax /* syscall sys_write */
syscall
lea buffer(%rip),%r9 /* load the buffer address to r9 */
mov %r15,%rax /* store dividend to rax */
xor %rdx,%rdx /* clear rdx value */
mov $10,%r11 /* store dividor to r11 */
div %r11 /* perform unsigned division */
mov %rax,%r8 /* store result to r8 */
mov %rdx,%r10 /* store remainder to r10 */
add $48,%r8 /* convert number to character */
movb %r8b,(%r9) /* store character into buffer */
add $1,%r9 /* move to next byte in buffer */
add $48,%r10 /* convert number to character */
movb %r10b,(%r9) /* store character into buffer */
add $1,%r9 /* move to next byte in buffer */
movb $10,(%r9) /* 10 in ASCII is newline character. Store newline character to buffer */
mov $3,%rdx /* message length */
mov $buffer,%rsi /* message location */
mov $1,%rdi /* file descriptor stdout */
mov $1,%rax /* syscall sys_write */
syscall
/* =============== End =============== */
inc %r15 /* increment the loop index */
cmp $max,%r15 /* see if we've hit the max */
jne loop /* if not, then continue the loop */
mov $0,%rdi /* set exit status to 0 */
mov $60,%rax /* exit is syscall #60 */
syscall /* invoke syscall */
.section .data
msg: .ascii "Loop: "
len= .-msg
buffer: .space 3
Result:
Print out the loop number with 1 digit when the number is less than 10.
.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:
/* ... body of the loop ... do something useful here ... */
/* ============== Start ============== */
mov $len,%rdx /* message length */
mov $msg,%rsi /* message location */
mov $1,%rdi /* file descriptor stdout */
mov $1,%rax /* syscall sys_write */
syscall
lea buffer(%rip),%r9 /* load the buffer address to r9 */
mov %r15,%rax /* store dividend to rax */
xor %rdx,%rdx /* clear rdx value */
mov $10,%r11 /* store dividor to r11 */
div %r11 /* perform unsigned division */
mov %rax,%r8 /* store result (ten) to r8 */
mov %rdx,%r10 /* store remainder (unit) to r10 */
cmp $0,%r8 /* compare ten digit if it is 0 */
je units_digit /* if it is 0, skip storing it and go to the unit digit */
add $48,%r8 /* convert number to character */
movb %r8b,(%r9) /* store character into buffer */
add $1,%r9 /* move to next byte in buffer */
units_digit:
add $48,%r10 /* convert number to character */
movb %r10b,(%r9) /* store character into buffer */
add $1,%r9 /* move to next byte in buffer */
movb $10,(%r9) /* 10 in ASCII is newline character. Store newline character to buffer */
mov $3,%rdx /* message length */
mov $buffer,%rsi /* message location */
mov $1,%rdi /* file descriptor stdout */
mov $1,%rax /* syscall sys_write */
syscall
/* =============== End =============== */
inc %r15 /* increment the loop index */
cmp $max,%r15 /* see if we've hit the max */
jne loop /* if not, then continue the loop */
mov $0,%rdi /* set exit status to 0 */
mov $60,%rax /* exit is syscall #60 */
syscall /* invoke syscall */
.section .data
msg: .ascii "Loop: "
len= .-msg
buffer: .space 3
Result:
Print out the loop number in hexadecimal instead of decimal number.
.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: /* ... body of the loop ... do something useful here ... */ /* ============== Start ============== */ mov $len,%rdx /* message length */ mov $msg,%rsi /* message location */ mov $1,%rdi /* file descriptor stdout */ mov $1,%rax /* syscall sys_write */ syscall lea buffer(%rip),%r9 /* load the buffer address to r9 */ mov %r15,%rax /* store dividend to rax */ xor %rdx,%rdx /* clear rdx value */ mov $16,%r11 /* store dividor to r11 */ div %r11 /* perform unsigned division */ mov %rax,%r8 /* store result (ten) to r8 */ mov %rdx,%r10 /* store remainder (unit) to r10 */ cmp $0,%r8 /* compare ten digit if it is 0 */ je units_digit /* if it is 0, skip storing it and go to the unit digit */ add $48,%r8 /* convert number to character */ movb %r8b,(%r9) /* store character into buffer */ add $1,%r9 /* move to next byte in buffer */ units_digit: add $48,%r10 /* convert number to character */ cmp $58,%r10 /* compare if character value greater than 58. 0-9 is ASCII value 48-57 */ jl st_unit /* if less than 58, go to store the value */ add $7,%r10 /* if greater or equal to, add 7 to A-E ASCII value */ st_unit: movb %r10b,(%r9) /* store character into buffer */ add $1,%r9 /* move to next byte in buffer */ movb $10,(%r9) /* 10 in ASCII is newline character. Store newline character to buffer */ mov $3,%rdx /* message length */ mov $buffer,%rsi /* message location */ mov $1,%rdi /* file descriptor stdout */ mov $1,%rax /* syscall sys_write */ syscall /* =============== End =============== */ inc %r15 /* increment the loop index */ cmp $max,%r15 /* see if we've hit the max */ jne loop /* if not, then continue the loop */ mov $0,%rdi /* set exit status to 0 */ mov $60,%rax /* exit is syscall #60 */ syscall /* invoke syscall */ .section .data msg: .ascii "Loop: " len= .-msg buffer: .space 3
Result:
Reflection
Understanding assembler instructions and logic is tough for me. I even struggled to print the values in registers and create space to store a string. There isn’t enough documentation to help guide me through it. Assembler is low-level, so I have to think carefully about how things work step-by-step. It takes practice to get used to how data moves and how operations happen. Without high-level abstractions, it’s hard to see the big picture sometimes.
Comments
Post a Comment