Subject: bfd, ld, and dlltool patches
From: [email-masked]

15 Aug 1997 23:56:35 -0700
Approved: [email-masked]
Distribution: cygnus
Message-ID: <[email-masked]>
Original-From: [email-masked]
Original-From: [email-masked]
Original-To: [email-masked]
X-Sun-Charset: US-ASCII
Original-Sender: [email-masked]

OK, well, several people have asked about this..  I had been trying to get
through the layers of red tape around here and get the GNU copyright assignment
straight, but perhaps it is best to send this along anyhow.  I think that
all of the bfd and ld patches are short and simple enough to not cause any
copyright concerns, but the dlltool changes are a little more substantial
(although still not anything much worth all the hassle about, but legal is
legal, I guess)..

Anyhow, with these changes I think that I can link .lib files with gcc produced
binaries except that some .lib modules have segments with communal data
flags that don't seem to be interpreted by ld the same way that Microsoft
must be intending them.  More work needs to be done here...  The patched
dlltool produces dlls that appear to be to be very similar to the Microsoft
dlls, except that Microsoft dlls have all internal filenames the same (the
name of the dll itself) and Microsoft LINK seems to depend on it.
Unfortunately, bfd makes it difficult to produce an archive with internal
files named the same, so I have to figure out something here (setting the
in-memory flag, perhaps?)

At any rate, I don't believe that this solves all of the inter-operability
problems, but it does solve some, I think.  In particular, the dlltool change
does remove the need for the fixup.c kludge to insert the import table
terminator, and it does it the way that the Microsoft .lib files do it, so
I think that that is a win, at least.

So, for what it's worth, here are my patches.  Lucent, being as paranoid as it
is, doesn't have any method for me to make them available as a URL, so I'll
post them to the list once (I know they're large).  If someone feels this is
too large for the list, I'm sorry, but several people have asked for them
and there may be others out there as well, so I think that this is appropriate.
I would suggest looking at all of the changes and make sure that they make
sense to you before applying them, since I was learning how things worked as
I went.  Certainly if somebody sees a bug or a better way to do something, I'd
really appreciate the insight!

marcus hall
-----

*** bfd/orig/coffcode.h	Wed May  7 04:44:57 1997
--- bfd/coffcode.h	Wed Jul 16 08:59:48 1997
***************
*** 390,396
      }
    else if (!strncmp (sec_name, ".stab", 5))
      {
!       styp_flags = STYP_INFO;
      }
  #ifdef COFF_WITH_PE
    else if (!strcmp (sec_name, ".edata"))

--- 390,396 -----
      }
    else if (!strncmp (sec_name, ".stab", 5))
      {
!       styp_flags = STYP_INFO | STYP_NOLOAD;
      }
  #ifdef COFF_WITH_PE
    else if (!strcmp (sec_name, ".edata"))
***************
*** 541,547
  	   || strncmp (name, ".stab", 5) == 0)
      {
  #ifdef COFF_PAGE_SIZE
!       sec_flags |= SEC_DEBUGGING;
  #endif
      }
  #ifdef _LIB

--- 541,547 -----
  	   || strncmp (name, ".stab", 5) == 0)
      {
  #ifdef COFF_PAGE_SIZE
!       sec_flags |= SEC_DEBUGGING | SEC_NEVER_LOAD;
  #endif
      }
  #ifdef _LIB
***************
*** 2610,2615
  
  #endif
  
  #ifdef COFF_IMAGE_WITH_PE
        /* suppress output of the sections if they are null.  ld includes
  	 the bss and data sections even if there is no size assigned

--- 2610,2635 -----
  
  #endif
  
+ #ifdef COFF_WITH_PE
+       /* move alignment into s_flags */
+       switch (current->alignment_power)
+         {
+       case 1:	section.s_flags |= IMAGE_SCN_ALIGN_1BYTES;
+ 	  break;
+       case 2:	section.s_flags |= IMAGE_SCN_ALIGN_2BYTES;
+ 	  break;
+       case 3:	section.s_flags |= IMAGE_SCN_ALIGN_4BYTES;
+ 	  break;
+       case 4:	section.s_flags |= IMAGE_SCN_ALIGN_8BYTES;
+ 	  break;
+       case 5:	section.s_flags |= IMAGE_SCN_ALIGN_16BYTES;
+ 	  break;
+       case 6:	section.s_flags |= IMAGE_SCN_ALIGN_32BYTES;
+ 	  break;
+       case 7:	section.s_flags |= IMAGE_SCN_ALIGN_64BYTES;
+ 	  break;
+         }
+ 
  #ifdef COFF_IMAGE_WITH_PE
        /* suppress output of the sections if they are null.  ld includes
  	 the bss and data sections even if there is no size assigned
***************
*** 2619,2624
  	internal_f.f_nscns--;
        else
  #endif
  	{
  	  SCNHDR buff;
  	  if (coff_swap_scnhdr_out (abfd, &section, &buff) == 0

--- 2639,2645 -----
  	internal_f.f_nscns--;
        else
  #endif
+ #endif
  	{
  	  SCNHDR buff;
  	  if (coff_swap_scnhdr_out (abfd, &section, &buff) == 0
*** bfd/orig/coffgen.c	Tue Apr 15 02:21:58 1997
--- bfd/coffgen.c	Tue Jun 24 10:23:17 1997
***************
*** 911,916
    if (native->u.syment.n_sclass == C_FILE)
      symbol->flags |= BSF_DEBUGGING;
  
    if (symbol->flags & BSF_DEBUGGING
        && bfd_is_abs_section (symbol->section))
      {

--- 911,922 -----
    if (native->u.syment.n_sclass == C_FILE)
      symbol->flags |= BSF_DEBUGGING;
  
+   if (symbol->flags & BSF_SECTION_SYM && coff_data(abfd)->pe)
+     {
+       /* Writing section symbol to PE file */
+       native->u.syment.n_sclass = C_SECTION;
+     }
+ 
    if (symbol->flags & BSF_DEBUGGING
        && bfd_is_abs_section (symbol->section))
      {
*** bfd/orig/cofflink.c	Tue Apr 15 02:21:58 1997
--- bfd/cofflink.c	Wed Jul 16 09:00:14 1997
***************
*** 34,39
  static boolean coff_link_check_ar_symbols
    PARAMS ((bfd *, struct bfd_link_info *, boolean *));
  static boolean coff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *));
  static char *dores_com PARAMS ((char *, bfd *, int));
  static char *get_name PARAMS ((char *, char **));
  static int process_embedded_commands

