* coffcode.h (bfd_coff_backend_data): Add _bfd_filnmlen field.
[deliverable/binutils-gdb.git] / bfd / coffcode.h
index 1f393946dcb8965135a463e6fb1f9222094a020d..36bf3e759772b91e89891af358c57d758898bce3 100644 (file)
@@ -131,7 +131,7 @@ SUBSUBSECTION
        moment. To port BFD, that person will have to add more @code{#defines}.
        Three of the bit twiddling routines are exported to
        @code{gdb}; @code{coff_swap_aux_in}, @code{coff_swap_sym_in}
-       and @code{coff_swap_linno_in}. @code{GDB} reads the symbol
+       and @code{coff_swap_lineno_in}. @code{GDB} reads the symbol
        table on its own, but uses BFD to fix things up.  More of the
        bit twiddlers are exported for @code{gas};
        @code{coff_swap_aux_out}, @code{coff_swap_sym_out},
@@ -313,11 +313,12 @@ CODE_FRAGMENT
 #define STRING_SIZE_SIZE (4)
 
 static long sec_to_styp_flags PARAMS ((const char *, flagword));
-static flagword styp_to_sec_flags PARAMS ((bfd *, PTR, const char *));
+static flagword styp_to_sec_flags
+  PARAMS ((bfd *, PTR, const char *, asection *));
 static boolean coff_bad_format_hook PARAMS ((bfd *, PTR));
 static void coff_set_custom_section_alignment
   PARAMS ((bfd *, asection *, const struct coff_section_alignment_entry *,
-          unsigned int));
+          const unsigned int));
 static boolean coff_new_section_hook PARAMS ((bfd *, asection *));
 static boolean coff_set_arch_mach_hook PARAMS ((bfd *, PTR));
 static boolean coff_write_relocs PARAMS ((bfd *, int));
@@ -343,12 +344,13 @@ static PTR coff_mkobject_hook PARAMS ((bfd *, PTR,  PTR));
 \f
 /* void warning(); */
 
-/*
- * Return a word with STYP_* (scnhdr.s_flags) flags set to represent the
- * incoming SEC_* flags.  The inverse of this function is styp_to_sec_flags().
- * NOTE: If you add to/change this routine, you should mirror the changes
- *     in styp_to_sec_flags().
- */
+/* Return a word with STYP_* (scnhdr.s_flags) flags set to represent
+   the incoming SEC_* flags.  The inverse of this function is
+   styp_to_sec_flags().  NOTE: If you add to/change this routine, you
+   should probably mirror the changes in styp_to_sec_flags().  */
+
+#ifndef COFF_WITH_PE
+
 static long
 sec_to_styp_flags (sec_name, sec_flags)
      CONST char *sec_name;
@@ -398,12 +400,6 @@ sec_to_styp_flags (sec_name, sec_flags)
     {
       styp_flags = STYP_INFO;
     }
-#ifdef COFF_WITH_PE
-  else if (!strcmp (sec_name, ".edata"))
-    {
-      styp_flags = STYP_DATA;
-    }
-#endif
 #ifdef RS6000COFF_C
   else if (!strcmp (sec_name, _PAD))
     {
@@ -445,27 +441,93 @@ sec_to_styp_flags (sec_name, sec_flags)
     styp_flags |= STYP_NOLOAD;
 #endif
 
-#ifdef COFF_WITH_PE
-  if (sec_flags & SEC_LINK_ONCE)
+  return styp_flags;
+}
+
+#else /* COFF_WITH_PE */
+
+/* The PE version; see above for the general comments.  The non-PE
+   case seems to be more guessing, and breaks PE format; specifically,
+   .rdata is readonly, but it sure ain't text.  Really, all this
+   should be set up properly in gas (or whatever assembler is in use),
+   and honor whatever objcopy/strip, etc. sent us as input.  */
+
+static long
+sec_to_styp_flags (sec_name, sec_flags)
+     const char *sec_name ATTRIBUTE_UNUSED;
+     flagword sec_flags;
+{
+  long styp_flags = 0;
+
+  /* caution: there are at least three groups of symbols that have
+     very similar bits and meanings: IMAGE_SCN*, SEC_*, and STYP_*.
+     SEC_* are the BFD internal flags, used for generic BFD
+     information.  STYP_* are the COFF section flags which appear in
+     COFF files.  IMAGE_SCN_* are the PE section flags which appear in
+     PE files.  The STYP_* flags and the IMAGE_SCN_* flags overlap,
+     but there are more IMAGE_SCN_* flags.  */
+
+  /* skip LOAD */
+  /* READONLY later */
+  /* skip RELOC */
+  if ((sec_flags & SEC_CODE) != 0)
+    styp_flags |= IMAGE_SCN_CNT_CODE;
+  if ((sec_flags & SEC_DATA) != 0)
+    styp_flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
+  if ((sec_flags & SEC_ALLOC) != 0 && (sec_flags & SEC_LOAD) == 0)
+    styp_flags |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;  /* ==STYP_BSS */
+  /* skip ROM */
+  /* skip CONSTRUCTOR */
+  /* skip CONTENTS */
+#ifdef STYP_NOLOAD
+  if ((sec_flags & (SEC_NEVER_LOAD | SEC_COFF_SHARED_LIBRARY)) != 0)
+    styp_flags |= STYP_NOLOAD;
+#endif
+  if ((sec_flags & SEC_IS_COMMON) != 0)
     styp_flags |= IMAGE_SCN_LNK_COMDAT;
+  if ((sec_flags & SEC_DEBUGGING) != 0)
+    styp_flags |= IMAGE_SCN_MEM_DISCARDABLE;
+  if ((sec_flags & SEC_EXCLUDE) != 0)
+    styp_flags |= IMAGE_SCN_LNK_REMOVE;
+  if ((sec_flags & SEC_NEVER_LOAD) != 0)
+    styp_flags |= IMAGE_SCN_LNK_REMOVE;
+  /* skip IN_MEMORY */
+  /* skip SORT */
+  if (sec_flags & SEC_LINK_ONCE) 
+    styp_flags |= IMAGE_SCN_LNK_COMDAT; 
+  /* skip LINK_DUPLICATES */
+  /* skip LINKER_CREATED */
+
+  /* For now, the read/write bits are mapped onto SEC_READONLY, even
+     though the semantics don't quite match.  The bits from the input
+     are retained in pei_section_data(abfd, section)->pe_flags */
+
+  styp_flags |= IMAGE_SCN_MEM_READ;       /* always readable. */
+  if ((sec_flags & SEC_READONLY) == 0)
+    styp_flags |= IMAGE_SCN_MEM_WRITE;    /* Invert READONLY for write */
+  if (sec_flags & SEC_CODE)
+    styp_flags |= IMAGE_SCN_MEM_EXECUTE;  /* CODE->EXECUTE */
   if (sec_flags & SEC_SHARED)
-    styp_flags |= IMAGE_SCN_MEM_SHARED;
-#endif
+    styp_flags |= IMAGE_SCN_MEM_SHARED;   /* Shared remains meaningful */
 
-  return (styp_flags);
+  return styp_flags; 
 }
