ld: generate SFrame stack trace info for .plt.got

PR/32298 sframe: no SFrame stack trace info generated for .plt.got

Add support to generate SFrame stack trace info for .plt.got section.
Enhance the current definition of struct elf_x86_sframe_plt to include
initialized SFrame FDE/FREs applicable for .plt.got section.  There are
two variants of .plt.got entries: 16 byte and 8 byte.

8 byte:
    ff 25 00 00 00 00     jmpq  *name@GOTPCREL(%rip)
    66 90                 xchg  %ax,%ax

16 byte:
    f3 0f 1e fa           endbr64
    ff 25 66 2f 00 00     jmpq  *name@GOTPCREL(%rip)
    66 0f 1f 44 00 00     nopw   0x0(%rax,%rax,1)

For the testcase, define some application symbols such that their PLT
entry is placed in .plt.got and ensure SFrame information is generated
with and without -z ibtplt.

ChangeLog:
	PR/32298
	* bfd/elf64-x86-64.c (elf_x86_64_link_setup_gnu_properties):
	PLT GOT entry size is different for IBT vs non IBT PLTs.
	* bfd/elfxx-x86.c (enum dynobj_sframe_plt_type): New enum for
	SFRAME_PLT_GOT.
	(_bfd_x86_elf_create_sframe_plt): Handle SFRAME_PLT_GOT.
	(_bfd_x86_elf_write_sframe_plt): Likewise.
	(_bfd_x86_elf_late_size_sections): Likewise.
	(_bfd_x86_elf_finish_dynamic_sections): Likewise.
	* bfd/elfxx-x86.h (struct elf_x86_sframe_plt): Add new members
	to keep information about PLT GOT entries.
	(struct elf_x86_link_hash_table): Add support for creating
	SFrame section for .plt.got.
	* ld/testsuite/ld-x86-64/x86-64.exp: Add new tests.
	* ld/testsuite/ld-x86-64/sframe-pltgot-1.d: New test.
	* ld/testsuite/ld-x86-64/sframe-pltgot-1.s: New test.
	* ld/testsuite/ld-x86-64/sframe-pltgot-2.d: New test.
This commit is contained in:
Indu Bhagat 2024-11-01 15:36:35 -07:00
parent 938fb51218
commit 47c88752f9
7 changed files with 198 additions and 9 deletions

View File

