bfd: linker: merge .sframe sections
authorIndu Bhagat <indu.bhagat@oracle.com>
Tue, 15 Nov 2022 23:07:04 +0000 (15:07 -0800)
committerIndu Bhagat <indu.bhagat@oracle.com>
Tue, 15 Nov 2022 23:49:47 +0000 (15:49 -0800)
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.

43 files changed:
Makefile.def
Makefile.in
bfd/Makefile.am
bfd/Makefile.in
bfd/bfd-in2.h
bfd/configure
bfd/configure.ac
bfd/elf-bfd.h
bfd/elf-sframe.c [new file with mode: 0644]
bfd/elf.c
bfd/elf64-x86-64.c
bfd/elflink.c
bfd/elfxx-x86.c
bfd/elfxx-x86.h
bfd/section.c
binutils/readelf.c
include/elf/common.h
include/elf/internal.h
include/sframe-api.h
ld/Makefile.am
ld/Makefile.in
ld/configure
ld/configure.ac
ld/ld.texi
ld/scripttempl/elf.sc
ld/testsuite/ld-aarch64/aarch64-elf.exp
ld/testsuite/ld-aarch64/sframe-bar.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/sframe-foo.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/sframe-simple-1.d [new file with mode: 0644]
ld/testsuite/ld-bootstrap/bootstrap.exp
ld/testsuite/ld-sframe/discard.d [new file with mode: 0644]
ld/testsuite/ld-sframe/discard.ld [new file with mode: 0644]
ld/testsuite/ld-sframe/discard.s [new file with mode: 0644]
ld/testsuite/ld-sframe/sframe-empty.d [new file with mode: 0644]
ld/testsuite/ld-sframe/sframe-empty.s [new file with mode: 0644]
ld/testsuite/ld-sframe/sframe.exp [new file with mode: 0644]
ld/testsuite/ld-x86-64/sframe-bar.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/sframe-foo.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/sframe-plt-1.d [new file with mode: 0644]
ld/testsuite/ld-x86-64/sframe-simple-1.d [new file with mode: 0644]
ld/testsuite/ld-x86-64/x86-64.exp
ld/testsuite/lib/ld-lib.exp
libsframe/sframe.c

index 1b39c910447db396d8cb9f5e5a2b0ea92e30233e..f974565d8ca8933652913858ad1f5419b0aa7c25 100644 (file)
@@ -458,11 +458,14 @@ dependencies = { module=all-gdbsupport; on=all-gnulib; };
 dependencies = { module=all-gdbsupport; on=all-intl; };
 
 // Host modules specific to binutils.
+// build libsframe before bfd for encoder/decoder support for linking
+// SFrame sections
 dependencies = { module=configure-bfd; on=configure-libiberty; hard=true; };
 dependencies = { module=configure-bfd; on=configure-intl; };
 dependencies = { module=all-bfd; on=all-libiberty; };
 dependencies = { module=all-bfd; on=all-intl; };
 dependencies = { module=all-bfd; on=all-zlib; };
+dependencies = { module=all-bfd; on=all-libsframe; };
 dependencies = { module=configure-opcodes; on=configure-libiberty; hard=true; };
 dependencies = { module=all-opcodes; on=all-libiberty; };
 
@@ -488,6 +491,7 @@ dependencies = { module=install-binutils; on=install-opcodes; };
 dependencies = { module=install-strip-binutils; on=install-strip-opcodes; };
 
 // Likewise for ld, libctf, and bfd.
+dependencies = { module=install-bfd; on=install-libsframe; };
 dependencies = { module=install-libctf; on=install-bfd; };
 dependencies = { module=install-ld; on=install-bfd; };
 dependencies = { module=install-ld; on=install-libctf; };
index b26f778a94a2d73edee64575296fadfad347c5e2..a425b54e09487812b24b7ef6a54045eb7dea96a2 100644 (file)
@@ -64407,6 +64407,16 @@ all-stagetrain-bfd: maybe-all-stagetrain-zlib
 all-stagefeedback-bfd: maybe-all-stagefeedback-zlib
 all-stageautoprofile-bfd: maybe-all-stageautoprofile-zlib
 all-stageautofeedback-bfd: maybe-all-stageautofeedback-zlib
+all-bfd: maybe-all-libsframe
+all-stage1-bfd: maybe-all-stage1-libsframe
+all-stage2-bfd: maybe-all-stage2-libsframe
+all-stage3-bfd: maybe-all-stage3-libsframe
+all-stage4-bfd: maybe-all-stage4-libsframe
+all-stageprofile-bfd: maybe-all-stageprofile-libsframe
+all-stagetrain-bfd: maybe-all-stagetrain-libsframe
+all-stagefeedback-bfd: maybe-all-stagefeedback-libsframe
+all-stageautoprofile-bfd: maybe-all-stageautoprofile-libsframe
+all-stageautofeedback-bfd: maybe-all-stageautofeedback-libsframe
 configure-opcodes: configure-libiberty
 configure-stage1-opcodes: configure-stage1-libiberty
 configure-stage2-opcodes: configure-stage2-libiberty
@@ -64539,6 +64549,7 @@ all-stageautoprofile-binutils: maybe-all-stageautoprofile-libsframe
 all-stageautofeedback-binutils: maybe-all-stageautofeedback-libsframe
 install-binutils: maybe-install-opcodes
 install-strip-binutils: maybe-install-strip-opcodes
+install-bfd: maybe-install-libsframe
 install-libctf: maybe-install-bfd
 install-ld: maybe-install-bfd
 install-ld: maybe-install-libctf
index 93313778d4234055fd6c857756549889841c79b5..a88c6a0034d729644c3ae3e9934a24c42d7a5486 100644 (file)
@@ -286,6 +286,7 @@ BFD32_BACKENDS = \
        ecofflink.lo \
        elf-attrs.lo \
        elf-eh-frame.lo \
+       elf-sframe.lo \
        elf-ifunc.lo \
        elf-m10200.lo \
        elf-m10300.lo \
@@ -419,6 +420,7 @@ BFD32_BACKENDS_CFILES = \
        ecofflink.c \
        elf-attrs.c \
        elf-eh-frame.c \
+       elf-sframe.c \
        elf-ifunc.c \
        elf-m10200.c \
        elf-m10300.c \
@@ -777,8 +779,8 @@ ofiles: stamp-ofiles ; @true
 # dependency tracking fragments are picked up in the Makefile.
 libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
 EXTRA_libbfd_la_SOURCES = $(CFILES)
-libbfd_la_DEPENDENCIES = $(OFILES) ofiles
-libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS)
+libbfd_la_DEPENDENCIES = $(OFILES) ofiles ../libsframe/libsframe.la
+libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS) ../libsframe/libsframe.la
 libbfd_la_LDFLAGS += -release `cat libtool-soversion` @SHARED_LDFLAGS@
 
 # libtool will build .libs/libbfd.a.  We create libbfd.a in the build
index 85cae1f6f0fb9f785efea4a9ea70ddf449f6ad00..d5cc5cb1e179820285a00af9fad3ce969f33c2ee 100644 (file)
@@ -755,6 +755,7 @@ BFD32_BACKENDS = \
        ecofflink.lo \
        elf-attrs.lo \
        elf-eh-frame.lo \
+       elf-sframe.lo \
        elf-ifunc.lo \
        elf-m10200.lo \
        elf-m10300.lo \
@@ -888,6 +889,7 @@ BFD32_BACKENDS_CFILES = \
        ecofflink.c \
        elf-attrs.c \
        elf-eh-frame.c \
+       elf-sframe.c \
        elf-ifunc.c \
        elf-m10200.c \
        elf-m10300.c \
@@ -1207,8 +1209,8 @@ OFILES = $(BFD_BACKENDS) $(BFD_MACHINES) @COREFILE@ @bfd64_libs@
 # dependency tracking fragments are picked up in the Makefile.
 libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
 EXTRA_libbfd_la_SOURCES = $(CFILES)
-libbfd_la_DEPENDENCIES = $(OFILES) ofiles
-libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS)
+libbfd_la_DEPENDENCIES = $(OFILES) ofiles ../libsframe/libsframe.la
+libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS) ../libsframe/libsframe.la
 
 # libtool will build .libs/libbfd.a.  We create libbfd.a in the build
 # directory so that we don't have to convert all the programs that use
@@ -1574,6 +1576,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-m10300.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-nacl.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-properties.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-sframe.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-strtab.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-vxworks.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf.Plo@am__quote@
index e09259b7eaee5ccac5673ad037b85c53d76c9413..0b071dda1e581c113ed1d4a37bfdabda147edcdb 100644 (file)
@@ -994,6 +994,7 @@ typedef struct bfd_section
 #define SEC_INFO_TYPE_JUST_SYMS 4
 #define SEC_INFO_TYPE_TARGET    5
 #define SEC_INFO_TYPE_EH_FRAME_ENTRY 6
+#define SEC_INFO_TYPE_SFRAME  7
 
   /* Nonzero if this section uses RELA relocations, rather than REL.  */
   unsigned int use_rela_p:1;
index 5c6e3821a136bdf4cfcfb8e5a9f31313bf795c36..74bc5a18471f1e6aedfd0c00af6e8ba24aede53d 100755 (executable)
@@ -13582,7 +13582,7 @@ selarchs="$f"
 tb=
 
 elf="elf.lo elflink.lo elf-attrs.lo elf-strtab.lo elf-eh-frame.lo
-     dwarf1.lo dwarf2.lo"
+     elf-sframe.lo dwarf1.lo dwarf2.lo"
 coffgen="coffgen.lo dwarf2.lo"
 coff="cofflink.lo $coffgen"
 ecoff="ecofflink.lo $coffgen"
index 74c0f0722250164f54e90dbbb4261f60833d14e1..5d450a4ad253c767f4837a0ade1352ce6e52fb87 100644 (file)
@@ -383,7 +383,7 @@ selarchs="$f"
 tb=
 
 elf="elf.lo elflink.lo elf-attrs.lo elf-strtab.lo elf-eh-frame.lo
-     dwarf1.lo dwarf2.lo"
+     elf-sframe.lo dwarf1.lo dwarf2.lo"
 coffgen="coffgen.lo dwarf2.lo"
 coff="cofflink.lo $coffgen"
 ecoff="ecofflink.lo $coffgen"
index fa4b9bcf193c176c5b0e904bdcda34619dbabc45..fc32fbe51e96dd974f6f525608b038f306cdae8f 100644 (file)
@@ -490,6 +490,40 @@ struct eh_frame_hdr_info
   u;
 };
 
