+#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;
+
+ /* Unfortunately, the PE format stores essential information in
+ the symbol table, of all places. We need to extract that
+ information now, so that objdump and the linker will know how
+ to handle the section without worrying about the symbols. We
+ can't call slurp_symtab, because the linker doesn't want the
+ swapped symbols. */
+
+ /* 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
+ 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 *esymstart, *esym, *esymend;
+ int seen_state = 0;
+ char *target_name = NULL;
+
+ esymstart = esym = (bfd_byte *) obj_coff_external_syms (abfd);
+ esymend = esym + obj_raw_syment_count (abfd) * bfd_coff_symesz (abfd);
+
+ while (esym < esymend)
+ {
+ struct internal_syment isym;
+ char buf[SYMNMLEN + 1];
+ const char *symname;
+
+ bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &isym);
+
+ if (sizeof (internal_s->s_name) > SYMNMLEN)
+ {
+ /* This case implies that the matching symbol name
+ will be in the string table. */
+ abort ();
+ }
+
+ if (isym.n_scnum == section->target_index)
+ {
+ /* According to the MSVC documentation, 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. Here, we've found the first
+ qualifying entry; we distinguish it from the
+ second with a state flag.
+
+ In the case of gas-generated (at least until that
+ is fixed) .o files, it isn't necessarily the
+ second one. It may be some other later symbol.
+
+ Since gas also doesn't follow MS conventions and
+ emits the section similar to .text$<name>, where
+ <something> is the name we're looking for, we
+ distinguish the two as follows:
+
+ If the section name is simply a section name (no
+ $) we presume it's MS-generated, and look at
+ precisely the second symbol for the comdat name.
+ If the section name has a $, we assume it's
+ gas-generated, and look for <something> (whatever
+ follows the $) as the comdat symbol. */
+
+ /* All 3 branches use this */
+ symname = _bfd_coff_internal_syment_name (abfd, &isym, buf);
+
+ if (symname == NULL)
+ abort ();
+
+ switch (seen_state)
+ {
+ case 0:
+ {
+ /* The first time we've seen the symbol. */
+ union internal_auxent aux;
+
+ seen_state = 1;
+
+ /* If it isn't the stuff we're expecting, die;
+ The MS documentation is vague, but it
+ appears that the second entry serves BOTH
+ as the comdat symbol and the defining
+ symbol record (either C_STAT or C_EXT,
+ possibly with an aux entry with debug
+ information if it's a function.) It
+ appears the only way to find the second one
+ is to count. (On Intel, they appear to be
+ adjacent, but on Alpha, they have been
+ found separated.)
+
+ Here, we think we've found the first one,
+ but there's some checking we can do to be
+ sure. */
+
+ if (! (isym.n_sclass == C_STAT
+ && isym.n_type == T_NULL
+ && isym.n_value == 0))
+ abort ();
+
+ /* FIXME LATER: MSVC generates section names
+ like .text for comdats. Gas generates
+ names like .text$foo__Fv (in the case of a
+ function). See comment above for more. */
+
+ if (strcmp (name, symname) != 0)
+ abort ();
+
+ /* This is the section symbol. */
+
+ bfd_coff_swap_aux_in (abfd, (PTR) (esym + bfd_coff_symesz (abfd)),
+ isym.n_type, isym.n_sclass,
+ 0, isym.n_numaux, (PTR) &aux);
+
+ target_name = strchr (name, '$');
+ if (target_name != NULL)
+ {
+ /* Gas mode. */
+ seen_state = 2;
+ /* Skip the `$'. */
+ target_name += 1;
+ }
+
+ /* FIXME: Microsoft uses NODUPLICATES and
+ ASSOCIATIVE, but gnu uses ANY and
+ SAME_SIZE. Unfortunately, gnu doesn't do
+ the comdat symbols right. So, until we can
+ fix it to do 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. */
+
+ /* Cygwin does not follow the MS style, and
+ uses ANY and SAME_SIZE where NODUPLICATES
+ and ASSOCIATIVE should be used. For
+ Interix, we just do the right thing up
+ front. */
+
+ switch (aux.x_scn.x_comdat)
+ {
+ case IMAGE_COMDAT_SELECT_NODUPLICATES:
+#ifdef STRICT_PE_FORMAT
+ sec_flags |= SEC_LINK_DUPLICATES_ONE_ONLY;
+#else
+ sec_flags &= ~SEC_LINK_ONCE;
+#endif
+ break;
+
+ case IMAGE_COMDAT_SELECT_ANY:
+ sec_flags |= SEC_LINK_DUPLICATES_DISCARD;
+ break;
+
+ case IMAGE_COMDAT_SELECT_SAME_SIZE:
+ sec_flags |= SEC_LINK_DUPLICATES_SAME_SIZE;
+ break;
+
+ case IMAGE_COMDAT_SELECT_EXACT_MATCH:
+ /* Not yet fully implemented ??? */
+ sec_flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS;
+ break;
+
+ /* debug$S gets this case; other
+ implications ??? */
+
+ /* There may be no symbol... we'll search
+ the whole table... Is this the right
+ place to play this game? Or should we do
+ it when reading it in. */
+ case IMAGE_COMDAT_SELECT_ASSOCIATIVE:
+#ifdef STRICT_PE_FORMAT
+ /* FIXME: This is not currently implemented. */
+ sec_flags |= SEC_LINK_DUPLICATES_DISCARD;
+#else
+ sec_flags &= ~SEC_LINK_ONCE;
+#endif
+ break;
+
+ default: /* 0 means "no symbol" */
+ /* debug$F gets this case; other
+ implications ??? */
+ sec_flags |= SEC_LINK_DUPLICATES_DISCARD;
+ break;
+ }
+ }
+ break;
+
+ case 2:
+ /* Gas mode: the first matching on partial name. */
+
+#ifndef TARGET_UNDERSCORE
+#define TARGET_UNDERSCORE 0
+#endif
+ /* Is this the name we're looking for? */
+ if (strcmp (target_name,
+ symname + (TARGET_UNDERSCORE ? 1 : 0)) != 0)
+ {
+ /* Not the name we're looking for */
+ esym += (isym.n_numaux + 1) * bfd_coff_symesz (abfd);
+ continue;
+ }
+ /* Fall through. */
+ case 1:
+ /* MSVC mode: the lexically second symbol (or
+ drop through from the above). */
+ {
+ char *newname;
+
+ /* This must 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) / bfd_coff_symesz (abfd);
+
+ newname = bfd_alloc (abfd, strlen (symname) + 1);
+ if (newname == NULL)
+ abort ();
+
+ strcpy (newname, symname);
+ section->comdat->name = newname;
+
+ }
+
+ goto breakloop;
+ }
+ }
+
+ esym += (isym.n_numaux + 1) * bfd_coff_symesz (abfd);
+ }
+ breakloop:
+ }
+ }
+
+#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;