aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf64-alpha.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elf64-alpha.c')
-rw-r--r--bfd/elf64-alpha.c83
1 files changed, 82 insertions, 1 deletions
diff --git a/bfd/elf64-alpha.c b/bfd/elf64-alpha.c
index ef6e853..6df126a 100644
--- a/bfd/elf64-alpha.c
+++ b/bfd/elf64-alpha.c
@@ -732,7 +732,22 @@ static reloc_howto_type elf64_alpha_howto_table[] =
false,
0,
0,
- true)
+ true),
+
+ /* A 21 bit branch that adjusts for gp loads. */
+ HOWTO (R_ALPHA_BRSGP, /* type */
+ 2, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 21, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ 0, /* special_function */
+ "BRSGP", /* name */
+ false, /* partial_inplace */
+ 0x1fffff, /* src_mask */
+ 0x1fffff, /* dst_mask */
+ true), /* pcrel_offset */
};
/* A relocation function which doesn't do anything. */
@@ -886,6 +901,7 @@ static const struct elf_reloc_map elf64_alpha_reloc_map[] =
{BFD_RELOC_ALPHA_GPREL_HI16, R_ALPHA_GPRELHIGH},
{BFD_RELOC_ALPHA_GPREL_LO16, R_ALPHA_GPRELLOW},
{BFD_RELOC_GPREL16, R_ALPHA_GPREL16},
+ {BFD_RELOC_ALPHA_BRSGP, R_ALPHA_BRSGP},
};
/* Given a BFD reloc type, return a HOWTO structure. */
@@ -2414,6 +2430,7 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
case R_ALPHA_GPREL32:
case R_ALPHA_GPRELHIGH:
case R_ALPHA_GPRELLOW:
+ case R_ALPHA_BRSGP:
/* We don't actually use the .got here, but the sections must
be created before the linker maps input sections to output
sections. */
@@ -3555,6 +3572,70 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
addend -= 4;
goto default_reloc;
+ case R_ALPHA_BRSGP:
+ {
+ int other;
+ const char *name;
+
+ /* The regular PC-relative stuff measures from the start of
+ the instruction rather than the end. */
+ addend -= 4;
+
+ /* The source and destination gp must be the same. */
+ if (h != NULL
+ && gotobj != alpha_elf_tdata (sec->owner)->gotobj)
+ {
+ if (h != NULL)
+ name = h->root.root.root.string;
+ else
+ {
+ name = (bfd_elf_string_from_elf_section
+ (input_bfd, symtab_hdr->sh_link, sym->st_name));
+ if (name == NULL)
+ name = _("<unknown>");
+ else if (name[0] == 0)
+ name = bfd_section_name (input_bfd, sec);
+ }
+ (*_bfd_error_handler)
+ (_("%s: change in gp: BRSGP %s"),
+ bfd_archive_filename (input_bfd), name);
+ ret_val = false;
+ }
+
+ /* The symbol should be marked either NOPV or STD_GPLOAD. */
+ if (h != NULL)
+ other = h->root.other;
+ else
+ other = sym->st_other;
+ switch (other & STO_ALPHA_STD_GPLOAD)
+ {
+ case STO_ALPHA_NOPV:
+ break;
+ case STO_ALPHA_STD_GPLOAD:
+ addend += 8;
+ break;
+ default:
+ if (h != NULL)
+ name = h->root.root.root.string;
+ else
+ {
+ name = (bfd_elf_string_from_elf_section
+ (input_bfd, symtab_hdr->sh_link, sym->st_name));
+ if (name == NULL)
+ name = _("<unknown>");
+ else if (name[0] == 0)
+ name = bfd_section_name (input_bfd, sec);
+ }
+ (*_bfd_error_handler)
+ (_("%s: !samegp reloc against symbol without .prologue: %s"),
+ bfd_archive_filename (input_bfd), name);
+ ret_val = false;
+ break;
+ }
+
+ goto default_reloc;
+ }
+
case R_ALPHA_REFLONG:
case R_ALPHA_REFQUAD:
{