在一个奇怪的转折中,我陷入了下面的困境,我使用下面的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
1条答案
按热度按时间qoefvg9y1#
在浏览了[PyData.Numba]: Numba * doc * s之后,经过一些调试、试错,我得出了一个结论:看起来你偏离了你的追求之路(评论中也指出了)。
@numba.jit
([PyData.Numba]:即时编译)。您遇到的行为是正确的。* Dispatcher * 对象(修饰 * six * 函数使用)只生成函数本身的(汇编)代码(这里没有 * main ,因为代码是在当前进程中执行的( Python * 解释器的 * main * 函数))。链接器抱怨没有 * main * 符号是很正常的,就像写一个 * C * 文件,里面只包含:
为了使设备正常工作,您必须:
1.将 *. asm * 文件构建为 *. o *(对象)文件(完成)
库将链接到(最终)可执行文件中。此步骤是可选的,因为您可以直接使用 *. o * 文件
作为一种替代方法,您可以查看[PyData.Numba]:提前编译代码,但请记住,这将生成一个 * Python *(扩展)模块。
回到当前问题。在 * Ubuntu 18.04 064bit * 上进行测试。
同时发布(因为它很重要)* numba_six_linux_064_030705.asm *:
1.* numba_six_linux_064_030705.asm (以及从它派生的所有内容)包含 * six * 函数的代码。实际上,有一堆符号(在 * OSX * 上,您还可以使用原生的
otool -T
),如:1.cfunc._ZN8__main__7six$241E-( C )函数本身
1. _ZN7cpython8__main__7six$241E - Python * Package 器:
2.1.执行 * C 〈=〉 Python * 转换(通过 * Python API * 函数,如 * PyArg_UnpackTuple )
2.2.由于 #1. ,它需要(取决于) libpython3.7m *
2.3.因此,
nopython=True
在这种情况下不起作用此外,这些符号中的 * main * 部分并不引用可执行文件入口点( main * 函数),而是引用Python * 模块的顶级名称空间(main)。
我没有尝试过,但我认为对生成的 *. asm * 文件进行以下(手动)更改会简化工作,这是有意义的:
更新 *#0 *
感谢@PeterCordes,他分享了我错过的确切信息([GNU.GCC]: Controlling Names Used in Assembler Code),这里有一个简单得多的版本。