binutils/add-ulp-section.diff

208 lines
5.9 KiB
Diff
Raw Normal View History

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
@@ -29,6 +29,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
@@ -607,6 +607,7 @@ struct elf_x86_link_hash_table
asection *plt_second_eh_frame;
asection *plt_got;
asection *plt_got_eh_frame;
+ asection *ulp;
sframe_encoder_ctx *plt_cfe_ctx;
asection *plt_sframe;
@@ -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