diff options
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; +} @@ -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 @@ -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; } } |