#8935: Obscure linker bug leads to crash in GHCi -------------------------------------+------------------------------------ Reporter: simonmar | Owner: simonmar Type: bug | Status: patch Priority: high | Milestone: 7.8.3 Component: Runtime System | Version: 7.8.1-rc2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Unknown/Multiple Type of failure: GHCi crash | Difficulty: Rocket Science Test Case: | Blocked By: Blocking: | Related Tickets: -------------------------------------+------------------------------------ Comment (by dagit): After playing with your example a bit I see what you mean about the copy semantics. I found this article: http://netwinder.osuosl.org/users/p/patb/public_html/elf_relocs.html Interestingly, [http://src.gnu-darwin.org/src/libexec/rtld- elf/amd64/reloc.c.html glibc] has these comments: {{{ /* * Process the special R_X86_64_COPY relocations in the main program. These * copy data from a shared object into a region in the main program's BSS * segment. * * Returns 0 on success, -1 on failure. */ int do_copy_relocations(Obj_Entry *dstobj) }}} And: {{{ case R_X86_64_COPY: /* * These are deferred until all other relocations have * been done. All we do here is make sure that the COPY * relocation is not in a shared library. They are allowed * only in executable files. */ }}} The elf interpreter delays processing of the `R_COPY`'s so that it gets the correct behavior. I think this supports your earlier hypothesis. At this point, I noticed that I can switch `environ` in the executable between `R_X86_64_GLOB_DAT` and `R_X86_64_COPY` by adding `-fPIC` (you probably already knew that). Specifically, without `-fPIC` I get copy and with it I get glob dat. Test program again: {{{ #define _GNU_SOURCE #include <dlfcn.h> #include <stdio.h> #include <stdlib.h> extern char**environ; char envname[] = "environ"; void dlsym_check(void *handle, char * lib, char * sym){ void * e = dlsym(handle,sym); fprintf(stderr, "dlsym(\"%s\", \"%s\") = %p\n", lib, sym, e); char * error = dlerror(); if( error != NULL ) fprintf(stderr, "Errors: %s\n", error); } int main(int argc, char *argv[]) { if( argc < 2 ){ printf("usage: ./check-environ <path to shared object>\n"); exit(1); } char* so = argv[1]; void *deflt, *hdl; fprintf(stderr, "environ = %p\n", &environ); deflt = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL); fprintf(stderr, "\nFind a symbol after passing NULL to dlopen:\n"); dlsym_check(deflt, NULL, envname); hdl = dlopen(so, RTLD_LAZY | RTLD_GLOBAL); if( hdl == NULL ){ fprintf(stderr, "Error: %s", dlerror()); exit(1); } fprintf(stderr, "\nFind a symbol that is located here and libc (handle comes from dlopen on %s)\n", so); dlsym_check(hdl, so, envname); } }}} {{{ $ ./check-environ-without-pic /usr/lib64/libgmp.so.10 environ = 0x601070 Find a symbol after passing NULL to dlopen: dlsym("(null)", "environ") = 0x601070 Find a symbol that is located here and libc (handle comes from dlopen on /usr/lib64/libgmp.so.10) dlsym("/usr/lib64/libgmp.so.10", "environ") = 0x31e45bd508 $ ./check-environ-with-pic /usr/lib64/libgmp.so.10 environ = 0x31e45bd508 Find a symbol after passing NULL to dlopen: dlsym("(null)", "environ") = 0x31e45bd508 Find a symbol that is located here and libc (handle comes from dlopen on /usr/lib64/libgmp.so.10) dlsym("/usr/lib64/libgmp.so.10", "environ") = 0x31e45bd508 }}} -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8935#comment:39> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler