Assembly 带post索引偏移量的STR后arm程序停止

Assembly 带post索引偏移量的STR后arm程序停止,assembly,arm,undefined-behavior,Assembly,Arm,Undefined Behavior,我正在完成一个任务,在这个任务中,我需要通过输入接收一个数组,并以相反的方式返回它。我以前问过关于这项作业的问题,这次我快要完成了。我现在的问题是,当我在内存中存储数组的一个值时,我的程序会中途停止。 编辑:我现在粘贴了完整的代码。失败的str与它的崩溃高度相关。对于这个假设,我得到的代码没有主代码,也没有变量primero、segundo和tercero,它们是程序运行时要打印的字符串。打印和FGET是打印到屏幕并从标准DIN读取的功能 @ Las siguientes funciones f

我正在完成一个任务,在这个任务中,我需要通过输入接收一个数组,并以相反的方式返回它。我以前问过关于这项作业的问题,这次我快要完成了。我现在的问题是,当我在内存中存储数组的一个值时,我的程序会中途停止。 编辑:我现在粘贴了完整的代码。失败的str与它的崩溃高度相关。对于这个假设,我得到的代码没有主代码,也没有变量primero、segundo和tercero,它们是程序运行时要打印的字符串。打印和FGET是打印到屏幕并从标准DIN读取的功能

@ 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 recived 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 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)

@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 recived 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 adress to ASCII string ending in null
@ Resultado:
@    N/A, but string is writen 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 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).
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 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)
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 adress 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 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
        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 lenght: "
segundo: .asciz "Enter next number of the array: "
tercero: .asciz "Inverted array is: "
arreglo: .word 0, 0, 0                  


多亏了厄尔科林在这一期中的投入,我才能够完成这个项目。最后我用错了STR。在我改变了这一点以及我在数组中移动的方式,并在数组中定义了一个100个字符的空格,如下所示:

.balign 4
array: .skip 400
我将数组的地址存储在一个寄存器中,然后通过将索引乘以4来添加偏移量。
感谢大家抽出时间

只是为了好玩,我将程序转换为使用Linux系统调用:

.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
然后通过以下方式进行组装、连接和运行:

armlinux-gnueabihf-as-g test.S-o test.o&&armlinux-gnueabihf-ld test.o-o test&&qemu-arm./test
通过使用
qemu arm-g 1234./test运行,您可以通过GDB调试它:

$gdb多拱。/test
(gdb)目标扩展远程:1234
使用:1234进行远程调试
_从测试开始()。S:16
16 ldr r0,=primero
(gdb)stepi
...
在基于ARM的SBC(如Raspberry PI)上,您可以通过安装
binutils
对其进行测试,然后:

as -g test.S -o test.o && ld test.o -o test && ./test

什么是
打印
primero
adr_num
arreglo
。。。?请出示整个节目。任何地方都没有
push{lr}
,因此您不能从
main
返回,这是故意的吗?由于您显然正在使用C库,因此只需从
main
返回(
bx-lr
),而无需调用
exit
。此外,对于
fgets
,您不能在
r2
中通过
0
;您必须加载
stdin
变量的地址(可能是
ldr r2,=stdin
)。
lr
的处理应该在她/他调用
beq exit
时起作用。给出数据声明和代码会很有帮助。如果我们被告知哪个
str
失败了,这将非常有帮助。寄存器是无效内存,您得到了SIGSEGV或类似的东西
itoa()
通常需要三个参数。如果
arreglo
在.text段中,它将在
str
上崩溃。请详细说明问题,并说明到目前为止为调试所做的工作this@old_timer我添加了完整的程序并解释了一些事情。感谢您的输入。您介意将注释和变量名翻译成英语吗?ARM具有缩放索引寻址模式(左移);如果你是这个意思的话,你不需要单独乘法。
as -g test.S -o test.o && ld test.o -o test && ./test