@@ -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)
{
@@ -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 *));
@@ -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
@@ -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,