ARM Assembly creating a function - linux

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.

Related

I get a wrong result if I copy the return value of a function to another register instead of r1, why?

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.

ARM Assembly loading string produces weird terminal output

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

Print Newline for Armv7 assembly program

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.

How to print a number in ARM assembly?

I am trying to print a number that I have stored. I'm not sure if I am close or way off. Any help would be appreciated though. Here is my code:
.data
.balign 4
a: .word 4
.text
.global main
main:
ldr r0, addr_of_a
mov r1, #8
str r1, [r0]
write:
mov r0, #1
ldr r1, addr_of_a
mov r2, #4
mov r7, #4
swi #0
bx lr
addr_of_a: .word a
It compiles and runs, but I don't see anything printed. From what I understand, I need the address of where to start printing in r1, how many bytes in r2, the file descriptor in r0, and r7 specifies the write call if it is set to #4. I am simply trying to store #8, then print the stored number.
The syscall write takes on the second argument (r1) as a pointer to the string you want to print. You are passing it a pointer to an integer, which is why it's not printing anything, because there are no ASCII characters on the memory region you are passing to it.
Below you'll find a "Hello World" program using the syscall write.
.text
.global main
main:
push {r7, lr}
mov r0, #1
ldr r1, =string
mov r2, #12
mov r7, #4
svc #0
pop {r7, pc}
.data
string: .asciz "Hello World\n"
If you want to print a number you can use the printf function from the C library. Like this:
.text
.global main
.extern printf
main:
push {ip, lr}
ldr r0, =string
mov r1, #1024
bl printf
pop {ip, pc}
.data
string: .asciz "The number is: %d\n"
Finally, if you want to print the number with the syscall write you can also implement a itoa function (one that converts an integer to a string).
Hi I appreciate that this is a pretty old thread but I've scratched my head over this for a while and would like to share my solution. Maybe it'll help someone along the way!
I was aiming to print to digit without recourse to using C++ in any way, though I realise that simply decompiling a tostring() - or whatever equivalent exists in C++ - and seeing what that came up with would have been a far quicker route.
Basically I ended up with creating a pointer to an empty .ascii string in the section .data and added the digit that I wanted to print + 48 to it before printing off that digit.
The +48 of course is to refer to the specific digit's ascii index number.
.global _start
_start:
MOV R8, #8
ADD R8, R8, #48
LDR R9, =num
STR R8, [R9]
MOV R0, #1
LDR R1, =num
MOV R2, #1
MOV R7, #4
SWI 0
.data
num:
.ascii: " "
The biggest drawback of this approach is that it doesn't handle any number more than one digit long of course.
My solution for that was much, much uglier and beyond the scope of this answer here but if you've a strong stomach you can see it here:

ARM - Infinite Loop While Searching String

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.

Resources