[rfc] new bfd hook: additional link map text

DJ Delorie dj@redhat.com
Sat May 10 02:33:00 GMT 2014


Here's the current patch, without the debugs, with elf32-rx.h, and
without the old bfd hook.

In case you're wondering, the purpose for all this is to have better
support for auto-generated interrupt vector tables.  The compiler sets
up all the hooks, the bfd pass stitches the tables together, and this
new linker map hook dumps the generated table info to the map file.

	* bfd/elf32-rx.c (get_symbol_value_maybe): New.
	(rx_elf_relocate_section): If we find a reloc against
	$tableentry$default$<name>, redirect it to the appropriate
	$tableentry$<n>$.
	(RX_Table_Info): New.
	(rx_table_find): New.  Check all tables and SEC_KEEP all sections
	with table parts in them.
	(rx_check_directives): New.
	(rx_table_map_2): New.
	(rx_table_map): New.
	(rx_additional_link_map_text): New.  Called to dump tables to the
	map file.
	* bfd/elf32-rx.h: New.

	* ld/ldemul.h (extra_map_file_text): New field.
	(ldemul_extra_map_file_text): Declare.
	* ld/ldemul.c (ldemul_extra_map_file_text): Define.
	* ld/ldlang.c (lang_map): Call it.

	* ld/emultempl/rxelf.em: Add extra_map_file_text hook.
	* ld/emultempl/aix.em: Add NULL extra_map_file_text hook.
	* ld/emultempl/armcoff.em: Likewise.
	* ld/emultempl/beos.em: Likewise.
	* ld/emultempl/elf32.em: Likewise.
	* ld/emultempl/generic.em: Likewise.
	* ld/emultempl/gld960.em: Likewise.
	* ld/emultempl/gld960c.em: Likewise.
	* ld/emultempl/linux.em: Likewise.
	* ld/emultempl/lnk960.em: Likewise.
	* ld/emultempl/m68kcoff.em: Likewise.
	* ld/emultempl/pe.em: Likewise.
	* ld/emultempl/pep.em: Likewise.
	* ld/emultempl/sunos.em: Likewise.
	* ld/emultempl/ticoff.em: Likewise.
	* ld/emultempl/vanilla.em: Likewise.

diff --git a/bfd/elf32-rx.c b/bfd/elf32-rx.c
index 2045cb7..e1856a9 100644
--- a/bfd/elf32-rx.c
+++ b/bfd/elf32-rx.c
@@ -24,6 +24,7 @@
 #include "elf-bfd.h"
 #include "elf/rx.h"
 #include "libiberty.h"
+#include "elf32-rx.h"
 
 #define RX_OPCODE_BIG_ENDIAN 0
 
@@ -335,6 +336,26 @@ get_symbol_value (const char *            name,
 
   return value;
 }
+static bfd_vma
+get_symbol_value_maybe (const char *            name,
+			struct bfd_link_info *  info)
+{
+  bfd_vma value = 0;
+  struct bfd_link_hash_entry * h;
+
+  h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE);
+
+  if (h == NULL
+      || (h->type != bfd_link_hash_defined
+	  && h->type != bfd_link_hash_defweak))
+    return 0;
+  else
+    value = (h->u.def.value
+	     + h->u.def.section->output_section->vma
+	     + h->u.def.section->output_offset);
+
+  return value;
+}
 
 static bfd_vma
 get_gp (bfd_reloc_status_type * status,
@@ -464,6 +485,9 @@ rx_elf_relocate_section
   Elf_Internal_Rela *           relend;
   bfd_boolean			pid_mode;
   bfd_boolean			saw_subtract = FALSE;
+  const char *			table_default_cache = NULL;
+  bfd_vma			table_start_cache = 0;
+  bfd_vma			table_end_cache = 0;
 
   if (elf_elfheader (output_bfd)->e_flags & E_FLAG_RX_PID)
     pid_mode = TRUE;
@@ -520,6 +544,86 @@ rx_elf_relocate_section
 	  name = h->root.root.string;
 	}
 
