Python ctypes 如何从传递给 NASM 的字符数组中读取一个字节

RTC222

更新:我在下面 Mark Tolonen 的回答的帮助下解决了这个问题。这是解决方案(但我对一件事感到困惑):

我从下面 Mark Tolonen 的回答(UTF-8)中显示的编码字符串开始:

CA_f1 = (ctypes.c_char_p * len(f1))(*(name.encode() for name in f1))

关闭优化后,我总是在入口时将 rcx 存储到内存变量中。后来在程序中当我需要使用rcx中的指针时,我从内存中读取它。这适用于单个指针,但不适用于访问如下所示的指针数组 Mark Tolonen;也许那是因为它是一个指针数组,而不仅仅是一个指针。如果我在进入时将 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 传递一个字符串。使用以下 Python 函数从文本文件 (Windows .txt) 中读取字符串数据:

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 文件包含名字和姓氏的列表,由换行符分隔。

我使用 ctypes 将 c_char_p 指针传递给 NASM dll。指针是用这个创建的:

CA_f1 = (ctypes.c_char_p * len(f1))()

Visual Studio 确认它是一个指向长度为 50 NAMES 的字节字符串的指针,这可能是问题所在,我需要字节,而不是列表元素。然后我使用这个 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   
马克·托洛宁

您的姓名读取代码将返回一个 Unicode 字符串列表。以下代码将 Unicode 字符串列表编码为字符串数组,以传递给采用 的函数POINTER(c_char_p)

>>> import ctypes
>>> names = ['Mark','John','Craig']
>>> ca = (ctypes.c_char_p * len(names))(*(name.encode() for name in names))
>>> ca
<__main__.c_char_p_Array_3 object at 0x000001DB7CF5F6C8>
>>> ca[0]
b'Mark'
>>> ca[1]
b'John'
>>> ca[2]
b'Craig'

如果ca作为第一个参数传递给您的函数,则该数组的地址将在rcx每个x64 调用约定中以下 C 代码及其反汇编显示了 VS2017 Microsoft 编译器如何读取它:

DLL 代码 (test.c)

#define API __declspec(dllexport)

int API func(const char** instr)
{
    return (instr[0][0] << 16) + (instr[1][0] << 8) + instr[2][0];
}

反汇编(编译优化以保持简短,我添加了评论)

; Listing generated by Microsoft (R) Optimizing Compiler Version 19.00.24215.1

include listing.inc

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC  func
; Function compile flags: /Ogtpy
; File c:\test.c
_TEXT   SEGMENT
instr$ = 8
func    PROC

; 5    :     return (instr[0][0] << 16) + (instr[1][0] << 8) + instr[2][0];

  00000 48 8b 51 08      mov     rdx, QWORD PTR [rcx+8]  ; address of 2nd string
  00004 48 8b 01         mov     rax, QWORD PTR [rcx]    ; address of 1st string
  00007 48 8b 49 10      mov     rcx, QWORD PTR [rcx+16] ; address of 3rd string
  0000b 44 0f be 02      movsx   r8d, BYTE PTR [rdx]     ; 1st char of 2nd string, r8d=4a
  0000f 0f be 00         movsx   eax, BYTE PTR [rax]     ; 1st char of 1st string, eax=4d
  00012 0f be 11         movsx   edx, BYTE PTR [rcx]     ; 1st char of 3rd string, edx=43
  00015 c1 e0 08         shl     eax, 8                  ; eax=4d00
  00018 41 03 c0         add     eax, r8d                ; eax=4d4a
  0001b c1 e0 08         shl     eax, 8                  ; eax=4d4a00
  0001e 03 c2            add     eax, edx                ; eax=4d4a43

; 6    : }

  00020 c3               ret     0
func    ENDP
_TEXT   ENDS
END

Python 代码 (test.py)

from ctypes import *

dll = CDLL('test')
dll.func.argtypes = POINTER(c_char_p),
dll.restype = c_int

names = ['Mark','John','Craig']
ca = (c_char_p * len(names))(*(name.encode() for name in names))
print(hex(dll.func(ca)))

输出:

0x4d4a43

这是“M”、“J”和“C”的正确 ASCII 代码。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何一次从python文件中读取一个字符?

来自分类常见问题

如何使用Ctypes将此numpy数组传递给C?

来自分类Dev

如何使用Ctypes将此numpy数组传递给C?

来自分类Dev

如何将C#中的StringBuilder参数传递给python中的ctypes,这不是普通ctypes支持的数据类型