+/* Additional information for each function (used at link time).  */
+struct sframe_func_bfdinfo
+{
+  /* Whether the function has been discarded from the final output.  */
+  bool func_deleted_p;
+  /* Relocation offset.  */
+  unsigned int func_r_offset;
+  /* Relocation index.  */
+  unsigned int func_reloc_index;
+};
+
+/* SFrame decoder info.
+   Contains all information for a decoded .sframe section.  */
+struct sframe_dec_info
+{
+  /* Decoder context.  */
+  struct sframe_decoder_ctx *sfd_ctx;
+  /* Number of function descriptor entries in this .sframe.  */
+  unsigned int sfd_fde_count;
+  /* Additional information for linking.  */
+  struct sframe_func_bfdinfo *sfd_func_bfdinfo;
+};
+
+/* SFrame encoder info.
+   Contains all information for an encoded .sframe section to be
+   written out.  */
+struct sframe_enc_info
+{
+  /* Encoder context.  */
+  struct sframe_encoder_ctx *sfe_ctx;
+  /* Output section.  */
+  asection *sframe_section;
+};
+
 /* Enum used to identify target specific extensions to the elf_obj_tdata
    and elf_link_hash_table structures.  Note the enums deliberately start
    from 1 so that we can detect an uninitialized field.  The generic value
@@ -668,6 +702,9 @@ struct elf_link_hash_table
   /* Used by eh_frame code when editing .eh_frame.  */
   struct eh_frame_hdr_info eh_info;
 
+  /* Used to link unwind data in .sframe sections.  */
+  struct sframe_enc_info sfe_info;
+
   /* A linked list of local symbols to be added to .dynsym.  */
   struct elf_link_local_dynamic_entry *dynlocal;
 
@@ -1944,6 +1981,10 @@ struct output_elf_obj_tdata
   /* Segment flags for the PT_GNU_STACK segment.  */
   unsigned int stack_flags;
 
+  /* Used to determine if PT_GNU_SFRAME segment header should be
+     created.  */
+  asection *sframe;
+
   /* Used to determine if the e_flags field has been initialized */
   bool flags_init;
 };
@@ -2125,6 +2166,7 @@ struct elf_obj_tdata
 #define elf_link_info(bfd)     (elf_tdata(bfd) -> o->link_info)
 #define elf_next_file_pos(bfd) (elf_tdata(bfd) -> o->next_file_pos)
 #define elf_stack_flags(bfd)   (elf_tdata(bfd) -> o->stack_flags)
+#define elf_sframe(bfd)                (elf_tdata(bfd) -> o->sframe)
 #define elf_shstrtab(bfd)      (elf_tdata(bfd) -> o->strtab_ptr)
 #define elf_onesymtab(bfd)     (elf_tdata(bfd) -> symtab_section)
 #define elf_symtab_shndx_list(bfd)     (elf_tdata(bfd) -> symtab_shndx_list)
@@ -2439,6 +2481,18 @@ extern bool _bfd_elf_eh_frame_entry_present
 extern bool _bfd_elf_maybe_strip_eh_frame_hdr
   (struct bfd_link_info *);
 
+extern bool _bfd_elf_sframe_present
+  (struct bfd_link_info *);
+extern bool _bfd_elf_parse_sframe
+  (bfd *, struct bfd_link_info *, asection *, struct elf_reloc_cookie *);
+extern bool _bfd_elf_discard_section_sframe
+  (asection *, bool (*) (bfd_vma, void *), struct elf_reloc_cookie *);
+extern bool _bfd_elf_merge_section_sframe
+  (bfd *, struct bfd_link_info *, asection *, bfd_byte *);
+extern bool _bfd_elf_write_section_sframe
+  (bfd *, struct bfd_link_info *);
+extern bool _bfd_elf_set_section_sframe (bfd *, struct bfd_link_info *);
+
 extern bool _bfd_elf_hash_symbol (struct elf_link_hash_entry *);
 
 extern long _bfd_elf_link_lookup_local_dynindx