-/*
- * Return a word with SEC_* flags set to represent the incoming
- * STYP_* flags (from scnhdr.s_flags).   The inverse of this
- * function is sec_to_styp_flags().
- * NOTE: If you add to/change this routine, you should mirror the changes
- *      in sec_to_styp_flags().
- */
+
+#endif /* COFF_WITH_PE */
+
+/* Return a word with SEC_* flags set to represent the incoming STYP_*
+   flags (from scnhdr.s_flags).  The inverse of this function is
+   sec_to_styp_flags().  NOTE: If you add to/change this routine, you
+   should probably mirror the changes in sec_to_styp_flags().  */
+
+#ifndef COFF_WITH_PE
+
 static flagword
-styp_to_sec_flags (abfd, hdr, name)
+styp_to_sec_flags (abfd, hdr, name, section)
      bfd *abfd ATTRIBUTE_UNUSED;
      PTR hdr;
      const char *name;
+     asection *section ATTRIBUTE_UNUSED;
 {
   struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr;
   long styp_flags = internal_s->s_flags;
@@ -580,13 +642,99 @@ styp_to_sec_flags (abfd, hdr, name)
     }
 #endif /* STYP_SDATA */
 
-#ifdef COFF_WITH_PE
+#if defined (COFF_LONG_SECTION_NAMES) && defined (COFF_SUPPORT_GNU_LINKONCE)
+  /* As a GNU extension, if the name begins with .gnu.linkonce, we
+     only link a single copy of the section.  This is used to support
+     g++.  g++ will emit each template expansion in its own section.
+     The symbols will be defined as weak, so that multiple definitions
+     are permitted.  The GNU linker extension is to actually discard
+     all but one of the sections.  */
+  if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0)
+    sec_flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+#endif
+
+  return sec_flags;
+}
+
+#else /* COFF_WITH_PE */
+
+/* The PE version; see above for the general comments.
+
+   Since to set the SEC_LINK_ONCE and associated flags, we have to
+   look at the symbol table anyway, we return the symbol table index
+   of the symbol being used as the COMDAT symbol.  This is admittedly
+   ugly, but there's really nowhere else that we have access to the
+   required information.  FIXME: Is the COMDAT symbol index used for
+   any purpose other than objdump?  */
+
+static flagword
+styp_to_sec_flags (abfd, hdr, name, section)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     PTR hdr;
+     const char *name;
+     asection *section;
+{
+  struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr;
+  long styp_flags = internal_s->s_flags;
+  flagword sec_flags = 0;
+
+  if (styp_flags & STYP_DSECT)
+    abort ();  /* Don't know what to do */
+#ifdef SEC_NEVER_LOAD
+  if (styp_flags & STYP_NOLOAD)
+    sec_flags |= SEC_NEVER_LOAD;
+#endif
+  if (styp_flags & STYP_GROUP)
+    abort ();  /* Don't know what to do */
+  /* skip IMAGE_SCN_TYPE_NO_PAD */
+  if (styp_flags & STYP_COPY)
+    abort ();  /* Don't know what to do */
+  if (styp_flags & IMAGE_SCN_CNT_CODE)
+    sec_flags |= SEC_CODE | SEC_ALLOC | SEC_LOAD;
+  if (styp_flags & IMAGE_SCN_CNT_INITIALIZED_DATA)
+    sec_flags |= SEC_DATA | SEC_ALLOC | SEC_LOAD;
+  if (styp_flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+    sec_flags |= SEC_ALLOC;
+  if (styp_flags & IMAGE_SCN_LNK_OTHER)
+    abort ();  /* Don't know what to do */
+  if (styp_flags & IMAGE_SCN_LNK_INFO)
+    {
+      /* We mark these as SEC_DEBUGGING, but only if COFF_PAGE_SIZE is
+        defined.  coff_compute_section_file_positions uses
+        COFF_PAGE_SIZE to ensure that the low order bits of the
+        section VMA and the file offset match.  If we don't know
+        COFF_PAGE_SIZE, we can't ensure the correct correspondence,
+        and demand page loading of the file will fail.  */
+#ifdef COFF_PAGE_SIZE
+      sec_flags |= SEC_DEBUGGING;
+#endif
+    }
+  if (styp_flags & STYP_OVER)
+    abort ();  /* Don't know what to do */
   if (styp_flags & IMAGE_SCN_LNK_REMOVE)
     sec_flags |= SEC_EXCLUDE;
 
   if (styp_flags & IMAGE_SCN_MEM_SHARED)
     sec_flags |= SEC_SHARED;
-
+  /* COMDAT: see below */
+  if (styp_flags & IMAGE_SCN_MEM_DISCARDABLE)
+    sec_flags |= SEC_DEBUGGING;
+  if (styp_flags & IMAGE_SCN_MEM_NOT_CACHED)
+    abort ();/* Don't know what to do */
+  if (styp_flags & IMAGE_SCN_MEM_NOT_PAGED)
+    abort (); /* Don't know what to do */
+
+  /* We infer from the distinct read/write/execute bits the settings
+     of some of the bfd flags; the actual values, should we need them,
+     are also in pei_section_data (abfd, section)->pe_flags.  */
+
+  if (styp_flags & IMAGE_SCN_MEM_EXECUTE)
+    sec_flags |= SEC_CODE;   /* Probably redundant */
+  /* IMAGE_SCN_MEM_READ is simply ignored, assuming it always to be true. */
+  if ((styp_flags & IMAGE_SCN_MEM_WRITE) == 0)
+    sec_flags |= SEC_READONLY;
+
+  /* COMDAT gets very special treatment.  */
   if (styp_flags & IMAGE_SCN_LNK_COMDAT)
     {
       sec_flags |= SEC_LINK_ONCE;
@@ -600,20 +748,26 @@ styp_to_sec_flags (abfd, hdr, name)
 
       /* COMDAT sections are special.  The first symbol is the section
         symbol, which tells what kind of COMDAT section it is.  The
-        *second* symbol is the "comdat symbol" - the one with the
+        second symbol is the "comdat symbol" - the one with the
         unique name.  GNU uses the section symbol for the unique
         name; MS uses ".text" for every comdat section.  Sigh.  - DJ */
 
+      /* This is not mirrored in sec_to_styp_flags(), but there
+        doesn't seem to be a need to, either, and it would at best be
+        rather messy.  */
+
       if (_bfd_coff_get_external_symbols (abfd))
        {
-         bfd_byte *esym, *esymend;
+         bfd_byte *esymstart, *esym, *esymend;
 
-         esym = (bfd_byte *) obj_coff_external_syms (abfd);
+         esymstart = esym = (bfd_byte *) obj_coff_external_syms (abfd);
          esymend = esym + obj_raw_syment_count (abfd) * SYMESZ;
 
          while (esym < esymend)
            {
              struct internal_syment isym;
+             char buf[SYMNMLEN + 1];
+             const char *symname;
 
              bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &isym);
 
@@ -624,21 +778,37 @@ styp_to_sec_flags (abfd, hdr, name)
                  abort ();
                }
 
-             if (isym.n_sclass == C_STAT
+             /* The MS documentation is vague, but it appears to
+                require that n_sclass be C_STAT for both entries;
+                However, the Alpha compiler uses C_EXT for the one
+                with the "real" name, at least for string-pooled
+                constants.  */
+             if (isym.n_scnum == section->target_index
+                 && (isym.n_sclass == C_STAT || isym.n_sclass == C_EXT)
                  && isym.n_type == T_NULL
-                 && isym.n_numaux == 1)
+                 && isym.n_value == 0)
                {
-                 char buf[SYMNMLEN + 1];
-                 const char *symname;
-
-                 symname = _bfd_coff_internal_syment_name (abfd, &isym, buf);
-                 if (symname == NULL)
-                   abort ();
-
-                 if (strcmp (name, symname) == 0)
+                 /* The first TWO entries with the section # are both
+                    of interest to us.  The first one is the "section
+                    symbol" (section name).  The second is the comdat
+                    symbol name.  'value' must be zero for it to
+                    apply.  Here, we've found a qualifying entry; we
+                    distinguish the first from the second by numaux
+                    (which should be 0 for the second).  FIXME: We
+                    should use the first one first rather than
+                    counting on numaux.  */
+                 if (isym.n_numaux == 1)
                    {
                      union internal_auxent aux;
 
+                     symname = _bfd_coff_internal_syment_name (abfd, &isym,
+                                                               buf);
+                     if (symname == NULL)
+                       abort ();
+
+                     if (strcmp (name, symname) != 0)
+                       abort ();
+
                      /* This is the section symbol.  */
 
                      bfd_coff_swap_aux_in (abfd, (PTR) (esym + SYMESZ),
@@ -652,19 +822,19 @@ styp_to_sec_flags (abfd, hdr, name)
                         the right thing, we are temporarily disabling
                         comdats for the MS types (they're used in
                         DLLs and C++, but we don't support *their*
-                        C++ libraries anyway - DJ */
+                        C++ libraries anyway - DJ */
 
                      switch (aux.x_scn.x_comdat)
                        {
                        case IMAGE_COMDAT_SELECT_NODUPLICATES:
-#if 0
+/* FIXME: This is bogus.  It breaks cross-compilers.  */
+#ifdef __INTERIX
                          sec_flags |= SEC_LINK_DUPLICATES_ONE_ONLY;
 #else
                          sec_flags &= ~SEC_LINK_ONCE;
 #endif
                          break;
 
-                       default:
                        case IMAGE_COMDAT_SELECT_ANY:
                          sec_flags |= SEC_LINK_DUPLICATES_DISCARD;
                          break;
@@ -674,18 +844,51 @@ styp_to_sec_flags (abfd, hdr, name)
                          break;
 
                        case IMAGE_COMDAT_SELECT_EXACT_MATCH:
+                         /* Not yet fully implemented in the linker.  */
                          sec_flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS;
                          break;
 
                        case IMAGE_COMDAT_SELECT_ASSOCIATIVE:
-#if 0
+/* FIXME: This is bogus.  It breaks cross-compilers.  */
+#ifdef __INTERIX
                          /* FIXME: This is not currently implemented.  */
                          sec_flags |= SEC_LINK_DUPLICATES_DISCARD;
 #else
                          sec_flags &= ~SEC_LINK_ONCE;
 #endif
                          break;
+
+                       default:
+                         /* FIXME: Shouldn't this be at least a
+                             warning?  */
+                         sec_flags |= SEC_LINK_DUPLICATES_DISCARD;
+                         break;
                        }
+                   }
+                 else 
+                   {
+                     char *newname;
+
+                     /* This should be the the second symbol with the
+                        section #.  It is the actual symbol name.
+                        Intel puts the two adjacent, but Alpha (at
+                        least) spreads them out.  */
+
+                     section->comdat =
+                       bfd_alloc (abfd, sizeof (struct bfd_comdat_info));
+                     if (section->comdat == NULL)
+                       abort ();
+                     section->comdat->symbol = (esym - esymstart) / SYMESZ;
+                     symname = _bfd_coff_internal_syment_name (abfd, &isym,
+                                                               buf);
+                     if (symname == NULL)
+                       abort ();
+
+                     newname = bfd_alloc (abfd, strlen (symname) + 1);
+                     if (newname == NULL)
+                       abort ();
+                     strcpy (newname, symname);
+                     section->comdat->name = newname;
 
                      break;
                    }
@@ -695,7 +898,6 @@ styp_to_sec_flags (abfd, hdr, name)
            }
        }
     }
-#endif
 
 #if defined (COFF_LONG_SECTION_NAMES) && defined (COFF_SUPPORT_GNU_LINKONCE)
   /* As a GNU extension, if the name begins with .gnu.linkonce, we
@@ -708,9 +910,11 @@ styp_to_sec_flags (abfd, hdr, name)
     sec_flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
 #endif
 
-  return (sec_flags);
+  return sec_flags;
 }
 
+#endif /* COFF_WITH_PE */
+
 #define        get_index(symbol)       ((symbol)->udata.i)
 
 /*
@@ -810,6 +1014,7 @@ dependent COFF routines:
 . unsigned int _bfd_auxesz;
 . unsigned int _bfd_relsz;
 . unsigned int _bfd_linesz;
+. unsigned int _bfd_filnmlen;
 . boolean _bfd_coff_long_filenames;
 . boolean _bfd_coff_long_section_names;
 . unsigned int _bfd_coff_default_section_alignment_power;
@@ -842,7 +1047,8 @@ dependent COFF routines:
 . flagword (*_bfd_styp_to_sec_flags_hook) PARAMS ((
 .       bfd     *abfd,
 .       PTR     internal_scnhdr,
-.       const char *name));
+.       const char *name,
+.       asection *section));
 . void (*_bfd_set_alignment_hook) PARAMS ((
 .       bfd     *abfd,
 .       asection *sec,
@@ -970,6 +1176,7 @@ dependent COFF routines:
 .#define bfd_coff_auxesz(abfd) (coff_backend_info (abfd)->_bfd_auxesz)
 .#define bfd_coff_relsz(abfd)  (coff_backend_info (abfd)->_bfd_relsz)
 .#define bfd_coff_linesz(abfd) (coff_backend_info (abfd)->_bfd_linesz)
+.#define bfd_coff_filnmlen(abfd) (coff_backend_info (abfd)->_bfd_filnmlen)
 .#define bfd_coff_long_filenames(abfd) (coff_backend_info (abfd)->_bfd_coff_long_filenames)
 .#define bfd_coff_long_section_names(abfd) \
 .        (coff_backend_info (abfd)->_bfd_coff_long_section_names)
@@ -995,8 +1202,9 @@ dependent COFF routines:
 .#define bfd_coff_mkobject_hook(abfd, filehdr, aouthdr)\
 .        ((coff_backend_info (abfd)->_bfd_coff_mkobject_hook) (abfd, filehdr, aouthdr))
 .
-.#define bfd_coff_styp_to_sec_flags_hook(abfd, scnhdr, name)\
-.        ((coff_backend_info (abfd)->_bfd_styp_to_sec_flags_hook) (abfd, scnhdr, name))
+.#define bfd_coff_styp_to_sec_flags_hook(abfd, scnhdr, name, section)\
+.        ((coff_backend_info (abfd)->_bfd_styp_to_sec_flags_hook)\
+.         (abfd, scnhdr, name, section))
 .
 .#define bfd_coff_set_alignment_hook(abfd, sec, scnhdr)\
 .        ((coff_backend_info (abfd)->_bfd_set_alignment_hook) (abfd, sec, scnhdr))
@@ -1281,38 +1489,34 @@ coff_set_alignment_hook (abfd, section, scnhdr)
     }
 #endif
 
-#ifdef COFF_IMAGE_WITH_PE
   /* In a PE image file, the s_paddr field holds the virtual size of a
-     section, while the s_size field holds the raw size.  */
-  if (hdr->s_paddr != 0)
+     section, while the s_size field holds the raw size.  We also keep
+     the original section flag value, since not every bit can be
+     mapped onto a generic BFD section bit.  */
+  if (coff_section_data (abfd, section) == NULL)
     {
-      if (coff_section_data (abfd, section) == NULL)
+      section->used_by_bfd =
+       (PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata));
+      if (section->used_by_bfd == NULL)
        {
-         section->used_by_bfd =
-           (PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata));
-         if (section->used_by_bfd == NULL)
-           {
-             /* FIXME: Return error.  */
-             abort ();
-           }
+         /* FIXME: Return error.  */
+         abort ();
        }
-      if (pei_section_data (abfd, section) == NULL)
+    }
+  if (pei_section_data (abfd, section) == NULL)
+    {
+      coff_section_data (abfd, section)->tdata =
+       (PTR) bfd_zalloc (abfd, sizeof (struct pei_section_tdata));
+      if (coff_section_data (abfd, section)->tdata == NULL)
        {
-         coff_section_data (abfd, section)->tdata =
-           (PTR) bfd_zalloc (abfd, sizeof (struct pei_section_tdata));
-         if (coff_section_data (abfd, section)->tdata == NULL)
-           {
-             /* FIXME: Return error.  */
-             abort ();
-           }
+         /* FIXME: Return error.  */
+         abort ();
        }
-      pei_section_data (abfd, section)->virt_size = hdr->s_paddr;
     }
-#endif
+  pei_section_data (abfd, section)->virt_size = hdr->s_paddr;
+  pei_section_data (abfd, section)->pe_flags = hdr->s_flags;
 
-#ifdef COFF_WITH_PE
   section->lma = hdr->s_vaddr;
-#endif
 }
 #undef ALIGN_SET
 #undef ELIFALIGN_SET
