We will create a program on both platforms x86 and Aarch64 which will loop 30 times printing the number in the index as shown below in the example:
Loop: 00
Loop: 01
Loop: 02
Loop: 03
Loop: 04
Loop: 05
Loop: 06
Loop: 07
Loop: 08
Loop: 09
....
Loop: 29
The twist here is that we will print these numbers using two values generated by dividing the index value by 10. So we will produce a quotient which will be the leading character and a remainder which will be the latter character.
------------------------------------------------------
STARTING WITH THE X86 ARCHITECTURE
------------------------------------------------------
Getting Loop to print the number in the index was fairly simple as we just needed to move the value of the index into a register of its own and then move that register into the memory address of the string we want to append to.
The tricky part here was figuring out we only needed 1 byte instead of the whole 64 which would overwrite the entire message and print garbage.
We also needed to use the "add" command, to add 48 to the byte of the register we were moving into memory so that the compiler can interpret it as ASCII.
Printing the complete list as shown above was a bit more challenging as we had to divide 2 number to get the quotient and the remainder.
--------------------------------
PROBLEMS WITH THE DIV COMMAND
--------------------------------
Now the DIV command in X86 architecture only takes one parameter and the way it works is the parameter it takes is the divisor. And it divides agaisnt whatever value is stored inside the %RAX register.
So we need to move our value of the index into the %RAX register and give the %R12 register the value 10 because 10 is our divisor.
Next before we divide we will need to clear the %RDX register as this is where the remainder will be placed, but it is often filled with garbage because it concatenates with the %RAX register
Once we do this and execute the "div" command and use the quotient in the %RAX register and the remainder in the %RDX register to genrate the above sequence
---------------------------------
SUPRESSING THE TRAILING ZERO CHARACTES
---------------------------------
We don't want the program to print 01 or 02 if there is a leading zero.
To surpress this we will use the "cmp", "jne" commands and a label.
So when we go to compare the quotient to the number 0, if these 2 are NOT EQUAL we will jump to a label which will add the quotient to the memory address of the string, otherwise we will skip over the quotient.
---------------------------------
---------------------------------
FULL CODE ANALYSIS
---------------------------------
---------------------------------
.text
.globl _start
start = 0 /* starting value for the loop index; note that this is a symbol (constant), not a variable */
max = 30 /* loop exits when the index hits this number (loop condition is i<max) */
_start:
mov $start,%r15 /* loop index */
loop:
mov %r15,%rax // Prepare registers for the div command
mov $10,%r12 // Our divisor
xor %rdx,%rdx // Set rdx to zero
div %r12 // divide the divsor by the value in %RAX
add $48,%rdx // Need to add 48 so that the buffer can read in ASCII
mov %dl,msg+6 // Move the value of the one byte in register %RDX to the memory location
cmp $0,%al // Compare to see if there is a zero
jne label // jump to the label if there is no zero
call printer // if there is a zero we will jump to the label printer
label:
mov %al,%r11b // Like above we will append the quotient to the msg memory address
add $48,%r11b
mov %r11b,msg+5
call printer
printer: // Print the message
mov $len,%rdx
mov $msg,%rsi
mov $1,%rdi
mov $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
Comments