diff --git a/bfd/elf-sframe.c b/bfd/elf-sframe.c
new file mode 100644 (file)
index 0000000..8055aa3
--- /dev/null
@@ -0,0 +1,544 @@
+/* .sframe section processing.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "sframe-api.h"
+
+/* Return TRUE if the function has been marked for deletion during the linking
+   process.  */
+
+static bool
+sframe_decoder_func_deleted_p (struct sframe_dec_info *sfd_info,
+                              unsigned int func_idx)
+{
+  if (func_idx < sfd_info->sfd_fde_count)
+    return sfd_info->sfd_func_bfdinfo[func_idx].func_deleted_p;
+
+  return false;
+}
+
+/* Mark the function in the decoder info for deletion.  */
+
+static void
+sframe_decoder_mark_func_deleted (struct sframe_dec_info *sfd_info,
+                                 unsigned int func_idx)
+{
+  if (func_idx < sfd_info->sfd_fde_count)
+    sfd_info->sfd_func_bfdinfo[func_idx].func_deleted_p = true;
+}
+
+/* Get the relocation offset from the decoder info for the given function.  */
+
+static unsigned int
+sframe_decoder_get_func_r_offset (struct sframe_dec_info *sfd_info,
+                                 unsigned int func_idx)
+{
+  BFD_ASSERT (func_idx < sfd_info->sfd_fde_count);
+  unsigned int func_r_offset
+    = sfd_info->sfd_func_bfdinfo[func_idx].func_r_offset;
+  /* There must have been a reloc.  */
+  BFD_ASSERT (func_r_offset);
+  return func_r_offset;
+}
+
+/* Bookkeep the function relocation offset in the decoder info.  */
+
+static void
+sframe_decoder_set_func_r_offset (struct sframe_dec_info *sfd_info,
+                                 unsigned int func_idx,
+                                 unsigned int r_offset)
+{
+  if (func_idx < sfd_info->sfd_fde_count)
+    sfd_info->sfd_func_bfdinfo[func_idx].func_r_offset = r_offset;
+}
+
+/* Get the relocation index in the elf_reloc_cookie for the function.  */
+
+static unsigned int
+sframe_decoder_get_func_reloc_index (struct sframe_dec_info *sfd_info,
+                                    unsigned int func_idx)
+{
+  BFD_ASSERT (func_idx < sfd_info->sfd_fde_count);
+  return sfd_info->sfd_func_bfdinfo[func_idx].func_reloc_index;
+}
+
+/* Bookkeep the relocation index in the elf_reloc_cookie for the function.  */
+
+static void
+sframe_decoder_set_func_reloc_index (struct sframe_dec_info *sfd_info,
+                                    unsigned int func_idx,
+                                    unsigned int reloc_index)
+{
+  if (func_idx < sfd_info->sfd_fde_count)
+    sfd_info->sfd_func_bfdinfo[func_idx].func_reloc_index = reloc_index;
+}
+
+/* Initialize the set of additional information in CFD_INFO,
+   needed for linking SEC.  Returns TRUE if setup is done successfully.  */
+
+static bool
+sframe_decoder_init_func_bfdinfo (asection *sec,
+                                 struct sframe_dec_info *sfd_info,
+                                 struct elf_reloc_cookie *cookie)
+{
+  unsigned int fde_count;
+  unsigned int func_bfdinfo_size, i;
+
+  fde_count = sframe_decoder_get_num_fidx (sfd_info->sfd_ctx);
+  sfd_info->sfd_fde_count = fde_count;
+
+  /* Allocate and clear the memory.  */
+  func_bfdinfo_size = (sizeof (struct sframe_func_bfdinfo)) * fde_count;
+  sfd_info->sfd_func_bfdinfo
+    = (struct sframe_func_bfdinfo*) bfd_malloc (func_bfdinfo_size);
+  if (sfd_info->sfd_func_bfdinfo == NULL)
+    return false;
+  memset (sfd_info->sfd_func_bfdinfo, 0, func_bfdinfo_size);
+
+  /* For linker generated .sframe sections, we have no relocs.  Skip.  */
+  if ((sec->flags & SEC_LINKER_CREATED) && cookie->rels == NULL)
+    return true;
+
+  for (i = 0; i < fde_count; i++)
+    {
+      cookie->rel = cookie->rels + i;
+      BFD_ASSERT (cookie->rel < cookie->relend);
+      /* Bookkeep the relocation offset and relocation index of each function
+        for later use.  */
+      sframe_decoder_set_func_r_offset (sfd_info, i, cookie->rel->r_offset);
+      sframe_decoder_set_func_reloc_index (sfd_info, i,
+                                          (cookie->rel - cookie->rels));
+
+      cookie->rel++;
+    }
+  BFD_ASSERT (cookie->rel == cookie->relend);
+
+  return true;
+}
+
+/* Read the value from CONTENTS at the specified OFFSET for the given ABFD.  */
+
+static bfd_vma
+sframe_read_value (bfd *abfd, bfd_byte *contents, unsigned int offset,
+                  unsigned int width)
+{
+  BFD_ASSERT (contents && offset);
+  /* Supporting the usecase of reading only the 4-byte relocated
+     value (signed offset for func start addr) for now.  */
+  BFD_ASSERT (width == 4);
+  /* FIXME endianness ?? */
+  unsigned char *buf = contents + offset;
+  bfd_vma value = bfd_get_signed_32 (abfd, buf);
+  return value;
+}
+
+/* Return true if there is at least one non-empty .sframe section in
+   input files.  Can only be called after ld has mapped input to
+   output sections, and before sections are stripped.  */
+
+bool
+_bfd_elf_sframe_present (struct bfd_link_info *info)
+{
+  asection *sframe = bfd_get_section_by_name (info->output_bfd, ".sframe");
+
+  if (sframe == NULL)
+    return false;
+
+  /* Count only sections which have at least a single FDE.  */
+  for (sframe = sframe->map_head.s; sframe != NULL; sframe = sframe->map_head.s)
+    /* Note that this may become an approximate check in the future when
+       some ABI/arch begin to use the sfh_auxhdr_len.  When sfh_auxhdr_len has
+       non-zero value, it will need to be accounted for in the calculation of
+       the SFrame header size.  */
+    if (sframe->size > sizeof (sframe_header))
+      return true;
+  return false;
+}
+
+/* Try to parse .sframe section SEC, which belongs to ABFD.  Store the
+   information in the section's sec_info field on success.  COOKIE
+   describes the relocations in SEC.
+
+   Returns TRUE if success, FALSE if any error or failure.  */
+
+bool
+_bfd_elf_parse_sframe (bfd *abfd,
+                      struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                      asection *sec, struct elf_reloc_cookie *cookie)
+{
+  bfd_byte *sfbuf = NULL;
+  struct sframe_dec_info *sfd_info;
+  sframe_decoder_ctx *sfd_ctx;
+  bfd_size_type sf_size;
+  int decerr = 0;
+
+  if (sec->size == 0
+      || sec->sec_info_type != SEC_INFO_TYPE_NONE)
+    {
+      /* This file does not contain .sframe information.  */
+      return false;
+    }
+
+  if (bfd_is_abs_section (sec->output_section))
+    {
+      /* At least one of the sections is being discarded from the
+        link, so we should just ignore them.  */
+      return false;
+    }
+
+  /* Read the SFrame unwind information from abfd.  */
+  if (!bfd_malloc_and_get_section (abfd, sec, &sfbuf))
+    goto fail_no_free;
+
+  /* Decode the buffer and keep decoded contents for later use.
+     Relocations are performed later, but are such that the section's
+     size is unaffected.  */
+  sfd_info = bfd_malloc (sizeof (struct sframe_dec_info));
+  sf_size = sec->size;
+
+  sfd_info->sfd_ctx = sframe_decode ((const char*)sfbuf, sf_size, &decerr);
+  sfd_ctx = sfd_info->sfd_ctx;
+  if (!sfd_ctx)
+    /* Free'ing up any memory held by decoder context is done by
+       sframe_decode in case of error.  */
+    goto fail_no_free;
+
+  if (!sframe_decoder_init_func_bfdinfo (sec, sfd_info, cookie))
+    {
+      sframe_decoder_free (&sfd_ctx);
+      goto fail_no_free;
+    }
+
+  elf_section_data (sec)->sec_info = sfd_info;
+  sec->sec_info_type = SEC_INFO_TYPE_SFRAME;
+
+  goto success;
+
+fail_no_free:
+  _bfd_error_handler
+   (_("error in %pB(%pA); no .sframe will be created"),
+    abfd, sec);
+  return false;
+success:
+  free (sfbuf);
+  return true;
+}
+
+/* This function is called for each input file before the .sframe section
+   is relocated.  It marks the SFrame FDE for the discarded functions for
+   deletion.
+
+   The function returns TRUE iff any entries have been deleted.  */
+
+bool
+_bfd_elf_discard_section_sframe
+   (asection *sec,
+    bool (*reloc_symbol_deleted_p) (bfd_vma, void *),
+    struct elf_reloc_cookie *cookie)
+{
+  bool changed;
+  bool keep;
+  unsigned int i;
+  unsigned int func_desc_offset;
+  unsigned int num_fidx;
+  struct sframe_dec_info *sfd_info;
+
+  changed = false;
+  /* FIXME - if relocatable link and changed = true, how does the final
+     .rela.sframe get updated ?.  */
+  keep = false;
+
+  sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info;
+
+  /* Skip checking for the linker created .sframe sections
+     (for PLT sections).  */
+  if ((sec->flags & SEC_LINKER_CREATED) == 0 || cookie->rels != NULL)
+    {
+      num_fidx = sframe_decoder_get_num_fidx (sfd_info->sfd_ctx);
+      for (i = 0; i < num_fidx; i++)
+       {
+         func_desc_offset = sframe_decoder_get_func_r_offset (sfd_info, i);
+
+         cookie->rel = cookie->rels
+           + sframe_decoder_get_func_reloc_index (sfd_info, i);
+         keep = !(*reloc_symbol_deleted_p) (func_desc_offset, cookie);
+
+         if (!keep)
+           {
+             sframe_decoder_mark_func_deleted (sfd_info, i);
+             changed = true;
+           }
+       }
+    }
+  return changed;
+}
+
+/* Update the reference to the output .sframe section in the output ELF
+   BFD ABFD.  Returns true if no error.  */
+
+bool
+_bfd_elf_set_section_sframe (bfd *abfd,
+                               struct bfd_link_info *info)
+{
+  asection *cfsec;
+
+  cfsec = bfd_get_section_by_name (info->output_bfd, ".sframe");
+  if (!cfsec)
+    return false;
+
+  elf_sframe (abfd) = cfsec;
+
+  return true;
+}
+
+/* Merge .sframe section SEC.  This is called with the relocated
+   CONTENTS.  */
+
+bool
+_bfd_elf_merge_section_sframe (bfd *abfd,
+                              struct bfd_link_info *info,
+                              asection *sec,
+                              bfd_byte *contents)
+{
+  struct sframe_dec_info *sfd_info;
+  struct sframe_enc_info *sfe_info;
+  sframe_decoder_ctx *sfd_ctx;
+  sframe_encoder_ctx *sfe_ctx;
+  unsigned char sfd_ctx_abi_arch;
+  int8_t sfd_ctx_fixed_fp_offset;
+  int8_t sfd_ctx_fixed_ra_offset;
+  int encerr = 0;
+
+  struct elf_link_hash_table *htab;
+  asection *cfsec;
+
+  /* Sanity check - handle SFrame sections only.  */
+  if (sec->sec_info_type != SEC_INFO_TYPE_SFRAME)
+    return false;
+
+  sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info;
+  sfd_ctx = sfd_info->sfd_ctx;
+
+  htab = elf_hash_table (info);
+  sfe_info = &(htab->sfe_info);
+  sfe_ctx = sfe_info->sfe_ctx;
+
+  /* All input bfds are expected to have a valid SFrame section.  Even if
+     the SFrame section is empty with only a header, there must be a valid
+     SFrame decoder context by now.  The SFrame encoder context, however,
+     will get set later here, if this is the first call to the function.  */
+  if (sfd_ctx == NULL || sfe_info == NULL)
+    return false;
+
+  if (htab->sfe_info.sfe_ctx == NULL)
+    {
+      sfd_ctx_abi_arch = sframe_decoder_get_abi_arch (sfd_ctx);
+      sfd_ctx_fixed_fp_offset = sframe_decoder_get_fixed_fp_offset (sfd_ctx);
+      sfd_ctx_fixed_ra_offset = sframe_decoder_get_fixed_ra_offset (sfd_ctx);
+
+      /* Valid values are non-zero.  */
+      if (!sfd_ctx_abi_arch)
+       return false;
+
+      htab->sfe_info.sfe_ctx = sframe_encode (SFRAME_VERSION_1,
+                                             0, /* SFrame flags.  */
+                                             sfd_ctx_abi_arch,
+                                             sfd_ctx_fixed_fp_offset,
+                                             sfd_ctx_fixed_ra_offset,
+                                             &encerr);
+      /* Handle errors from sframe_encode.  */
+      if (htab->sfe_info.sfe_ctx == NULL)
+       return false;
+    }
+  sfe_ctx = sfe_info->sfe_ctx;
+
+  if (sfe_info->sframe_section == NULL)
+    {
+      /* Make sure things are set for an eventual write.
+        Size of the output section is not known until
+        _bfd_elf_write_section_sframe is ready with the buffer
+        to write out.  */
+      cfsec = bfd_get_section_by_name (info->output_bfd, ".sframe");
+      if (cfsec)
+       {
+         sfe_info->sframe_section = cfsec;
+         // elf_sframe (abfd) = cfsec;
+       }
+      else
+       return false;
+    }
+
+  /* Check that all .sframe sections being linked have the same
+     ABI/arch.  */
+  if (sframe_decoder_get_abi_arch (sfd_ctx)
+      != sframe_encoder_get_abi_arch (sfe_ctx))
+    {
+      _bfd_error_handler
+       (_("input SFrame sections with different abi prevent .sframe"
+         " generation"));
+      return false;
+    }
+
+  /* Iterate over the function descriptor entries and the FREs of the
+     function from the decoder context.  Add each of them to the encoder
+     context, if suitable.  */
+  unsigned int i = 0, j = 0, cur_fidx = 0;
+
+  unsigned int num_fidx = sframe_decoder_get_num_fidx (sfd_ctx);
+  unsigned int num_enc_fidx = sframe_encoder_get_num_fidx (sfe_ctx);
+
+  for (i = 0; i < num_fidx; i++)
+    {
+      unsigned int num_fres = 0;
+      int32_t func_start_address;
+      bfd_vma address;
+      uint32_t func_size = 0;
+      unsigned char func_info = 0;
+      unsigned int r_offset = 0;
+      bool pltn_reloc_by_hand = false;
+      unsigned int pltn_r_offset = 0;
+
+      if (!sframe_decoder_get_funcdesc (sfd_ctx, i, &num_fres, &func_size,
+                                       &func_start_address, &func_info))
+       {
+         /* If function belongs to a deleted section, skip editing the
+            function descriptor entry.  */
+         if (sframe_decoder_func_deleted_p(sfd_info, i))
+           continue;
+
+         /* Don't edit function descriptor entries for relocatable link.  */
+         if (!bfd_link_relocatable (info))
+           {
+             if (!(sec->flags & SEC_LINKER_CREATED))
+               {
+                 /* Get relocated contents by reading the value of the
+                    relocated function start address at the beginning of the
+                    function descriptor entry.  */
+                 r_offset = sframe_decoder_get_func_r_offset (sfd_info, i);
+               }
+             else
+               {
+                 /* Expected to land here for SFrame unwind info as created
+                    for the .plt* sections.  These sections can have upto two
+                    FDE entries.  Although the code should work for > 2,
+                    leaving this assert here for safety.  */
+                 BFD_ASSERT (num_fidx <= 2);
+                 /* For the first entry, we know the offset of the SFrame FDE's
+                    sfde_func_start_address.  Side note: see how the value
+                    of PLT_SFRAME_FDE_START_OFFSET is also set to the
+                    same.  */
+                 r_offset = sframe_decoder_get_hdr_size (sfd_ctx);
+                 /* For any further SFrame FDEs, the generator has already put
+                    in an offset in place of sfde_func_start_address of the
+                    corresponding FDE.  We will use it by hand to relocate.  */
+                 if (i > 0)
+                   {
+                     pltn_r_offset
+                       = r_offset + (i * sizeof (sframe_func_desc_entry));
+                     pltn_reloc_by_hand = true;
+                   }
+               }
+
+             /* Get the SFrame FDE function start address after relocation.  */
+             address = sframe_read_value (abfd, contents, r_offset, 4);
+             if (pltn_reloc_by_hand)
+               address += sframe_read_value (abfd, contents,
+                                             pltn_r_offset, 4);
+             address += (sec->output_offset + r_offset);
+
+             /* FIXME For testing only. Cleanup later.  */
+             // address += (sec->output_section->vma);
+
+             func_start_address = address;
+           }
+
+         /* Update the encoder context with updated content.  */
+         int err = sframe_encoder_add_funcdesc (sfe_ctx, func_start_address,
+                                                func_size, func_info,
+                                                num_fres);
+         cur_fidx++;
+         BFD_ASSERT (!err);
+       }
+
+      for (j = 0; j < num_fres; j++)
+       {
+         sframe_frame_row_entry fre;
+         if (!sframe_decoder_get_fre (sfd_ctx, i, j, &fre))
+           {
+             int err = sframe_encoder_add_fre (sfe_ctx,
+                                               cur_fidx-1+num_enc_fidx,
+                                               &fre);
+             BFD_ASSERT (!err);
+           }
+       }
+    }
+  /* Free the SFrame decoder context.  */
+  sframe_decoder_free (&sfd_ctx);
+
+  return true;
+}
+
+/* Write out the .sframe section.  This must be called after
+   _bfd_elf_merge_section_sframe has been called on all input
+   .sframe sections.  */
+
+bool
+_bfd_elf_write_section_sframe (bfd *abfd, struct bfd_link_info *info)
+{
+  bool retval = true;
+
+  struct elf_link_hash_table *htab;
+  struct sframe_enc_info *sfe_info;
+  sframe_encoder_ctx *sfe_ctx;
+  asection *sec;
+  void *contents;
+  size_t sec_size;
+  int err = 0;
+
+  htab = elf_hash_table (info);
+  sfe_info = &htab->sfe_info;
+  sec = sfe_info->sframe_section;
+  sfe_ctx = sfe_info->sfe_ctx;
+
+  if (sec == NULL)
+    return true;
+
+  contents = sframe_encoder_write (sfe_ctx, &sec_size, &err);
+  sec->size = (bfd_size_type) sec_size;
+
+  if (!bfd_set_section_contents (abfd, sec->output_section, contents,
+                                (file_ptr) sec->output_offset,
+                                sec->size))
+    retval = false;
+  else if (!bfd_link_relocatable (info))
+    {
+      Elf_Internal_Shdr *hdr = &elf_section_data (sec)->this_hdr;
+      hdr->sh_size = sec->size;
+    }
+  /* For relocatable links, do not update the section size as the section
+     contents have not been relocated.  */
+
+  sframe_encoder_free (&sfe_ctx);
+
+  return retval;
+}
index 81825b748d75f2b68a6cca1c54b126df53c36dc2..87ec1623313aafb937e8520f1d5555826033f124 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1673,6 +1673,7 @@ get_segment_type (unsigned int p_type)
     case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
     case PT_GNU_STACK: pt = "STACK"; break;
     case PT_GNU_RELRO: pt = "RELRO"; break;