@@ -2309,6 +2513,30 @@ coff_set_arch_mach (abfd, arch, machine)
   return true;                 /* We're easy ... */
 }
 
+#ifdef COFF_IMAGE_WITH_PE
+
+/* This is used to sort sections by VMA, as required by PE image
+   files.  */
+
+static int sort_by_secaddr PARAMS ((const PTR, const PTR));
+
+static int
+sort_by_secaddr (arg1, arg2)
+     const PTR arg1;
+     const PTR arg2;
+{
+  const asection *a = *(const asection **) arg1;
+  const asection *b = *(const asection **) arg2;
+
+  if (a->vma < b->vma)
+    return -1;
+  else if (a->vma > b->vma)
+    return 1;
+  else
+    return 0;
+}
+
+#endif /* COFF_IMAGE_WITH_PE */
 
 /* Calculate the file position for each section. */
 
@@ -2327,7 +2555,6 @@ coff_compute_section_file_positions (abfd)
   asection *previous = (asection *) NULL;
   file_ptr sofar = FILHSZ;
   boolean align_adjust;
-  unsigned int count;
 #ifdef ALIGN_SECTIONS_IN_FILE
   file_ptr old_sofar;
 #endif
@@ -2411,30 +2638,114 @@ coff_compute_section_file_positions (abfd)
       sofar += SCNHSZ;
 #endif
 