+      if (strncmp (name, "$tableentry$default$", 20) == 0)
+	{
+	  bfd_vma entry_vma;
+	  int idx;
+	  char *buf;
+	  bfd_reloc_status_type tstat = 0;
+
+	  if (table_default_cache != name)
+	    {
+
+	      /* All relocs for a given table should be to the same
+		 (weak) default symbol) so we can use it to detect a
+		 cache miss.  We use the offset into the table to find
+		 the "real" symbol.  Calculate and store the table's
+		 offset here.  */
+
+	      table_default_cache = name;
+
+	      /* We have already done error checking in rx_table_find().  */
+
+	      buf = (char *) malloc (13 + strlen (name + 20));
+
+	      sprintf (buf, "$tablestart$%s", name + 20);
+	      tstat = 0;
+	      table_start_cache = get_symbol_value (buf,
+						    &tstat,
+						    info,
+						    input_bfd,
+						    input_section,
+						    rel->r_offset);
+
+	      sprintf (buf, "$tableend$%s", name + 20);
+	      tstat = 0;
+	      table_end_cache = get_symbol_value (buf,
+						  &tstat,
+						  info,
+						  input_bfd,
+						  input_section,
+						  rel->r_offset);
+
+	      free (buf);
+	    }
+
+	  entry_vma = (input_section->output_section->vma
+		       + input_section->output_offset
+		       + rel->r_offset);
+
+	  if (table_end_cache <= entry_vma || entry_vma < table_start_cache)
+	    {
+	      _bfd_error_handler (_("%B:%A: table entry %s outside table"),
+				  input_bfd, input_section,
+				  name);
+	    }
+	  else if ((int) (entry_vma - table_start_cache) % 4)
+	    {
+	      _bfd_error_handler (_("%B:%A: table entry %s not word-aligned within table"),
+				  input_bfd, input_section,
+				  name);
+	    }
+	  else
+	    {
+	      idx = (int) (entry_vma - table_start_cache) / 4;
+
+	      /* This will look like $tableentry$<N>$<name> */
+	      buf = (char *) malloc (12 + 20 + strlen (name + 20));
+	      sprintf (buf, "$tableentry$%d$%s", idx, name + 20);
+
+	      h = (struct elf_link_hash_entry *) bfd_link_hash_lookup (info->hash, buf, FALSE, FALSE, TRUE);
+
+	      if (h)
+		{
+		  relocation = (h->root.u.def.value
+				+ h->root.u.def.section->output_section->vma
+				+ h->root.u.def.section->output_offset);;
+		}
+
+	      free (buf);
+	    }
+	}
+
       if (sec != NULL && discarded_section (sec))
 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
 					 rel, 1, relend, howto, 0, contents);
@@ -3544,6 +3648,298 @@ static const struct bfd_elf_special_section elf32_rx_special_sections[] =
   { NULL,                        0,      0, 0,            0 }
 };
 
