尝试加倍数组时在程序集中出现分段错误

问题描述 投票:0回答:1

我已经尝试解决这个问题 5 个小时了。我试图得到它,以便在将 5 个元素输入数组后,数组加倍并将旧元素复制到新元素中并继续直到你停止然后它输出统计信息,出于某种原因在输入 5 个数字后我只是得到分段错误


 %define ARRAY_SIZE  5
   %define ELEMENT_SIZE 4
   %define EOF -1
   
segment .data
   inputPrompt: db "Enter int value (ctrl-d to stop): ",0
   intFormat:   db "%d",0
   output:      db "Array[%d] = %d",10,0
   dbout:       db 10, 10,"[%d]",10,10,0 ; This is just for debugging output
   newline:     db 10,0                  ; For whenever we need a newline
   numElements: db "Number of elements: %d",10,0
   outputSum:   db "sum of elements: %d",10,0
   minValue:    db "Min value: %d",10,0
   maxValue:    db "Max value: %d",10,0

segment .bss
   arrayPtr:  resq 1                     ; pointer to our array
   intInput:  resd 1

segment .text
   global asm_main
   extern printf, scanf, calloc
   
createNewArray:
   mov   rdi, [arrayPtr]
   mov   rsi, ARRAY_SIZE
   add   rsi, rsi            ; Double the array size
   mov   rdx, ELEMENT_SIZE
   call  calloc
   mov   rbx, [arrayPtr]     ; Move the old array elements to the new array
   mov   rcx, ARRAY_SIZE
   cld
   rep   movsd
   mov   [arrayPtr], rax     ; Save the new array pointer
   ret  
   
asm_main:
   enter 0,0

   ;; Get memory for our array
   ;; Give calloc() number of element and element size
   ;; and calloc returns a pointer to zerioized memory
   mov   rdi, ARRAY_SIZE
   mov   rsi, ELEMENT_SIZE
   call  calloc
   mov   [arrayPtr], rax
   
   mov   rdi, [arrayPtr]        ; Will use RDI and stosd to write the array
   mov   rcx, ARRAY_SIZE
   mov   r15, 0                 ; R15 counts how many elements in our array
   cld
