Какой тип указателя для возврата в NASM из обратного вызова ctypes? - PullRequest
0 голосов
/ 21 мая 2018

Я звоню в NASM 64 dll из ctypes;он включает в себя обратный вызов функции SciPy integrate.dblquad.Обратный вызов получает указатель на массив из двух двойных и возвращает указатель на массив из двух двойных.Функция обратного вызова выполняется правильно и показывает правильные результаты в Python, но у меня возникают проблемы с возвратом указателя обратно в NASM.

Я разместил этот вопрос 12 мая в виде вопроса ctypes на Какой тип указателя верен для обратного вызова ctypes? .Я получил ответ на языке C с решением, которое не могу использовать в NASM.Я надеюсь, что кто-то может помочь с тем, как это может работать в NASM, а не C.

Вот часть кода ctypes, который вызывает dll и выполняет обратный вызов:

CA_data1 = (ctypes.c_double * len(data1))(*data1)
CA_data2 = (ctypes.c_double * len(data2))(*data2)
hDLL = ctypes.WinDLL("C:/NASM_Test_Projects/SciPy_Test/SciPy_Test.dll")
CallName = hDLL.Main_Entry_fn
CallName.argtypes = [ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_longlong)]
CallName.restype = ctypes.c_double

ret_ptr = CallName(CA_data1,CA_data2,length_array_out,lib_call)

Воткод обратного вызова:

from scipy.integrate import dblquad
import ctypes

    def LibraryCall(ptr):
      n = ctypes.cast(ptr,ctypes.POINTER(ctypes.c_double))
      x = n[0]
      y = n[1]
      area = dblquad(lambda x, y: x*y, 0, 0.5, lambda x: 0, lambda x: 1-2*x)
      return_val = area[0], area[1]
      r_val = (ctypes.c_double * len(return_val))(*return_val)
      rv = ctypes.cast(r_val,ctypes.POINTER(ctypes.c_double))
          #All three of these return the same data:
      return (r_val)
      #return (rv)
      #return (return_val)

lib_call = LibraryCB(LibraryCall)
lib_call = ctypes.cast(lib_call,ctypes.POINTER(ctypes.c_longlong))

Я также пытался использовать эти объявления, но нет никакой разницы:

LibraryCB = ctypes.WINFUNCTYPE(None, ctypes.POINTER(ctypes.c_double))

LibraryCB = ctypes.PYFUNCTYPE(None,ctypes.POINTER(ctypes.c_double))

Вот часть кода NASM, которая вызывает обратный вызов и получаетуказатель обратно из обратного вызова в переменной [dblquad_Pointer]):

pop rbp
pop rdi
sub rsp,32
call [scipy.integrate_dblquad_Pointer]
add rsp,32
push rdi
push rbp
mov [dblquad_Pointer],rax

; check the values returned
lea rdi,[rel dblquad_Pointer]
mov rbp,qword [rdi] ; Return Pointer
movsd xmm0,qword[rbp]
ret

Я пробовал три отдельных вызова, чтобы вернуть указатель на dll:

    return (r_val)
    return (rv)
    return (return_val)

Все три из нихвернуть тот же неверный результат из DLL обратно в ctypes.

Предложенное решение, когда я опубликовал это последнее, состояло в том, чтобы изменить код DLL для использования параметра ввода / вывода, например, на C, но я не знаю эквивалента в NASM.

Итак, чтобы подвести итог, мой вопрос, если у меня есть обратный вызов от отправляющих и получающих указатели dll NASM, как мне обработать указатель, возвращенный обратно в dll?

1 Ответ

0 голосов
/ 22 мая 2018

Ответ Марка Толонена, приведенный выше, работает, если я делаю это так, как я показываю здесь.

В типах:

def LibraryCall(ptr):
    x = ptr[0]
    y = ptr[1]
    area = dblquad(lambda x, y: x*y, 0, 0.5, lambda x: 0, lambda x: 1-2*x)
    ptr[0] = area[0] #new
    ptr[1] = area[1] #new
    return (ptr)

Наиболее важной частью является то, что при возврате в DLL я сделал это, чтобы проверить возвращаемые значения:

mov [dblquad_Pointer],rax
lea rdi,[rel dblquad_Pointer]
mov rbp,qword [rdi] ; Return Pointer
movsd xmm0,qword[rbp]

Это неправильно,При входе в функцию обратного вызова я поместил значения в локальный массив callback_data_vals и передал их в функцию обратного вызова:

mov rdi,callback_data_vals
movsd [rdi],xmm0
movsd [rdi+8],xmm1
mov rcx,callback_data_vals
[make the call to the callback]

При возврате возвращенные значения находятся в том же месте (callback_data_vals).Получите к ним доступ следующим образом:

mov rdi,callback_data_vals
movsd xmm0,[rdi]
movsd xmm1,[rdi+8]

Для более длинного массива, который не будет практичным, потому что новые значения должны были бы быть переназначены в цикле в Python, что является медленным.Здесь только с двумя значениями тривиально назначить их указателю возврата.

...