This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch ld]: Fix for bug ld/11539: ld --gc-sections should work for PE-COFF on MinGW


Hi,

I am in vacation.  So pinging for a patch on this list isn't the best
way IMHO.  It is misleading as we just noticed.  As I said in a prior
post to this thread, I am looking into this issue.  In future, if you
want to ping me to work on a patch, please sent such mails directly to
me.

I inline the current version of the patch I have right now, and it
works.  Nevertheless there is still room for improvements.

[Bug ld/11539] ld --gc-sections should work for PE-COFF on MinGW

Hello,

This patch addresses for pe-coff and pe+-coff the issue reported about
--gc-sections.
Additional it adds the required code for pe-coff to bfd.

ChangeLog bfd/

2012-08-22  Kai Tietz

	PR ld/11539
	* coffcode.h (coff_bfd_gc_sections): Define default
	to bfd_coff_gc_sections function.
	* cofflink.c (init_reloc_cookie): Copy and adjust coff
	related code about gc-sections from elflink.c to here.
	(fini_reloc_cookie): Likewise.
	(init_reloc_cookie_rels): Likewise.
	(fini_reloc_cookie_rels): Likewise.
	(init_reloc_cookie_for_section): Likewise.
	(fini_reloc_cookie_for_section): Likewise.
	(_bfd_coff_gc_mark_hook): Likewise.
	(_bfd_coff_gc_mark_rsec): Likewise.
	(_bfd_coff_gc_mark_reloc): Likewise.
	(_bfd_coff_gc_mark): Likewise.
	(_bfd_coff_gc_mark_extra_sections): Likewise.
	(coff_gc_sweep_symbol_info): Likewise.
	(coff_gc_sweep_symbol): Likewise.
	(gc_sweep_hook_fn): Likewise.
	(coff_gc_sweep): Likewise.
	(bfd_coff_gc_sections): Likewise.
	(_bfd_coff_gc_keep): Likewise.
	* libcoff.h (coff_reloc_cookie): New struct.
	(bfd_coff_gc_sections): New prototype.
	(coff_gc_mark_hook_fn): New type.

ChangeLog ld/

2012-08-22  Kai Tietz

	PR ld/11539
	* scripttempl/pep.sc: Mark .idata*, .CRT*, .tls*,
	.rsrc*, .init, .ctor*, .dtor*, .fini, .jcr,
	.eh_frame, .pdata. .xdata, and .gcc_except_table sections
	as KEEP.
	* scripttempl/pe.sc: Likewise.
	
Tested for i686-w64-mingw32, and for x86_64-w64-mingw32.  Ok for apply?

Regards,
Kai


Index: src/ld/scripttempl/pe.sc
===================================================================
--- src.orig/ld/scripttempl/pe.sc
+++ src/ld/scripttempl/pe.sc
@@ -24,27 +24,27 @@ if test "${RELOCATING}"; then
              *(SORT(.rdata$*))'
   fi
   R_IDATA234='
-    SORT(*)(.idata$2)
-    SORT(*)(.idata$3)
+    KEEP(SORT(*)(.idata$2))
+    KEEP(SORT(*)(.idata$3))
     /* These zeroes mark the end of the import list.  */
     LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
-    SORT(*)(.idata$4)'
-  R_IDATA5='SORT(*)(.idata$5)'
+    KEEP(SORT(*)(.idata$4))'
+  R_IDATA5='KEEP(SORT(*)(.idata$5))'
   R_IDATA67='
-    SORT(*)(.idata$6)
-    SORT(*)(.idata$7)'
-  R_CRT_XC='*(SORT(.CRT$XC*))  /* C initialization */'
-  R_CRT_XI='*(SORT(.CRT$XI*))  /* C++ initialization */'
-  R_CRT_XL='*(SORT(.CRT$XL*))  /* TLS callbacks */'
-  R_CRT_XP='*(SORT(.CRT$XP*))  /* Pre-termination */'
-  R_CRT_XT='*(SORT(.CRT$XT*))  /* Termination */'
+    KEEP(SORT(*)(.idata$6))
+    KEEP(SORT(*)(.idata$7))'
+  R_CRT_XC='KEEP(*(SORT(.CRT$XC*)))  /* C initialization */'
+  R_CRT_XI='KEEP(*(SORT(.CRT$XI*)))  /* C++ initialization */'
+  R_CRT_XL='KEEP(*(SORT(.CRT$XL*)))  /* TLS callbacks */'
+  R_CRT_XP='KEEP(*(SORT(.CRT$XP*)))  /* Pre-termination */'
+  R_CRT_XT='KEEP(*(SORT(.CRT$XT*)))  /* Termination */'
   R_TLS='