inputLoop:
   push  rcx                    ; Save RCX and RDI across printf/scanf calls
   push  rdi
   mov   rdi, inputPrompt
   call  printf

   mov   rdi, intFormat
   mov   rsi, intInput
   call  scanf

   cmp   eax, EOF               ; Did scanf() return -1 (didn't read anything?)
   je    inputDone
   inc   r15                    ; O/w count another element & store it
   
   cmp   r15, ARRAY_SIZE        ; Check if we've filled up the current array
   jl    arrayNotFull           ; O/w, create a new array
   call  createNewArray
   mov   rdi, [arrayPtr]        ; Update the pointers and sizes
   mov   rcx, r15
   
arrayNotFull:
   
   xor   rax, rax               ; Clear out RAX for stosd to write array to mem
   mov   eax, [intInput]
   pop   rdi                    ; Restore RDI for stosd
   stosd
   pop   rcx                    ; Restore RCS for loop instruction
   loop  inputLoop
   
inputDone:                      ; Let's get ready to print
   mov   rdi, newline
   call  printf
   mov   rsi, [arrayPtr]        ; Will use RSI and lodsd to read the array
   mov   rcx, r15               ; Store actual array size to RCX
   mov   rbx, 0
   cld
printLoop:
   xor   rax, rax
   xor   rdx, rdx
   lodsd
   push  rcx                    ; Save RCX and RSI across printf call
   push  rsi
   mov   rdi, output
   mov   rsi, rbx

   movsx rdx, eax
   call  printf
   inc   rbx

   pop   rsi                    ; Restore RCX and RSI
   pop   rcx
   loop  printLoop
   je    printStats
   
printStats:
   mov   rdi, newline
   call  printf
   mov   rdi, numElements
   mov   rsi, r15
   call  printf
   
   mov   rax, 0         ; Initialize the sum to zero
   mov   rsi, [arrayPtr] ; Get the address of the array
   mov   rcx, r15        ; Store actual array size to RCX
   cld
   
   xor   rdx, rdx       ; Clear out RDX for the first add instruction
   
   mov   rax, 0           ; Initialize the sum to zero
   mov   rsi, [arrayPtr]  ; Get the address of the array
   mov   rcx, r15         ; Store actual array size to RCX
   cld
sumLoop:
   lodsd                  ; Load the next element of the array into EAX
   add   rax, r8          ; Add the current sum to EAX
   mov   r8, rax          ; Store the updated sum in R8
   loop  sumLoop
   mov   rdi, outputSum
   mov   rsi, r8
   call  printf
   
 ; Find the minimum value in the array
   mov   rax, [arrayPtr]     ; Load the base address of the array into RAX
   mov   ebx, [rax]          ; Load the first element of the array into EBX
   mov   rcx, r15            ; Loop counter will be the number of elements
   dec   rcx                 ; Decrement RCX since we've already loaded the first element
   mov   rsi, [rax]          ; Initialize RSI to the first element
loopStart:
   add   rax, ELEMENT_SIZE   ; Move the pointer to the next element
   cmp   [rax], ebx          ; Compare the value at the current pointer to the minimum value
   jge   loopEnd             ; If the value is greater than or equal to the minimum, skip to the end of the loop
   mov   ebx, [rax]          ; Otherwise, update the minimum value
   mov   rsi, rax            ; and store the address of the minimum value in RSI
loopEnd:
   loop  loopStart           ; Repeat for the remaining elements of the array
   mov   rdi, minValue
   mov   rsi, rbx
   call  printf

; Find the maximum value in the array
   mov   rax, [arrayPtr]     ; Load the base address of the array into RAX
   mov   ebx, [rax]          ; Load the first element of the array into EBX
   mov   rcx, r15            ; Loop counter will be the number of elements
   dec   rcx                 ; Decrement RCX since we've already loaded the first element
   mov   rsi, [rax]          ; Initialize RSI to the first element
loopStartd:
   add   rax, ELEMENT_SIZE   ; Move the pointer to the next element
   cmp   [rax], ebx          ; Compare the value at the current pointer to the maximum value
   jle   loopEndd             ; If the value is less than or equal to the maximum, skip to the end of the loop
   mov   ebx, [rax]          ; O/w, update the maximum value to the current value
   mov   rsi, rax            ; Store the address of the current maximum value
loopEndd:
   loop  loopStartd
   mov   rdi, maxValue
   mov   rsi, rbx
   call  printf

   mov   rax, 0
   leave 
   ret

我试图保存新的数组指针 [arrayPtr],rax 但它似乎没有做任何事情或者我做错了什么,任何帮助都会很棒。

arrays assembly segmentation-fault x86-64
1个回答
0
投票

calloc 是如何工作的?寄存器的使用方式不一致。

第一次(在main)你像这样使用它:

mov   rdi, ARRAY_SIZE
mov   rsi, ELEMENT_SIZE
call  calloc   ; -> RAX

但是第二次(在 createNewArray 中)你像这样使用它:

mov   rdi, [arrayPtr]
mov   rsi, ARRAY_SIZE
add   rsi, rsi            ; Double the array size
mov   rdx, ELEMENT_SIZE
call  calloc   ; -> RAX

接下来的

rep movsd
既没有给出合适的RSI也没有RDI。 segmentation fault的原因...

mov   rbx, [arrayPtr]     ; Move the old array elements to the new array
mov   rcx, ARRAY_SIZE
cld
rep   movsd
mov   [arrayPtr], rax     ; Save the new array pointer

inputLoop中,您甚至在将第五个数组元素存储在第一个数组中之前就调用了createNewArray。这是您上述

rep movsd
无法正常运行的另一个原因。
难道你不应该等到 inputDone 才想创建第二个数组吗?


也许是一个想法

如果你知道你无论如何都要复制数组,为什么不在 main 中分配两倍的内存,然后同时存储到两个数组:

mov   eax, [intInput]
pop   rdi                                   ; Restore RDI for stosd
mov   [rdi + ELEMENT_SIZE * ARRAYSIZE], eax ; Store in 2nd array
stosd                                       ; Store in 1st array
© www.soinside.com 2019 - 2024. All rights reserved.