+#ifdef COFF_IMAGE_WITH_PE
+  {
+    /* PE requires the sections to be in memory order when listed in
+       the section headers.  It also does not like empty loadable
+       sections.  The sections apparently do not have to be in the
+       right order in the image file itself, but we do need to get the
+       target_index values right.  */
+
+    int count;
+    asection **section_list;
+    int i;
+    int target_index;
+
+    count = 0;
+    for (current = abfd->sections; current != NULL; current = current->next)
+      ++count;
+
+    /* We allocate an extra cell to simplify the final loop.  */
+    section_list = bfd_malloc (sizeof (struct asection *) * (count + 1));
+    if (section_list == NULL)
+      return false;
+
+    i = 0;
+    for (current = abfd->sections; current != NULL; current = current->next)
+      {
+       section_list[i] = current;
+       ++i;
+      }
+    section_list[i] = NULL;
+
+    qsort (section_list, count, sizeof (asection *), sort_by_secaddr);
+
+    /* Rethread the linked list into sorted order; at the same time,
+       assign target_index values.  */
+    target_index = 1;
+    abfd->sections = section_list[0];
+    for (i = 0; i < count; i++)
+      {
+       current = section_list[i];
+       current->next = section_list[i + 1];
+
+       /* Later, if the section has zero size, we'll be throwing it
+          away, so we don't want to number it now.  Note that having
+          a zero size and having real contents are different
+          concepts: .bss has no contents, but (usually) non-zero
+          size.  */
+       if (current->_raw_size == 0)
+         {
+           /* Discard.  However, it still might have (valid) symbols
+              in it, so arbitrarily set it to section 1 (indexing is
+              1-based here; usually .text).  __end__ and other
+              contents of .endsection really have this happen.
+              FIXME: This seems somewhat dubious.  */
+           current->target_index = 1;
+         }
+       else
+         current->target_index = target_index++;
+      }
+
+    free (section_list);
+  }
+#else /* ! COFF_IMAGE_WITH_PE */
+  {
+    /* Set the target_index field.  */
+    int target_index;
+
+    target_index = 1;
+    for (current = abfd->sections; current != NULL; current = current->next)
+      current->target_index = target_index++;
+  }
+#endif /* ! COFF_IMAGE_WITH_PE */
+
   align_adjust = false;