+typedef struct {
+  bfd *abfd;
+  struct bfd_link_info *info;
+  bfd_vma table_start;
+  int table_size;
+  bfd_vma *table_handlers;
+  bfd_vma table_default_handler;
+  struct bfd_link_hash_entry **table_entries;
+  struct bfd_link_hash_entry *table_default_entry;
+  FILE *mapfile;
+} RX_Table_Info;
+
+static bfd_boolean
+rx_table_find (struct bfd_hash_entry *vent, void *vinfo)
+{
+  RX_Table_Info *info = (RX_Table_Info *)vinfo;
+  struct bfd_link_hash_entry *ent = (struct bfd_link_hash_entry *)vent;
+  const char *name; /* of the symbol we've found */
+  asection *sec;
+  struct bfd *abfd;
+  int idx;
+  const char *tname; /* name of the table */
+  bfd_vma start_addr, end_addr;
+  char *buf;
+  struct bfd_link_hash_entry * h;
+
+  /* We're looking for globally defined symbols of the form
+     $tablestart$<NAME>.  */
+  if (ent->type != bfd_link_hash_defined
+      && ent->type != bfd_link_hash_defweak)
+    return TRUE;
+
+  name = ent->root.string;
+  sec = ent->u.def.section;
+  abfd = sec->owner;
+
+  if (strncmp (name, "$tablestart$", 12))
+    return TRUE;
+
+  sec->flags |= SEC_KEEP;
+
+  tname = name + 12;
+
+  start_addr = ent->u.def.value;
+
+  /* At this point, we can't build the table but we can (and must)
+     find all the related symbols and mark their sections as SEC_KEEP
+     so we don't garbage collect them.  */
+
+  buf = (char *) malloc (12 + 10 + strlen (tname));
+
+  sprintf (buf, "$tableend$%s", tname);
+  h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE);
+  if (!h || (h->type != bfd_link_hash_defined
+	     && h->type != bfd_link_hash_defweak))
+    {
+      _bfd_error_handler (_("%B:%A: table %s missing corresponding %s"),
+			  abfd, sec, name, buf);
+      return TRUE;
+    }
+
+  if (h->u.def.section != ent->u.def.section)
+    {
+      _bfd_error_handler (_("%B:%A: %s and %s must be in the same input section"),
+			  h->u.def.section->owner, h->u.def.section,
+			  name, buf);
+      return TRUE;
+    }
+
+  end_addr = h->u.def.value;
+
+  sprintf (buf, "$tableentry$default$%s", tname);
+  h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE);
+  if (h && (h->type == bfd_link_hash_defined
+	    || h->type == bfd_link_hash_defweak))
+    {
+      h->u.def.section->flags |= SEC_KEEP;
+    }
+
+  for (idx = 0; idx < (int) (end_addr - start_addr) / 4; idx ++)
+    {
+      sprintf (buf, "$tableentry$%d$%s", idx, tname);
+      h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE);
+      if (h && (h->type == bfd_link_hash_defined
+		|| h->type == bfd_link_hash_defweak))
+	{
+	  h->u.def.section->flags |= SEC_KEEP;
+	}
+    }
+
+  /* Return TRUE to keep scanning, FALSE to end the traversal.  */
+  return TRUE;
+}
+
+/* We need to check for table entry symbols and build the tables, and
+   we need to do it before the linker does garbage collection.  This function is
+   called once per input object file.  */
+static bfd_boolean
+rx_check_directives
+    (bfd *                     abfd ATTRIBUTE_UNUSED,
+     struct bfd_link_info *    info ATTRIBUTE_UNUSED)
+{
+  RX_Table_Info stuff;
+
+  stuff.abfd = abfd;
+  stuff.info = info;
+  bfd_hash_traverse (&(info->hash->table), rx_table_find, &stuff);
+
+  return TRUE;
+}
+
+
+static bfd_boolean
+rx_table_map_2 (struct bfd_hash_entry *vent, void *vinfo)
+{
+  RX_Table_Info *info = (RX_Table_Info *)vinfo;
+  struct bfd_link_hash_entry *ent = (struct bfd_link_hash_entry *)vent;
+  int idx;
+  const char *name;
+  bfd_vma addr;
+
+  /* See if the symbol ENT has an address listed in the table, and
+     isn't a debug/special symbol.  If so, put it in the table.  */
+
+  if (ent->type != bfd_link_hash_defined
+      && ent->type != bfd_link_hash_defweak)
+    return TRUE;
+
+  name = ent->root.string;
+
+  if (name[0] == '$' || name[0] == '.' || name[0] < ' ')
+    return TRUE;
+
+  addr = (ent->u.def.value
+	  + ent->u.def.section->output_section->vma
+	  + ent->u.def.section->output_offset);
+
+  for (idx = 0; idx < info->table_size; idx ++)
+    if (addr == info->table_handlers[idx])
+      info->table_entries[idx] = ent;
+
+  if (addr == info->table_default_handler)
+    info->table_default_entry = ent;
+
+  return TRUE;
+}
+
+static bfd_boolean
+rx_table_map (struct bfd_hash_entry *vent, void *vinfo)
+{
+  RX_Table_Info *info = (RX_Table_Info *)vinfo;
+  struct bfd_link_hash_entry *ent = (struct bfd_link_hash_entry *)vent;
+  const char *name; /* of the symbol we've found */
+  asection *sec;
+  struct bfd *abfd;
+  int idx;
+  const char *tname; /* name of the table */
+  bfd_vma start_addr, end_addr;
+  char *buf;
+  struct bfd_link_hash_entry * h;
+  int need_elipses;
+
+  /* We're looking for globally defined symbols of the form
+     $tablestart$<NAME>.  */
+  if (ent->type != bfd_link_hash_defined
+      && ent->type != bfd_link_hash_defweak)
+    return TRUE;
+
+  name = ent->root.string;
+  sec = ent->u.def.section;
+  abfd = sec->owner;
+
+  if (strncmp (name, "$tablestart$", 12))
+    return TRUE;
+
+  tname = name + 12;
+  start_addr = (ent->u.def.value
+		+ ent->u.def.section->output_section->vma
+		+ ent->u.def.section->output_offset);
+
+  buf = (char *) malloc (12 + 10 + strlen (tname));
+
+  sprintf (buf, "$tableend$%s", tname);
+  end_addr = get_symbol_value_maybe (buf, info->info);
+
+  sprintf (buf, "$tableentry$default$%s", tname);
+  h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE);
+  if (h)
+    {
+      info->table_default_handler = (h->u.def.value
+				     + h->u.def.section->output_section->vma
+				     + h->u.def.section->output_offset);
+    }
+  else
+    /* Zero is a valid handler address!  */
+    info->table_default_handler = (bfd_vma) (-1);
+  info->table_default_entry = NULL;
+
+  info->table_start = start_addr;
+  info->table_size = (int) (end_addr - start_addr) / 4;
+  info->table_handlers = (bfd_vma *) malloc (info->table_size * sizeof (bfd_vma));
+  info->table_entries = (struct bfd_link_hash_entry **) malloc (info->table_size * sizeof (struct bfd_link_hash_entry));
+
+  for (idx = 0; idx < (int) (end_addr - start_addr) / 4; idx ++)
+    {
+      sprintf (buf, "$tableentry$%d$%s", idx, tname);
+      h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE);
+      if (h && (h->type == bfd_link_hash_defined
+		|| h->type == bfd_link_hash_defweak))
+	{
+	  info->table_handlers[idx] = (h->u.def.value
+				       + h->u.def.section->output_section->vma
+				       + h->u.def.section->output_offset);
+	}
+      else
+	info->table_handlers[idx] = info->table_default_handler;
+      info->table_entries[idx] = NULL;
+    }
+
+  free (buf);
+
+  bfd_hash_traverse (&(info->info->hash->table), rx_table_map_2, info);
+
+  fprintf (info->mapfile, "\nRX Vector Table: %s has %d entries at 0x%08lx\n\n",
+	   tname, info->table_size, start_addr);
+
+  if (info->table_default_entry)
+    fprintf (info->mapfile, "  default handler is: %s at 0x%08lx\n",
+	     info->table_default_entry->root.string,
+	     info->table_default_handler);
+  else if (info->table_default_handler != (bfd_vma)(-1))
+    fprintf (info->mapfile, "  default handler is at 0x%08lx\n",
+	     info->table_default_handler);
+  else
+    fprintf (info->mapfile, "  no default handler\n");
+
+  need_elipses = 1;
+  for (idx = 0; idx < info->table_size; idx ++)
+    {
+      if (info->table_handlers[idx] == info->table_default_handler)
+	{
+	  if (need_elipses)
+	    fprintf (info->mapfile, "  . . .\n");
+	  need_elipses = 0;
+	  continue;
+	}
+      need_elipses = 1;
+
+      fprintf (info->mapfile, "  0x%08lx [%3d] ", start_addr + 4 * idx, idx);
+
+      if (info->table_handlers[idx] == (bfd_vma) (-1))
+	fprintf (info->mapfile, "(no handler found)\n");
+
+      else if (info->table_handlers[idx] == info->table_default_handler)
+	{
+	  if (info->table_default_entry)
+	    fprintf (info->mapfile, "(default)\n");
+	  else
+	    fprintf (info->mapfile, "(default)\n");
+	}
+
+      else if (info->table_entries[idx])
+	{
+	  fprintf (info->mapfile, "0x%08lx %s\n", info->table_handlers[idx], info->table_entries[idx]->root.string);
+	}
+
+      else
+	{
+	  fprintf (info->mapfile, "0x%08lx ???\n", info->table_handlers[idx]);
+	}
+    }
+  if (need_elipses)
+    fprintf (info->mapfile, "  . . .\n");
+
+  return TRUE;
+}
+
+void
+rx_additional_link_map_text (bfd *obfd, struct bfd_link_info *info, FILE *mapfile)
+{
+  /* We scan the symbol table looking for $tableentry$'s, and for
+     each, try to deduce which handlers go with which entries.  */
+
+  RX_Table_Info stuff;
+
+  stuff.abfd = obfd;
+  stuff.info = info;
+  stuff.mapfile = mapfile;
+  bfd_hash_traverse (&(info->hash->table), rx_table_map, &stuff);
+}
+
+
 #define ELF_ARCH		bfd_arch_rx
 #define ELF_MACHINE_CODE	EM_RX
 #define ELF_MAXPAGESIZE		0x1000
