powerpc64 linux dot symbols

Alan Modra amodra@bigpond.net.au
Tue Aug 10 11:55:00 GMT 2004


This is the gcc part of my patch to binutils+gcc to remove use of "dot"
symbols on PowerPC64 Linux function entry points.  The main reason for
making this change is to remove a user visible PowerPC64 ELF wart:
Functions called names like "data" and "dynamic" won't compile, since
the associated dot symbols, ".data" and ".dynamic" clash with ELF
section names.  A secondary reason is that reducing the number of global
symbols speeds application load time, because ld.so's symbol table is
somewhat smaller.


So, what's different?

Old

function call:		bl .foo
descriptor sym:		foo, type=object, size=24
entry sym:		.foo, type=function, size=<function code size>
descriptor:		.quad .foo, .TOC.@tocbase, 0

New

function call:		bl foo
descriptor sym:		foo, type=function, size=<function code size>
entry sym:		.LEfoo local sym (won't appear in object)
descriptor:		.quad .LEfoo, .TOC.@tocbase, 0

Note that old descriptor syms have been given type "function" by the
linker in executables and dynamic libraries for quite some time.
(see http://sources.redhat.com/ml/binutils/2004-03/msg00550.html)
So for tools like FDPR that process binaries, the net change in
executables is that dot symbols are missing, and function size is
attached to a different symbol.

Of course, this change has implications in other parts of the
toolchain.  For instance, I need to make some changes to objdump,
as .text tends to be one large block of code without any symbols.
gdb likely needs some work too, as it will need to look up function
descriptors to find code addresses.  glibc is probably OK, although I
haven't yet compiled it with the new compiler.  One very fortunate
property of old dynamic libraries is that they don't make references
to external dot symbols, so there shouldn't be any change needed in
ld.so.


Testing of the following patch against mainline hasn't completed yet,
but a virtually identical patch against 3.4 has survived bootstrap and
regression testing on powerpc64-linux, with both old and new linkers.

	* config/rs6000/linux64.h (DOT_SYMBOLS): Define.
	(CRT_CALL_STATIC_FUNCTION): Define !DOT_SYMBOLS version.
	(ASM_DECLARE_FUNCTION_SIZE): Modify for !DOT_SYMBOLS.
	(ASM_OUTPUT_SOURCE_LINE, DBX_OUTPUT_BRAC, DBX_OUTPUT_NFUN): Likewise.
	* config/rs6000/rs6000-protos.h (rs6000_output_function_entry): Decl.
	* config/rs6000/rs6000.c (rs6000_output_function_entry): New function,
	modified for !DOT_SYMBOLS..
	(print_operand <case 'z'>): ..extracted from here.
	(rs6000_assemble_visibility): Modify for !DOT_SYMBOLS.
	(rs6000_output_function_epilogue): Likewise.
	(rs6000_elf_declare_function_name): Likewise.
	* config/rs6000/rs6000.h (DOT_SYMBOLS): Define.
	(ASM_WEAKEN_DECL, ASM_OUTPUT_DEF_FROM_DECLS): Modify for !DOT_SYMBOLS.
	* configure.ac (HAVE_LD_NO_DOT_SYMS): Add new AC_DEFINE.
	* configure: Regenerate.
	* config.in: Regenerate.

Index: gcc/configure.ac
===================================================================
RCS file: /cvs/gcc/gcc/gcc/configure.ac,v
retrieving revision 2.50
diff -u -p -r2.50 configure.ac
--- gcc/configure.ac	23 Jul 2004 06:59:34 -0000	2.50
+++ gcc/configure.ac	9 Aug 2004 23:52:02 -0000
@@ -2857,6 +2857,47 @@ if test x"$gcc_cv_ld_as_needed" = xyes; 
 [Define if your linker supports --as-needed and --no-as-needed options.])
 fi
 
+case "$target" in
+  powerpc64*-*-linux*)
+    AC_CACHE_CHECK(linker support for omitting dot symbols,
+    gcc_cv_ld_no_dot_syms,
+    [gcc_cv_ld_no_dot_syms=no
+    if test $in_tree_ld = yes ; then
+      if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 16 -o "$gcc_cv_gld_major_version" -gt 2; then
+        gcc_cv_ld_no_dot_syms=yes
+      fi
+    elif test x$gcc_cv_as != x -a x$gcc_cv_ld != x ; then
+      cat > conftest1.s <<EOF
+	.text
+	bl foo
+EOF
+      cat > conftest2.s <<EOF
+	.section ".opd","aw"
+	.align 3
+	.globl foo
+	.type foo,@function
+foo:
+	.quad .LEfoo,.TOC.@tocbase,0
+	.text
+.LEfoo:
+	blr
+	.size foo,.-.LEfoo
+EOF
+      if $gcc_cv_as -o conftest1.o conftest1.s > /dev/null 2>&1 \
+         && $gcc_cv_as -o conftest2.o conftest2.s > /dev/null 2>&1 \
+         && $gcc_cv_ld -o conftest conftest1.o conftest2.o > /dev/null 2>&1; then
+        gcc_cv_ld_no_dot_syms=yes
+      fi
+      rm -f conftest conftest1.o conftest2.o conftest1.s conftest2.s
+    fi
+    ])
+    if test x"$gcc_cv_ld_no_dot_syms" = xyes; then
+      AC_DEFINE(HAVE_LD_NO_DOT_SYMS, 1,
+    [Define if your PowerPC64 linker only needs function descriptor syms.])
+    fi
+    ;;
+esac
+
 if test x$with_sysroot = x && test x$host = x$target \
    && test "$prefix" != "/usr" && test "x$prefix" != "x$local_prefix" ; then
   AC_DEFINE_UNQUOTED(PREFIX_INCLUDE_DIR, "$prefix/include",
Index: gcc/config/rs6000/linux64.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/linux64.h,v
retrieving revision 1.62
diff -u -p -r1.62 linux64.h
--- gcc/config/rs6000/linux64.h	13 Jul 2004 07:45:04 -0000	1.62
+++ gcc/config/rs6000/linux64.h	9 Aug 2004 23:52:06 -0000
@@ -50,6 +50,12 @@
 #undef	TARGET_AIX
 #define	TARGET_AIX TARGET_64BIT
 
+#ifdef HAVE_LD_NO_DOT_SYMS
+/* New ABI uses a local sym for the function entry point.  */
+#undef DOT_SYMBOLS
+#define DOT_SYMBOLS 0
+#endif
+
 #undef PROCESSOR_DEFAULT64
 #define PROCESSOR_DEFAULT64 PROCESSOR_PPC630
 
@@ -386,11 +398,19 @@
    object files, each potentially with a different TOC pointer.  For
    that reason, place a nop after the call so that the linker can
    restore the TOC pointer if a TOC adjusting call stub is needed.  */
+#if DOT_SYMBOLS
 #define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC)	\
   asm (SECTION_OP "\n"					\
 "	bl ." #FUNC "\n"				\
 "	nop\n"						\
 "	.previous");
+#else
+#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC)	\
+  asm (SECTION_OP "\n"					\
+"	bl " #FUNC "\n"					\
+"	nop\n"						\
+"	.previous");
+#endif
 #endif
 
 /* FP save and restore routines.  */
@@ -415,13 +435,11 @@
       if (!flag_inhibit_size_directive)					\
 	{								\
 	  fputs ("\t.size\t", (FILE));					\
-	  if (TARGET_64BIT)						\
+	  if (TARGET_64BIT && DOT_SYMBOLS)				\
 	    putc ('.', (FILE));						\
 	  assemble_name ((FILE), (FNAME));				\
 	  fputs (",.-", (FILE));					\
-	  if (TARGET_64BIT)						\
-	    putc ('.', (FILE));						\
-	  assemble_name ((FILE), (FNAME));				\
+	  rs6000_output_function_entry (FILE, FNAME);			\
 	  putc ('\n', (FILE));						\
 	}								\
     }									\
