[07/21] Add --user-defined-sdata-sections

Message ID 20250402121759.1962001-8-jovan.dmitrovic@htecgroup.com
State New
Headers
Series Integrate MIPS-Specific Support |

Commit Message

Jovan Dmitrovic April 2, 2025, 12:18 p.m. UTC
  From: Matthew Fortune <matthew.fortune@imgtec.com>

This feature has never been used. It was not properly documented at the
usual places or tested. Posting the entire documentation that Matthew
provided to the customer in to the commit message, for lack of better
alternative:

    Introduction
    ============

This documentation describes how a user can specify which small data
area is used for each data item. This allows different software
contexts to use different small data areas. There are three stages:

1. GCC is informed which small data area to use.
2. The linker script places each small data area around a specifically
named anchor.
3. System code sets up GP to contain the correct value for each
software context.

    Compiling/Assembling
    ====================

    Automatic data placement
    ------------------------
The -mgpopt and -G<num> behaviour is modified by the -msdata-num=<num>
option to tell the compiler to use a numbered small data area instead of
the generic area.
<num> can be 0 to 999.

    e.g. mips-mti-elf-gcc -mgpopt -G4 -msdata-num=4

GP relative addressing will be used for automatically chosen data items
as usual.

    Manual data placement
    ---------------------

The section attribute can be used to place data into a numbered small
data section.

       int a __attribute__((section(".sdata_1"))) = 9;
       int b __attribute__((section(".sdata_2")));

    e.g. mips-mti-elf-gcc -mgpopt -msdata-num=<any>

When using the -msdata-num=<num> option then these data items will be
accessed via GP relative addressing. This will happen even if the number
given to the compiler option does not match the numbered data section in
the section attribute.  It is the user's responsibility to only access
data from one small data area in each software context. If the
-msdata-num=<num> option is not given then global addressing will be
used for these variables.

    Manual data placement with a list
    ---------------------------------

The -moptimize-sdata-list=<file> option is modified by the
-msdata-num=<num> option to use a numbered small data section for the
list of symbols instead of the generic area.

    e.g. mips-mti-elf-gcc -moptimize-sdata-list=sdata.lst -msdata-num=4

    Linking
    =======

Add the --user-defined-sdata-sections option to the link command to
perform multi small data area linking. This will need prefixing with
"-Wl," if passed via the 'mips-mti-elf-gcc' compiler driver.

The linker script also needs modifying to place the multiple small data
sections and define the 'gp' anchors.  Each numbered area requires a
corresponding numbered anchor defined like this:

      . = ALIGN(8);
      _gp_1 = . + 0x8000;
      .sdata_1 : {
        *(.sdata_1)
        *(.sdata_1.*)
      }

      . = ALIGN(4);
      _fsbss_1 = .;
      .sbss_1 : {
        *(.sbss_1)
        *(.sbss_1.*)
      }

      . = ALIGN(4);
      _esbss_1 = .;

The range _fsbss_1 to _esbss_1 must be cleared to zero by CRT code
similarly to the normal bss area.

    Runtime
    =======

System code needs to set the 'gp' register to the correct _gp_<num>
value for each software context. There are no runtime checks to
ensure that the correct GP value is used for each data item.

Context switching code may need to save/restore GP if contexts
running on the same VPE use different areas or contexts migrate
between VPEs or cores.

Cherry-picked 236e648
from https://github.com/MIPS/binutils-gdb

Signed-off-by: Matthew Fortune <matthew.fortune@mips.com>
Signed-off-by: Faraz Shahbazker <fshahbazker@wavecomp.com>
Signed-off-by: Milica Matic <milica.matic@htecgroup.com>
---
 bfd/elfxx-mips.c        | 58 ++++++++++++++++++++++++++++++++++++++++-
 bfd/elfxx-mips.h        |  2 ++
 ld/emultempl/mipself.em | 23 ++++++++++++++++
 ld/ldlex.h              |  2 ++
 4 files changed, 84 insertions(+), 1 deletion(-)
  

Patch

diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index 6345e782776..a895d08e009 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -464,6 +464,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
+     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.  */
+  bool user_def_sdata_sections;
+
   /* True if we're generating code for VxWorks.  */
   bool is_vxworks;
 
@@ -606,6 +612,8 @@  struct mips_elf_obj_tdata
   asection *elf_data_section;
   asection *elf_text_section;
 
+  bfd_signed_vma sdata_section[1000];
+
   struct mips_hi16 *mips_hi16_list;
 };
 
@@ -5604,6 +5612,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;
 
   dynobj = elf_hash_table (info)->dynobj;
   htab = mips_elf_hash_table (info);
@@ -6000,6 +6009,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]);
+
+      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);
+	      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
      to R_MIPS_GOT_DISP/R_MICROMIPS_GOT_DISP.  The addend is applied by the
      corresponding R_MIPS_GOT_OFST/R_MICROMIPS_GOT_OFST.  */
@@ -7597,7 +7627,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)
 	hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
       else if (strcmp (name, ".srdata") == 0)
 	hdr->sh_flags |= SHF_ALLOC | SHF_MIPS_GPREL;
@@ -7889,7 +7920,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
 	   || strcmp (name, ".lit4") == 0
 	   || strcmp (name, ".lit8") == 0)
     hdr->sh_flags |= SHF_MIPS_GPREL;
@@ -14832,6 +14865,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;
+}
+
 
 /* Structure for saying that BFD machine EXTENSION extends BASE.  */
 
@@ -15182,6 +15221,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++)
+    {
+      struct bfd_link_hash_entry *h;
+      char gp_name[8];
+      bfd_signed_vma gp_vma = -1;
+
+      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;
+    }
+
   /* Get a value for the GP register.  */
   if (elf_gp (abfd) == 0)
     {
diff --git a/bfd/elfxx-mips.h b/bfd/elfxx-mips.h
index 85fb3da78f8..6e5843b565b 100644
--- a/bfd/elfxx-mips.h
+++ b/bfd/elfxx-mips.h
@@ -171,6 +171,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);
 extern bool _bfd_mips_elf_init_stubs
   (struct bfd_link_info *,
    asection *(*) (const char *, asection *, asection *));
diff --git a/ld/emultempl/mipself.em b/ld/emultempl/mipself.em
index 3259f654b36..b9bea3756b2 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;
 
 struct hook_stub_info
 {
@@ -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);
       _bfd_mips_elf_init_stubs (&link_info, mips_add_stub_section);
     }
 }
@@ -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 },
 '
 
 PARSE_AND_LIST_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"));
 '
 
 PARSE_AND_LIST_ARGS_CASES='
@@ -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;
 '
 
 LDEMUL_BEFORE_ALLOCATION=mips_before_allocation
diff --git a/ld/ldlex.h b/ld/ldlex.h
index bb431101fb2..c86352553bf 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,
   /* Used by emultempl/msp430.em.  */
   OPTION_CODE_REGION,
   OPTION_DATA_REGION,