-    *(.tls$AAA)
-    *(.tls)
-    *(.tls$)
-    *(SORT(.tls$*))
-    *(.tls$ZZZ)'
-  R_RSRC='*(SORT(.rsrc$*))'
+    KEEP(*(.tls$AAA))
+    KEEP(*(.tls))
+    KEEP(*(.tls$))
+    KEEP(*(SORT(.tls$*)))
+    KEEP(*(.tls$ZZZ))'
+  R_RSRC='KEEP(*(SORT(.rsrc$*)))'
 else
   R_TEXT=
   R_DATA=
@@ -71,7 +71,7 @@ SECTIONS
   ${RELOCATING+. = ALIGN(__section_alignment__);}
   .text ${RELOCATING+ __image_base__ + ( __section_alignment__ <
${TARGET_PAGE_SIZE} ? . : __section_alignment__ )} :
   {
-    ${RELOCATING+ *(.init)}
+    ${RELOCATING+ KEEP(*(.init))}
     *(.text)
     ${R_TEXT}
     ${RELOCATING+ *(.text.*)}
@@ -102,7 +102,7 @@ SECTIONS
     *(.data)
     *(.data2)
     ${R_DATA}
-    *(.jcr)
+    KEEP(*(.jcr))
     ${RELOCATING+__data_end__ = . ;}
     ${RELOCATING+*(.data_cygwin_nocopy)}
   }
@@ -122,12 +122,12 @@ SECTIONS

   .eh_frame ${RELOCATING+BLOCK(__section_alignment__)} :
   {
-    *(.eh_frame*)
+    KEEP(*(.eh_frame*))
   }

   .pdata ${RELOCATING+BLOCK(__section_alignment__)} :
   {
-    *(.pdata)
+    KEEP(*(.pdata))
   }

   .bss ${RELOCATING+BLOCK(__section_alignment__)} :
@@ -203,7 +203,7 @@ SECTIONS

   .rsrc ${RELOCATING+BLOCK(__section_alignment__)} :
   { 					
-    *(.rsrc)
+    KEEP(*(.rsrc))
     ${R_RSRC}
   }

Index: src/ld/scripttempl/pep.sc
===================================================================
--- src.orig/ld/scripttempl/pep.sc
+++ src/ld/scripttempl/pep.sc
@@ -24,27 +24,27 @@ if test "${RELOCATING}"; then
              *(SORT(.rdata$*))'
   fi
   R_IDATA234='
-    SORT(*)(.idata$2)
-    SORT(*)(.idata$3)
+    KEEP(SORT(*)(.idata$2))
+    KEEP(SORT(*)(.idata$3))
     /* These zeroes mark the end of the import list.  */
     LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
-    SORT(*)(.idata$4)'
-  R_IDATA5='SORT(*)(.idata$5)'
+    KEEP(SORT(*)(.idata$4))'
+  R_IDATA5='KEEP(SORT(*)(.idata$5))'
   R_IDATA67='
-    SORT(*)(.idata$6)
-    SORT(*)(.idata$7)'
-  R_CRT_XC='*(SORT(.CRT$XC*))  /* C initialization */'
-  R_CRT_XI='*(SORT(.CRT$XI*))  /* C++ initialization */'
-  R_CRT_XL='*(SORT(.CRT$XL*))  /* TLS callbacks */'
-  R_CRT_XP='*(SORT(.CRT$XP*))  /* Pre-termination */'
-  R_CRT_XT='*(SORT(.CRT$XT*))  /* Termination */'
+    KEEP(SORT(*)(.idata$6))
+    KEEP(SORT(*)(.idata$7))'
+  R_CRT_XC='KEEP(*(SORT(.CRT$XC*)))  /* C initialization */'
+  R_CRT_XI='KEEP(*(SORT(.CRT$XI*)))  /* C++ initialization */'
+  R_CRT_XL='KEEP(*(SORT(.CRT$XL*)))  /* TLS callbacks */'
+  R_CRT_XP='KEEP(*(SORT(.CRT$XP*)))  /* Pre-termination */'
+  R_CRT_XT='KEEP(*(SORT(.CRT$XT*)))  /* Termination */'
   R_TLS='
