ОБНОВЛЕНИЕ: я решил эту проблему с помощью ответа Марка Толонена ниже. Вот решение (но я озадачен одной вещью):
Я начинаю со строки кодирования, показанной в ответе Марка Толонена ниже (UTF-8):
CA_f1 = (ctypes.c_char_p * len(f1))(*(name.encode() for name in f1))
При отключенных оптимизациях я всегда сохраняю rcx в переменной памяти при входе. Позже в программе, когда мне нужно использовать указатель в rcx, я читаю его из памяти. Это работает для одного указателя, но не работает для доступа к массиву указателей, который Марк Толонен показал ниже; может быть, это потому, что это массив указателей, а не просто один указатель. Это работает, если я сохраняю rcx в r15 при входе, и вниз по течению в программе это работает так:
;To access the first char of the first name pair:
xor rax,rax
mov rdx,qword[r15]
movsx eax,BYTE[rdx]
ret
;To access the second char of the second name pair:
mov rdx,qword[r15+8]
movsx eax,BYTE[rdx+1]
Это не проблема, потому что я обычно храню как можно больше переменных в регистрах; иногда не хватает регистров, поэтому приходится прибегать к хранению некоторых в памяти. Теперь при обработке строк я всегда буду резервировать r15 для хранения указателя, переданного в rcx, если это массив указателей.
Любое понимание того, почему ячейка памяти не работает?
**** КОНЕЦ ОТВЕТА ****
Я новичок в обработке строк в NASM и передаю строку из ctypes. Строковые данные считываются из текстового файла (Windows .txt), используя следующую функцию Python:
with open(fname, encoding = "utf8") as f1:
for item in f1:
item = item.lstrip()
item = item.rstrip()
return_data.append(item)
return return_data
Файл .txt содержит список имен и фамилий, разделенных символами перевода строки.
Я передаю указатель c_char_p в dll NASM, используя ctypes. Указатель создается с помощью этого:
CA_f1 = (ctypes.c_char_p * len(f1))()
Visual Studio подтверждает, что это указатель на строку байтов длиной 50 ИМЕН, что может быть проблемой, мне нужны байты, а не элементы списка. Затем я передаю его, используя синтаксис ctypes:
CallName.argtypes = [ctypes.POINTER(ctypes.c_char_p),ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_double)]
ОБНОВЛЕНИЕ: перед передачей строки теперь я преобразую список в строку, подобную этой:
f1_x = ' '.join(f1)
Теперь VS показывает указатель на строку длиной 558 байт, что правильно, но я все еще не могу прочитать байт.
В моей программе NASM я проверяю ее, считывая случайный байт в al, используя следующий код:
lea rdi,[rel f1_ptr]
mov rbp,qword [rdi] ; Pointer
xor rax,rax
mov al,byte[rbp+1]
Но возвращаемое значение в rax равно 0.
Если я создаю локальный строковый буфер следующим образом:
name_array: db "Margaret Swanson"
Я могу прочитать это так:
mov rdi,name_array
xor rax,rax
mov al,[rdi]
Но не из указателя, переданного в DLL.
Вот полный код для простого, воспроизводимого примера в NASM. Прежде чем передать его в NASM, я проверил случайные байты, и они - то, что я ожидаю, поэтому я не думаю, что это кодирование.
[BITS 64]
[default rel]
extern malloc, calloc, realloc, free
global Main_Entry_fn
export Main_Entry_fn
global FreeMem_fn
export FreeMem_fn
section .data align=16
f1_ptr: dq 0
f1_length: dq 0
f2_ptr: dq 0
f2_length: dq 0
data_master_ptr: dq 0
section .text
String_Test_fn:
;______
lea rdi,[rel f1_ptr]
mov rbp,qword [rdi]
xor rax,rax
mov al,byte[rbp+10]
ret
;__________
;Free the memory
FreeMem_fn:
sub rsp,40
call free
add rsp,40
ret
; __________
; Main Entry
Main_Entry_fn:
push rdi
push rbp
mov [f1_ptr],rcx
mov [f2_ptr],rdx
mov [data_master_ptr],r8
lea rdi,[data_master_ptr]
mov rbp,[rdi]
xor rcx,rcx
movsd xmm0,qword[rbp+rcx]
cvttsd2si rax,xmm0
mov [f1_length],rax
add rcx,8
movsd xmm0,qword[rbp+rcx]
cvttsd2si rax,xmm0
mov [f2_length],rax
add rcx,8
call String_Test_fn
pop rbp
pop rdi
ret
ОБНОВЛЕНИЕ 2:
В ответ на запрос вот обертка ctypes для использования:
def Read_Data():
Dir= "[FULL PATH TO DATA]"
fname1 = Dir + "Random Names.txt"
fname2 = Dir + "Random Phone Numbers.txt"
f1 = Trans_02_Data.StrDataRead(fname1)
f2 = Trans_02_Data.StrDataRead(fname2)
f2_Int = [ int(numeric_string) for numeric_string in f2]
StringTest_asm(f1, f2_Int)
def StringTest_asm(f1,f2):
f1.append("0")
f1_x = ' '.join(f1)
f1_x[0].encode(encoding='UTF-8',errors='strict')
Input_Length_Array = []
Input_Length_Array.append(len(f1))
Input_Length_Array.append(len(f2*8))
length_array_out = (ctypes.c_double * len(Input_Length_Array))(*Input_Length_Array)
CA_f1 = (ctypes.c_char_p * len(f1_x))() #due to SO research
CA_f2 = (ctypes.c_double * len(f2))(*f2)
hDLL = ctypes.WinDLL("C:/NASM_Test_Projects/StringTest/StringTest.dll")
CallName = hDLL.Main_Entry_fn
CallName.argtypes = [ctypes.POINTER(ctypes.c_char_p),ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_double)]
CallName.restype = ctypes.c_int64
Free_Mem = hDLL.FreeMem_fn
Free_Mem.argtypes = [ctypes.POINTER(ctypes.c_double)]
Free_Mem.restype = ctypes.c_int64
start_time = timeit.default_timer()
ret_ptr = CallName(CA_f1,CA_f2,length_array_out)
abc = 1 #Check the value of the ret_ptr, should be non-zero