@@ -465,14 +483,13 @@
 do									\
   {									\
     char temp[256];							\
+    const char *s;							\
     ASM_GENERATE_INTERNAL_LABEL (temp, "LM", COUNTER);			\
     fprintf (FILE, "\t.stabn 68,0,%d,", LINE);				\
     assemble_name (FILE, temp);						\
     putc ('-', FILE);							\
-    if (TARGET_64BIT)							\
-      putc ('.', FILE);							\
-    assemble_name (FILE,						\
-		   XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));\
+    s = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);		\
+    rs6000_output_function_entry (FILE, s);				\
     putc ('\n', FILE);							\
     (*targetm.asm_out.internal_label) (FILE, "LM", COUNTER);		\
   }									\
@@ -482,19 +499,20 @@ while (0)
 #define DBX_OUTPUT_BRAC(FILE, NAME, BRAC) \
   do									\
     {									\
-      const char *flab;							\
+      const char *s;							\
       fprintf (FILE, "%s%d,0,0,", ASM_STABN_OP, BRAC);			\
       assemble_name (FILE, NAME);					\
       putc ('-', FILE);							\
       if (current_function_func_begin_label != NULL_TREE)		\
-	flab = IDENTIFIER_POINTER (current_function_func_begin_label);	\
+	{								\
+	  s = IDENTIFIER_POINTER (current_function_func_begin_label);	\
+	  assemble_name (FILE, s);					\
+	}								\
       else								\
 	{								\
-	  if (TARGET_64BIT)						\
-	    putc ('.', FILE);						\
-	  flab = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);	\
+	  s = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);	\
+	  rs6000_output_function_entry (FILE, s);			\
 	}								\
