GCC 将包含程序集的静态库插入到动态库中
GCC insert a static library containing assembly into a dynamic lib
我有一个问题:我有 2 个库(一个在 ASM 中用 NASM 编译的静态库和一个在 C 中用 GCC 编译的动态库)。
我首先使用以下 Makefile 编译 ASM 中的那个(我删除了部分以使其更具可读性):
ASM = nasm
NAME = libasmlib.a
SRC = [...all .asm files...]
OBJ = $(SRC:.asm=.o)
FLAGS = -f elf64 -g
all : $(NAME)
$(NAME) : $(OBJ)
ar rc $(NAME) $(OBJ)
ranlib $(NAME)
%.o : %.asm
$(ASM) $(FLAGS) -o $@ $<
然后我编译动态库,让它使用静态的函数:
CC = gcc
NAMEDYN = libclib.so
SRC = [...all .c files...]
OBJ = $(SRC:%.c=%.o)
CFLAGS = -W -Wall -Werror -pedantic -fPIC
LDFLAGS = -L./libs/ASM -lasmlib
$(NAME) : $(OBJ)
$(CC) $(LDFLAGS) -shared -o $(NAMEDYN) $(OBJ)
all : $(NAME)
我没问题,一切都可以完美编译,但是当我使用以下 .c 测试代码时(使用 gcc maindyn.c -ldl) :
#include <stdio.h>
#include <dlfcn.h>
int main(int ac, char **av)
{
int res;
void *handle;
int (*c_function)(char *str);
if (!(handle = dlopen("./libclib.so", RTLD_LAZY | RTLD_GLOBAL | RTLD_NOW)))
return 1;
c_function = dlsym(handle, "c_function");
res = c_function("Hi!");
printf("%d\n", res);
[...]
}
我收到这个错误:
./a.out: symbol lookup error: ./libclib.so: undefined symbol: asm_function
nm 在动态库上:
U asm_function
0000000000202078 B __bss_start
0000000000202078 b completed.7558
<snip>
0000000000000ee0 T c_function
0000000000000e20 t register_tm_clones
U __stack_chk_fail@@GLIBC_2.4
0000000000202078 d __TMC_END__
nm 在静态库上:
asm_function.o:
0000000000000000 T asm_function
000000000000001c t _end
0000000000000021 t _finded
0000000000000008 t _loop
在创建动态库(或通常 linking)时,依赖关系的顺序 很重要。
您的 makefile 的一部分:
$(NAME) : $(OBJ)
$(CC) $(LDFLAGS) -shared -o $(NAMEDYN) $(OBJ)
构建线扩展(大致)为:
gcc -L./libs/ASM -lasmlib -shared -o libdyn.so obj1.o obj2.o
问题是,asm_function
在 .a
文件中定义,但在 .o
文件之一中使用。您必须将 .a
文件 放在 文件 .o
之后,否则它将被忽略(link 对象必须从最依赖的对象开始到最不依赖的对象依赖对象)
我会把 linker 标志放在最后,所以静态库在最后:
$(NAME) : $(OBJ)
$(CC) -shared -o $(NAMEDYN) $(OBJ) $(LDFLAGS)
这解决了符号解析问题,但没有解决与位置无关的代码问题。
对于C语言,没有什么比设置-fPIC
选项更容易的了(实际上,"modern"编译器默认是这样,所以不用费心),但是汇编语言没有那么高水平层。如果你加载一个有效地址,但你没有让它成为 pc-relative,你有一个 (一些汇编器可以为某些指令让它成为 pc-relative,但这并不涵盖每条指令)。
为确保您在汇编中生成与位置无关的代码,请修改您的代码并将其反汇编,直到您在反汇编中看不到外部重定位。我不是 x86 专家,但我在 68k 系列上做了很多。
这是不正确的:
LDFLAGS = -L./libs/ASM -lasmlib
$(NAME) : $(OBJ)
$(CC) $(LDFLAGS) -shared -o $(NAMEDYN) $(OBJ)
顺序很重要。通常,-L
和 -l
参数不应是 LDFLAGS
(链接器标志)的一部分,而是 LIBS
(库)的一部分,它们按以下顺序出现在命令行中:
# No interesting LDFLAGS now, but maybe you want --gc-sections or --as-needed
LDFLAGS =
# Libraries go here
LIBS = -L./libs/ASM -lasmlib
libclib.so: $(OBJ)
$(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS)
顺序之所以重要,是因为链接器只会解析在命令行参数之后定义的库中的符号,而不是在它们被引用的地方。因此,您所有的 -l
标志通常都应位于所有 .o
文件之后。此规则不影响 .o
个文件,这些文件可以按任何顺序排列。
这也不适用于所有链接器。
(作为一个小提示,我发现由于其特殊的缩进样式而难以阅读 makefile — 标准化缩进样式的主要目的是使人们更容易在项目之间切换而不必 "re-train" 他们的眼睛阅读新代码。当然,您可以自由地继续使用任何有效的样式。$@
和 $^
的使用也是相当标准的。)
我有一个问题:我有 2 个库(一个在 ASM 中用 NASM 编译的静态库和一个在 C 中用 GCC 编译的动态库)。
我首先使用以下 Makefile 编译 ASM 中的那个(我删除了部分以使其更具可读性):
ASM = nasm
NAME = libasmlib.a
SRC = [...all .asm files...]
OBJ = $(SRC:.asm=.o)
FLAGS = -f elf64 -g
all : $(NAME)
$(NAME) : $(OBJ)
ar rc $(NAME) $(OBJ)
ranlib $(NAME)
%.o : %.asm
$(ASM) $(FLAGS) -o $@ $<
然后我编译动态库,让它使用静态的函数:
CC = gcc
NAMEDYN = libclib.so
SRC = [...all .c files...]
OBJ = $(SRC:%.c=%.o)
CFLAGS = -W -Wall -Werror -pedantic -fPIC
LDFLAGS = -L./libs/ASM -lasmlib
$(NAME) : $(OBJ)
$(CC) $(LDFLAGS) -shared -o $(NAMEDYN) $(OBJ)
all : $(NAME)
我没问题,一切都可以完美编译,但是当我使用以下 .c 测试代码时(使用 gcc maindyn.c -ldl) :
#include <stdio.h>
#include <dlfcn.h>
int main(int ac, char **av)
{
int res;
void *handle;
int (*c_function)(char *str);
if (!(handle = dlopen("./libclib.so", RTLD_LAZY | RTLD_GLOBAL | RTLD_NOW)))
return 1;
c_function = dlsym(handle, "c_function");
res = c_function("Hi!");
printf("%d\n", res);
[...]
}
我收到这个错误:
./a.out: symbol lookup error: ./libclib.so: undefined symbol: asm_function
nm 在动态库上:
U asm_function
0000000000202078 B __bss_start
0000000000202078 b completed.7558
<snip>
0000000000000ee0 T c_function
0000000000000e20 t register_tm_clones
U __stack_chk_fail@@GLIBC_2.4
0000000000202078 d __TMC_END__
nm 在静态库上:
asm_function.o:
0000000000000000 T asm_function
000000000000001c t _end
0000000000000021 t _finded
0000000000000008 t _loop
在创建动态库(或通常 linking)时,依赖关系的顺序 很重要。
您的 makefile 的一部分:
$(NAME) : $(OBJ)
$(CC) $(LDFLAGS) -shared -o $(NAMEDYN) $(OBJ)
构建线扩展(大致)为:
gcc -L./libs/ASM -lasmlib -shared -o libdyn.so obj1.o obj2.o
问题是,asm_function
在 .a
文件中定义,但在 .o
文件之一中使用。您必须将 .a
文件 放在 文件 .o
之后,否则它将被忽略(link 对象必须从最依赖的对象开始到最不依赖的对象依赖对象)
我会把 linker 标志放在最后,所以静态库在最后:
$(NAME) : $(OBJ)
$(CC) -shared -o $(NAMEDYN) $(OBJ) $(LDFLAGS)
这解决了符号解析问题,但没有解决与位置无关的代码问题。
对于C语言,没有什么比设置-fPIC
选项更容易的了(实际上,"modern"编译器默认是这样,所以不用费心),但是汇编语言没有那么高水平层。如果你加载一个有效地址,但你没有让它成为 pc-relative,你有一个
为确保您在汇编中生成与位置无关的代码,请修改您的代码并将其反汇编,直到您在反汇编中看不到外部重定位。我不是 x86 专家,但我在 68k 系列上做了很多。
这是不正确的:
LDFLAGS = -L./libs/ASM -lasmlib
$(NAME) : $(OBJ)
$(CC) $(LDFLAGS) -shared -o $(NAMEDYN) $(OBJ)
顺序很重要。通常,-L
和 -l
参数不应是 LDFLAGS
(链接器标志)的一部分,而是 LIBS
(库)的一部分,它们按以下顺序出现在命令行中:
# No interesting LDFLAGS now, but maybe you want --gc-sections or --as-needed
LDFLAGS =
# Libraries go here
LIBS = -L./libs/ASM -lasmlib
libclib.so: $(OBJ)
$(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS)
顺序之所以重要,是因为链接器只会解析在命令行参数之后定义的库中的符号,而不是在它们被引用的地方。因此,您所有的 -l
标志通常都应位于所有 .o
文件之后。此规则不影响 .o
个文件,这些文件可以按任何顺序排列。
这也不适用于所有链接器。
(作为一个小提示,我发现由于其特殊的缩进样式而难以阅读 makefile — 标准化缩进样式的主要目的是使人们更容易在项目之间切换而不必 "re-train" 他们的眼睛阅读新代码。当然,您可以自由地继续使用任何有效的样式。$@
和 $^
的使用也是相当标准的。)