@@ -3572,6 +3968,7 @@ static const struct bfd_elf_special_section elf32_rx_special_sections[] =
 #define bfd_elf32_bfd_final_link		rx_final_link
 #define bfd_elf32_bfd_relax_section		elf32_rx_relax_section_wrapper
 #define elf_backend_special_sections	        elf32_rx_special_sections
+#define elf_backend_check_directives		rx_check_directives
 
 #include "elf32-target.h"
 
diff --git a/bfd/elf32-rx.h b/bfd/elf32-rx.h
new file mode 100644
index 0000000..3779388
--- /dev/null
+++ b/bfd/elf32-rx.h
@@ -0,0 +1,21 @@
+/* Renesas RX specific support for 32-bit ELF.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+
+void rx_additional_link_map_text (bfd *obfd, struct bfd_link_info *info, FILE *mapfile);
diff --git a/ld/emultempl/aix.em b/ld/emultempl/aix.em
index caa74a9..56985cf 100644
--- a/ld/emultempl/aix.em
+++ b/ld/emultempl/aix.em
@@ -1553,6 +1553,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = {
   NULL,				/* list_options */
   NULL,				/* recognized_file */
   NULL,				/* find potential_libraries */
-  NULL				/* new_vers_pattern */
+  NULL,				/* new_vers_pattern */
+  NULL				/* extra_map_file_text */
 };
 EOF
