trying to learn some basic ARM and I am trying to figure how to get the length of a string using a while loop. Below is what I am trying to achieve in C and also what I am attempting to do in ARM. My issue comes from the while loop, I am unable to go through the string until I hit the null terminator and to keep track of it with a variable.
char inputString[7];
int lengthOfInput = 0;
while (inputString[lengthOfInput] != '\0')
{
lengthOfInput++;
}
.section .data
#need to include \n if you want to test the output. no idea why
input_prompt : .asciz "string: "
input_spec : .asciz "%[^\n]"
length_spec : .asciz "length: %d\n"
#8 bytes for 7 characters plus \0
input: .space 8
.section .text
.global main
main:
#print prompt
ldr x0, =input_prompt
bl printf
#get input
ldr x0, =input_spec
ldr x1, =input
bl scanf
#call get_length
ldr x9, =input
ldrsw x0, [x9]
bl get_length
#print result from get_length
#to do
#exit
b exit
get_length:
#intializing "i" as 0
add x19, xzr, xzr
get_length_loop:
#address of userString[i]
add x12,x19,x1
#if == 0, go somewhere, maybe get_length should be changed
cbz x12, get_length
add x19,x19, 1
b get_length_loop
#return result
mov x0, x19
ret
exit:
mov x0, 0
mov x8, 93
svc 0
ret
Related
.equ READERROR, 0 #Used to check for scanf read error.
.global main # Have to use main because of C library uses.
main:
prompt:
# Ask the user to enter a number.
ldr r0, =strInputPrompt # Put the address of my string into the first parameter
bl printf # Call the C printf to display input prompt.
ldr r0, =numInputPattern # Setup to read in one number.
ldr r1, =intInput # load r1 with the address of where the
# input value will be stored.
bl scanf # scan the keyboard.
cmp r0, #READERROR # Check for a read error.
beq readerror # If there was a read error go handle it.
ldr r1, =intInput # Have to reload r1 because it gets wiped out.
ldr r1, [r1] # Read the contents of intInput and store in r1 so that
# it can be printed
ldr r0, =strOutputNum
bl printf
ldr r0, =strOutputEven
loop:
cmp r1, #101
beq end
cmp r1, #0
bne odd
cmp r1, #1
bne even
odd:
add r1, r1, LSL #1 /* r1 ← r1 + (r1 << 1) */
bl printf
even:
mov r1, r1, ASR #1 /* r1 ← (r1 >> 1) */
b end_loop
end_loop:
add r2, r2, #1 /* r2 ← r2 + 1 */
b loop /* branch to loop */
# Print the input out as a number.
# r1 contains the value input to keyboard.
b myexit # leave the code.
readerror:
# Got a read error from the scanf routine. Clear out the input buffer then
# branch back for the user to enter a value.
# Since an invalid entry was made we now have to clear out the input buffer by
# reading with this format %[^\n] which will read the buffer until the user
# presses the CR.
ldr r0, =strInputPattern
ldr r1, =strInputError # Put address into r1 for read.
bl scanf # scan the keyboard.
Not going to do anything with the input. This just cleans up the input buffer. The input buffer should now be clear so get another input.
b prompt
myexit:
End of my code. Force the exit and return control to OS
mov r7, #0x01 # SVC call to exit
svc 0 # Make the system call.
.data
Declare the strings and data needed
.balign 4
strInputPrompt: .asciz "Input a number between 1 and 100: \n"
.balign 4
strOutputNum: .asciz "You entered: %d \n"
.balign 4
strOutputEven: .asciz "The even numbers from 1 to %d are: \n"
Format pattern for scanf call.
.balign 4
numInputPattern: .asciz "%d" # integer format for read.
.balign 4
strInputPattern: .asciz "%[^\n]" # Used to clear the input buffer for invalid input.
.balign 4
strInputError: .skip 100*4 # User to clear the input buffer for invalid input.
.balign 4
intInput: .word 0 # Location used to store the user input.
.global printf
.global scanf
cannot get even and odd functions to work
The first problem is here:
cmp r1, #0
bne odd
cmp r1, #1
bne even
This actually compares the entire number to 0 or 1, when you only want the rightmost bit. You'll need to do something like this. I'll only list the even case, I think you can figure out the odd. I'm a bit rusty at ARM assembly and haven't tested this but something like it should work:
tst r1,#1 # sets the flags as you did "AND r1,r1,#1" but doesn't change r1
bne odd # now you will jump to label "odd" if r1 is odd, or keep
# going if it's even.
# if it isn't odd, it must be even, so your even code goes here!
push r1-r2 # technically this is a thumb mode only instruction but if your
# assembler allows unified syntax it should get assembled as the
# 32-bit instruction "STMFD sp!,{r1-r2}"
# this saves r1 and r2 on the stack, we get them back with POP.
# C functions assume the stack is aligned to 8 bytes so we have to push
# an even number of registers even though we only needed to push R1.
ldr r0,=strOutputEven # r1 still contains intInput
bl printf # prints "The even numbers from 1 to %d are,"
pop R1-R2 # unified syntax for "LDMFD sp!,{r1-r2}"
# now we'll do the loop:
ldr r0,=numInputPattern
mov r1,#0 # we don't need the input anymore
mov r2,#0 # the sum goes here
loop_even:
add r1,r1,#2
cmp r1,#101
bcc exitLoop # if R1 is greater than or equal to 101, exit.
PUSH R0-R3 # I can't remember what printf alters so better safe than sorry.
bl printf
POP R0-R3
add r2,r2,r1 # add R1 to R2 and store the result in R2.
b loop_even
exitloop:
mov r1,r2 # put the sum into r1 so we can print it
bl printf # print the string
b my_exit # we're done!
odd:
I would recommend reading up on the PUSH and POP instructions and how they work, it's a much more reliable way of temporarily preserving registers than the method you used with ldr r1,[r1]. Don't feel ashamed if you need to print out a reference list of the ARM instructions - I use one all the time.
.global main
.type main%function
# r4 = argc
# r5 = current offset
# r6 = end offset
# r7 = array argv
main:
mov r4,r0
ldr r0,=message
mov r5,#0 // initialize offset
mov r6,#4
mul r6,r4,r6 // calculate end offset
mov r7,r1 // put array argv in r7
loop:
ldr r1,[r7,r5] // load the argv element with offset r5
push {ip,lr} // save lr
bl printf
pop {ip,lr}
add r5,r5,#4 // go to next word
cmp r5,r6
bne loop // if I haven't reached the end offset, it does another cycle
end:
mov r0,#0 // clear exit code
bx lr // returns
message:
.asciz "%s\n"
Output:
$ ./a.out a
./a.out
Segmentation fault
but:
$ ./a.out
./a.out
so apparently the problems comes when I try to access the next element of the array... really don't know why... I'm new with arm and assembly..
Currently doing a project for school in Arm Assembly and I've run into a strange problem early on. The program takes two integers as input and is supposed to print the first integer and then, print the absolute value of that integer. The problem is that when I input a negative value, I can't find a way to identify that it is negative, as no matter what kind of branch condition I use the branch is not taken.
This is in Armv8, I've tried to compare the value in x1 to #0 and use BLT and BMI both, but it seems that in either case the branch is not taken. Interestingly the value is always printed as negative, so I'm very confused as to how this works.
.data
newline: .asciz "\n"
input_fmt: .asciz "%d %d"
output_fmt: .asciz "%d"
strfmt: .asciz "hello"
num1: .space 256
num2: .space 256
.text
.global main
main:
//take input
ldr x0, =input_fmt
ldr x1, =num1
ldr x2, =num2
bl scanf
ldr x0, =output_fmt
ldr x1, =num1
ldr x1, [x1]
bl printf
ldr x1, =num1
ldr x1, [x1]
cmp x1, #0 //<---- PROBLEM
bmi ABS //Branch is never taken, even when input is negative
ldr x0, =output_fmt
bl printf
b exit
ABS:
neg x1, x1
br x30
exit:
mov x0, #0
mov x8, #93
svc #0
I am trying to implement insertion sort in Assembly ARMV-8A. More specifically i tried to translate the following code in C:
void insertionSortRecursive(int arr[], int n)
{
if (n <= 1)
return;
insertionSortRecursive( arr, n-1 );
int last = arr[n-1];
int j = n-2;
while (j >= 0 && arr[j] > last)
{
arr[j+1] = arr[j];
j--;
}
arr[j+1] = last;
}
I have tried to translate it as it is but my implementation gets into infinite loop in function loop_insertion as debugger shows:
.data
my_Table: .space 16
size: .word 4
FileOpenMode: .string "r"
FileName: .string "test1.txt"
fscanf_str: .string "%d"
printf_str: .string "%d "
out_message_str: .string "%d "
.text
.global main
main:
stp x29,x30,[sp,-32]!
add x29,sp,0
adr x1,FileOpenMode
adr x0,FileName
bl fopen
mov x20,x0
adr x0,my_Table
mov x22,x0 //x22 adr of table
mov x21,4
mov x23,0
//**************** READ FROM FILE ******************
loop:
add x2,x29,28
adr x1,fscanf_str
mov x0,x20
bl fscanf
ldr w1,[x29,28]
mov x0,x22
str w1,[x0,x23]
add x23,x23,4
add w21,w21,-1
cbnz w21,loop
//********************************************
mov x0,x22 //adr of table
mov x1,4
bl insertion_sort
//**************** PRINT TO SCREEN FROM TABLE *****************
mov x21,0
mov x23,4
loop_print:
adr x0, out_message_str
ldr w1,[x22,x21]
bl printf
add x21,x21,4
sub x23,x23,1
cbnz x23,loop_print
//***********************************************************
ldp x29, x30, [sp], 32
ret
insertion_sort:
stp x29,x30,[sp,-64]!
add x29,sp,0
str x19,[x29,32] //str the save register
str x0,[x29,16] //str the address of table
str w1,[x29,24] //str the n
mov x19,4
cmp w1,1
b.le exit_ins
sub w1,w1,1
bl insertion_sort
ldr w9,[x29,24] //load the n for the suitable function
sub w9,w9,1 //n-1
mul w9,w9,w19
ldr x10,[x29,16] //adr table
ldr w11,[x10,x9] //last
udiv w9,w9,w19
sub w12,w9,1 //j=n-2
loop_insertion:
ldr w12,[x29,24]
cmp w12,0
b.lt label1
mul w12,w12,w19
ldr w13,[x10,x12] // w13=arr[j]
cmp w13,w11
b.le label1
add w12,w12,w19
str w13,[x10,x12] //arr[j+1]=w13
udiv w12,w12,w19
sub w12,w12,1
str w12,[x29,24]
b loop_insertion
label1:
add w12,w12,1
mul w12,w12,w19
str w11,[x10,x12]
exit_ins:
ldr x19,[x29,32] //ldr the value of x19 back to the x19
ldp x29, x30, [sp], 64
ret
I did some modifications such as loading and storing the value of n-2 inside the insertion_loop function but that does not make any change.
You need to comment your code better, especially if you want others to help.
I am guessing that instead of preserving j in w12 you are doing calculations with it and then try to get the original value back but fail. Since you have done add w12,w12,w19 to get arr[j+1], the value of w12 after udiv w12,w12,w19 will be j+1 and when you subtract one from that you end up with j again, hence the infinite loop. You have tons of registers, just use a different one for the j+1.
You should have been able to see this in your debugger.
I'm writing a rot13 in armsim# everything works besides the fact that it will not read the next line
.equ SWI_Open, 0x66 #open a file
.equ SWI_Close,0x68 #close a file
.equ SWI_PrChr,0x00 # Write an ASCII char to Stdout
.equ SWI_PrStr, 0x69 # Write a null-ending string
.equ SWI_PrInt,0x6b # Write an Integer
.equ SWI_RdInt,0x6c # Read an Integer from a file
.equ SWI_RdStr, 0x6a # Read string from file
.equ Stdout, 1 # Set output target to be Stdout
.equ SWI_Exit, 0x11 # Stop execution
.global _start
.text
_start:
ldr r0,=InFileName # set Name for input file
mov r1,#0 # mode is input
swi SWI_Open # open file for input
ldr r1,=InFileHandle
str r0,[r1]
ldr r7,[r1]
ldr r1,=array
mov r2,#85
swi SWI_RdStr #stores the string into =array
bcs EofReached
mov r5,#0 #r5 is index
loop: #processes a single char then loops back
ldrb r4,[r1,r5] #loads the character value from =array[r5] into r4
cmp r4,#0
BEQ newline
cmp r4,#32
beq skip
cmp r4,#96
bgt lowercase
cmp r4,#91
blt uppercase
uppercase:
cmp r4,#77
ble add
cmp r4,#91
blt sub
lowercase:
cmp r4,#109
ble add
cmp r4,#123
blt sub
add:
add r4,r4,#13
b skip
sub:
sub r4,r4,#26
add r4,r4,#13
skip:
mov r0,r4
swi SWI_PrChr
strb r4,[r1,r5]
add r5,r5,#1
b loop
newline:
bcs EofReached
mov R0,#Stdout # print new line
ldr r1,=NL
swi SWI_PrStr
bal loop
swi SWI_Close
swi SWI_Exit
EofReached:
mov R0, #Stdout # print last message
ldr R1, =EndOfFileMsg
swi SWI_PrStr
Exit:
swi SWI_Exit # stop executing
.data
InFileName: .asciz "lab2.txt"
EndOfFileMsg: .asciz " End of file reached\n"
ColonSpace: .asciz": "
NL: .asciz "\n" # new line
.array: .skip 85
.align
InFileHandle: .word 0
.end
Anyone with knowledge of ARMSIM feel free to help
I'm using this example to help me
http://armsim.cs.uvic.ca/AttachedFiles/ARMSim_UserGuide4Plus.pdf example 11.2 but to no help the program stops reading after one line is finished