@ -922,7 +922,7 @@ static const sframe_frame_row_entry elf_x86_64_sframe_sec_pltn_fre1 =
SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B) /* FRE info. */
};
/* SFrame helper object for non-lazy PLT. Also used for IBT enabled PLT. */
/* SFrame helper object for non-lazy PLT. */
static const struct elf_x86_sframe_plt elf_x86_64_sframe_non_lazy_plt =
{
LAZY_PLT_ENTRY_SIZE,
@ -935,7 +935,31 @@ static const struct elf_x86_sframe_plt elf_x86_64_sframe_non_lazy_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 }
{ &elf_x86_64_sframe_null_fre },
NON_LAZY_PLT_ENTRY_SIZE,
1, /* Number of FREs for PLT GOT. */
/* Array of SFrame FREs for PLT GOT. */
{ &elf_x86_64_sframe_null_fre },
};
/* SFrame helper object for non-lazy IBT enabled PLT. */
static const struct elf_x86_sframe_plt elf_x86_64_sframe_non_lazy_ibt_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 },
LAZY_PLT_ENTRY_SIZE,
1, /* Number of FREs for PLT GOT. */
/* Array of SFrame FREs for PLT GOT. */
{ &elf_x86_64_sframe_null_fre },
};
/* SFrame helper object for lazy PLT. */
@ -952,7 +976,11 @@ static const struct elf_x86_sframe_plt elf_x86_64_sframe_plt =
NON_LAZY_PLT_ENTRY_SIZE,
1, /* Number of FREs for second PLT. */
/* Array of SFrame FREs for second PLT. */
{ &elf_x86_64_sframe_sec_pltn_fre1 }
{ &elf_x86_64_sframe_sec_pltn_fre1 },
NON_LAZY_PLT_ENTRY_SIZE,
1, /* Number of FREs for PLT GOT. */
/* Array of SFrame FREs for PLT GOT. */
{ &elf_x86_64_sframe_null_fre },
};
/* SFrame helper object for lazy PLT with IBT. */
@ -969,7 +997,11 @@ static const struct elf_x86_sframe_plt elf_x86_64_sframe_ibt_plt =
LAZY_PLT_ENTRY_SIZE,
1, /* Number of FREs for second PLT. */
/* Array of SFrame FREs for second plt. */
{ &elf_x86_64_sframe_sec_pltn_fre1 }
{ &elf_x86_64_sframe_sec_pltn_fre1 },
LAZY_PLT_ENTRY_SIZE,
1, /* Number of FREs for PLT GOT. */
/* Array of SFrame FREs for PLT GOT. */
{ &elf_x86_64_sframe_null_fre },
};
/* These are the standard parameters. */
@ -5703,7 +5735,7 @@ elf_x86_64_link_setup_gnu_properties (struct bfd_link_info *info)
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_ibt_plt;
init_table.sframe_non_lazy_ibt_plt = &elf_x86_64_sframe_non_lazy_plt;
init_table.sframe_non_lazy_ibt_plt = &elf_x86_64_sframe_non_lazy_ibt_plt;
}
else
{

View File

@ -1817,7 +1817,8 @@ elf_x86_relative_reloc_compare (const void *pa, const void *pb)
enum dynobj_sframe_plt_type
{
SFRAME_PLT = 1,
SFRAME_PLT_SEC = 2
SFRAME_PLT_SEC = 2,
SFRAME_PLT_GOT = 3,
};
/* Create SFrame stack trace info for the plt entries in the .plt section
@ -1880,6 +1881,21 @@ _bfd_x86_elf_create_sframe_plt (bfd *output_bfd,
break;
}
case SFRAME_PLT_GOT:
{
ectx = &htab->plt_got_cfe_ctx;
dpltsec = htab->plt_got;
plt0_entry_size = 0;
plt_entry_size = htab->sframe_plt->plt_got_entry_size;
pltn_fres = htab->sframe_plt->plt_got_fres;
num_pltn_fres = htab->sframe_plt->plt_got_num_fres;
num_pltn_entries = dpltsec->size / plt_entry_size;
break;
}
default:
/* No other value is possible. */
return false;
@ -1984,6 +2000,10 @@ _bfd_x86_elf_write_sframe_plt (bfd *output_bfd,
ectx = htab->plt_second_cfe_ctx;
sec = htab->plt_second_sframe;
break;
case SFRAME_PLT_GOT:
ectx = htab->plt_got_cfe_ctx;
sec = htab->plt_got_sframe;
break;
default:
/* No other value is possible. */
return false;
@ -2511,7 +2531,18 @@ _bfd_x86_elf_late_size_sections (bfd *output_bfd,
htab->plt_sframe->size = sizeof (sframe_header) + 1;
}
/* FIXME - generate for .plt.got ? */
if (htab->plt_got_sframe != NULL
&& htab->plt_got != NULL
&& htab->plt_got->size != 0
&& !bfd_is_abs_section (htab->plt_got->output_section))
{
_bfd_x86_elf_create_sframe_plt (output_bfd, info, SFRAME_PLT_GOT);
/* 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_got_sframe->size = sizeof (sframe_header) + 1;
}
if (htab->plt_second_sframe != NULL
&& htab->plt_second != NULL
@ -2578,6 +2609,7 @@ _bfd_x86_elf_late_size_sections (bfd *output_bfd,
|| s == htab->plt_second_eh_frame
|| s == htab->plt_sframe
|| s == htab->plt_second_sframe
|| s == htab->plt_got_sframe
|| s == htab->elf.sdynbss
|| s == htab->elf.sdynrelro)
{
@ -2622,7 +2654,8 @@ _bfd_x86_elf_late_size_sections (bfd *output_bfd,
/* Skip allocating contents for .sframe section as it is written
out differently. See below. */
if ((s == htab->plt_sframe) || (s == htab->plt_second_sframe))
if ((s == htab->plt_sframe) || (s == htab->plt_second_sframe)
|| (s == htab->plt_got_sframe))
continue;
/* NB: Initially, the iplt section has minimal alignment to
@ -2687,6 +2720,12 @@ _bfd_x86_elf_late_size_sections (bfd *output_bfd,
&& htab->plt_second->size != 0
&& htab->plt_second_sframe->contents == NULL)
_bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT_SEC);
if (htab->plt_got_sframe != NULL
&& htab->plt_got != NULL
&& htab->plt_got->size != 0
&& htab->plt_got_sframe->contents == NULL)
_bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT_GOT);
}
if (resolved_plt != NULL
@ -2997,6 +3036,34 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd,
return NULL;
}
}
if (htab->plt_got_sframe != NULL
&& htab->plt_got_sframe->contents != NULL)
{
if (htab->plt_got != NULL
&& htab->plt_got->size != 0
&& (htab->plt_got->flags & SEC_EXCLUDE) == 0
&& htab->plt_got->output_section != NULL
&& htab->plt_got_sframe->output_section != NULL)
{
bfd_vma plt_start = htab->plt_got->output_section->vma;
bfd_vma sframe_start
= (htab->plt_got_sframe->output_section->vma
+ htab->plt_got_sframe->output_offset
+ PLT_SFRAME_FDE_START_OFFSET);
bfd_put_signed_32 (dynobj, plt_start - sframe_start,
htab->plt_got_sframe->contents
+ PLT_SFRAME_FDE_START_OFFSET);
}
if (htab->plt_got_sframe->sec_info_type == SEC_INFO_TYPE_SFRAME)
{
if (! _bfd_elf_merge_section_sframe (output_bfd, info,
htab->plt_got_sframe,
htab->plt_got_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;
@ -4764,7 +4831,18 @@ _bfd_x86_elf_link_setup_gnu_properties
htab->plt_second_sframe = sec;
}
/* FIXME - add later for plt_got. */
/* .plt.got. */
if (htab->plt_got != NULL)
{
sec = bfd_make_section_anyway_with_flags (dynobj,
".sframe",
flags);
if (sec == NULL)
info->callbacks->einfo (_("%F%P: failed to create PLT GOT .sframe section\n"));
htab->plt_got_sframe = sec;
}
}
}

View File

@ -401,6 +401,10 @@ struct elf_x86_sframe_plt
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];
unsigned int plt_got_entry_size;
unsigned int plt_got_num_fres;
const sframe_frame_row_entry *plt_got_fres[SFRAME_PLTN_MAX_NUM_FRES];
};
struct elf_x86_lazy_plt_layout
@ -606,6 +610,8 @@ struct elf_x86_link_hash_table
asection *plt_sframe;
sframe_encoder_ctx *plt_second_cfe_ctx;
asection *plt_second_sframe;
sframe_encoder_ctx *plt_got_cfe_ctx;
asection *plt_got_sframe;
/* Parameters describing PLT generation, lazy or non-lazy. */
struct elf_x86_plt_layout plt;