diff --git a/ld/emultempl/armcoff.em b/ld/emultempl/armcoff.em
index 8e9befc..de10a6c 100644
--- a/ld/emultempl/armcoff.em
+++ b/ld/emultempl/armcoff.em
@@ -279,6 +279,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   gld${EMULATION_NAME}_list_options,
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
-  NULL	/* new_vers_pattern */
+  NULL,	/* new_vers_pattern */
+  NULL	/* extra_map_file_text */
 };
 EOF
diff --git a/ld/emultempl/beos.em b/ld/emultempl/beos.em
index 2196510..732abfd 100644
--- a/ld/emultempl/beos.em
+++ b/ld/emultempl/beos.em
@@ -777,6 +777,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   NULL,	/* list options */
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
-  NULL	/* new_vers_pattern */
+  NULL,	/* new_vers_pattern */
+  NULL	/* extra_map_file_text */
 };
 EOF
diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
index 31761ca..3ebf3b5 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -2498,6 +2498,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   ${LDEMUL_LIST_OPTIONS-gld${EMULATION_NAME}_list_options},
   ${LDEMUL_RECOGNIZED_FILE-gld${EMULATION_NAME}_load_symbols},
   ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
-  ${LDEMUL_NEW_VERS_PATTERN-NULL}
+  ${LDEMUL_NEW_VERS_PATTERN-NULL},
+  ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL}
 };
 EOF
diff --git a/ld/emultempl/generic.em b/ld/emultempl/generic.em
index b22e2a6..aac4b93 100644
--- a/ld/emultempl/generic.em
+++ b/ld/emultempl/generic.em
@@ -156,5 +156,6 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   ${LDEMUL_RECOGNIZED_FILE-NULL},
   ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
   ${LDEMUL_NEW_VERS_PATTERN-NULL}
