Lab05 - x86_64
Objective:
In this lab, I worked with 64-bit assembly language on x86_64 platform to learn about CPU architecture and assembly instructions.
Getting Started with Code Example
The first step is to retrieve the code example from the server. The file is compressed, so we'll extract it into the desired location (in my case, the home directory):
cd ~
tar xvf /public/spo600-assembler-lab-examples.tgz
Once extracted, you’ll see a folder named spo600
, which contains all the necessary files.
x86_64:
Investigating the C Code
To explore the C version of the program, navigate to the folder containing the hello.c
file and compile it using make
:
make
x86_64:
Disassemble the binary to view the assembly code:
objdump -d hello
This will show us the assembly instructions, where we can observe that different CPU architectures (x86_64 vs Aarch64) generate different instructions, even for the same program.
Exploring the x86_64 Platform
Now, let’s dive into the Aarch64-specific example:
Fixing a Loop in x86_64
We were provided with a loop in x86_64, but it wasn’t doing anything. The task was to modify it to print something each time it loops.
Here's a simple version of the loop that prints "Loop"
each time it runs:
We were provided with a loop in x86_64, but it wasn’t doing anything. The task was to modify it to print something each time it loops.
Here's a simple version of the loop that prints "Loop"
each time it runs:
.text
.globl _start
min = 0 /* Initial value for the loop index (constant, not a variable) */
max = 5 /* Loop terminates when the index reaches this value (i < max) */
_start:
mov $min,%r15 /* Initialize the loop counter with the starting value (min) */
loop:
mov $len,%rdx /* Set the message length */
mov $msg,%rsi /* Set the message location (address of msg) */
mov $1,%rdi /* Set file descriptor for stdout (1) */
mov $1,%rax /* Set the syscall number for sys_write (1) */
syscall /* Perform the syscall to print the message */
inc %r15 /* Increment the loop counter by 1 */
cmp $max,%r15 /* Compare the loop counter with the max value */
jne loop /* If the counter is less than max, continue the loop */
mov $0,%rdi /* Set the exit status to 0 (successful execution) */
mov $60,%rax /* Set the syscall number for sys_exit (60) */
syscall /* Perform the syscall to exit the program */
.section .data
msg: .ascii "Loop\n" /* The message to be printed each time */
len= .-msg /* Calculate the length of the message */
Result:
Loop with Loop Number
We can further enhance the loop to print the loop number alongside "Loop"
. Here’s an updated version:
.text
.globl _start
min = 0 /* Initial value for the loop index (constant, not a variable) */
max = 6 /* Loop terminates when the index reaches this value (i < max) */
_start:
mov $min,%r15 /* Initialize the loop counter with the starting value (min) */
loop:
mov $len,%rdx /* Set the message length */
mov $msg,%rsi /* Set the message location (address of msg) */
mov $1,%rdi /* Set file descriptor for stdout (1) */
mov $1,%rax /* Set the syscall number for sys_write (1) */
syscall /* Perform the syscall to print the message */
lea buffer(%rip),%r9 /* Load the address of buffer into r9 */
mov %r15,%r8 /* Copy the loop counter (r15) into r8 */
add $48,%r8 /* Convert the loop counter to ASCII (48 is '0') */
movb %r8b,(%r9) /* Store the ASCII character in buffer */
add $1,%r9 /* Move to the next byte in buffer */
movb $10,(%r9) /* Store newline character (ASCII 10) into buffer */
mov $2,%rdx /* Set the message length (2 bytes: number + newline) */
mov $buffer,%rsi /* Set the message location (buffer address) */
mov $1,%rdi /* Set file descriptor for stdout (1) */
mov $1,%rax /* Set the syscall number for sys_write (1) */
syscall /* Perform the syscall to print the loop counter and newline */
inc %r15 /* Increment the loop counter by 1 */
cmp $max,%r15 /* Compare the loop counter with the max value */
jne loop /* If the counter is less than max, continue the loop */
mov $0,%rdi /* Set the exit status to 0 (successful execution) */
mov $60,%rax /* Set the syscall number for sys_exit (60) */
syscall /* Perform the syscall to exit the program */
.section .data
msg: .ascii "Loop: " /* The message to be printed before each loop count */
len= .-msg /* Calculate the length of the "Loop: " message */
buffer: .space 2 /* Allocate space for the loop count character and newline */
Result:.text
.globl _start
min = 0 /* Initial value for the loop index (constant, not a variable) */
max = 6 /* Loop terminates when the index reaches this value (i < max) */
_start:
mov $min,%r15 /* Initialize the loop counter with the starting value (min) */
loop:
mov $len,%rdx /* Set the message length */
mov $msg,%rsi /* Set the message location (address of msg) */
mov $1,%rdi /* Set file descriptor for stdout (1) */
mov $1,%rax /* Set the syscall number for sys_write (1) */
syscall /* Perform the syscall to print the message */
lea buffer(%rip),%r9 /* Load the address of buffer into r9 */
mov %r15,%r8 /* Copy the loop counter (r15) into r8 */
add $48,%r8 /* Convert the loop counter to ASCII (48 is '0') */
movb %r8b,(%r9) /* Store the ASCII character in buffer */
add $1,%r9 /* Move to the next byte in buffer */
movb $10,(%r9) /* Store newline character (ASCII 10) into buffer */
mov $2,%rdx /* Set the message length (2 bytes: number + newline) */
mov $buffer,%rsi /* Set the message location (buffer address) */
mov $1,%rdi /* Set file descriptor for stdout (1) */
mov $1,%rax /* Set the syscall number for sys_write (1) */
syscall /* Perform the syscall to print the loop counter and newline */
inc %r15 /* Increment the loop counter by 1 */
cmp $max,%r15 /* Compare the loop counter with the max value */
jne loop /* If the counter is less than max, continue the loop */
mov $0,%rdi /* Set the exit status to 0 (successful execution) */
mov $60,%rax /* Set the syscall number for sys_exit (60) */
syscall /* Perform the syscall to exit the program */
.section .data
msg: .ascii "Loop: " /* The message to be printed before each loop count */
len= .-msg /* Calculate the length of the "Loop: " message */
buffer: .space 2 /* Allocate space for the loop count character and newline */
Loop with 2-digit Numbers (Up to 32)
text
.globl _start
min = 0 /* Initial value for the loop index (constant, not a variable) */
max = 33 /* Loop terminates when the index reaches this value (i < max) */
_start:
mov $min,%r15 /* Initialize the loop counter with the starting value (min) */
loop:
mov $len,%rdx /* Set the message length */
mov $msg,%rsi /* Set the message location (address of msg) */
mov $1,%rdi /* Set file descriptor for stdout (1) */
mov $1,%rax /* Set the syscall number for sys_write (1) */
syscall /* Perform the syscall to print the message */
lea buffer(%rip),%r9 /* Load the address of buffer into r9 */
mov %r15,%rax /* Copy the loop counter (r15) into rax */
xor %rdx,%rdx /* Clear the rdx register */
mov $10,%r11 /* Store the divisor (10) into r11 */
div %r11 /* Perform unsigned division (rax = quotient, rdx = remainder) */
mov %rax,%r8 /* Store the quotient (tens place) in r8 */
mov %rdx,%r10 /* Store the remainder (ones place) in r10 */
add $48,%r8 /* Convert the quotient (tens place) to ASCII */
movb %r8b,(%r9) /* Store the ASCII character of tens place in buffer */
add $1,%r9 /* Move to the next byte in buffer */
add $48,%r10 /* Convert the remainder (ones place) to ASCII */
movb %r10b,(%r9) /* Store the ASCII character of ones place in buffer */
add $1,%r9 /* Move to the next byte in buffer */
movb $10,(%r9) /* Store newline character (ASCII 10) into buffer */
mov $3,%rdx /* Set the message length (3 bytes: tens digit + ones digit + newline) */
mov $buffer,%rsi /* Set the message location (buffer address) */
mov $1,%rdi /* Set file descriptor for stdout (1) */
mov $1,%rax /* Set the syscall number for sys_write (1) */
syscall /* Perform the syscall to print the loop counter and newline */
inc %r15 /* Increment the loop counter by 1 */
cmp $max,%r15 /* Compare the loop counter with the max value */
jne loop /* If the counter is less than max, continue the loop */
mov $0,%rdi /* Set the exit status to 0 (successful execution) */
mov $60,%rax /* Set the syscall number for sys_exit (60) */
syscall /* Perform the syscall to exit the program */
.section .data
msg: .ascii "Loop: " /* The message to be printed before each loop count */
len= .-msg /* Calculate the length of the "Loop: " message */
buffer: .space 3 /* Allocate space for the two digits (tens and ones) and newline */
Result:
text
.globl _start
min = 0 /* Initial value for the loop index (constant, not a variable) */
max = 33 /* Loop terminates when the index reaches this value (i < max) */
_start:
mov $min,%r15 /* Initialize the loop counter with the starting value (min) */
loop:
mov $len,%rdx /* Set the message length */
mov $msg,%rsi /* Set the message location (address of msg) */
mov $1,%rdi /* Set file descriptor for stdout (1) */
mov $1,%rax /* Set the syscall number for sys_write (1) */
syscall /* Perform the syscall to print the message */
lea buffer(%rip),%r9 /* Load the address of buffer into r9 */
mov %r15,%rax /* Copy the loop counter (r15) into rax */
xor %rdx,%rdx /* Clear the rdx register */
mov $10,%r11 /* Store the divisor (10) into r11 */
div %r11 /* Perform unsigned division (rax = quotient, rdx = remainder) */
mov %rax,%r8 /* Store the quotient (tens place) in r8 */
mov %rdx,%r10 /* Store the remainder (ones place) in r10 */
add $48,%r8 /* Convert the quotient (tens place) to ASCII */
movb %r8b,(%r9) /* Store the ASCII character of tens place in buffer */
add $1,%r9 /* Move to the next byte in buffer */
add $48,%r10 /* Convert the remainder (ones place) to ASCII */
movb %r10b,(%r9) /* Store the ASCII character of ones place in buffer */
add $1,%r9 /* Move to the next byte in buffer */
movb $10,(%r9) /* Store newline character (ASCII 10) into buffer */
mov $3,%rdx /* Set the message length (3 bytes: tens digit + ones digit + newline) */
mov $buffer,%rsi /* Set the message location (buffer address) */
mov $1,%rdi /* Set file descriptor for stdout (1) */
mov $1,%rax /* Set the syscall number for sys_write (1) */
syscall /* Perform the syscall to print the loop counter and newline */
inc %r15 /* Increment the loop counter by 1 */
cmp $max,%r15 /* Compare the loop counter with the max value */
jne loop /* If the counter is less than max, continue the loop */
mov $0,%rdi /* Set the exit status to 0 (successful execution) */
mov $60,%rax /* Set the syscall number for sys_exit (60) */
syscall /* Perform the syscall to exit the program */
.section .data
msg: .ascii "Loop: " /* The message to be printed before each loop count */
len= .-msg /* Calculate the length of the "Loop: " message */
buffer: .space 3 /* Allocate space for the two digits (tens and ones) and newline */
Loop with 2-digit Numbers (Up to 32) Suppressing the Leading 0s
.text
.globl _start
min = 0 /* Initial value for the loop index (constant, not a variable) */
max = 33 /* Loop terminates when the index reaches this value (i < max) */
_start:
mov $min,%r15 /* Initialize the loop counter with the starting value (min) */
loop:
mov $len,%rdx /* Set the message length */
mov $msg,%rsi /* Set the message location (address of msg) */
mov $1,%rdi /* Set file descriptor for stdout (1) */
mov $1,%rax /* Set the syscall number for sys_write (1) */
syscall /* Perform the syscall to print the message */
lea buffer(%rip),%r9 /* Load the address of buffer into r9 */
mov %r15,%rax /* Copy the loop counter (r15) into rax */
xor %rdx,%rdx /* Clear rdx value */
mov $10,%r11 /* Store divisor to r11 (for division by 10) */
div %r11 /* Perform unsigned division, rax = quotient (tens), rdx = remainder (ones) */
mov %rax,%r8 /* Store quotient (tens place) in r8 */
mov %rdx,%r10 /* Store remainder (ones place) in r10 */
cmp $0,%r8 /* Check if the tens place is zero */
je units_digit /* If it is zero, skip storing the tens place and go directly to the ones place */
add $48,%r8 /* Convert tens place to ASCII */
movb %r8b,(%r9) /* Store the tens place character into buffer */
add $1,%r9 /* Move to next byte in buffer */
units_digit:
add $48,%r10 /* Convert ones place to ASCII */
movb %r10b,(%r9) /* Store the ones place character into buffer */
add $1,%r9 /* Move to next byte in buffer */
movb $10,(%r9) /* Store newline character (ASCII 10) into buffer */
mov $3,%rdx /* Set the message length (3 bytes: tens digit, ones digit, newline) */
mov $buffer,%rsi /* Set the message location (buffer address) */
mov $1,%rdi /* Set file descriptor for stdout (1) */
mov $1,%rax /* Set the syscall number for sys_write (1) */
syscall /* Perform the syscall to print the loop counter and newline */
inc %r15 /* Increment the loop counter by 1 */
cmp $max,%r15 /* Compare the loop counter with the max value */
jne loop /* If the counter is less than max, continue the loop */
mov $0,%rdi /* Set the exit status to 0 (successful execution) */
mov $60,%rax /* Set the syscall number for sys_exit (60) */
syscall /* Perform the syscall to exit the program */
.section .data
msg: .ascii "Loop: " /* The message to be printed before each loop count */
len= .-msg /* Calculate the length of the "Loop: " message */
buffer: .space 3 /* Allocate space for the loop counter (2 digits max) and newline */
Result:
.text
.globl _start
min = 0 /* Initial value for the loop index (constant, not a variable) */
max = 33 /* Loop terminates when the index reaches this value (i < max) */
_start:
mov $min,%r15 /* Initialize the loop counter with the starting value (min) */
loop:
mov $len,%rdx /* Set the message length */
mov $msg,%rsi /* Set the message location (address of msg) */
mov $1,%rdi /* Set file descriptor for stdout (1) */
mov $1,%rax /* Set the syscall number for sys_write (1) */
syscall /* Perform the syscall to print the message */
lea buffer(%rip),%r9 /* Load the address of buffer into r9 */
mov %r15,%rax /* Copy the loop counter (r15) into rax */
xor %rdx,%rdx /* Clear rdx value */
mov $10,%r11 /* Store divisor to r11 (for division by 10) */
div %r11 /* Perform unsigned division, rax = quotient (tens), rdx = remainder (ones) */
mov %rax,%r8 /* Store quotient (tens place) in r8 */
mov %rdx,%r10 /* Store remainder (ones place) in r10 */
cmp $0,%r8 /* Check if the tens place is zero */
je units_digit /* If it is zero, skip storing the tens place and go directly to the ones place */
add $48,%r8 /* Convert tens place to ASCII */
movb %r8b,(%r9) /* Store the tens place character into buffer */
add $1,%r9 /* Move to next byte in buffer */
units_digit:
add $48,%r10 /* Convert ones place to ASCII */
movb %r10b,(%r9) /* Store the ones place character into buffer */
add $1,%r9 /* Move to next byte in buffer */
movb $10,(%r9) /* Store newline character (ASCII 10) into buffer */
mov $3,%rdx /* Set the message length (3 bytes: tens digit, ones digit, newline) */
mov $buffer,%rsi /* Set the message location (buffer address) */
mov $1,%rdi /* Set file descriptor for stdout (1) */
mov $1,%rax /* Set the syscall number for sys_write (1) */
syscall /* Perform the syscall to print the loop counter and newline */
inc %r15 /* Increment the loop counter by 1 */
cmp $max,%r15 /* Compare the loop counter with the max value */
jne loop /* If the counter is less than max, continue the loop */
mov $0,%rdi /* Set the exit status to 0 (successful execution) */
mov $60,%rax /* Set the syscall number for sys_exit (60) */
syscall /* Perform the syscall to exit the program */
.section .data
msg: .ascii "Loop: " /* The message to be printed before each loop count */
len= .-msg /* Calculate the length of the "Loop: " message */
buffer: .space 3 /* Allocate space for the loop counter (2 digits max) and newline */
Result:
Output in hexadecimal (0-20)
.text
.globl _start
/* Constants for loop index and maximum loop value */
min = 0
max = 33
_start:
/* Initialize loop counter (min) */
mov $min, %r15
loop:
/* Display "Loop: " before each count */
mov $len, %rdx /* Message length */
mov $msg, %rsi /* Message address */
mov $1, %rdi /* File descriptor: stdout */
mov $1, %rax /* Syscall number for sys_write */
syscall /* Invoke syscall to print the message */
/* Prepare buffer for storing the loop counter (tens and ones digits) */
lea buffer(%rip), %r9 /* Load address of buffer into r9 */
/* Perform division to separate tens and ones places */
mov %r15, %rax /* Copy loop counter (r15) to rax */
xor %rdx, %rdx /* Clear rdx (remainder) */
mov $16, %r11 /* Divisor is 16 */
div %r11 /* Perform unsigned division: quotient in rax, remainder in rdx */
mov %rax, %r8 /* Store quotient (tens place) in r8 */
mov %rdx, %r10 /* Store remainder (ones place) in r10 */
/* Process tens place: */
cmp $0, %r8 /* Check if tens place is 0 */
je units_digit /* If 0, skip storing tens digit and move to units place */
add $48, %r8 /* Convert tens place to ASCII */
movb %r8b, (%r9) /* Store the tens place character in buffer */
add $1, %r9 /* Move to next byte in buffer */
units_digit:
add $48, %r10 /* Convert ones place to ASCII */
cmp $58, %r10 /* Check if ones place is less than or equal to 9 */
jl st_unit /* If less than 58 ('9' in ASCII), store it */
/* If greater than '9', adjust for ASCII letters A-E */
add $7, %r10 /* Convert numbers 10-15 to 'A'-'F' */
st_unit:
movb %r10b, (%r9) /* Store ones place character in buffer */
add $1, %r9 /* Move to next byte in buffer */
/* Add newline after the number */
movb $10, (%r9) /* Store newline character (ASCII 10) in buffer */
/* Display the number (two digits and newline) */
mov $3, %rdx /* Message length: 3 bytes (tens, ones, newline) */
mov $buffer, %rsi /* Address of buffer with number and newline */
mov $1, %rdi /* File descriptor: stdout */
mov $1, %rax /* Syscall number for sys_write */
syscall /* Invoke syscall to print the buffer */
/* Increment loop counter */
inc %r15
/* Check if loop counter has reached max value */
cmp $max, %r15
jne loop /* If counter < max, continue the loop */
/* Exit program */
mov $0, %rdi /* Exit status: 0 */
mov $60, %rax /* Syscall number for sys_exit */
syscall /* Invoke syscall to exit */
.section .data
msg: .ascii "Loop: " /* "Loop: " message to be printed before number */
len= .-msg /* Calculate length of "Loop: " */
buffer: .space 3 /* Allocate space for two digits and newline character */
Comments
Post a Comment