Skip to content
Snippets Groups Projects
Select Git revision
  • ab727af49fd068cd97c3bf5ce4f6e55f23f9b34f
  • master default protected
  • 9.0
  • 8.0
  • 7.8
  • 7.6
  • 7.4
  • 7.2
  • 7.0
  • 0.6
  • rosuav/latex-markdown-renderer
  • rxnpatch/rxnpatch
  • marcus/gobject-introspection
  • rxnpatch/8.0
  • rosuav/pre-listening-ports
  • nt-tools
  • rosuav/async-annotations
  • rosuav/pgsql-ssl
  • rxnpatch/rxnpatch-broken/2023-10-06T094250
  • grubba/fdlib
  • grubba/wip/sakura/8.0
  • v8.0.2000
  • v8.0.1998
  • v8.0.1996
  • v8.0.1994
  • v8.0.1992
  • v8.0.1990
  • v8.0.1988
  • v8.0.1986
  • rxnpatch/clusters/8.0/2025-04-29T124414
  • rxnpatch/2025-04-29T124414
  • v8.0.1984
  • v8.0.1982
  • v8.0.1980
  • v8.0.1978
  • v8.0.1976
  • v8.0.1974
  • v8.0.1972
  • v8.0.1970
  • v8.0.1968
  • v8.0.1966
41 results

dlopen.c