+  ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL}
 };
 EOF
diff --git a/ld/emultempl/gld960.em b/ld/emultempl/gld960.em
index 0df99e3..5632f31 100644
--- a/ld/emultempl/gld960.em
+++ b/ld/emultempl/gld960.em
@@ -148,6 +148,7 @@ struct ld_emulation_xfer_struct ld_gld960_emulation =
   NULL,	/* list options */
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
-  NULL	/* new_vers_pattern */
+  NULL,	/* new_vers_pattern */
+  NULL	/* extra_map_file_text */
 };
 EOF
diff --git a/ld/emultempl/gld960c.em b/ld/emultempl/gld960c.em
index 805e69b..dd69c79 100644
--- a/ld/emultempl/gld960c.em
+++ b/ld/emultempl/gld960c.em
@@ -161,6 +161,7 @@ struct ld_emulation_xfer_struct ld_gld960coff_emulation =
   NULL,	/* list options */
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
-  NULL	/* new_vers_pattern */
+  NULL,	/* new_vers_pattern */
+  NULL	/* extra_map_file_text */
 };
 EOF
diff --git a/ld/emultempl/linux.em b/ld/emultempl/linux.em
index b30e872..bbc5946 100644
--- a/ld/emultempl/linux.em
+++ b/ld/emultempl/linux.em
@@ -205,6 +205,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   NULL,	/* list options */
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
-  NULL	/* new_vers_pattern */
+  NULL,	/* new_vers_pattern */
+  NULL	/* extra_map_file_text */
 };
 EOF
diff --git a/ld/emultempl/lnk960.em b/ld/emultempl/lnk960.em
index 9c6ff38..6364f6d 100644
--- a/ld/emultempl/lnk960.em
+++ b/ld/emultempl/lnk960.em
@@ -342,6 +342,7 @@ struct ld_emulation_xfer_struct ld_lnk960_emulation =
   NULL,	/* list options */
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
-  NULL	/* new_vers_pattern */
+  NULL,	/* new_vers_pattern */
+  NULL	/* extra_map_file_text */
 };
 EOF
diff --git a/ld/emultempl/m68kcoff.em b/ld/emultempl/m68kcoff.em
index 1ea900a..e46889a 100644
--- a/ld/emultempl/m68kcoff.em
+++ b/ld/emultempl/m68kcoff.em
@@ -239,6 +239,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   NULL,	/* list options */
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
-  NULL	/* new_vers_pattern */
+  NULL,	/* new_vers_pattern */
+  NULL	/* extra_map_file_text */
 };
 EOF
diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em
index ba51cc0..3a37508 100644
--- a/ld/emultempl/pe.em
+++ b/ld/emultempl/pe.em
@@ -2449,6 +2449,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   gld_${EMULATION_NAME}_list_options,
   gld_${EMULATION_NAME}_recognized_file,
   gld_${EMULATION_NAME}_find_potential_libraries,
-  NULL	/* new_vers_pattern.  */
+  NULL,	/* new_vers_pattern.  */
+  NULL	/* extra_map_file_text.  */
 };
 EOF
diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em
index d1575e2..1f78655 100644
--- a/ld/emultempl/pep.em
+++ b/ld/emultempl/pep.em
@@ -2213,6 +2213,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   gld_${EMULATION_NAME}_list_options,
   gld_${EMULATION_NAME}_recognized_file,
   gld_${EMULATION_NAME}_find_potential_libraries,
-  NULL	/* new_vers_pattern.  */
+  NULL,	/* new_vers_pattern.  */
+  NULL	/* extra_map_file_text */
 };
 EOF
diff --git a/ld/emultempl/rxelf.em b/ld/emultempl/rxelf.em
index 5998790..6386abd 100644
--- a/ld/emultempl/rxelf.em
+++ b/ld/emultempl/rxelf.em
@@ -25,6 +25,8 @@
 test -z "$TARGET2_TYPE" && TARGET2_TYPE="rel"
 fragment <<EOF
 
