装配-算术平均-分段错误
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
...
我应该解决这个问题,我应该使用 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
...