装配-算术平均-分段错误

Assembly - calculating arithmetic mean - segmentation fault

我应该解决这个问题,我应该使用 CDECL 约定计算 x (6) 个数的算术平均值:

C 中的函数如下所示:float average(const float *array, long N, float (*f)(float), long *error);

section .data
    array dd 1.5,-100.0,30.0,1.0,-1.0,90.0
    array_len dd 6
    error dd -1

section .text
average:
    push ebp
    mov ebp, esp

    ; condition if array is empty
    cmp [ebp+8], dword 0
    je .array_zero

    ; condition if array_len is 0
    cmp [ebp+12], dword 0
    jle .count_zero

    ; condition if passed function is null
    cmp [ebp+16], dword 0
    je .function_zero

    ; preserving registers
    push esi
    push edi

    mov esi, [ebp+8]
    mov ecx, [ebp+12]

    ; define-ing Quiet NaN (used as a error return value)
    QNAN EQU 0x7FFFFFFF
    MASK_IS_NAN EQU 0000_0001_0000_0000b

    ; applying the user-defined function on the numbers
.loop:
    push ecx
    lodsd
    push eax
    call dword [ebp+16] ; the pointer to the function is at this address
    add esp, 4
    pop ecx

    fxam
    fstsw ax
    and ax, 0100_0101_0000_0000b
    cmp ax, MASK_IS_NAN
    je .is_not_a_number

    fstp dword [edi + ecx*4 - 4] ; storing the number in edi register
    loop .loop

    ; calculating the arithmetic average
    mov ecx, [ebp+12]
    fld dword [edi + ecx*4 - 4] 
    dec ecx

.calc:
    fld dword [edi + ecx*4 - 4]
    fadd
    loop .calc

    fild dword [ebp+12]

    fdiv ; the result of the arithmetic average is as defined in CDECL in st0 FPU register
    ; setting error = 0 and exiting
    mov [ebp+20], dword 0
    jmp .exit

.is_not_a_number:
    mov [ebp+20], dword 8
    jmp .error

.array_zero:
    cmp [ebp+12], dword 0
    jle .array_count_zero
    cmp [ebp+16], dword 0
    je .array_function_zero

    mov [ebp+20], dword 1
    jmp .error

.count_zero:
    cmp [ebp+8], dword 0
    je .array_count_zero
    cmp [ebp+16], dword 0
    je .count_function_zero

    mov [ebp+20], dword 2
    jmp .error

.function_zero:
    mov [ebp+20], dword 4
    jmp .error

.array_count_zero:
    cmp [ebp+16], dword 0
    je .all_zero

    mov [ebp+20], dword 3
    jmp .error

.array_function_zero:
    cmp [ebp+12], dword 0
    jle .all_zero

    mov [ebp+20], dword 5
    jmp .error

.count_function_zero:
    cmp [ebp+8], dword 0
    je .all_zero

    mov [ebp+20], dword 6
    jmp .error

.all_zero:
    mov [ebp+20], dword 7
    jmp .error

.error:
    push dword QNAN
    fld dword [esp]
    add esp,4
    jmp .exit

.exit:
    pop edi
    pop esi
    mov esp, ebp
    pop ebp
    ret

fn_example:
    finit
    fld dword [esp+4]
    xor ecx,-1
    xor edx,-1
    xor eax,-1
    ret

CMAIN:
    push ebp
    mov ebp,esp
    sub esp,4

    ; un-mask FPU exceptions
    fstcw [esp]
    and [esp],word 1111_1111_1110_0000b
    fldcw [esp]
    
    push error
    push fn_example
    push dword [array_len]
    push array
    call average
    add esp,16

    mov esp,ebp
    pop ebp
    ret

我在检查结果的托管服务器上遇到分段错误,但在我的本地设备上,它工作正常。

任何想法,为什么会导致段错误?

因此,我发现 EDI 寄存器 (fld dword [edi + ecx*4 - 4]) 导致了段错误,因为它不是 malloc-ed。奇怪的是,在 VSCode 调试器中它工作正常,但 server-sided 编译器对此有问题。

我在代码中添加的内容:

...
mov esi, [ebp+8]
mov ecx, [ebp+12]

; ADDED SNIPET
lea eax, [ecx*4]
push eax
EXTERN malloc
call malloc
add esp, 4
mov edi, eax

mov ecx, [ebp+12]
; ADDED SNIPPET

; define-ing Quiet NaN (used as a error return value)
QNAN EQU 0x7FFFFFFF
...