-  for (current = abfd->sections, count = 1;
+  for (current = abfd->sections;
        current != (asection *) NULL;
-       current = current->next, ++count)
+       current = current->next)
     {
 #ifdef COFF_IMAGE_WITH_PE
-      /* The NT loader does not want empty section headers, so we omit
-         them.  We don't actually remove the section from the BFD,
-         although we probably should.  This matches code in
-         coff_write_object_contents.  */
-      if (current->_raw_size == 0)
+      /* With PE we have to pad each section to be a multiple of its
+        page size too, and remember both sizes.  */
+      if (coff_section_data (abfd, current) == NULL)
+       {
+         current->used_by_bfd =
+           (PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata));
+         if (current->used_by_bfd == NULL)
+           return false;
+       }
+      if (pei_section_data (abfd, current) == NULL)
        {
-         current->target_index = -1;
-         --count;
-         continue;
+         coff_section_data (abfd, current)->tdata =
+           (PTR) bfd_zalloc (abfd, sizeof (struct pei_section_tdata));
+         if (coff_section_data (abfd, current)->tdata == NULL)
+           return false;
        }
+      if (pei_section_data (abfd, current)->virt_size == 0)
+       pei_section_data (abfd, current)->virt_size = current->_raw_size;
 #endif
 
-      current->target_index = count;
-
-      /* Only deal with sections which have contents */
+      /* Only deal with sections which have contents.  */
       if (!(current->flags & SEC_HAS_CONTENTS))
        continue;
 