来自分类Dev

将FILE *从Python / ctypes传递给函数

来自分类Dev

如何从Python的字节列表中获取最后一个字节项?

来自分类Dev

Python 3.5 ctypes libc printf()仅打印字符串Windows 7/10的第一个字节

来自分类Dev

Python 3.5 ctypes libc printf()仅打印字符串Windows 7/10的第一个字节

来自分类Dev

如何在 Python 3 中将 '0b11001100' 作为一个字节块而不是字符串读取?

来自分类Dev

Python-如何一次读取一个字符的文件?

来自分类Dev

将python列表传递给使用ctypes返回数组数据的“c”DLL函数

来自分类Dev

使用ctypes将python字符串传递给Fortran子例程

来自分类Dev

如何在python scrapy中删除数组中项目的第一个字符

来自分类Dev

Python3如何从整数列表中创建一个字节对象

来自分类Dev

python-使用ctypes将imgdata指针传递给C中的函数

来自分类Dev

如何让 Python 使用 csv 读取一行中的第一个单词而不是第一个字符?

来自分类Dev

如何在NASM x86_64 Linux Assembly中将字符串中的一个字符与另一个字符进行比较

来自分类Dev

如何在NASM x86_64 Linux Assembly中将字符串中的字符与另一个字符进行比较

来自分类Dev

使用 ctypes 将字节 numpy 数组传递给 C 函数

来自分类Dev

分割一个字符串,并使用python3将第一个参数传递给elif块中的函数

来自分类Dev

python ctypes C++ 在linux上找回缺少最后一个字符的char*

来自分类Dev

Python ctypes无法在结构中传递内存数组

来自分类Dev

如何访问作为numpy数组传递给ctypes回调的数组?

来自分类Dev

python ctypes的数组输出?

来自分类Dev

用ctypes传递数组

来自分类Dev

NASM程序集,如何打印字符串数组的前4个字节

来自分类Dev

如何查找python中单词的下一个字符?

来自分类Dev

如何从python IO流中删除最后一个字符

来自分类Dev

如何解析 Python Pandas String 中的一个字符?

Related 相关文章

  1. 1

    如何一次从python文件中读取一个字符?

  2. 2

    如何使用Ctypes将此numpy数组传递给C?

  3. 3

    如何使用Ctypes将此numpy数组传递给C?

  4. 4

    如何将C#中的StringBuilder参数传递给python中的ctypes,这不是普通ctypes支持的数据类型

  5. 5

    将FILE *从Python / ctypes传递给函数

  6. 6

    如何从Python的字节列表中获取最后一个字节项?

  7. 7

    Python 3.5 ctypes libc printf()仅打印字符串Windows 7/10的第一个字节

  8. 8

    Python 3.5 ctypes libc printf()仅打印字符串Windows 7/10的第一个字节

  9. 9

    如何在 Python 3 中将 '0b11001100' 作为一个字节块而不是字符串读取?

  10. 10

    Python-如何一次读取一个字符的文件?

  11. 11

    将python列表传递给使用ctypes返回数组数据的“c”DLL函数

  12. 12

    使用ctypes将python字符串传递给Fortran子例程

  13. 13

    如何在python scrapy中删除数组中项目的第一个字符

  14. 14

    Python3如何从整数列表中创建一个字节对象

  15. 15

    python-使用ctypes将imgdata指针传递给C中的函数

  16. 16

    如何让 Python 使用 csv 读取一行中的第一个单词而不是第一个字符?

  17. 17

    如何在NASM x86_64 Linux Assembly中将字符串中的一个字符与另一个字符进行比较

  18. 18

    如何在NASM x86_64 Linux Assembly中将字符串中的字符与另一个字符进行比较

  19. 19

    使用 ctypes 将字节 numpy 数组传递给 C 函数

  20. 20

    分割一个字符串,并使用python3将第一个参数传递给elif块中的函数

  21. 21

    python ctypes C++ 在linux上找回缺少最后一个字符的char*

  22. 22

    Python ctypes无法在结构中传递内存数组

  23. 23

    如何访问作为numpy数组传递给ctypes回调的数组?

  24. 24

    python ctypes的数组输出?

  25. 25

    用ctypes传递数组

  26. 26

    NASM程序集,如何打印字符串数组的前4个字节

  27. 27

    如何查找python中单词的下一个字符?

  28. 28

    如何从python IO流中删除最后一个字符

  29. 29

    如何解析 Python Pandas String 中的一个字符?

热门标签

归档