Commit: Do not treat annobin symbols as potential function symbols

Message ID 87pmyek7ld.fsf@redhat.com
State New
Headers show
Series
  • Commit: Do not treat annobin symbols as potential function symbols
Related show

Commit Message

Richard Earnshaw via Binutils April 28, 2021, 10:48 a.m.
Hi Guys,

  I am applying the attached patch to stop the BFD library from treating
  symbols created by the annobin plugins for gcc and clang as if they
  were potential function symbols.

Cheers
  Nick

bfd/ChangeLog
2021-04-28  Nick Clifton  <nickc@redhat.com>

	* elf.c (_bfd_elf_maybe_function_sym): Do not accept annobin
	symbols as potential function symbols.
	* elfnn-aarch64.c (elfNN_aarch64_maybe_function_sym): Likewise.
	* elf64-ppc.c (ppc64_elf_maybe_function_sym): Likewise.
	* elf32-arm.c (elf32_arm_maybe_function_sym): Likewise.

ld/ChangeLog
2021-04-28  Nick Clifton  <nickc@redhat.com>

	* testsuite/ld-elf/anno-sym.s: New test source file.
	* testsuite/ld-elf/anno-sym.d: New test driver.
	* testsuite/ld-elf/anno-sym.l: New test error output.

Patch

diff --git a/bfd/elf.c b/bfd/elf.c
index 4846b7bd47f..851440b7652 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -12618,19 +12618,30 @@  _bfd_elf_maybe_function_sym (const asymbol *sym, asection *sec,
 			     bfd_vma *code_off)
 {
   bfd_size_type size;
+  elf_symbol_type * elf_sym = (elf_symbol_type *) sym;
 
   if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
 		     | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0
       || sym->section != sec)
     return 0;
 
+  size = (sym->flags & BSF_SYNTHETIC) ? 0 : elf_sym->internal_elf_sym.st_size;
+  
+  /* In theory we should check that the symbol's type satisfies
+     _bfd_elf_is_function_type(), but there are some function-like
+     symbols which would fail this test.  (eg _start).  Instead
+     we check for hidden, local, notype symbols with zero size.
+     This type of symbol is generated by the annobin plugin for gcc
+     and clang, and should not be considered to be a function symbol.  */
+  if (size == 0
+      && ((sym->flags & (BSF_SYNTHETIC | BSF_LOCAL)) == BSF_LOCAL)
+      && ELF_ST_TYPE (elf_sym->internal_elf_sym.st_info) == STT_NOTYPE
+      && ELF_ST_VISIBILITY (elf_sym->internal_elf_sym.st_other) == STV_HIDDEN)
+    return 0;
+  
   *code_off = sym->value;
-  size = 0;
-  if (!(sym->flags & BSF_SYNTHETIC))
-    size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
-  if (size == 0)
-    size = 1;
-  return size;
+  /* Do not return 0 for the function's size.  */
+  return size ? size : 1;
 }
 
 /* Set to non-zero to enable some debug messages.  */
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 81667ea090d..79b94e836fc 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -15898,35 +15898,44 @@  elf32_arm_maybe_function_sym (const asymbol *sym, asection *sec,
 			      bfd_vma *code_off)
 {
   bfd_size_type size;
+  elf_symbol_type * elf_sym = (elf_symbol_type *) sym;
 
   if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
 		     | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0
       || sym->section != sec)
     return 0;
 
+  size = (sym->flags & BSF_SYNTHETIC) ? 0 : elf_sym->internal_elf_sym.st_size;
+
   if (!(sym->flags & BSF_SYNTHETIC))
-    switch (ELF_ST_TYPE (((elf_symbol_type *) sym)->internal_elf_sym.st_info))
+    switch (ELF_ST_TYPE (elf_sym->internal_elf_sym.st_info))
       {
+	case STT_NOTYPE:
+	  /* Ignore symbols created by the annobin plugin for gcc and clang.
+	     These symbols are hidden, local, notype and have a size of 0.  */
+	  if (size == 0
+	      && sym->flags & BSF_LOCAL
+	      && ELF_ST_VISIBILITY (elf_sym->internal_elf_sym.st_other) == STV_HIDDEN)
+	    return 0;
+	  /* Fall through.  */
 	case STT_FUNC:
 	case STT_ARM_TFUNC:
-	case STT_NOTYPE:
+	  /* FIXME: Allow STT_GNU_IFUNC as well ?  */
 	  break;
 	default:
 	  return 0;
       }
-
+											     
   if ((sym->flags & BSF_LOCAL)
       && bfd_is_arm_special_symbol_name (sym->name,
 					 BFD_ARM_SPECIAL_SYM_TYPE_ANY))
     return 0;
 
   *code_off = sym->value;
-  size = 0;
-  if (!(sym->flags & BSF_SYNTHETIC))
-    size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
-  if (size == 0)
-    size = 1;
-  return size;
+
+  /* Do not return 0 for the function's size.  */
+  return size ? size : 1;
+
 }
 
 static bool
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 08227f0e43a..ed72de27507 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -5534,14 +5534,25 @@  ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec,
 			      bfd_vma *code_off)
 {
   bfd_size_type size;
+  elf_symbol_type * elf_sym = (elf_symbol_type *) sym;
 
   if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
 		     | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0)
     return 0;
 