+    case PT_GNU_SFRAME: pt = "SFRAME"; break;
     default: pt = NULL; break;
     }
   return pt;
@@ -3081,6 +3082,10 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int hdr_index)
     case PT_GNU_RELRO:
       return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "relro");
 
+    case PT_GNU_SFRAME:
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index,
+                                             "sframe");
+
     default:
       /* Check for any processor-specific program segment types.  */
       bed = get_elf_backend_data (abfd);
@@ -4450,6 +4455,12 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info)
       ++segs;
     }
 
+  if (elf_sframe (abfd))
+    {
+      /* We need a PT_GNU_SFRAME segment.  */
+      ++segs;
+    }
+
   s = bfd_get_section_by_name (abfd,
                               NOTE_GNU_PROPERTY_SECTION_NAME);
   if (s != NULL && s->size != 0)
@@ -4715,6 +4726,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd,
       asection *first_tls = NULL;
       asection *first_mbind = NULL;
       asection *dynsec, *eh_frame_hdr;
+      asection *sframe;
       size_t amt;
       bfd_vma addr_mask, wrap_to = 0;  /* Bytes.  */
       bfd_size_type phdr_size;  /* Octets/bytes.  */
@@ -5210,6 +5222,26 @@ _bfd_elf_map_sections_to_segments (bfd *abfd,
          pm = &m->next;
        }
 
+      /* If there is a .sframe section, throw in a PT_GNU_SFRAME
+        segment.  */
+      sframe = elf_sframe (abfd);
+      if (sframe != NULL
+         && (sframe->output_section->flags & SEC_LOAD) != 0
+         && sframe->size != 0)
+       {
+         amt = sizeof (struct elf_segment_map);
+         m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+         if (m == NULL)
+           goto error_return;
+         m->next = NULL;
+         m->p_type = PT_GNU_SFRAME;
+         m->count = 1;
+         m->sections[0] = sframe->output_section;
+
+         *pm = m;
+         pm = &m->next;
+       }
+
       if (elf_stack_flags (abfd))
        {
          amt = sizeof (struct elf_segment_map);
index 2ae8dffba0f0f980f16931ad7bbc41db0a0886d6..fb872793d5f806389c31e2fac5d7596348e60668 100644 (file)
@@ -22,6 +22,7 @@
 #include "elfxx-x86.h"
 #include "dwarf2.h"
 #include "libiberty.h"
+#include "sframe.h"
 
 #include "opcode/i386.h"
 
@@ -818,6 +819,87 @@ static const bfd_byte elf_x86_64_eh_frame_non_lazy_plt[] =
   DW_CFA_nop, DW_CFA_nop, DW_CFA_nop
 };
 