--- 34,41 -----
  static boolean coff_link_check_ar_symbols
    PARAMS ((bfd *, struct bfd_link_info *, boolean *));
  static boolean coff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *));
+ static asection *coff_get_first_section_of_archive
+   PARAMS ((struct bfd_link_info *, bfd *, CONST char *));
  static char *dores_com PARAMS ((char *, bfd *, int));
  static char *get_name PARAMS ((char *, char **));
  static int process_embedded_commands
***************
*** 2482,2487
  		     + sec->output_offset);
  	      }
  
  	  else if (! info->relocateable)
  	    {
  	      if (! ((*info->callbacks->undefined_symbol)

--- 2484,2510 -----
  		     + sec->output_offset);
  	      }
  
+ 	  else if (coff_data(input_bfd)->pe
+ 		&& h->class == C_SECTION
+ 		&& h->root.type == bfd_link_hash_undefined)
+ 
+ 	    {
+ 	      /* Reference to a section label, currently undefined */
+  	      asection *sec;
+ 
+ 	      sec = coff_get_first_section_of_archive(info,
+ 			h->root.u.undef.abfd,
+ 			h->root.root.string);
+ 	      if (sec == NULL)
+ 		goto undef_sym;
+ 
+               val = (sec->output_section->vma
+ 		     + sec->output_offset
+ 		     + sym->n_value
+ 		     - sec->vma);
+ 
+ 	      }
+ 
  	  else if (! info->relocateable)
  	    {
  undef_sym:
***************
*** 2484,2489
  
  	  else if (! info->relocateable)
  	    {
  	      if (! ((*info->callbacks->undefined_symbol)
  		     (info, h->root.root.string, input_bfd, input_section,
  		      rel->r_vaddr - input_section->vma)))

--- 2507,2513 -----
  
  	  else if (! info->relocateable)
  	    {
+ undef_sym:
  	      if (! ((*info->callbacks->undefined_symbol)
  		     (info, h->root.root.string, input_bfd, input_section,
  		      rel->r_vaddr - input_section->vma)))
***************
*** 2494,2500
        if (info->base_file)
  	{
  	  /* Emit a reloc if the backend thinks it needs it. */
! 	  if (sym && pe_data(output_bfd)->in_reloc_p(output_bfd, howto))
  	    {
  	      /* relocation to a symbol in a section which
  		 isn't absolute - we output the address here 

--- 2518,2525 -----
        if (info->base_file)
  	{
  	  /* Emit a reloc if the backend thinks it needs it. */
! 	  if (sym && pe_data(output_bfd)->in_reloc_p(output_bfd, howto)
! 	   && !(input_section->flags & SEC_NEVER_LOAD))
  	    {
  	      /* relocation to a symbol in a section which
  		 isn't absolute - we output the address here 
***************
*** 2554,2556
    return true;
  }

--- 2579,2612 -----
    return true;
  }
  
+ static asection *
+ coff_get_first_section_of_archive(info, abfd, name)
+      struct bfd_link_info *info;
+      bfd *abfd;
+      CONST char *name;
+ {
+ bfd *sub;
+ asection *sect;
+ asection *rtn = NULL;
+ bfd_vma offset;
+ 
+   /* move abfd to containing archive */
+   if (abfd->my_archive == NULL)
+     return NULL;
+   abfd = abfd->my_archive;
+ 
+   for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) {
+     /* make sure that the bfd comes from the same archive */
+     if (sub->my_archive == NULL
+      || strcmp(abfd->filename, sub->my_archive->filename) )
+       continue;
+ 
+     for (sect = sub->sections; sect != NULL; sect = sect->next) {
+       if (strcmp (sect->name, name))
+ 	continue;
+       if (rtn == NULL || offset > sect->output_offset)
+ 	rtn = sect;
+     }
+   }
+   return rtn;
+ }
*** bfd/orig/peicode.h	Tue Apr 15 02:22:16 1997
--- bfd/peicode.h	Wed Jul 16 09:00:27 1997
***************
*** 493,499
       rather than something useful.  When these symbols are encountered, change
       the value to 0 and the section number to 1 so that they will be handled
       somewhat correctly in the bfd code. */
!   if (in->n_sclass == 0x68) {
      in->n_value = 0x0;
      in->n_scnum = 1;
      /* I have tried setting the class to 3 and using the following to set

--- 493,499 -----
       rather than something useful.  When these symbols are encountered, change
       the value to 0 and the section number to 1 so that they will be handled
       somewhat correctly in the bfd code. */
!   if (in->n_sclass == C_SECTION) {
      in->n_value = 0x0;
  /*    in->n_scnum = 1;*/ /*!*/
      /* I have tried setting the class to 3 and using the following to set
***************
*** 495,501
       somewhat correctly in the bfd code. */
    if (in->n_sclass == 0x68) {
      in->n_value = 0x0;
!     in->n_scnum = 1;
      /* I have tried setting the class to 3 and using the following to set
         the section number.  This will put the address of the pointer to the
         string kernel32.dll at addresses 0 and 0x10 off start of idata section

--- 495,501 -----
       somewhat correctly in the bfd code. */
    if (in->n_sclass == C_SECTION) {
      in->n_value = 0x0;
! /*    in->n_scnum = 1;*/ /*!*/
      /* I have tried setting the class to 3 and using the following to set
         the section number.  This will put the address of the pointer to the
         string kernel32.dll at addresses 0 and 0x10 off start of idata section
***************
*** 844,850
    if (sec != NULL)
      {
        aout->DataDirectory[idx].VirtualAddress = sec->vma - base;
!       aout->DataDirectory[idx].Size = pei_section_data (abfd, sec)->virt_size;
        sec->flags |= SEC_DATA;
      }
  }

--- 844,852 -----
    if (sec != NULL)
      {
        aout->DataDirectory[idx].VirtualAddress = sec->vma - base;
!       if (coff_section_data(abfd, sec) != NULL
! 	&& pei_section_data(abfd, sec) != NULL)
!           aout->DataDirectory[idx].Size = pei_section_data (abfd, sec)->virt_size;
        sec->flags |= SEC_DATA;
      }
  }
***************
*** 1123,1128
        flags = SEC_DATA| IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE;
      else if (strcmp (scnhdr_int->s_name, ".idata") == 0)
        flags = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | SEC_DATA;     
      else if (strcmp (scnhdr_int->s_name, ".rdata") == 0
  	     || strcmp (scnhdr_int->s_name, ".edata") == 0)
        flags =  IMAGE_SCN_MEM_READ | SEC_DATA;     

--- 1125,1132 -----
        flags = SEC_DATA| IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE;
      else if (strcmp (scnhdr_int->s_name, ".idata") == 0)
        flags = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | SEC_DATA;     
+     else if (strncmp (scnhdr_int->s_name, ".idata$", strlen(".idata$")) == 0)
+       flags = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | SEC_DATA;     
      else if (strcmp (scnhdr_int->s_name, ".rdata") == 0
  	     || strcmp (scnhdr_int->s_name, ".edata") == 0)
        flags =  IMAGE_SCN_MEM_READ | SEC_DATA;     
***************
*** 1150,1155
        }
  #endif
  
      bfd_h_put_32(abfd, flags, (bfd_byte *) scnhdr_ext->s_flags);
    }

--- 1154,1162 -----
        }
  #endif
  
+     /* put back alignment info */
+     flags |= scnhdr_int->s_flags & IMAGE_SCN_ALIGN_64BYTES;
+ 
      bfd_h_put_32(abfd, flags, (bfd_byte *) scnhdr_ext->s_flags);
    }
  
*** binutils/orig/dlltool.c	Fri May  2 02:54:19 1997
--- binutils/dlltool.c	Wed Jul 16 09:01:59 1997
***************
*** 1437,1442
    int i;
    export_type *exp;
    dlist_type *dl;
  
    sprintf (outfile, "t%s", exp_name);

--- 1437,1443 -----
    int i;
    export_type *exp;
    dlist_type *dl;
+ static char *xlate (char *);
  
    sprintf (outfile, "t%s", exp_name);
  
***************
*** 1532,1538
        fprintf(f,"%s Export Name Table\n", ASM_C);
        for (i = 0; (exp = d_exports_lexically[i]); i++)
  	if (!exp->noname || show_allnames)
! 	  fprintf (f, "n%d:	%s	\"%s\"\n", exp->ordinal, ASM_TEXT, exp->name);
  
        if (a_list)
  	{

--- 1533,1539 -----
        fprintf(f,"%s Export Name Table\n", ASM_C);
        for (i = 0; (exp = d_exports_lexically[i]); i++)
  	if (!exp->noname || show_allnames)
! 	  fprintf (f, "n%d:	%s	\"%s\"\n", exp->ordinal, ASM_TEXT, xlate(exp->name));
  
        if (a_list)
  	{
***************
*** 1722,1735
  #ifndef DLLTOOL_PPC
  
  #define TEXT 0
! #define DATA 1
! #define BSS 2
! #define IDATA7 3
! #define IDATA5 4
! #define IDATA4 5
! #define IDATA6 6
! #define PDATA 7
! #define RDATA 8
  
  #define NSECS 7

--- 1723,1731 -----
  #ifndef DLLTOOL_PPC
  
  #define TEXT 0
! #define IDATA5 1
! #define IDATA4 2
! #define IDATA6 3
  
  #define NSECS 4
  
***************
*** 1731,1737
  #define PDATA 7
  #define RDATA 8
  
! #define NSECS 7

  static sinfo secdata[NSECS] = 

--- 1727,1733 -----
  #define IDATA4 2
  #define IDATA6 3
  
! #define NSECS 4

  static sinfo secdata[NSECS] = 
***************
*** 1737,1745
  static sinfo secdata[NSECS] = 
  {
    { TEXT,   ".text",    SEC_CODE | SEC_HAS_CONTENTS, 2},
-   { DATA,   ".data",    SEC_DATA,                    2},
-   { BSS,    ".bss",     0,                           2},
-   { IDATA7, ".idata$7", SEC_HAS_CONTENTS,            2},
    { IDATA5, ".idata$5", SEC_HAS_CONTENTS,            2},
    { IDATA4, ".idata$4", SEC_HAS_CONTENTS,            2},
    { IDATA6, ".idata$6", SEC_HAS_CONTENTS,            1}

--- 1733,1738 -----
  static sinfo secdata[NSECS] = 
  {
    { TEXT,   ".text",    SEC_CODE | SEC_HAS_CONTENTS, 2},
    { IDATA5, ".idata$5", SEC_HAS_CONTENTS,            2},
    { IDATA4, ".idata$4", SEC_HAS_CONTENTS,            2},
    { IDATA6, ".idata$6", SEC_HAS_CONTENTS,            1}
***************
*** 1832,1884
       export_type *exp;
       int i;
  {
-   if (0)
-     {
-       FILE *f;
-       char *prefix="d";
-       sprintf (outfile, "%ss%d.s", prefix, i);
-       f = fopen (outfile, FOPEN_WT);
-       fprintf (f, "\t.text\n");
-       fprintf (f, "\t%s\t%s%s\n", ASM_GLOBAL, ASM_PREFIX, exp->name);
-       fprintf (f, "\t%s\t__imp_%s\n", ASM_GLOBAL, exp->name);
-       fprintf (f, "%s%s:\n\t%s\t__imp_%s\n", ASM_PREFIX,
- 	       exp->name, ASM_JUMP, exp->name);
- 
-       fprintf (f, "\t.section\t.idata$7\t%s To force loading of head\n", ASM_C);
-       fprintf (f, "\t%s\t%s\n", ASM_LONG, head_label);
- 
- 
-       fprintf (f,"%s Import Address Table\n", ASM_C);
- 
-       fprintf (f, "\t.section	.idata$5\n");
-       fprintf (f, "__imp_%s:\n", exp->name);
- 
-       dump_iat (f, exp);
- 
-       fprintf (f, "\n%s Import Lookup Table\n", ASM_C);
-       fprintf (f, "\t.section	.idata$4\n");
- 
-       dump_iat (f, exp);
- 
-       if(!exp->noname || show_allnames) 
- 	{
- 	  fprintf (f, "%s Hint/Name table\n", ASM_C);
- 	  fprintf (f, "\t.section	.idata$6\n");
- 	  fprintf (f, "ID%d:\t%s\t%d\n", exp->ordinal, ASM_SHORT, exp->hint);      
- 	  fprintf (f, "\t%s\t\"%s\"\n", ASM_TEXT, xlate (exp->name));
- 	}
- 
-       fclose (f);
- 
- 
-       sprintf (outfile, "-o %ss%d.o %ss%d.s", prefix, i, prefix, i);
- 
-       run (as_name, outfile);
- 
-     }
-   else  /* fnord */
-     {
- 
        bfd *abfd;
  
        asymbol *exp_label;

--- 1825,1830 -----
       export_type *exp;
       int i;
  {
        bfd *abfd;
  
        asymbol *exp_label;
***************
*** 1948,1957
  	 rdata section, the first element of which is a pointer to the
  	 code (..function_name), and the second points to the .toc
        */
!       if (machine == MPPC)
! 	exp_label->section = secdata[RDATA].sec;
!       else
! 	exp_label->section = secdata[TEXT].sec;
  
        exp_label->flags = BSF_GLOBAL;
        exp_label->value = 0;

--- 1894,1904 -----
  	 rdata section, the first element of which is a pointer to the
  	 code (..function_name), and the second points to the .toc
        */
! #ifdef DLLTOOL_PPC
!       exp_label->section = secdata[RDATA].sec;
! #else
!       exp_label->section = secdata[TEXT].sec;
! #endif
  
        exp_label->flags = BSF_GLOBAL;
        exp_label->value = 0;
***************
*** 1959,1965
        ptrs[oidx++] = exp_label;
  
        iname = bfd_make_empty_symbol(abfd);
!       iname->name = make_label ("__imp_", exp->name);
        iname->section = secdata[IDATA5].sec;
        iname->flags = BSF_GLOBAL;
        iname->value = 0;

--- 1906,1912 -----
        ptrs[oidx++] = exp_label;
  
        iname = bfd_make_empty_symbol(abfd);
!       iname->name = make_label ("_imp__", exp->name);
        iname->section = secdata[IDATA5].sec;
        iname->flags = BSF_GLOBAL;
        iname->value = 0;
***************
*** 2029,2035
  		{
  		  rel->howto = bfd_reloc_type_lookup (abfd, 
  						      BFD_RELOC_16_GOTOFF);
- 		  rel->sym_ptr_ptr = iname_pp;
  		}
  	      else
  		{

--- 1976,1981 -----
  		{
  		  rel->howto = bfd_reloc_type_lookup (abfd, 
  						      BFD_RELOC_16_GOTOFF);
  		}
  	      else
  		{
***************
*** 2034,2040
  	      else
  		{
  		  rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
- 		  rel->sym_ptr_ptr = secdata[IDATA5].sympp;
  		}
  	      sec->orelocation = rpp;
  	      sec->reloc_count = 1;

--- 1980,1985 -----
  	      else
  		{
  		  rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
  		}
  	      rel->sym_ptr_ptr = iname_pp;
  	      sec->orelocation = rpp;
***************
*** 2036,2041
  		  rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
  		  rel->sym_ptr_ptr = secdata[IDATA5].sympp;
  		}
  	      sec->orelocation = rpp;
  	      sec->reloc_count = 1;
  	      break;

--- 1981,1987 -----
  		{
  		  rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
  		}
+ 	      rel->sym_ptr_ptr = iname_pp;
  	      sec->orelocation = rpp;
  	      sec->reloc_count = 1;
  	      break;
***************
*** 2082,2087
  		  strcpy (si->data + 2, xlate (exp->name));
  		}
  	      break;
  	    case IDATA7:
  	      si->size = 4;
  	      si->data =xmalloc(4);

--- 2028,2034 -----
  		  strcpy (si->data + 2, xlate (exp->name));
  		}
  	      break;
+ #ifdef DLLTOOL_PPC
  	    case IDATA7:
  	      si->size = 4;
  	      si->data =xmalloc(4);
***************
*** 2205,2210
  	      sec->orelocation = rpp;
  	      sec->reloc_count = 2;
  	      break;
  	    }
  	}

--- 2152,2158 -----
  	      sec->orelocation = rpp;
  	      sec->reloc_count = 2;
  	      break;
+ #endif /*DLLTOOL_PPC*/
  	    }
  	}
  
***************
*** 2243,2249
        return abfd;
      }
  
- }

  static bfd *

--- 2191,2196 -----
        return abfd;
      }

  char import_desc[20];
  char null_thunk[4];
***************
*** 2245,2250
  
  }

  static bfd *
  make_head()

--- 2192,2199 -----
      }

+ char import_desc[20];
+ char null_thunk[4];
  
  static bfd *
  make_head()
***************
*** 2249,2255
  static bfd *
  make_head()
  {
!   FILE *  f = fopen ("dh.s", FOPEN_WT);
  
    fprintf (f, "%s IMAGE_IMPORT_DESCRIPTOR\n", ASM_C);
    fprintf (f, "\t.section	.idata$2\n");

--- 2198,2210 -----
  static bfd *
  make_head()
  {
! bfd *abfd;
! asection *idata2, *idata6;
! asymbol *symarray[7];
! asymbol **sym = symarray;
! asymbol *sym_idata4, *sym_idata5, *sym_idata6;
! arelent **rpp;
! char *str;
  
    abfd = bfd_openw ("dh.o", HOW_BFD_TARGET);
  
***************
*** 2251,2258
  {
    FILE *  f = fopen ("dh.s", FOPEN_WT);
  
!   fprintf (f, "%s IMAGE_IMPORT_DESCRIPTOR\n", ASM_C);
!   fprintf (f, "\t.section	.idata$2\n");
  
    fprintf(f,"\t%s\t%s\n", ASM_GLOBAL,head_label);

--- 2206,2212 -----
  arelent **rpp;
  char *str;
  
!   abfd = bfd_openw ("dh.o", HOW_BFD_TARGET);
  
    if (!abfd)
      {
***************
*** 2254,2260
    fprintf (f, "%s IMAGE_IMPORT_DESCRIPTOR\n", ASM_C);
    fprintf (f, "\t.section	.idata$2\n");
  
!   fprintf(f,"\t%s\t%s\n", ASM_GLOBAL,head_label);
  
    fprintf (f, "%s:\n", head_label);

--- 2208,2221 -----
  
    abfd = bfd_openw ("dh.o", HOW_BFD_TARGET);
  
!   if (!abfd)
!     {
!       fprintf (stderr, "%s: bfd_open failed open output file dh.o\n",
! 		program_name);
!       exit(1);
!     }
!   bfd_set_format (abfd, bfd_object);
!   bfd_set_arch_mach (abfd, HOW_BFD_ARCH, 0);
  
    idata2 = bfd_make_section (abfd, ".idata$2");
    bfd_set_section_flags (abfd, idata2, SEC_HAS_CONTENTS);
***************
*** 2256,2262
  
    fprintf(f,"\t%s\t%s\n", ASM_GLOBAL,head_label);
  
!   fprintf (f, "%s:\n", head_label);
  
    fprintf (f, "\t%shname%s\t%sPtr to image import by name list\n",
  	   ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C);

--- 2217,2226 -----
    bfd_set_format (abfd, bfd_object);
    bfd_set_arch_mach (abfd, HOW_BFD_ARCH, 0);
  
!   idata2 = bfd_make_section (abfd, ".idata$2");
!   bfd_set_section_flags (abfd, idata2, SEC_HAS_CONTENTS);
!   bfd_set_section_alignment (abfd, idata2, 2);
!   idata2->output_section = idata2;
  
    /* label for import descriptor */
    *sym = bfd_make_empty_symbol (abfd);
***************
*** 2258,2265
  
    fprintf (f, "%s:\n", head_label);
  
!   fprintf (f, "\t%shname%s\t%sPtr to image import by name list\n",
! 	   ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C);
  
    fprintf (f, "\t%sthis should be the timestamp, but NT sometimes\n", ASM_C);
    fprintf (f, "\t%sdoesn't load DLLs when this is set.\n", ASM_C);

--- 2222,2234 -----
    bfd_set_section_alignment (abfd, idata2, 2);
    idata2->output_section = idata2;
  
!   /* label for import descriptor */
!   *sym = bfd_make_empty_symbol (abfd);
!   (*sym)->name = head_label;
!   (*sym)->section = idata2;
!   (*sym)->flags = BSF_GLOBAL;
!   (*sym)->value = 0;
!   sym++;
  
    *sym = sym_idata4 = bfd_make_empty_symbol (abfd);
    (*sym)->name = ".idata$4";
***************
*** 2261,2278
    fprintf (f, "\t%shname%s\t%sPtr to image import by name list\n",
  	   ASM_RVA_BEFORE, ASM_RVA_AFTER, ASM_C);
  
!   fprintf (f, "\t%sthis should be the timestamp, but NT sometimes\n", ASM_C);
!   fprintf (f, "\t%sdoesn't load DLLs when this is set.\n", ASM_C);
!   fprintf (f, "\t%s\t0\t%s loaded time\n", ASM_LONG, ASM_C);
!   fprintf (f, "\t%s\t0\t%s Forwarder chain\n", ASM_LONG, ASM_C);
!   fprintf (f, "\t%s__%s_iname%s\t%s imported dll's name\n",
! 	   ASM_RVA_BEFORE,
! 	   imp_name_lab,
! 	   ASM_RVA_AFTER,
! 	   ASM_C);
!   fprintf (f, "\t%sfthunk%s\t%s pointer to firstthunk\n",
! 	   ASM_RVA_BEFORE,
! 	   ASM_RVA_AFTER, ASM_C);
  
    fprintf (f, "%sStuff for compatibility\n", ASM_C);

--- 2230,2241 -----
    (*sym)->value = 0;
    sym++;
  
!   *sym = sym_idata4 = bfd_make_empty_symbol (abfd);
!   (*sym)->name = ".idata$4";
!   (*sym)->section = (asection *)&bfd_und_section;
!   (*sym)->flags = BSF_SECTION_SYM;
!   (*sym)->value = 0xc0000040;
!   sym++;
  
    *sym = sym_idata5 = bfd_make_empty_symbol (abfd);
    (*sym)->name = ".idata$5";
***************
*** 2274,2280
  	   ASM_RVA_BEFORE,
  	   ASM_RVA_AFTER, ASM_C);
  
!   fprintf (f, "%sStuff for compatibility\n", ASM_C);
  
    if (!no_idata5) 
      {

--- 2237,2248 -----
    (*sym)->value = 0xc0000040;
    sym++;
  
!   *sym = sym_idata5 = bfd_make_empty_symbol (abfd);
!   (*sym)->name = ".idata$5";
!   (*sym)->section = (asection *)&bfd_und_section;
!   (*sym)->flags = BSF_SECTION_SYM;
!   (*sym)->value = 0xc0000040;
!   sym++;
  
    /* label for NULL_IMPORT_DESCRIPTOR */
    *sym = bfd_make_empty_symbol (abfd);
***************
*** 2276,2282
  
    fprintf (f, "%sStuff for compatibility\n", ASM_C);
  
!   if (!no_idata5) 
      {
        fprintf (f, "\t.section\t.idata$5\n");
        fprintf (f, "\t%s\t0\n", ASM_LONG);

--- 2244,2335 -----
    (*sym)->value = 0xc0000040;
    sym++;
  
!   /* label for NULL_IMPORT_DESCRIPTOR */
!   *sym = bfd_make_empty_symbol (abfd);
!   (*sym)->name = "__NULL_IMPORT_DESCRIPTOR";
!   (*sym)->section = (asection *)&bfd_und_section;
!   (*sym)->flags = BSF_NO_FLAGS;
!   (*sym)->value = 0;
!   sym++;
! 
!   /* label for NULL_THUNK */
!   str = xmalloc (strlen(imp_name_lab) + 18);
!   str[0] = '\177';
!   strcpy (str+1, imp_name_lab);
!   strcat (str, "_NULL_THUNK_DATA");
!   *sym = bfd_make_empty_symbol (abfd);
!   (*sym)->name = str;
!   (*sym)->section = (asection *)&bfd_und_section;
!   (*sym)->flags = BSF_NO_FLAGS;
!   (*sym)->value = 0;
!   sym++;
! 
!   *sym = sym_idata6 = bfd_make_empty_symbol (abfd);
!   /* name and section filled in later */
!   (*sym)->flags = BSF_LOCAL /*| BSF_SECTION_SYM*/;
!   (*sym)->value = 0;
!   sym++;
! 
!   memset (&import_desc, 0, sizeof (import_desc));
!   bfd_set_section_size (abfd, idata2, sizeof (import_desc));
!   bfd_set_section_vma (abfd, idata2, 0);
! 
!   rpp = xmalloc (sizeof (arelent *) * 4);
!   rpp[0] = xmalloc (sizeof (arelent) * 3);
!   rpp[1] = rpp[0]+1;
!   rpp[2] = rpp[0]+2;
!   rpp[3] = 0;
! 
!   /* Import list pointer */
!   rpp[0]->address = 0;
!   rpp[0]->addend = 0;
!   rpp[0]->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_RVA);
!   rpp[0]->sym_ptr_ptr = &sym_idata4;
! 
!   /* library name pointer */
!   rpp[1]->address = 12;
!   rpp[1]->addend = 0;
!   rpp[1]->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_RVA);
!   rpp[1]->sym_ptr_ptr = &sym_idata6;
! 
!   /* Thunk list pointer */
!   rpp[2]->address = 16;
!   rpp[2]->addend = 0;
!   rpp[2]->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_RVA);
!   rpp[2]->sym_ptr_ptr = &sym_idata5;
! 
!   idata2->reloc_count = 3;
!   idata2->orelocation = rpp;
! 
!   idata6 = bfd_make_section (abfd, ".idata$6");
!   bfd_set_section_flags (abfd, idata6, SEC_HAS_CONTENTS);
!   bfd_set_section_alignment (abfd, idata6, 1);
!   bfd_set_section_size (abfd, idata6, strlen (dll_name)+1);
!   bfd_set_section_vma (abfd, idata6, 0);
!   idata6->output_section = idata6;
!   sym_idata6->name = idata6->name;
!   sym_idata6->section = idata6;
! 
!   /* generate output */
!   bfd_set_section_contents (abfd, idata2, &import_desc, 0,
! 		sizeof (import_desc));
!   bfd_set_section_contents (abfd, idata6, dll_name, 0, strlen(dll_name)+1);
! 
!   bfd_set_symtab (abfd, symarray, sym-symarray);
!   bfd_close (abfd);
! 
!   return  bfd_openr ("dh.o", HOW_BFD_TARGET);
! }
! 
! static bfd *
! make_hterm()
! {
! bfd *abfd;
! asection *idata3;
! asymbol *sym;
! 
!   abfd = bfd_openw ("dht.o", HOW_BFD_TARGET);
!   if (!abfd)
      {
        fprintf (stderr, "%s: bfd_open failed open output file dht.o\n",
  		program_name);
***************
*** 2278,2286
  
    if (!no_idata5) 
      {
!       fprintf (f, "\t.section\t.idata$5\n");
!       fprintf (f, "\t%s\t0\n", ASM_LONG);
!       fprintf (f, "fthunk:\n");
      }
    if (!no_idata4) 
      {

--- 2331,2339 -----
    abfd = bfd_openw ("dht.o", HOW_BFD_TARGET);
    if (!abfd)
      {
!       fprintf (stderr, "%s: bfd_open failed open output file dht.o\n",
! 		program_name);
!       exit(1);
      }
    bfd_set_format (abfd, bfd_object);
    bfd_set_arch_mach (abfd, HOW_BFD_ARCH, 0);
***************
*** 2282,2290
        fprintf (f, "\t%s\t0\n", ASM_LONG);
        fprintf (f, "fthunk:\n");
      }
!   if (!no_idata4) 
!     {
!       fprintf (f, "\t.section\t.idata$4\n");
  
        fprintf (f, "\t%s\t0\n", ASM_LONG);
        fprintf (f, "\t.section	.idata$4\n");

--- 2335,2342 -----
  		program_name);
        exit(1);
      }
!   bfd_set_format (abfd, bfd_object);
!   bfd_set_arch_mach (abfd, HOW_BFD_ARCH, 0);
  
    idata3 = bfd_make_section (abfd, ".idata$3");
    bfd_set_section_flags (abfd, idata3, SEC_HAS_CONTENTS);
***************
*** 2286,2296
      {
        fprintf (f, "\t.section\t.idata$4\n");
  
!       fprintf (f, "\t%s\t0\n", ASM_LONG);
!       fprintf (f, "\t.section	.idata$4\n");
!       fprintf (f, "hname:\n");
!     }
!   fclose (f);
  
    sprintf (outfile, "-o dh.o dh.s");
    run (as_name, outfile);

--- 2338,2347 -----
    bfd_set_format (abfd, bfd_object);
    bfd_set_arch_mach (abfd, HOW_BFD_ARCH, 0);
  
!   idata3 = bfd_make_section (abfd, ".idata$3");
!   bfd_set_section_flags (abfd, idata3, SEC_HAS_CONTENTS);
!   bfd_set_section_alignment (abfd, idata3, 2);
!   idata3->output_section = idata3;
  
    /* label for NULL_IMPORT_DESCRIPTOR */
    sym = bfd_make_empty_symbol (abfd);
***************
*** 2292,2299
      }
    fclose (f);
  
!   sprintf (outfile, "-o dh.o dh.s");
!   run (as_name, outfile);
  
    return  bfd_openr ("dh.o", HOW_BFD_TARGET);  
  }

--- 2343,2354 -----
    bfd_set_section_alignment (abfd, idata3, 2);
    idata3->output_section = idata3;
  
!   /* label for NULL_IMPORT_DESCRIPTOR */
!   sym = bfd_make_empty_symbol (abfd);
!   sym->name = "__NULL_IMPORT_DESCRIPTOR";
!   sym->section = idata3;
!   sym->flags = BSF_GLOBAL;
!   sym->value = 0;
  
    memset (&import_desc, 0, sizeof (import_desc));
    bfd_set_section_size (abfd, idata3, sizeof (import_desc));
***************
*** 2295,2301
    sprintf (outfile, "-o dh.o dh.s");
    run (as_name, outfile);
  
!   return  bfd_openr ("dh.o", HOW_BFD_TARGET);  
  }
  
  static bfd * 

--- 2350,2364 -----
    sym->flags = BSF_GLOBAL;
    sym->value = 0;
  
!   memset (&import_desc, 0, sizeof (import_desc));
!   bfd_set_section_size (abfd, idata3, sizeof (import_desc));
!   bfd_set_section_vma (abfd, idata3, 0);
!   bfd_set_section_contents (abfd, idata3, &import_desc, 0,
! 		sizeof (import_desc));
!   bfd_set_symtab (abfd, &sym, 1);
!   bfd_close (abfd);
! 
!   return  bfd_openr ("dht.o", HOW_BFD_TARGET);  
  }
  
  static bfd * 
***************
*** 2301,2307
  static bfd * 
  make_tail()
  {
!   FILE *  f;
  
    f  = fopen ("dt.s", FOPEN_WT);

--- 2364,2373 -----
  static bfd * 
  make_tail()
  {
! bfd *abfd;
! asection *idata4, *idata5;
! asymbol *sym;
! char *str;
  
    abfd = bfd_openw ("dt.o", HOW_BFD_TARGET);
    if (!abfd)
***************
*** 2303,2311
  {
    FILE *  f;
  
!   f  = fopen ("dt.s", FOPEN_WT);
! 
!   if (!no_idata4) 
      {
        fprintf (f, "\t.section	.idata$4\n");
        fprintf (f, "\t%s\t0\n", ASM_LONG);

--- 2369,2376 -----
  asymbol *sym;
  char *str;
  
!   abfd = bfd_openw ("dt.o", HOW_BFD_TARGET);
!   if (!abfd)
      {
        fprintf (stderr, "%s: bfd_open failed open output file dt.o\n",
  		program_name);
***************
*** 2307,2314
  
    if (!no_idata4) 
      {
!       fprintf (f, "\t.section	.idata$4\n");
!       fprintf (f, "\t%s\t0\n", ASM_LONG);
      }
    if (!no_idata5) 
      {

--- 2372,2380 -----
    abfd = bfd_openw ("dt.o", HOW_BFD_TARGET);
    if (!abfd)
      {
!       fprintf (stderr, "%s: bfd_open failed open output file dt.o\n",
! 		program_name);
!       exit(1);
      }
    bfd_set_format (abfd, bfd_object);
    bfd_set_arch_mach (abfd, HOW_BFD_ARCH, 0);
***************
*** 2310,2320
        fprintf (f, "\t.section	.idata$4\n");
        fprintf (f, "\t%s\t0\n", ASM_LONG);
      }
!   if (!no_idata5) 
!     {
!       fprintf (f, "\t.section	.idata$5\n");
!       fprintf (f, "\t%s\t0\n", ASM_LONG);
!     }
  
  #ifdef DLLTOOL_PPC
    /* Normally, we need to see a null descriptor built in idata$3 to

--- 2376,2383 -----
  		program_name);
        exit(1);
      }
!   bfd_set_format (abfd, bfd_object);
!   bfd_set_arch_mach (abfd, HOW_BFD_ARCH, 0);
  
    idata4 = bfd_make_section (abfd, ".idata$4");
    bfd_set_section_flags (abfd, idata4, SEC_HAS_CONTENTS);
***************
*** 2316,2329
        fprintf (f, "\t%s\t0\n", ASM_LONG);
      }
  
! #ifdef DLLTOOL_PPC
!   /* Normally, we need to see a null descriptor built in idata$3 to
!      act as the terminator for the list. The ideal way, I suppose,
!      would be to mark this section as a comdat type 2 section, so
!      only one would appear in the final .exe (if our linker supported
!      comdat, that is) or cause it to be inserted by something else (say
!      crt0)
!   */
  
    fprintf (f, "\t.section	.idata$3\n");
    fprintf (f, "\t%s\t0\n", ASM_LONG);

--- 2379,2390 -----
    bfd_set_format (abfd, bfd_object);
    bfd_set_arch_mach (abfd, HOW_BFD_ARCH, 0);
  
!   idata4 = bfd_make_section (abfd, ".idata$4");
!   bfd_set_section_flags (abfd, idata4, SEC_HAS_CONTENTS);
!   bfd_set_section_alignment (abfd, idata4, 2);
!   idata4->output_section = idata4;
!   bfd_set_section_size (abfd, idata4, sizeof (null_thunk));
!   bfd_set_section_vma (abfd, idata4, 0);
  
    idata5 = bfd_make_section (abfd, ".idata$5");
    bfd_set_section_flags (abfd, idata5, SEC_HAS_CONTENTS);
***************
*** 2325,2337
       crt0)
    */
  
!   fprintf (f, "\t.section	.idata$3\n");
!   fprintf (f, "\t%s\t0\n", ASM_LONG);
!   fprintf (f, "\t%s\t0\n", ASM_LONG);
!   fprintf (f, "\t%s\t0\n", ASM_LONG);
!   fprintf (f, "\t%s\t0\n", ASM_LONG);
!   fprintf (f, "\t%s\t0\n", ASM_LONG);
! #endif
  
  #ifdef DLLTOOL_PPC
    /* Other PowerPC NT compilers use idata$6 for the dllname, so I

--- 2386,2397 -----
    bfd_set_section_size (abfd, idata4, sizeof (null_thunk));
    bfd_set_section_vma (abfd, idata4, 0);
  
!   idata5 = bfd_make_section (abfd, ".idata$5");
!   bfd_set_section_flags (abfd, idata5, SEC_HAS_CONTENTS);
!   bfd_set_section_alignment (abfd, idata5, 2);
!   idata5->output_section = idata5;
!   bfd_set_section_size (abfd, idata5, sizeof (null_thunk));
!   bfd_set_section_vma (abfd, idata5, 0);
  
    /* label for NULL_THUNK */
    str = xmalloc (strlen(imp_name_lab) + 18);
***************
*** 2333,2345
    fprintf (f, "\t%s\t0\n", ASM_LONG);
  #endif
  
! #ifdef DLLTOOL_PPC
!   /* Other PowerPC NT compilers use idata$6 for the dllname, so I
!      do too. Original, huh? */
!   fprintf (f, "\t.section	.idata$6\n");
! #else
!   fprintf (f, "\t.section	.idata$7\n");
! #endif
  
    fprintf (f, "\t%s\t__%s_iname\n", ASM_GLOBAL, imp_name_lab);
    fprintf (f, "__%s_iname:\t%s\t\"%s\"\n", imp_name_lab, ASM_TEXT, dll_name);

--- 2393,2408 -----
    bfd_set_section_size (abfd, idata5, sizeof (null_thunk));
    bfd_set_section_vma (abfd, idata5, 0);
  
!   /* label for NULL_THUNK */
!   str = xmalloc (strlen(imp_name_lab) + 18);
!   str[0] = '\177';
!   strcpy (str+1, imp_name_lab);
!   strcat (str, "_NULL_THUNK_DATA");
!   sym = bfd_make_empty_symbol (abfd);
!   sym->name = str;
!   sym->section = idata5;
!   sym->flags = BSF_GLOBAL;
!   sym->value = 0;
  
    bfd_set_section_contents (abfd, idata4, &null_thunk, 0, sizeof (null_thunk));
    bfd_set_section_contents (abfd, idata5, &null_thunk, 0, sizeof (null_thunk));
***************
*** 2341,2349
    fprintf (f, "\t.section	.idata$7\n");
  #endif
  
!   fprintf (f, "\t%s\t__%s_iname\n", ASM_GLOBAL, imp_name_lab);
!   fprintf (f, "__%s_iname:\t%s\t\"%s\"\n", imp_name_lab, ASM_TEXT, dll_name);
!   fclose (f);
  
    sprintf (outfile, "-o dt.o dt.s");
    run (as_name, outfile);

--- 2404,2413 -----
    sym->flags = BSF_GLOBAL;
    sym->value = 0;
  
!   bfd_set_section_contents (abfd, idata4, &null_thunk, 0, sizeof (null_thunk));
!   bfd_set_section_contents (abfd, idata5, &null_thunk, 0, sizeof (null_thunk));
!   bfd_set_symtab (abfd, &sym, 1);
!   bfd_close (abfd);
  
    return  bfd_openr ("dt.o", HOW_BFD_TARGET);  
  }
***************
*** 2345,2352
    fprintf (f, "__%s_iname:\t%s\t\"%s\"\n", imp_name_lab, ASM_TEXT, dll_name);
    fclose (f);
  
-   sprintf (outfile, "-o dt.o dt.s");
-   run (as_name, outfile);
    return  bfd_openr ("dt.o", HOW_BFD_TARGET);  
  }

--- 2409,2414 -----
    bfd_set_symtab (abfd, &sym, 1);
    bfd_close (abfd);
  
    return  bfd_openr ("dt.o", HOW_BFD_TARGET);  
  }
  
***************
*** 2356,2361
    int i;
    export_type *exp;
    bfd *ar_head;
    bfd *ar_tail;
    bfd *outarch;
    bfd * head  = 0;

--- 2418,2424 -----
    int i;
    export_type *exp;
    bfd *ar_head;
+   bfd *ar_hterm;
    bfd *ar_tail;
    bfd *outarch;
    bfd * head  = 0;
***************
*** 2377,2384
    /* Work out a reasonable size of things to put onto one line. */

!   ar_head = make_head();
!   ar_tail = make_tail();
  
    for (i = 0; (exp = d_exports_lexically[i]); i++) 
      {

--- 2440,2448 -----
    /* Work out a reasonable size of things to put onto one line. */

!   ar_head = make_head (outarch);
!   ar_hterm = make_hterm (outarch);
!   ar_tail = make_tail(outarch);
  
    for (i = 0; (exp = d_exports_lexically[i]); i++) 
      {
***************
*** 2382,2388
  
    for (i = 0; (exp = d_exports_lexically[i]); i++) 
      {
!       bfd *n = make_one_lib_file (exp, i); /* fnord */
        n->next = head;
        head = n;
      }

--- 2446,2452 -----
  
    for (i = 0; (exp = d_exports_lexically[i]); i++) 
      {
!       bfd *n = make_one_lib_file (exp, i, outarch);
        n->next = head;
        head = n;
      }
***************
*** 2390,2396
    /* Now stick them all into the archive */
  
    ar_head->next = head;
!   ar_tail->next = ar_head;
    head = ar_tail;
  
    bfd_set_archive_head (outarch, head);

--- 2454,2461 -----
    /* Now stick them all into the archive */
  
    ar_head->next = head;
!   ar_hterm->next = ar_head;
!   ar_tail->next = ar_hterm;
    head = ar_tail;
  
    bfd_set_archive_head (outarch, head);
***************
*** 2399,2412
    /* Delete all the temp files */
    if (dontdeltemps == 0)
      {
!       sprintf (outfile, "dh.o");
!       unlink (outfile);
!       sprintf (outfile, "dh.s");
!       unlink (outfile);
!       sprintf (outfile, "dt.o");
!       unlink (outfile);
!       sprintf (outfile, "dt.s");
!       unlink (outfile);
      }
  
    if (dontdeltemps < 2)

--- 2464,2472 -----
    /* Delete all the temp files */
    if (dontdeltemps == 0)
      {
!       unlink ("dh.o");
!       unlink ("dht.o");
!       unlink ("dt.o");
      }
  
    if (dontdeltemps < 2)
***************
*** 2878,2884
  	  if (!isalpha (*p) && !isdigit (*p))
  	    *p = '_';
  	}
!       head_label = make_label("_head_", imp_name_lab);
        gen_lib_file (); 
      }

--- 2938,2944 -----
  	  if (!isalpha (*p) && !isdigit (*p))
  	    *p = '_';
  	}
!       head_label = make_label ("_IMPORT_DESCRIPTOR_", imp_name_lab);
        gen_lib_file (); 
      }
  
***************
*** 2888,2891
    return 0;
  }
  
! 

--- 2948,2954 -----
    return 0;
  }
  
! wwww(char *fmt, int a1, int a2, int a3, int a4, int a5, int a6)
! {
! 	fprintf(stderr, fmt, a1, a2, a3, a4, a5, a6);
! }
-
For help on using this list (especially unsubscribing), send a message to
"[email-masked]" with one line of text: "help".