+#ifdef COFF_IMAGE_WITH_PE
+      /* Make sure we skip empty sections in a PE image.  */
+      if (current->_raw_size == 0)
+       continue;
+#endif
+
       /* Align the sections in the file to the same boundary on
         which they are aligned in virtual memory.  I960 doesn't
         do this (FIXME) so we can stay in sync with Intel.  960
@@ -2465,26 +2776,7 @@ coff_compute_section_file_positions (abfd)
       current->filepos = sofar;
 
 #ifdef COFF_IMAGE_WITH_PE
-      /* With PE we have to pad each section to be a multiple of its
-        page size too, and remember both sizes.  */
-
-      if (coff_section_data (abfd, current) == NULL)
-       {
-         current->used_by_bfd =
-           (PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata));
-         if (current->used_by_bfd == NULL)
-           return false;
-       }
-      if (pei_section_data (abfd, current) == NULL)
-       {
-         coff_section_data (abfd, current)->tdata =
-           (PTR) bfd_zalloc (abfd, sizeof (struct pei_section_tdata));
-         if (coff_section_data (abfd, current)->tdata == NULL)
-           return false;
-       }
-      if (pei_section_data (abfd, current)->virt_size == 0)
-       pei_section_data (abfd, current)->virt_size = current->_raw_size;
-
+      /* Set the padded size.  */
       current->_raw_size = (current->_raw_size + page_size -1) & -page_size;
 #endif
 
@@ -2749,7 +3041,7 @@ coff_write_object_contents (abfd)
 
 #ifdef COFF_LONG_SECTION_NAMES
       /* Handle long section names as in PE.  This must be compatible
-         with the code in coff_write_symbols.  */
+         with the code in coff_write_symbols and _bfd_coff_final_link.  */
       {
        size_t len;
 
@@ -2844,10 +3136,11 @@ coff_write_object_contents (abfd)
 #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
-        to them.  NT loader doesn't like it if these section headers are
-        included if the sections themselves are not needed */
+      /* Suppress output of the sections if they are null.  ld
+        includes the bss and data sections even if there is no size
+        assigned to them.  NT loader doesn't like it if these section
+        headers are included if the sections themselves are not
+        needed.  See also coff_compute_section_file_positions.  */
       if (section.s_size == 0)
        internal_f.f_nscns--;
       else
@@ -3016,11 +3309,12 @@ coff_write_object_contents (abfd)
   if (abfd->flags & EXEC_P)
     internal_f.f_flags |= F_EXEC;
 
-  /* FIXME: this is wrong for PPC_PE! */
+#ifndef COFF_WITH_PE
   if (bfd_little_endian (abfd))
     internal_f.f_flags |= F_AR32WR;
   else
     internal_f.f_flags |= F_AR32W;
+#endif
 
 #ifdef TIC80_TARGET_ID
   internal_f.f_target_id = TIC80_TARGET_ID;
@@ -3472,6 +3766,9 @@ SUBSUBSECTION
        base of the line number information for the table is stored in
        the symbol associated with the function.
 
+       Note: The PE format uses line number 0 for a flag indicating a
+       new source file.
+
        The information is copied from the external to the internal
        table, and each symbol which marks a function is marked by
        pointing its...
@@ -3561,6 +3858,10 @@ coff_slurp_line_table (abfd, asect)
   return true;
 }
 
+/* Slurp in the symbol table, converting it to generic form.  Note
+   that if coff_relocate_section is defined, the linker will read
+   symbols via coff_link_add_symbols, rather than via this routine.  */
+
 static boolean
 coff_slurp_symbol_table (abfd)
      bfd * abfd;
@@ -3726,7 +4027,7 @@ coff_slurp_symbol_table (abfd)
             case C_THUMBSTATFUNC:/* Thumb static function        */
 #endif
            case C_LABEL:       /* label                         */
-             if (src->u.syment.n_scnum == -2)
+             if (src->u.syment.n_scnum == N_DEBUG)
                dst->symbol.flags = BSF_DEBUGGING;
              else
                dst->symbol.flags = BSF_LOCAL;
@@ -3854,6 +4155,13 @@ coff_slurp_symbol_table (abfd)
              break;
 
            case C_NULL:
+             /* PE DLLs sometimes have zeroed out symbols for some
+                 reason.  Just ignore them without a warning.  */
+             if (src->u.syment.n_type == 0
+                 && src->u.syment.n_value == 0
+                 && src->u.syment.n_scnum == 0)
+               break;
+             /* Fall through.  */
            case C_EXTDEF:      /* external definition           */
            case C_ULABEL:      /* undefined label               */
            case C_USTATIC:     /* undefined static              */
@@ -4269,6 +4577,7 @@ dummy_reloc16_estimate (abfd, input_section, reloc, shrink, link_info)
      struct bfd_link_info *link_info ATTRIBUTE_UNUSED;
 {
   abort ();
+  return 0;
 }
 
 #endif
@@ -4406,16 +4715,14 @@ coff_final_link_postscript (abfd, pfinfo)
 #define coff_SWAP_scnhdr_in coff_swap_scnhdr_in
 #endif
 
