GCC将包含程序集的静态库插入到动态库中

时间:2017-03-23 20:15:43

标签: c gcc assembly makefile shared-libraries

我有一个问题:我有2个库(ASM编译的静态NASM和用GCC编译的C动态)。

我首先使用以下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 $@ $<

然后我编译动态库,以便它使用static的函数:

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:符号查找错误:./ libclib.so:未定义符号: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__
静态lib上的

nm:

asm_function.o:
0000000000000000 T asm_function
000000000000001c t _end
0000000000000021 t _finded
0000000000000008 t _loop

2 个答案:

答案 0 :(得分:1)

创建动态库(或一般链接)时,依赖项的顺序很重要。

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文件之后,否则它将被忽略(链接对象必须从大多数依赖对象开始到最少依赖对象)

我将链接器标志放在最后,以便静态库在最后:

$(NAME)             :   $(OBJ)
                        $(CC) -shared -o $(NAMEDYN) $(OBJ) $(LDFLAGS)

解决了符号解析问题,但不解决与位置无关的代码问题。

使用C语言,没有什么比设置-fPIC选项更容易了(实际上,它默认情况下是“现代”编译器,所以不需要打扰),但汇编语言没有那个高级层。如果你加载了一个有效的地址,而你没有使它成为pc相对的,那么你有一个non-relocatable code(一些汇编程序可以使它与某些指令相关,但不包括每条指令)。< / p>

为确保您在装配中生成与位置无关的代码,请修改代码并反汇编,直到您在反汇编中看不到外部重定位。我不是x86专家,但我在68k系列中做了很多。

答案 1 :(得分:1)

这是不正确的:

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 - 标准化缩进样式的主要目的是让人们更容易在不需要“重新训练”的情况下在项目之间切换他们的目光是阅读新代码。当然,您可以继续使用任何风格的作品。使用$@$^也是相当标准的。)