I'm trying to make an Assembly program concatenate two Strings. Here's my program.
AREA Assignment4, CODE, READONLY
ENTRY
;;;;;;;;;;Setting Up
ADR r0, StrF ;Address of first block in destination
;;;String 1
ADR r1, Str1 ;Address of first string
ADR r2, EoS ;Address of EoS1
SUBS r2, r2,r1 ;Length of str1, counter
;;;;String2
ADR r3, Str2 ;Address of second string
ADR r4, EoS2 ;Address of EoS2
SUBS r4, r4,r3 ;Length of Str2
;;;;;;;;;;Performing Actions
;;;;First String
Loop LDRB r5,[r1],#1 ;Load next bit of "r1" in r5
STRB r5,[r0],#1 ;Store prev bit in memory at r0
SUBS r2, r2, #1 ;Decrement counter
CMP r2, #0 ;Compare our counter
BNE Loop ;Branch if counter != 0
;;;;;Second String
Loop2 LDRB r5,[r3],#1 ;Load next bit of "r3" to r5
STRB r0,[r5],#1 ;Store this bit in r0
SUBS r4, r4, #1 ;Decrement length counter
CMP r4, #0 ;Compare our counter
BNE Loop2 ;Branch if counter != 0
;; Testing the memory - Delete these lines later
ADR r0, StrF
loop3 LDRB r1,[r0],#1
B loop3
Finished B Finished
Str1 DCB "This is a test string1" ;Str1
EoS DCB 0x00
Str2 DCB "This is a test string2" ;Str2
EoS2 DCB 0x00
StrF DCB 0x00 ;Saving this
END
My problem is on lines 22 + 29. I don't know how to successfully store the current byte onto the memory; more specifically the memory in register r0, initialized initially by StrF.
Any ideas on how to fix my STRB or STR?
I get this once I pass that line:
"error 65: access violation at 0x00000082 : no 'write' permission"
thats the memory address that at StrF that im trying to save into.
You see that big "READONLY" in the first line?
Since strF is located in the same area as the code declared as readonly, it of course doesn't work.
You should put strF in a differnt area declared as readwrite, but you won't be able to use adr then.
All in all, you should design the routines in a way that they receive memory addresses as parameters from the callers.
i had this problem, so if you are using keil, when u in debug mode go to debug -> memorymap, then add memory range manually
0x00000048 ,0x0000011A
and check on read, write a/o execute
check this page
DEBUGGER: ERROR 65 (ACCESS VIOLATION)
Related
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.
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
While learning ARMv6 ASM (using raspberry pi) I was trying to implement a loop which would modify the contents of a string, however I cannot seem to store the modified byte back to memory.
Using GDB and breaking at various points shows me all registry values are working perfectly until it comes to the STRB instruction. Then it crashes for some unknown reason.
The loop should decrement all bytes by 1 in reverse order.
.text
.global _start
_start:
/* Thumb mode */
.code 32
add r6, pc, #1
bx r6
.code 16
mov r4, #6
mov r0, pc
add r0, #16
loop:
/*load, modify, store*/
ldrb r3, [r0]
sub r3, #1
strb r3, [r0] /*THIS IS BROKEN*/
sub r0, #1
sub r4, r4, #1
bne loop
bx lr
.data
string:
asciz "HiThere"
The STRB instruction seems to crash the program, I am using an old book to learn from, am I missing something obvious here?
EDIT: yes I know that isnt the best way to load r0 but it works...i guess it could use a label in future.
EDIT2: Sorry I know my question was badly written, Ive included more code for clarity. Still crashes on STRB when stepping through in gdb.
EDIT: rather than increasing r0, your loop decreases it. So, rather than scrolling through the string, you are scrolling up straight into your code, overwriting instructions with less-by-one byte values. Once you overwrite the strb instruction, SIGILL happens.
Replace
sub r0, #1
with
add r0, #1
PREVIOUS: I see r0 being initialized to a memory location in the code section, past pc. Is that a writable memory block? I'm not so sure.
Place the string in the data section instead.
EDIT: there's another thing; your loop has no exit condition. SUB doesn't set flags unless told to; so replace
sub r4, r4, #1
with
subs r4, r4, #1
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:
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.