]> git.feebdaed.xyz Git - 0xmirror/binutils-gdb.git/commitdiff
bfd: include: sframe: fix PR ld/32789
authorIndu Bhagat <indu.bhagat@oracle.com>
Sat, 20 Dec 2025 07:11:45 +0000 (23:11 -0800)
committerIndu Bhagat <indu.bhagat@oracle.com>
Sat, 20 Dec 2025 07:11:45 +0000 (23:11 -0800)
Currently, when SFrame sections are emitted after linking the input
SFrame sections, the SFrame FDEs are sorted on start PC.  Doing so for
relocatable links has no effect (SFrame FDEs remain in place), because
the start PC is unrelocated data.  For relocatable links, then, the
emitted SFrame FDEs in the output section remain in the same order as
that in the respective input BFD.

The assembler does not guarantee the emission of SFrame FDEs in the same
order as the placement of the associated .text* sections,
(SFRAME_F_FDE_SORTED is not set in the ET_REL objs generated by GAS).
This means setting SFRAME_F_FDE_SORTED by the linker was wrong when:
  - doing relocatable link, and
  - the input bfds contain multiple .text sections, say .text.hot,
    .text.init, .text.unlikely etc.

For relocatable links, skip sorting the SFrame FDEs.  Do not set
SFRAME_F_FDE_SORTED for relocatable links.

This is achieved by adding an explicit argument (bool sort_fde_p) to the
sframe_encoder_write API.  Move the API from 2.0 to the 2.1 node as this
is an ABI-incompatible change.  Skip bumping the "current" in
libsframe/libtool-version ATM, we will do so closer to release.

When writing of SFrame data for PLT entries, indicate sort_fde_p to
false: these sections are like the other SFrame sections for any other
ET_REL binary.

Add a test in ld/testsuite/ld-sframe/sframe.exp, these tests are run for
all ABIs supported for SFrame.  In this test, for object file generated
for pr32789-1a.c:
  - the emitted SFrame FDEs by GAS are in the order of the .text* in the
    input assembly (i.e., .text.init, .text, .text.exit)
  - the emitted .text* sections by GAS are placed in the following order
    .text, .text.init, .text.exit.
  - GAS does not set SFRAME_F_FDE_SORTED, as expected.

Reviewed-by: Jens Remus <jremus@linux.ibm.com>
bfd/
PR ld/32789
* elf-sframe.c (_bfd_elf_write_section_sframe): Skip sorting the
SFrame FDEs for relocatable links.
* elf64-s390.c (_bfd_s390_elf_write_sframe_plt): Additional
argument to sframe_encoder_write.
* elfxx-x86.c (_bfd_x86_elf_write_sframe_plt): Likewise.
libsframe/
* libsframe.ver: Move from 2.0 node to 2.1.
* sframe.c (sframe_encoder_write_sframe): Conditionalize based
on argument sort_fde_p.
(sframe_encoder_write): New argument to indicate whether SFrame
FDEs are to be sorted in output.
include/
* sframe-api.h (sframe_encoder_write): New argument.
ld/testsuite/
PR ld/32789
* ld/testsuite/ld-sframe/sframe.exp: New test.
* ld/testsuite/ld-sframe/pr32789-1.rd: New test.
* ld/testsuite/ld-sframe/pr32789-1.sd: New test.
* ld/testsuite/ld-sframe/pr32789-1a.c: New test.
* ld/testsuite/ld-sframe/pr32789-1b.c: New test.
* ld/testsuite/ld-x86-64/sframe-reloc-1.d: Remove
SFRAME_F_FDE_SORTED.

12 files changed:
bfd/elf-sframe.c
bfd/elf64-s390.c
bfd/elfxx-x86.c
include/sframe-api.h
ld/testsuite/ld-sframe/pr32789-1.rd [new file with mode: 0644]
ld/testsuite/ld-sframe/pr32789-1.sd [new file with mode: 0644]
ld/testsuite/ld-sframe/pr32789-1a.c [new file with mode: 0644]
ld/testsuite/ld-sframe/pr32789-1b.c [new file with mode: 0644]
ld/testsuite/ld-sframe/sframe.exp
ld/testsuite/ld-x86-64/sframe-reloc-1.d
libsframe/libsframe.ver
libsframe/sframe.c

index 80043550777ff7c7c872f87cf04ccedbfc72492b..f34d58f3f5a6c1196eb11b2d939b38fdfd79a38f 100644 (file)
@@ -692,7 +692,8 @@ _bfd_elf_write_section_sframe (bfd *abfd, struct bfd_link_info *info)
   if (sec == NULL)
     return true;
 