+static const sframe_frame_row_entry elf_x86_64_sframe_null_fre =
+{
+  0,
+  SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .sframe FRE covering the .plt section entry.  */
+static const sframe_frame_row_entry elf_x86_64_sframe_plt0_fre1 =
+{
+  0, /* SFrame FRE start address.  */
+  SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .sframe FRE covering the .plt section entry.  */
+static const sframe_frame_row_entry elf_x86_64_sframe_plt0_fre2 =
+{
+  6, /* SFrame FRE start address.  */
+  SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .sframe FRE covering the .plt section entry.  */
+static const sframe_frame_row_entry elf_x86_64_sframe_pltn_fre1 =
+{
+  0, /* SFrame FRE start address.  */
+  SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .sframe FRE covering the .plt section entry.  */
+static const sframe_frame_row_entry elf_x86_64_sframe_pltn_fre2 =
+{
+  11, /* SFrame FRE start address.  */
+  SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .sframe FRE covering the second .plt section entry.  */
+static const sframe_frame_row_entry elf_x86_64_sframe_sec_pltn_fre1 =
+{
+  0, /* SFrame FRE start address.  */
+  SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* SFrame helper object for non-lazy PLT.  Also used for IBT enabled PLT.  */
+static const struct elf_x86_sframe_plt elf_x86_64_sframe_non_lazy_plt =
+{
+  LAZY_PLT_ENTRY_SIZE,
+  2, /* Number of FREs for PLT0.  */
+  /* Array of SFrame FREs for plt0.  */
+  { &elf_x86_64_sframe_plt0_fre1, &elf_x86_64_sframe_plt0_fre2 },
+  LAZY_PLT_ENTRY_SIZE,
+  1, /* Number of FREs for PLTn.  */
+  /* Array of SFrame FREs for plt.  */
+  { &elf_x86_64_sframe_sec_pltn_fre1, &elf_x86_64_sframe_null_fre },
+  0,
+  0, /* There is no second PLT necessary.  */
+  { &elf_x86_64_sframe_null_fre }
+};
+
+/* SFrame helper object for lazy PLT.  Also used for IBT enabled PLT.  */
+static const struct elf_x86_sframe_plt elf_x86_64_sframe_plt =
+{
+  LAZY_PLT_ENTRY_SIZE,
+  2, /* Number of FREs for PLT0.  */
+  /* Array of SFrame FREs for plt0.  */
+  { &elf_x86_64_sframe_plt0_fre1, &elf_x86_64_sframe_plt0_fre2 },
+  LAZY_PLT_ENTRY_SIZE,
+  2, /* Number of FREs for PLTn.  */
+  /* Array of SFrame FREs for plt.  */
+  { &elf_x86_64_sframe_pltn_fre1, &elf_x86_64_sframe_pltn_fre2 },
+  NON_LAZY_PLT_ENTRY_SIZE,
+  1, /* Number of FREs for PLTn for second PLT.  */
+  /* FREs for second plt ( unwind info for .plt.got is
+     identical).  Used when IBT or non-lazy PLT is in effect.  */
+  { &elf_x86_64_sframe_sec_pltn_fre1 }
+};
+
 /* These are the standard parameters.  */
 static const struct elf_x86_lazy_plt_layout elf_x86_64_lazy_plt =
   {
@@ -971,7 +1053,6 @@ static const struct elf_x86_non_lazy_plt_layout elf_x32_non_lazy_ibt_plt =
     sizeof (elf_x86_64_eh_frame_non_lazy_plt) /* eh_frame_plt_size */
   };
 
-
 static bool
 elf64_x86_64_elf_object_p (bfd *abfd)
 {
@@ -5228,6 +5309,20 @@ elf_x86_64_link_setup_gnu_properties (struct bfd_link_info *info)
       init_table.non_lazy_ibt_plt = &elf_x32_non_lazy_ibt_plt;
     }
 
+  if (ABI_64_P (info->output_bfd))
+    {
+      init_table.sframe_lazy_plt = &elf_x86_64_sframe_plt;
+      init_table.sframe_non_lazy_plt = &elf_x86_64_sframe_non_lazy_plt;
+      init_table.sframe_lazy_ibt_plt = &elf_x86_64_sframe_plt;
+      init_table.sframe_non_lazy_ibt_plt = &elf_x86_64_sframe_non_lazy_plt;
+    }
+  else
+    {
+      /* SFrame is not supported for non AMD64.  */
+      init_table.sframe_lazy_plt = NULL;
+      init_table.sframe_non_lazy_plt = NULL;
+    }
+
   if (ABI_64_P (info->output_bfd))
     {
       init_table.r_info = elf64_r_info;
index 4ef0739416045027c8fbede5f7d176c4fd7a32d5..20cee4c76a49ee5089f5bfa26ffd638988cee7c1 100644 (file)
@@ -10900,6 +10900,7 @@ elf_section_ignore_discarded_relocs (asection *sec)
     case SEC_INFO_TYPE_STABS:
     case SEC_INFO_TYPE_EH_FRAME:
     case SEC_INFO_TYPE_EH_FRAME_ENTRY:
+    case SEC_INFO_TYPE_SFRAME:
       return true;
     default:
       break;
@@ -10938,6 +10939,9 @@ _bfd_elf_default_action_discarded (asection *sec)
       && strncmp (sec->name, ".eh_frame.", 10) == 0)
     return 0;
 
+  if (strcmp (".sframe", sec->name) == 0)
+    return 0;
+
   if (strcmp (".gcc_except_table", sec->name) == 0)
     return 0;
 
@@ -11871,6 +11875,16 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
              return false;
          }
          break;
+       case SEC_INFO_TYPE_SFRAME:
+           {
+             /* Merge .sframe sections into the ctf frame encoder
+                context of the output_bfd's section.  The final .sframe
+                output section will be written out later.  */
+             if (!_bfd_elf_merge_section_sframe (output_bfd, flinfo->info,
+                                                 o, contents))
+               return false;
+           }
+           break;
        default:
          {
            if (! (o->flags & SEC_EXCLUDE))
@@ -13454,6 +13468,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info))
     goto error_return;
 
+  if (! _bfd_elf_write_section_sframe (abfd, info))
+    goto error_return;
+
   if (info->callbacks->emit_ctf)
       info->callbacks->emit_ctf ();
 
@@ -14909,6 +14926,41 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
                                _bfd_elf_adjust_eh_frame_global_symbol, NULL);
     }
 
+  o = bfd_get_section_by_name (output_bfd, ".sframe");
+  if (o != NULL)
+    {
+      asection *i;
+
+      for (i = o->map_head.s; i != NULL; i = i->map_head.s)
+       {
+         if (i->size == 0)
+           continue;
+
+         abfd = i->owner;
+         if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+           continue;
+
+         if (!init_reloc_cookie_for_section (&cookie, info, i))
+           return -1;
+
+         if (_bfd_elf_parse_sframe (abfd, info, i, &cookie))
+           {
+             if (_bfd_elf_discard_section_sframe (i,
+                                                  bfd_elf_reloc_symbol_deleted_p,
+                                                  &cookie))
+               {
+                 if (i->size != i->rawsize)
+                   changed = 1;
+               }
+           }
+         fini_reloc_cookie_for_section (&cookie, i);
+       }
+      /* Update the reference to the output .sframe section.  Used to
+        determine later if PT_GNU_SFRAME segment is to be generated.  */
+      if (!_bfd_elf_set_section_sframe (output_bfd, info))
+       return -1;
+    }
+
   for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
     {
       const struct elf_backend_data *bed;
index 7fb972752b347617137548da1c2764700d90a61e..c48d0385485ceaf731a9a3c17326225c6d86c084 100644 (file)
@@ -1777,6 +1777,191 @@ elf_x86_relative_reloc_compare (const void *pa, const void *pb)
   return 0;
 }
 
+enum dynobj_sframe_plt_type
+{
+  SFRAME_PLT = 1,
+  SFRAME_PLT_SEC = 2
+};
+
+/* Create SFrame unwind info for the plt entries in the .plt section
+   of type PLT_SEC_TYPE.  */
+
+static bool
+_bfd_x86_elf_create_sframe_plt (bfd *output_bfd,
+                               struct bfd_link_info *info,
+                               unsigned int plt_sec_type)
+{
+  struct elf_x86_link_hash_table *htab;
+  const struct elf_backend_data *bed;
+
+  bool plt0_generated_p;
+  unsigned int plt0_entry_size;
+  unsigned char func_info;
+  unsigned int fre_type;
+  /* The dynamic plt section for which .sframe unwind information is being
+     created.  */
+  asection *dpltsec;
+
+  int err = 0;
+
+  sframe_encoder_ctx **ectx = NULL;
+  unsigned plt_entry_size = 0;
+  unsigned int num_pltn_fres = 0;
+  unsigned int num_pltn_entries = 0;
+
+  bed = get_elf_backend_data (output_bfd);
+  htab = elf_x86_hash_table (info, bed->target_id);
+  /* Whether SFrame unwind info for plt0 is to be generated.  */
+  plt0_generated_p = htab->plt.has_plt0;
+  plt0_entry_size
+    = (plt0_generated_p) ? htab->sframe_plt->plt0_entry_size : 0;
+
+  switch (plt_sec_type)
+    {
+    case SFRAME_PLT:
+       {
+         ectx = &htab->plt_cfe_ctx;
+         dpltsec = htab->elf.splt;
+
+         plt_entry_size = htab->plt.plt_entry_size;
+         num_pltn_fres = htab->sframe_plt->pltn_num_fres;
+         num_pltn_entries
+           = (htab->elf.splt->size - plt0_entry_size) / plt_entry_size;
+
+         break;
+       }
+    case SFRAME_PLT_SEC:
+       {
+         ectx = &htab->plt_second_cfe_ctx;
+         /* FIXME - this or htab->plt_second_sframe ?  */
+         dpltsec = htab->plt_second_eh_frame;
+
+         plt_entry_size = htab->sframe_plt->sec_pltn_entry_size;
+         num_pltn_fres = htab->sframe_plt->sec_pltn_num_fres;
+         num_pltn_entries
+               = htab->plt_second_eh_frame->size / plt_entry_size;
+         break;
+       }
+    default:
+      /* No other value is possible.  */
+      return false;
+      break;
+    }
+
+  *ectx = sframe_encode (SFRAME_VERSION_1,
+                        0,
+                        SFRAME_ABI_AMD64_ENDIAN_LITTLE,
+                        SFRAME_CFA_FIXED_FP_INVALID,
+                        -8, /*  Fixed RA offset.  */
+                        &err);
+
+  /* FRE type is dependent on the size of the function.  */
+  fre_type = sframe_calc_fre_type (dpltsec->size);
+  func_info = sframe_fde_func_info (fre_type,
+                                   SFRAME_FDE_TYPE_PCINC);
+
+  /* Add SFrame FDE and the associated FREs for plt0 if plt0 has been
+     generated.  */
+  if (plt0_generated_p)
+    {
+      /* Add SFrame FDE for plt0, the function start address is updated later
+        at _bfd_elf_merge_section_sframe time.  */
+      sframe_encoder_add_funcdesc (*ectx,
+                                  0, /* func start addr.  */
+                                  plt0_entry_size,
+                                  func_info,
+                                  0 /* Num FREs.  */);
+      sframe_frame_row_entry plt0_fre;
+      unsigned int num_plt0_fres = htab->sframe_plt->plt0_num_fres;
+      for (unsigned int j = 0; j < num_plt0_fres; j++)
+       {
+         plt0_fre = *(htab->sframe_plt->plt0_fres[j]);
+         sframe_encoder_add_fre (*ectx, 0, &plt0_fre);
+       }
+    }
+
+
+  if (num_pltn_entries)
+    {
+      /* pltn entries use an SFrame FDE of type
+        SFRAME_FDE_TYPE_PCMASK to exploit the repetitive
+        pattern of the instructions in these entries.  Using this SFrame FDE
+        type helps in keeping the unwind information for pltn entries
+        compact.  */
+      func_info        = sframe_fde_func_info (fre_type, SFRAME_FDE_TYPE_PCMASK);
+      /* Add the SFrame FDE for all PCs starting at the first pltn entry (hence,
+        function start address = plt0_entry_size.  As usual, this will be
+        updated later at _bfd_elf_merge_section_sframe, by when the
+        sections are relocated.  */
+      sframe_encoder_add_funcdesc (*ectx,
+                                  plt0_entry_size, /* func start addr.  */
+                                  dpltsec->size - plt0_entry_size,
+                                  func_info,
+                                  0 /* Num FREs.  */);
+
+      sframe_frame_row_entry pltn_fre;
+      /* Now add the FREs for pltn.  Simply adding the two FREs suffices due
+        to the usage of SFRAME_FDE_TYPE_PCMASK above.  */
+      for (unsigned int j = 0; j < num_pltn_fres; j++)
+       {
+         pltn_fre = *(htab->sframe_plt->pltn_fres[j]);
+         sframe_encoder_add_fre (*ectx, 1, &pltn_fre);
+       }
+    }
+
+  return true;
+}
+
+/* Put contents of the .sframe section corresponding to the specified
+   PLT_SEC_TYPE.  */
+
+static bool
+_bfd_x86_elf_write_sframe_plt (bfd *output_bfd,
+                              struct bfd_link_info *info,
+                              unsigned int plt_sec_type)
+{
+  struct elf_x86_link_hash_table *htab;
+  const struct elf_backend_data *bed;
+  sframe_encoder_ctx *ectx;
+  size_t sec_size;
+  asection *sec;
+  bfd *dynobj;
+
+  int err = 0;
+
+  bed = get_elf_backend_data (output_bfd);
+  htab = elf_x86_hash_table (info, bed->target_id);
+  dynobj = htab->elf.dynobj;
+
+  switch (plt_sec_type)
+    {
+    case SFRAME_PLT:
+      ectx = htab->plt_cfe_ctx;
+      sec = htab->plt_sframe;
+      break;
+    case SFRAME_PLT_SEC:
+      ectx = htab->plt_second_cfe_ctx;
+      sec = htab->plt_second_sframe;
+      break;
+    default:
+      /* No other value is possible.  */
+      return false;
+      break;
+    }
+
+  BFD_ASSERT (ectx);
+
+  void *contents = sframe_encoder_write (ectx, &sec_size, &err);
+
+  sec->size = (bfd_size_type) sec_size;
+  sec->contents = (unsigned char *) bfd_zalloc (dynobj, sec->size);
+  memcpy (sec->contents, contents, sec_size);
+
+  sframe_encoder_free (&ectx);
+
+  return true;
+}
+
 bool
 _bfd_elf_x86_size_relative_relocs (struct bfd_link_info *info,
                                   bool *need_layout)
@@ -2267,6 +2452,42 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
          = htab->non_lazy_plt->eh_frame_plt_size;
     }
 
+  /* No need to size the .sframe section explicitly because the write-out
+     mechanism is different.  Simply prep up the FDE/FRE for the
+     .plt section.  */
+  if (_bfd_elf_sframe_present (info))
+    {
+      if (htab->plt_sframe != NULL
+         && htab->elf.splt != NULL
+         && htab->elf.splt->size != 0
+         && !bfd_is_abs_section (htab->elf.splt->output_section))
+       {
+         _bfd_x86_elf_create_sframe_plt (output_bfd, info, SFRAME_PLT);
+         /* FIXME - Dirty Hack.  Set the size to something non-zero for now,
+            so that the section does not get stripped out below.  The precise
+            size of this section is known only when the contents are
+            serialized in _bfd_x86_elf_write_sframe_plt.  */
+         htab->plt_sframe->size = sizeof (sframe_header) + 1;
+       }
+
+      /* FIXME - generate for .got.plt ?  */
+
+      /* Unwind info for the second PLT.  */
+      if (htab->plt_second_sframe != NULL
+         && htab->plt_second != NULL
+         && htab->plt_second->size != 0
+         && !bfd_is_abs_section (htab->plt_second->output_section))
+       {
+         _bfd_x86_elf_create_sframe_plt (output_bfd, info,
+                                         SFRAME_PLT_SEC);
+         /* FIXME - Dirty Hack.  Set the size to something non-zero for now,
+            so that the section does not get stripped out below.  The precise
+            size of this section is known only when the contents are
+            serialized in _bfd_x86_elf_write_sframe_plt.  */
+         htab->plt_second_sframe->size = sizeof (sframe_header) + 1;
+       }
+    }
+
   /* We now have determined the sizes of the various dynamic sections.
      Allocate memory for them.  */
   relocs = false;
@@ -2302,6 +2523,8 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
               || s == htab->plt_eh_frame
               || s == htab->plt_got_eh_frame
               || s == htab->plt_second_eh_frame
+              || s == htab->plt_sframe
+              || s == htab->plt_second_sframe
               || s == htab->elf.sdynbss
               || s == htab->elf.sdynrelro)
        {
@@ -2344,6 +2567,11 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
       if ((s->flags & SEC_HAS_CONTENTS) == 0)
        continue;
 
+      /* Skip allocating contents for .sframe section as it is written
+        out differently.  See below.  */
+      if ((s == htab->plt_sframe) || (s == htab->plt_second_sframe))
+       continue;
+
       /* NB: Initially, the iplt section has minimal alignment to
         avoid moving dot of the following section backwards when
         it is empty.  Update its section alignment now since it
@@ -2393,6 +2621,21 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
                   + PLT_FDE_LEN_OFFSET));
     }
 
+  if (_bfd_elf_sframe_present (info))
+    {
+      if (htab->plt_sframe != NULL
+         && htab->elf.splt != NULL
+         && htab->elf.splt->size != 0
+         && htab->plt_sframe->contents == NULL)
+       _bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT);
+
+      if (htab->plt_second_sframe != NULL
+         && htab->elf.splt != NULL
+         && htab->elf.splt->size != 0
+         && htab->plt_second_sframe->contents == NULL)
+       _bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT_SEC);
+    }
+
   return _bfd_elf_maybe_vxworks_add_dynamic_tags (output_bfd, info,
                                                  relocs);
 }
@@ -2607,6 +2850,74 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd,
        }
     }
 
+  /* Make any adjustment if necessary and merge .sframe section to
+     create the final .sframe section for output_bfd.  */
+  if (htab->plt_sframe != NULL
+      && htab->plt_sframe->contents != NULL)
+    {
+      if (htab->elf.splt != NULL
+         && htab->elf.splt->size != 0
+         && (htab->elf.splt->flags & SEC_EXCLUDE) == 0
+         && htab->elf.splt->output_section != NULL
+         && htab->plt_sframe->output_section != NULL)
+       {
+         bfd_vma plt_start = htab->elf.splt->output_section->vma;
+         bfd_vma sframe_start = htab->plt_sframe->output_section->vma
+                                  + htab->plt_sframe->output_offset
+                                  + PLT_SFRAME_FDE_START_OFFSET;
+#if 0 /* FIXME Testing only. Remove before review.  */
+         bfd_vma test_value = (plt_start - sframe_start)
+           + htab->plt_sframe->output_section->vma
+           + htab->plt_sframe->output_offset
+           + PLT_SFRAME_FDE_START_OFFSET;
+         bfd_put_signed_32 (dynobj, test_value,
+#endif
+         bfd_put_signed_32 (dynobj, plt_start - sframe_start,
+                            htab->plt_sframe->contents
+                            + PLT_SFRAME_FDE_START_OFFSET);
+       }
+      if (htab->plt_sframe->sec_info_type == SEC_INFO_TYPE_SFRAME)
+       {
+         if (! _bfd_elf_merge_section_sframe (output_bfd, info,
+                                              htab->plt_sframe,
+                                              htab->plt_sframe->contents))
+           return NULL;
+       }
+    }
+
+  if (htab->plt_second_sframe != NULL
+      && htab->plt_second_sframe->contents != NULL)
+    {
+      if (htab->plt_second != NULL
+         && htab->plt_second->size != 0
+         && (htab->plt_second->flags & SEC_EXCLUDE) == 0
+         && htab->plt_second->output_section != NULL
+         && htab->plt_second_sframe->output_section != NULL)
+       {
+         bfd_vma plt_start = htab->plt_second->output_section->vma;
+         bfd_vma sframe_start
+           = (htab->plt_second_sframe->output_section->vma
+              + htab->plt_second_sframe->output_offset
+              + PLT_SFRAME_FDE_START_OFFSET);
+#if 0 /* FIXME Testing only. Remove before review.  */
+         bfd_vma test_value = (plt_start - sframe_start)
+           + htab->plt_second_sframe->output_section->vma
+           + htab->plt_second_sframe->output_offset
+           + PLT_SFRAME_FDE_START_OFFSET;
+         bfd_put_signed_32 (dynobj, test_value,
+#endif
+         bfd_put_signed_32 (dynobj, plt_start - sframe_start,
+                            htab->plt_second_sframe->contents
+                            + PLT_SFRAME_FDE_START_OFFSET);
+       }
+      if (htab->plt_second_sframe->sec_info_type == SEC_INFO_TYPE_SFRAME)
+       {
+         if (! _bfd_elf_merge_section_sframe (output_bfd, info,
+                                              htab->plt_second_sframe,
+                                              htab->plt_second_sframe->contents))
+           return NULL;
+       }
+    }
   if (htab->elf.sgot && htab->elf.sgot->size > 0)
     elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize
       = htab->got_entry_size;
@@ -3949,12 +4260,36 @@ _bfd_x86_elf_link_setup_gnu_properties
 
   pltsec = htab->elf.splt;
 
-  /* If the non-lazy PLT is available, use it for all PLT entries if
-     there are no PLT0 or no .plt section.  */
   if (htab->non_lazy_plt != NULL
       && (!htab->plt.has_plt0 || pltsec == NULL))
+    lazy_plt = false;
+  else
+    lazy_plt = true;
+
+  if (normal_target)
+    {
+      if (use_ibt_plt)
+       {
+         if (lazy_plt)
+           htab->sframe_plt = init_table->sframe_lazy_ibt_plt;
+         else
+           htab->sframe_plt = init_table->sframe_non_lazy_ibt_plt;
+       }
+      else
+       {
+         if (lazy_plt)
+           htab->sframe_plt = init_table->sframe_lazy_plt;
+         else
+           htab->sframe_plt = init_table->sframe_non_lazy_plt;
+       }
+    }
+  else
+    htab->sframe_plt = NULL;
+
+  /* If the non-lazy PLT is available, use it for all PLT entries if
+     there are no PLT0 or no .plt section.  */
+  if (!lazy_plt)
     {
-      lazy_plt = false;
       if (bfd_link_pic (info))
        htab->plt.plt_entry = htab->non_lazy_plt->pic_plt_entry;
       else
@@ -3969,7 +4304,6 @@ _bfd_x86_elf_link_setup_gnu_properties
     }
   else
     {
-      lazy_plt = true;
       if (bfd_link_pic (info))
        {
          htab->plt.plt0_entry = htab->lazy_plt->pic_plt0_entry;
@@ -4145,6 +4479,39 @@ _bfd_x86_elf_link_setup_gnu_properties
              htab->plt_second_eh_frame = sec;
            }
        }
+
+      /* .sframe sections are emitted for AMD64 ABI only.  */
+      if (ABI_64_P (info->output_bfd) && !info->no_ld_generated_unwind_info)
+       {
+         flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+                           | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+                           | SEC_LINKER_CREATED);
+
+         sec = bfd_make_section_anyway_with_flags (dynobj,
+                                                   ".sframe",
+                                                   flags);
+         if (sec == NULL)
+           info->callbacks->einfo (_("%F%P: failed to create PLT .sframe section\n"));
+
+         // FIXME check this
+         // if (!bfd_set_section_alignment (sec, class_align))
+         //  goto error_alignment;
+
+         htab->plt_sframe = sec;
+
+         /* Second PLT is generated for Intel IBT / MPX Support + lazy plt.  */
+         if (htab->plt_second != NULL)
+           {
+             sec = bfd_make_section_anyway_with_flags (dynobj,
+                                                       ".sframe",
+                                                       flags);
+             if (sec == NULL)
+               info->callbacks->einfo (_("%F%P: failed to create second PLT .sframe section\n"));
+
+             htab->plt_second_sframe = sec;
+           }
+         /* FIXME - add later for plt_got. */
+       }
     }
 
   /* The .iplt section is used for IFUNC symbols in static
index 7d23893938c271326166d9cbcc793156d0fb508b..83f417acb0c72ff8f8e842d4305d3457c47db772 100644 (file)
@@ -30,6 +30,7 @@
 #include "elf-linker-x86.h"
 #include "elf/i386.h"
 #include "elf/x86-64.h"
+#include "sframe-api.h"
 
 #define X86_64_PCREL_TYPE_P(TYPE) \
   ((TYPE) == R_X86_64_PC8 \
    || (TYPE) == R_X86_64_PC32_BND \
    || (TYPE) == R_X86_64_PC64)
 
+/* This must be the same as sframe_get_hdr_size (sfh).  For x86-64, this value
+   is the same as sizeof (sframe_header) because there is no SFrame auxilliary
+   header.  */
+#define PLT_SFRAME_FDE_START_OFFSET    sizeof (sframe_header)
+
 #define ABI_64_P(abfd) \
   (get_elf_backend_data (abfd)->s->elfclass == ELFCLASS64)
 
@@ -388,6 +394,24 @@ struct elf_x86_link_hash_entry
   bfd_vma tlsdesc_got;
 };
 
