Lab 3 x86_64 finished
Now, we’ll change our code to loop until 30. To make things easier, I’ll modify my code to be able to use %r15 instead increasing %r8 as we’ll have a divide numbers. So you won’t need to start %r8:
mov $start,%r15 /* loop index */
mov $10,%r9 /* initialize register with line feed */
But now, you’ll need to replace %r8 for %15 (mov %r15,%r8) and convert into a character adding 48 (add $48,%r8), do this in the beginning of the loop and remove the inc of %r8 (inc %r8), so the beginning of your loop will be like:
mov %r15,%r8 /* replace %r8 with the counter */
add $48,%r8 /* add 48 to turn into a character */
mov %r8,d /* replace d with %r8 value */
mov %r9,l /* replace l with %r9 value */
movq $len,%rdx /* message length */
movq $msg,%rsi /* message location */
movq $1,%rdi /* file descriptor stdout */
movq $1,%rax /* syscall sys_write */
inc %r15 /* increment index */
As 10-30 needs more space than 1-9, we’ll have to add a third space in our message to fit the right length ("Loop: \n"). We’ll have two digits, so d will be now d1 (d1 = msg + 6), we’ll have a d2 (d2 = msg + 7) and l will be in position 8 (l = msg + 8). As we have two digits, I prefer to put them in a row, so I’ll move the line feed to %r10 (mov $10,%r10), the first digit will initialize with an empty space (mov $32,%r8).
Obs.: As you maybe remember, we’re working with ascii number. So 32 is the ascii to an empty space.
Remember that we have to modify the loop too, so the beginning of our code we’ll be like this:
mov $start,%r15 /* loop index */
mov $32,%r8 /* initialize register with space */
mov $10,%r10 /* initialize register with line feed */
mov %r15,%r9 /* replace %r9 with the counter */
add $48,%r9 /* add 48 to turn into a character */
mov %r8,d1 /* replace d1 with %r8 value */
mov %r9,d2 /* replace d2 with %r9 value */
mov %r10,l /* replace l with %r10 value */
And our data like this:
msg: .ascii "Loop: \n"
len = . - msg /* message length */
d1 = msg + 6 /* position of second space */
d2 = msg + 7 /* position of third space */
l = msg + 8 /* position of line feed */
Now we can test. We’ll be able to see our same code, but now with another space in the middle. If you try modify the max to 31 (it will execute until 0-30, max = 31) you’ll see that it’s not so simple to print numbers in assembly (I don’t know you, but I already knew it when I lost some hours in the 0-9 program). The increment will not add +1 to our digits, but 1 to ascii digits, that’s why you’ll see some weird characters instead of numbers. To solve this, we’ll have to divide the counter and take the quotient and remainder to write the first and second digit respectively.
To divide, we need first to put 0 in the rdx (mov $0,%rdx), then put the number that we need to divide in the %rax, in this case, %r15, the counter (mov %r15,%rax) and divide per 10 to have the two numbers, as we already have this number to the line feed, we don’t have to use another register (div %r10). The first number, the quotient, will be in rax and the second, the remainder, in rdx. We have to put these number in the registers (mov %rax,%r8 and mov %rdx,%r9) and add 48 to have the string (add $48,%r8 and add $48,%r9).
Obs.: Note that you don’t need to initialize %r8 anymore, as you’ll receive the quotient before being printed (mov $32,%r8).
The last thing, before the full code, is to remove the “0” before the numbers 0-9. To do that, I’ll compare 48 with %r8 before turning it in a character number (cmp $48,%r8), if it’s zero, I’ll go to a label, named space (je space), to replace it for a space (mov $32,%r8). Either if it is or it isn’t zero, I’ll continue to another label (jmp continue) to continue the code and write the result in the screen.
You’ll be able to see the full code in https://drive.google.com/file/d/1Z3Z0lCj13nJvGfV8rMa84VKgR31ay-ON/view?usp=sharing . Next post we’ll do the same thing in a aarch64 architecture.