I am trying to space out my string by replacing each character with a space string combined with an underscore string to create _ _ _ _.
However, I get a weird output:
If I load 1 character e.g ldr r1, = '_'
it works however I get _____ and I am trying to get _ _ _ _ _. What is the best way to do this?
NOTE: I do not know C and I am new to ARM.
My function:
sub r3, r0, #1 #has the length
ldr r0, = buffer #has the word
mov r5, #0 #start of increment
mov r6, r0 #copies word to r6
loop:
ldr r1, =spaceChar
strb r1, [r6, r5]
add r5, r5, #1
cmp r3, r5
bne loop
mov r1,r6
ldr r0, = HiddenWord
bl printf
pop {r4,lr}
bx lr
.data
HiddenWord:
.asciz "Word: %s"
spaceChar:
.asciz " _"
buffer:
.space 100
Since you already statically allocate the buffer the simplest solution is to preset it with " _" using your assembler and just put the terminating zero in the right place. I don't think you mentioned which assembler you use, the following works in gnu assembler:
ldr r0, =buffer-1
mov r1, #0
strb r1, [r0, r3, lsl #1]
ldr r0, =HiddenWord
ldr r1, =buffer
bl printf
pop {r4,lr}
bx lr
.data
HiddenWord:
.asciz "Word: %s\n"
buffer:
.rept 50
.ascii "_ "
.endr
If you want to fill the buffer programmatically, that could look like:
ldr r0, =buffer #has the word
ldr r1, =0x205f # underscore + space
loop:
strh r1, [r0], #2
subs r3, r3, #1
bne loop
mov r1, #0 # replace final
strb r1, [r0, #-1] # space with zero
Related
I am trying to print do_something's return value that is stored in r0. After bl do_something statement, if a copy r0 in r1 the output is correct (8). But if a copy r0 in r2, the output is incorrect, why?
.global main
.extern abs
.extern printf
.text
output_str:
.ascii "The answer is %d\n\0"
.align 4
diffofsums:
push {r4, r5, lr}
add r4, r0, r1 ;r4 = f - g
add r5, r2, r3 ;r5 = h - i
sub r0, r4, r5 ;r0 = result = r4 - r5
pop {r4, r5, pc}
bx lr
main:
push {ip, lr}
mov r0, #2
mov r1, #3
mov r2, #4
mov r3, #5
bl diffofsums
mov r2, r0 ;incorrect output! (correct output when I write mov r1, r0)
ldr r0, =output_str
bl printf
mov r0, #0
pop {ip, pc}
Maybe it's a printf problem? I don't quite understand how printing works in ARM Assembly.
I get this output from my program which takes a user input, and replaces the linefeed with a null terminating and prints it back out to the console
pi#raspberrypi:~ $ ./tester
Please enter 4 different numbers between 1-5 together without space or special characters.
1234
1234
pi#raspberrypi:~ $
pi#raspberrypi:~ $
But when I type 123 I only get a single line prompt which is what I'm looking for when I enter 1234.
pi#raspberrypi:~ $ ./tester
Please enter 4 different numbers between 1-5 together without space or special characters.
123
123
pi#raspberrypi:~ $
This is the code I'm executing, it's as minimum as I could get it for minimum functional requirements.
.global _start
_start:
LDR r1, =prompt
BL _sPrint
LDR r1, =userInput # point to the space allocated for input
MOV r2, #4 # set the limit of character to read in
BL _sInput
LDR r1, =userInput
BL _sPrint
Ldr r1, =newline
BL _sPrint
B _exit
#_sPrint prints out a string based on it's variable length determined by _strlen
#strlen, and findEnd are both needed for _sPrint.
_sPrint:
MOV r7, #4 #sets r7 to console STDOUT
MOV r0, #1 #set WRITE destination to STDOUT (terminal)
PUSH {r0, r1, lr}
BL _strLen #gets the stringlength and the end
POP {r0, r1, lr}
SWI 0
mov pc, lr
_strLen:
mov r2, #0
#find end of strlen finds the end of the string and stores the length in r2 for console output
findEnd:
LDRB r0, [r1], #1
ADD r2, r2, #1
CMP r0, #0
BNE findEnd
SUB r2, r2, #1
MOV pc, lr
_sInput:
PUSH {R1-R8, lr}
MOV r7, #3 #register r7 being set to 3 to indicate message being read in (read syscall)
MOV r0, #0 #Set READ device to the STDIN (keyboard)
SWI 0
POP {R1-R8, lr}
#String fix takes a string value at r1's address and changes the line feed to be null termianted.
strfx:
LDRB r0, [r1],#1 #loads a single byte from r1 (r1 is dereferenced), which is the _sInput to r0
CMP r0, #10 #is r0 our newline?
BNE strfx
MOV r0, #0 #set r0 to null
STRB r0, [r1, #-1] #store r0's value back into r1's current address location. The final address
MOV PC, LR #location of r1 newline to be the NULL in r1.
_exit:
MOV r7, #1
SWI #0
.data
prompt: .asciz "\nPlease enter 4 different numbers between 1-5 together without space or special characters. \n \n"
newline: .asciz "\n"
userInput: .space 6
You're reading four characters. When the user enters "1234\n" (five characters), the newline is left in the input buffer to be read by the shell. When the user enters "123\n", the newline is actually read by you. Since you have newline-handling code, the solution is simple: you need to read five characters, not four.
The following code is what im having some difficulties with, it takes 3 numbers from the user and adds them up. Although it only returns 1 number no matter the inputs, 135228. I did some research and thought the problem was printf not being able to print ints, but thats not the problem, and I am stuck.
.global main
.func main
.data
x: .word 0
y: .word 0
z: .word 0
sum: .word 0
scanPattern: .asciz "%d %d %d"
.balign 4
mes1: .asciz "Enter 3 numbers, separated by spaces"
.balign 4
mes2: .asciz "The sum of the numbers you just entered is %d\n"
.text
main:
push {lr}
ldr r0, =mes1
bl puts
ldr r0, =scanPattern
ldr r1, =x
ldr r2, =y
ldr r3, =z
bl scanf
ldr r0, =x
ldr r1, =y
ldr r2, =z
bl summerFunc
ldr r3, =sum
str r0, [r3]
ldr r0, =mes2
ldr r1, =sum
bl printf
pop {lr}
bx lr
summerFunc:
push {lr}
add r0, r0, r1
add r0, r2
pop {lr}
bx lr
ldr r0, =mes2
ldr r1, =sum
bl printf
maybe this will help. mes2 is a string with a %d meaning for this string take the first operand and print that value. But what you have passed to printf is the ADDRESS to sum not the value sum. Even though just before that your code showed the understanding that =sum is the address to sum. (storing the result of the prior function assuming that returns the summation in r0. r3 = address of sum, write r0 to memory at address of sum. in this case you could just mov r1,r0, then ldr r0,=mes2. But I suspect your call to the summation function has a pointer vs value problem as well. dont know what that function looks like though.
if near enough (no doubt here) ldr r1,sum should load the value of sum into r1, where ldr r1,=sum is a syntax trick/shortcut. assemble then disassemble this code to see what is happening.
I'm working on this armv7 assembly program that finds the greatest common divisor(gcd) of two integers. Everything is working fine except for the newline function. When i assemble and run the program, it doesn't print any newlines, just the integers in one line. Any suggestions on how i can fix that?
.global _start
_start:
mov r2, #24 #first set of integers
mov r4, #18
bl mysub1
bl mysub2
bl mysub3
mov r2, #78 #second set of integers
mov r4, #34
bl mysub1
bl mysub2
bl mysub3
mov r2, #99 #third set of integers
mov r4, #36
bl mysub1
bl mysub2
bl mysub3
_exit:
mov r7, #1
swi 0
mysub1: #subroutine to find gcd
cmp r2, r4
beq done
bgt greater
blt less
greater:
sub r2, r2, r4
bal mysub1
less:
sub r4, r4, r2
bal mysub1
done:
bx lr
mysub2: #subroutine to convert gcd result to ascii value
add r4, #48
ldr r9, =store
str r4, [r9]
mov r7, #4 #print out a newline
mov r0, #1
mov r2, #1
ldr r1, =newline
swi 0
bx lr
mysub3: #subroutine to print out the ascii value
mov r7, #4
mov r0, #1
mov r2, #2
ldr r1, =store
swi 0
bx lr
.data
store:
.space 2
newline:
.ascii "\n"
This is the culprint:
add r4, #48
ldr r9, =store
str r4, [r9]
This code has two bugs:
it only works for numbers between 0 and 9
str r4, [r9] stores four bytes to store, overwriting the newline right after the two-byte buffer.
To fix the first issue, you need to do a division with rest to separate the number in r4 into two digits. To fix the second issue, use strb or strh to store a byte or halfword instead as to not overrun the buffer.
Can anybody point out why? I can't see the problem.
String to search: "aassaas"
String to search with: "as"
SEARCHSTRING:
STMFD SP!, {R4-R7, LR}
MOV R6, #0 #Matches found
MOV R3, #0 #Placeholder
LOOP: LDRB R4, [R0] #R4 = String to search
LDRB R5, [R1] #R5 = String to search with
CMP R4, R5 #Do they match?
ADDEQ R3, R3, #1 #If yes, increase placeholder
LDREQB R4, [R0, #1]! #Get next char
LDREQB R5, [R1, #1]! #Get next char
BLNE RESET #If not, reset placeholder and strings.
#R0 is nevertheless initial pos+1
CMP R5, #0 #Is string to search with at the end?
ADDEQ R6, R6, #1 #If so, add +1 to matches
BLEQ RESET #Reset placeholder and strings.
CMP R4, #0 #Is the string to search finished?
BNE LOOP #If not, start over.
MOV R0, R6 #If so, move answer into R0.
LDMFD SP!, {R4-R7, PC} #Jump back.
RESET:
STMFD SP!, {LR}
CMP R3, #0 #Is the placeholder at 0? (initial position)
SUBNE R0, R0, R3 #If not, subtract from String to search pos
SUBNE R1, R1, R3 #And string to be searched pos
ADDNE R0, R0, #1 #Increment string to search+1 so we don't start at the same spot
MOVNE R3, #0 #Empty the placeholder
LDMFD SP!, {PC} #Jump back
I don't understand why a) you're writing this in assembler instead of C, and b) why you're not using some routine based on strstr. The most likely scenario is that this is a homework problem, or some other form of learning exercise, so I don't want to give too much away. In any event, there are a couple of problems that I noticed. The first bit I notice is in the RESET routine:
RESET:
STMFD SP!, {LR}
CMP R3, #0 #Is the placeholder at 0? (initial position)
SUBNE R0, R0, R3 #If not, subtract from String to search pos
SUBNE R1, R1, R3 #And string to be searched pos
ADDNE R0, R0, #1 #Increment string to search+1 so we don't start at the same spot
MOVNE R3, #0 #Empty the placeholder
LDMFD SP!, {PC} #Jump back
The CMP is unnecessary - consider what the effect of the SUBNE calls will be if R3 is 0, and you'll see that you can perform the subtractions unconditionally. You want to run ADD R0, R0, #1 unconditionally - in fact, this is a big part of the reason you have an infinite loop. If you get to the RESET subroutine, and R3 is 0, then it doesn't change any state. I also notice that the STMFD / LDMFD pair is really not necessary - LR won't be modified in this subroutine, so it doesn't need to go on the stack.
Next, I notice that you're not careful enough about when to terminate your loop. Consider what happens if you give two empty strings as arguments to SEARCHSTRING. Call it with two empty strings as arguments, and single-step through your assembly code to see the problem. The general form of a for loop, when compiled to assembly, will be something like:
for(initial; comparison; increment) {
body;
}
INITIAL:
MOV R0, #0 #initialize variables
B CONDITION #jump to condition check
BODY:
LDR R1, [R0]
INCREMENT: #really, part of the for-loop body.
ADD R0, R0, #1
CONDITION:
CMP BLAH, BLAH #test-condition
BLT BODY #restart loop if condition indicates we should do so.
hopefully this will help you to reorganize the code in a more straightforward way.