+#define SFRAME_PLT0_MAX_NUM_FRES 2
+#define SFRAME_PLTN_MAX_NUM_FRES 2
+
+struct elf_x86_sframe_plt
+{
+  unsigned int plt0_entry_size;
+  unsigned int plt0_num_fres;
+  const sframe_frame_row_entry *plt0_fres[SFRAME_PLT0_MAX_NUM_FRES];
+
+  unsigned int pltn_entry_size;
+  unsigned int pltn_num_fres;
+  const sframe_frame_row_entry *pltn_fres[SFRAME_PLTN_MAX_NUM_FRES];
+
+  unsigned int sec_pltn_entry_size;
+  unsigned int sec_pltn_num_fres;
+  const sframe_frame_row_entry *sec_pltn_fres[SFRAME_PLTN_MAX_NUM_FRES];
+};
+
 struct elf_x86_lazy_plt_layout
 {
   /* The first entry in a lazy procedure linkage table looks like this.  */
@@ -584,6 +608,11 @@ struct elf_x86_link_hash_table
   asection *plt_got;
   asection *plt_got_eh_frame;
 
+  sframe_encoder_ctx *plt_cfe_ctx;
+  asection *plt_sframe;
+  sframe_encoder_ctx *plt_second_cfe_ctx;
+  asection *plt_second_sframe;
+
   /* Parameters describing PLT generation, lazy or non-lazy.  */
   struct elf_x86_plt_layout plt;
 
@@ -593,6 +622,10 @@ struct elf_x86_link_hash_table
   /* Parameters describing non-lazy PLT generation.  */
   const struct elf_x86_non_lazy_plt_layout *non_lazy_plt;
 
+  /* The .sframe helper object for .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_sframe_plt *sframe_plt;
+
   union
   {
     bfd_signed_vma refcount;
@@ -682,6 +715,22 @@ struct elf_x86_init_table
   /* The non-lazy PLT layout for IBT.  */
   const struct elf_x86_non_lazy_plt_layout *non_lazy_ibt_plt;
 
+  /* The .sframe helper object for lazy .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_sframe_plt *sframe_lazy_plt;
+
+  /* The .sframe helper object for non-lazy .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_sframe_plt *sframe_non_lazy_plt;
+
+  /* The .sframe helper object for lazy IBT .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_sframe_plt *sframe_lazy_ibt_plt;
+
+  /* The .sframe helper object for non-lazy IBT .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_sframe_plt *sframe_non_lazy_ibt_plt;
+
   bfd_byte plt0_pad_byte;
 
   bfd_vma (*r_info) (bfd_vma, bfd_vma);
index 48505f373e23d81b60a9535700405a002a4b8a7a..f73e0345e1582cfd487bf87d3de15fffa8bf78cc 100644 (file)
@@ -409,6 +409,7 @@ CODE_FRAGMENT
 .#define SEC_INFO_TYPE_JUST_SYMS 4
 .#define SEC_INFO_TYPE_TARGET    5
 .#define SEC_INFO_TYPE_EH_FRAME_ENTRY 6
+.#define SEC_INFO_TYPE_SFRAME  7
 .
 .  {* Nonzero if this section uses RELA relocations, rather than REL.  *}
 .  unsigned int use_rela_p:1;
index c8323539a21f3d3ba757e364c06c3dc0e6e7fade..f82c3a973f23dc39417540920a3ec9d2bdb0b8a0 100644 (file)
@@ -4604,6 +4604,7 @@ get_segment_type (Filedata * filedata, unsigned long p_type)
     case PT_GNU_STACK: return "GNU_STACK";
     case PT_GNU_RELRO:  return "GNU_RELRO";
     case PT_GNU_PROPERTY: return "GNU_PROPERTY";
+    case PT_GNU_SFRAME: return "GNU_SFRAME";
 
     case PT_OPENBSD_RANDOMIZE: return "OPENBSD_RANDOMIZE";
     case PT_OPENBSD_WXNEEDED: return "OPENBSD_WXNEEDED";
index 287526d74ede1ed2a36236549c2444188184089d..16587f6fb063cd7219f6a1cc670325dd7bf5bae5 100644 (file)
 #define PT_GNU_STACK   (PT_LOOS + 0x474e551) /* Stack flags */
 #define PT_GNU_RELRO   (PT_LOOS + 0x474e552) /* Read-only after relocation */
 #define PT_GNU_PROPERTY        (PT_LOOS + 0x474e553) /* GNU property */
+#define PT_GNU_SFRAME  (PT_LOOS + 0x474e554) /* SFrame unwind information */
 
 /* OpenBSD segment types.  */
 #define PT_OPENBSD_RANDOMIZE (PT_LOOS + 0x5a3dbe6)  /* Fill with random data.  */
index 8affb3d9b2e3a9cff50e650b9e964c54fbdc6817..de9f67809b374b5646b4f95ce0883cd4a44425d1 100644 (file)
@@ -339,6 +339,7 @@ struct elf_segment_map
            || (segment)->p_type == PT_GNU_EH_FRAME                     \
            || (segment)->p_type == PT_GNU_STACK                        \
            || (segment)->p_type == PT_GNU_RELRO                        \
+           || (segment)->p_type == PT_GNU_SFRAME                       \
            || ((segment)->p_type >= PT_GNU_MBIND_LO                    \
                && (segment)->p_type <= PT_GNU_MBIND_HI)))              \
    /* Any section besides one of type SHT_NOBITS must have file                \
index f0924dc91e36a7f8008838494d3b41085306c957..010a35a1674ab0b330cde15347c3860dc03c8166 100644 (file)
@@ -187,7 +187,7 @@ sframe_encode (unsigned char ver, unsigned char flags, int abi,
 
 /* Free the encoder context.  */
 extern void