-
-
-static CONST bfd_coff_backend_data bfd_coff_std_swap_table =
+static const bfd_coff_backend_data bfd_coff_std_swap_table =
 {
   coff_SWAP_aux_in, coff_SWAP_sym_in, coff_SWAP_lineno_in,
   coff_SWAP_aux_out, coff_SWAP_sym_out,
   coff_SWAP_lineno_out, coff_SWAP_reloc_out,
   coff_SWAP_filehdr_out, coff_SWAP_aouthdr_out,
   coff_SWAP_scnhdr_out,
-  FILHSZ, AOUTSZ, SCNHSZ, SYMESZ, AUXESZ, RELSZ, LINESZ,
+  FILHSZ, AOUTSZ, SCNHSZ, SYMESZ, AUXESZ, RELSZ, LINESZ, FILNMLEN,
 #ifdef COFF_LONG_FILENAMES
   true,
 #else
@@ -4506,95 +4813,99 @@ static CONST bfd_coff_backend_data bfd_coff_std_swap_table =
 #endif
 
 #define CREATE_BIG_COFF_TARGET_VEC(VAR, NAME, EXTRA_O_FLAGS, EXTRA_S_FLAGS, UNDER, ALTERNATIVE)        \
-const bfd_target VAR =                                                                         \
-{                                                                                              \
-  NAME ,                                                                                       \
-  bfd_target_coff_flavour,                                                                     \
-  BFD_ENDIAN_BIG,              /* data byte order is big */                                    \
-  BFD_ENDIAN_BIG,              /* header byte order is big */                                  \
-  /* object flags */                                                                           \
-  (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG |                                               \
-   HAS_SYMS | HAS_LOCALS | WP_TEXT | EXTRA_O_FLAGS),                                           \
-  /* section flags */                                                                          \
-  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | EXTRA_S_FLAGS),                       \
-  UNDER,                       /* leading symbol underscore */                                 \
-  '/',                         /* ar_pad_char */                                               \
-  15,                          /* ar_max_namelen */                                            \
-                                                                                               \
-  /* Data conversion functions.  */                                                            \
-  bfd_getb64, bfd_getb_signed_64, bfd_putb64,                                                  \
-  bfd_getb32, bfd_getb_signed_32, bfd_putb32,                                                  \
-  bfd_getb16, bfd_getb_signed_16, bfd_putb16,                                                  \
-                                                                                               \
-  /* Header conversion functions.  */                                                          \
-  bfd_getb64, bfd_getb_signed_64, bfd_putb64,                                                  \
-  bfd_getb32, bfd_getb_signed_32, bfd_putb32,                                                  \
-  bfd_getb16, bfd_getb_signed_16, bfd_putb16,                                                  \
-                                                                                               \
-       /* bfd_check_format */                                                                  \
-  { _bfd_dummy_target, coff_object_p, bfd_generic_archive_p, _bfd_dummy_target },              \
-       /* bfd_set_format */                                                                    \
-  { bfd_false, coff_mkobject, _bfd_generic_mkarchive, bfd_false },                             \
-       /* bfd_write_contents */                                                                \
-  { bfd_false, coff_write_object_contents, _bfd_write_archive_contents, bfd_false },           \
-                                                                                               \
-  BFD_JUMP_TABLE_GENERIC (coff),                                                               \
-  BFD_JUMP_TABLE_COPY (coff),                                                                  \
-  BFD_JUMP_TABLE_CORE (_bfd_nocore),                                                           \
-  BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),                                                  \
-  BFD_JUMP_TABLE_SYMBOLS (coff),                                                               \
-  BFD_JUMP_TABLE_RELOCS (coff),                                                                        \
-  BFD_JUMP_TABLE_WRITE (coff),                                                                 \
-  BFD_JUMP_TABLE_LINK (coff),                                                                  \
-  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),                                                     \
-                                                                                               \
-  ALTERNATIVE,                                                                                 \
-                                                                                               \
-  COFF_SWAP_TABLE                                                                              \
+const bfd_target VAR =                                                 \
+{                                                                      \
+  NAME ,                                                               \
+  bfd_target_coff_flavour,                                             \
+  BFD_ENDIAN_BIG,              /* data byte order is big */            \
+  BFD_ENDIAN_BIG,              /* header byte order is big */          \
+  /* object flags */                                                   \
+  (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG |                       \
+   HAS_SYMS | HAS_LOCALS | WP_TEXT | EXTRA_O_FLAGS),                   \
+  /* section flags */                                                  \
+  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | EXTRA_S_FLAGS),\
+  UNDER,                       /* leading symbol underscore */         \
+  '/',                         /* ar_pad_char */                       \
+  15,                          /* ar_max_namelen */                    \
+                                                                       \
+  /* Data conversion functions.  */                                    \
+  bfd_getb64, bfd_getb_signed_64, bfd_putb64,                          \
+  bfd_getb32, bfd_getb_signed_32, bfd_putb32,                          \
+  bfd_getb16, bfd_getb_signed_16, bfd_putb16,                          \
+                                                                       \
+  /* Header conversion functions.  */                                  \
+  bfd_getb64, bfd_getb_signed_64, bfd_putb64,                          \
+  bfd_getb32, bfd_getb_signed_32, bfd_putb32,                          \
+  bfd_getb16, bfd_getb_signed_16, bfd_putb16,                          \
+                                                                       \
+       /* bfd_check_format */                                          \
+  { _bfd_dummy_target, coff_object_p, bfd_generic_archive_p,           \
+    _bfd_dummy_target },                                               \
+       /* bfd_set_format */                                            \
+  { bfd_false, coff_mkobject, _bfd_generic_mkarchive, bfd_false },     \
+       /* bfd_write_contents */                                        \
+  { bfd_false, coff_write_object_contents, _bfd_write_archive_contents,        \
+    bfd_false },                                                       \
+                                                                       \
+  BFD_JUMP_TABLE_GENERIC (coff),                                       \
+  BFD_JUMP_TABLE_COPY (coff),                                          \
+  BFD_JUMP_TABLE_CORE (_bfd_nocore),                                   \
+  BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),                          \
+  BFD_JUMP_TABLE_SYMBOLS (coff),                                       \
+  BFD_JUMP_TABLE_RELOCS (coff),                                                \
+  BFD_JUMP_TABLE_WRITE (coff),                                         \
+  BFD_JUMP_TABLE_LINK (coff),                                          \
+  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),                             \
+                                                                       \
+  ALTERNATIVE,                                                         \
+                                                                       \
+  COFF_SWAP_TABLE                                                      \
 };
 
 #define CREATE_LITTLE_COFF_TARGET_VEC(VAR, NAME, EXTRA_O_FLAGS, EXTRA_S_FLAGS, UNDER, ALTERNATIVE)     \
