[PATCH 3 07/16] MIPS: Add user-defined sdata sections

Maciej W. Rozycki macro@orcam.me.uk
Mon Sep 21 13:43:54 GMT 2026


On Thu, 5 Feb 2026, Jovan Dmitrovic via Binutils wrote:

> Adds functionality to allow user to use different small data areas for
> each data item. When turned on, gp relative relocation against a symbol
> in the .sdata_<num> or .sbss_<num> use the gp value based on _gp_<num>
> symbol.

 This is a psABI extension.  Is there a document available that describes 
it?  I've gone through this change based on lone code at this time, but 
I'd like to verify it against the spec too.

> diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
> index 701ac76cd33..e44cea87740 100644
> --- a/bfd/elfxx-mips.c
> +++ b/bfd/elfxx-mips.c
> @@ -482,6 +482,12 @@ struct mips_elf_link_hash_table
>    /* True if we are targetting R6 compact branches.  */
>    bool compact_branches;
>  
> +  /* When True and processing a gp relative relocation against a symbol

 s/True/TRUE/

> +     in a .sdata_<num>/.sbss_<num> section use the gp value
> +     based on the address of the _gp_<num> symbol where <num> is
> +     the number of the .sbss/.sdata section the symbol is in.  */

 Please rejustify the comment as it's weirdly formatted.

> +  bool user_def_sdata_sections;
> +

 OK, a flag tracking whether the feature has been enabled.

> @@ -602,6 +608,9 @@ struct mips_elf_obj_tdata
>       text/data symbols defined in dynamic objects.  */
>    asection *elf_data_section;
>    asection *elf_text_section;
> +
> +  struct mips_hi16 *mips_hi16_list;

 Where is this new member of the struct used?

> +  bfd_signed_vma sdata_section[1000];

 Missing member description.  Use plural.  Presumably the fixed size of 
the array comes from the psABI spec?

> @@ -5657,6 +5666,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
>    struct mips_elf_link_hash_table *htab;
>    bfd *dynobj;
>    bool resolved_to_zero;
> +  int gp_sec_num = 0;

 This is not used outside the block below, so move it there.