-      assemble_name (FILE, flab);					\
       putc ('\n', FILE);						\
     }									\
   while (0)
@@ -506,12 +524,12 @@ while (0)
 #define	DBX_OUTPUT_NFUN(FILE, LSCOPE, DECL)				\
   do									\
     {									\
+      const char *s;							\
       fprintf (FILE, "%s\"\",%d,0,0,", ASM_STABS_OP, N_FUN);		\
       assemble_name (FILE, LSCOPE);					\
       putc ('-', FILE);							\
-      if (TARGET_64BIT)							\
-        putc ('.', FILE);						\
-      assemble_name (FILE, XSTR (XEXP (DECL_RTL (DECL), 0), 0));	\
+      s = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);		\
+      rs6000_output_function_entry (FILE, s);				\
       putc ('\n', FILE);						\
     }									\
   while (0)
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000-protos.h,v
retrieving revision 1.85
diff -u -p -r1.85 rs6000-protos.h
--- gcc/config/rs6000/rs6000-protos.h	28 Jul 2004 12:13:13 -0000	1.85
+++ gcc/config/rs6000/rs6000-protos.h	9 Aug 2004 23:52:06 -0000
@@ -110,6 +110,7 @@ extern enum reg_class secondary_reload_c
 extern int ccr_bit (rtx, int);
 extern int extract_MB (rtx);
 extern int extract_ME (rtx);
