aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.def4
-rw-r--r--Makefile.in11
-rw-r--r--bfd/Makefile.am6
-rw-r--r--bfd/Makefile.in7
-rw-r--r--bfd/bfd-in2.h1
-rwxr-xr-xbfd/configure2
-rw-r--r--bfd/configure.ac2
-rw-r--r--bfd/elf-bfd.h54
-rw-r--r--bfd/elf-sframe.c544
-rw-r--r--bfd/elf.c32
-rw-r--r--bfd/elf64-x86-64.c97
-rw-r--r--bfd/elflink.c52
-rw-r--r--bfd/elfxx-x86.c375
-rw-r--r--bfd/elfxx-x86.h49
-rw-r--r--bfd/section.c1
-rw-r--r--binutils/readelf.c1
-rw-r--r--include/elf/common.h1
-rw-r--r--include/elf/internal.h1
-rw-r--r--include/sframe-api.h2
-rw-r--r--ld/Makefile.am2
-rw-r--r--ld/Makefile.in2
-rwxr-xr-xld/configure8
-rw-r--r--ld/configure.ac3
-rw-r--r--ld/ld.texi4
-rw-r--r--ld/scripttempl/elf.sc2
-rw-r--r--ld/testsuite/ld-aarch64/aarch64-elf.exp4
-rw-r--r--ld/testsuite/ld-aarch64/sframe-bar.s7
-rw-r--r--ld/testsuite/ld-aarch64/sframe-foo.s10
-rw-r--r--ld/testsuite/ld-aarch64/sframe-simple-1.d26
-rw-r--r--ld/testsuite/ld-bootstrap/bootstrap.exp8
-rw-r--r--ld/testsuite/ld-sframe/discard.d10
-rw-r--r--ld/testsuite/ld-sframe/discard.ld9
-rw-r--r--ld/testsuite/ld-sframe/discard.s13
-rw-r--r--ld/testsuite/ld-sframe/sframe-empty.d10
-rw-r--r--ld/testsuite/ld-sframe/sframe-empty.s2
-rw-r--r--ld/testsuite/ld-sframe/sframe.exp47
-rw-r--r--ld/testsuite/ld-x86-64/sframe-bar.s31
-rw-r--r--ld/testsuite/ld-x86-64/sframe-foo.s37
-rw-r--r--ld/testsuite/ld-x86-64/sframe-plt-1.d29
-rw-r--r--ld/testsuite/ld-x86-64/sframe-simple-1.d35
-rw-r--r--ld/testsuite/ld-x86-64/x86-64.exp5
-rw-r--r--ld/testsuite/lib/ld-lib.exp45
-rw-r--r--libsframe/sframe.c28
43 files changed, 1595 insertions, 24 deletions
diff --git a/Makefile.def b/Makefile.def
index 1b39c91..f974565 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -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; };
diff --git a/Makefile.in b/Makefile.in
index b26f778..a425b54 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -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
diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 9331377..a88c6a0 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -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
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index 85cae1f..d5cc5cb 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -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@
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index e09259b..0b071dd 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -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;
diff --git a/bfd/configure b/bfd/configure
index 5c6e382..74bc5a1 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -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"
diff --git a/bfd/configure.ac b/bfd/configure.ac
index 74c0f07..5d450a4 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -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"
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index fa4b9bc..fc32fbe 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -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
index 0000000..8055aa3
--- /dev/null
+++ b/bfd/elf-sframe.c
@@ -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;
+}
diff --git a/bfd/elf.c b/bfd/elf.c
index 81825b7..87ec162 100644
--- 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);
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 2ae8dff..fb87279 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -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)
{
@@ -5230,6 +5311,20 @@ elf_x86_64_link_setup_gnu_properties (struct bfd_link_info *info)
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;
init_table.r_sym = elf64_r_sym;
}
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 4ef0739..20cee4c 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -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;
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 7fb9727..c48d038 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -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
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index 7d23893..83f417a 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -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 \
@@ -105,6 +106,11 @@
|| (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);
diff --git a/bfd/section.c b/bfd/section.c
index 48505f3..f73e034 100644
--- a/bfd/section.c
+++ b/bfd/section.c
@@ -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;
diff --git a/binutils/readelf.c b/binutils/readelf.c
index c832353..f82c3a9 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -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";
diff --git a/include/elf/common.h b/include/elf/common.h
index 287526d..16587f6 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -489,6 +489,7 @@
#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. */
diff --git a/include/elf/internal.h b/include/elf/internal.h
index 8affb3d..de9f678 100644
--- a/include/elf/internal.h
+++ b/include/elf/internal.h
@@ -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 \
diff --git a/include/sframe-api.h b/include/sframe-api.h
index f0924dc..010a35a 100644
--- a/include/sframe-api.h
+++ b/include/sframe-api.h
@@ -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
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 <<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+*}) }
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index 337bead..0a732b5 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -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
index 0000000..8dd50bf
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/sframe-bar.s
@@ -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
index 0000000..a2780a6
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/sframe-foo.s
@@ -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
index 0000000..6f61715
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/sframe-simple-1.d
@@ -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 +
diff --git a/ld/testsuite/ld-bootstrap/bootstrap.exp b/ld/testsuite/ld-bootstrap/bootstrap.exp
index 99a1109..de82a2b 100644
--- a/ld/testsuite/ld-bootstrap/bootstrap.exp
+++ b/ld/testsuite/ld-bootstrap/bootstrap.exp
@@ -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
index 0000000..cb0371e
--- /dev/null
+++ b/ld/testsuite/ld-sframe/discard.d
@@ -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
index 0000000..5745cce
--- /dev/null
+++ b/ld/testsuite/ld-sframe/discard.ld
@@ -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
index 0000000..a438b42
--- /dev/null
+++ b/ld/testsuite/ld-sframe/discard.s
@@ -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
index 0000000..bad08c5
--- /dev/null
+++ b/ld/testsuite/ld-sframe/sframe-empty.d
@@ -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
index 0000000..659b3b9
--- /dev/null
+++ b/ld/testsuite/ld-sframe/sframe-empty.s
@@ -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
index 0000000..392dfbd
--- /dev/null
+++ b/ld/testsuite/ld-sframe/sframe.exp
@@ -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
index 0000000..4d03213
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/sframe-bar.s
@@ -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
index 0000000..a871908
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/sframe-foo.s
@@ -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
index 0000000..06bb16b
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/sframe-plt-1.d
@@ -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
index 0000000..afc0006
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/sframe-simple-1.d
@@ -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 +
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index e6a834a..1782e8e 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -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
}
diff --git a/ld/testsuite/lib/ld-lib.exp b/ld/testsuite/lib/ld-lib.exp
index 2cd840c..47d1494 100644
--- a/ld/testsuite/lib/ld-lib.exp
+++ b/ld/testsuite/lib/ld-lib.exp
@@ -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
+}
diff --git a/libsframe/sframe.c b/libsframe/sframe.c
index 9059d95..fce821e 100644
--- a/libsframe/sframe.c
+++ b/libsframe/sframe.c
@@ -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;
}
}