[binutils-gdb] x86: Cache the symbol table when packing relative relocations

H.J. Lu hjl@sourceware.org
Sun Jan 11 00:34:39 GMT 2026


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

commit 4e007c6bff146cf4b432987fad0ac17d89ac07ad
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Fri Jan 9 08:54:42 2026 +0800

    x86: Cache the symbol table when packing relative relocations
    
    When packing relative relocations, x86 linker may load the same symbol
    table repeatedly, which can take a long time.  On Intel Core i7-1195G7
    with 32GB RAM, it takes more than 45 minutes to create an output with
    -pie -z pack-relative-relocs from an input with 208025 code sections.
    Cache the symbol table to reduce the link time to less than 2 seconds.
    
    On the same machine, creating 3.1GB clang executable in LLVM 21.1.3 debug
    build:
    
    user            55.39 seconds
    system          6.71 seconds
    total           65.80 seconds
    maximum set(GB) 10.43
    page faults     2406941
    
            PR ld/33765
            * elfxx-x86.c (elf_x86_relative_reloc_record_add): Remove
            keep_symbuf_p.
            (_bfd_x86_elf_link_relax_section): Updated.  Cache the symbol
            table to avoid loading it again.
    
    Signed-off-by: H.J. Lu <hjl.tools@gmail.com>

Diff:
---
 bfd/elfxx-x86.c | 52 +++++++++++++++++++++-------------------------------
 1 file changed, 21 insertions(+), 31 deletions(-)

diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 36ba7919f47..fc51bf262a5 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -1011,7 +1011,7 @@ elf_x86_relative_reloc_record_add
    struct elf_x86_relative_reloc_data *relative_reloc,
    Elf_Internal_Rela *rel, asection *sec,
    asection *sym_sec, struct elf_link_hash_entry *h,
-   Elf_Internal_Sym *sym, bfd_vma offset, bool *keep_symbuf_p)
+   Elf_Internal_Sym *sym, bfd_vma offset)
 {
   bfd_size_type newidx;
 
@@ -1055,8 +1055,6 @@ elf_x86_relative_reloc_record_add
     {
       relative_reloc->data[newidx].sym = sym;
       relative_reloc->data[newidx].u.sym_sec = sym_sec;
-      /* We must keep the symbol buffer since SYM will be used later.  */
-      *keep_symbuf_p = true;
     }
   relative_reloc->data[newidx].offset = offset;
   relative_reloc->data[newidx].address = 0;
@@ -1079,7 +1077,7 @@ _bfd_x86_elf_link_relax_section (bfd *abfd ATTRIBUTE_UNUSED,
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Rela *internal_relocs;
   Elf_Internal_Rela *irel, *irelend;
-  Elf_Internal_Sym *isymbuf = NULL;
+  Elf_Internal_Sym *isymbuf;
   struct elf_link_hash_entry **sym_hashes;
   elf_backend_data *bed;
   struct elf_x86_link_hash_table *htab;
@@ -1087,7 +1085,6 @@ _bfd_x86_elf_link_relax_section (bfd *abfd ATTRIBUTE_UNUSED,
   bool is_x86_64;
   bool unaligned_section;
   bool return_status = false;
-  bool keep_symbuf = false;
 
   /* Assume we're not going to change any sizes, and we'll only need
      one pass.  */
@@ -1131,6 +1128,23 @@ _bfd_x86_elf_link_relax_section (bfd *abfd ATTRIBUTE_UNUSED,
   if (internal_relocs == NULL)
     return false;
 
+  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+  if (isymbuf == NULL && symtab_hdr->sh_info > 1)
+    {
+      /* symtab_hdr->sh_info == the number of local symbols + 1.  Load
+	 the symbol table if there are local symbols.  */
+      isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+				      symtab_hdr->sh_info,
+				      0, NULL, NULL, NULL);
+      if (isymbuf == NULL)
+	return false;
+
+      /* Cache the symbol table to avoid loading the same symbol table
+	 repeatedly which can take a long time if the input has many
+	 code sections.  */
+      symtab_hdr->contents = (unsigned char *) isymbuf;
+    }
+
   irelend = internal_relocs + input_section->reloc_count;
   for (irel = internal_relocs; irel < irelend; irel++)
     {
@@ -1163,20 +1177,6 @@ _bfd_x86_elf_link_relax_section (bfd *abfd ATTRIBUTE_UNUSED,
 
       if (r_symndx < symtab_hdr->sh_info)
 	{
-	  /* Read this BFD's local symbols.  */
-	  if (isymbuf == NULL)
-	    {
-	      isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
-	      if (isymbuf == NULL)
-		{
-		  isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
-						  symtab_hdr->sh_info,
-						  0, NULL, NULL, NULL);
-		  if (isymbuf == NULL)
-		    goto error_return;
-		}
-	    }
-
 	  isym = isymbuf + r_symndx;
 	  switch (isym->st_shndx)
 	    {
@@ -1278,8 +1278,7 @@ _bfd_x86_elf_link_relax_section (bfd *abfd ATTRIBUTE_UNUSED,
 	  if (!elf_x86_relative_reloc_record_add (info,
 						  &htab->relative_reloc,
 						  irel, htab->elf.sgot,
-						  sec, h, isym, offset,
-						  &keep_symbuf))
+						  sec, h, isym, offset))
 	    goto error_return;
 
 	  continue;
@@ -1348,8 +1347,7 @@ _bfd_x86_elf_link_relax_section (bfd *abfd ATTRIBUTE_UNUSED,
 		 ((unaligned_section || unaligned_offset)
 		  ? &htab->unaligned_relative_reloc
 		  : &htab->relative_reloc),
-		 irel, input_section, sec, h, isym, offset,
-		 &keep_symbuf))
+		 irel, input_section, sec, h, isym, offset))
 	    goto error_return;
 	}
     }
@@ -1359,14 +1357,6 @@ _bfd_x86_elf_link_relax_section (bfd *abfd ATTRIBUTE_UNUSED,
   return_status = true;
 
 error_return:
-  if ((unsigned char *) isymbuf != symtab_hdr->contents)
-    {
-      /* Cache the symbol buffer if it must be kept.  */
-      if (keep_symbuf)
-	symtab_hdr->contents = (unsigned char *) isymbuf;
-      else
-	free (isymbuf);
-    }
   if (elf_section_data (input_section)->relocs != internal_relocs)
     free (internal_relocs);
   return return_status;


More information about the Binutils-cvs mailing list