-  contents = sframe_encoder_write (sfe_ctx, &sec_size, &err);
+  bool sort_p = !bfd_link_relocatable (info);
+  contents = sframe_encoder_write (sfe_ctx, &sec_size, sort_p, &err);
   sec->size = (bfd_size_type) sec_size;
 
   if (!bfd_set_section_contents (abfd, sec->output_section, contents,
index 182a1119cdd2390787e4087de589f32604829278..fe07e486795ef0ce79e24150a8138894baeeb5f4 100644 (file)
@@ -1682,7 +1682,7 @@ _bfd_s390_elf_write_sframe_plt (struct bfd_link_info *info)
 
   BFD_ASSERT (ectx);
 
-  void *contents = sframe_encoder_write (ectx, &sec_size, &err);
+  void *contents = sframe_encoder_write (ectx, &sec_size, false, &err);
 
   sec->size = (bfd_size_type) sec_size;
   sec->contents = (unsigned char *) bfd_zalloc (dynobj, sec->size);
index 6400d3e6473aacf0a61d2c846d8febd63a5a91d9..14bbcc2644890e79cae8ba8f40cff3029eefbe7d 100644 (file)
@@ -2016,7 +2016,7 @@ _bfd_x86_elf_write_sframe_plt (bfd *output_bfd,
 
   BFD_ASSERT (ectx);
 
-  void *contents = sframe_encoder_write (ectx, &sec_size, &err);
+  void *contents = sframe_encoder_write (ectx, &sec_size, false, &err);
 
   sec->size = (bfd_size_type) sec_size;
   sec->contents = (unsigned char *) bfd_zalloc (dynobj, sec->size);
index 79a748f9e3b803b350228c18ad0cbd0f99345a07..7e37e6af84d7743ca83a128406e3df9c0eb70cee 100644 (file)
@@ -309,11 +309,11 @@ sframe_encoder_add_funcdesc_v2 (sframe_encoder_ctx *ectx,
                                uint32_t num_fres);
 
 /* Serialize the contents of the encoder context ECTX and return the buffer.
-   ENCODED_SIZE is updated to the size of the buffer.
-   Sets ERRP if failure.  */
+   Sort the SFrame FDEs on start PC if SORT_FDE_P is true.  ENCODED_SIZE is
+   updated to the size of the buffer.  Sets ERRP if failure.  */
 extern char  *
-sframe_encoder_write (sframe_encoder_ctx *ectx,
-                     size_t *encoded_size, int *errp);
+sframe_encoder_write (sframe_encoder_ctx *ectx, size_t *encoded_size,
+                     bool sort_fde_p, int *errp);
 
 #ifdef __cplusplus
 }
diff --git a/ld/testsuite/ld-sframe/pr32789-1.rd b/ld/testsuite/ld-sframe/pr32789-1.rd
new file mode 100644 (file)
index 0000000..6fe8f7d
--- /dev/null
@@ -0,0 +1,9 @@
+#...
+Relocation section '.rela.sframe' at offset 0x[0-9a-f]+ contains 5 entries:
+ +Offset +Info +Type +Sym.* Value +Sym.* Name \+ Addend
+[0-9a-f ]+ R_.* +0+ .text.init \+ 0
+[0-9a-f ]+ R_.* +0+ .text \+ 0
+[0-9a-f ]+ R_.* +0+ .text.exit \+ 0
+[0-9a-f ]+ R_.* +0+ .text \+ [0-9a-f]+
+[0-9a-f ]+ R_.* +0+ .text \+ [0-9a-f]+
+#...
diff --git a/ld/testsuite/ld-sframe/pr32789-1.sd b/ld/testsuite/ld-sframe/pr32789-1.sd
new file mode 100644 (file)
index 0000000..5219a8c
--- /dev/null
@@ -0,0 +1,4 @@
+#failif
+#...
+.*\(SFRAME_F_FDE_SORTED\).*
+#...
diff --git a/ld/testsuite/ld-sframe/pr32789-1a.c b/ld/testsuite/ld-sframe/pr32789-1a.c
new file mode 100644 (file)
index 0000000..b7d1e88
--- /dev/null
@@ -0,0 +1,22 @@
+static int a = 0;
+
+extern int bar(void);
+
+__attribute__((section((".text.init"))))
+int foo_init(void)
+{
+  return 10;
+}
+
+void foo (void)
+{
+  foo_init ();
+  a++;
+  bar ();
+}
+
+__attribute__((section((".text.exit"))))
+void foo_exit(void)
+{
+  foo ();
+}
diff --git a/ld/testsuite/ld-sframe/pr32789-1b.c b/ld/testsuite/ld-sframe/pr32789-1b.c
new file mode 100644 (file)
index 0000000..e3e64eb
--- /dev/null
@@ -0,0 +1,12 @@
+static int bar_var = 2;
+
+int bar(void)
+{
+  return 20;
+}
+
+void bar2(void)
+{
+  bar_var++;
+  bar ();
+}
index 5358cfd81842eb5a2a429a22b8ec79785aeaedab..c9c3bed9df373f174f53934f477bfd1fd411fc76 100644 (file)
@@ -90,6 +90,22 @@ foreach sframe_test $sframe_test_list {
 
 check_pr33401
 
+# Run other compile and link tests.
+if { [check_compiler_available] } {
+    run_cc_link_tests [list \
+       [list \
+           "Build pr32789-1a.o pr32789-1b.o" \
+           "-r" \
+           "-Wa,--gsframe" \
+           { pr32789-1a.c pr32789-1b.c } \
+           {{readelf --sframe pr32789-1.sd}
+            {readelf -r pr32789-1.rd}} \
+           "pr32789-1.o" \
+           "c" \
+       ] \
+    ]
+}
+
 if {[info exists old_lc_all]} {
     set env(LC_ALL) $old_lc_all
 } else {
index 19725e8bf09c98757b435c9c671f9c830b5bf4fb..d4915bd28f3c81cdc69e0efed678c96c9a67c204 100644 (file)
@@ -11,8 +11,7 @@ Contents of the SFrame section .sframe:
   Header :
 
     Version: SFRAME_VERSION_2
-    Flags: SFRAME_F_FDE_SORTED,
-           SFRAME_F_FDE_FUNC_START_PCREL
+    Flags: SFRAME_F_FDE_FUNC_START_PCREL
     CFA fixed RA offset: \-8
     Num FDEs: 2
     Num FREs: 8
index 4286a72b93bce970954e11dbc96b4af9a4595d0f..fdd08a11ad97bf1772a2af481003a8a04269cbb5 100644 (file)
@@ -34,7 +34,6 @@ LIBSFRAME_2.0 {
     sframe_encoder_add_fre;
     sframe_encoder_add_funcdesc;
     sframe_encoder_add_funcdesc_v2;
-    sframe_encoder_write;
     dump_sframe;
     sframe_errmsg;
 
@@ -45,4 +44,5 @@ LIBSFRAME_2.0 {
 LIBSFRAME_2.1 {
   global:
     sframe_fre_get_ra_undefined_p;
+    sframe_encoder_write;
 } LIBSFRAME_2.0;
index 3a02a76a2a969d8244db540c139714c3ab3d95f7..42d00ec412bd6a81da9f6d022c10743d8d8c0515 100644 (file)
@@ -1975,11 +1975,11 @@ sframe_encoder_write_fre (char *contents, sframe_frame_row_entry *frep,
 }
 
 /* Serialize the core contents of the SFrame section and write out to the
-   output buffer held in the encoder context ECTX.  Return SFRAME_ERR if
-   failure.  */
+   output buffer held in the encoder context ECTX.  Sort the SFrame FDEs on
+   start PC if SORT_FDE_P is true.  Return SFRAME_ERR if failure.  */
 
 static int
-sframe_encoder_write_sframe (sframe_encoder_ctx *ectx)
+sframe_encoder_write_sframe (sframe_encoder_ctx *ectx, bool sort_fde_p)
 {
   char *contents;
   size_t buf_size;
@@ -2059,12 +2059,13 @@ sframe_encoder_write_sframe (sframe_encoder_ctx *ectx)
   sframe_assert ((size_t)(contents - ectx->sfe_data) == buf_size);
 
   /* Sort the FDE table */
-  sframe_sort_funcdesc (ectx);
+  if (sort_fde_p)
+    sframe_sort_funcdesc (ectx);
 
   /* Sanity checks:
      - the FDE section must have been sorted by now on the start address
-     of each function.  */
-  if (!(sframe_encoder_get_flags (ectx) & SFRAME_F_FDE_SORTED)
+     of each function, if sorting was needed.  */
+  if ((sort_fde_p != (sframe_encoder_get_flags (ectx) & SFRAME_F_FDE_SORTED))
       || (fd_info == NULL))
     return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
 
@@ -2082,12 +2083,12 @@ sframe_encoder_write_sframe (sframe_encoder_ctx *ectx)
 }
 
 /* Serialize the contents of the encoder context ECTX and return the buffer.
-   ENCODED_SIZE is updated to the size of the buffer.
-   Sets ERRP if failure.  */
+   Sort the SFrame FDEs on start PC if SORT_FDE_P is true.  ENCODED_SIZE is
+   updated to the size of the buffer.  Sets ERRP if failure.  */
 
 char *
-sframe_encoder_write (sframe_encoder_ctx *ectx,
-                     size_t *encoded_size, int *errp)
+sframe_encoder_write (sframe_encoder_ctx *ectx, size_t *encoded_size,
+                     bool sort_fde_p, int *errp)
 {
   sframe_header *ehp;
   size_t hdrsize, fsz, fresz, bufsize;
@@ -2128,7 +2129,7 @@ sframe_encoder_write (sframe_encoder_ctx *ectx,
   foreign_endian = need_swapping (ehp->sfh_abi_arch);
 
   /* Write out the FDE Index and the FRE table in the sfe_data. */
-  if (sframe_encoder_write_sframe (ectx))
+  if (sframe_encoder_write_sframe (ectx, sort_fde_p))
     return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
 
   /* Endian flip the contents if necessary.  */