我的问题基于this reddit帖子。那里的示例显示了如何使用cast
模块中的ctypes
函数更改内存中的整数:
>>> import ctypes
>>> ctypes.cast(id(29), ctypes.POINTER(ctypes.c_long))[3] = 100
>>> 29
100
我对这里的底层内部结构感兴趣,并且我已经通过在cast
中的CPython
函数上设置断点在GDB会话中对此进行了检查:
(gdb) break cast
Function "cast" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (cast) pending.
(gdb) run test.py
Starting program: /root/.pyenv/versions/3.8.0-debug/bin/python test.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
0x7ffff00e7b40
Breakpoint 1, cast (ptr=0x9e6e40 <small_ints+1088>, src=10382912, ctype=<_ctypes.PyCPointerType at remote 0xa812a0>) at /root/.pyenv/sources/3.8.0-debug/Python-3.8.0/Modules/_ctypes/_ctypes.c:5540
5540 if (0 == cast_check_pointertype(ctype))
(gdb) p *(PyLongObject *) ptr
$38 = {
ob_base = {
ob_base = {
ob_refcnt = 12,
ob_type = 0x9b8060 <PyLong_Type>
},
ob_size = 1
},
ob_digit = {100}
}
(gdb) p *((long *) ptr + 3)
$39 = 100
(gdb) p ((long *) ptr + 3)
$40 = (long *) 0x9e6e58 <small_ints+1112>
(gdb) p *((char *) ptr + 3 * 8)
$41 = 100 'd'
(gdb) p ((char *) ptr + 3 * 8)
$42 = 0x9e6e58 <small_ints+1112> "d"
(gdb) set *((long *) ptr + 3) = 29
(gdb) p *((long *) ptr + 3)
$46 = 29
(gdb) p *((char *) ptr + 3 * 8)
$47 = 29 '\035'
我想知道是否可以在GDB会话中使用Python获取内存地址,因为我无法访问返回的地址:
(gdb) python print("{:#x}".format(ctypes.addressof(ctypes.c_int(29))))
0x7f1053c947f0
(gdb) python print("{:#x}".format(id(29)))
0x22699d8
(gdb) p *0x7f1053c947f0
Cannot access memory at address 0x7f1053c947f0
(gdb) p *0x22699d8
Cannot access memory at address 0x22699d8
索引也不同于Python REPL,我想这与字节序有关?
(gdb) python print(ctypes.cast(id(29), ctypes.POINTER(ctypes.c_long))[3])
9
(gdb) python print (ctypes.cast(id(29), ctypes.POINTER(ctypes.c_long))[2])
29
问题:
info proc mappings
)中?src
CPython
函数中的cast
参数保存对象的地址,但似乎是ptr
,并且在memcpy result->b_ptr
指向与&ptr
不同的值?这是实际的铸造吗?(gdb) python
>import ctypes
>print(ctypes.cast(id(29), ctypes.POINTER(ctypes.c_long))[3])
>end
29
我无法想到这种行为会发生的任何原因(最少字节序,在整个系统中都是相同的*)src
参数似乎被用作原始类型,而不是原始对象。供参考,请参见ctypes.h和ctypes/__init__.py(_ SimpleCData只是CDataObject,具有一些诸如索引和repr之类的帮助器)**在ARM上除外,您可以在其中使用指令更改字节序