[PATCH v2 1/3] x86-64/ELF: permit relaxed overflow checking for 32-bit PC-relative relocs
H.J. Lu
hjl.tools@gmail.com
Fri Mar 4 14:18:08 GMT 2022
On Fri, Mar 04, 2022 at 02:34:58PM +0100, Jan Beulich wrote:
> Right now it is impossible to encode certain valid 32-bit mode
> constructs; see the respective new test case. Note that there are
> further 32-bit PC-relative relocations, but I don't think they make a
> lot of sense to use in mixed-bitness code, so they're not having
> overrides put in place.
>
> Putting in place a new testcase, I'd like to note that the two existing
> ones (pcrel16 and pcrel16abs) appear to be pretty pointless: They don't
> expect any error despite supposedly checking for overflow, and in fact
> there can't possibly be any error for the
> - former since gas doesn't emit any relocation in the first place there,
> - latter because the way the relocation gets expressed by gas doesn't
> allow the linker to notice the overflow; it should be detected by gas
> if at all, but see above (an error would be reported here for x86-64
> afaict, but this test doesn't get re-used there).
> ---
> TBD: I didn't put thoughts yet into also making this work when linking
> ELF to PE.
>
> Note that I'm not sure at all whether this propagation of the struct
> elf_linker_x86_params pointer is actually acceptable. But this is the
> 5th or 6th try I made, with all others having been worse or not even
> working out. Hence I'd need pretty detailed guidance on how else the
> information could be made available.
> ---
> v2: Re-base and split.
>
> --- a/bfd/elf-linker-x86.h
> +++ b/bfd/elf-linker-x86.h
> @@ -28,6 +28,13 @@ enum elf_x86_prop_report
> prop_report_shstk = 1 << 3 /* Report missing SHSTK property. */
> };
>
> +/* Control of PC32 (on 64-bit) overflow check strictness. */
> +enum elf_x86_pcrel_relocs
> +{
> + pcrel_relocs_default,
> + pcrel_relocs_lax,
> +};
> +
> /* Used to pass x86-specific linker options from ld to bfd. */
> struct elf_linker_x86_params
> {
> @@ -64,6 +71,9 @@ struct elf_linker_x86_params
> /* Report relative relocations. */
> unsigned int report_relative_reloc : 1;
>
> + /* Strictness of PC32 (on 64-bit) overflow checks. */
> + enum elf_x86_pcrel_relocs pcrel_relocs;
> +
> /* X86-64 ISA level needed. */
> unsigned int isa_level;
>
> --- a/bfd/elf64-x86-64.c
> +++ b/bfd/elf64-x86-64.c
> @@ -192,6 +192,15 @@ static reloc_howto_type x86_64_elf_howto
> false)
> };
>
> +static reloc_howto_type x86_64_howto_pc32_lax =
> + HOWTO(R_X86_64_PC32, 0, 2, 32, true, 0, complain_overflow_bitfield,
> + bfd_elf_generic_reloc, "R_X86_64_PC32", false, 0, 0xffffffff, true);
> +
> +static reloc_howto_type x86_64_howto_pc32_bnd_lax =
> + HOWTO(R_X86_64_PC32_BND, 0, 2, 32, true, 0, complain_overflow_bitfield,
> + bfd_elf_generic_reloc, "R_X86_64_PC32_BND", false, 0, 0xffffffff,
> + true);
> +
> /* Map BFD relocs to the x86_64 elf relocs. */
> struct elf_reloc_map
> {
> @@ -248,6 +257,30 @@ static const struct elf_reloc_map x86_64
> };
>
> static reloc_howto_type *
> +elf_x86_64_reloc_override (const bfd *abfd, reloc_howto_type *howto)
> +{
> + const struct elf_linker_x86_params *params = elf_x86_tdata (abfd)->params;
> +
> + switch (howto->type)
> + {
> + default:
> + break;
> +
> + case R_X86_64_PC32:
> + if (params == NULL || params->pcrel_relocs != pcrel_relocs_lax)
> + break;
> + return &x86_64_howto_pc32_lax;
> +
> + case R_X86_64_PC32_BND:
> + if (params == NULL || params->pcrel_relocs != pcrel_relocs_lax)
> + break;
> + return &x86_64_howto_pc32_bnd_lax;
> + }
> +
> + return howto;
> +}
> +
> +static reloc_howto_type *
> elf_x86_64_rtype_to_howto (bfd *abfd, unsigned r_type)
> {
> unsigned i;
> @@ -275,7 +308,7 @@ elf_x86_64_rtype_to_howto (bfd *abfd, un
> else
> i = r_type - (unsigned int) R_X86_64_vt_offset;
> BFD_ASSERT (x86_64_elf_howto_table[i].type == r_type);
> - return &x86_64_elf_howto_table[i];
> + return elf_x86_64_reloc_override (abfd, &x86_64_elf_howto_table[i]);
> }
>
> /* Given a BFD reloc type, return a HOWTO structure. */
> @@ -313,7 +346,7 @@ elf_x86_64_reloc_name_lookup (bfd *abfd,
> for (i = 0; i < ARRAY_SIZE (x86_64_elf_howto_table); i++)
> if (x86_64_elf_howto_table[i].name != NULL
> && strcasecmp (x86_64_elf_howto_table[i].name, r_name) == 0)
> - return &x86_64_elf_howto_table[i];
> + return elf_x86_64_reloc_override (abfd, &x86_64_elf_howto_table[i]);
>
> return NULL;
> }
> @@ -1846,6 +1879,9 @@ elf_x86_64_scan_relocs (bfd *abfd, struc
>
> BFD_ASSERT (is_x86_elf (abfd, htab));
>
> + /* Make command line controlled settings accessible from the object. */
> + elf_x86_tdata (abfd)->params = htab->params;
> +
> /* Get the section contents. */
> if (elf_section_data (sec)->this_hdr.contents != NULL)
> contents = elf_section_data (sec)->this_hdr.contents;
> --- a/bfd/elfxx-x86.h
> +++ b/bfd/elfxx-x86.h
> @@ -702,6 +702,9 @@ struct elf_x86_obj_tdata
> /* R_*_RELATIVE relocation in GOT for this local symbol has been
> processed. */
> char *relative_reloc_done;
> +
> + /* Container holding command line controlled linker settings. */
> + const struct elf_linker_x86_params *params;
> };
>
> enum elf_x86_plt_type
> --- /dev/null
> +++ b/gas/testsuite/gas/i386/code32.d
> @@ -0,0 +1,3 @@
> +#name: x86-64 code32
> +#as: -mx86-used-note=no --generate-missing-build-notes=no
> +#readelf: -n
> --- /dev/null
> +++ b/gas/testsuite/gas/i386/code32.s
> @@ -0,0 +1,11 @@
> + .code32
> + .text
> + .section .text.0, "ax", @progbits
> + .type func0, @function
> +func0:
> + call func1
> + ret
> + .section .text.1, "ax", @progbits
> + .type func1, @function
> +func1:
> + jmp func0
> --- a/gas/testsuite/gas/i386/i386.exp
> +++ b/gas/testsuite/gas/i386/i386.exp
> @@ -1331,6 +1331,7 @@ if [gas_64_check] then {
> run_dump_test "x86-64-property-8"
> run_dump_test "x86-64-property-9"
> run_dump_test "x86-64-property-14"
> + run_dump_test "code32"
>
> if {[istarget "*-*-linux*"]} then {
> run_dump_test "x86-64-align-branch-3"
> --- a/ld/emulparams/elf32_x86_64.sh
> +++ b/ld/emulparams/elf32_x86_64.sh
> @@ -2,6 +2,7 @@ source_sh ${srcdir}/emulparams/plt_unwin
> source_sh ${srcdir}/emulparams/extern_protected_data.sh
> source_sh ${srcdir}/emulparams/dynamic_undefined_weak.sh
> source_sh ${srcdir}/emulparams/reloc_overflow.sh
> +source_sh ${srcdir}/emulparams/pcrel-relocs.sh
> source_sh ${srcdir}/emulparams/call_nop.sh
> source_sh ${srcdir}/emulparams/cet.sh
> source_sh ${srcdir}/emulparams/x86-report-relative.sh
> --- a/ld/emulparams/elf_x86_64.sh
> +++ b/ld/emulparams/elf_x86_64.sh
> @@ -2,6 +2,7 @@ source_sh ${srcdir}/emulparams/plt_unwin
> source_sh ${srcdir}/emulparams/extern_protected_data.sh
> source_sh ${srcdir}/emulparams/dynamic_undefined_weak.sh
> source_sh ${srcdir}/emulparams/reloc_overflow.sh
> +source_sh ${srcdir}/emulparams/pcrel-relocs.sh
> source_sh ${srcdir}/emulparams/call_nop.sh
> source_sh ${srcdir}/emulparams/cet.sh
> source_sh ${srcdir}/emulparams/x86-report-relative.sh
> --- /dev/null
> +++ b/ld/emulparams/pcrel-relocs.sh
> @@ -0,0 +1,11 @@
> +PARSE_AND_LIST_OPTIONS_STRICT_PCREL_RELOCS='
> + fprintf (file, _("\
> + -z lax-pcrel-relocs Lax PC-relative relocation overflow checks\n"));
> +'
> +PARSE_AND_LIST_ARGS_CASE_Z_STRICT_PCREL_RELOCS='
> + else if (strcmp (optarg, "lax-pcrel-relocs") == 0)
> + params.pcrel_relocs = pcrel_relocs_lax;
> +'
> +
> +PARSE_AND_LIST_OPTIONS="$PARSE_AND_LIST_OPTIONS $PARSE_AND_LIST_OPTIONS_STRICT_PCREL_RELOCS"
> +PARSE_AND_LIST_ARGS_CASE_Z="$PARSE_AND_LIST_ARGS_CASE_Z $PARSE_AND_LIST_ARGS_CASE_Z_STRICT_PCREL_RELOCS"
> --- a/ld/ld.texi
> +++ b/ld/ld.texi
> @@ -1372,6 +1372,12 @@ missing properties in input files. @opt
> the linker issue an error for missing properties in input files.
> Supported for Linux/x86_64.
>
> +@item lax-pcrel-relocs
> +Relax relocation overflow checks for certain 32-bit PC-relative relocations
> +which, when used by 32-bit code inside a 64-bit object, may require a
> +larger range of values to be considered valid.
> +Supported for x86-64 ELF targets.
> +
I think the check should be turned on automatically. Can you use a GNU
property bit to tell linker that a larger range of values should be
checked for R_X86_64_PC32 and issue an error for R_X86_64_PC32_BND?
H.J.
More information about the Binutils
mailing list