Reputation: 105
I am finishing an assignment in which I need to receive an array by input and return it in reverse. I have asked questions about this assignment before and this time I'm close to finishing it. My issue now is that when I store one value of the array on memory my program stops immediately.
Edit: I pasted the full code now. The str that is failing is highlighted with the annotation HERE IT CRASHES. For this assignment I was given this code without a main code or the variables primero, segundo and tercero, which are strings to be printed as the program goes. Prints and fgets are functions to print to screen and read from stdin.
@ Las siguientes funciones fueron obtenidas del archivo ejemplo "UsefulFunctions.s" presente
@en la pagina oficial de descarga del software ARMSIM#
@(Agradecimientos al desarrollador original de estas funciones: R.N. Horspool)
.global prints, fprints, fgets
@ PROGRAMA
.text
.global main
main:
ldr r0, =primero
bl prints
ldr r0, adr_num @where n will be stored
mov r1, #4 @buffer for the first number
mov r2, #0 @indicates fgets must read from stdin
bl fgets
bl atoi @turns to int so as to evaluate without caring about a "\n"
mov r5, r0 @store de received int
ldr r6, =arreglo
firstLoop:
cmp r5, #0
beq msg
ldr r0, =segundo
bl prints
ldr r0, adr_num @where n will be stored
mov r1, #4 @buffer for the first number
mov r2, #0 @indicates fgets must read from stdin
bl fgets
bl atoi @turns to int so as to evaluate without caring about a "\n"
str r0, [r6], #4 @--HERE IT CRASHES--store de recived int in register
sub r5, r5, #1
b firstLoop
msg:
ldr r0, =tercero
bl prints
ldr r0, [r6], #-4
secondLoop:
cmp r8, #0
beq exit
ldr r0, [r6], #-4 @move result to register r0 so as to turn int to string
ldr r1, adr_str @enough space is saved so as to store the result of transformation
bl itoa
bl prints
sub r8, r8, #1
b secondLoop
@Memory data address in DATOS
adr_num: .word number @Here the space for an int is defined (see end of document, section .DATA)
adr_str: .word string @Here the space for a string is defined (see end of document, section .DATA)
@reading of the first character (n):
ldr r0, adr_num @where n will be stored
mov r1, #4 @buffer for the first number
mov r2, #0 @indicates fgets must read from stdin
bl fgets
bl atoi @turns to int so as to evaluate without caring about a "\n"
mov r5, r0 @store de received int
mov r0, r5 @move result to register r0 so as to turn int to string
ldr r1, adr_str @enough space is saved so as to store the result of transformation
bl itoa
bl prints
b exit
exit:
mov r0, #0x18
mov r1, #0
swi 0x123456
@ prints: Returns an ASCII string ending in null to stdout
@
@ Abstract use:
@ prints(r0)
@ Inputs:
@ r0: memory address to ASCII string ending in null
@ Resultado:
@ N/A, but string is written to stdout (console)
prints:
stmfd sp!, {r0,r1,lr}
ldr r1, =operands
str r0, [r1,#4]
bl strlen
str r0, [r1,#8]
mov r0, #0x0
str r0, [r1]
mov r0, #0x05
swi 0x123456
ldmfd sp!, {r0,r1,pc}
@ fgets: read a line of ASCII text from a stream of inputs (open text file or stdin)
@
@ Abstract use:
@ r0 = fgets(r0, r1, r2)
@ Inputs:
@ r0: memory address of a buffer where first line will be stored
@ r1: buffer size (must accommodate an ending character)
@ r2: name of a file to open for input or "0" to read from stdin
@ Resultado:
@ r0: buffer memory address if characters where able to be read or = if @ characters weren't read by an EOF error.
@ One text line including a terminating linefeed character
@ is read into the buffer, if the buffer is large enough.
@ Otherwise the buffer holds size-1 characters and a null byte.
@ Note: the line stored in the buffer will have only a linefeed
@ (\n) line ending, even if the input source has a DOS line
@ ending (a \r\n pair).
fgets: stmfd sp!, {r1-r4,lr}
ldr r3, =operands
str r2, [r3] @ specify input stream
mov r2, r0
mov r4, r1
mov r0, #1
str r0, [r3,#8] @ to read one character
mov r1, r3
mov r3, r2
1: subs r4, r4, #1
ble 3f @ jump if buffer has been filled
str r3, [r1,#4]
2: mov r0, #0x06 @ read operation
swi 0x123456
cmp r0, #0
bne 4f @ branch if read failed
ldrb r0, [r3]
cmp r0, #'\r' @ ignore \r char (result is a Unix line)
beq 2b
add r3, r3, #1
cmp r0, #'\n'
bne 1b
3: mov r0, #0
strb r0, [r3]
mov r0, r2 @ set success result
ldmfd sp!, {r1-r4,pc}
4: cmp r4, r2
bne 3b @ some chars were read, so return them
mov r0, #0 @ set failure code
strb r0, [r2] @ put empty string in the buffer
ldmfd sp!, {r1-r4,pc}
@ strlen: computes the length of a string made form ASCII characters ending in null
@
@ Abstract use:
@ r0 = strlen(r0)
@ Inputs:
@ r0: memory address of an ASCII string ending in null.
@ Resultado:
@ r0: string length (excluding ending byte)
strlen:
stmfd sp!, {r1-r3,lr}
mov r1, #0
mov r3, r0
1: ldrb r2, [r3], #1
cmp r2, #0
bne 1b
sub r0, r3, r0
ldmfd sp!, {r1-r3,pc}
@ atoi: turns an ASCII string ending in null to it's int equivalent
@
@ Abstract use:
@ r0 = atoi(r0)
@ Inputs:
@ r0: memory address of an ASCII string ending in null.
@ Resultado:
@ r0: value of te converted int
atoi:
stmfd sp!, {r1-r4,lr}
mov r2, #0 @ holds result
mov r3, #0 @ set to 1 if a negative number
mov r4, #10
1: ldrb r1, [r0], #1 @ get next char
cmp r1, #0
beq 4f
cmp r1, #' '
beq 1b
cmp r1, #'\n' @se añadio la regla para que no procese los '\n'
beq 1b
cmp r1, #'-'
moveq r3, #1
ldreqb r1, [r0], #1
b 3f
2: cmp r1, #9
bgt 4f
mul r2, r4, r2
add r2, r2, r1
ldrb r1, [r0], #1
3: subs r1, r1, #'0'
bge 2b
4: cmp r3, #0
moveq r0, r2
mvnne r0, r2
ldmfd sp!, {r1-r4,pc}
@ itoa: int to ASCII
@
@ Abstract use:
@ r0 = itoa(r0, r1)
@ Exit parameters:
@ r0: signed integer
@ r1: buffer address that is large enough to keep the functions result, @ @ which will be an ASCII string ending in NULL characterla direccion @ @ de un buffer suficientemente grande para mantener el
@ Resultado:
@ r0: buffers address
itoa:
stmfd sp!, {r1-r7,lr}
mov r7, r1 @ remember buffer address
cmp r0, #0 @ check if negative and if zero
movlt r2, #'-'
moveq r2, #'0'
strleb r2, [r1],#1 @ store a '-' symbol or a '0' digit
beq 3f
mvnlt r0, r0
ldr r3, =4f @ R3: multiple pointer
mov r6, #0 @ R6: write zero digits? (no, for leading zeros)
1: ldr r4, [r3],#4 @ R4: current power of ten
cmp r4, #1 @ stop when power of ten < 1
blt 3f
mov r5, #0 @ R5: multiples count
2: subs r0, r0, r4 @ subtract multiple from value
addpl r5, r5, #1 @ increment the multiples count
bpl 2b
add r0, r0, r4 @ correct overshoot
cmp r5, #0 @ if digit is '0' and ...
cmpeq r6, #0 @ if it's a leading zero
beq 1b @ then skip it
mov r6, #1
add r2, r5, #'0' @ ASCII code for the digit
strb r2, [r1],#1 @ store it
b 1b
3: mov r0, #0
strb r0, [r1]
mov r0, r7
ldmfd sp!, {r1-r7,pc}
4: .word 1000000000, 100000000, 10000000, 1000000
.word 100000, 10000, 1000, 100, 10, 1, 0
@ DATOS
.data
operands: .word 0, 0, 0
string: .space 32 @buffer for a 32 character string
number: .space 4 @buffer for a number (n y then k) + ending character
list: .space 4000 @buffer for a 1000 numbers max list (only 999 will be used as true max)
found: .ascii "Number is in the list."
space: .space 2
unfound: .ascii "Number is not on the list."
primero: .asciz "Enter array length: "
segundo: .asciz "Enter next number of the array: "
tercero: .asciz "Inverted array is: "
arreglo: .word 0, 0, 0
If anyone could tell me what am I doing wrong I'd be much obliged. So far I have used the debugger integrated on ARMSim to pin point the line that gives me issues, i tried adding a memory address to r6 so it isn't in 00000000 but it didn't help.
--------EDIT--------- I tried simply storing a number into a register in another file without any other functions and my problem persist, seems I don't know how to use the STR instruction, for example this code stops right in the first STR and doesn't continue:
.data
array: .word 0
.text
main:
ldr r1, =array
mov r2, #4
str r1, [r2]
ldr r3, [r1]
add r3, r3, r3
Upvotes: 0
Views: 516
Reputation: 2754
Just for the fun of it, I converted the program to use Linux syscalls:
.syntax unified
.cpu arm1176jzf-s
.arm
@ Las siguientes funciones fueron obtenidas del archivo ejemplo "UsefulFunctions.s" presente
@ en la pagina oficial de descarga del software ARMSIM#
@ (Agradecimientos al desarrollador original de estas funciones: R.N. Horspool)
.global _start
@ PROGRAMA
.text
.type _start, %function
_start:
ldr r0, =primero
bl prints
ldr r0, adr_num @where n will be stored
movs r1, #4 @buffer for the first number
movs r2, #0 @indicates fgets must read from stdin
bl fgets
bl atoi @turns to int so as to evaluate without caring about a "\n"
movs r5, r0 @store de recived int
mov r8, r0
cmp r0, #100
it hi
bhi exit
ldr r6, =arreglo
firstLoop:
cmp r5, #0
beq msg
ldr r0, =segundo
bl prints
ldr r0, adr_num @where n will be stored
movs r1, #4 @buffer for the first number
movs r2, #0 @indicates fgets must read from stdin
bl fgets
bl atoi @turns to int so as to evaluate without caring about a "\n"
str r0, [r6], #4 @--HERE IT CRASHES--store de recived int in register
sub r5, r5, #1
b firstLoop
msg:
ldr r0, =tercero
bl prints
secondLoop:
cmp r8, #0
beq exit
ldr r0, [r6, #-4]! @move result to register r0 so as to turn int to string
ldr r1, adr_str @enough space is saved so as to store the result of transformation
bl itoa
bl prints
sub r8, r8, #1
b secondLoop
@Memory data adress in DATOS
adr_num: .word number @Here the space for an int is defined (see end of document, section .DATA)
adr_str: .word string @Here the space for a string is defined (see end of document, section .DATA)
.type exit, %function
exit:
movs r7, #1
movs r0, #0
svc #0
@ prints: Returns an ASCII string ending in null to stdout
@
@ Abstract use:
@ prints(r0)
@ Inputs:
@ r0: memory adress to ASCII string ending in null
@ Resultado:
@ N/A, but string is writen to stdout (console)
.type prints, %function
prints:
stmfd sp!, {r0-r7,lr}
bl strlen
movs r7, #4
movs r2, r0
ldr r1, [sp]
movs r0, #1
svc #0
ldmfd sp!, {r0-r7,pc}
@ fgets: read a line of ASCII text from a stream of inputs (open text file or stdin)
@
@ Abstract use:
@ r0 = fgets(r0, r1, r2)
@ Inputs:
@ r0: memory adress of a buffer where first line will be stored
@ r1: buffer size (must acomodate an ending character)
@ r2: name of a file to open for input or "0" to read from stdin
@ Resultado:
@ r0: buffer memory adress if characters where able to be read or = if @ characters wheren't read by an EOF error.
@ One text line including a terminating linefeed character
@ is read into the buffer, if the buffer is large enough.
@ Otherwise the buffer holds size-1 characters and a null byte.
@ Note: the line stored in the buffer will have only a linefeed
@ (\n) line ending, even if the input source has a DOS line
@ ending (a \r\n pair).
.type fgets, %function
fgets: stmfd sp!, {r0-r9,lr}
mov r8, r1 @ Count
mov r9, r0 @ Buffer
1: subs r8, r8, #1
ble 3f @ jump if buffer has been filled
2:
ldr r0, [sp, #8] @ File Descriptor
mov r1, r9 @ Buffer
movs r2, #1 @ Count
movs r7, #3 @ read syscall
svc #0
cmp r0, #1
bne 4f @ branch if read failed
ldrb r0, [r9]
cmp r0, #'\r' @ ignore \r char (result is a Unix line)
beq 2b
adds r9, r9, #1
cmp r0, #'\n'
bne 1b
3: movs r0, #0
strb r0, [r9]
ldmfd sp!, {r0-r9,pc}
4: ldr r2, [sp, #4]
cmp r8, r2
bne 3b @ some chars were read, so return them
movs r0, #0 @ set failure code
strb r0, [r9] @ put empty string in the buffer
adds sp, #4 @ Skip over saved buffer pointer
ldmfd sp!, {r1-r9,pc}
@ strlen: computes the lenght of a string made form ASCII characters ending in null
@
@ Abstract use:
@ r0 = strlen(r0)
@ Inputs:
@ r0: memory adress of an ASCII string enfing in null.
@ Resultado:
@ r0: string lenght (excluding ending byte)
.type strlen, %function
strlen:
stmfd sp!, {r1-r2,lr}
mov r2, r0
1: ldrb r1, [r2], #1
tst r1, r1
bne 1b
sub r0, r2, r0
ldmfd sp!, {r1-r2,pc}
@ atoi: turns an ASCII string ending in null to it's int equivalent
@
@ Abstract use:
@ r0 = atoi(r0)
@ Inputs:
@ r0: memory adress of an ASCII string ending in null.
@ Resultado:
@ r0: value of te converted int
.type atoi, %function
atoi:
stmfd sp!, {r1-r4,lr}
movs r2, #0 @ holds result
movs r3, #0 @ set to 1 if a negative number
movs r4, #10
1: ldrb r1, [r0], #1 @ get next char
cmp r1, #0
beq 4f
cmp r1, #' '
beq 1b
cmp r1, #'\n' @se añadio la regla para que no procese los '\n'
beq 1b
cmp r1, #'-'
itt eq
moveq r3, #1
ldrbeq r1, [r0], #1
b 3f
2: cmp r1, #9
bgt 4f
mul r2, r4, r2
add r2, r2, r1
ldrb r1, [r0], #1
3: subs r1, r1, #'0'
bge 2b
4: cmp r3, #0
ite eq
moveq r0, r2
rsbne r0, r2, #0
ldmfd sp!, {r1-r4,pc}
@ itoa: int to ASCII
@
@ Abstract use:
@ r0 = itoa(r0, r1)
@ Exit parameters:
@ r0: signed integer
@ r1: buffer adress that is large enough to keep the functions result, @ @ which will be an ASCII string ending in NULL characterla direccion @ @ de un buffer suficientemente grande para mantener el
@ Resultado:
@ r0: buffers adress
itoa:
stmfd sp!, {r1-r7,lr}
mov r7, r1 @ remember buffer address
cmp r0, #0 @ check if negative and if zero
it lt
movlt r2, #'-'
it eq
moveq r2, #'0'
it le
strble r2, [r1],#1 @ store a '-' symbol or a '0' digit
beq 3f
it lt
rsblt r0, r0, #0
ldr r3, =4f @ R3: multiple pointer
movs r6, #0 @ R6: write zero digits? (no, for leading zeros)
1: ldr r4, [r3],#4 @ R4: current power of ten
cmp r4, #1 @ stop when power of ten < 1
blt 3f
movs r5, #0 @ R5: multiples count
2: subs r0, r0, r4 @ subtract multiple from value
itt pl
addpl r5, r5, #1 @ increment the multiples count
bpl 2b
add r0, r0, r4 @ correct overshoot
cmp r5, #0 @ if digit is '0' and ...
itt eq
cmpeq r6, #0 @ if it's a leading zero
beq 1b @ then skip it
movs r6, #1
add r2, r5, #'0' @ ASCII code for the digit
strb r2, [r1],#1 @ store it
b 1b
3: movs r0, #0
strb r0, [r1]
movs r0, r7
ldmfd sp!, {r1-r7,pc}
4: .word 1000000000, 100000000, 10000000, 1000000
.word 100000, 10000, 1000, 100, 10, 1, 0
@ DATOS
.data
.align 4
.type string, %object
string: .space 32 @buffer for a 32 character string
.type number, %object
number: .space 4 @buffer for a number (n y then k) + ending character
.type list, %object
list: .space 4000 @buffer for a 1000 numbers max list (only 999 will be used as true max)
.type found, %object
found: .ascii "NUmber is in the list."
.align 4
.type unfound, %object
unfound: .ascii "Number is not on the list."
.align 4
.type primero, %object
primero: .asciz "Enter array lenght: "
.align 4
.type segundo, %object
segundo: .asciz "Enter next number of the array: "
.align 4
.type tercero, %object
tercero: .asciz "Inverted array is: "
.align 4
.type arreglo, %object
arreglo: .space 100*4
On an x86 desktop PC with Ubuntu or Debian Linux, you can install the cross-assembler, -linker, -debugger and qemu via:
sudo apt-get install binutils-arm-linux-gnueabihf qemu-user gdb-multiarch
And then assemble, link and run it via:
arm-linux-gnueabihf-as -g test.S -o test.o && arm-linux-gnueabihf-ld test.o -o test && qemu-arm ./test
By running with qemu-arm -g 1234 ./test
you can then debug it via GDB:
$ gdb-multiarch ./test
(gdb) target extended-remote :1234
Remote debugging using :1234
_start () at test.S:16
16 ldr r0, =primero
(gdb) stepi
...
On an ARM-based SBC such as Raspberry PI, you can test it by installing binutils
and then:
as -g test.S -o test.o && ld test.o -o test && ./test
Upvotes: 1
Reputation: 105
Thanks to Erlkoeing's input in this issue i was able to finish the program. In the end i was using STR the wrong way. After i changed that and the way I moved across the array plus defining a space for 100 characters in the array like this:
.balign 4
array: .skip 400
i stored the array's adress in a register, then added an offset made by multiplying an index by 4. Thank all of you for your time
Upvotes: 0