I am passing three arrays of doubles from Python (3.6.2) into a DLL written in 64-bit NASM (Windows) using CTypes. The pointers to the arrays are in rcx, rdx, r8 and r9.
On entry, I extract the pointers into three separate arrays, called a_in_data, b_in_data, and c_in_data. The elements of those arrays are (1) pointer (2) data type and (3) length.
In the area preceded by "Test #1" in the code below we check the value at b_in_data[0] and we get a valid pointer (just remove the comment symbols and jump to the end).
In the area preceded by "Test #2" we check the value at b_in_data[0] and we get zero. The array b_in_data[0] has not been changed by this point, but somehow it gets set to back zero.
The same happens in the block following for c_in_data. For some reason, the first code block (headed by "Extract data type and length") zeroes out the first value in b_in_data and c_in_data.
I have identified the line that is causing the problem; it's followed by the comment "THIS LINE IS THE PROBLEM, BUT IT'S NOT CLEAR WHY."
The Python code is long, but if it helps to reproduce this, please ask and I will post it. Here is the NASM code:
; Header Section
[BITS 64]
export TryThemAll
section .data
a_in_data: dd 0, 0, 0
b_in_data: dd 0, 0, 0
c_in_data: dd 0, 0, 0
out_array_pointer: dd 0
call_var_length: dd 0
section .text
finit
; _________________
TryThemAll:
push rdi
push rbp
push qword rcx
pop qword [a_in_data]
push qword rdx
pop qword [b_in_data]
push qword r8
pop qword [c_in_data]
push qword r9
pop qword [out_array_pointer]
; Test #1
; Now the value at b_in_data[0] is the pointer we just extracted from rdx
;mov rbp,b_in_data
;mov rax,qword [rbp]
;jmp out_here
;_______
; Extract data type and length
mov rdi,[out_array_pointer]
mov rbp,a_in_data
movsd xmm0,qword [rdi] ;Data type for a_in
cvttsd2si rax,xmm0
mov [rbp+8],rax ; THIS LINE IS THE PROBLEM, BUT IT'S NOT CLEAR WHY
movsd xmm0,qword [rdi+8] ;Length for a_in
cvttsd2si rax,xmm0
mov [rbp+16],rax
mov rbp,b_in_data
movsd xmm0,qword [rdi+16] ;Data type for b_in
cvttsd2si rax,xmm0
mov [rbp+8],rax
movsd xmm0,qword [rdi+24] ;Length for b_in
cvttsd2si rax,xmm0
mov [rbp+16],rax
; Test #2
; Now the value at [0] in b_in_data is zero !!!
mov rbp,b_in_data
mov rax,qword [rbp]
jmp out_here
mov rbp,c_in_data
movsd xmm0,qword [rdi+32] ;Data type for c_in
cvttsd2si rax,xmm0
mov [rbp+8],rax
movsd xmm0,qword [rdi+40] ;Length for c_in
cvttsd2si rax,xmm0
mov [rbp+16],rax
;_______
out_here:
pop rbp
pop rdi
ret
Thanks in advance for any help.
The solution to this problem was quite simple. The three arrays a_in_data, b_in_data and c_in_data were defined contiguously in the .data section as "dd" but should have been defined as "dq" to occupy eight bytes per element instead of four. Naturally successive writes had the effect of overstoring adjacent values.
I recently switched from 32-bit MASM to 64-bit NASM and I'm still getting used to NASM syntax and 64-bit assembly programming, so I'm still making some elementary mistakes.
Thanks, Peter, for the time you took on this. You made some other interesting points. For example, I've switched to using lea (load effective address) instead of moving the pointer to rbp (e.g., mov rbp,b_in_data).
Thanks again, and thanks to Michael Petch for adding the other tags.
BTW, these data are all converted to 64-bit integers, so the struc is not necessary -- they are not mixed types.