在一个奇怪的情况下,我陷入了以下困境,我使用以下Python代码将Numba生成的程序集写入文件:
@jit(nopython=True, nogil=True)
def six():
return 6
with open("six.asm", "w") as f:
for k, v in six.inspect_asm().items():
f.write(v)
汇编代码已成功写入该文件,但我不知道如何执行它。我尝试了以下方法:
$ as -o six.o six.asm
$ ld six.o -o six.bin
$ chmod +x six.bin
$ ./six.bin
但是,链接步骤失败,原因如下:
ld: warning: cannot find entry symbol _start; defaulting to 00000000004000f0
six.o: In function `cpython::__main__::six$241':
<string>:(.text+0x20): undefined reference to `PyArg_UnpackTuple'
<string>:(.text+0x47): undefined reference to `PyEval_SaveThread'
<string>:(.text+0x53): undefined reference to `PyEval_RestoreThread'
<string>:(.text+0x62): undefined reference to `PyLong_FromLongLong'
<string>:(.text+0x74): undefined reference to `PyExc_RuntimeError'
<string>:(.text+0x88): undefined reference to `PyErr_SetString'
我怀疑Numba和/或Python标准库需要与生成的对象文件进行动态链接才能成功运行,但我不确定该如何实现(如果一开始就可以实现的话)
我还尝试了以下方法,将中间LLVM代码写入文件而不是程序集:
with open("six.ll", "w") as f:
for k, v in six.inspect_llvm().items():
f.write(v)
然后
$ lli six.ll
但这也会失败,并出现以下错误:
'main' function not found in module.
更新:
事实证明,存在一个实用程序来查找要传递给ld
命令的相关标志,以动态链接Python标准库
$ python3-config --ldflags
返回
-L/Users/rayan/anaconda3/lib/python3.7/config-3.7m-darwin -lpython3.7m -ldl -framework CoreFoundation
再次运行以下命令,这次使用正确的标志:
$ as -o six.o six.asm
$ ld six.o -o six.bin -L/Users/rayan/anaconda3/lib/python3.7/config-3.7m-darwin -lpython3.7m -ldl -framework CoreFoundation
$ chmod +x six.bin
$ ./six.bin
我现在越来越紧张了
ld: warning: No version-min specified on command line
ld: entry point (_main) undefined. for inferred architecture x86_64
我曾尝试在程序集文件中添加_main
标签,但似乎没有任何效果。关于如何定义入口点有什么想法吗
更新2:
下面是有用的汇编代码,目标函数似乎是带有标签_ZN8__main__7six$241E
的函数:
.text
.file "<string>"
.globl _ZN8__main__7six$241E
.p2align 4, 0x90
.type _ZN8__main__7six$241E,@function
_ZN8__main__7six$241E:
movq $6, (%rdi)
xorl %eax, %eax
retq
.Lfunc_end0:
.size _ZN8__main__7six$241E, .Lfunc_end0-_ZN8__main__7six$241E
.globl _ZN7cpython8__main__7six$241E
.p2align 4, 0x90
.type _ZN7cpython8__main__7six$241E,@function
_ZN7cpython8__main__7six$241E:
.cfi_startproc
pushq %rax
.cfi_def_cfa_offset 16
movq %rsi, %rdi
movabsq $.const.six, %rsi
movabsq $PyArg_UnpackTuple, %r8
xorl %edx, %edx
xorl %ecx, %ecx
xorl %eax, %eax
callq *%r8
testl %eax, %eax
je .LBB1_3
movabsq $_ZN08NumbaEnv8__main__7six$241E, %rax
cmpq $0, (%rax)
je .LBB1_2
movabsq $PyEval_SaveThread, %rax
callq *%rax
movabsq $PyEval_RestoreThread, %rcx
movq %rax, %rdi
callq *%rcx
movabsq $PyLong_FromLongLong, %rax
movl $6, %edi
popq %rcx
.cfi_def_cfa_offset 8
jmpq *%rax
.LBB1_2:
.cfi_def_cfa_offset 16
movabsq $PyExc_RuntimeError, %rdi
movabsq $".const.missing Environment", %rsi
movabsq $PyErr_SetString, %rax
callq *%rax
.LBB1_3:
xorl %eax, %eax
popq %rcx
.cfi_def_cfa_offset 8
retq
.Lfunc_end1:
.size _ZN7cpython8__main__7six$241E, .Lfunc_end1-_ZN7cpython8__main__7six$241E
.cfi_endproc
.globl cfunc._ZN8__main__7six$241E
.p2align 4, 0x90
.type cfunc._ZN8__main__7six$241E,@function
cfunc._ZN8__main__7six$241E:
movl $6, %eax
retq
.Lfunc_end2:
.size cfunc._ZN8__main__7six$241E, .Lfunc_end2-cfunc._ZN8__main__7six$241E
.type _ZN08NumbaEnv8__main__7six$241E,@object
.comm _ZN08NumbaEnv8__main__7six$241E,8,8
.type .const.six,@object
.section .rodata,"a",@progbits
.const.six:
.asciz "six"
.size .const.six, 4
.type ".const.missing Environment",@object
.p2align 4
.const.missing Environment:
.asciz "missing Environment"
.size ".const.missing Environment", 20
.section ".note.GNU-stack","",@progbits
在浏览了[PyData.Numba]: Numbadocs,以及一些调试、尝试和错误之后,我得出了一个结论:看来你已经偏离了追求的道路(评论中也指出了这一点)
Numba将Python代码(函数)转换为机器代码(原因很明显:速度)。它可以在运行过程中执行所有操作(转换、构建、插入),程序员只需将函数修饰为,例如
@numba.jit
([PyData.Numba]: Just-in-Time compilation)你所经历的行为是正确的。Dispatcher对象(用于修饰six函数)只为函数本身生成(汇编)代码(它不在那里,因为代码在当前进程中执行(Python解释器的main函数))。因此,链接器抱怨没有main符号是正常的。这就像编写一个只包含以下内容的C文件:
为了使事情正常运行,您必须:
将.asm文件构建到.o(对象)文件中(完成)
包括#1中的.o文件进入一个可以
该库将链接到(最终)可执行文件中。此步骤是可选的,因为您可以直接使用.o文件
将另一个定义main的文件(并调用six——我认为这就是全部目的)构建到一个.o文件中。因为我对汇编不是很熟悉,所以我在C
将两个实体(从#2.(#1.)和#3.)链接在一起
作为替代方案,您可以查看[PyData.Numba]: Compiling code ahead of time,但请记住,它将生成一个Python(扩展)模块
回到当前的问题。在Ubuntu 18.04 64位上进行了测试
code00.py:
main00.c:
build.sh:
输出:
同时发布(因为它很重要)numba\u six\u linux\u 064\u 030705.asm:
注释:
numba_six_linux_064_030705.asm(以及由此派生的所有内容)包含函数的代码。实际上,有一组符号(在OSX上,您也可以使用本机
otool -T
),如:cfunc.\u ZN8\u main\u 7six$241E-(C)函数本身
\u ZN7cpython8\u main\u 7six$241E-Python包装器:
nopython=True
在这种情况下没有效果此外,这些符号中的main部分并不是指一个可执行的入口点(main函数),而是指一个Python模块的顶级名称空间(\uu main\uu)。毕竟,这段代码应该是从Python
由于C普通函数的名称中包含一个点(),我无法直接从C调用它(因为它是一个无效的标识符名称),所以我必须手动加载.so和该函数(dlopen/dlsym),产生了比简单调用函数更多的代码
我没有尝试,但我认为对生成的.asm文件进行以下(手动)更改可以简化工作:
更新#0
感谢@PeterCordes,他分享了我丢失的那条信息([GNU.GCC]: Controlling Names Used in Assembler Code),这里有一个更简单的版本
main01.c:
输出:
相关问题 更多 >
编程相关推荐