- Get link
- X
- Other Apps
This blog post is for my SPO600 class I am participating at Seneca College, this is related to Lab 4 detailed here.
This post is a follow-up to the first part of this lab covered here. The first part covered giving an assembly language loop something to print each loop, and then adding the loop index to the output. The task involved implementing this for both AArch64 and x86_64 assembly languages.
Loop v3
The next task for this lab includes extending the loops from 10 iterations to 31 total, printing values 00 to 30. This is slightly more complicated than simply adding 0-9 to the value of an ascii character and inserting it into the string to write. Dealing with two digits to print means converting each digit separately and inserting each byte individually into the string. The solution to this is dividing the loop index by ten and converting the quotient and remainder into the first and second digits, respectively.
AArch64 Loop v3
.text
.globl _start
min = 0
max = 31
_start:
mov x19, min
loop:
// Prepare message
mov x22, 10 /* store int value 10 into x22 */
udiv x23, x19, x22 /* calculate both digits of the index */
msub x24, x23, x22, x19
add x20, x23, 48 /* convert first digit */
adr x21, msg+6 /* set first digit placeholder address */
strb w20, [x21] /* overwrite first digit placehokder */
add x20, x24, 48 /* convert 2nd digit */
adr x21, msg+7 /* set 2nd digit placeholder address */
strb w20, [x21] /* overwrite 2nd digit placehokder */
// Print
mov x0, 1 /* file descriptor: 1 is stdout */
adr x1, msg /* message location (memory address) */
mov x2, len /* message length (bytes) */
mov x8, 64 /* write is syscall #64 */
svc 0 /* invoke syscall */
// Continue the loop
add x19, x19, 1
cmp x19, max
b.ne loop
// Exit
mov x0, 0 /* status -> 0 */
mov x8, 93 /* exit is syscall #93 */
svc 0 /* invoke syscall */
.data
msg: .ascii "Loop: ##\n"
len= . - msg
The process for the AArch64 version of Loop v3 begins with storing the value 10 into register x22. Using that register, the loop index is divided by 10 and the quotient is stored into register x23. In order to calculate the remainder, an "msub" instruction is used with the quotient (x23), the divisor (x22 = 10), and the dividend (x19 = index) storing the result into register x24. Once this is complete both digits are available to use, and all that's left to do is convert to the ascii values and insert each into bytes 6 and 7 in the string.
x86_64 Loop v3
.text
.globl _start
min = 0
max = 31
_start:
mov $min,%r12
loop:
mov %r12,%rax /* prepare div args */
mov $10,%r13
mov $0,%rdx
div %r13 /* divide loop index by 10 */
add $'0',%rax /* convert quotient into char */
add $'0',%rdx /* convert remainder into char */
movb %al,msg+6 /* overwrite first digit placeholder */
movb %dl,msg+7 /* overwrite 2nd digit placeholder */
movq $len,%rdx /* message length */
movq $msg,%rsi /* message location */
movq $1,%rdi /* file descriptor stdout */
movq $1,%rax /* syscall sys_write */
syscall
inc %r12
cmp $max,%r12
jne loop
movq $0,%rdi /* exit status */
movq $60,%rax /* syscall sys_exit */
syscall
.section .data
msg: .ascii "Loop: ##\n"
len = . - msg
The x86_64 version of Loop v3 is made slightly simpler due to the way the "div" instruction works on this architecture. For x86_64, div provides both quotient and remainder in one instruction. To set up for div, the loop index is stored into register "rax", register r13 is loaded with the number 10, and register rdx is loaded with the number 0 (this is simply a requirement for the div instruction). div is called with register r13 as the argument. Register rax is divided by r13, the quotient is stored into rax, and the remainder is stored into rdx. Once that is complete, once again, the rest is simply converting to the proper ascii characters and inserting into the string.
Loop v4 - The Finale
The next and final task is to simply remove the leading '0' from the output that Loop v3 produces while the loop index is still in the single digits. Luckily, the solution is remarkably simple and universal between the two architectures. The solution is comparing the converted quotient with the ascii value 48 or '0', if equal branching past inserting that digit, and making sure the placeholders for the two digits are now initially whitespace. If the character for the first digit is equal to '0' the branch will jump ahead to inserting the second digit, and the 6th byte in the string will remain empty, producing single digit output for the 0-9 loops.
AArch64 Loop v4
.text
.globl _start
min = 0
max = 31
_start:
mov x19, min
loop:
// Prepare message
mov x22, 10 /* store int value 10 into x22 */
udiv x23, x19, x22 /* calculate both digits of the index */
msub x24, x23, x22, x19
add x20, x23, 48 /* convert first digit */
cmp x20, 48 /* check 1st digit == '0' */
b.eq digit2 /* skip writing 1st digit if '0' */
adr x21, msg+6 /* set first digit placeholder address */
strb w20, [x21] /* overwrite first digit placehokder */
digit2: add x20, x24, 48 /* convert 2nd digit */
adr x21, msg+7 /* set 2nd digit placeholder address */
strb w20, [x21] /* overwrite 2nd digit placehokder */
// Print
mov x0, 1 /* file descriptor: 1 is stdout */
adr x1, msg /* message location (memory address) */
mov x2, len /* message length (bytes) */
mov x8, 64 /* write is syscall #64 */
svc 0 /* invoke syscall */
// Continue the loop
add x19, x19, 1
cmp x19, max
b.ne loop
// Exit
mov x0, 0 /* status -> 0 */
mov x8, 93 /* exit is syscall #93 */
svc 0 /* invoke syscall */
.data
msg: .ascii "Loop: \n"
len= . - msg
X86_64 Loop v4
.text
.globl _start
min = 0
max = 31
_start:
mov $min,%r12
loop:
mov %r12,%rax /* prepare div args */
mov $10,%r13
mov $0,%rdx
div %r13 /* divide loop index by 10 */
add $'0',%rax /* convert quotient into char */
add $'0',%rdx /* convert remainder into char */
cmp $'0',%rax /* check 1st digit == '0' */
je digit2 /* skip writing 1st digit if '0' */
movb %al,msg+6 /* overwrite first digit placeholder */
digit2: movb %dl,msg+7 /* overwrite 2nd digit placeholder */
movq $len,%rdx /* message length */
movq $msg,%rsi /* message location */
movq $1,%rdi /* file descriptor stdout */
movq $1,%rax /* syscall sys_write */
syscall
inc %r12
cmp $max,%r12
jne loop
movq $0,%rdi /* exit status */
movq $60,%rax /* syscall sys_exit */
syscall
.section .data
msg: .ascii "Loop: \n"
len = . - msg
- Get link
- X
- Other Apps
Comments
Post a Comment