-const bfd_target VAR =                                                                         \
-{                                                                                              \
-  NAME ,                                                                                       \
-  bfd_target_coff_flavour,                                                                     \
-  BFD_ENDIAN_LITTLE,           /* data byte order is little */                                 \
-  BFD_ENDIAN_LITTLE,           /* header byte order is little */                               \
-       /* object flags */                                                                      \
-  (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG |                                               \
-   HAS_SYMS | HAS_LOCALS | WP_TEXT | EXTRA_O_FLAGS),                                           \
-       /* section flags */                                                                     \
-  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | EXTRA_S_FLAGS),                       \
-  UNDER,                       /* leading symbol underscore */                                 \
-  '/',                         /* ar_pad_char */                                               \
-  15,                          /* ar_max_namelen */                                            \
-                                                                                               \
-  /* Data conversion functions.  */                                                            \
-  bfd_getl64, bfd_getl_signed_64, bfd_putl64,                                                  \
-  bfd_getl32, bfd_getl_signed_32, bfd_putl32,                                                  \
-  bfd_getl16, bfd_getl_signed_16, bfd_putl16,                                                  \
-  /* Header conversion functions.  */                                                          \
-  bfd_getl64, bfd_getl_signed_64, bfd_putl64,                                                  \
-  bfd_getl32, bfd_getl_signed_32, bfd_putl32,                                                  \
-  bfd_getl16, bfd_getl_signed_16, bfd_putl16,                                                  \
-       /* bfd_check_format */                                                                  \
-  { _bfd_dummy_target, coff_object_p, bfd_generic_archive_p, _bfd_dummy_target },              \
-       /* bfd_set_format */                                                                    \
-  { bfd_false, coff_mkobject, _bfd_generic_mkarchive, bfd_false },                             \
-       /* bfd_write_contents */                                                                \
-  { bfd_false, coff_write_object_contents, _bfd_write_archive_contents, bfd_false },           \
-                                                                                               \
-  BFD_JUMP_TABLE_GENERIC (coff),                                                               \
-  BFD_JUMP_TABLE_COPY (coff),                                                                  \
-  BFD_JUMP_TABLE_CORE (_bfd_nocore),                                                           \
-  BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),                                                  \
-  BFD_JUMP_TABLE_SYMBOLS (coff),                                                               \
-  BFD_JUMP_TABLE_RELOCS (coff),                                                                        \
-  BFD_JUMP_TABLE_WRITE (coff),                                                                 \
-  BFD_JUMP_TABLE_LINK (coff),                                                                  \
-  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),                                                     \
-                                                                                               \
-  ALTERNATIVE,                                                                                 \
-                                                                                               \
-  COFF_SWAP_TABLE                                                                              \
+const bfd_target VAR =                                                 \
+{                                                                      \
+  NAME ,                                                               \
+  bfd_target_coff_flavour,                                             \
+  BFD_ENDIAN_LITTLE,           /* data byte order is little */         \
+  BFD_ENDIAN_LITTLE,           /* header byte order is little */       \
+       /* object flags */                                              \
+  (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG |                       \
+   HAS_SYMS | HAS_LOCALS | WP_TEXT | EXTRA_O_FLAGS),                   \
+       /* section flags */                                             \
+  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | EXTRA_S_FLAGS),\
+  UNDER,                       /* leading symbol underscore */         \
+  '/',                         /* ar_pad_char */                       \
+  15,                          /* ar_max_namelen */                    \
+                                                                       \
+  /* Data conversion functions.  */                                    \
+  bfd_getl64, bfd_getl_signed_64, bfd_putl64,                          \
+  bfd_getl32, bfd_getl_signed_32, bfd_putl32,                          \
+  bfd_getl16, bfd_getl_signed_16, bfd_putl16,                          \
+  /* Header conversion functions.  */                                  \
+  bfd_getl64, bfd_getl_signed_64, bfd_putl64,                          \
+  bfd_getl32, bfd_getl_signed_32, bfd_putl32,                          \
+  bfd_getl16, bfd_getl_signed_16, bfd_putl16,                          \
+       /* bfd_check_format */                                          \
+  { _bfd_dummy_target, coff_object_p, bfd_generic_archive_p,           \
+    _bfd_dummy_target },                                               \
+       /* bfd_set_format */                                            \
+  { bfd_false, coff_mkobject, _bfd_generic_mkarchive, bfd_false },     \
+       /* bfd_write_contents */                                        \
+  { bfd_false, coff_write_object_contents, _bfd_write_archive_contents,        \
+    bfd_false },                                                       \
+                                                                       \
+  BFD_JUMP_TABLE_GENERIC (coff),                                       \
+  BFD_JUMP_TABLE_COPY (coff),                                          \
+  BFD_JUMP_TABLE_CORE (_bfd_nocore),                                   \
+  BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),                          \
+  BFD_JUMP_TABLE_SYMBOLS (coff),                                       \
+  BFD_JUMP_TABLE_RELOCS (coff),                                                \
+  BFD_JUMP_TABLE_WRITE (coff),                                         \
+  BFD_JUMP_TABLE_LINK (coff),                                          \
+  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),                             \
+                                                                       \
+  ALTERNATIVE,                                                         \
+                                                                       \
+  COFF_SWAP_TABLE                                                      \
 };
This page took 0.036403 seconds and 4 git commands to generate.