File add-ulp-section.diff of Package binutils.29920

This is for userspace live patching, adding some space into
shared libs or executable (in the .ulp section) when one of the 
input files contains a section named .ulp.track.

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 101c2fdf50d..f5d9e201fdb 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1487,6 +1487,10 @@ struct elf_backend_data
     (const bfd *ibfd, bfd *obfd, const Elf_Internal_Shdr *isection,
      Elf_Internal_Shdr *osection);
 
+  bool (*elf_backend_is_ulp_enabled) (bfd *abfd);
+
+  bool (*elf_backend_setup_ulp) (struct bfd_link_info *);
+
   /* Used to handle bad SHF_LINK_ORDER input.  */
   void (*link_order_error_handler) (const char *, ...);
 
diff --git a/bfd/elflink.c b/bfd/elflink.c
index ce1407fa2dc..5c70bcf6c07 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -7260,6 +7260,13 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 	  s = bfd_get_linker_section (dynobj, ".gnu.version");
 	  s->flags |= SEC_EXCLUDE;
 	}
+
+      if (bed->elf_backend_is_ulp_enabled != NULL
+	  && bed->elf_backend_setup_ulp != NULL
+	  && (*bed->elf_backend_is_ulp_enabled) (info->input_bfds))
+        {
+          (*bed->elf_backend_setup_ulp)(info);
+        }
     }
   return true;
 }
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 4c6b1f20340..1f54509cd08 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -771,6 +771,14 @@
 #define elf_backend_copy_special_section_fields _bfd_elf_copy_special_section_fields
 #endif
 
+#ifndef elf_backend_is_ulp_enabled
+#define elf_backend_is_ulp_enabled NULL
+#endif
+
+#ifndef elf_backend_setup_ulp
+#define elf_backend_setup_ulp NULL
+#endif
+
 #ifndef elf_backend_compact_eh_encoding
 #define elf_backend_compact_eh_encoding NULL
 #endif
@@ -904,6 +912,8 @@ static const struct elf_backend_data elfNN_bed =
   elf_backend_maybe_function_sym,
   elf_backend_get_reloc_section,
   elf_backend_copy_special_section_fields,
+  elf_backend_is_ulp_enabled,
+  elf_backend_setup_ulp,
   elf_backend_link_order_error_handler,
   elf_backend_relplt_name,
   ELF_MACHINE_ALT1,
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 62d516aab8d..c0fb718d85c 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -31,6 +31,8 @@
 #define ELF64_DYNAMIC_INTERPRETER "/lib/ld64.so.1"
 #define ELFX32_DYNAMIC_INTERPRETER "/lib/ldx32.so.1"
 
+#define ULP_ENTRY_LEN 16
+
 bool
 _bfd_x86_elf_mkobject (bfd *abfd)
 {
@@ -984,6 +986,64 @@ _bfd_elf_x86_valid_reloc_p (asection *input_section,
   return valid_p;
 }
 
+/* Check if input bfds are ulp-enabled by containing .ulp.track section */
+
+bool
+_bfd_x86_elf_is_ulp_enabled (struct bfd *input_bfd)
+{
+  while (input_bfd != NULL)
+  for (; input_bfd != NULL; input_bfd = input_bfd->link.next)
+    {
+      if (input_bfd->section_count == 0) continue;
+      if (bfd_get_section_by_name (input_bfd, ".ulp.track")) return true;
+    }
+  return false;
+}
+
+/* To be used by elf_link_hash_traverse when computing the ulp length */
+
+static bool
+bfd_x86_elf_link_compute_ulp (struct elf_link_hash_entry *h, void *data)
+{
+  unsigned long *ulp_length = (unsigned long *) data;
+
+  if (h->dynindx != -1 && h->type == STT_FUNC && !h->def_dynamic)
+    {
+      ++(*ulp_length);
+    }
+  return true;
+}
+
+/* Fill the user-space live patching section */
+
+bool
+_bfd_x86_elf_setup_ulp (struct bfd_link_info *info)
+{
+  struct elf_x86_link_hash_table *htab;
+  asection *ulp;
+  unsigned int ulp_length = 0;
+
+  htab = elf_x86_hash_table (info, X86_64_ELF_DATA);
+
+  elf_link_hash_traverse (elf_hash_table (info),
+                          bfd_x86_elf_link_compute_ulp,
+                          &ulp_length);
+
+  ulp = htab->ulp;
+
+  ulp->size = ulp_length * ULP_ENTRY_LEN;
+
+  ulp->contents = (bfd_byte *) bfd_malloc (ulp->size);
+  if (ulp->contents == NULL)
+    return false;
+
+  if (!ulp->contents)
+    return false;
+
+  memset(ulp->contents, 0x00, ulp->size);
+  return true;
+}
+
 /* Set the sizes of the dynamic sections.  */
 
 bool
@@ -3030,7 +3090,26 @@ _bfd_x86_elf_link_setup_gnu_properties
 
 	      htab->plt_second = sec;
 	    }
-	}
+
+         /* create sections to support user-space live patching */
+         if (_bfd_x86_elf_is_ulp_enabled(info->input_bfds))
+           {
+             flagword flags = (bed->dynamic_sec_flags
+                               | SEC_ALLOC
+                               | SEC_CODE
+                               | SEC_LOAD
+                               | SEC_READONLY);
+
+              sec = bfd_make_section_anyway_with_flags (dynobj, ".ulp", flags);
+              if (sec == NULL)
+                info->callbacks->einfo (_("%F%P: failed to create ULP section\n"));
+
+              if (!bfd_set_section_alignment (sec,  plt_alignment))
+                goto error_alignment;
+
+              htab->ulp = sec;
+           }
+      }
 
       if (!info->no_ld_generated_unwind_info)
 	{
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index db11327e96f..89f51382216 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -456,6 +456,7 @@ struct elf_x86_link_hash_table
   asection *plt_second_eh_frame;
   asection *plt_got;
   asection *plt_got_eh_frame;
+  asection *ulp;
 
   /* Parameters describing PLT generation, lazy or non-lazy.  */
   struct elf_x86_plt_layout plt;
@@ -694,6 +695,12 @@ extern void _bfd_x86_elf_link_report_relative_reloc
   (struct bfd_link_info *, asection *, struct elf_link_hash_entry *,
    Elf_Internal_Sym *, const char *, const void *);
 
+extern bool _bfd_x86_elf_is_ulp_enabled
+  (struct bfd *);
+
+extern bool _bfd_x86_elf_setup_ulp
+  (struct bfd_link_info *);
+
 #define bfd_elf64_mkobject \
   _bfd_x86_elf_mkobject
 #define bfd_elf32_mkobject \
@@ -907,6 +914,10 @@ extern void _bfd_x86_elf_link_report_relative_reloc
   _bfd_elf_x86_size_relative_relocs
 #define elf_backend_finish_relative_relocs \
   _bfd_elf_x86_finish_relative_relocs
+#define elf_backend_is_ulp_enabled \
+  _bfd_x86_elf_is_ulp_enabled
+#define elf_backend_setup_ulp \
+  _bfd_x86_elf_setup_ulp
 
 #define ELF_P_ALIGN ELF_MINPAGESIZE
 
openSUSE Build Service is sponsored by