Lab 4 - 64-bit Assembly Language Lab - Part 3
Welcome to part 3 of lab 4. This lab goes over some basics of 64-bit assembly languages, specifically in the AArch64 and x86_64 platforms. This specific part will be going over the second half of the lab in the AArch64 system. Links for the other parts are listed here:
Part 1 - First half in AArch64
Part 2 - First half in x86_64
Part 4 - Second half in x86_64
I'll be outlining the steps in detail as I go along but the full instructions for this lab can be found here.
Okay this is where the lab gets a bit trickier. Our instructions now are to make our loop from previous parts loop from 00-30, printing a double digit on every line. Before we relied on a somewhat simplistic method to print the index, and now we'll have to get a bit fancier. To do this I used udiv and msub. udiv divides a register by another register, and it very specifically wants a register it seems, and not just a value. So I made register 28 equal 10, and used that for my equations. Then I used msub to calculate the remainder and honestly in this first 2 parts of this lab I started to feel like AArch64 was cumbersome, but now I'm really feeling it. I multiply register 20, the result from the division, by 10 (register 28) and subtract it from the index to get the remainder (if any) from the original division. And then I store it in register 21. Cumbersome. After that it's just a matter of converting these individual digits into characters and inserting them into their respective spots in msg. Honestly I'll admit my code is a bit messy and I could have probably reused some registers in some part to make the program use less registers but too late now. The edited code is provided below:
.text
.globl _start
min = 0 /* starting value for the loop index; note that this is a symbol (constant), not a variable */
max = 31 /* loop exits when the index hits this number (loop condition is i<max) */
_start:
mov x19, min //index for looping
mov x28, 10 //value 10 for dividing
loop:
udiv x20, x19, x28 //calculate first digit
msub x21, x20, x28, x19 //calculate remainder (second digit)
add x24, x20, '0' //Create first digit character
add x25, x21, '0' //Create second digit character
adr x26, msg+6 //Pointer for first digit location
adr x27, msg+7 //Pointer for second digit location
strb w24, [x26] //Insert first digit
strb w25, [x27] //Insert second digit
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 */
add x19, x19, 1
cmp x19, max
b.ne loop
mov x0, 0 /* status -> 0 */
mov x8, 93 /* exit is syscall #93 */
svc 0 /* invoke syscall */
.data
msg: .ascii "Loop: ##\n"
len= . - msg
And of course, the output is shown here.
Loop: 00
Loop: 01
Loop: 02
Loop: 03
Loop: 04
Loop: 05
Loop: 06
Loop: 07
Loop: 08
Loop: 09
Loop: 10
Loop: 11
Loop: 12
Loop: 13
Loop: 14
Loop: 15
Loop: 16
Loop: 17
Loop: 18
Loop: 19
Loop: 20
Loop: 21
Loop: 22
Loop: 23
Loop: 24
Loop: 25
Loop: 26
Loop: 27
Loop: 28
Loop: 29
Loop: 30
For this next part I need to suppress that leading zero. Not entirely sure how that's meant to look but I interpreted that as making the first digit a space if it was zero. I'm going to provide a small sample of the code below of the important logic. First I'm just checking if the first digit is a zero, and if it is I branch to a label called suppressLeadZero. This skips over the section of code where I would have inserted the first digit, and instead I add a space to the first digits spot. If instead the first digit isn't zero, I insert the digit normally and than branch past suppressLeadZero and go straight to inserting the second digit. Definitely feel like my code is neater now that I'm using labels, but once again I should have reused some registers to reduce the overall amount of registers used. Like I could have just used the same registers in both firstDigit and secondDigit as overwriting them would have been pretty easy. Oh well.
cmp x20, 0 //check if first digit is zero
b.eq suppressLeadZero
firstDigit:
add x24, x20, '0' //Create first digit character
adr x26, msg+6 //Pointer for first digit location
strb w24, [x26] //Insert first digit
bl secondDigit //branch to secondDigit
suppressLeadZero:
mov x24, ' '
adr x26, msg+6 //Pointer for first digit location
strb w24, [x26] //Insert first digit
secondDigit:
add x25, x21, '0' //Create second digit character
adr x27, msg+7 //Pointer for second digit location
strb w25, [x27] //Insert second digit
Here's the full code by the way:
.text
.globl _start
min = 0 /* starting value for the loop index; note that this is a symbol (constant), not a variable */
max = 31 /* loop exits when the index hits this number (loop condition is i<max) */
_start:
mov x19, min //index for looping
mov x28, 10 //value 10 for dividing
loop:
udiv x20, x19, x28 //calculate first digit
msub x21, x20, x28, x19 //calculate remainder (second digit)
cmp x20, 0 //check if first digit is zero
b.eq suppressLeadZero
firstDigit:
add x24, x20, '0' //Create first digit character
adr x26, msg+6 //Pointer for first digit location
strb w24, [x26] //Insert first digit
bl secondDigit //branch to secondDigit
suppressLeadZero:
mov x24, ' '
adr x26, msg+6 //Pointer for first digit location
strb w24, [x26] //Insert first digit
secondDigit:
add x25, x21, '0' //Create second digit character
adr x27, msg+7 //Pointer for second digit location
strb w25, [x27] //Insert second digit
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 */
add x19, x19, 1
cmp x19, max
b.ne loop
mov x0, 0 /* status -> 0 */
mov x8, 93 /* exit is syscall #93 */
svc 0 /* invoke syscall */
.data
msg: .ascii "Loop: ##\n"
len= . - msg
And of course, the output.
Loop: 0
Loop: 1
Loop: 2
Loop: 3
Loop: 4
Loop: 5
Loop: 6
Loop: 7
Loop: 8
Loop: 9
Loop: 10
Loop: 11
Loop: 12
Loop: 13
Loop: 14
Loop: 15
Loop: 16
Loop: 17
Loop: 18
Loop: 19
Loop: 20
Loop: 21
Loop: 22
Loop: 23
Loop: 24
Loop: 25
Loop: 26
Loop: 27
Loop: 28
Loop: 29
Loop: 30
This is the end of the AArch64 portions, in the next and final part I will conclude by doing these same steps in the x86_64 platform. Click here for that.
Comments
Post a Comment