-    *(.tls$AAA)
-    *(.tls)
-    *(.tls$)
-    *(SORT(.tls$*))
-    *(.tls$ZZZ)'
-  R_RSRC='*(SORT(.rsrc$*))'
+    KEEP(*(.tls$AAA))
+    KEEP(*(.tls))
+    KEEP(*(.tls$))
+    KEEP(*(SORT(.tls$*)))
+    KEEP(*(.tls$ZZZ))'
+  R_RSRC='KEEP(*(SORT(.rsrc$*)))'
 else
   R_TEXT=
   R_DATA=
@@ -71,7 +71,7 @@ SECTIONS
   ${RELOCATING+. = ALIGN(__section_alignment__);}
   .text ${RELOCATING+ __image_base__ + ( __section_alignment__ <
${TARGET_PAGE_SIZE} ? . : __section_alignment__ )} :
   {
-    ${RELOCATING+ *(.init)}
+    ${RELOCATING+ KEEP(*(.init))}
     *(.text)
     ${R_TEXT}
     ${RELOCATING+ *(.text.*)}
@@ -80,14 +80,18 @@ SECTIONS
     *(.glue_7)
     ${CONSTRUCTING+. = ALIGN(8);}
     ${CONSTRUCTING+ ___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
-			LONG (-1); LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*));  LONG
(0); LONG (0); }
+			LONG (-1); LONG (-1);KEEP(*(.ctors));
+			KEEP(*(.ctor)); KEEP(*(SORT(.ctors.*)));
+			LONG (0); LONG (0); }
     ${CONSTRUCTING+ ___DTOR_LIST__ = .; __DTOR_LIST__ = . ;
-			LONG (-1); LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*));
LONG (0); LONG (0); }
-    ${RELOCATING+ *(.fini)}
+			LONG (-1); LONG (-1); KEEP(*(.dtors));
+			KEEP(*(.dtor)); KEEP(*(SORT(.dtors.*)));
+			LONG (0); LONG (0); }
+    ${RELOCATING+ KEEP(*(.fini))}
     /* ??? Why is .gcc_exc here?  */
     ${RELOCATING+ *(.gcc_exc)}
     ${RELOCATING+PROVIDE (etext = .);}
