From cf0e0a0ba91664b680dff1e310f24dbe6447bd4c Mon Sep 17 00:00:00 2001 From: Indu Bhagat Date: Tue, 15 Nov 2022 15:07:04 -0800 Subject: bfd: linker: merge .sframe sections The linker merges all the input .sframe sections. When merging, the linker verifies that all the input .sframe sections have the same abi/arch. The linker uses libsframe library to perform key actions on the .sframe sections - decode, read, and create output data. This implies buildsystem changes to make and install libsframe before libbfd. The linker places the output .sframe section in a new segment of its own: PT_GNU_SFRAME. A new segment is not added, however, if the generated .sframe section is empty. When a section is discarded from the final link, the corresponding entries in the .sframe section for those functions are also deleted. The linker sorts the SFrame FDEs on start address by default and sets the SFRAME_F_FDE_SORTED flag in the .sframe section. This patch also adds support for generation of SFrame unwind information for the .plt* sections on x86_64. SFrame unwind info is generated for IBT enabled PLT, lazy/non-lazy PLT. The existing linker option --no-ld-generated-unwind-info has been adapted to include the control of whether .sframe unwind information will be generated for the linker generated sections like PLT. Changes to the linker script have been made as necessary. ChangeLog: * Makefile.def: Add install dependency on libsframe for libbfd. * Makefile.in: Regenerated. * bfd/Makefile.am: Add elf-sframe.c * bfd/Makefile.in: Regenerated. * bfd/bfd-in2.h (SEC_INFO_TYPE_SFRAME): Regenerated. * bfd/configure: Regenerate. * bfd/configure.ac: Add elf-sframe.lo. * bfd/elf-bfd.h (struct sframe_func_bfdinfo): New struct. (struct sframe_dec_info): Likewise. (struct sframe_enc_info): Likewise. (struct elf_link_hash_table): New member for encoded .sframe object. (struct output_elf_obj_tdata): New member. (elf_sframe): New access macro. (_bfd_elf_set_section_sframe): New declaration. * bfd/elf.c (get_segment_type): Handle new segment PT_GNU_SFRAME. (bfd_section_from_phdr): Likewise. (get_program_header_size): Likewise. (_bfd_elf_map_sections_to_segments): Likewise. * bfd/elf64-x86-64.c (elf_x86_64_link_setup_gnu_properties): Add contents to the .sframe sections or .plt* entries. * bfd/elflink.c (elf_section_ignore_discarded_relocs): Handle SEC_INFO_TYPE_SFRAME. (_bfd_elf_default_action_discarded): Handle .sframe section. (elf_link_input_bfd): Merge .sframe section. (bfd_elf_final_link): Write the output .sframe section. (bfd_elf_discard_info): Handle discarding .sframe section. * bfd/elfxx-x86.c (_bfd_x86_elf_size_dynamic_sections): Create .sframe section for .plt and .plt.sec. (_bfd_x86_elf_finish_dynamic_sections): Handle .sframe from .plt* sections. * bfd/elfxx-x86.h (PLT_SFRAME_FDE_START_OFFSET): New definition. (SFRAME_PLT0_MAX_NUM_FRES): Likewise. (SFRAME_PLTN_MAX_NUM_FRES): Likewise. (struct elf_x86_sframe_plt): New structure. (struct elf_x86_link_hash_table): New member. (struct elf_x86_init_table): New members for .sframe creation. * bfd/section.c: Add new definition SEC_INFO_TYPE_SFRAME. * binutils/readelf.c (get_segment_type): Handle new segment PT_GNU_SFRAME. * ld/ld.texi: Update documentation for --no-ld-generated-unwind-info. * ld/scripttempl/elf.sc: Support .sframe sections. * ld/Makefile.am (TESTSFRAMELIB): Use it. (check-DEJAGNU): Likewise. * ld/Makefile.in: Regenerated. * ld/configure.ac (TESTSFRAMELIB): Set to the .so or .a like TESTBFDLIB. * ld/configure: Regenerated. * bfd/elf-sframe.c: New file. include/ChangeLog: * elf/common.h (PT_GNU_SFRAME): New definition. * elf/internal.h (struct elf_segment_map): Handle new segment type PT_GNU_SFRAME. ld/testsuite/ChangeLog: * ld/testsuite/ld-bootstrap/bootstrap.exp: Add SFRAMELIB. * ld/testsuite/ld-aarch64/aarch64-elf.exp: Add new test sframe-simple-1. * ld/testsuite/ld-aarch64/sframe-bar.s: New file. * ld/testsuite/ld-aarch64/sframe-foo.s: Likewise. * ld/testsuite/ld-aarch64/sframe-simple-1.d: Likewise. * ld/testsuite/ld-sframe/sframe-empty.d: New test. * ld/testsuite/ld-sframe/sframe-empty.s: New file. * ld/testsuite/ld-sframe/sframe.exp: New testsuite. * ld/testsuite/ld-x86-64/sframe-bar.s: New file. * ld/testsuite/ld-x86-64/sframe-foo.s: Likewise. * ld/testsuite/ld-x86-64/sframe-simple-1.d: Likewise. * ld/testsuite/ld-x86-64/sframe-plt-1.d: Likewise. * ld/testsuite/ld-x86-64/sframe-simple-1.d: Likewise. * ld/testsuite/ld-x86-64/x86-64.exp: Add new tests - sframe-simple-1, sframe-plt-1. * ld/testsuite/lib/ld-lib.exp: Add new proc to check if assembler supports SFrame section. * ld/testsuite/ld-sframe/discard.d: New file. * ld/testsuite/ld-sframe/discard.ld: Likewise. * ld/testsuite/ld-sframe/discard.s: Likewise. --- ld/Makefile.am | 2 ++ ld/Makefile.in | 2 ++ ld/configure | 8 ++++-- ld/configure.ac | 3 ++ ld/ld.texi | 4 ++- ld/scripttempl/elf.sc | 2 ++ ld/testsuite/ld-aarch64/aarch64-elf.exp | 4 +++ ld/testsuite/ld-aarch64/sframe-bar.s | 7 +++++ ld/testsuite/ld-aarch64/sframe-foo.s | 10 +++++++ ld/testsuite/ld-aarch64/sframe-simple-1.d | 26 +++++++++++++++++ ld/testsuite/ld-bootstrap/bootstrap.exp | 8 +++--- ld/testsuite/ld-sframe/discard.d | 10 +++++++ ld/testsuite/ld-sframe/discard.ld | 9 ++++++ ld/testsuite/ld-sframe/discard.s | 13 +++++++++ ld/testsuite/ld-sframe/sframe-empty.d | 10 +++++++ ld/testsuite/ld-sframe/sframe-empty.s | 2 ++ ld/testsuite/ld-sframe/sframe.exp | 47 +++++++++++++++++++++++++++++++ ld/testsuite/ld-x86-64/sframe-bar.s | 31 ++++++++++++++++++++ ld/testsuite/ld-x86-64/sframe-foo.s | 37 ++++++++++++++++++++++++ ld/testsuite/ld-x86-64/sframe-plt-1.d | 29 +++++++++++++++++++ ld/testsuite/ld-x86-64/sframe-simple-1.d | 35 +++++++++++++++++++++++ ld/testsuite/ld-x86-64/x86-64.exp | 5 ++++ ld/testsuite/lib/ld-lib.exp | 45 +++++++++++++++++++++++++++++ 23 files changed, 342 insertions(+), 7 deletions(-) create mode 100644 ld/testsuite/ld-aarch64/sframe-bar.s create mode 100644 ld/testsuite/ld-aarch64/sframe-foo.s create mode 100644 ld/testsuite/ld-aarch64/sframe-simple-1.d create mode 100644 ld/testsuite/ld-sframe/discard.d create mode 100644 ld/testsuite/ld-sframe/discard.ld create mode 100644 ld/testsuite/ld-sframe/discard.s create mode 100644 ld/testsuite/ld-sframe/sframe-empty.d create mode 100644 ld/testsuite/ld-sframe/sframe-empty.s create mode 100644 ld/testsuite/ld-sframe/sframe.exp create mode 100644 ld/testsuite/ld-x86-64/sframe-bar.s create mode 100644 ld/testsuite/ld-x86-64/sframe-foo.s create mode 100644 ld/testsuite/ld-x86-64/sframe-plt-1.d create mode 100644 ld/testsuite/ld-x86-64/sframe-simple-1.d (limited to 'ld') diff --git a/ld/Makefile.am b/ld/Makefile.am index 66e9094..65fef4e 100644 --- a/ld/Makefile.am +++ b/ld/Makefile.am @@ -972,6 +972,7 @@ EXTRA_ld_new_SOURCES += $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES) # This is the real libbfd.a and libctf.a created by libtool. TESTBFDLIB = @TESTBFDLIB@ TESTCTFLIB = @TESTCTFLIB@ +TESTSFRAMELIB = @TESTSFRAMELIB@ check-DEJAGNU: site.exp (cd .libs; test -e ldscripts || test ! -e ld-new || $(LN_S) ../ldscripts .) @@ -989,6 +990,7 @@ check-DEJAGNU: site.exp CXX_FOR_TARGET="$(CXX_FOR_TARGET)" \ CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ OFILES="$(OFILES)" BFDLIB="$(TESTBFDLIB)" CTFLIB="$(TESTCTFLIB) $(ZLIB)" \ + SFRAMELIB="$(TESTSFRAMELIB)" \ LIBIBERTY="$(LIBIBERTY) $(LIBINTL)" LIBS="$(LIBS)" \ DO_COMPARE="`echo '$(do_compare)' | sed -e 's,\\$$,,g'`" \ $(RUNTESTFLAGS); \ diff --git a/ld/Makefile.in b/ld/Makefile.in index 5e4787f..ff4c916 100644 --- a/ld/Makefile.in +++ b/ld/Makefile.in @@ -470,6 +470,7 @@ TARGET_SYSTEM_ROOT_DEFINE = @TARGET_SYSTEM_ROOT_DEFINE@ # This is the real libbfd.a and libctf.a created by libtool. TESTBFDLIB = @TESTBFDLIB@ TESTCTFLIB = @TESTCTFLIB@ +TESTSFRAMELIB = @TESTSFRAMELIB@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WARN_CFLAGS = @WARN_CFLAGS@ @@ -2642,6 +2643,7 @@ check-DEJAGNU: site.exp CXX_FOR_TARGET="$(CXX_FOR_TARGET)" \ CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ OFILES="$(OFILES)" BFDLIB="$(TESTBFDLIB)" CTFLIB="$(TESTCTFLIB) $(ZLIB)" \ + SFRAMELIB="$(TESTSFRAMELIB)" \ LIBIBERTY="$(LIBIBERTY) $(LIBINTL)" LIBS="$(LIBS)" \ DO_COMPARE="`echo '$(do_compare)' | sed -e 's,\\$$,,g'`" \ $(RUNTESTFLAGS); \ diff --git a/ld/configure b/ld/configure index 7900045..a4d30ab 100755 --- a/ld/configure +++ b/ld/configure @@ -634,6 +634,7 @@ ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS +TESTSFRAMELIB TESTCTFLIB TESTBFDLIB EMULATION_LIBPATH @@ -11624,7 +11625,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11627 "configure" +#line 11628 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11730,7 +11731,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11733 "configure" +#line 11734 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -17487,9 +17488,11 @@ EMULATION_LIBPATH=$all_libpath if test x${enable_static} = xno; then TESTBFDLIB="-Wl,--rpath,../bfd/.libs ../bfd/.libs/libbfd.so" TESTCTFLIB="-Wl,--rpath,../libctf/.libs ../libctf/.libs/libctf.so" + TESTSFRAMELIB="-Wl,--rpath,../libsframe/.libs ../libsframe/.libs/libsframe.so" else TESTBFDLIB="../bfd/.libs/libbfd.a" TESTCTFLIB="../libctf/.libs/libctf.a" + TESTSFRAMELIB="../libsframe/.libs/libsframe.a" fi if test "${enable_libctf}" = no; then TESTCTFLIB= @@ -17497,6 +17500,7 @@ fi + target_vendor=${target_vendor=$host_vendor} case "$target_vendor" in hp) EXTRA_SHLIB_EXTENSION=".sl" ;; diff --git a/ld/configure.ac b/ld/configure.ac index 6123ea7..1ee40a5 100644 --- a/ld/configure.ac +++ b/ld/configure.ac @@ -628,15 +628,18 @@ AC_SUBST(EMULATION_LIBPATH) if test x${enable_static} = xno; then TESTBFDLIB="-Wl,--rpath,../bfd/.libs ../bfd/.libs/libbfd.so" TESTCTFLIB="-Wl,--rpath,../libctf/.libs ../libctf/.libs/libctf.so" + TESTSFRAMELIB="-Wl,--rpath,../libsframe/.libs ../libsframe/.libs/libsframe.so" else TESTBFDLIB="../bfd/.libs/libbfd.a" TESTCTFLIB="../libctf/.libs/libctf.a" + TESTSFRAMELIB="../libsframe/.libs/libsframe.a" fi if test "${enable_libctf}" = no; then TESTCTFLIB= fi AC_SUBST(TESTBFDLIB) AC_SUBST(TESTCTFLIB) +AC_SUBST(TESTSFRAMELIB) target_vendor=${target_vendor=$host_vendor} case "$target_vendor" in diff --git a/ld/ld.texi b/ld/ld.texi index 82527e3..3836465 100644 --- a/ld/ld.texi +++ b/ld/ld.texi @@ -2837,7 +2837,9 @@ section and ELF @code{PT_GNU_EH_FRAME} segment header. @item --no-ld-generated-unwind-info Request creation of @code{.eh_frame} unwind info for linker generated code sections like PLT. This option is on by default -if linker generated unwind info is supported. +if linker generated unwind info is supported. This option also +controls the generation of @code{.sframe} unwind info for linker +generated code sections like PLT. @kindex --enable-new-dtags @kindex --disable-new-dtags diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc index bf2268b..5cc364b 100644 --- a/ld/scripttempl/elf.sc +++ b/ld/scripttempl/elf.sc @@ -601,6 +601,7 @@ cat <