This is the mail archive of the binutils@sources.redhat.com 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]

powerpc64 ._savef* and ._restf*


._savef14 through ._savef31 and corresponding ._restf* functions are
used by powerpc64-linux-gcc to save and restore floating point regs,
at least past a certain cutoff point for inline saves and restores.
One mildly unusual thing about these functions is that we don't want
them to be exported from shared libraries, as the powerpc64 call
sequence adds quite a bit of overhead.  Instead they are supposed to
be linked statically into each application or shared library needing
them.

For reasons I don't fully understand, it's no longer OK to put these
sort of functions into libgcc.a which IMO is the natural place to
poke them.  The gcc camp wants them to go into libc_nonshared.a,
which would be OK too;  In either case you need to link against
that library when creating applications or shared libraries.  Or you
need to do something a little clever in the linker..

This patch makes the linker generate the functions automagically as
needed, which also has a size benefit of slightly reducing code
size.  I'm also merging .glink into the .text output section where
it belongs.

bfd/ChangeLog
	* elf64-ppc.c (STFD_FR0_0R1, LFD_FR0_0R1, BLR): Define.
	(struct ppc_link_hash_table): Add sfpr.
	(ppc64_elf_link_hash_table_create): Init it.
	(ppc64_elf_create_dynamic_sections): Split creation of .stub and
	.glink out to..
	(create_linkage_sections): ..here.  Make .sfpr too.
	(ppc64_elf_check_relocs): Call create_linkage_sections, and set
	dynobj early.
	(MIN_SAVE_FPR, MAX_SAVE_FPR): Define.
	(ppc64_elf_func_desc_adjust): Look for missing ._savef* and
	._restf* functions, and create as needed.
	(func_desc_adjust): Only force_local for shared libs.

ld/ChangeLog
	* emulparams/elf64ppc.sh (OTHER_TEXT_SECTIONS): Define.

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.28
diff -u -p -r1.28 elf64-ppc.c
--- elf64-ppc.c	2002/02/12 06:34:57	1.28
+++ elf64-ppc.c	2002/02/18 11:18:30
@@ -51,6 +51,8 @@ static struct bfd_hash_entry *link_hash_
   PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
 static struct bfd_link_hash_table *ppc64_elf_link_hash_table_create
   PARAMS ((bfd *));
+static boolean create_linkage_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
 static boolean create_got_section
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean ppc64_elf_create_dynamic_sections
@@ -153,6 +155,11 @@ static boolean ppc64_elf_finish_dynamic_
 #define LIS_R0_0	0x3c000000	/* lis   %r0,0		*/
 #define ORI_R0_R0_0	0x60000000	/* ori	 %r0,%r0,0	*/
 
+/* Instructions to save and restore floating point regs.  */
+#define STFD_FR0_0R1	0xd8010000	/* stfd  %fr0,0(%r1)	*/
+#define LFD_FR0_0R1	0xc8010000	/* lfd   %fr0,0(%r1)	*/
+#define BLR		0x4e800020	/* blr			*/
+
 /* Since .opd is an array of descriptors and each entry will end up
    with identical R_PPC64_RELATIVE relocs, there is really no need to
    propagate .opd relocs;  The dynamic linker should be taught to
@@ -1719,6 +1726,7 @@ struct ppc_link_hash_table
   asection *srelbss;
   asection *sstub;
   asection *sglink;
+  asection *sfpr;
 
   /* Set on error.  */
   int plt_overflow;
@@ -1790,12 +1798,49 @@ ppc64_elf_link_hash_table_create (abfd)
   htab->srelbss = NULL;
   htab->sstub = NULL;
   htab->sglink = NULL;
+  htab->sfpr = NULL;
   htab->plt_overflow = 0;
   htab->sym_sec.abfd = NULL;
 
   return &htab->elf.root;
 }
 
+/* Create sections for linker generated code.  */
+
+static boolean
+create_linkage_sections (dynobj, info)
+     bfd *dynobj;
+     struct bfd_link_info *info;
+{
+  struct ppc_link_hash_table *htab;
+  flagword flags;
+
+  htab = ppc_hash_table (info);
+
+  /* Create .sfpr for code to save and restore fp regs.  */
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
+	   | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+  htab->sfpr = bfd_make_section (dynobj, ".sfpr");
+  if (htab->sfpr == NULL
+      || ! bfd_set_section_flags (dynobj, htab->sfpr, flags)
+      || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
+    return false;
+
+  /* Create .stub and .glink for global linkage functions.  */
+  htab->sstub = bfd_make_section (dynobj, ".stub");
+  if (htab->sstub == NULL
+      || ! bfd_set_section_flags (dynobj, htab->sstub, flags)
+      || ! bfd_set_section_alignment (dynobj, htab->sstub, 2))
+    return false;
+  htab->sglink = bfd_make_section (dynobj, ".glink");
+  if (htab->sglink == NULL
+      || ! bfd_set_section_flags (dynobj, htab->sglink, flags)
+      || ! bfd_set_section_alignment (dynobj, htab->sglink, 2))
+    return false;
+
+  return true;
+}
+
 /* Create .got and .rela.got sections in DYNOBJ, and set up
    shortcuts to them in our hash table.  */
 
@@ -1825,8 +1870,7 @@ create_got_section (dynobj, info)
   return true;
 }
 