-  size = 0;
-  if (!(sym->flags & BSF_SYNTHETIC))
-    size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
+  size = (sym->flags & BSF_SYNTHETIC) ? 0 : elf_sym->internal_elf_sym.st_size;
+
+  /* In theory we should check that the symbol's type satisfies
+     _bfd_elf_is_function_type(), but there are some function-like
+     symbols which would fail this test.  (eg _start).  Instead
+     we check for hidden, local, notype symbols with zero size.
+     This type of symbol is generated by the annobin plugin for gcc
+     and clang, and should not be considered to be a function symbol.  */
+  if (size == 0
+      && ((sym->flags & (BSF_SYNTHETIC | BSF_LOCAL)) == BSF_LOCAL)
+      && ELF_ST_TYPE (elf_sym->internal_elf_sym.st_info) == STT_NOTYPE
+      && ELF_ST_VISIBILITY (elf_sym->internal_elf_sym.st_other) == STV_HIDDEN)
+    return 0;
 
   if (strcmp (sym->section->name, ".opd") == 0)
     {
@@ -5585,9 +5596,9 @@  ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec,
 	return 0;
       *code_off = sym->value;
     }
-  if (size == 0)
-    size = 1;
-  return size;
+
+  /* Do not return 0 for the function's size.  */
+  return size ? size : 1;
 }
 
 /* Return true if symbol is a strong function defined in an ELFv2
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 0a1d7a617c8..b6f083e430b 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -8012,34 +8012,42 @@  elfNN_aarch64_maybe_function_sym (const asymbol *sym, asection *sec,
 				  bfd_vma *code_off)
 {
   bfd_size_type size;
+  elf_symbol_type * elf_sym = (elf_symbol_type *) sym;
 
   if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
 		     | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0
       || sym->section != sec)
     return 0;
 
+  size = (sym->flags & BSF_SYNTHETIC) ? 0 : elf_sym->internal_elf_sym.st_size;
+  
   if (!(sym->flags & BSF_SYNTHETIC))
-    switch (ELF_ST_TYPE (((elf_symbol_type *) sym)->internal_elf_sym.st_info))
+    switch (ELF_ST_TYPE (elf_sym->internal_elf_sym.st_info))
       {
-	case STT_FUNC:
 	case STT_NOTYPE:
+	  /* Ignore symbols created by the annobin plugin for gcc and clang.
+	     These symbols are hidden, local, notype and have a size of 0.  */
+	  if (size == 0
+	      && sym->flags & BSF_LOCAL
+	      && ELF_ST_VISIBILITY (elf_sym->internal_elf_sym.st_other) == STV_HIDDEN)
+	    return 0;
+	  /* Fall through.  */
+	case STT_FUNC:
+	  /* FIXME: Allow STT_GNU_IFUNC as well ?  */
 	  break;
 	default:
 	  return 0;
       }
-
+  
   if ((sym->flags & BSF_LOCAL)
       && bfd_is_aarch64_special_symbol_name (sym->name,
 					     BFD_AARCH64_SPECIAL_SYM_TYPE_ANY))
     return 0;
 
   *code_off = sym->value;
-  size = 0;
-  if (!(sym->flags & BSF_SYNTHETIC))
-    size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
-  if (size == 0)
-    size = 1;
-  return size;
+
+  /* Do not return 0 for the function's size.  */
+  return size ? size : 1;
 }
 
 static bool
--- /dev/null	2021-04-28 08:42:18.002627155 +0100
+++ current/ld/testsuite/ld-elf/anno-sym.s	2021-04-28 11:29:00.336434507 +0100
@@ -0,0 +1,13 @@ 
+	.text
+
+	.hidden .annobin_hello.c
+	.type .annobin_hello.c, STT_NOTYPE
+	.equiv .annobin_hello.c, .
+	.size .annobin_hello.c, 0
+	
+	.global _start
+_start:
+	.nop
+	.align 4
+	.dc.a foo
+
--- /dev/null	2021-04-28 08:42:18.002627155 +0100
+++ current/ld/testsuite/ld-elf/anno-sym.d	2021-04-28 11:31:59.343105983 +0100
@@ -0,0 +1,5 @@ 
+# Check that linking anno-sym.o produces an undefined reference message referring to '_start' and not 'annobin_hello.c'
+#ld:  -e _start
+#error_output: anno-sym.l
+# The mips-irix6 target fails this test because it does not find any function symbols.  Not sure why.
+#skip: *-*-irix*
--- /dev/null	2021-04-28 08:42:18.002627155 +0100
+++ current/ld/testsuite/ld-elf/anno-sym.l	2021-04-28 11:07:50.381358662 +0100
@@ -0,0 +1,4 @@ 
+#...
+.*: in function `(|_)start':
+.*: undefined reference to `foo'
+#pass