Reputation: 379
I have a problem: I have 2 libraries (a static in ASM compiled with NASM and a dynamics in C compiled with GCC).
I compile first the one in ASM with the following Makefile (I removed parts to make it more readable) :
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 $@ $<
Then I compile the dynamic library so that it uses the functions of the 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)
I have no problem, everything compiles perfectly but when I test the code with the following .c (with 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);
[...]
}
I get this error :
./a.out: symbol lookup error: ./libclib.so: undefined symbol: asm_function
nm on the dynamic lib :
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 on the static lib :
asm_function.o:
0000000000000000 T asm_function
000000000000001c t _end
0000000000000021 t _finded
0000000000000008 t _loop
Upvotes: 2
Views: 2262
Reputation: 140286
When creating your dynamic library (or linking in general), order of dependencies is important.
Part of your makefile:
$(NAME) : $(OBJ)
$(CC) $(LDFLAGS) -shared -o $(NAMEDYN) $(OBJ)
the build line expands (roughly) to:
gcc -L./libs/ASM -lasmlib -shared -o libdyn.so obj1.o obj2.o
Problem is, asm_function
is defined in the .a
file, but used in one of the .o
files. You have to put the .a
file after the .o
file or it will be ignored (link objects have to start from most depending objects to least depending objects)
I'd put the linker flags in the end so the static library is at the end:
$(NAME) : $(OBJ)
$(CC) -shared -o $(NAMEDYN) $(OBJ) $(LDFLAGS)
That solves the symbol resolution problem, but not the position-independent code problem.
With C language, nothing easier than setting -fPIC
option (actually, it's by default on "modern" compilers, so no need to bother), but assembly language doesn't have that high-level layer. If you load an effective address, and you don't make it pc-relative, you have a non-relocatable code (some assemblers can make it pc-relative for some instructions, but that doesn't cover every instruction).
To be sure that you're producing position independent code in assembly, modify your code and disassemble it until you see no external relocs in the disassembly. I'm not a x86 expert but I've done that a lot with the 68k family.
Upvotes: 2
Reputation: 213748
This is incorrect:
LDFLAGS = -L./libs/ASM -lasmlib
$(NAME) : $(OBJ)
$(CC) $(LDFLAGS) -shared -o $(NAMEDYN) $(OBJ)
The order is important. Ordinarily, -L
and -l
parameters should not be part of LDFLAGS
(linker flags) but part of LIBS
(libraries), which appear in the command line in the following order:
# 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)
The reason why the order is important is because the linker will only resolve symbols in libraries that are defined later in the command-line arguments than where they are referenced. So all your -l
flags should ordinarily come after all your .o
files. This rule does not affect .o
files, which can be in any order.
This also doesn't apply to all linkers.
(As a minor note, I found it difficult to read the makefile due to its peculiar indentation style—the main purpose of standardized indentation styles is to make it easier for people to switch between projects without having to "re-train" their eyes to read the new code. You are, of course, free to continue using whatever style works. The use of $@
and $^
is also fairly standard.)
Upvotes: 1