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