Dear list,

While porting a smalltalk VM to OpenBSD I came across this peculiar
quirk and I don't quite understand what's going on.

This VM does its FFI calls through dlopen'ing and dlsym'ing the
symbols in question. This seems to work fine for all kinds of
functions. However it fails with libc's "environ" symbol.

What happens in the VM boils down to this snippet:

--------------------------------------------------
#include <dlfcn.h>
#include <stdio.h>

int main (int argc, char** argv){
        void* handle;
        void *fn;
        char **e;

        handle = dlopen("libc.so", RTLD_NOW|RTLD_GLOBAL);
        printf("Handle %p\n", handle);

        if (handle == NULL) return -1;

        fn = dlsym(handle, "environ");
        if (fn == NULL) return -1;

        printf("Fn %p\n", fn);

        for (e=(char**)*((char **)fn); *e; e++)
                printf("%s\n", *e);

        return 0;
}
--------------------------------------------------

Surprisingly this works on linux. (Substitute libc.so with
/usr/x86_64-linux-gnu/libc.so.6 madness for linux)

On OpenBSD-current I get a handle for the symbol but it does not
seem to point to a sane place resulting in a segfault.

When running this with LD_DEBUG=1 I see that the loader does resolve
environ:

--------------------------------------------------
LD_DEBUG=1 ./a.out
rtld loading: 'a.out'
exe load offset:  0xc796800000
 flags ./a.out = 0x0
head ./a.out
obj ./a.out has ./a.out as head
examining: './a.out'
loading: libc.so.92.0 required by ./a.out
 flags /usr/lib/libc.so.92.0 = 0x0
obj /usr/lib/libc.so.92.0 has ./a.out as head
linking dep /usr/lib/libc.so.92.0 as child of ./a.out
examining: '/usr/lib/libc.so.92.0'
 flags /usr/libexec/ld.so = 0x0
obj /usr/libexec/ld.so has ./a.out as head
protect start RELRO = 0xc9f48f4f80 in /usr/lib/libc.so.92.0
protect end RELRO = 0xc9f48f7000 in /usr/lib/libc.so.92.0
protect start RELRO = 0xc796a00e28 in ./a.out
protect end RELRO = 0xc796a01000 in ./a.out
        Start            End              Type Open Ref GrpRef Name
        000000c796800000 000000c796a02000 exe  1    0   0      ./a.out
        000000c9f462b000 000000c9f490b000 rlib 0    1   0      
/usr/lib/libc.so.92.0
        000000ca09b00000 000000ca09b00000 rtld 0    1   0      
/usr/libexec/ld.so
symcache lookups 37 hits 0 ratio 0% hits
dynamic loading done, success.
tib new=0xca56f75f80
setting environ 0xca09d14640@/usr/libexec/ld.so[0xca7476d000] from 0xca09d14640
setting __progname 0xca09d14648@/usr/libexec/ld.so[0xca7476d000] from 
0xca09d14648
entry point: 0xc7968003f0
dlopen: loading: libc.so
linking /usr/lib/libc.so.92.0 as dlopen()ed
dlopen: libc.so: done (success).
Handle 0xca1f595800
dlsym: environ in /usr/lib/libc.so.92.0: 0xc9f4902720
Fn 0xc9f4902720
Segmentation fault (core dumped) 
--------------------------------------------------
 
Where does the semantic of dlsym differ from OpenBSD and Linux? Or
is it the loader? What exactly am I getting back from dlsym here?

Can someone enlighten me?

Thanks for reading.

Kind regards,

Christian.

Reply via email to