-sframe_free_encoder (sframe_encoder_ctx *encoder);
+sframe_encoder_free (sframe_encoder_ctx **encoder);
 
 /* Get the size of the SFrame header from the encoder ctx ENCODER.  */
 extern unsigned int
index 66e9094e86afbaf6c26980a4875da3748a598c2b..65fef4e16903b30d2f1ce5869725e3f24db41d94 100644 (file)
@@ -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); \
index 5e4787f89b42198ff665bd596942d68337dfd18a..ff4c916c27ba8c86434c4dfeea914956b64b1f75 100644 (file)
@@ -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); \
index 79000452c959c55774c236ab238c92db1b0445aa..a4d30abfb1ca3afe55a3028aed037806b238b4c8 100755 (executable)
@@ -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" ;;
index 6123ea786112a0d5ce5d0ced44a613a28a8e5648..1ee40a51b08e5764c67d9fccbc1454d9759b2101 100644 (file)
@@ -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
index 82527e3652cae9503b1a6a94ded261ba133922b1..3836465730cf4a31123b72d7d4960491e5dafcfe 100644 (file)
@@ -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
index bf2268bb0ad96f30cc1f8c514b6895c272df726c..5cc364b0c2a78ce0dc8db45f17afb6c8b386d2cd 100644 (file)
@@ -601,6 +601,7 @@ cat <<EOF
   ${OTHER_READONLY_SECTIONS}
   .eh_frame_hdr ${RELOCATING-0} : { *(.eh_frame_hdr)${RELOCATING+ *(.eh_frame_entry .eh_frame_entry.*)} }
   .eh_frame     ${RELOCATING-0} : ONLY_IF_RO { KEEP (*(.eh_frame))${RELOCATING+ *(.eh_frame.*)} }
+  .sframe       ${RELOCATING-0} : ONLY_IF_RO { *(.sframe)${RELOCATING+ *(.sframe.*)} }
   .gcc_except_table ${RELOCATING-0} : ONLY_IF_RO { *(.gcc_except_table${RELOCATING+ .gcc_except_table.*}) }
   .gnu_extab ${RELOCATING-0} : ONLY_IF_RO { *(.gnu_extab*) }
   /* These sections are generated by the Sun/Oracle C++ compiler.  */
@@ -619,6 +620,7 @@ cat <<EOF
 
   /* Exception handling  */
   .eh_frame     ${RELOCATING-0} : ONLY_IF_RW { KEEP (*(.eh_frame))${RELOCATING+ *(.eh_frame.*)} }
+  .sframe       ${RELOCATING-0} : ONLY_IF_RW { *(.sframe)${RELOCATING+ *(.sframe.*)} }
   .gnu_extab    ${RELOCATING-0} : ONLY_IF_RW { *(.gnu_extab) }
   .gcc_except_table ${RELOCATING-0} : ONLY_IF_RW { *(.gcc_except_table${RELOCATING+ .gcc_except_table.*}) }
   .exception_ranges ${RELOCATING-0} : ONLY_IF_RW { *(.exception_ranges${RELOCATING+*}) }
index 337beadcbfe5d7ea54a7bba45017b10bb1604cb0..0a732b55860a1c61476fe649c3beda9b347f5a8f 100644 (file)
@@ -457,3 +457,7 @@ run_dump_test "bti-pac-plt-2"
 run_dump_test "bti-warn"
 run_dump_test "weak-tls"
 run_dump_test "undef-tls"
+
+if { ![skip_sframe_tests] } {
+  run_dump_test "sframe-simple-1"
+}
diff --git a/ld/testsuite/ld-aarch64/sframe-bar.s b/ld/testsuite/ld-aarch64/sframe-bar.s
new file mode 100644 (file)
index 0000000..8dd50bf
--- /dev/null
@@ -0,0 +1,7 @@
+       .cfi_startproc
+       cmp     w0, 1000
+       bgt     .L4
+       ret
+.L4:
+       b       foo
+       .cfi_endproc
diff --git a/ld/testsuite/ld-aarch64/sframe-foo.s b/ld/testsuite/ld-aarch64/sframe-foo.s
new file mode 100644 (file)
index 0000000..a2780a6
--- /dev/null
@@ -0,0 +1,10 @@
+       .cfi_startproc
+       mov     w1, 26215
+       movk    w1, 0x6666, lsl 16
+       smull   x1, w0, w1
+       asr     x1, x1, 34
+       sub     w1, w1, w0, asr 31
+       add     w1, w1, w1, lsl 2
+       sub     w0, w0, w1, lsl 1
+       ret
+       .cfi_endproc
diff --git a/ld/testsuite/ld-aarch64/sframe-simple-1.d b/ld/testsuite/ld-aarch64/sframe-simple-1.d
new file mode 100644 (file)
index 0000000..6f61715
--- /dev/null
@@ -0,0 +1,26 @@
+#as: --gsframe
+#source: sframe-foo.s
+#source: sframe-bar.s
+#objdump: --sframe=.sframe
+#ld: -shared
+#name: SFrame Simple link
+
+.*:     file format .*
+
+Contents of the SFrame section .sframe:
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: SFRAME_F_FDE_SORTED
+    Num FDEs: 2
+    Num FREs: 2
+
+  Function Index :
+
+#...
+    STARTPC +CFA +FP +RA +
+    0+[0-9a-f]+ +sp\+0 +u +u +
+
+#...
+    STARTPC +CFA +FP +RA +
+    0+[0-9a-f]+ +sp\+0 +u +u +
index 99a11090ee766456b343066a9255f8c1953ef967..de82a2bfbfff7555cd75fe2226c7fbc5c801b328 100644 (file)
@@ -184,7 +184,7 @@ foreach flags $test_flags {
        setup_xfail "mips*-*-irix5*"
     }
 