+extern void rs6000_output_function_entry (FILE *, const char *);
 extern void print_operand (FILE *, rtx, int);
 extern void print_operand_address (FILE *, rtx);
 extern enum rtx_code rs6000_reverse_condition (enum machine_mode,
Index: gcc/config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.675
diff -u -p -r1.675 rs6000.c
--- gcc/config/rs6000/rs6000.c	2 Aug 2004 01:46:39 -0000	1.675
+++ gcc/config/rs6000/rs6000.c	9 Aug 2004 23:52:15 -0000
@@ -9543,6 +9539,36 @@ rs6000_get_some_local_dynamic_name_1 (rt
   return 0;
 }
 
+/* Write out a function code label.  */
+
+void
+rs6000_output_function_entry (FILE *file, const char *fname)
+{
+  if (fname[0] != '.')
+    {
+      switch (DEFAULT_ABI)
+	{
+	default:
+	  abort ();
+
+	case ABI_AIX:
+	  if (DOT_SYMBOLS)
+	    putc ('.', file);
+	  else
+	    ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LE");
+	  break;
+
+	case ABI_V4:
+	case ABI_DARWIN:
+	  break;
+	}
+    }
+  if (TARGET_AIX)
+    RS6000_OUTPUT_BASENAME (file, fname);
+  else
+    assemble_name (file, fname);
+}
+
 /* Print an operand.  Recognize special options, documented below.  */
 
 #if TARGET_ELF
@@ -10075,23 +10101,7 @@ print_operand (FILE *file, rtx x, int co
       if (SYMBOL_REF_DECL (x))
         mark_decl_referenced (SYMBOL_REF_DECL (x));
 
-      if (XSTR (x, 0)[0] != '.')
-	{
-	  switch (DEFAULT_ABI)
-	    {
-	    default:
-	      abort ();
-
-	    case ABI_AIX:
-	      putc ('.', file);
-	      break;
-
-	    case ABI_V4:
-	    case ABI_DARWIN:
-	      break;
-	    }
-	}
-      /* For macho, we need to check it see if we need a stub.  */
+      /* For macho, check to see if we need a stub.  */
       if (TARGET_MACHO)
 	{
 	  const char *name = XSTR (x, 0);
@@ -10102,10 +10112,10 @@ print_operand (FILE *file, rtx x, int co
 #endif
 	  assemble_name (file, name);
 	}
-     else if (TARGET_AIX)
-	RS6000_OUTPUT_BASENAME (file, XSTR (x, 0));
-      else
+      else if (!DOT_SYMBOLS)
 	assemble_name (file, XSTR (x, 0));
+      else
+	rs6000_output_function_entry (file, XSTR (x, 0));
       return;
 
     case 'Z':
@@ -10361,7 +10371,9 @@ rs6000_assemble_visibility (tree decl, i
 {
   /* Functions need to have their entry point symbol visibility set as
      well as their descriptor symbol visibility.  */
-  if (DEFAULT_ABI == ABI_AIX && TREE_CODE (decl) == FUNCTION_DECL)
+  if (DEFAULT_ABI == ABI_AIX
+      && DOT_SYMBOLS
+      && TREE_CODE (decl) == FUNCTION_DECL)
     {
       static const char * const visibility_types[] = {
         NULL, "internal", "hidden", "protected"
@@ -13686,17 +13698,12 @@ rs6000_output_function_epilogue (FILE *f
       /* Offset from start of code to tb table.  */
       fputs ("\t.long ", file);
       ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
-#if TARGET_AIX
-      RS6000_OUTPUT_BASENAME (file, fname);
-#else
-      assemble_name (file, fname);
-#endif
-      fputs ("-.", file);
-#if TARGET_AIX
-      RS6000_OUTPUT_BASENAME (file, fname);
-#else
-      assemble_name (file, fname);
-#endif
+      if (TARGET_AIX)
+	RS6000_OUTPUT_BASENAME (file, fname);
+      else
+	assemble_name (file, fname);
+      putc ('-', file);
+      rs6000_output_function_entry (file, fname);
       putc ('\n', file);
 
       /* Interrupt handler mask.  */
@@ -16262,22 +16269,27 @@ rs6000_elf_declare_function_name (FILE *
       fputs ("\t.section\t\".opd\",\"aw\"\n\t.align 3\n", file);
       ASM_OUTPUT_LABEL (file, name);
       fputs (DOUBLE_INT_ASM_OP, file);
-      putc ('.', file);
-      assemble_name (file, name);
-      fputs (",.TOC.@tocbase,0\n\t.previous\n\t.size\t", file);
-      assemble_name (file, name);
-      fputs (",24\n\t.type\t.", file);
-      assemble_name (file, name);
-      fputs (",@function\n", file);
-      if (TREE_PUBLIC (decl) && ! DECL_WEAK (decl))
+      rs6000_output_function_entry (file, name);
+      fputs (",.TOC.@tocbase,0\n\t.previous\n", file);
+      if (DOT_SYMBOLS)
 	{
-	  fputs ("\t.globl\t.", file);
+	  fputs ("\t.size\t", file);
 	  assemble_name (file, name);
-	  putc ('\n', file);
+	  fputs (",24\n\t.type\t.", file);
+	  assemble_name (file, name);
+	  fputs (",@function\n", file);
+	  if (TREE_PUBLIC (decl) && ! DECL_WEAK (decl))
+	    {
+	      fputs ("\t.globl\t.", file);
+	      assemble_name (file, name);
+	      putc ('\n', file);
+	    }
 	}
+      else
+	ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
       ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
-      putc ('.', file);
-      ASM_OUTPUT_LABEL (file, name);
+      rs6000_output_function_entry (file, name);
+      fputs (":\n", file);
       return;
     }
 
Index: gcc/config/rs6000/rs6000.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.329
diff -u -p -r1.329 rs6000.h
--- gcc/config/rs6000/rs6000.h	16 Jul 2004 23:25:47 -0000	1.329
+++ gcc/config/rs6000/rs6000.h	9 Aug 2004 23:52:17 -0000
@@ -40,6 +40,10 @@
 #define TARGET_AIX 0
 #endif
 
+/* Control whether function entry points use a "dot" symbol when
+   ABI_AIX.  */
+#define DOT_SYMBOLS 1
+
 /* Default string to use for cpu if not specified.  */
 #ifndef TARGET_CPU_DEFAULT
 #define TARGET_CPU_DEFAULT ((char *)0)
@@ -2233,9 +2237,9 @@ extern int toc_initialized;
   do									\
     {									\
       fputs ("\t.weak\t", (FILE));					\
-      RS6000_OUTPUT_BASENAME ((FILE), (NAME)); 			\
+      RS6000_OUTPUT_BASENAME ((FILE), (NAME)); 				\
       if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL			\
-	  && DEFAULT_ABI == ABI_AIX)					\
+	  && DEFAULT_ABI == ABI_AIX && DOT_SYMBOLS)			\
 	{								\
 	  if (TARGET_XCOFF)						\
 	    fputs ("[DS]", (FILE));					\
@@ -2247,7 +2251,7 @@ extern int toc_initialized;
 	{								\
 	  ASM_OUTPUT_DEF ((FILE), (NAME), (VAL));			\
 	  if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL		\
-	      && DEFAULT_ABI == ABI_AIX)				\
+	      && DEFAULT_ABI == ABI_AIX && DOT_SYMBOLS)			\
 	    {								\
 	      fputs ("\t.set\t.", (FILE));				\
 	      RS6000_OUTPUT_BASENAME ((FILE), (NAME));			\
@@ -2268,7 +2272,7 @@ extern int toc_initialized;
       const char *alias = XSTR (XEXP (DECL_RTL (DECL), 0), 0);		\
       const char *name = IDENTIFIER_POINTER (TARGET);			\
       if (TREE_CODE (DECL) == FUNCTION_DECL				\
-	  && DEFAULT_ABI == ABI_AIX)					\
+	  && DEFAULT_ABI == ABI_AIX && DOT_SYMBOLS)			\
 	{								\
 	  if (TREE_PUBLIC (DECL))					\
 	    {								\

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre



More information about the Gcc-patches mailing list