aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
Diffstat (limited to 'bfd')
-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
13 files changed, 1211 insertions, 11 deletions
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;