-/* Create the .stub and .glink sections as well as the ordinary
-   dynamic sections.  */
+/* Create the dynamic sections, and set up shortcuts.  */
 
 static boolean
 ppc64_elf_create_dynamic_sections (dynobj, info)
@@ -1834,7 +1878,6 @@ ppc64_elf_create_dynamic_sections (dynob
      struct bfd_link_info *info;
 {
   struct ppc_link_hash_table *htab;
-  flagword flags;
 
   htab = ppc_hash_table (info);
   if (!htab->sgot && !create_got_section (dynobj, info))
@@ -1853,20 +1896,6 @@ ppc64_elf_create_dynamic_sections (dynob
       || (!info->shared && !htab->srelbss))
     abort ();
 
-  /* Create .stub and .glink for global linkage functions.  */
-  flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
-	   | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-  htab->sstub = bfd_make_section (dynobj, ".stub");
-  if (htab->sstub == NULL
-      || ! bfd_set_section_flags (dynobj, htab->sstub, flags)
-      || ! bfd_set_section_alignment (dynobj, htab->sstub, 2))
-    return false;
-  htab->sglink = bfd_make_section (dynobj, ".glink");
-  if (htab->sglink == NULL
-      || ! bfd_set_section_flags (dynobj, htab->sglink, flags)
-      || ! bfd_set_section_alignment (dynobj, htab->sglink, 3))
-    return false;
-
   return true;
 }
 
@@ -1955,6 +1984,12 @@ ppc64_elf_check_relocs (abfd, info, sec,
   sreloc = NULL;
   is_opd = strcmp (bfd_get_section_name (abfd, sec), ".opd") == 0;
 
+  if (htab->elf.dynobj == NULL)
+    htab->elf.dynobj = abfd;
+  if (htab->sfpr == NULL
+      && !create_linkage_sections (htab->elf.dynobj, info))
+    return false;
+
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
     {
@@ -1980,13 +2015,9 @@ ppc64_elf_check_relocs (abfd, info, sec,
 	case R_PPC64_GOT16_LO_DS:
 
 	  /* This symbol requires a global offset table entry.  */
-	  if (htab->sgot == NULL)
-	    {
-	      if (htab->elf.dynobj == NULL)
-		htab->elf.dynobj = abfd;
-	      if (!create_got_section (htab->elf.dynobj, info))
-		return false;
-	    }
+	  if (htab->sgot == NULL
+	      && !create_got_section (htab->elf.dynobj, info))
+	    return false;
 
 	  if (h != NULL)
 	    {
@@ -2197,9 +2228,6 @@ ppc64_elf_check_relocs (abfd, info, sec,
 		      bfd_set_error (bfd_error_bad_value);
 		    }
 
-		  if (htab->elf.dynobj == NULL)
-		    htab->elf.dynobj = abfd;
-
 		  dynobj = htab->elf.dynobj;
 		  sreloc = bfd_get_section_by_name (dynobj, name);
 		  if (sreloc == NULL)
@@ -2554,25 +2582,117 @@ func_desc_adjust (h, inf)
 	 been imported from another library.  Function code syms that
 	 are really in the library we must leave global to prevent the
 	 linker dragging in a definition from a static library.  */
-      force_local = (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0;
+      force_local = ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+		     && info->shared);
       _bfd_elf_link_hash_hide_symbol (info, h, force_local);
     }
 
   return true;
 }
 
+#define MIN_SAVE_FPR 14
+#define MAX_SAVE_FPR 31
+
 /* Called near the start of bfd_elf_size_dynamic_sections.  We use
-   this hook to transfer dynamic linking information gathered so far
-   on function code symbol entries, to their corresponding function
-   descriptor symbol entries.  */
+   this hook to a) provide some gcc support functions, and b) transfer
+   dynamic linking information gathered so far on function code symbol
+   entries, to their corresponding function descriptor symbol entries.  */
 static boolean
 ppc64_elf_func_desc_adjust (obfd, info)
      bfd *obfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
   struct ppc_link_hash_table *htab;
+  unsigned int lowest_savef = MAX_SAVE_FPR + 2;
+  unsigned int lowest_restf = MAX_SAVE_FPR + 2;
+  unsigned int i;
+  struct elf_link_hash_entry *h;
+  char sym[10];
 
   htab = ppc_hash_table (info);
+
+  if (htab->sfpr == NULL)
+    /* We don't have any relocs.  */
+    return true;
+
+  /* First provide any missing ._savef* and ._restf* functions.  */
+  memcpy (sym, "._savef14", 10);
+  for (i = MIN_SAVE_FPR; i <= MAX_SAVE_FPR; i++)
+    {
+      sym[7] = i / 10 + '0';
+      sym[8] = i % 10 + '0';
+      h = elf_link_hash_lookup (&htab->elf, sym, false, false, true);
+      if (h != NULL
+	  && h->root.type == bfd_link_hash_undefined)
+	{
+	  if (lowest_savef > i)
+	    lowest_savef = i;
+	  h->root.type = bfd_link_hash_defined;
+	  h->root.u.def.section = htab->sfpr;
+	  h->root.u.def.value = (i - lowest_savef) * 4;
+	  h->type = STT_FUNC;
+	  h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+	  _bfd_elf_link_hash_hide_symbol (info, h, info->shared);
+	}
+    }
+
+  memcpy (sym, "._restf14", 10);
+  for (i = MIN_SAVE_FPR; i <= MAX_SAVE_FPR; i++)
+    {
+      sym[7] = i / 10 + '0';
+      sym[8] = i % 10 + '0';
+      h = elf_link_hash_lookup (&htab->elf, sym, false, false, true);
+      if (h != NULL
+	  && h->root.type == bfd_link_hash_undefined)
+	{
+	  if (lowest_restf > i)
+	    lowest_restf = i;
+	  h->root.type = bfd_link_hash_defined;
+	  h->root.u.def.section = htab->sfpr;
+	  h->root.u.def.value = ((MAX_SAVE_FPR + 2 - lowest_savef) * 4
+				 + (i - lowest_restf) * 4);
+	  h->type = STT_FUNC;
+	  h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+	  _bfd_elf_link_hash_hide_symbol (info, h, info->shared);
+	}
+    }
+
+  htab->sfpr->_raw_size = ((MAX_SAVE_FPR + 2 - lowest_savef) * 4
+			   + (MAX_SAVE_FPR + 2 - lowest_restf) * 4);
+
+  if (htab->sfpr->_raw_size == 0)
+    {
+      _bfd_strip_section_from_output (info, htab->sfpr);
+    }
+  else
+    {
+      bfd_byte *p = (bfd_byte *) bfd_alloc (htab->elf.dynobj,
+					    htab->sfpr->_raw_size);
+      if (p == NULL)
+	return false;
+      htab->sfpr->contents = p;
+
+      for (i = lowest_savef; i <= MAX_SAVE_FPR; i++)
+	{
+	  unsigned int fpr = i << 21;
+	  unsigned int stackoff = (1 << 16) - (MAX_SAVE_FPR + 1 - i) * 8;
+	  bfd_put_32 (htab->elf.dynobj, STFD_FR0_0R1 + fpr + stackoff, p);
+	  p += 4;
+	}
+      bfd_put_32 (htab->elf.dynobj, BLR, p);
+      p += 4;
+
+      for (i = lowest_restf; i <= MAX_SAVE_FPR; i++)
+	{
+	  unsigned int fpr = i << 21;
+	  unsigned int stackoff = (1 << 16) - (MAX_SAVE_FPR + 1 - i) * 8;
+	  bfd_put_32 (htab->elf.dynobj, LFD_FR0_0R1 + fpr + stackoff, p);
+	  p += 4;
+	}
+      bfd_put_32 (htab->elf.dynobj, BLR, p);
+      p += 4;
+    }
+
   elf_link_hash_traverse (&htab->elf, func_desc_adjust, (PTR) info);
   return true;
 }
Index: ld/emulparams/elf64ppc.sh
===================================================================
RCS file: /cvs/src/src/ld/emulparams/elf64ppc.sh,v
retrieving revision 1.2
diff -u -p -r1.2 elf64ppc.sh
--- elf64ppc.sh	2002/01/16 05:52:36	1.2
+++ elf64ppc.sh	2002/02/18 10:19:17
@@ -15,6 +15,7 @@ CTOR_START='PROVIDE (__CTOR_LIST__ = .);
 CTOR_END='PROVIDE (__CTOR_END__ = .); PROVIDE (___CTOR_END__ = .);'
 DTOR_START='PROVIDE (__DTOR_LIST__ = .); PROVIDE (___DTOR_LIST__ = .);'
 DTOR_END='PROVIDE (__DTOR_END__ = .); PROVIDE (___DTOR_END__ = .);'
+OTHER_TEXT_SECTIONS="*(.sfpr .glink)"
 BSS_PLT=
 OTHER_BSS_SYMBOLS="
   .tocbss	${RELOCATING-0}${RELOCATING+ALIGN(8)} : { *(.tocbss)}"


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