> @@ -6053,6 +6063,27 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
>    if (gnu_local_gp_p)
>      symbol = gp;
>  
> +  if (mips_elf_hash_table (info)->user_def_sdata_sections && sec != NULL)
> +    {
> +      if (strncmp (".sdata_", sec->name, 7) == 0)
> +	gp_sec_num = atoi (&sec->name[7]);
> +      else if (strncmp (".sbss_", sec->name, 6) == 0)
> +	gp_sec_num = atoi (&sec->name[6]);

 So how about sections called `.sdata_', `.sdata_foo', or`.sdata_001foo'?  
Or say `.sdata_0' vs `.sdata_000'?  It seems to me this would best be 
factored out to a helper returning the section number or -1 if not a 
matching section name.  Then all the individual checks can be done there.

> +
> +      if (gp_sec_num)
> +	{
> +	  if (gp_sec_num < 0 || gp_sec_num > 999
> +	      || mips_elf_tdata(abfd)->sdata_section[gp_sec_num] == -1)
> +	    {
> +	      (*_bfd_error_handler)
> +		(_("%pB: Error: Unable to apply gp relocation to section `%s'"),
> +		   abfd, sec->name);

 Use `%pA'; s/Error: Unable/error: unable/.

> +	      bfd_set_error (bfd_error_bad_value);
> +	    }
> +	}
> +
> +      gp = mips_elf_tdata(abfd)->sdata_section[gp_sec_num];
> +    }
>    /* Global R_MIPS_GOT_PAGE/R_MICROMIPS_GOT_PAGE relocations are equivalent

 New line above the comment please.

> @@ -7649,7 +7680,8 @@ _bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr)
>  	 on it in an input file will be followed.  */
>        if (strcmp (name, ".sdata") == 0
>  	  || strcmp (name, ".lit8") == 0
> -	  || strcmp (name, ".lit4") == 0)
> +	  || strcmp (name, ".lit4") == 0
> +	  || strncmp (name, ".sdata_", 7) == 0)

 Again can this section name be properly validated?

> @@ -7941,7 +7973,9 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
>    else if (strcmp (name, ".got") == 0
>  	   || strcmp (name, ".srdata") == 0
>  	   || strcmp (name, ".sdata") == 0
> +	   || strncmp (name, ".sdata_", 7) == 0
>  	   || strcmp (name, ".sbss") == 0
> +	   || strncmp (name, ".sbss_", 6) == 0

 Likewise?

> @@ -14948,6 +14982,12 @@ _bfd_mips_elf_compact_branches (struct bfd_link_info *info, bool on)
>    mips_elf_hash_table (info)->compact_branches = on;
>  }
>  
> +void
> +_bfd_mips_elf_user_def_sdata_sections (struct bfd_link_info *info, bool on)
> +{
> +  mips_elf_hash_table (info)->user_def_sdata_sections = on;
> +}
> +

 Document a new function.

> @@ -15298,6 +15338,23 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
>    if (hti.error)
>      return false;
>  
> +  unsigned int gp_num;
> +  for (gp_num = 0 ; gp_num < 1000 ; gp_num++)

 Move the declaration into the statement.  Fix formatting.

> +    {
> +      struct bfd_link_hash_entry *h;
> +      char gp_name[8];
> +      bfd_signed_vma gp_vma = -1;

 Reorder for reverse Xmas tree.

> +
> +      sprintf (gp_name, "_gp_%d", gp_num);
> +      h = bfd_link_hash_lookup (info->hash, gp_name, false, false, true);
> +      if (h != NULL && h->type == bfd_link_hash_defined)
> +	gp_vma = (h->u.def.value
> +		  + h->u.def.section->output_section->vma
> +		  + h->u.def.section->output_offset);
> +
> +      mips_elf_tdata(abfd)->sdata_section[gp_num] = gp_vma;
> +    }
> +

 OK, gathering `_gp_*' definitions.

> diff --git a/bfd/elfxx-mips.h b/bfd/elfxx-mips.h
> index fedc21ed3d9..528929e7c31 100644
> --- a/bfd/elfxx-mips.h
> +++ b/bfd/elfxx-mips.h
> @@ -182,6 +182,8 @@ extern void _bfd_mips_elf_linker_flags
>    (struct bfd_link_info *, bool, bool, bool);
>  extern void _bfd_mips_elf_compact_branches
>    (struct bfd_link_info *, bool);
> +extern void _bfd_mips_elf_user_def_sdata_sections
> +  (struct bfd_link_info *, bool);

 OK, used externally.

> diff --git a/ld/emultempl/mipself.em b/ld/emultempl/mipself.em
> index f84ad1c6de9..7414a948ad4 100644
> --- a/ld/emultempl/mipself.em
> +++ b/ld/emultempl/mipself.em
> @@ -45,6 +45,7 @@ static bfd *stub_bfd;
>  static bool insn32;
>  static bool ignore_branch_isa;
>  static bool compact_branches;
> +static bool user_def_sdata_sections;

 OK, hold the setting of `--user-defined-sdata-sections'.

> @@ -204,6 +205,7 @@ mips_create_output_section_statements (void)
>    if (is_mips_elf (link_info.output_bfd))
>      {
>        _bfd_mips_elf_compact_branches (&link_info, compact_branches);
> +      _bfd_mips_elf_user_def_sdata_sections (&link_info, user_def_sdata_sections);

 OK, propagate the setting to BFD.

> @@ -239,6 +241,8 @@ PARSE_AND_LIST_LONGOPTS='
>    { "no-ignore-branch-isa", no_argument, NULL, OPTION_NO_IGNORE_BRANCH_ISA },
>    { "compact-branches", no_argument, NULL, OPTION_COMPACT_BRANCHES },
>    { "no-compact-branches", no_argument, NULL, OPTION_NO_COMPACT_BRANCHES },
> +  { "user-defined-sdata-sections", no_argument, NULL, OPTION_USER_DEF_SDATA_SECTIONS },
> +  { "no-user-defined-sdata-sections", no_argument, NULL, OPTION_NO_USER_DEF_SDATA_SECTIONS },
>  '

 OK, the user options.

> @@ -262,6 +266,17 @@ PARSE_AND_LIST_OPTIONS='
>    fprintf (file, _("\
>    --no-compact-branches       Generate delay slot branches/jumps for MIPS R6\n"
>  		   ));
> +  fprintf (file, _("\
> +  --user-defined-sdata-sections\n\
> +                              When processing a gp relative relocation against a symbol\n\
> +                              in a .sdata_<num>/.sbss_<num> section use the gp value\n\
> +                              based on the address of the _gp_<num> symbol where <num> is\n\
> +                              the number of the .sbss/.sdata section the symbol is in\n"));
> +  fprintf (file, _("\
> +  --no-user-defined-sdata-sections\n\
> +                              When processing a gp relative relocation against a symbol\n\
> +                              in a .sdata_<num>/.sbss_<num> section use the gp value\n\
> +                              based on the address of the _gp symbol\n"));
>  '

 I find this way too verbose.  It seems to me like almost an entry for the 
manual rather than a terse reminder for the forgetful, which the `--help' 
option summary is supposed to be.  Have a look at the other descriptions 
and make these two similarly brief as well.

 Conversely a manual update is missing altogether and these descriptions 
will be a good starting point.

> @@ -288,6 +303,14 @@ PARSE_AND_LIST_ARGS_CASES='
>      case OPTION_NO_COMPACT_BRANCHES:
>        compact_branches = false;
>        break;
> +
> +    case OPTION_USER_DEF_SDATA_SECTIONS:
> +      user_def_sdata_sections = true;
> +      break;
> +
> +    case OPTION_NO_USER_DEF_SDATA_SECTIONS:
> +      user_def_sdata_sections = false;
> +      break;
>  '

 OK, record the options supplied.

> diff --git a/ld/ldlex.h b/ld/ldlex.h
> index 85e06b6fcc4..52d5352de56 100644
> --- a/ld/ldlex.h
> +++ b/ld/ldlex.h
> @@ -306,6 +306,8 @@ enum option_values
>    OPTION_NO_IGNORE_BRANCH_ISA,
>    OPTION_COMPACT_BRANCHES,
>    OPTION_NO_COMPACT_BRANCHES,
> +  OPTION_USER_DEF_SDATA_SECTIONS,
> +  OPTION_NO_USER_DEF_SDATA_SECTIONS,

 OK, new enumeration constants corresponding to the new options.

 Thank you for your submission.  Please update and repost.

  Maciej


More information about the Binutils mailing list