-    ${RELOCATING+ *(.gcc_except_table)}
+    ${RELOCATING+ KEEP(*(.gcc_except_table))}
   }

   /* The Cygwin32 library uses a section to avoid copying certain data
@@ -102,7 +106,7 @@ SECTIONS
     *(.data)
     *(.data2)
     ${R_DATA}
-    *(.jcr)
+    KEEP(*(.jcr))
     ${RELOCATING+__data_end__ = . ;}
     ${RELOCATING+*(.data_cygwin_nocopy)}
   }
@@ -127,12 +131,12 @@ SECTIONS

   .pdata ${RELOCATING+BLOCK(__section_alignment__)} :
   {
-    *(.pdata*)
+    KEEP(*(.pdata*))
   }

   .xdata ${RELOCATING+BLOCK(__section_alignment__)} :
   {
-    *(.xdata*)
+    KEEP(*(.xdata*))
   }

   .bss ${RELOCATING+BLOCK(__section_alignment__)} :
@@ -208,7 +212,7 @@ SECTIONS

   .rsrc ${RELOCATING+BLOCK(__section_alignment__)} :
   { 					
-    *(.rsrc)
+    KEEP(*(.rsrc))
     ${R_RSRC}
   }

Index: src/bfd/coffcode.h
===================================================================
--- src.orig/bfd/coffcode.h
+++ src/bfd/coffcode.h
@@ -5655,7 +5655,7 @@ static bfd_coff_backend_data ticoff1_swa
 #endif

 #ifndef coff_bfd_gc_sections
-#define coff_bfd_gc_sections		    bfd_generic_gc_sections
+#define coff_bfd_gc_sections		    bfd_coff_gc_sections
 #endif

 #ifndef coff_bfd_lookup_section_flags
Index: src/bfd/cofflink.c
===================================================================
--- src.orig/bfd/cofflink.c
+++ src/bfd/cofflink.c
@@ -3193,3 +3193,464 @@ _bfd_coff_generic_relocate_section (bfd
     }
   return TRUE;
 }
+
+/* Initialize COOKIE for input bfd ABFD. */
+
+static bfd_boolean
+init_reloc_cookie (struct coff_reloc_cookie *cookie,
+		   struct bfd_link_info *info ATTRIBUTE_UNUSED, bfd *abfd)
+{
+  /* Sometimes the symbol table does not yet have been loaded here. */
+  bfd_coff_slurp_symbol_table (abfd);
+
+  cookie->abfd = abfd;
+  cookie->sym_hashes = obj_coff_sym_hashes (abfd);
+
+  cookie->symbols = obj_symbols (abfd);
+
+  return TRUE;
+}
+
+/* Free the memory allocated by init_reloc_cookie, if appropriate.  */
+
+static void
+fini_reloc_cookie (struct coff_reloc_cookie *cookie ATTRIBUTE_UNUSED,
bfd *abfd ATTRIBUTE_UNUSED)
+{
+  /* Nothing to do.  */
+}
+
+/* Initialize the relocation information in COOKIE for input section SEC
+   of input bfd ABFD.  */
+
+static bfd_boolean
+init_reloc_cookie_rels (struct coff_reloc_cookie *cookie,
+			struct bfd_link_info *info ATTRIBUTE_UNUSED, bfd *abfd,
+			asection *sec)
+{
+  if (sec->reloc_count == 0)
+    {
+      cookie->rels = NULL;
+      cookie->relend = NULL;
+      cookie->rel = NULL;
+      return TRUE;
+    }
+
+  cookie->rels = _bfd_coff_read_internal_relocs (abfd, sec, FALSE,
NULL, 0, NULL);
+
+  if (cookie->rels == NULL)
+    return FALSE;
+
+  cookie->rel = cookie->rels;
+  cookie->relend = (cookie->rels + sec->reloc_count);
+  return TRUE;
+}
+
+/* Free the memory allocated by init_reloc_cookie_rels,
+   if appropriate.  */
+
+static void
+fini_reloc_cookie_rels (struct coff_reloc_cookie *cookie,
+			asection *sec)
+{
+  if (cookie->rels && coff_section_data (NULL, sec)->relocs != cookie->rels)
+    free (cookie->rels);
+}
+
+/* Initialize the whole of COOKIE for input section SEC.  */
+
+static bfd_boolean
+init_reloc_cookie_for_section (struct coff_reloc_cookie *cookie,
+			       struct bfd_link_info *info,
+			       asection *sec)
+{
+  if (!init_reloc_cookie (cookie, info, sec->owner))
+    return FALSE;
+
+  if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec))
+    {
+      fini_reloc_cookie (cookie, sec->owner);
+      return FALSE;
+    }
+  return TRUE;
+}
+
+/* Free the memory allocated by init_reloc_cookie_for_section,
+   if appropriate.  */
+
+static void
+fini_reloc_cookie_for_section (struct coff_reloc_cookie *cookie,
+			       asection *sec)
+{
+  fini_reloc_cookie_rels (cookie, sec);
+  fini_reloc_cookie (cookie, sec->owner);
+}
+
+static asection *
+_bfd_coff_gc_mark_hook (asection *sec,
+		       struct bfd_link_info *info ATTRIBUTE_UNUSED,
+		       struct internal_reloc *rel ATTRIBUTE_UNUSED,
+		       struct coff_link_hash_entry *h,
+		       struct internal_syment *sym)
+{
+  if (h != NULL)
+    {
+      switch (h->root.type)
+        {
+        case bfd_link_hash_defined:
+        case bfd_link_hash_defweak:
+          return h->root.u.def.section;
+
+        case bfd_link_hash_common:
+          return h->root.u.c.p->section;
+
+	case bfd_link_hash_undefined:
+	case bfd_link_hash_undefweak:
+        default:
+          break;
+        }
+      return NULL;
+    }
+
+  return coff_section_from_bfd_index (sec->owner, sym->n_scnum);
+}
+
+/* COOKIE->rel describes a relocation against section SEC, which is
+   a section we've decided to keep.  Return the section that contains
+   the relocation symbol, or NULL if no section contains it.  */
+static asection *
+_bfd_coff_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
+		       coff_gc_mark_hook_fn gc_mark_hook,
+		       struct coff_reloc_cookie *cookie)
+{
+  struct coff_link_hash_entry *h;
+
+  h = cookie->sym_hashes[cookie->rel->r_symndx];
+  if (h != NULL) {
+    while (h->root.type == bfd_link_hash_indirect
+           || h->root.type == bfd_link_hash_warning)
+      h = (struct coff_link_hash_entry *) h->root.u.i.link;
+
+    return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL);
+  }
+
+  return (*gc_mark_hook) (sec, info, cookie->rel, NULL,
+			  &(cookie->symbols + obj_convert
(sec->owner)[cookie->rel->r_symndx])->native->u.syment);
+}
+
+static
+bfd_boolean
+_bfd_coff_gc_mark (struct bfd_link_info *info,
+		  asection *sec,
+		  coff_gc_mark_hook_fn gc_mark_hook);
+
+/* COOKIE->rel describes a relocation against section SEC, which is
+   a section we've decided to keep.  Mark the section that contains
+   the relocation symbol.  */
+static bfd_boolean
+_bfd_coff_gc_mark_reloc (struct bfd_link_info *info,
+			asection *sec,
+			coff_gc_mark_hook_fn gc_mark_hook,
+			struct coff_reloc_cookie *cookie)
+{
+  asection *rsec;
+
+  rsec = _bfd_coff_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
+  if (rsec && !rsec->gc_mark)
+    {
+      if (bfd_get_flavour (rsec->owner) != bfd_target_coff_flavour)
+	rsec->gc_mark = 1;
+      else if (!_bfd_coff_gc_mark (info, rsec, gc_mark_hook))
+	return FALSE;
+    }
+  return TRUE;
+}
+
+
+/* The mark phase of garbage collection.  For a given section, mark
+   it and any sections in this section's group, and all the sections
+   which define symbols to which it refers.  */
+
+static bfd_boolean
+_bfd_coff_gc_mark (struct bfd_link_info *info,
+		  asection *sec,
+		  coff_gc_mark_hook_fn gc_mark_hook)
+{
+  bfd_boolean ret;
+
+  sec->gc_mark = 1;
+
+  /* Look through the section relocs.  */
+  ret = TRUE;
+  if ((sec->flags & SEC_RELOC) != 0
+      && sec->reloc_count > 0)
+    {
+      struct coff_reloc_cookie cookie;
+
+
+      if (!init_reloc_cookie_for_section (&cookie, info, sec))
+        ret = FALSE;
+      else
+        {
+          for (; cookie.rel < cookie.relend; cookie.rel++)
+            {
+	      if (!_bfd_coff_gc_mark_reloc (info, sec, gc_mark_hook, &cookie))
+		{
+		  ret = FALSE;
+		  break;
+		}
+	    }
+          fini_reloc_cookie_for_section (&cookie, sec);
+        }
+
+    }
+
+  return ret;
+}
+
+static bfd_boolean
+_bfd_coff_gc_mark_extra_sections (struct bfd_link_info *info,
+				  coff_gc_mark_hook_fn mark_hook ATTRIBUTE_UNUSED)
+{
+  bfd *ibfd;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    {
+      asection *isec;
+      bfd_boolean some_kept;
+
+      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+	continue;
+
+      /* Ensure all linker created sections are kept, and see whether
+	 any other section is already marked.  */
+      some_kept = FALSE;
+      for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+	{
+	  if ((isec->flags & SEC_LINKER_CREATED) != 0)
+	    isec->gc_mark = 1;
+	  else if (isec->gc_mark)
+	    some_kept = TRUE;
+	}
+
+      /* If no section in this file will be kept, then we can
+	 toss out debug sections.  */
+      if (!some_kept)
+	continue;
+
+      /* Keep debug and special sections like .comment when they are
+	 not part of a group, or when we have single-member groups.  */
+      for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+	if ((isec->flags & SEC_DEBUGGING) != 0
+	    || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)
+	  isec->gc_mark = 1;
+    }
+  return TRUE;
+}
+
+/* Sweep symbols in swept sections.  Called via coff_link_hash_traverse.  */
+
+struct coff_gc_sweep_symbol_info
+{
+  struct bfd_link_info *info;
+  void (*hide_symbol) (struct bfd_link_info *, struct coff_link_hash_entry *,
+		       bfd_boolean);
+};
+
+static bfd_boolean
+coff_gc_sweep_symbol (struct coff_link_hash_entry *h, void *data)
+{
+  if (h->root.type == bfd_link_hash_warning)
+    h = (struct coff_link_hash_entry *) h->root.u.i.link;
+
+/*  if (h->mark)
+    return TRUE; */
+  if ((h->root.type == bfd_link_hash_defined
+       || h->root.type == bfd_link_hash_defweak)
+      && !h->root.u.def.section->gc_mark
+      && !(h->root.u.def.section->owner->flags & DYNAMIC))
+    {
+      struct coff_gc_sweep_symbol_info *inf ATTRIBUTE_UNUSED =
+          (struct coff_gc_sweep_symbol_info *) data;
+      /* FIXME: elflink.c hides the symbol here - how can we do this for COFF?
+      (*inf->hide_symbol) (inf->info, h, TRUE); */
+    }
+  else if (h->root.type == bfd_link_hash_undefined
+	   || h->root.type == bfd_link_hash_undefweak)
+    {
+      struct coff_gc_sweep_symbol_info *inf ATTRIBUTE_UNUSED =
+          (struct coff_gc_sweep_symbol_info *) data;
+      /* FIXME: elflink.c hides the symbol here - how can we do this for COFF?
+      (*inf->hide_symbol) (inf->info, h, TRUE); */
+    }
+
+  return TRUE;
+}
+
+
+/* The sweep phase of garbage collection.  Remove all garbage sections.  */
+
+typedef bfd_boolean (*gc_sweep_hook_fn)
+  (bfd *, struct bfd_link_info *, asection *, const struct internal_reloc *);
+
+static bfd_boolean
+coff_gc_sweep (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
+{
+  bfd *sub;
+  struct coff_gc_sweep_symbol_info sweep_info;
+
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+    {
+      asection *o;
+
+      if (bfd_get_flavour (sub) != bfd_target_coff_flavour)
+	continue;
+
+      for (o = sub->sections; o != NULL; o = o->next)
+	{
+	  if (o->gc_mark)
+	    continue;
+          if (strncmp (o->name, ".idata", 6) == 0
+              || strncmp (o->name, ".pdata", 6) == 0
+              || strncmp (o->name, ".xdata", 6) == 0
+              || strncmp (o->name, ".rsrc", 5) == 0)
+            {
+	      o->gc_mark = 1;
+	      continue;
+	    }
+
+          if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0
+		   || (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)
+	    {
+	      /* Keep debug and special sections.  */
+	      o->gc_mark = 1;
+	    }
+
+	  if (o->gc_mark)
+	    continue;
+
+	  /* Skip sweeping sections already excluded.  */
+	  if (o->flags & SEC_EXCLUDE)
+	    continue;
+
+	  /* Since this is early in the link process, it is simple
+	     to remove a section from the output.  */
+	  o->flags |= SEC_EXCLUDE;
+
+	  if (info->print_gc_sections && o->size != 0)
+            _bfd_error_handler (_("Removing unused section '%s' in
file '%B'"), sub, o->name);
+
+#if 0
+	  /* But we also have to update some of the relocation
+	     info we collected before.  */
+	  if (gc_sweep_hook
+	      && (o->flags & SEC_RELOC) != 0
+	      && o->reloc_count > 0
+	      && !bfd_is_abs_section (o->output_section))
+	    {
+	      struct internal_reloc *internal_relocs;
+	      bfd_boolean r;
+
+	      internal_relocs
+		= _bfd_coff_link_read_relocs (o->owner, o, NULL, NULL,
+					     info->keep_memory);
+	      if (internal_relocs == NULL)
+		return FALSE;
+
+	      r = (*gc_sweep_hook) (o->owner, info, o, internal_relocs);
+
+	      if (coff_section_data (o)->relocs != internal_relocs)
+		free (internal_relocs);
+
+	      if (!r)
+		return FALSE;
+	    }
+#endif
+	}
+    }
+
+  /* Remove the symbols that were in the swept sections from the dynamic
+     symbol table.  GCFIXME: Anyone know how to get them out of the
+     static symbol table as well?  */
+
+  sweep_info.info = info;
+  /* FIXME: Do we need this for COFF?
+     sweep_info.hide_symbol = bed->coff_backend_hide_symbol; */
+  coff_link_hash_traverse (coff_hash_table (info), coff_gc_sweep_symbol,
+			  &sweep_info);
+
+
+
+  return TRUE;
+}
+
+
+/* Keep all sections containing symbols undefined on the command-line,
+   and the section containing the entry symbol.  */
+
+static void
+_bfd_coff_gc_keep (struct bfd_link_info *info)
+{
+  struct bfd_sym_chain *sym;
+
+  for (sym = info->gc_sym_list; sym != NULL; sym = sym->next)
+    {
+      struct coff_link_hash_entry *h;
+
+      h = coff_link_hash_lookup (coff_hash_table (info), sym->name,
+				FALSE, FALSE, FALSE);
+
+      if (h != NULL
+	  && (h->root.type == bfd_link_hash_defined
+	      || h->root.type == bfd_link_hash_defweak)
+	  && !bfd_is_abs_section (h->root.u.def.section))
+	h->root.u.def.section->flags |= SEC_KEEP;
+    }
+}
+
+/* Do mark and sweep of unused sections.  */
+
+bfd_boolean
+bfd_coff_gc_sections (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
+{
+  bfd *sub;
+
+  /* FIXME: Should we implement this? */
+#if 0
+  const bfd_coff_backend_data *bed = coff_backend_info (abfd);
+
+  if (!bed->can_gc_sections
+      || !is_coff_hash_table (info->hash))
+    {
+      (*_bfd_error_handler)(_("Warning: gc-sections option ignored"));
+      return TRUE;
+    }
+#endif
+
+  _bfd_coff_gc_keep (info);
+
+  /* Grovel through relocs to find out who stays ...  */
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+    {
+      asection *o;
+
+      if (bfd_get_flavour (sub) != bfd_target_coff_flavour)
+        continue;
+
+      for (o = sub->sections; o != NULL; o = o->next)
+        {
+	  if (((o->flags & (SEC_EXCLUDE | SEC_KEEP)) == SEC_KEEP
+	       || strncmp (o->name, ".ctors", 6) == 0
+	       || strncmp (o->name, ".dtors", 6) == 0)
+	      && !o->gc_mark)
+	    {
+	      if (!_bfd_coff_gc_mark (info, o, _bfd_coff_gc_mark_hook))
+		return FALSE;
+	    }
+        }
+      }
+
+  /* Allow the backend to mark additional target specific sections.  */
+  _bfd_coff_gc_mark_extra_sections (info, _bfd_coff_gc_mark_hook);
+  /* ... and mark SEC_EXCLUDE for those that go.  */
+  return coff_gc_sweep (abfd, info);
+}
Index: src/bfd/libcoff.h
===================================================================
--- src.orig/bfd/libcoff.h
+++ src/bfd/libcoff.h
@@ -284,6 +284,14 @@ struct coff_link_hash_table
   struct stab_info stab_info;
 };

+struct coff_reloc_cookie
+{
+  struct internal_reloc *rels, *rel, *relend;
+  struct coff_symbol_struct *symbols;	/* Symtab for input bfd.  */
+  bfd *abfd;
+  struct coff_link_hash_entry **sym_hashes;
+};
+
 /* Look up an entry in a COFF linker hash table.  */

 #define coff_link_hash_lookup(table, string, create, copy, follow)	\
@@ -569,6 +577,8 @@ extern struct internal_reloc *_bfd_coff_
 extern bfd_boolean _bfd_coff_generic_relocate_section
   (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
    struct internal_reloc *, struct internal_syment *, asection **);
+extern bfd_boolean bfd_coff_gc_sections
+  (bfd *abfd, struct bfd_link_info *info);
 extern struct bfd_hash_entry *_bfd_coff_debug_merge_hash_newfunc
   (struct bfd_hash_entry *, struct bfd_hash_table *, const char *);
 extern bfd_boolean _bfd_coff_write_global_sym
@@ -685,6 +695,10 @@ enum coff_symbol_classification
   COFF_SYMBOL_PE_SECTION
 };

+typedef asection * (*coff_gc_mark_hook_fn)
+  (asection *, struct bfd_link_info *, struct internal_reloc *,
+   struct coff_link_hash_entry *, struct internal_syment *);
+
 typedef struct
 {
   void (*_bfd_coff_swap_aux_in)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]