【发布时间】:2020-08-23 22:56:00
【问题描述】:
在一个奇怪的事件中,我最终陷入了以下困境,我使用以下 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
【问题讨论】:
-
我能问一下如何你最终需要这样做吗? :D
-
我必须承认,这听起来很危险,而且充满了极端情况。
-
您收到
main not defined错误,因为您需要一个入口点。numba所做的是,它生成asm,然后用ctypes包装它——所以 numba 不需要在那里定义 main。长话短说,没有入口点你的asm是没有用的,除非你用ctypes包装它,或者你做一些事情,比如将它与具有入口点(main) 的C 程序链接。 -
您发布的汇编代码看起来不像一个完整的程序。相反,它看起来像是可以用作程序一部分的单个函数。当您将此代码作为程序执行时,您期望会发生什么?
标签: python assembly linker numba