1999-09-06 Donn Terry <donn@interix.com>
authorIan Lance Taylor <ian@airs.com>
Tue, 7 Sep 1999 02:11:54 +0000 (02:11 +0000)
committerIan Lance Taylor <ian@airs.com>
Tue, 7 Sep 1999 02:11:54 +0000 (02:11 +0000)
* coffcode.h (sec_to_styp_flags): Write separate COFF_WITH_PE
version.  Move COFF_WITH_PE specific code to new version.
(stype_to_sec_flags): Likewise.  Add section parameter.
* coffgen.c (make_a_section_from_file): Set target_index before
calling styp_to_sec_flags.  Pass section to styp_to_sec_flags.
* libcoff.h: Rebuild.

bfd/ChangeLog
bfd/coffcode.h
bfd/coffgen.c
bfd/libcoff.h

index 8a4fa95..031db6e 100644 (file)
@@ -1,5 +1,12 @@
 1999-09-06  Donn Terry  <donn@interix.com>
 
+       * coffcode.h (sec_to_styp_flags): Write separate COFF_WITH_PE
+       version.  Move COFF_WITH_PE specific code to new version.
+       (stype_to_sec_flags): Likewise.  Add section parameter.
+       * coffgen.c (make_a_section_from_file): Set target_index before
+       calling styp_to_sec_flags.  Pass section to styp_to_sec_flags.
+       * libcoff.h: Rebuild.
+
        * syms.c (stt): Add some PE/PEI section names.
        (bfd_decode_symclass): Return 'w', not 'U', for a weak undefined
        symbol.
index b87e814..5f82f85 100644 (file)
@@ -313,7 +313,8 @@ 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 *,
@@ -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)
 
 /*
@@ -842,7 +1046,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,
@@ -995,8 +1200,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))
index 53aaf4f..a104887 100644 (file)
@@ -140,9 +140,9 @@ make_a_section_from_file (abfd, hdr, target_index)
   return_section->lineno_count = hdr->s_nlnno;
   return_section->userdata = NULL;
   return_section->next = (asection *) NULL;
-  return_section->flags = bfd_coff_styp_to_sec_flags_hook (abfd, hdr, name);
-
   return_section->target_index = target_index;
+  return_section->flags = bfd_coff_styp_to_sec_flags_hook (abfd, hdr, name,
+                                                          return_section);
 
   /* At least on i386-coff, the line number count for a shared library
      section must be ignored.  */
index 5b3d703..ffa06bf 100644 (file)
@@ -739,7 +739,8 @@ typedef struct
  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,
@@ -892,8 +893,9 @@ typedef struct
 #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))