the solution is to be relative to got
and add yet another level of indirection. Thanks to Matthew Flatt.
dvanhorn@starburst:small $ nasm -f elf64 call_f.s -o call_f.o
dvanhorn@starburst:small $ gcc static.c f.c call_f.o -o static
dvanhorn@starburst:small $ gcc -ldl dynamic.c -o dynamic
dvanhorn@starburst:small $ gcc -shared f.c call_f.o -o f.so
dvanhorn@starburst:small $ ./static frog
42
dvanhorn@starburst:small $ ./static duck
42
dvanhorn@starburst:small $ ./dynamic frog
42
dvanhorn@starburst:small $ ./dynamic duck
42