.o 文件中缺少汇编函数
Assembly function is missing in .o file
我需要构建 OpenBLAS
包含汇编函数的静态库 - https://github.com/xianyi/OpenBLAS/releases。就个人而言,我正在尝试构建 0.3.6
版本。
虽然编译过程是成功的,但 .o 文件在汇编函数方面缺少实际实现。
我的所有汇编函数都有问题,但我将举其中之一作为示例 - _sdot_k
。
如何定义缺少实现?我可以通过以下事实来定义它:当我执行 nm [library_name].a
时,此函数的输出如下:
libopenblas_armv8p-r0.3.6.a(sdot_k.o):
0000000000000050 t .Ldot_kernel_F1
0000000000000058 t .Ldot_kernel_F10
0000000000000028 t .Ldot_kernel_F4
000000000000001c t .Ldot_kernel_F_BEGIN
00000000000000d8 t .Ldot_kernel_L999
00000000000000bc t .Ldot_kernel_S1
00000000000000c4 t .Ldot_kernel_S10
0000000000000084 t .Ldot_kernel_S4
0000000000000070 t .Ldot_kernel_S_BEGIN
0000000000000000 t ltmp0
.o
文件中没有 T
标识符表明函数实现在这里。当然,如果我将这个库放入我的 iOS 项目中,我会遇到这样的错误:
Undefined symbols for architecture arm64:
"_sdot_k", referenced from:
_strmv_TLN in libopenblas.a(strmv_TLN.o)
_strmv_TLU in libopenblas.a(strmv_TLU.o)
_strmv_TUN in libopenblas.a(strmv_TUN.o)
_strmv_TUU in libopenblas.a(strmv_TUU.o)
_trmv_kernel in libopenblas.a(strmv_thread_TLN.o)
_trmv_kernel in libopenblas.a(strmv_thread_TLU.o)
_trmv_kernel in libopenblas.a(strmv_thread_TUN.o)
...
这是实际的 dot.S
文件:
#define ASSEMBLER
#include "common.h"
#define N x0 /* vector length */
#define X x1 /* X vector address */
#define INC_X x2 /* X stride */
#define Y x3 /* Y vector address */
#define INC_Y x4 /* Y stride */
#define I x5 /* loop variable */
/*******************************************************************************
* Macro definitions
*******************************************************************************/
#if !defined(DOUBLE)
#if !defined(DSDOT)
#define REG0 wzr
#define DOTF s0
#else // DSDOT
#define REG0 xzr
#define DOTF d0
#endif
#define DOTI s1
#define TMPX s2
#define LD1VX {v2.s}[0]
#define TMPY s3
#define LD1VY {v3.s}[0]
#define TMPVY v3.s[0]
#define SZ 4
#else
#define REG0 xzr
#define DOTF d0
#define DOTI d1
#define TMPX d2
#define LD1VX {v2.d}[0]
#define TMPY d3
#define LD1VY {v3.d}[0]
#define TMPVY v3.d[0]
#define SZ 8
#endif
/******************************************************************************/
.macro KERNEL_F1
ldr TMPX, [X], #SZ
ldr TMPY, [Y], #SZ
#if !defined(DSDOT)
fmadd DOTF, TMPX, TMPY, DOTF
#else // DSDOT
fcvt d3, TMPY
fcvt d2, TMPX
fmul d2, d2, d3
fadd DOTF, DOTF, d2
#endif
.endm
.macro KERNEL_F4
#if !defined(DOUBLE)
ld1 {v2.4s}, [X], #16
ld1 {v3.4s}, [Y], #16
#if !defined(DSDOT)
fmla v0.4s, v2.4s, v3.4s
#else
fcvtl2 v5.2d, v3.4s
fcvtl2 v4.2d, v2.4s
fcvtl v3.2d, v3.2s
fcvtl v2.2d, v2.2s
fmul v4.2d, v4.2d, v5.2d
fmul v2.2d, v2.2d, v3.2d
fadd v2.2d, v2.2d, v4.2d
fadd v0.2d, v0.2d, v2.2d
#endif
#else //DOUBLE
ld1 {v2.2d, v3.2d}, [X], #32
ld1 {v4.2d, v5.2d}, [Y], #32
fmul v2.2d, v2.2d, v4.2d
fmul v3.2d, v3.2d, v5.2d
fadd v0.2d, v0.2d, v2.2d
fadd v0.2d, v0.2d, v3.2d
#endif
PRFM PLDL1KEEP, [X, #1024]
PRFM PLDL1KEEP, [Y, #1024]
.endm
.macro KERNEL_F4_FINALIZE
#if !defined(DOUBLE)
#if !defined(DSDOT)
ext v1.16b, v0.16b, v0.16b, #8
fadd v0.2s, v0.2s, v1.2s
faddp DOTF, v0.2s
#else
faddp DOTF, v0.2d
#endif
#else //DOUBLE
faddp DOTF, v0.2d
#endif
.endm
.macro INIT_S
#if !defined(DOUBLE)
lsl INC_X, INC_X, #2
lsl INC_Y, INC_Y, #2
#else
lsl INC_X, INC_X, #3
lsl INC_Y, INC_Y, #3
#endif
.endm
.macro KERNEL_S1
ld1 LD1VX, [X], INC_X
ld1 LD1VY, [Y], INC_Y
#if !defined(DSDOT)
fmadd DOTF, TMPX, TMPY, DOTF
#else // DSDOT
fcvt d3, TMPY
fcvt d2, TMPX
fmul d2, d2, d3
fadd DOTF, DOTF, d2
#endif
.endm
/*******************************************************************************
* End of macro definitions
*******************************************************************************/
PROLOGUE
fmov DOTF, REG0
#if defined(DOUBLE)
fmov d6, DOTF
#endif
cmp N, xzr
ble .Ldot_kernel_L999
cmp INC_X, #1
bne .Ldot_kernel_S_BEGIN
cmp INC_Y, #1
bne .Ldot_kernel_S_BEGIN
.Ldot_kernel_F_BEGIN:
asr I, N, #2
cmp I, xzr
beq .Ldot_kernel_F1
.Ldot_kernel_F4:
KERNEL_F4
subs I, I, #1
bne .Ldot_kernel_F4
KERNEL_F4_FINALIZE
.Ldot_kernel_F1:
ands I, N, #3
ble .Ldot_kernel_L999
.Ldot_kernel_F10:
KERNEL_F1
subs I, I, #1
bne .Ldot_kernel_F10
ret
.Ldot_kernel_S_BEGIN:
INIT_S
asr I, N, #2
cmp I, xzr
ble .Ldot_kernel_S1
.Ldot_kernel_S4:
KERNEL_S1
KERNEL_S1
KERNEL_S1
KERNEL_S1
subs I, I, #1
bne .Ldot_kernel_S4
.Ldot_kernel_S1:
ands I, N, #3
ble .Ldot_kernel_L999
.Ldot_kernel_S10:
KERNEL_S1
subs I, I, #1
bne .Ldot_kernel_S10
.Ldot_kernel_L999:
ret
EPILOGUE
如你所见,PROLOGUE
和 EPILOGUE
是宏,定义在 C 头文件中:
#ifndef F_INTERFACE
#define REALNAME ASMNAME
#else
#define REALNAME ASMFNAME
#endif
#if defined(ASSEMBLER) && !defined(NEEDPARAM)
#define PROLOGUE \
.text ;\
.align 2 ;\
.globl REALNAME ;\
REALNAME:
#define EPILOGUE
#define PROFCODE
#endif
我的直觉告诉我问题出在 EPILOGUE
和 PROLOGUE
的某处,但我没有足够的汇编程序知识来自己解决问题。
我也找到了这篇文章 - https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/Assembler/040-Assembler_Directives/asm_directives.html,但它对我的帮助不大。可能是因为我组装技术不够
注意: 如果有人正在努力使用同一个库,试图让它在 iOS
上运行,这是我的帖子 Github - https://github.com/xianyi/OpenBLAS/issues/2275#issuecomment-536982253is。它包含我克服的所有问题的描述。
注意 2: 我真的需要 OpenBLAS
库,不幸的是,在我的情况下使用 Accelerate.framework
不是一个选项。
我很高兴地说我克服了这个问题。问题确实出在我的 PROLOGUE
宏中。
PROLOGUE
我使用的宏以这种方式转换为汇编代码:
.text; .align 2; .globl REALNAME; REALNAME:
这是个问题。为了使 Assembly 标签正常工作,它应该如下所示:
.text;
.align 2;
.globl REALNAME;
REALNAME:
//assembly code
因此,为了实现该结果,我将 C
宏更改为 GAS
宏:
.macro PROLOGUE
.text
.align 2
.globl REALNAME
REALNAME:
.endm
之后那个问题就解决了!
注意: 为了消除任何混淆,;
在这里并没有真正发挥作用。重要的是在每个逗号后换行。
我需要构建 OpenBLAS
包含汇编函数的静态库 - https://github.com/xianyi/OpenBLAS/releases。就个人而言,我正在尝试构建 0.3.6
版本。
虽然编译过程是成功的,但 .o 文件在汇编函数方面缺少实际实现。
我的所有汇编函数都有问题,但我将举其中之一作为示例 - _sdot_k
。
如何定义缺少实现?我可以通过以下事实来定义它:当我执行 nm [library_name].a
时,此函数的输出如下:
libopenblas_armv8p-r0.3.6.a(sdot_k.o):
0000000000000050 t .Ldot_kernel_F1
0000000000000058 t .Ldot_kernel_F10
0000000000000028 t .Ldot_kernel_F4
000000000000001c t .Ldot_kernel_F_BEGIN
00000000000000d8 t .Ldot_kernel_L999
00000000000000bc t .Ldot_kernel_S1
00000000000000c4 t .Ldot_kernel_S10
0000000000000084 t .Ldot_kernel_S4
0000000000000070 t .Ldot_kernel_S_BEGIN
0000000000000000 t ltmp0
.o
文件中没有 T
标识符表明函数实现在这里。当然,如果我将这个库放入我的 iOS 项目中,我会遇到这样的错误:
Undefined symbols for architecture arm64:
"_sdot_k", referenced from:
_strmv_TLN in libopenblas.a(strmv_TLN.o)
_strmv_TLU in libopenblas.a(strmv_TLU.o)
_strmv_TUN in libopenblas.a(strmv_TUN.o)
_strmv_TUU in libopenblas.a(strmv_TUU.o)
_trmv_kernel in libopenblas.a(strmv_thread_TLN.o)
_trmv_kernel in libopenblas.a(strmv_thread_TLU.o)
_trmv_kernel in libopenblas.a(strmv_thread_TUN.o)
...
这是实际的 dot.S
文件:
#define ASSEMBLER
#include "common.h"
#define N x0 /* vector length */
#define X x1 /* X vector address */
#define INC_X x2 /* X stride */
#define Y x3 /* Y vector address */
#define INC_Y x4 /* Y stride */
#define I x5 /* loop variable */
/*******************************************************************************
* Macro definitions
*******************************************************************************/
#if !defined(DOUBLE)
#if !defined(DSDOT)
#define REG0 wzr
#define DOTF s0
#else // DSDOT
#define REG0 xzr
#define DOTF d0
#endif
#define DOTI s1
#define TMPX s2
#define LD1VX {v2.s}[0]
#define TMPY s3
#define LD1VY {v3.s}[0]
#define TMPVY v3.s[0]
#define SZ 4
#else
#define REG0 xzr
#define DOTF d0
#define DOTI d1
#define TMPX d2
#define LD1VX {v2.d}[0]
#define TMPY d3
#define LD1VY {v3.d}[0]
#define TMPVY v3.d[0]
#define SZ 8
#endif
/******************************************************************************/
.macro KERNEL_F1
ldr TMPX, [X], #SZ
ldr TMPY, [Y], #SZ
#if !defined(DSDOT)
fmadd DOTF, TMPX, TMPY, DOTF
#else // DSDOT
fcvt d3, TMPY
fcvt d2, TMPX
fmul d2, d2, d3
fadd DOTF, DOTF, d2
#endif
.endm
.macro KERNEL_F4
#if !defined(DOUBLE)
ld1 {v2.4s}, [X], #16
ld1 {v3.4s}, [Y], #16
#if !defined(DSDOT)
fmla v0.4s, v2.4s, v3.4s
#else
fcvtl2 v5.2d, v3.4s
fcvtl2 v4.2d, v2.4s
fcvtl v3.2d, v3.2s
fcvtl v2.2d, v2.2s
fmul v4.2d, v4.2d, v5.2d
fmul v2.2d, v2.2d, v3.2d
fadd v2.2d, v2.2d, v4.2d
fadd v0.2d, v0.2d, v2.2d
#endif
#else //DOUBLE
ld1 {v2.2d, v3.2d}, [X], #32
ld1 {v4.2d, v5.2d}, [Y], #32
fmul v2.2d, v2.2d, v4.2d
fmul v3.2d, v3.2d, v5.2d
fadd v0.2d, v0.2d, v2.2d
fadd v0.2d, v0.2d, v3.2d
#endif
PRFM PLDL1KEEP, [X, #1024]
PRFM PLDL1KEEP, [Y, #1024]
.endm
.macro KERNEL_F4_FINALIZE
#if !defined(DOUBLE)
#if !defined(DSDOT)
ext v1.16b, v0.16b, v0.16b, #8
fadd v0.2s, v0.2s, v1.2s
faddp DOTF, v0.2s
#else
faddp DOTF, v0.2d
#endif
#else //DOUBLE
faddp DOTF, v0.2d
#endif
.endm
.macro INIT_S
#if !defined(DOUBLE)
lsl INC_X, INC_X, #2
lsl INC_Y, INC_Y, #2
#else
lsl INC_X, INC_X, #3
lsl INC_Y, INC_Y, #3
#endif
.endm
.macro KERNEL_S1
ld1 LD1VX, [X], INC_X
ld1 LD1VY, [Y], INC_Y
#if !defined(DSDOT)
fmadd DOTF, TMPX, TMPY, DOTF
#else // DSDOT
fcvt d3, TMPY
fcvt d2, TMPX
fmul d2, d2, d3
fadd DOTF, DOTF, d2
#endif
.endm
/*******************************************************************************
* End of macro definitions
*******************************************************************************/
PROLOGUE
fmov DOTF, REG0
#if defined(DOUBLE)
fmov d6, DOTF
#endif
cmp N, xzr
ble .Ldot_kernel_L999
cmp INC_X, #1
bne .Ldot_kernel_S_BEGIN
cmp INC_Y, #1
bne .Ldot_kernel_S_BEGIN
.Ldot_kernel_F_BEGIN:
asr I, N, #2
cmp I, xzr
beq .Ldot_kernel_F1
.Ldot_kernel_F4:
KERNEL_F4
subs I, I, #1
bne .Ldot_kernel_F4
KERNEL_F4_FINALIZE
.Ldot_kernel_F1:
ands I, N, #3
ble .Ldot_kernel_L999
.Ldot_kernel_F10:
KERNEL_F1
subs I, I, #1
bne .Ldot_kernel_F10
ret
.Ldot_kernel_S_BEGIN:
INIT_S
asr I, N, #2
cmp I, xzr
ble .Ldot_kernel_S1
.Ldot_kernel_S4:
KERNEL_S1
KERNEL_S1
KERNEL_S1
KERNEL_S1
subs I, I, #1
bne .Ldot_kernel_S4
.Ldot_kernel_S1:
ands I, N, #3
ble .Ldot_kernel_L999
.Ldot_kernel_S10:
KERNEL_S1
subs I, I, #1
bne .Ldot_kernel_S10
.Ldot_kernel_L999:
ret
EPILOGUE
如你所见,PROLOGUE
和 EPILOGUE
是宏,定义在 C 头文件中:
#ifndef F_INTERFACE
#define REALNAME ASMNAME
#else
#define REALNAME ASMFNAME
#endif
#if defined(ASSEMBLER) && !defined(NEEDPARAM)
#define PROLOGUE \
.text ;\
.align 2 ;\
.globl REALNAME ;\
REALNAME:
#define EPILOGUE
#define PROFCODE
#endif
我的直觉告诉我问题出在 EPILOGUE
和 PROLOGUE
的某处,但我没有足够的汇编程序知识来自己解决问题。
我也找到了这篇文章 - https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/Assembler/040-Assembler_Directives/asm_directives.html,但它对我的帮助不大。可能是因为我组装技术不够
注意: 如果有人正在努力使用同一个库,试图让它在 iOS
上运行,这是我的帖子 Github - https://github.com/xianyi/OpenBLAS/issues/2275#issuecomment-536982253is。它包含我克服的所有问题的描述。
注意 2: 我真的需要 OpenBLAS
库,不幸的是,在我的情况下使用 Accelerate.framework
不是一个选项。
我很高兴地说我克服了这个问题。问题确实出在我的 PROLOGUE
宏中。
PROLOGUE
我使用的宏以这种方式转换为汇编代码:
.text; .align 2; .globl REALNAME; REALNAME:
这是个问题。为了使 Assembly 标签正常工作,它应该如下所示:
.text;
.align 2;
.globl REALNAME;
REALNAME:
//assembly code
因此,为了实现该结果,我将 C
宏更改为 GAS
宏:
.macro PROLOGUE
.text
.align 2
.globl REALNAME
REALNAME:
.endm
之后那个问题就解决了!
注意: 为了消除任何混淆,;
在这里并没有真正发挥作用。重要的是在每个逗号后换行。