View File

@ -0,0 +1,28 @@
#as: --gsframe
#source: sframe-pltgot-1.s
#objdump: --sframe=.sframe
#ld: -shared -z ibtplt --no-rosegment
#name: SFrame for IBT .plt.got
.*: +file format .*
Contents of the SFrame section .sframe:
Header :
Version: SFRAME_VERSION_2
Flags: SFRAME_F_FDE_SORTED
CFA fixed RA offset: \-8
#...
Function Index :
func idx \[0\]: pc = 0x1000, size = 16 bytes
STARTPC +CFA +FP +RA +
0+1000 +sp\+16 +u +f +
0+1006 +sp\+24 +u +f +
func idx \[1\]: pc = 0x1010, size = 64 bytes
STARTPC\[m\] +CFA +FP +RA +
0+0000 +sp\+16 +u +f +
#...

View File

@ -0,0 +1,15 @@
.text
.globl foo
.type foo, @function
foo:
.cfi_startproc
call func1@plt
movq func1@GOTPCREL(%rip), %rax
call func2@plt
movq func2@GOTPCREL(%rip), %rax
call func3@plt
movq func3@GOTPCREL(%rip), %rax
call func4@plt
movq func4@GOTPCREL(%rip), %rax
.cfi_endproc
.section .note.GNU-stack,"",@progbits

View File

@ -0,0 +1,28 @@
#as: --gsframe
#source: sframe-pltgot-1.s
#objdump: --sframe=.sframe
#ld: -shared --no-rosegment
#name: SFrame for .plt.got
.*: +file format .*
Contents of the SFrame section .sframe:
Header :
Version: SFRAME_VERSION_2
Flags: SFRAME_F_FDE_SORTED
CFA fixed RA offset: \-8
#...
Function Index :
func idx \[0\]: pc = 0x1000, size = 16 bytes
STARTPC +CFA +FP +RA +
0+1000 +sp\+16 +u +f +
0+1006 +sp\+24 +u +f +
func idx \[1\]: pc = 0x1010, size = 32 bytes
STARTPC\[m\] +CFA +FP +RA +
0+0000 +sp\+16 +u +f +
#...

View File

@ -549,6 +549,8 @@ if { ![skip_sframe_tests] } {
run_dump_test "sframe-simple-1"
run_dump_test "sframe-plt-1"
run_dump_test "sframe-ibt-plt-1"
run_dump_test "sframe-pltgot-1"
run_dump_test "sframe-pltgot-2"
}
if ![istarget "x86_64-*-linux*"] {