assembly 如何记录Python程序执行的CPU指令?

wmvff8tz  于 2023-03-02  发布在  Python
关注(0)|答案(2)|浏览(125)

我知道Python源代码被编译成字节码,然后由Python VM(比如说CPython)解释,如果我理解正确的话,这意味着VM解析字节码指令,并决定(在运行时)应该相应地执行哪些CPU指令。

我的问题:

  • 作为解释特定Python文件(.py)的结果,是否可以记录计算机上执行的实际CPU指令?我知道要获得.py文件和CPU指令之间的1-1对应关系可能并不简单(甚至不可行),但您能获得的最接近的对应关系是什么?
    ***更进一步:**是否可以记录与特定进程对应的已执行指令?
ukqbszuj

ukqbszuj1#

在Linux上使用strace,它会显示任何程序(包括python)所做的每个系统调用。在Windows上,你必须使用类似wtLogger.exe的东西来跟踪所有的库调用(不仅仅是系统调用)。
你可以使用gdb这样的调试器来实时查看机器码,既然你有CPython源代码,一个更好的选择是用调试符号编译它,然后在C调试器中运行它,这可以给予你一个高级调用栈,这将更容易理解。

carvr3hs

carvr3hs2#

以下是我在ARM CPU(macOS 13运行在Apple silicon上)上使用lldb(类似于gdb)到VS Code时,查看CPython的CPU指令的过程:
1.安装CodeLLDB VS代码扩展

  1. git clone https://github.com/python/cpython.git
  2. cd cpython
  3. git checkout 20cf32e761(因为最新的代码可能被破坏)
    1.编译CPython(请参阅README文件或他们如何构建它以进行测试,以了解详细信息),这将生成一个名为“python.exe”的可执行文件:
brew install pkg-config openssl@1.1 xz gdbm tcl-tk

CFLAGS="-I$(brew --prefix gdbm)/include -I$(brew --prefix xz)/include" \
LDFLAGS="-L$(brew --prefix gdbm)/lib -I$(brew --prefix xz)/lib" \
PKG_CONFIG_PATH="$(brew --prefix tcl-tk)/lib/pkgconfig" \
./configure \
  --with-pydebug \
  --with-openssl="$(brew --prefix openssl@1.1)"

make

1.在VS Code(code .)中打开CPython源代码目录,并添加一个. vscode/launch.json文件,该文件包含以下内容(将args设置为要传递给python可执行文件的参数,在本例中我运行的是python -c '30858 + 7',它只让Python添加30858 + 7并退出,而不打印任何内容):

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "launch",
            "name": "Debug",
            "program": "${workspaceFolder}/python.exe",
            // Add two integers
            "args": ["-c", "30858 + 7"],
            "cwd": "${workspaceFolder}"
        }
    ]
}

1.在某处添加一个断点。放置断点的有趣地方是main()函数或求值循环(一个巨大的switch语句that looks at the opcode),它们将位于generated_cases. c. h中(它不在源代码中),或者对于我的30858 + 7示例,_PyLong_Add()是实现加法的。
1.按F5键运行命令
此时,您应该已经命中断点,并且能够看到C代码中的执行位置。要查看当前汇编指令,请按Cmd+Shift+P并执行“LLDB:显示反汇编...”命令并选择“总是”,则可以通过再次运行该命令并选择“自动”返回到C视图。您可以在左上角的“寄存器”下拉菜单下看到寄存器值,在当前变量值的下面。
下面的机器指令将30858(十六进制的788A)相加,存储在寄存器x20中,然后将7存储在寄存器x 0中,最后将结果存储在寄存器x 0中(我对代码做了一些修改,将加法放在单独的一行中,以便更容易地将断点精确地设置在add指令处):

相关问题