This is with 5.5 release on i386 (32 bit). When main program has more than one function pointer declared with the *same names* as functions in a shared library, and initializes one (at least) with the symbol from that library with dlsym(), and references the second in some way (take address, dereference/call. etc.), and the shared library calls the second function, then the program segfaults at the point of the lib making that call, but after ld.so has printed messages like: "WARNING: symbol(fn_02) size mismatch, relink your program" apparently one for each reference to that symbol in either the main program or library.
This is reliably repeatable, and is probably easier to understand in code than in my description, so a near-minimal program and Makefile are appended to this message. For the test prog try: # bug % make clean; make # workaround 1 -- initialize symbol in main prog % make clean; make fix # workaround 2 -- do not reference symbol in prog % make clean; make fix2 # still bug, different output (FPIC defaults empty) % make clean; make FPIC="-fPIC" I'm sure this was not a problem with OpenBSD 4.9 because the code that raised the issue was fine on that. -Ed FILES: /** BEGIN dltst.c */ #include <stdio.h> #ifdef BUILDPROG #ifdef LOADRUNTIME #include <dlfcn.h> void (*fn_01)(); #if FIXHACK == 1 void (*fn_02)() = 0; #else void (*fn_02)(); #endif void loadsyms() { /* * RTLD_LAZY reorders "size mismatch, relink your program" * message and backtrace is different, but segfaults IAC */ void* handle = dlopen(DLTST_SONAME, RTLD_NOW); fn_01 = dlsym(handle, "fn_01"); /* a reference to fn_02 (here and main()) will trigger bug */ #if FIXHACK != 2 fn_02 = dlsym(handle, "fn_02"); #endif } #else /* LOADRUNTIME */ void fn_01(); void fn_02(); void loadsyms() { } #endif /* LOADRUNTIME */ int main() { loadsyms(); /* look at addresses *of* and *in* pointers */ printf("From main prog; fn_01 at %p points to %p\n", &fn_01, fn_01); #if FIXHACK != 2 printf("From main prog; fn_02 at %p points to %p\n", &fn_02, fn_02); #endif /* call 1st func only; it calls the 2nd within so */ fn_01(); return 0; } #else /* BUILDPROG */ /* this section compiles for shared lib */ void fn_02() { void (*p)() = fn_02; /* look at this func address */ printf("From shared lib; %s at %p\n", __FUNCTION__, p); } void fn_01() { void (*p)() = fn_01; /* look at this func address */ printf("From shared lib; %s at %p\n", __FUNCTION__, p); p = fn_02; /* look at *2nd* func address; before segfault */ printf("From shared lib; %s -- fn_02 is at %p\n", __FUNCTION__, p); fn_02(); } #endif /* BUILDPROG */ /** END dltst.c */ ## BEGIN Makefile NAME = dltst SONAME = lib$(NAME) SRC = $(NAME).c SOSRC = so_$(NAME).c PROG = $(NAME)_lt PROGRT = $(NAME)_rt SO = $(SONAME).so # not for OpenBSD, but others use -ldl #LIBS = -ldl LIBS = # pic difference? yes, but still gets message and segfault #FPIC = -fPIC FPIC = # default: build and run program w/ runtime loading that will segfault all: run_rt # 1st run prog w/o runtime loading (no core), then as above both check compare: run_lt run_rt # workaround: initialize (assign 0) pertinent global symbol: no segfault fix: rm -f $(PROGRT) make CFLAGS="$(CFLAGS) -DFIXHACK=1" run_rt # workaround: declare but do not reference pertinent global symbol: no segfault fix2: rm -f $(PROGRT) make CFLAGS="$(CFLAGS) -DFIXHACK=2" run_rt run_rt: $(PROGRT) @echo === running $(PROGRT) -- runtime load LD_LIBRARY_PATH=$$PWD ./$(PROGRT) run_lt: $(PROG) @echo === running $(PROG) -- implicit link LD_LIBRARY_PATH=$$PWD ./$(PROG) $(SO) mk_so: $(SOSRC) $(CC) $(CFLAGS) -shared $(FPIC) -o $(SO) $(SOSRC) $(PROG) mk_prog_lt: $(SRC) $(SO) $(CC) $(CFLAGS) -DBUILDPROG -o $(PROG) $(SRC) $(LIBS) -L$$PWD -l$(NAME) # make program using runtime loading $(PROGRT) mk_prog_rt: $(SRC) $(SO) $(CC) $(CFLAGS) -DBUILDPROG -DLOADRUNTIME -DDLTST_SONAME=\"$(SO)\" -o $(PROGRT) $(SRC) $(LIBS) # copy source to new name for so; this is for clarity in gdb $(SOSRC): $(SRC) @rm -f $@; cp -p $(SRC) $@ clean: rm -f $(PROG) $(PROGRT) $(SO) $(SOSRC) *.core core ## END Makefile