-    if ![ld_link $CC tmpdir/ld1 "$CFLAGS $flags tmpdir/ld-partial.o $CTFLIB $BFDLIB $LIBIBERTY $extralibs"] {
+    if ![ld_link $CC tmpdir/ld1 "$CFLAGS $flags tmpdir/ld-partial.o $CTFLIB $BFDLIB $LIBIBERTY $SFRAMELIB $extralibs"] {
        fail $testname
        continue
     }
@@ -201,13 +201,13 @@ foreach flags $test_flags {
     }
 
     regsub /tmpdir/ld/ $gcc_B_opt_save /tmpdir/gccld1/ gcc_B_opt
-    if ![ld_link $CC tmpdir/ld2 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $extralibs"] {
+    if ![ld_link $CC tmpdir/ld2 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $SFRAMELIB $extralibs"] {
        fail $testname
        continue
     }
 
     regsub /tmpdir/ld/ $gcc_B_opt_save /tmpdir/gccld2/ gcc_B_opt
-    if ![ld_link $CC tmpdir/ld3 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $extralibs"] {
+    if ![ld_link $CC tmpdir/ld3 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $SFRAMELIB $extralibs"] {
        fail $testname
        continue
     }
@@ -220,7 +220,7 @@ foreach flags $test_flags {
        # generated by different linkers, tmpdir/ld1 and tmpdir/ld2.
        # So we rebuild tmpdir/ld2 with tmpdir/ld3.
        regsub /tmpdir/ld/ $gcc_B_opt_save /tmpdir/gccld3/ gcc_B_opt
-       if ![ld_link $CC tmpdir/ld2 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $extralibs"] {
+       if ![ld_link $CC tmpdir/ld2 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $SFRAMELIB $extralibs"] {
            fail $testname
            continue
        }
diff --git a/ld/testsuite/ld-sframe/discard.d b/ld/testsuite/ld-sframe/discard.d
new file mode 100644 (file)
index 0000000..cb0371e
--- /dev/null
@@ -0,0 +1,10 @@
+#as:
+#source: discard.s
+#ld: -T discard.ld
+#objdump: -hw
+#name: Check that SFrame section can be discarded
+
+#failif
+#...
+  [0-9] .sframe .*
+#...
diff --git a/ld/testsuite/ld-sframe/discard.ld b/ld/testsuite/ld-sframe/discard.ld
new file mode 100644 (file)
index 0000000..5745cce
--- /dev/null
@@ -0,0 +1,9 @@
+ENTRY(_start)
+SECTIONS
+{
+  . = SIZEOF_HEADERS;
+  /* Sections to be discarded */
+  /DISCARD/ : {
+       *(.sframe)
+       }
+}
diff --git a/ld/testsuite/ld-sframe/discard.s b/ld/testsuite/ld-sframe/discard.s
new file mode 100644 (file)
index 0000000..a438b42
--- /dev/null
@@ -0,0 +1,13 @@
+       .text
+       .cfi_sections .sframe
+       .globl  foo
+       .type   foo, @function
+foo:
+       .cfi_startproc
+       .cfi_def_cfa_offset 16
+       .cfi_def_cfa 7, 8
+       .cfi_endproc
+
+       .globl _start
+_start:
+       .long   foo
diff --git a/ld/testsuite/ld-sframe/sframe-empty.d b/ld/testsuite/ld-sframe/sframe-empty.d
new file mode 100644 (file)
index 0000000..bad08c5
--- /dev/null
@@ -0,0 +1,10 @@
+#as:
+#source: sframe-empty.s
+#objdump: -hw
+#ld: -shared
+#name: Empty SFrame section
+
+#failif
+#...
+  [0-9] .sframe .*
+#...
diff --git a/ld/testsuite/ld-sframe/sframe-empty.s b/ld/testsuite/ld-sframe/sframe-empty.s
new file mode 100644 (file)
index 0000000..659b3b9
--- /dev/null
@@ -0,0 +1,2 @@
+       .cfi_startproc
+       .cfi_endproc
diff --git a/ld/testsuite/ld-sframe/sframe.exp b/ld/testsuite/ld-sframe/sframe.exp
new file mode 100644 (file)
index 0000000..392dfbd
--- /dev/null
@@ -0,0 +1,47 @@
+# Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+if [skip_sframe_tests] {
+    unsupported "no SFrame format support in the assembler, or SFrame disabled"
+    return 0
+}
+
+if ![is_elf_format] {
+    unsupported "SFrame not supported"
+    return 0
+}
+
+if {[info exists env(LC_ALL)]} {
+    set old_lc_all $env(LC_ALL)
+}
+set env(LC_ALL) "C"
+
+set sframe_test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
+
+foreach sframe_test $sframe_test_list {
+    verbose [file rootname $sframe_test]
+    run_dump_test [file rootname $sframe_test]
+}
+
+if {[info exists old_lc_all]} {
+    set env(LC_ALL) $old_lc_all
+} else {
+    unset env(LC_ALL)
+}
diff --git a/ld/testsuite/ld-x86-64/sframe-bar.s b/ld/testsuite/ld-x86-64/sframe-bar.s
new file mode 100644 (file)
index 0000000..4d03213
--- /dev/null
@@ -0,0 +1,31 @@
+       .file   "sframe-bar.c"
+       .text
+       .globl  bar
+       .type   bar, @function
+bar:
+.LFB0:
+       .cfi_startproc
+       pushq   %rbp
+       .cfi_def_cfa_offset 16
+       .cfi_offset 6, -16
+       movq    %rsp, %rbp
+       .cfi_def_cfa_register 6
+       subq    $16, %rsp
+       movl    %edi, -4(%rbp)
+       cmpl    $1000, -4(%rbp)
+       jle     .L2
+       movl    -4(%rbp), %eax
+       movl    %eax, %edi
+       call    foo
+       jmp     .L3
+.L2:
+       movl    -4(%rbp), %eax
+.L3:
+       leave
+       .cfi_def_cfa 7, 8
+       ret
+       .cfi_endproc
+.LFE0:
+       .size   bar, .-bar
+       .ident  "GCC: (GNU) 13.0.0 20220519 (experimental)"
+       .section        .note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/sframe-foo.s b/ld/testsuite/ld-x86-64/sframe-foo.s
new file mode 100644 (file)
index 0000000..a871908
--- /dev/null
@@ -0,0 +1,37 @@
+       .file   "sframe-foo.c"
+       .text
+       .globl  foo
+       .type   foo, @function
+foo:
+.LFB0:
+       .cfi_startproc
+       pushq   %rbp
+       .cfi_def_cfa_offset 16
+       .cfi_offset 6, -16
+       movq    %rsp, %rbp
+       .cfi_def_cfa_register 6
+       movl    %edi, -4(%rbp)
+       movl    -4(%rbp), %ecx
+       movslq  %ecx, %rax
+       imulq   $1717986919, %rax, %rax
+       shrq    $32, %rax
+       movl    %eax, %edx
+       sarl    $2, %edx
+       movl    %ecx, %eax
+       sarl    $31, %eax
+       subl    %eax, %edx
+       movl    %edx, %eax
+       sall    $2, %eax
+       addl    %edx, %eax
+       addl    %eax, %eax
+       subl    %eax, %ecx
+       movl    %ecx, %edx
+       movl    %edx, %eax
+       popq    %rbp
+       .cfi_def_cfa 7, 8
+       ret
+       .cfi_endproc
+.LFE0:
+       .size   foo, .-foo
+       .ident  "GCC: (GNU) 13.0.0 20220519 (experimental)"
+       .section        .note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/sframe-plt-1.d b/ld/testsuite/ld-x86-64/sframe-plt-1.d
new file mode 100644 (file)
index 0000000..06bb16b
--- /dev/null
@@ -0,0 +1,29 @@
+#as: --gsframe
+#source: sframe-foo.s
+#source: sframe-bar.s
+#objdump: --sframe=.sframe
+#ld: -shared
+#name: SFrame for plt0 and pltN
+
+.*: +file format .*
+
+Contents of the SFrame section .sframe:
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: SFRAME_F_FDE_SORTED
+#...
+
+  Function Index :
+
+    func idx \[0\]: pc = 0x1000, size = 16 bytes
+    STARTPC +CFA +FP +RA +
+    0+1000 +sp\+16 +u +u +
+    0+1006 +sp\+24 +u +u +
+
+    func idx \[1\]: pc = 0x1010, size = 16 bytes
+    STARTPC\[m\] +CFA +FP +RA +
+    0+0000 +sp\+8 +u +u +
+    0+000b +sp\+16 +u +u +
+
+#...
diff --git a/ld/testsuite/ld-x86-64/sframe-simple-1.d b/ld/testsuite/ld-x86-64/sframe-simple-1.d
new file mode 100644 (file)
index 0000000..afc0006
--- /dev/null
@@ -0,0 +1,35 @@
+#as: --gsframe
+#source: sframe-foo.s
+#source: sframe-bar.s
+#objdump: --sframe=.sframe
+#ld: -shared
+#name: SFrame Simple link
+
+.*: +file format .*
+
+Contents of the SFrame section .sframe:
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: SFRAME_F_FDE_SORTED
+#...
+
+  Function Index :
+
+#...
+
+#...
+
+    func idx \[2\]: pc = 0x1020, size = 53 bytes
+    STARTPC +CFA +FP +RA +
+    0+1020 +sp\+8 +u +u +
+    0+1021 +sp\+16 +c-16 +u +
+    0+1024 +fp\+16 +c-16 +u +
+    0+1054 +sp\+8 +c-16 +u +
+
+    func idx \[3\]: pc = 0x1055, size = 37 bytes
+    STARTPC +CFA +FP +RA +
+    0+1055 +sp\+8 +u +u +
+    0+1056 +sp\+16 +c-16 +u +
+    0+1059 +fp\+16 +c-16 +u +
+    0+1079 +sp\+8 +c-16 +u +
index e6a834a2a61b0a63789e260ce56d10c177aa7ba9..1782e8e5defa2f0a47f79fdd821b434b6671612b 100644 (file)
@@ -506,6 +506,11 @@ run_dump_test "dt-relr-1a-x32"
 run_dump_test "dt-relr-1b"
 run_dump_test "dt-relr-1b-x32"
 
+if { ![skip_sframe_tests] } {
+    run_dump_test "sframe-simple-1"
+    run_dump_test "sframe-plt-1"
+}
+
 if ![istarget "x86_64-*-linux*"] {
     return
 }
index 2cd840c016938c88be3d87c6bf1cd908ed9c7681..47d14941d2a012124ad94d873034e151b2fdcad7 100644 (file)
@@ -1690,3 +1690,48 @@ proc skip_ctf_tests { } {
 
     return 1
 }
+
+# Check if the assembler supports SFrame.
+
+proc check_as_sframe { } {
+    global check_as_sframe_result
+    global as
+    if [info exists check_as_sframe_result] {
+       return $check_as_sframe_result
+    }
+
+    # SFrame generation needs CFI support
+    if { ![check_as_cfi] } {
+       set check_as_sframe_result 0;
+       return 0
+    }
+
+    set as_file "tmpdir/check_as_sframe.s"
+    set as_fh [open $as_file w 0666]
+    puts $as_fh "# Generated file. DO NOT EDIT"
+    puts $as_fh "\t.cfi_sections \".sframe\""
+    puts $as_fh "\t.cfi_startproc"
+    puts $as_fh "\t.cfi_endproc"
+    close $as_fh
+    remote_download host $as_file
+    verbose -log "Checking SFrame:"
+    set success [ld_assemble $as $as_file "/dev/null"]
+    #remote_file host delete $as_file
+    set check_as_sframe_result $success
+    return $success
+}
+
+proc skip_sframe_tests { } {
+# FIXME TODO
+#    global enable_libsframe
+#
+#    if {$enable_libsframe eq "no"} {
+#      return 1
+#    }
+
+    if [check_as_sframe] {
+       return 0
+    }
+
+    return 1
+}
index 9059d9562b65c0ee12582c9b72ee50139017f892..fce821e44142e8dc943d0f13bcf70f3f5e7e3175 100644 (file)
@@ -1202,14 +1202,32 @@ sframe_encode (unsigned char ver, unsigned char flags, int abi_arch,
 /* Free the encoder context.  */
 
 void
-sframe_free_encoder (sframe_encoder_ctx *encoder)
+sframe_encoder_free (sframe_encoder_ctx **encoder)
 {
   if (encoder != NULL)
     {
-      free (encoder->sfe_funcdesc);
-      free (encoder->sfe_fres);
-      free (encoder->sfe_data);
-      free (encoder);
+      sframe_encoder_ctx *ectx = *encoder;
+      if (ectx == NULL)
+       return;
+
+      if (ectx->sfe_funcdesc != NULL)
+       {
+         free (ectx->sfe_funcdesc);
+         ectx->sfe_funcdesc = NULL;
+       }
+      if (ectx->sfe_fres != NULL)
+       {
+         free (ectx->sfe_fres);
+         ectx->sfe_fres = NULL;
+       }
+      if (ectx->sfe_data != NULL)
+       {
+         free (ectx->sfe_data);
+         ectx->sfe_data = NULL;
+       }
+
+      free (*encoder);
+      *encoder = NULL;
     }
 }