[PATCH v3 2/2] [ld] Allow relocation finalization for ld -r

Jan Beulich jbeulich@suse.com
Fri Nov 7 11:43:12 GMT 2025


On 17.10.2025 19:50, Eyal Itkin wrote:
> Introduce the "--finalize-locals" CLI flag, which will
> be supported only for relocatables (ld -r).
> 
> When provided, relocations that are associated with
> local symbols, and that support finalization, will
> undergo a finalization step. This change aligns the
> ET_REL creation to support the same finalization
> semantics as that of the shared library (ET_DYN). In
> essence, if the symbols are local, and support finalize,
> there is no need to keep these relocations in the binary.
> 
> This added support will enable users to properly strip
> the output of "ld -r --localize-hidden --finalize-locals",
> as the symbols will no longer be tied to unneeded relocations.
> 
> The full discussion about the format is available in
> the generic-abi group that is responsible for the ELF
> standard. Specifically, the summarized architecture can
> be found here:
> https://groups.google.com/g/generic-abi/c/sT25-xfX9yc/m/J9SIthF4BgAJ
> 
> Signed-off-by: Eyal Itkin <eyal.itkin@gmail.com>
> ---
>  bfd/elf64-x86-64.c                     | 54 +++++++++++++++++++++++++-
>  include/bfdlink.h                      |  3 ++
>  ld/ld.h                                |  3 ++
>  ld/ldlex.h                             |  1 +
>  ld/lexsup.c                            |  9 +++++
>  ld/testsuite/ld-elf/finalize_locals.s  | 23 +++++++++++
>  ld/testsuite/ld-elf/finalize_locals1.d | 12 ++++++
>  ld/testsuite/ld-elf/finalize_locals2.d | 13 +++++++
>  ld/testsuite/ld-elf/finalize_locals3.d |  3 ++
>  9 files changed, 120 insertions(+), 1 deletion(-)
>  create mode 100644 ld/testsuite/ld-elf/finalize_locals.s
>  create mode 100644 ld/testsuite/ld-elf/finalize_locals1.d
>  create mode 100644 ld/testsuite/ld-elf/finalize_locals2.d
>  create mode 100644 ld/testsuite/ld-elf/finalize_locals3.d

Please consider using - in place of _ in the names of new files. On most
keyboards that's easier to type. Underscores really should only be used
when dashes have some special meaning. (Applies to patch 1 as well.)

> --- a/bfd/elf64-x86-64.c
> +++ b/bfd/elf64-x86-64.c
> @@ -3158,6 +3158,47 @@ elf_x86_64_tpoff (struct bfd_link_info *info, bfd_vma address)
>    return address - static_tls_size - htab->tls_sec->vma;
>  }
>  
> +/* Check if a given symbol-related relocation can be finalized.  */
> +
> +static int
> +elf_x86_64_can_finalize_reloc (Elf_Internal_Rela *rel,
> +			       asection *input_section,
> +			       asection *output_section)

The function returning a boolean result, its return type wants to be bool.

> +{
> +  struct bfd_section *input_sec_out;
> +  struct bfd_section *sym_sec_out;
> +  unsigned int r_type;
> +
> +  if (output_section == NULL)
> +    return 0;

Can output_section really be NULL here?

> +  input_sec_out = input_section->output_section;
> +  sym_sec_out = output_section->output_section;
> +
> +  /* Relocation must not cross section boundaries.  */
> +  if (sym_sec_out->index != input_sec_out->index)
> +    return 0;
> +
> +  r_type = ELF32_R_TYPE (rel->r_info);
> +
> +  /* Some relocation types can not be finalized.  */
> +  switch (r_type)
> +    {
> +    default:
> +      break;
> +    case R_X86_64_GOTPCREL:
> +    case R_X86_64_GOTPCRELX:
> +    case R_X86_64_REX_GOTPCRELX:
> +    case R_X86_64_CODE_4_GOTPCRELX:
> +    case R_X86_64_CODE_5_GOTPCRELX:
> +    case R_X86_64_CODE_6_GOTPCRELX:
> +    case R_X86_64_GOTPCREL64:
> +      return 0;

What about relocations involving the PLT? Or about anything related to
TLS? I wonder whether you rather want to white-list relocations that
are suitable.

> @@ -3227,7 +3268,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
>        bool converted_reloc;
>        bool need_copy_reloc_in_pie;
>        bool no_copyreloc_p;
> +      bool reloc_skip_symbol;
>  
> +      reloc_skip_symbol = true;
>        r_type = ELF32_R_TYPE (rel->r_info);
>        if (r_type == (int) R_X86_64_GNU_VTINHERIT
>  	  || r_type == (int) R_X86_64_GNU_VTENTRY)
> @@ -3286,6 +3329,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
>  				   h, sec, relocation,
>  				   unresolved_reloc, warned, ignored);
>  	  st_size = h->size;
> +	  if (info->finalize_locals && h->forced_local
> +	      && elf_x86_64_can_finalize_reloc (rel, input_section, sec))
> +	    reloc_skip_symbol = false;

Why would this need limiting to "forced" locals?

> @@ -3310,7 +3356,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
>  	  continue;
>  	}
>  
> -      if (bfd_link_relocatable (info))
> +      if (bfd_link_relocatable (info) && reloc_skip_symbol)
>  	{
>  	  if (wrel != rel)
>  	    *wrel = *rel;

I continue to find this confusing: You check a variable with "skip" in
its name just to do something when the implication is that something
wants skipping.

> --- a/include/bfdlink.h
> +++ b/include/bfdlink.h
> @@ -489,6 +489,9 @@ struct bfd_link_info
>    /* TRUE if supports localizing hidden symbols.  */
>    unsigned int localize_hidden: 1;
>  
> +  /* TRUE if supports finalizing local symbols.  */
> +  unsigned int finalize_locals: 1;

Same question as for the other patch: Why "supports"?

> --- a/ld/ld.h
> +++ b/ld/ld.h
> @@ -335,6 +335,9 @@ typedef struct
>  
>    /* If set, localize hidden symbols.  */
>    bool localize_hidden;
> +
> +  /* If set, finalize locale symbols.  */
> +  bool finalize_locals;
>  } ld_config_type;

And again - where is this used?

> --- a/ld/lexsup.c
> +++ b/ld/lexsup.c
> @@ -210,6 +210,8 @@ static const struct ld_option ld_options[] =
>      'r', NULL, N_("Generate relocatable output"), TWO_DASHES },
>    { {"localize-hidden", no_argument, NULL, OPTION_LOCALIZE_HIDDEN},
>      '\0', NULL, N_("Localize hidden relocatable symbols"), TWO_DASHES },
> +  { {"finalize-locals", no_argument, NULL, OPTION_FINALIZE_LOCALS},
> +    '\0', NULL, N_("Attempt to finalize local relocatable symbols"), TWO_DASHES },

Also for patch 1: New command line options will want documenting.

Jan


More information about the Binutils mailing list