[binutils-gdb] bfd/COFF: propagate function size when copying/linking ELF objects

Jan Beulich jbeulich@sourceware.org
Mon Apr 14 12:26:31 GMT 2025


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=06d3221915577d421c4f3a1a9ee559d88e95acc2

commit 06d3221915577d421c4f3a1a9ee559d88e95acc2
Author: Jan Beulich <jbeulich@suse.com>
Date:   Mon Apr 14 14:22:49 2025 +0200

    bfd/COFF: propagate function size when copying/linking ELF objects
    
    While COFF, unlike ELF, doesn't have a generic way to express symbol
    size, there is a means to do so for functions. When inputs are ELF,
    propagate function sizes, including the fact that a symbol denotes a
    function, to the output's symbol table.
    
    Note that this requires hackery (cross-object-format processing) in two
    places - when linking, global symbols are entered into a global hash
    table, and hence relevant information needs to be updated there in that
    case, while otherwise the original symbol structures can be consulted.
    
    For the setting of ->u.syment.n_type the later writing of the field to
    literal 0 needs to be dropped from coff_write_alien_symbol(). It was
    redundant anyway with an earlier write of the field using C_NUL.

Diff:
---
 bfd/coffgen.c  | 18 +++++++++++++++++-
 bfd/cofflink.c | 47 +++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 60 insertions(+), 5 deletions(-)

diff --git a/bfd/coffgen.c b/bfd/coffgen.c
index f87e54f9722..ab4d790ad30 100644
--- a/bfd/coffgen.c
+++ b/bfd/coffgen.c
@@ -42,6 +42,7 @@
 #include "libbfd.h"
 #include "coff/internal.h"
 #include "libcoff.h"
+#include "elf-bfd.h"
 #include "hashtab.h"
 
 /* Extract a long section name at STRINDEX and copy it to the bfd objstack.
@@ -1270,9 +1271,24 @@ coff_write_alien_symbol (bfd *abfd,
 	if (c != (coff_symbol_type *) NULL)
 	  native->u.syment.n_flags = bfd_asymbol_bfd (&c->symbol)->flags;
       }
+
+      const elf_symbol_type *elfsym = elf_symbol_from (symbol);
+      if (elfsym
+	  && (symbol->flags & BSF_FUNCTION)
+	  && elfsym->internal_elf_sym.st_size)
+	{
+	  /* coff_data (abfd)->local_n_btshft is what ought to be used here,
+	     just that it's set only when reading in COFF objects.  */
+	  native->u.syment.n_type = DT_FCN << 4;
+	  native->u.syment.n_numaux = 1;
+	  native[1].u.auxent.x_sym.x_misc.x_fsize
+	    = elfsym->internal_elf_sym.st_size;
+	  /* FIXME .u.auxent.x_sym.x_fcnary.x_fcn.x_endndx would better also
+	     be set, which would require updating the field once the next
+	     function is seen.  */
+	}
     }
 
-  native->u.syment.n_type = 0;
   if (symbol->flags & BSF_FILE)
     native->u.syment.n_sclass = C_FILE;
   else if (symbol->flags & BSF_LOCAL)
diff --git a/bfd/cofflink.c b/bfd/cofflink.c
index 501731bd811..38278e230da 100644
--- a/bfd/cofflink.c
+++ b/bfd/cofflink.c
@@ -27,6 +27,7 @@
 #include "libbfd.h"
 #include "coff/internal.h"
 #include "libcoff.h"
+#include "elf-bfd.h"
 #include "safe-ctype.h"
 
 static bool coff_link_add_object_symbols (bfd *, struct bfd_link_info *);
@@ -931,14 +932,52 @@ _bfd_coff_final_link (bfd *abfd,
 	      bfd_vma written = 0;
 	      bool rewrite = false;
 
-	      if (! (sym->flags & BSF_LOCAL)
-		  || (sym->flags & (BSF_SECTION_SYM | BSF_DEBUGGING_RELOC
-				    | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC
-				    | BSF_SYNTHETIC))
+	      if ((sym->flags & (BSF_SECTION_SYM | BSF_DEBUGGING_RELOC
+				 | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC
+				 | BSF_SYNTHETIC))
 		  || ((sym->flags & BSF_DEBUGGING)
 		      && ! (sym->flags & BSF_FILE)))
 		continue;
 
+	      if (! (sym->flags & BSF_LOCAL))
+		{
+		  /* For ELF symbols try to represent their function-ness and
+		     size, if available.  */
+		  if (! (sym->flags & BSF_FUNCTION))
+		    continue;
+
+		  const elf_symbol_type *elfsym = elf_symbol_from (sym);
+		  if (!elfsym)
+		    continue;
+
+		  struct coff_link_hash_entry *hent
+		    = (struct coff_link_hash_entry *) bfd_hash_lookup
+			(&info->hash->table, bfd_asymbol_name (sym),
+			 false, false);
+		  if (!hent)
+		    continue;
+
+		  /* coff_data (abfd)->local_n_btshft is what ought to be used
+		     here, just that it's set only when reading in COFF
+		     objects.  */
+		  hent->type = DT_FCN << 4;
+		  if (!elfsym->internal_elf_sym.st_size)
+		    continue;
+
+		  hent->aux = bfd_zalloc (abfd, sizeof (*hent->aux));
+		  if (!hent->aux)
+		    continue;
+
+		  hent->numaux = 1;
+		  hent->aux->x_sym.x_misc.x_fsize
+		    = elfsym->internal_elf_sym.st_size;
+		  /* FIXME ->x_sym.x_fcnary.x_fcn.x_endndx would better
+		     also be set, yet that would likely need to happen
+		     elsewhere anyway.  */
+
+		  continue;
+		}
+
 	      /* See if we are discarding symbols with this name.  */
 	      if ((flaginfo.info->strip == strip_some
 		   && (bfd_hash_lookup (flaginfo.info->keep_hash,


More information about the Binutils-cvs mailing list