Blame
  • dlopen.c 65.14 KiB
    /*
    || This file is part of Pike. For copyright information see COPYRIGHT.
    || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
    || for more information.
    || $Id: dlopen.c,v 1.76 2006/07/05 19:06:46 mast Exp $
    */
    
    /* Note: This is not used if --enable-dll is. */
    
    #include <global.h>
    #include "fdlib.h"
    #define DL_INTERNAL
    #include "pike_dlfcn.h"
    #include "pike_memory.h"
    #include "pike_error.h"
    #include "pike_macros.h"
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
    /* FreeBSD and OpenBSD has <malloc.h>, but it just contains a warning... */
    #include <malloc.h>
    #endif /* !__FreeBSD__ && !__OpenBSD__ */
    #include <windows.h>
    #include <memory.h>
    #include <sys/stat.h>
    #include <assert.h>
    #include <math.h>
    #include <tchar.h>
    #include <interpret.h>
    #include <callback.h>
    
    /* In case we're compiling with NDEBUG */
    _CRTIMP void __cdecl _assert(void*, void*, unsigned);
    
    #ifdef DEBUG_MALLOC
    #define ACCEPT_MEMORY_LEAK(X) dmalloc_accept_leak(X)
    #else
    #define ACCEPT_MEMORY_LEAK(X)
    #endif
    
    static char *dlerr=0;
    
    
    /* Todo:
     *  Make image debugable if possible
     *  Separate RWX, RW and R memory sections.
     */
    
    #ifdef _WIN64
    #define USE_PDB_SYMBOLS
    #endif
    
    /* Enable debug output if compiled on win64. */
    #ifdef _WIN64
    #define DLDEBUG 1
    #endif /* _WIN64 */
    
    /* #define DL_VERBOSE 1 */
    /* #define DLDEBUG */
    
    /*
     * This define makes dlopen create a logfile which maps
     * addresses to symbols. This can be very helpful when
     * debugging since regular debug info does not work with
     * code loaded by dlopen.
     */
    /* #define DL_SYMBOL_LOG */
    
    
    /*
     * This puts unused memory after each writable data section
     * In the future, this padded memory will be filled with
     * a pattern that can be verified as not being changed later.
     * This is for debug only of course
     */
    #define PAD_DATA 0
    
    
    /*
     * If you enable this, calls to
     * fopen, fseek etc. from dynamic modules will be dumped to
     * stderr (only fopen and fseek implemented so far, see below)
     */
    /* #define DL_WRAP_STDIO */
    
    /*
     * If EFENCE_BOTTOM is defined, each writable symbol will have it's
     * own data page and be located at the end of that page with a guard
     * page right afterwards.
     */
    /* #define EFENCE_BOTTOM */
    
    /*
     * If EFENCE_TOP is defined, each writable symbol will have it's
     * own data page and be located at the beginning of that page with a guard
     * page right afterwards.
     */
    /* #define EFENCE_TOP */
    
    #define REALLY_FLUSH() /* do{ fflush(stderr); Sleep(500); }while(0) */
    
    #ifdef DLDEBUG
    #define FLUSH() REALLY_FLUSH()
    #define DO_IF_DLDEBUG(X) X
    #else
    #define FLUSH()
    #define DO_IF_DLDEBUG(X)
    #endif
    
    #ifdef DL_SYMBOL_LOG
    FILE *dl_symlog;
    #endif
    
    /* Windows/IA64 does not prepend symbols with "_". */
    #ifdef _WIN64
    #define SYMBOL_PREFIX	""
    #else /* !_WIN64 */
    #define SYMBOL_PREFIX	"_"
    #endif /* _WIN64 */
    
    
    #if defined(EFENCE_BOTTOM) || defined(EFENCE_TOP)
    #define EFENCE
    DWORD dlopen_page_size;
    
    #define EFENCE_ADD(X) 				\
      X+=dlopen_page_size*2-1;			\
      X&=-dlopen_page_size;
    
    static char *EFENCE_ALIGN(char *x, int size, int align)
    {
      if(!VirtualAlloc(x,size,MEM_COMMIT,PAGE_EXECUTE_READWRITE) && size)
      {
        fprintf(stderr,"dlopen:EFENCE ALIGN failed to allocate %d bytes at %p\n",size,x);
      }
      
      if(!VirtualAlloc(x + ( (size + dlopen_page_size -1) & -dlopen_page_size),
    		   dlopen_page_size,MEM_COMMIT,PAGE_NOACCESS))
      {
        fprintf(stderr,"dlopen:EFENCE ALIGN failed to protect a page!\n");
      }
      
    
    #ifdef EFENCE_BOTTOM
      {
        char *ret=x + ( ((dlopen_page_size - (size & (dlopen_page_size-1))) & ~align));
    #ifdef DLDEBUG
         fprintf(stderr,"ALIGN: %p@%x/%x -> %p\n",x,size,align,ret);
    #endif
        return ret;
      }
    	    
    #else
      return x;
    #endif
    }
    
    
    #else /* EFENCE */
    #define EFENCE_ADD(X)
    #define EFENCE_ALIGN(X,SIZE,AL) X
    #define EFENCE_PROT_PREV_PAGE(X)
    #endif
    
    #ifndef PAD_DATA
    #define PAD_DATA 0
    #endif
    
    #ifndef PIKE_CONCAT
    
    #include <io.h>
    #include <fcntl.h>
    
    #define INT8 char
    #define INT16 short
    #define INT32 int
    #define ptrdiff_t long
    #define STRTOL strtol
    
    #define RTLD_GLOBAL 1
    #define RTLD_LAZY 0 /* never */
    #define RTLD_NOW 0 /* always */
    
    #define fd_open open
    #define fd_close close
    #define fd_read read
    #define fd_RDONLY O_RDONLY
    #define fd_BINARY O_BINARY
    
    long hashmem(char *mem, ptrdiff_t size)
    {
      long ret=size * 9278234247;
      while(--size>=0) ret+=(ret<<4) + *(mem++);
      return ret;
    }
    
    size_t STRNLEN(char *s, size_t maxlen)
    {
      char *tmp=memchr(s,0,maxlen);
      if(tmp) return tmp-s;
      return maxlen;
    }
    
    #else /* PIKE_CONCAT */
    
    #endif
    
    /****************************************************************/
    
    struct Sym
    {
      struct Sym *next;
      void *sym;
      size_t len;
      char name[1];
    };
    
    struct Htable
    {
      size_t size; /* size of hash table */
      size_t entries;
      struct Sym *symbols[1];
    };
    
    static struct Htable *alloc_htable(size_t size)
    {
      int e;
      struct Htable *ret;
      if(size<1) size=1;
    #ifdef DLDEBUG
      fprintf(stderr,"alloc_htable(%d)\n",size);
      FLUSH();
    #endif
      ret=(struct Htable *)malloc(sizeof(struct Htable) +
    			      sizeof(void *)*(size-1));
      ACCEPT_MEMORY_LEAK(ret);
      ret->size=size;
      ret->entries=0;
      for(e=0;e<size;e++) ret->symbols[e]=0;
      return ret;
    }
    
    static struct Htable *htable_add_space(struct Htable *h,
    				       size_t extra_space)
    {
    #if 1
      if(h->entries+extra_space > h->size)
      {
        struct Htable *ret;
        size_t i, new_size = (h->size * 2)+1;
        if(h->entries+extra_space > new_size)
          new_size = (h->entries+extra_space) | 0x10101;
        /** rehashto new_size */
        ret = alloc_htable(new_size);
        for(i=0; i<h->size; i++) {
          struct Sym *next, *curr = h->symbols[i];
          while(curr) {
    	size_t hval;
    	DO_HASHMEM(hval, curr->name, curr->len, 128);
    	hval %= new_size;
    	next = curr->next;
    	curr->next = ret->symbols[hval];
    	ret->symbols[hval] = curr;
    	curr = next;
          }
        }
        ret->entries = h->entries;
        free(h);
        h = ret;
      }
    #endif
      return h;
    }
    
    
    static struct Sym *htable_get_low(struct Htable *h,
    				  char *name,
    				  size_t len,
    				  size_t hval)
    {
      struct Sym *tmp;
    
    #ifdef DLDEBUG
      if(name[len])
        fprintf(stderr,"htable_get_low(%c%c%c%c%c%c%c%c) len=%d hval=%x/%x\n",
    	    name[0],
    	    name[1],
    	    name[2],
    	    name[3],
    	    name[4],
    	    name[5],
    	    name[6],
    	    name[7],
    	    len,
    	    hval,h->size);
      else
        fprintf(stderr,"htable_get_low(%s) len=%d hval=%x/%x\n",name,len,
    	    hval,h->size);
    #endif
    
      for(tmp=h->symbols[hval];tmp;tmp=tmp->next)
      {
        
    /* fprintf(stderr,"Looking %s/%d =? %s/%d\n",name,len, tmp->name,tmp->len); */
        if(tmp->len == len && !memcmp(name, tmp->name, len))
        {
    #ifdef DLDEBUG
          fprintf(stderr, "  ==> Found at 0x%08p\n", tmp);
    #endif
          return tmp;
        }
      }
    #ifdef DLDEBUG
      fprintf(stderr, "Not found.\n");
    #endif
      return 0;
    }
    
    static void *htable_get(struct Htable *h, char *name, size_t l)
    {
      struct Sym * tmp;
      size_t hval;
      DO_HASHMEM(hval, name, l, 128);
    
      if((tmp=htable_get_low(h, name, l, hval % h->size)))
        return tmp->sym;
      return 0;
    }
    
    static void htable_put(struct Htable *h, char *name, size_t l, void *ptr,
    		       int replace)
    {
      struct Sym *tmp;
    
      size_t hval;
      DO_HASHMEM(hval, name, l, 128);
      hval %= h->size;
    
    #ifdef DLDEBUG
      if(name[l])
      {
        fprintf(stderr,"DL: htable_put(%c%c%c%c%c%c%c%c,%p)\n",
    	    name[0],
    	    name[1],
    	    name[2],
    	    name[3],
    	    name[4],
    	    name[5],
    	    name[6],
    	    name[7],
    	    ptr);
      }else{
        fprintf(stderr,"DL: htable_put(%s,%p)\n",name,ptr);
      }
    #endif
    
      /* FIXME: Should duplicate symbols be overloaded or what? */
      if((tmp=htable_get_low(h, name, l, hval)))
      {
        if(replace)
          tmp->sym=ptr;
        return;
      }
      tmp=(struct Sym *)malloc(sizeof(struct Sym) + l);
      if(!tmp)
      {
        /* out of memory */
        exit(1);
      }
      ACCEPT_MEMORY_LEAK(tmp);
      memcpy(tmp->name, name, l);
      tmp->name[l]=0;
      tmp->len=l;
      tmp->next=h->symbols[hval];
      tmp->sym=ptr;
      h->symbols[hval]=tmp;
      h->entries++;
    #ifdef DLDEBUG
      if (tmp != htable_get_low(h, name, l, hval)) {
        fprintf(stderr, "DL: Failed to put!\n");
      }
    #endif
    }
    
    static void htable_free(struct Htable *h, void(*hfree)(void *))
    {
      size_t hval;
      struct Sym *tmp,*next;
      if(hfree)
      {
        for(hval=0; hval<h->size; hval++)
        {
          for(next=h->symbols[hval];tmp=next;)
          {
    	next=tmp->next;
    	hfree(tmp->sym);
    	free((char *)tmp);
          }
        }
      }else{
        for(hval=0; hval<h->size; hval++)
        {
          for(next=h->symbols[hval];tmp=next;)
          {
    	next=tmp->next;
    	free((char *)tmp);
          }
        }
      }
      free((char *)h);
    }
    
    /****************************************************************/
    
    static int filesize(const char *filename)
    {
      struct stat st;
    #ifdef DLDEBUG
      fprintf(stderr,"filesize(%s)\n",filename);
    #endif
      if(stat(filename, &st)<0) return -1;
      return st.st_size;
    }
    
    static char *read_file(const char *name, size_t *len)
    {
      ptrdiff_t tmp;
      char *buffer;
      int fd;
      int l=filesize(name);
      if(l<0) return 0;
    
      len[0]=(size_t)l;
      do{
    #ifdef DLDEBUG
      fprintf(stderr,"Opening file: %s\n",name);
    #endif
        fd=fd_open(name,fd_RDONLY | fd_BINARY, 0);
    #ifndef TEST
        check_threads_etc();
    #endif
      }while(fd<0 && errno == EINTR);
    
      if(fd < 0) return 0;
    
      buffer=(unsigned char *)malloc(l);
      
      for(tmp=0;tmp<l;)
      {
        ptrdiff_t x;
        do{
          x=fd_read(fd, buffer + tmp, l - tmp);
    #ifndef TEST
          check_threads_etc();
    #endif
        } while(x < 0 && errno == EINTR);
    #ifdef DLDEBUG
          fprintf(stderr,"Reading ... tmp=%d len=%d x=%d errno=%d\n",tmp,l,x,errno);
    #endif
        if(x > 0) tmp+=x;
        if(x<0)
        {
          free(buffer);
          return 0;
        }
      }
      while(fd_close(fd) < 0 && errno==EINTR) {
    #ifndef TEST
        check_threads_etc();
    #endif
      }
    #ifdef DLDEBUG
      fprintf(stderr,"Done reading\n");
      fflush(stderr);
      Sleep(500);
    #endif
      return buffer;
    }
    
    /****************************************************************/
    
    struct DLHandle
    {
      int refs;
      char *filename;
      int flags;
      struct DLHandle *next;
    
      size_t codesize;
      size_t memsize;
      void *code;
      void *memory;
      struct Htable *htable;
      struct DLLList *dlls;
    };
    
    struct DLLList
    {
      struct DLLList *next;
      HINSTANCE dll;
    };
    
    static struct DLHandle *first;
    static struct DLHandle global_dlhandle;
    static INT32 global_imagebase = 0x00400000;
    
    static HMODULE low_LoadLibrary(LPCTSTR lpFileName)
    {
      if(_tcschr(lpFileName, '/')) {
        _TCHAR *p, *tmp = alloca((_tcslen(lpFileName)+1)*sizeof(_TCHAR));
        _tcscpy(tmp, lpFileName);
        for(p=tmp; (p=_tcschr(p, '/')); p++)
          *p = '\\';
        return LoadLibrary(tmp);
      } else return LoadLibrary(lpFileName);
    }
    
    static void *lookup_dlls(struct DLLList *l, char *name)
    {
      void *ret;
      char *tmp,*tmp2;
      if(name[0]=='_') name++;
    #ifdef DLDEBUG
      fprintf(stderr,"DL: lookup_dlls(%s)\n",name);
    #endif
    #if 1
      if((tmp=STRCHR(name,'@')))
      {
        tmp2=(char *)alloca(tmp - name + 1);
        MEMCPY(tmp2,name,tmp-name);
        tmp2[tmp-name]=0;
    #ifdef DLDEBUG
        fprintf(stderr,"DL: Ordinal cutoff: %s -> %s\n",name,tmp2);
    #endif
        name=tmp2;
      }
    #endif
        
      while(l)
      {
    #ifdef DLDEBUG
        char modname[4711];
        GetModuleFileName(l->dll, modname, 4710);
        fprintf(stderr,"Looking for %s in %s ...\n",
    	    name,
    	    modname);
    #endif
        if((ret=GetProcAddress(l->dll,name))) return ret;
        l=l->next;
      }
      return 0;
    }
    
    static void dlllist_free(struct DLLList *l)
    {
      if(l)
      {
        FreeLibrary(l->dll);
        dlllist_free(l->next);
        free((char *)l);
      }
    }
    
    static int append_dlllist(struct DLLList **l,
    			  char *name)
    {
      struct DLLList *n;
      HINSTANCE tmp;
    #ifdef DLDEBUG
      fprintf(stderr,"append_dlllist(%s)\n",name);
      FLUSH();
    #endif
      tmp=low_LoadLibrary(name);
      if(!tmp) return 0;
      n=(struct DLLList *)malloc(sizeof(struct DLLList));
      if(!n)
      {
        dlerr="Out of memory";
        return 0;
      }
      n->dll=tmp;
    #ifdef DLDEBUG
      fprintf(stderr,"append_dlllist(%s)->%p\n",name,n->dll);
      FLUSH();
    #endif
      n->next=0;
      while( *l ) l= & (*l)->next;
      *l=n;
      return 1;
    }
    
    #define i1(X) (data->buffer[(X)])
    #define i2(X) (i1((X))|(i1((X)+1)<<8))
    #define i4(X) (i1((X))|(i1((X)+1)<<8)|\
                    (i1((X)+2)<<16)|(i1((X)+3)<<24))
    /* Truncated */
    #define i8(X) (i1((X))|(i1((X)+1)<<8)|\
                    (i1((X)+2)<<16)|(i1((X)+3)<<24))
    
    #define COFF_SECT_NOLOAD (1<<1)
    #define COFF_SECT_LNK_INFO 0x200
    #define COFF_SECT_MEM_LNK_REMOVE (1<<11)
    #define COFF_SECT_MEM_DISCARDABLE (1<<25)
    #define COFF_SECT_MEM_EXECUTE (1<<29)
    #define COFF_SECT_MEM_READ (1<<30)
    #define COFF_SECT_MEM_WRITE (1<<31)
    
    #define COFF_SYMBOL_EXTERN 2
    #define COFF_SYMBOL_WEAK_EXTERN 105
    
    struct COFF
    {
      INT16 machine;
      INT16 num_sections;
      INT32 timestamp;
      INT32 symboltable;
      INT32 num_symbols;
      INT16 sizeof_optheader;
      INT16 characteristics;
    };
    
    union COFFname
    {
      INT32 ptr[2];
      char text[8];
    };
    
    struct COFFsection
    {
      union COFFname name;
    
      INT32 virtual_size;
      INT32 virtual_addr;
    
      INT32 raw_data_size;
      INT32 ptr2_raw_data;
      INT32 ptr2_relocs;
      INT32 ptr2_linenums;
      INT16 num_relocs;
      INT16 num_linenums;
      INT32 characteristics;
    };
    
    struct COFFSymbol
    {
      union COFFname name;
      INT32 value;
      INT16 secnum;
      INT16 type;
      INT8  class;
      INT8  aux;
    };
    
    
    #define COFFReloc_I386_dir32 6
    #define COFFReloc_I386_dir32nb 7
    #define COFFReloc_I386_sect 10
    #define COFFReloc_I386_sectrel 11 
    #define COFFReloc_I386_rel32 20
    
    #define COFFReloc_IA64_imm14 1		/* A4 */
    #define COFFReloc_IA64_imm22 2		/* A5 */
    #define COFFReloc_IA64_imm64 3		/* X2 */
    #define COFFReloc_IA64_dir32 4
    #define COFFReloc_IA64_dir64 5
    #define COFFReloc_IA64_pcrel21b 6	/* M22, M23, B1, B2, B3, B6 */
    #define COFFReloc_IA64_pcrel21m 7	/* I20, M20, M21  */
    #define COFFReloc_IA64_pcrel21f 8	/* I19, M37, B9, F14, F15 */
    #define COFFReloc_IA64_gprel22 9	/* A5 */
    #define COFFReloc_IA64_ltoff22 10	/* A5 */
    #define COFFReloc_IA64_sect 11		/* */
    #define COFFReloc_IA64_secrel22 12	/* A5 */
    #define COFFReloc_IA64_secrel64i 13	/* */
    #define COFFReloc_IA64_secrel32 14	/* */
    #define COFFReloc_IA64_ltoff64 15	/* X2 */
    #define COFFReloc_IA64_dir32nb 16	/* */
    #define COFFReloc_IA64_addend 31	/* */
    
    
    /* This structure is correct, but should not be used because of
     * portability issues
     */
    struct COFFReloc
    {
      INT32 location;
      INT32 symbol;
      INT16 type;
    };
    
    union PEAOUT {
      struct {
        struct {
          INT16 magic;
          INT16 version;
          INT32 text_size;
          INT32 data_size;
          INT32 bss_size;
          INT32 entry;
          INT32 text_start;
          INT32 data_start;
        } aout;
        INT32 image_base;
        INT32 section_alignment;
        INT32 file_alignment;
        INT16 major_os_version;
        INT16 minor_os_version;
        INT16 major_image_version;
        INT16 minor_image_version;
        INT16 major_subsys_version;
        INT16 minor_subsys_version;
        INT32 reserved1;
        INT32 size_of_image;
        INT32 size_of_headers;
        INT32 checksum;
        INT16 subsys;
        INT16 dll_flags;
        INT32 size_of_stack_reserve;
        INT32 size_of_stack_commit;
        INT32 size_of_heap_reserve;
        INT32 size_of_heap_commit;
        INT32 loader_flags;
        INT32 number_of_rva_and_sizes;
        INT32 data_directory[16][2];
      } pe32;
      struct {
        struct {
          INT16 magic;
          INT16 version;
          INT32 text_size;
          INT32 data_size;
          INT32 bss_size;
          INT32 entry;
          INT32 text_start;
        } aout;
        INT64 image_base;
        INT32 section_alignment;
        INT32 file_alignment;
        INT16 major_os_version;
        INT16 minor_os_version;
        INT16 major_image_version;
        INT16 minor_image_version;
        INT16 major_subsys_version;
        INT16 minor_subsys_version;
        INT32 reserved1;
        INT32 size_of_image;
        INT32 size_of_headers;
        INT32 checksum;
        INT16 subsys;
        INT16 dll_flags;
        INT64 size_of_stack_reserve;
        INT64 size_of_stack_commit;
        INT64 size_of_heap_reserve;
        INT64 size_of_heap_commit;
        INT32 loader_flags;
        INT32 number_of_rva_and_sizes;
        INT32 data_directory[16][2];
      } pe32plus;
    };
    #define PEAOUT_GET(P,E) ((P).pe32.aout.magic==0x20b? (P).pe32plus.E : (P).pe32.E)
    
    
    struct DLTempData
    {
      unsigned char *buffer;
      ptrdiff_t buflen;
      int flags;
    };
    
    
    struct DLObjectTempData
    {
      unsigned char *buffer;
      size_t buflen;
      int flags;
    
      struct COFF *coff;
      struct COFFSymbol *symbols;
      char *stringtable;
      struct COFFsection *sections;
    
      union PEAOUT *peaout;
    
      /* temporary storage */
      char **symbol_addresses;
      char **section_addresses;
    };
    
    
    static void *low_dlsym(struct DLHandle *handle,
    		       char *name,
    		       size_t len,
    		       int self)
    {
      void *ptr;
      char *tmp=name;
    #ifdef DLDEBUG
      if(name[len])
        fprintf(stderr,"low_dlsym(%c%c%c%c%c%c%c%c)\n",
    	    name[0],
    	    name[1],
    	    name[2],
    	    name[3],
    	    name[4],
    	    name[5],
    	    name[6],
    	    name[7]);
      else
        fprintf(stderr,"low_dlsym(%s)\n",name);
    #endif
      if(!self)
        ptr=htable_get(handle->htable,name,len);
      else
        ptr=0;
    
      if(!ptr)
      {
        if(name[len])
        {
          tmp=(char *)alloca(len+1);
          MEMCPY(tmp, name, len);
          tmp[len]=0;
        }
        ptr=lookup_dlls(handle->dlls, tmp);
      }
    #ifdef DLDEBUG
      if(!ptr)
      {
        fprintf(stderr,"Failed to find identifier %s\n",tmp);
      } else {
        fprintf(stderr, "Found identifier %s at 0x%p\n", tmp, ptr);
      }
    #endif
      return ptr;
    }
    		       
    void *dlsym(struct DLHandle *handle, char *name)
    {
      return low_dlsym(handle, name, strlen(name), 0);
    }
    
    const char *dlerror(void)
    {
      return dlerr;
    }
    
    static parse_link_info(struct DLHandle *ret,
    		       struct DLObjectTempData *data,
    		       char *info,
    		       int len)
    {
      int ptr=0;
      char buffer[1024];
    
    #ifdef DLDEBUG
      {
        int z;
        fprintf(stderr,"DLINFO(%d): ",len);
        for(z=0;z<len;z++) fprintf(stderr,"%c",info[z]);
        fprintf(stderr,"\n");
        FLUSH();
      }
    #endif
    
      while(ptr < len)
      {
        int l,x=ptr;
        char *end;
    
    #ifdef DLDEBUG    
        fprintf(stderr,"Parse link info ptr=%d\n",ptr);
        FLUSH();
    #endif
    
        end=MEMCHR(info+ptr,' ',len-ptr);
        if(end) 
          l = DO_NOT_WARN((int)(end - (info+x)));
        else
          l=len-ptr;
    
    #ifdef DLDEBUG    
        fprintf(stderr,"Parse link info ptr=%d len=%d '%c%c%c%c%c%c%c%c'\n",
    	    ptr,l,
    	    info[x],
    	    info[x+1],
    	    info[x+2],
    	    info[x+3],
    	    info[x+4],
    	    info[x+5],
    	    info[x+6],
    	    info[x+7]);
        FLUSH();
    #endif
    
        if((info[x] == '-') || (info[x] == '/'))
        {
          x++;
          if(info[x]=='?') x++;
          if(!memcmp(info+x,"lib:",4) || !memcmp(info+x,"LIB:",4))
          {
    	x+=4;
    #ifdef DLDEBUG    
    	fprintf(stderr,"Found lib: ptr=%d len=%d '%c%c%c%c%c%c%c%c'\n",
    		x,
    		l-(x-ptr),
    		info[x],
    		info[x+1],
    		info[x+2],
    		info[x+3],
    		info[x+4],
    		info[x+5],
    		info[x+6],
    		info[x+7]);
    	FLUSH();
    #endif
    	memcpy(buffer,info+x,l-(x-ptr));
    	buffer[l-(x-ptr)]=0;
    	append_dlllist(&ret->dlls, buffer);
          }
        }
        ptr+=l+1;
      }
    #ifdef DLDEBUG    
      fprintf(stderr,"Parse link info done.\n");
      FLUSH();
    #endif
    }
    
    static int dl_load_coff_files(struct DLHandle *ret,
    			      struct DLObjectTempData *tmp,
    			      int num)
    {
      int e=0,s,r;
      size_t memptr,codeptr;
      size_t num_exports=0;
      int data_protection_mode = PAGE_READWRITE;
    #ifdef _M_IA64
      size_t gp_size = 0;
      void **gp = NULL;
      size_t gp_pos = 0;
    #endif /* _M_IA64 */
    
    #define data (tmp+e)
    #define SYMBOLS(X) (*(struct COFFSymbol *)(18 * (X) + (char *)data->symbols))
    
    #ifdef DLDEBUG
      fprintf(stderr,"dl_load_coff_files(%p,%p,%d)\n",ret,tmp,num);
      FLUSH();
    #endif
    
      if(!num) return 0;
    
      ret->memsize=0;
      ret->codesize=0;
    
      /* Initialize tables and count how much memory is needed */
    #ifdef DLDEBUG
      fprintf(stderr,"DL: counting\n");
    #endif
      for(e=0;e<num;e++)
      {
        data->coff=(struct COFF *)data->buffer;
        data->symbols=(struct COFFSymbol *)(data->buffer +
    					data->coff->symboltable);
    
        data->stringtable=(unsigned char *)( ((char *)data->symbols) + 
    					 18 * data->coff->num_symbols);
    
        data->sections=(struct COFFsection *)( ((char *)data->coff) +
    					   sizeof(struct COFF)+ 
    					   data->coff->sizeof_optheader);
    
        if(data->coff->sizeof_optheader)
          data->peaout=(union PEAOUT *)(data->coff + 1);
        else
          data->peaout = NULL;
    
    #ifdef DLDEBUG
      fprintf(stderr,"DL: %p %d %d %d\n",
    	  data->coff,
    	  sizeof(data->coff[0]),
    	  data->coff->sizeof_optheader,
    	  sizeof(struct COFFsection));
      fprintf(stderr, "DL: num_sections:%d, num_symbols: %d\n",
    	  data->coff->num_sections, data->coff->num_symbols);
    #endif
    
        for(s=0;s<data->coff->num_sections;s++)
        {
          size_t align;
          if(data->sections[s].characteristics & COFF_SECT_LNK_INFO)
          {
    	parse_link_info(ret,data,
    			(char *)data->buffer + data->sections[s].ptr2_raw_data,
    			data->sections[s].raw_data_size);
    	continue;
          }
    
          if(data->sections[s].characteristics & 
    	 (COFF_SECT_NOLOAD | COFF_SECT_MEM_DISCARDABLE | COFF_SECT_MEM_LNK_REMOVE))
    	continue;
    
          align=(data->sections[s].characteristics>>20) & 0xf;
          if(align)
    	align=(1<<(align-1))-1;
    #ifdef DLDEBUG
          fprintf(stderr, "DL: section[%d,%d], %d bytes, align=%d (0x%x)\n",
    	      e, s, data->sections[s].raw_data_size, align+1,
    	      data->sections[s].characteristics);
    #endif
          if(data->sections[s].characteristics & COFF_SECT_MEM_WRITE)
          {
    	if(data->sections[s].characteristics & COFF_SECT_MEM_EXECUTE)
    	{
    	  /* Data section needs to be executable */
    	  data_protection_mode=PAGE_EXECUTE_READWRITE;
    	}
    	ret->memsize+=align;
    	ret->memsize&=~align;
    	ret->memsize+=MAXIMUM(data->sections[s].raw_data_size,
    			      data->sections[s].virtual_size);
    	EFENCE_ADD(ret->memsize);
    	ret->memsize+=PAD_DATA;
          }else{
    	/* We place all non-writable sections in the code segment
    	 * to protect it from accidental writing.
    	 */
    	ret->codesize+=align;
    	ret->codesize&=~align;
    	ret->codesize+=MAXIMUM(data->sections[s].raw_data_size,
    			       data->sections[s].virtual_size);
          }
        }
        if(data->coff->num_symbols)
        {
          /* symbol table in code section as well */
          ret->codesize += (data->coff->num_symbols + 1) * sizeof(void *) - 1;
          ret->codesize &= ~(sizeof(void *) - 1);
        }
    
    #ifdef _M_IA64
        /* To support ltoff relocations, we need to calculate the size
         * needed for the global offset table (gp).
         *
         * We're conservative, and allocate an entry for every ltoff relocation.
         */
    
        for(s=0;s<data->coff->num_sections;s++)
        {
          struct COFFReloc *relocs;
          if(data->sections[s].characteristics & 
    	 (COFF_SECT_NOLOAD | COFF_SECT_MEM_DISCARDABLE | COFF_SECT_MEM_LNK_REMOVE))
    	continue;
    
          /* relocate all symbols in this section */
          relocs=(struct COFFReloc *)(data->buffer +
    				  data->sections[s].ptr2_relocs);
    
          for(r=0;r<data->sections[s].num_relocs;r++)
          {
    /* This should work fine on x86 and other processors which handle
     * unaligned memory access
     */
    #define RELOCS(X) (*(struct COFFReloc *)( 10*(X) + (char *)relocs ))
    
    	if (RELOCS(r).type == COFFReloc_IA64_ltoff22) {
    	  /* FIXME: Ought to check if the symbol already has an entry. */
    	  gp_size++;
    	}
    #undef RELOCS
          }
        }
    #endif /* _M_IA64 */
    
        /* Count export symbols */
        for(s=0;s<data->coff->num_symbols;s++)
        {
          size_t align;
          if(SYMBOLS(s).class == COFF_SYMBOL_EXTERN ||
    	 SYMBOLS(s).class == COFF_SYMBOL_WEAK_EXTERN)
    	num_exports++;
    
          /* Count memory in common symbols,
           * I wonder what the alignment should be?
           */
          if((SYMBOLS(s).class == COFF_SYMBOL_EXTERN ||
    	  SYMBOLS(s).class == COFF_SYMBOL_WEAK_EXTERN) &&
    	 !SYMBOLS(s).secnum &&
    	 SYMBOLS(s).value)
          {
    	switch(SYMBOLS(s).value)
    	{
    	  case 0:
    	  case 1: align=0; break;
    	  case 2:
    	  case 3: align=1; break;
    	  case 4: 
    	  case 5:
    	  case 6:
    	  case 7: align=3; break;
    	  default: align=7;
    	}
    	ret->memsize+=align;
    	ret->memsize&=~align;
    	ret->memsize+=SYMBOLS(s).value;
    	EFENCE_ADD(ret->memsize);
    	ret->memsize+=PAD_DATA;
          }
        }
      }
    
    #ifdef _M_IA64
    #ifdef DLDEBUG
      fprintf(stderr, "Global Offset Table size: %d entries.\n", gp_size);
    #endif /* DLDEBUG */
    
      /* Allocate place in the data segment. */
      ret->memsize += (gp_size + 1)*sizeof(void *)-1;
      ret->memsize &= ~(sizeof(void *)-1);
      EFENCE_ADD(ret->memsize);
      ret->memsize += PAD_DATA;
    #endif /* _M_IA64 */
    
    
    #ifdef DLDEBUG
      fprintf(stderr,"DL: allocating %d bytes\n",ret->memsize);
    #endif
    
      /* Allocate data memory */
      ret->memory=VirtualAlloc(0,
    			   ret->memsize,
    #ifdef EFENCE
    			   MEM_RESERVE,
    #else
    			   MEM_COMMIT,
    #endif
    			   data_protection_mode);
    
      if(!ret->memory && ret->memsize)
      {
        static char buf[300];
        sprintf(buf, "Failed to allocate %d bytes RW(X)-memory.", ret->memsize);
    #ifdef DLDEBUG
        fprintf(stderr, "%s\n", buf);
    #endif
        dlerr=buf;
        return -1;
      }
    
      ret->code=VirtualAlloc(0,
    			 ret->codesize,
    			 MEM_COMMIT,
    			 PAGE_READWRITE); /* changed later */
    
      if(!ret->code && ret->codesize)
      {
        static char buf[300];
        sprintf(buf, "Failed to allocate %d bytes executable memory.", ret->memsize);
    #ifdef DLDEBUG
        fprintf(stderr, "%s\n", buf);
    #endif
        dlerr=buf;
        return -1;
      }
    
    
    #ifdef DLDEBUG
      fprintf(stderr,"DL: Got %d bytes RWX memory at %p\n",ret->memsize,ret->memory);
    #endif
    
      /* Create a hash table for exported symbols */
      ret->htable=alloc_htable(num_exports);
    
      if(data->flags & RTLD_GLOBAL)
        global_dlhandle.htable = htable_add_space(global_dlhandle.htable, num_exports);
    
    #ifdef DLDEBUG
      fprintf(stderr,"DL: moving code\n");
      FLUSH();
    #endif
    
      /* Copy code into executable memory */
      memptr=0;
      codeptr=0;
      for(e=0;e<num;e++)
      {
        data->section_addresses =
          (char **)calloc(sizeof(char *),data->coff->num_sections);
    
        for(s=0;s<data->coff->num_sections;s++)
        {
          size_t align;
          if(data->sections[s].characteristics & 
           (COFF_SECT_NOLOAD | COFF_SECT_MEM_DISCARDABLE | COFF_SECT_MEM_LNK_REMOVE))
    	continue;
    
          align=(data->sections[s].characteristics>>20) & 0xf;
          if(align)
    	align=(1<<(align-1))-1;
    
          if(data->sections[s].characteristics & COFF_SECT_MEM_WRITE)
          {
    	memptr+=align;
    	memptr&=~align;
    
    	data->section_addresses[s]=
    	  EFENCE_ALIGN((char *)ret->memory + memptr,
    		       MAXIMUM(data->sections[s].raw_data_size,
    			       data->sections[s].virtual_size),
    		       align);
    	memptr+=MAXIMUM(data->sections[s].raw_data_size,
    			data->sections[s].virtual_size);
    	EFENCE_ADD(memptr);
    	memptr+=PAD_DATA;
          }else{
    	codeptr+=align;
    	codeptr&=~align;
    
    	data->section_addresses[s]=(char *)ret->code + codeptr;
    	codeptr+=MAXIMUM(data->sections[s].raw_data_size,
    			data->sections[s].virtual_size);
          }
    #ifdef DLDEBUG
          fprintf(stderr,"DL: section[%d]=%p { %d, %d }\n",s,
    	      data->section_addresses[s],
    	      data->sections[s].ptr2_raw_data,
    	      data->sections[s].raw_data_size);
          FLUSH();
    #endif
    
          if(data->sections[s].ptr2_raw_data)
          {
    	memcpy((char *)data->section_addresses[s],
    	       data->buffer + data->sections[s].ptr2_raw_data,
    	       data->sections[s].raw_data_size);
    	if(data->sections[s].raw_data_size < data->sections[s].virtual_size)
    	{
    	  memset((char *)data->section_addresses[s] +
    		 data->sections[s].raw_data_size,
    		 0,
    		 data->sections[s].virtual_size - 
    		 data->sections[s].raw_data_size);
    	}
          }else{
    	memset((char *)data->section_addresses[s],
    	       0,
    	       MAXIMUM(data->sections[s].raw_data_size,
    		       data->sections[s].virtual_size));
          }
        }
    
        if(data->coff->num_symbols)
        {
          codeptr += sizeof(void *)-1;
          codeptr &= ~(sizeof(void *)-1);
          data->symbol_addresses=(char **)( ((char *)ret->code) + codeptr);
          MEMSET(data->symbol_addresses,
    	     0,
    	     data->coff->num_symbols * sizeof(void *));
    #ifdef DLDEBUG
          fprintf(stderr,"DL: data->symbol_addresses=%p\n",
    	      data->symbol_addresses);
    #endif
          codeptr += data->coff->num_symbols * sizeof(void *);
        }
    
    
        /* Make addresses for common symbols */
        for(s=0;s<data->coff->num_symbols;s++)
        {
          size_t align;
          /* 
           * Setup poiners to common symbols
           */
          if((SYMBOLS(s).class == COFF_SYMBOL_EXTERN ||
    	  SYMBOLS(s).class == COFF_SYMBOL_WEAK_EXTERN) &&
    	 !SYMBOLS(s).secnum &&
    	 SYMBOLS(s).value)
          {
    	switch(SYMBOLS(s).value)
    	{
    	  case 0:
    #ifdef DL_VERBOSE
    	    fprintf(stderr,"DLOPEN: common symbol with size 0!\n");
    #endif
    	  case 1: align=0; break;
    	  case 2:
    	  case 3: align=1; break;
    	  case 4: 
    	  case 5:
    	  case 6:
    	  case 7: align=3; break;
    	  default: align=7;
    	}
    	memptr += align;
    	memptr &= ~align;
    
    	data->symbol_addresses[s]=
    	  EFENCE_ALIGN((char *)ret->memory + memptr,
    		       SYMBOLS(s).value,
    		       align);
    	  
    	memset((char *)data->symbol_addresses[s],
    	       0,
    	       SYMBOLS(s).value);
    	memptr+=SYMBOLS(s).value;
    	EFENCE_ADD(memptr);
    	memptr+=PAD_DATA;
          }
        }
    
    #ifdef DLDEBUG
        fprintf(stderr,"DL: exporting symbols (%d)\n",data->coff->num_symbols);
    #endif
    
        /* Export symbols */
        for(s=0;s<data->coff->num_symbols;s++)
        {
    #if defined(DLDEBUG) && 0
          fprintf(stderr,"DL: xporting, class=%d secnum=%d\n",
    	      SYMBOLS(s).class,
    	      SYMBOLS(s).secnum);
    #endif
    
    #ifdef DL_SYMBOL_LOG
          {
    	char *value=0;
    	static char buf[10];
    	size_t len;
    	char *name;
    
    	if(SYMBOLS(s).secnum>0)
    	  value=data->section_addresses[SYMBOLS(s).secnum-1]+
    	    SYMBOLS(s).value;
    	else if(!SYMBOLS(s).secnum && SYMBOLS(s).value)
    	  value=data->symbol_addresses[s];
    
    	if(value)
    	{
    	  if(!SYMBOLS(s).name.ptr[0])
    	  {
    	    name=data->stringtable + SYMBOLS(s).name.ptr[1];
    	    len=strlen(name);
    #ifdef DLDEBUG
    	    fprintf(stderr,"DL: exporting %s -> %p\n",name,value);
    #endif
    	  }else{
    	    name=SYMBOLS(s).name.text;
    	    len=STRNLEN(name,8);
    	    if(len == 8)
    	    {
    	      MEMCPY(buf,name,8);
    	      buf[8]=0;
    	      name=buf;
    	    }
    	  }
    	  if(name[0] != '$')
    	    fprintf(dl_symlog,"%p = %s\n", value, name);
    	}
          }
    #endif
    
          if(SYMBOLS(s).class == COFF_SYMBOL_EXTERN ||
    	 SYMBOLS(s).class == COFF_SYMBOL_WEAK_EXTERN)
          {
    	char *value;
    	char *name;
    	size_t len;
    
    	if(SYMBOLS(s).secnum>0)
    	{
    	  value=data->section_addresses[SYMBOLS(s).secnum-1]+
    	    SYMBOLS(s).value;
    	}
    	else if(!SYMBOLS(s).secnum && SYMBOLS(s).value)
    	{
    	  value=data->symbol_addresses[s];
    	  if(!value)
    	  {
    	    fprintf(stderr,"Something is fishy here!!!\n");
    	    exit(99);
    	  }
    	}
    	else
    	  continue;
    
    
    	if(!SYMBOLS(s).name.ptr[0])
    	{
    	  name=data->stringtable + SYMBOLS(s).name.ptr[1];
    	  len=strlen(name);
    #ifdef DLDEBUG
    	  fprintf(stderr,"DL: exporting %s -> %p\n",name,value);
    #endif
    	}else{
    	  name=SYMBOLS(s).name.text;
    	  len=STRNLEN(name,8);
    #ifdef DLDEBUG
    	  fprintf(stderr,"DL: exporting %c%c%c%c%c%c%c%c -> %p\n",
    		  name[0],
    		  name[1],
    		  name[2],
    		  name[3],
    		  name[4],
    		  name[5],
    		  name[6],
    		  name[7],value);
    #endif
    	}
    	
    	htable_put(ret->htable, name, len, value,
    		   SYMBOLS(s).class != COFF_SYMBOL_WEAK_EXTERN);
    	if(data->flags & RTLD_GLOBAL)
    	  htable_put(global_dlhandle.htable, name, len, value,
    		     SYMBOLS(s).class != COFF_SYMBOL_WEAK_EXTERN);
          }
        }
      }
    
    #ifdef _M_IA64
      /* Set up the global pointer. */
    
      memptr += sizeof(void *)-1;
      memptr &= ~(sizeof(void *)-1);
    
      gp = (void **)EFENCE_ALIGN((char *)ret->memory + memptr,
    			     gp_size * sizeof(void *),
    			     sizeof(void *) - 1);
      memptr += gp_size * sizeof(void *);
      EFENCE_ADD(memptr);
      memptr += PAD_DATA;
    #endif /* _M_IA64 */
    
    
    #ifdef DLDEBUG
      fprintf(stderr,"DL: resolving\n");
      FLUSH();
    #endif
    
      /* Do resolve and relocations */
    
      for(e=0;e<num;e++)
      {
        for(s=0;s<data->coff->num_sections;s++)
        {
          struct COFFReloc *relocs;
          if(data->sections[s].characteristics & 
    	 (COFF_SECT_NOLOAD | COFF_SECT_MEM_DISCARDABLE | COFF_SECT_MEM_LNK_REMOVE))
    	continue;
    
          /* relocate all symbols in this section */
          relocs=(struct COFFReloc *)(data->buffer +
    				  data->sections[s].ptr2_relocs);
    
          dlerr=0;
          for(r=0;r<data->sections[s].num_relocs;r++)
          {
    
    /* This should work fine on x86 and other processors which handle
     * unaligned memory access
     */
    #define RELOCS(X) (*(struct COFFReloc *)( 10*(X) + (char *)relocs ))
    
    	char *loc=data->section_addresses[s] + RELOCS(r).location;
    	char *ptr;
    	ptrdiff_t sym=RELOCS(r).symbol;
    	char *name;
    	size_t len;
    
    	if(!SYMBOLS(sym).name.ptr[0])
    	{
    	  name=data->stringtable + SYMBOLS(sym).name.ptr[1];
    	  len=strlen(name);
    	}else{
    	  name=SYMBOLS(sym).name.text;
    	  len=STRNLEN(name,8);
    	}
    
    #ifdef DLDEBUG
    	fprintf(stderr,"DL: Reloc[%d] sym=%d loc=%d type=%d\n",
    		r,
    		sym,
    		RELOCS(r).location,
    		RELOCS(r).type);
    
    	if(!name[len])
    	{
    	  fprintf(stderr,"DL: symbol name=%s\n",name);
    	}else{
    	  fprintf(stderr,"DL: symbol name=%c%c%c%c%c%c%c%c\n",
    		  name[0],
    		  name[1],
    		  name[2],
    		  name[3],
    		  name[4],
    		  name[5],
    		  name[6],
    		  name[7]);
    	}
    #endif
    
    	if(!(ptr=data->symbol_addresses[sym]))
    	{
    	  /* FIXME: check storage class of symbol */
    	  
    	  if(SYMBOLS(sym).secnum > 0)
    	  {
    	    ptr=data->symbol_addresses[sym]=
    	      data->section_addresses[SYMBOLS(sym).secnum-1]+
    	      SYMBOLS(sym).value;
    	  }
    	  else if(!SYMBOLS(sym).secnum /* && !SYMBOLS(sym).value */)
    	  {
    	       
    #ifdef DLDEBUG
    	    fprintf(stderr,"DL: resolving symbol[%d], type=%d class=%d secnum=%d aux=%d value=%d\n",
    		    sym,
    		    SYMBOLS(sym).type,
    		    SYMBOLS(sym).class,
    		    SYMBOLS(sym).secnum,
    		    SYMBOLS(sym).aux,
    		    SYMBOLS(sym).value);
    #endif
    
    #ifdef _M_IA64
    	    if ((len == 3) && !memcmp(name, "_gp", 3)) {
    	      /* Magic reference to the Global Offset Table. */
    	      ptr = (void *)gp;
    	    } else {
    #endif /* _M_IA64 */
    
    	      ptr=low_dlsym(ret, name, len, 1);
    	      if(!ptr) 
    		ptr=low_dlsym(&global_dlhandle, name, len, 0);
    	      if(ptr)
    		data->symbol_addresses[sym]=ptr;
    	      else if(len > 6 && !memcmp(name,"__imp_",6)) {
    		ptr=low_dlsym(ret, name+6, len-6, 1);
    		if(!ptr) 
    		  ptr=low_dlsym(&global_dlhandle, name+6, len-6, 0);
    		/* This is cheating a bit.  We should really put this
    		   value somewhere else, and have symbol_addresses[sym] point
    		   to this somewhere else, but this saves allocating the extra
    		   memory. */
    		if(ptr) {
    		  data->symbol_addresses[sym]=ptr;
    		  ptr = (char *)&data->symbol_addresses[sym];
    		}
    	      }
    	      if(!ptr)
    	      {
    		static char err[256];
    		MEMCPY(err,"Symbol '",8);
    		MEMCPY(err+8,name,MINIMUM(len, 128));
    		MEMCPY(err+8+MINIMUM(len, 128),"' not found.\0",13);
    		dlerr=err;
    #ifndef DL_VERBOSE
    		return -1;
    #else
    		fprintf(stderr,"DL: %s\n",err);
    #endif
    	      }
    #ifdef _M_IA64
    	    }
    #endif /* _M_IA64 */
    	  }else{
    	    static char err[200];
    #ifdef DLDEBUG
    	    fprintf(stderr,"Gnapp??\n");
    #endif
    	    sprintf(err,"Unknown symbol[%d] type=%d class=%d section=%d value=%d",
    		    sym,
    		    SYMBOLS(sym).type,
    		    SYMBOLS(sym).class,
    		    SYMBOLS(sym).secnum,
    		    SYMBOLS(sym).value);
    	    dlerr=err;
    	    return -1;
    	  }
    
    	}
    
    #ifndef DL_VERBOSE
    	if(!ptr || !data->symbol_addresses)
    	{
    	  fprintf(stderr,"How on earth did this happen??\n");
    	  dlerr="Zero symbol?";
    	  return -1;
    	}
    #endif
    
    	switch(RELOCS(r).type)
    	{
    	  static char err[100];
    
    #ifdef DL_VERBOSE
    #define UNIMPLEMENTED_REL(X)						\
    	case X:								\
    	  sprintf(err, "Unimplemented relocation type: " #X " (%d)", X);\
    	  dlerr = err;							\
    	  fprintf(stderr, "DLERR: \"%s\"\n", dlerr);			\
    	  return -1
    #else /* !DL_VERBOSE */
    #define UNIMPLEMENTED_REL(X)						\
    	case X:								\
    	  sprintf(err, "Unimplemented relocation type: " #X " (%d)", X);\
    	  dlerr = err;							\
    	  return -1
    #endif /* DL_VERBOSE */
    
    #ifdef _M_IA64
    	  /* Data relocation. */
    	case COFFReloc_IA64_dir64:
    #ifdef DLDEBUG
    	  fprintf(stderr,"DL: reloc absolute: loc %p = %p\n", loc,ptr);
    #endif
    	  ((INT64 *)loc)[0]+=(INT64)ptr;
    	  break;
    
    	  UNIMPLEMENTED_REL(COFFReloc_IA64_dir32nb);
    
    	default:
    	  {
    	    /* Instruction relocation. */
    
    	    /* IA64 bundle format:
    	     *
    	     * 128bit little-endian.
    	     *
    	     * 22222222 22222222 22222222 22222222
    	     * 22222222 21111111 11111111 11111111
    	     * 11111111 11111111 11000000 00000000
    	     * 00000000 00000000 00000000 000ttttt
    	     *
    	     * Bundles are 16 byte aligned.
    	     */
    
    	    /* Instruction relocation pointers are
    	     * stored as a pointer to the bundle in
    	     * the upper bits, and sub-instruction
    	     * number in the least significant four
    	     * bits.
    	     */
    
    	    int flag = ((size_t)loc) & 0xf;
    	    unsigned INT64 instr = 0;
    	    unsigned INT64 S;
    	    unsigned INT64 lost_bits;
    	    loc = (void *)(((size_t)loc) & ~((size_t)0xf));
    
    	    /* Read sub-instruction.
    	     *
    	     * The instruction is msb aligned to avoid needing
    	     * to shift in case 2.
    	     *
    	     * Note that the low order bits are kept as is to
    	     * simplify the write-back.
    	     *
    	     * lost_bits is used to retain the high order bits
    	     * that are lost due to the shift.
    	     */
    	    switch (flag) {
    	    case 0:
    	      lost_bits = ((unsigned INT64 *)loc)[0];
    	      instr = lost_bits << 18;
    	      break;
    	    case 1:
    	      lost_bits = ((unsigned INT32 *)loc)[2];
    	      instr = (lost_bits << 41) |
    		(((unsigned INT64)((unsigned INT32 *)loc)[1]) << 9);
    	      break;
    	    case 2:
    	      instr = ((unsigned INT64 *)loc)[1];
    	      break;
    	    default:
    	      sprintf(err, "Unsupported relocation: %d, 0x%p, %d",
    		      RELOCS(r).type, loc, flag);
    	      dlerr = err;
    #ifdef DL_VERBOSE
    	      fprintf(stderr, "DLERR: \"%s\"\n", dlerr);
    #endif /* DL_VERBOSE */
    	      return -1;
    	    }
    #ifdef DLDEBUG
    	    fprintf(stderr, "DL: instr 0x%p\n", (void *)(instr >> 23));
    #endif
    	    switch (RELOCS(r).type) {
    	      /* We will need to support more types here */
    
    	      UNIMPLEMENTED_REL(COFFReloc_IA64_imm14);
    	      UNIMPLEMENTED_REL(COFFReloc_IA64_imm22);
    	      UNIMPLEMENTED_REL(COFFReloc_IA64_imm64);
    	      UNIMPLEMENTED_REL(COFFReloc_IA64_dir32);
    
    	    case COFFReloc_IA64_pcrel21b:
    	      /* Instruction format M22, M23, B1, B2, B3, B6
    	       *
    	       * 43333333 33322222 22222111 11111110 00000000 0
    	       * 09876543 21098765 43210987 65432109 87654321 0
    	       * XXXX.XXX ........ ........ ....XXXX XXXXXXXX X
    	       *
    	       * S += ptr - loc
    	       */
    	      S = (instr & 0x00fffff000000000) + ((ptr - loc)<<(23 - 4));
    	      if (S & 0x0100000000000000) {
    		/* Got carry, adjust sign. */
    		instr ^= 0x0800000000000000;
    	      }
    	      instr = (instr & ~0x00fffff000000000) | (S & 0x00fffff000000000);
    	      break;
    
    	      UNIMPLEMENTED_REL(COFFReloc_IA64_pcrel21m);
    	      UNIMPLEMENTED_REL(COFFReloc_IA64_pcrel21f);
    
    	    case COFFReloc_IA64_gprel22:
    	      /* Instruction format A5
    	       *
    	       * 43333333 33322222 22222111 11111110 00000000 0
    	       * 09876543 21098765 43210987 65432109 87654321 0
    	       * XXXX.... ........ ...XX... ....XXXX XXXXXXXX X
    	       *
    	       * S += ptr - gp;
    	       */
    	      S = (ptr - (char *)gp) +
    		(((instr & 0x0fffe00000000000) >> 38)|
    		 ((instr & 0x000007f000000000) >> 36));
    	      instr = (instr & ~0x0fffe7f000000000) |
    		((S & 0x3fff80)<<38)|((S & 0x7f)<<36);
    #ifdef DLDEBUG
    	      if ((S & ~0x3fffff) + ((S & 0x200000)<<1)) {
    		fprintf(stderr, "DL: gp relative offset > 22 bits: 0x%p\n",
    			(void *)S);
    	      }
    #endif /* DLDEBUG */
    	      break;
    
    	    case COFFReloc_IA64_ltoff22:
    	      /* Instruction format A5
    	       *
    	       * 43333333 33322222 22222111 11111110 00000000 0
    	       * 09876543 21098765 43210987 65432109 87654321 0
    	       * XXXX.... ........ ...XX... ....XXXX XXXXXXXX X
    	       *
    	       * gp[gp_pos] = S + ptr;
    	       * S = gp_pos++;
    	       */
    
    	      gp[gp_pos] = ((unsigned INT64) ptr) +
    		(((instr & 0x0fffe00000000000) >> 38)|
    		 ((instr & 0x000007f000000000) >> 36));
    
    	      /* Note: multiplies gp_pos with 8 in the same operation. */
    	      instr = (instr & ~0x0fffe7f000000000) |
    		((gp_pos & 0x07fff0)<<41) | ((gp_pos & 0x00000f)<<39);
    	      gp_pos++;
    	      break;
    
    	      UNIMPLEMENTED_REL(COFFReloc_IA64_sect);
    	      UNIMPLEMENTED_REL(COFFReloc_IA64_secrel22);
    	      UNIMPLEMENTED_REL(COFFReloc_IA64_secrel64i);
    	      UNIMPLEMENTED_REL(COFFReloc_IA64_secrel32);
    	      UNIMPLEMENTED_REL(COFFReloc_IA64_ltoff64);
    	      UNIMPLEMENTED_REL(COFFReloc_IA64_addend);
    
    	    default:
    	      sprintf(err,"Unknown relocation type: %d",RELOCS(r).type);
    	      dlerr=err;
    #ifdef DL_VERBOSE
    	      fprintf(stderr, "DLERR: \"%s\"\n", dlerr);
    #endif /* DL_VERBOSE */
    	      return -1;
    	    }
    #ifdef DLDEBUG
    	    fprintf(stderr, "DL: relocated instr 0x%p\n",
    		    (void *)(instr >> 23));
    #endif
    	    /* Store back the modified instruction. */
    	    switch(flag) {
    	    case 0:
    	      ((unsigned INT64 *)loc)[0] = (lost_bits & 0xffffc00000000000) |
    		(instr >> 18);
    	      break;
    	    case 1:
    	      ((unsigned INT32 *)loc)[1] = (instr >> 9);
    	      ((unsigned INT32 *)loc)[2] = (lost_bits & ~0x7fffff) |
    		(instr >> 41);
    	      break;
    	    case 2:
    	      ((unsigned INT64 *)loc)[1] = instr;
    	      break;
    	    }
    	  }
    	  break;
    #elif defined(_M_IX86)
    
    	    /* We may need to support more types here */
    	case COFFReloc_I386_dir32:
    #ifdef DLDEBUG
    	  fprintf(stderr,"DL: reloc absolute: loc %p = %p\n", loc,ptr);
    #endif
    	  ((INT32 *)loc)[0]+=(INT32)ptr;
    	  break;
    
    #if 0
    	case COFFReloc_I386_dir32nb:
    #ifdef DLDEBUG
    	  fprintf(stderr,"DL: reloc absolute nb: loc %p = %p\n", loc,ptr);
    #endif
    	  ((int32 *)loc)[0]+=((INT32)ptr) - global_imagebase;
    	  break;	   
    #endif
    
    	case COFFReloc_I386_rel32:
    #ifdef DLDEBUG
    	  fprintf(stderr,"DL: reloc relative: loc %p = %p = %d\n",
    		  loc,
    		  ptr,
    		  ptr - (loc+sizeof(INT32)));
    #endif
    	  ((INT32*)loc)[0]+=ptr - (loc+sizeof(INT32));
    	  break;
    
    
    	default:
    	  sprintf(err,"Unknown relocation type: %d",RELOCS(r).type);
    	  dlerr=err;
    #ifdef DL_VERBOSE
    	  fprintf(stderr, "DLERR: \"%s\"\n", dlerr);
    #endif /* DL_VERBOSE */
    	  return -1;
    #endif /* _M_IA64 || _M_IX86 */
    	}
          }
    
    #ifdef DL_VERBOSE
          if(dlerr)
    	return -1;
    #endif
    
        }
      }
    
      for(e=0;e<num;e++)
        free((char *) data->section_addresses);
    
      if(ret->code)
      {
        DWORD oldprotect;
    #if defined(_M_IA64) && 0
        extern void (*ia64_flush_instruction_cache)(void *addr, size_t len);
        /* Flush the instruction cache. */
        ia64_flush_instruction_cache(ret->code, ret->codesize);
    #endif /* _M_IA64 && 0 */
        if(!VirtualProtect(ret->code,
    		       ret->codesize,
    		       PAGE_EXECUTE_READ,
    		       &oldprotect))
        {
          dlerr="Failed to set memory executable";
          return -1;
        }
      }
    
      return 0; /* Done (I hope) */
    #undef data
    }
    
    static int dl_loadarchive(struct DLHandle *ret,
    			  struct DLTempData *data)
    {
      ptrdiff_t pos,len,o;
      struct DLTempData save=*data;
      int retcode;
    
      struct DLObjectTempData *tmp;
      INT32 object_files=0;
    
    
    #ifdef DLDEBUG
      fprintf(stderr,"dl_loadarchive\n");
      FLUSH();
    #endif
    
      /* Count how many object files there are in the loop */
      for(pos=8;pos < save.buflen;pos+=60+(len+1)&~1)
      {
        len=STRTOL(save.buffer+pos+48,0,10);
        if(save.buffer[pos]!='/') object_files++;
    #ifdef DLDEBUG
        fprintf(stderr,"DLARCH: pos=%d len=%d\n",pos,len);
    #endif
      }
    #ifdef DLDEBUG
      fprintf(stderr,"DLARCH: object files in archive: %d\n",object_files);
    #endif
    
    
      tmp=(struct DLObjectTempData *)malloc(sizeof(struct DLObjectTempData) * object_files);
      if(!tmp)
      {
        dlerr="Failed to allocate temporary storage";
        return -1;
      }
      o=0;
    
      /* Initialize data objects for these */
      for(pos=8;pos < save.buflen;pos+=60+(len+1)&~1)
      {
        len=STRTOL(save.buffer+pos+48,0,10);
        if(save.buffer[pos]!='/')
        {
          tmp[o].buflen=len;
          tmp[o].buffer=data->buffer+pos+60;
          o++;
        }
      }
    
      retcode=dl_load_coff_files(ret, tmp, object_files);
      free((char *)tmp);
      return retcode;
    }
    
    static int dl_loadcoff(struct DLHandle *ret,
    		       struct DLTempData *data)
    {
      struct DLObjectTempData tmp;
    
    #ifdef DLDEBUG
      fprintf(stderr,"dl_loadcoff\n");
      FLUSH();
    #endif
    
      tmp.buflen=data->buflen;
      tmp.buffer=data->buffer;
      tmp.flags = data->flags;
      return dl_load_coff_files(ret, &tmp, 1);
    }
    
    static int dl_loadpe(struct DLHandle *ret,
    		     struct DLTempData *data)
    {
      dlerr="PE images not supported yet.";
      return -1;
    }
    
    static int dl_load_file(struct DLHandle *ret,
    		       struct DLTempData *data)
    {
      INT32 tmp;
    #ifdef DLDEBUG
      fprintf(stderr,"dl_load_file\n");
      FLUSH();
    #endif
    
      if(data->buflen > 8 && ! memcmp(data->buffer,"!<arch>\n",8))
        return dl_loadarchive(ret,data);
    
      tmp=i4(0x3c);
      if(tmp >=0 && tmp<data->buflen-4 &&!memcmp(data->buffer+tmp,"PE\0\0",4))
        return dl_loadpe(ret, data);
    
      return dl_loadcoff(ret, data);
    }
    
    static void init_dlopen(void);
    
    struct DLHandle *dlopen(const char *name, int flags)
    {
      struct DLHandle *ret;
      struct DLTempData tmpdata;
      int retcode;
      tmpdata.flags=flags;
    
      if(!global_dlhandle.htable) init_dlopen();
    
      if(!name)
      {
        global_dlhandle.refs++;
        return &global_dlhandle;
      }
    
    #ifdef DLDEBUG
      fprintf(stderr,"dlopen(%s,%d)\n",name,flags);
    #endif
    
      for(ret=first;ret;ret=ret->next)
      {
        if(!strcmp(name, ret->filename))
        {
          ret->refs++;
          return ret;
        }
      }
    
      /* LD_LIBRARY_PATH ? */
      tmpdata.buflen=filesize(name);
      if(tmpdata.buflen==-1) return 0;
    
      ret=(struct DLHandle *)calloc(sizeof(struct DLHandle),1);
      ACCEPT_MEMORY_LEAK(ret);
      ret->refs=1;
      ret->filename=strdup(name);
      ACCEPT_MEMORY_LEAK(ret->filename);
      ret->flags=flags;
    
      tmpdata.buffer = (unsigned char *)read_file(name, &tmpdata.buflen);
      if(!tmpdata.buffer)
      {
        dlerr="Failed to read file.";
        dlclose(ret);
        return 0;
      }
      
      retcode=dl_load_file(ret, &tmpdata);
      free(tmpdata.buffer);
    
      if(retcode < 0)
      {
        dlclose(ret);
        return 0;
      }
    
      /* register module for future dlopens */
      ret->next=first;
      first=ret;
    
    
    #ifdef DL_SYMBOL_LOG
      fflush(dl_symlog);
    #endif
    
      return ret;
    }
    
    int dlclose(struct DLHandle *h)
    {
    #ifdef DLDEBUG
      fprintf(stderr,"Dlclose(%s)\n",h->filename);
    #endif
      if(! --h->refs)
      {
        struct DLHandle **ptr;
        for(ptr=&first;*ptr;ptr=&(ptr[0]->next))
        {
          if(*ptr == h)
          {
    	*ptr=h->next;
    	break;
          }
        }
        
        if(h->filename) free(h->filename);
        if(h->htable) htable_free(h->htable,0);
        if(h->dlls) dlllist_free(h->dlls);
        if(h->memory) VirtualFree(h->memory,h->memsize,MEM_RELEASE);
        if(h->code) VirtualFree(h->code,h->codesize,MEM_RELEASE);
        free((char *)h);
      }
      return 0;
    }
    
    #ifdef DEBUG_MALLOC
    #ifndef __NT__
    #define __cdecl
    #endif
    
    void * __cdecl dlopen_malloc_wrap(size_t size)
    {
      return malloc(size);
    }
    
    void * __cdecl dlopen_realloc_wrap(void *m, size_t size)
    {
      return realloc(m, size);
    }
    
    void * __cdecl dlopen_calloc_wrap(size_t size,size_t num)
    {
      return calloc(size,num);
    }
    
    void __cdecl dlopen_free_wrap(void * size)
    {
      free(size);
    }
    
    void * __cdecl dlopen_strdup_wrap(const char *s)
    {
      return strdup(s);
    }
    #endif
    
    #ifdef DL_WRAP_STDIO
    int __cdecl dlopen_fseek_wrapper(FILE *f, long pos, int mode)
    {
      fprintf(stderr,"fseek(%p,%ld,%d)\n",f,pos,mode);
      return fseek(f,pos,mode);
    }
    
    FILE *__cdecl dlopen_fopen_wrapper(const char *fname, const char *mode)
    {
      FILE *ret=fopen(fname,mode);
      fprintf(stderr,"fopen(\"%s\",\"%s\") => %p\n",fname,mode,ret);
      return ret;
    }
    #endif
    
    #ifdef USE_PDB_SYMBOLS
    
    /* IA64 PDB (Program Data Base) support. */
    
    /*
     * PDB file format:
     *
     * All values are stored in little-endian.
     *
     * PDB Format Identifier
     *   The file begins with a 0x1a (aka EOF) terminated string
     *   describing the program that generated the file.
     *   This is followed by two byte tag specifying the fileformat.
     *   Only format 0x44 0x55 is currently supported.
     *   The file is then padded to an even multiple of 4 bytes.
     *
     * PDB Header
     *   Then follows the PDB header.
     */
    
    struct pdb_header {
      INT32 blocksize;	/* Blocksize */
      INT32 freelist;
      INT32 total_alloc;	/* Total number of blocks in the file */
      INT32 toc_size;	/* Size in bytes of the Table Of Contents. */
      INT32 unknown;
      INT32 toc_loc;	/* Block number of the TOC block table. */
    };
    
    /* Read a sequence of blocks from the PDB file buf. */
    static void *read_pdb_blocks(unsigned char *buf, size_t len,
    			     INT32 *blocklist, size_t nbytes,
    			     struct pdb_header *header)
    {
      unsigned char *ret, *p;
    
    #ifdef DLDEBUG
      fprintf(stderr, "read_pdb_blocks(0x%p, %ld, 0x%p, %ld, X)...\n",
    	  buf, len, blocklist, nbytes);
    #endif /* DLDEBUG */
    
      if(len<1 || !(ret = p = malloc(nbytes))) return NULL;
      while(nbytes>0) {
        size_t chunk = (nbytes>header->blocksize? header->blocksize : nbytes);
        size_t offs = header->blocksize**(blocklist++);
        if(offs + chunk > len) { free(ret); return NULL; }
        memcpy(p, buf+offs, chunk);
        p += chunk;
        nbytes -= chunk;
      }
    #ifdef DLDEBUG
      fprintf(stderr, "OK, data at 0x%p\n", ret);
    #endif /* DLDEBUG */
      return ret;
    }
    
    /* Table Of Contents
     *
     * The table of contents consists of 3 sections.
     *
     *   INT32 number_of_files;
     *
     *   INT32 byte_lengths[number_of_files];
     *
     *   INT32 concatenated_block_tables[];
     */
    
    /* Read file #n specified in the toc from the PDB file buf. */
    static void *read_pdb_file(unsigned char *buf, size_t *plen,
    			   INT32 *toc, int n, struct pdb_header *header)
    {
      INT32 *fsz = toc+1;
      INT32 *blocklist = fsz+*toc;
      size_t len = *plen;
      int i;
      if(n<0 || n>=*toc) return NULL;
      for(i=0; i<n; i++) {
        int f_blocks = (*fsz+++header->blocksize-1)/header->blocksize;
        blocklist += f_blocks;
      }
      if(4+4*((blocklist-toc)+(*fsz+header->blocksize-1)/header->blocksize) >
         header->toc_size) 
        return NULL;
    #ifdef DLDEBUG
      fprintf(stderr, "Reading PDB file %d at block %d len %d\n",
    	  n, *blocklist, *fsz);
    #endif
      return read_pdb_blocks(buf, len, blocklist, *plen = *fsz, header);
    }
    
    /* PDB file #1 contains the root header. */
    
    struct pdb_root_header {
      INT32 version;	/* Root header version number (20000404). */
      INT32 timestamp;	/* Creation date (seconds since 1970). */
      INT32 unknown;
      INT32 names;
    };
    
    /* PDB file #3 contains the symbols header. */
    
    struct pdb_symbols_header {
      INT32 signature;	/* Marker to indicate versioned header (-1). */
      INT32 version;	/* Symboltable version number (19990903). */
      INT32 unknown;	/* Symbols header file number? (3). */
      INT32 hash1_file;	/* File number */
      INT32 hash2_file;	/* File number */
      INT32 gsym_file;	/* File number of the global symbol table. */
      INT32 module_size, offset_size, hash_size;
      INT32 srcmodule_size, pdbimport_size;      
    };
    
    /* Global Symbol Table
     *
     * This table consists of entries with the format
     *
     *   INT16 len;
     *   INT8 data[len];
     *
     * Each data block starts with an INT16 identifing the type.
     *
     * Currently only the following data blocks are understood:
     */
    
    struct cv_global_symbol {
      unsigned INT16 len;		/* Entry length */
      unsigned INT16 id;		/* 0x110e */
      unsigned INT32 type;		/* Symbol type */
      unsigned INT32 value;		/* Symbol value */
      unsigned INT16 secnum;	/* Section number (>= 1). */
      char name[1];			/* Symbol name */
    };
    
    static unsigned char *find_pdb_symtab(unsigned char *buf, size_t *plen)
    {
      struct pdb_header *header;
      struct pdb_symbols_header *st;
      size_t stlen, len = *plen;
      int gsym_file, idlen=0;
      INT32 *toc;
      unsigned char *ret;
      while(idlen<256 && idlen<len && buf[idlen]!=0x1a) idlen++;
      if(idlen>=256 || idlen>=len) return NULL;
    #ifdef DLDEBUG
      buf[idlen]='\0';
      fprintf(stderr, "Found PDB header, ident=\"%s\", sig=<%x,%x,%x,%x>\n",
    	  buf,  buf[idlen+1],  buf[idlen+2], buf[idlen+3],  buf[idlen+4]);
    #endif
      if(len<idlen+3 || buf[idlen+1]!=0x44 || buf[idlen+2]!=0x53) return NULL;
      idlen += 5;
      if(idlen&3) idlen+=4-(idlen&3);
      header = (void*)(buf+idlen);
    #ifdef DLDEBUG
      fprintf(stderr, "header at:0x%p (offset:%d)\n", header, idlen);
      fprintf(stderr,
    	  "blocksize:  %d\nfreelist:   %d\ntotalalloc: %d\n"
    	  "toc_size:   %d\nunknown:    %d\ntoc_loc:    %d\n",
    	  header->blocksize, header->freelist, header->total_alloc,
    	  header->toc_size, header->unknown, header->toc_loc);
    #endif /* DLDEBUG */
      if(idlen+sizeof(*header)>len || header->blocksize==0 ||
         header->toc_size < 20) return NULL;
      toc = read_pdb_blocks(buf, len,
    			(INT32*)(buf+header->toc_loc*header->blocksize),
    			header->toc_size, header);
      if(!toc) return NULL;
      if(*toc < 4 || header->toc_size < 4+4**toc) { free(toc); return NULL; }
    
      stlen = len;
      if(!(st = read_pdb_file(buf, &stlen, toc, 3, header))) {
        free(toc); return NULL;
      }
      if(stlen < sizeof(*st) || st->signature != -1) {
        free(st); free(toc); return NULL;
      }
      gsym_file = st->gsym_file;
      free(st);
      
    #ifdef DLDEBUG
      fprintf(stderr, "Located PDB global symtab as file %d\n", gsym_file);
    #endif
      ret = read_pdb_file(buf, plen, toc, gsym_file, header);
      free(toc);
      return ret;
    }
    #endif
    
    static void init_dlopen(void)
    {
      static char pike_path[MAX_PATH];
      INT32 offset;
      struct DLObjectTempData objtmp;
      HINSTANCE h;
      DWORD c;
    
      c=GetModuleFileName(NULL, pike_path, MAX_PATH);
      assert(c > 0);
    
    #ifdef DLDEBUG
      fprintf(stderr,"dlopen_init(%s)\n",pike_path);
    #endif
    
    #ifdef DL_SYMBOL_LOG
      dl_symlog=fopen("dlopen_symlog","w");
    #endif
    
      global_dlhandle.refs=1;
      global_dlhandle.filename=pike_path;
      global_dlhandle.next=0;
      first=&global_dlhandle;
      
      h=GetModuleHandle(NULL);
    
    #undef data
    #define data (&objtmp)
      assert(sizeof(union COFFname) == 8);
      assert(sizeof(struct COFFsection) == 40);
    
      data->buffer=(char *)h; /* portable? nope */
      offset=i4(0x3c);
      
      if(!memcmp(data->buffer+offset, "PE\0\0", 4))
      {
        int s;
        unsigned char *buf;
        size_t len;
        objtmp.coff=(struct COFF *)(data->buffer+offset+4);
    #ifdef DLDEBUG
        fprintf(stderr,"Found PE header.\n");
        fprintf(stderr,"num_sections=%d num_symbols=%d sizeof(optheader)=%d\n",
    	    objtmp.coff->num_sections,
    	    objtmp.coff->num_symbols,
    	    objtmp.coff->sizeof_optheader);
    #endif
        
        data->sections=(struct COFFsection *)( ((char *)data->coff) +
    					   sizeof(struct COFF)+ 
    					   data->coff->sizeof_optheader);
        
        
        buf= (unsigned char *)read_file(pike_path, &len);
        
        data->symbols=(struct COFFSymbol *)(buf +
    					data->coff->symboltable);
        
        data->stringtable=(unsigned char *)( ((char *)data->symbols) + 
    					 18 * data->coff->num_symbols);
        
    
        if(data->coff->sizeof_optheader) {
    
          data->peaout=(union PEAOUT *)(data->coff + 1);
    
          global_imagebase = PEAOUT_GET(*data->peaout, image_base);
    
        } else
    
          data->peaout = NULL;
    
    #if defined(PIKE_DEBUG) && !defined(USE_PDB_SYMBOLS)
        if(!data->coff->num_symbols)
          Pike_fatal("No COFF symbols found in pike binary.\n");
    #endif      
        global_dlhandle.htable=alloc_htable(data->coff->num_symbols);
        
    #ifdef DLDEBUG
        fprintf(stderr,"buffer=%p\n",data->buffer);
        fprintf(stderr,"buf=%p\n",buf);
        fprintf(stderr,"symbols=%p\n",data->symbols);
        fprintf(stderr,"stringtable=%p\n",data->stringtable);
        fprintf(stderr,"sections=%p\n",data->sections);
        
        
        for(s=0;s<data->coff->num_sections;s++)
        {
          fprintf(stderr,"sect[%d]=%p\n",
    	      s,
    	      data->buffer + data->sections[s].virtual_addr);
        }
        
        fprintf(stderr,"data->coff->num_symbols=%d\n",data->coff->num_symbols);
    #endif
        
        for(s=0;s<data->coff->num_symbols;s++)
        {
          char *name;
          int len;
          if(SYMBOLS(s).class != COFF_SYMBOL_EXTERN &&
    	 SYMBOLS(s).class != COFF_SYMBOL_WEAK_EXTERN) continue;
          if(SYMBOLS(s).secnum <= 0) continue;
          
          if(!SYMBOLS(s).name.ptr[0])
          {
    	name=data->stringtable + SYMBOLS(s).name.ptr[1];
    	if(name[0]=='?') continue; /* C++ garbled */
    	len = DO_NOT_WARN((int)strlen(name));
    #ifdef DLDEBUG
    	fprintf(stderr,"Sym[%04d] %s : ",s,name);
    #endif
          }else{
    	name=SYMBOLS(s).name.text;
    	if(name[0]=='?') continue; /* C++ garbled */
    	len = DO_NOT_WARN((int)STRNLEN(name,8));
    #ifdef DLDEBUG
    	fprintf(stderr,"Sym[%04d] %c%c%c%c%c%c%c%c = ",s,
    		name[0],
    		name[1],
    		name[2],
    		name[3],
    		name[4],
    		name[5],
    		name[6],
    		name[7]);
    #endif
          }
    #ifdef DLDEBUG
          fprintf(stderr,"sect=%d value=%d class=%d type=%d",
    	      SYMBOLS(s).secnum,
    	      SYMBOLS(s).value,
    	      SYMBOLS(s).class,
    	      SYMBOLS(s).type);
          
          fprintf(stderr," addr=%p+%x-%x+%x = %p",
    	      data->buffer,
    	      data->sections[SYMBOLS(s).secnum-1].virtual_addr,
    	      data->sections[SYMBOLS(s).secnum-1].ptr2_raw_data,
    	      SYMBOLS(s).value,
    	      data->buffer +
    	      data->sections[SYMBOLS(s).secnum-1].virtual_addr -
    	      data->sections[SYMBOLS(s).secnum-1].ptr2_raw_data +
    	      SYMBOLS(s).value);
          
          fprintf(stderr,"\n");
    #endif
          
          htable_put(global_dlhandle.htable, name, len,
    		 data->buffer +
    		 data->sections[SYMBOLS(s).secnum-1].virtual_addr -
    		 data->sections[SYMBOLS(s).secnum-1].ptr2_raw_data +
    		 SYMBOLS(s).value,
    		 SYMBOLS(s).class != COFF_SYMBOL_WEAK_EXTERN);		   
          
        }
        free(buf);
    #ifdef USE_PDB_SYMBOLS
        if(strlen(pike_path)>4) {
          char *pdb_name = alloca(strlen(pike_path)+1);
          strcpy(pdb_name, pike_path);
          strcpy(pdb_name+strlen(pdb_name)-4, ".PDB");
          buf= (unsigned char *)read_file(pdb_name, &len);
        } else buf = NULL;
        if(buf) {
          unsigned char *symtab = find_pdb_symtab(buf, &len);
          if(symtab) {
    	size_t i;
    #ifdef DLDEBUG
    	fprintf(stderr,"Loading PDB symbols (%d bytes)\n", len);
    #endif
    	for(i=0; i<len; i+=2+*(unsigned INT16 *)&symtab[i])
    	  if(*(unsigned INT16 *)&symtab[i+2] == 0x110e) {
    	    struct cv_global_symbol *sym = (void *)&symtab[i];
    	    size_t namelen=STRNLEN(sym->name,sym->len-12);
    	  
    #ifdef DLDEBUG
    	    if(!sym->name[namelen])
    	      fprintf(stderr,"Sym[%04d] %s : ",s,sym->name);
    	    else
    	      fprintf(stderr,"Sym[%04d] %c%c%c%c%c%c%c%c = ",s,
    		      sym->name[0],
    		      sym->name[1],
    		      sym->name[2],
    		      sym->name[3],
    		      sym->name[4],
    		      sym->name[5],
    		      sym->name[6],
    		      sym->name[7]);
    	    fprintf(stderr,"sect=%d value=%d type=%d",
    		    sym->secnum,
    		    sym->value,
    		    sym->type);
    #endif
    	    htable_put(global_dlhandle.htable, sym->name, namelen,
    		       data->buffer +
    		       data->sections[sym->secnum-1].virtual_addr -
    		       data->sections[sym->secnum-1].ptr2_raw_data +
    		       sym->value,
    		       1 /* Fixme? Weak symbols... */);
    	  }
    	free(symtab);
          }
          free(buf);
        }
    #endif
      }else{
    #ifdef DLDEBUG
        fprintf(stderr,"Couldn't find PE header.\n");
    #endif
        append_dlllist(&global_dlhandle.dlls, pike_path);
        global_dlhandle.htable=alloc_htable(997);
    
    #define EXPORT(X) \
      DO_IF_DLDEBUG( fprintf(stderr,"EXP: %s\n",#X); ) \
      htable_put(global_dlhandle.htable, SYMBOL_PREFIX #X, \
    	     sizeof(SYMBOL_PREFIX #X)-sizeof(""), &X, 1)
        
        
        fprintf(stderr,"Fnord, rand()=%d\n",rand());
        EXPORT(fprintf);
        EXPORT(_iob);
        EXPORT(abort);
        EXPORT(rand);
        EXPORT(srand);
        EXPORT(getc);
        EXPORT(ungetc);
        EXPORT(printf);
        EXPORT(perror);
        EXPORT(sscanf);
        EXPORT(abs);
        EXPORT(putchar);
        EXPORT(putenv);
        EXPORT(strncat);
        EXPORT(fdopen);
        EXPORT(fstat);
        EXPORT(_assert);
        EXPORT(qsort);
        EXPORT(exp);
        EXPORT(log);
        EXPORT(sqrt);
        EXPORT(fopen);
        EXPORT(fseek);
        EXPORT(fread);
        EXPORT(strtol);
        EXPORT(rewind);
        EXPORT(fputs);
        EXPORT(freopen);
        EXPORT(memcmp);
      }
    #if 0
    #ifdef _M_IA64
      {
        extern void *_gp[];
        EXPORT(_gp);
      }
    #endif
    #endif /* 0 */
    
    #define EXPORT_AS(X,Y) \
      DO_IF_DLDEBUG( fprintf(stderr,"EXP: %s = %s\n",#X,#Y); ) \
      htable_put(global_dlhandle.htable, SYMBOL_PREFIX #X, \
    	     sizeof(SYMBOL_PREFIX #X)-sizeof(""), &Y, 1)
    
    #if 0
      /* This doesn't work, don't know why - Hubbe */
    #ifdef DEBUG_MALLOC
      EXPORT_AS(malloc,dlopen_malloc_wrap);
      EXPORT_AS(calloc,dlopen_calloc_wrap);
      EXPORT_AS(free,dlopen_free_wrap);
      EXPORT_AS(realloc,dlopen_free_wrap);
      EXPORT_AS(strdup,dlopen_strdup_wrap);
    #endif
    #endif
    
    #ifdef DL_WRAP_STDIO
      EXPORT_AS(fseek, dlopen_fseek_wrapper);
      EXPORT_AS(fopen, dlopen_fopen_wrapper);
    #endif
    
    #ifdef EFENCE
      {
        SYSTEM_INFO sysinfo;
        GetSystemInfo(&sysinfo);
        dlopen_page_size=sysinfo.dwPageSize;
        fprintf(stderr,"Activating EFENCE, page_size=%d\n",dlopen_page_size);
        fflush(stderr);
      }
    #endif
    
    #ifdef PIKE_DEBUG
      if(global_imagebase != (INT32)data->buffer)
        Pike_fatal("LoadLibrary(ARGV[0]) didn't return instantiated program.\n");
    #endif 
    
    #ifdef DLDEBUG
      fprintf(stderr,"DL: init done\n");
    #endif
    }
    
    /* Strap to load symbols that might be needed from modules. */
    #ifdef HAVE__ALLDIV
    void _alldiv(void);
    #endif
    #ifdef HAVE__AULLSHR
    void _aullshr(void);
    #endif
    void dl_dummy(void)
    {
    #ifdef HAVE__ALLDIV
      _alldiv();
    #endif
    
    #ifdef HAVE__AULLSHR
      _aullshr();
    #endif
    }
    
    /****************************************************************/
    
    #ifdef TEST
    
    __declspec(dllexport) void func1(void)
    {
      fprintf(stderr,"func1()\n");
      fprintf(stdout,"func1()\n");
    }
    
    __declspec(dllexport) void func3(void)
    {
      fprintf(stderr,"func3()\n");
    }
    
    __declspec(dllexport) void func4(void)
    {
      fprintf(stderr,"func4()\n");
    }
    
    __declspec(dllexport) void func5(void)
    {
      fprintf(stderr,"func5()\n");
    }
    
    int main(int argc, char ** argv)
    {
      int tmp;
      assert(sizeof(union COFFname) == 8);
      assert(sizeof(struct COFFsection) == 40);
    #if 0
      HINSTANCE l;
      void *addr;
    
      fprintf(stderr,"....\n");
      l=low_LoadLibrary(argv[0]);
      fprintf(stderr,"LoadLibrary(%s) => %p\n",argv[0],(long)l);
      addr = GetProcAddress(l, "func1");
      fprintf(stderr,"GetProcAddress(\"func1\") => %p (&func1 = %p)\n",addr, func1);
    #else
    
      {
        HINSTANCE h=low_LoadLibrary(argv[0]);
        INT32 offset;
        struct DLObjectTempData objtmp;
    #undef data
    #define data (&objtmp)
    
        data->buffer=(char *)h; /* portable? nope */
        offset=i4(0x3c);
    
        if(!memcmp(data->buffer+offset, "PE\0\0", 4))
        {
          int s;
          unsigned char *buf;
          size_t len;
          objtmp.coff=(struct COFF *)(data->buffer+offset+4);
    #ifdef DLDEBUG
          fprintf(stderr,"Found PE header.\n");
          fprintf(stderr,"num_sections=%d num_symbols=%d sizeof(optheader)=%d\n",
    	      objtmp.coff->num_sections,
    	      objtmp.coff->num_symbols,
    	      objtmp.coff->sizeof_optheader);
    #endif
    
          data->sections=(struct COFFsection *)( ((char *)data->coff) +
    					     sizeof(struct COFF)+ 
    					     data->coff->sizeof_optheader);
    
    
          buf= (unsigned char *)read_file(argv[0], &len);
    
          data->symbols=(struct COFFSymbol *)(buf +
    					  data->coff->symboltable);
          
          data->stringtable=(unsigned char *)( ((char *)data->symbols) + 
    					   18 * data->coff->num_symbols);
          
    
          global_dlhandle.htable=alloc_htable(data->coff->num_symbols);
    
    #ifdef DLDEBUG
          fprintf(stderr,"buffer=%p\n",data->buffer);
          fprintf(stderr,"buf=%p\n",buf);
          fprintf(stderr,"symbols=%p\n",data->symbols);
          fprintf(stderr,"stringtable=%p\n",data->stringtable);
          fprintf(stderr,"sections=%p\n",data->sections);
    
    
          for(s=0;s<data->coff->num_sections;s++)
          {
    	fprintf(stderr,"sect[%d]=%p\n",
    		s,
    		data->buffer + data->sections[s].virtual_addr);
          }
    
          fprintf(stderr,"data->coff->num_symbols=%d\n",data->coff->num_symbols);
    #endif
    
    
          for(s=0;s<data->coff->num_symbols;s++)
          {
    	char *name;
    	int len;
    	if(SYMBOLS(s).class != COFF_SYMBOL_EXTERN &&
    	   SYMBOLS(s).class != COFF_SYMBOL_WEAK_EXTERN) continue;
    	if(SYMBOLS(s).secnum <= 0) continue;
    
    	if(!SYMBOLS(s).name.ptr[0])
    	{
    	  name=data->stringtable + SYMBOLS(s).name.ptr[1];
    	  if(name[0]=='?') continue; /* C++ garbled */
    	  len=strlen(name);
    #ifdef DLDEBUG
    	  fprintf(stderr,"Sym[%04d] %s : ",s,name);
    #endif
    	}else{
    	  name=SYMBOLS(s).name.text;
    	  if(name[0]=='?') continue; /* C++ garbled */
    	  len=STRNLEN(name,8);
    #ifdef DLDEBUG
    	  fprintf(stderr,"Sym[%04d] %c%c%c%c%c%c%c%c = ",s,
    		  name[0],
    		  name[1],
    		  name[2],
    		  name[3],
    		  name[4],
    		  name[5],
    		  name[6],
    		  name[7]);
    #endif
    	}
    #ifdef DLDEBUG
    	fprintf(stderr,"sect=%d value=%d class=%d type=%d",
    		SYMBOLS(s).secnum,
    		SYMBOLS(s).value,
    		SYMBOLS(s).class,
    		SYMBOLS(s).type);
    
    	fprintf(stderr," addr=%p+%x-%x+%x = %p",
    		data->buffer,
    		data->sections[SYMBOLS(s).secnum-1].virtual_addr,
    		data->sections[SYMBOLS(s).secnum-1].ptr2_raw_data,
    		SYMBOLS(s).value,
    		data->buffer +
    		data->sections[SYMBOLS(s).secnum-1].virtual_addr -
    		data->sections[SYMBOLS(s).secnum-1].ptr2_raw_data +
    		SYMBOLS(s).value);
    
    	fprintf(stderr,"\n");
    #endif
    
    	  htable_put(global_dlhandle.htable, name, len,
    		     data->buffer +
    		     data->sections[SYMBOLS(s).secnum-1].virtual_addr -
    		     data->sections[SYMBOLS(s).secnum-1].ptr2_raw_data +
    		     SYMBOLS(s).value,
    		     SYMBOLS(s).class != COFF_SYMBOL_WEAK_EXTERN);	   
    
          }
          free(buf);
    
    #ifdef USE_PDB_SYMBOLS
          if(strlen(argv[0]>4)) {
    	char *pdbname = alloca(strlen(argv[0])+1);
    	strcpy(pdbname, argv[0]);
    	strcpy(pdbname+strlen(pdbname)-4, ".PDB");
    	buf= (unsigned char *)read_file(pdb_name, &len);
          } else buf = NULL;
          if(buf) {
    	unsigned char *symtab = find_pdb_symtab(buf, &len);
    	if(symtab) {
    	  size_t i;
    #ifdef DLDEBUG
    	  fprintf(stderr,"Loading PDB symbols (%d bytes)\n", len);
    #endif
    	  for(i=0; i<len; i+=2+*(unsigned INT16 *)&symtab[i])
    	    if(*(unsigned INT16 *)&symtab[i+2] == 0x110e) {
    	      struct {
    		unsigned INT16 len, id;
    		unsigned INT32 type, value;
    		unsigned INT16 secnum;
    		char name[1];
    	      } *sym = (void *)&symtab[i];
    	      int namelen=STRNLEN(sym->name,sym->len-12);
    	      
    #ifdef DLDEBUG
    	      if(!sym->name[namelen])
    		fprintf(stderr,"Sym[%04d] %s : ",s,sym->name);
    	      else
    		fprintf(stderr,"Sym[%04d] %c%c%c%c%c%c%c%c = ",s,
    			sym->name[0],
    			sym->name[1],
    			sym->name[2],
    			sym->name[3],
    			sym->name[4],
    			sym->name[5],
    			sym->name[6],
    			sym->name[7]);
    	      fprintf(stderr,"sect=%d value=%d type=%d",
    		      sym->secnum,
    		      sym->value,
    		      sym->type);
    #endif
    	      htable_put(global_dlhandle.htable, sym->name, namelen,
    			 data->buffer +
    			 data->sections[sym->secnum-1].virtual_addr -
    			 data->sections[sym->secnum-1].ptr2_raw_data +
    			 sym->value,
    			 1 /* Fixme? Weak symbols... */);
    	    }
    	  free(symtab);
    	}
    	free(buf);
          }
    #endif
        }else{
    #ifdef DLDEBUG
          fprintf(stderr,"Couldn't find PE header.\n");
    #endif
          append_dlllist(&global_dlhandle.dlls, argv[0]);
          global_dlhandle.htable=alloc_htable(997);
    #define EXPORT(X) \
      DO_IF_DLDEBUG( fprintf(stderr,"EXP: %s\n",#X); ) \
      htable_put(global_dlhandle.htable, SYMBOL_PREFIX #X, \
    	     sizeof(SYMBOL_PREFIX #X)-sizeof(""), &X, 1)
          
          
          fprintf(stderr,"Fnord, rand()=%d\n",rand());
          EXPORT(fprintf);
          EXPORT(_iob);
          EXPORT(abort);
          EXPORT(rand);
          EXPORT(srand);
        }
    #if 0
    #ifdef _M_IA64
        {
          extern void *_gp[];
          EXPORT(_gp);
        }
    #endif
    #endif /* 0 */
      }
      
      /* FIXME: open argv[0] and check what dlls is it is linked
       *        against and add those to the list
       */
      {
        struct DLHandle *h;
        void *f;
        h=dlopen("./foo.o",0);
        fprintf(stderr,"dlopen(./fnord) => %p\n",h);
        if(h)
        {
          f=dlsym(h,"_func2");
          fprintf(stderr,"dsym(_func2) => %p\n",f);
          if(f)
          {
    	fprintf(stderr,"Calling %p (func1=%p)\n",f,func1);
    	fflush(stderr);
    	((void (*)(void))f)();
          }
        }
      }
    #endif
      exit(0);
    }
    
    
    #endif