+#include "elf32-rx.h"
+
 static bfd_boolean no_flag_mismatch_warnings = TRUE;
 static bfd_boolean ignore_lma = TRUE;
 
@@ -86,3 +88,5 @@ PARSE_AND_LIST_ARGS_CASES='
 '
 
 LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=rx_elf_create_output_section_statements
+
+LDEMUL_EXTRA_MAP_FILE_TEXT=rx_additional_link_map_text
diff --git a/ld/emultempl/sunos.em b/ld/emultempl/sunos.em
index b527bba..e57e1f0 100644
--- a/ld/emultempl/sunos.em
+++ b/ld/emultempl/sunos.em
@@ -1033,6 +1033,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   NULL,	/* list options */
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
-  NULL	/* new_vers_pattern */
+  NULL,	/* new_vers_pattern */
+  NULL	/* extra_map_file_text */
 };
 EOF
diff --git a/ld/emultempl/ticoff.em b/ld/emultempl/ticoff.em
index a94f937..c403d56 100644
--- a/ld/emultempl/ticoff.em
+++ b/ld/emultempl/ticoff.em
@@ -180,6 +180,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   gld_${EMULATION_NAME}_list_options,
   NULL, /* recognized file */
   NULL,	/* find_potential_libraries */
-  NULL	/* new_vers_pattern */
+  NULL,	/* new_vers_pattern */
+  NULL  /* extra_map_file_text */
 };
 EOF
diff --git a/ld/emultempl/vanilla.em b/ld/emultempl/vanilla.em
index f53a4e3..f8ade99 100644
--- a/ld/emultempl/vanilla.em
+++ b/ld/emultempl/vanilla.em
@@ -81,6 +81,7 @@ struct ld_emulation_xfer_struct ld_vanilla_emulation =
   NULL,	/* list options */
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
-  NULL	/* new_vers_pattern */
+  NULL,	/* new_vers_pattern */
+  NULL	/* extra_map_file_text */
 };
 EOF
diff --git a/ld/ldemul.c b/ld/ldemul.c
index edbc9ee..7409046 100644
--- a/ld/ldemul.c
+++ b/ld/ldemul.c
@@ -348,3 +348,10 @@ ldemul_new_vers_pattern (struct bfd_elf_version_expr *entry)
     entry = (*ld_emulation->new_vers_pattern) (entry);
   return entry;
 }
+
+void
+ldemul_extra_map_file_text (bfd *abfd, struct bfd_link_info *info, FILE *mapf)
+{
+  if (ld_emulation->extra_map_file_text)
+    ld_emulation->extra_map_file_text (abfd, info, mapf);
+}
diff --git a/ld/ldemul.h b/ld/ldemul.h
index a9ea2f6..27b13ad 100644
--- a/ld/ldemul.h
+++ b/ld/ldemul.h
@@ -94,6 +94,8 @@ extern int  ldemul_find_potential_libraries
   (char *, struct lang_input_statement_struct *);
 extern struct bfd_elf_version_expr *ldemul_new_vers_pattern
   (struct bfd_elf_version_expr *);
+extern void ldemul_extra_map_file_text
+  (bfd *, struct bfd_link_info *, FILE *);
 
 typedef struct ld_emulation_xfer_struct {
   /* Run before parsing the command line and script file.
@@ -194,6 +196,11 @@ typedef struct ld_emulation_xfer_struct {
   struct bfd_elf_version_expr * (*new_vers_pattern)
     (struct bfd_elf_version_expr *);
 
+  /* Called when printing the map file, in case there are
+     emulation-specific sections for it.  */
+  void (*extra_map_file_text)
+    (bfd *, struct bfd_link_info *, FILE *);
+
 } ld_emulation_xfer_type;
 
 typedef enum {
diff --git a/ld/ldlang.c b/ld/ldlang.c
index d147ee0..596aecc 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -2123,6 +2123,8 @@ lang_map (void)
     }
   lang_statement_iteration++;
   print_statements ();
+
+  ldemul_extra_map_file_text (link_info.output_bfd, &link_info, config.map_file);
 }
 
 static bfd_boolean



More information about the Binutils mailing list