[PATCH 3 07/16] MIPS: Add user-defined sdata sections
Jovan Dmitrovic
jovan.dmitrovic@htecgroup.com
Thu Feb 5 16:23:56 GMT 2026
From: Matthew Fortune <matthew.fortune@imgtec.com>
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.
---
bfd/elfxx-mips.c | 59 ++++++++++++++++++++++++++++++++++++++++-
bfd/elfxx-mips.h | 2 ++
ld/emultempl/mipself.em | 23 ++++++++++++++++
ld/ldlex.h | 2 ++
4 files changed, 85 insertions(+), 1 deletion(-)
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
+ 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 already reported the small-data section overflow. */
bool small_data_overflow_reported;
@@ -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;
+ bfd_signed_vma sdata_section[1000];
};
/* Get MIPS ELF private object data from BFD's tdata. */
@@ -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;
dynobj = elf_hash_table (info)->dynobj;
htab = mips_elf_hash_table (info);
@@ -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]);
+
+ 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. */
@@ -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)
hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
else if (strcmp (name, ".srdata") == 0)
hdr->sh_flags |= SHF_ALLOC | SHF_MIPS_GPREL;
@@ -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
|| strcmp (name, ".lit4") == 0
|| strcmp (name, ".lit8") == 0)
hdr->sh_flags |= SHF_MIPS_GPREL;
@@ -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;
+}
+
/* Structure for saying that BFD machine EXTENSION extends BASE. */
@@ -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++)
+ {
+ 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 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);
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 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;
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 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,
/* Used by emultempl/msp430.em. */
OPTION_CODE_REGION,
OPTION_DATA_REGION,
--
2.34.1
More information about the Binutils
mailing list