#define SH64_ELF64
#include "bfd.h"
#include "sysdep.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf/sh.h"
#define DATALABEL_SUFFIX " DL"
#define GOT_BIAS (-((long)-32768))
#define PLT_ENTRY_SIZE 64
#define elf_sh64_sizeof_plt(info) PLT_ENTRY_SIZE
#define elf_sh64_plt_plt0_offset(info) 32
#define elf_sh64_plt0_gotplt_offset(info) 0
#define elf_sh64_plt_temp_offset(info) 33
#define elf_sh64_plt_symbol_offset(info) 0
#define elf_sh64_plt_reloc_offset(info) (info->shared ? 52 : 44)
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1"
struct elf_sh64_pcrel_relocs_copied
{
struct elf_sh64_pcrel_relocs_copied *next;
asection *section;
bfd_size_type count;
};
struct elf_sh64_link_hash_entry
{
struct elf_link_hash_entry root;
bfd_vma datalabel_got_offset;
struct elf_sh64_pcrel_relocs_copied *pcrel_relocs_copied;
};
struct elf_sh64_link_hash_table
{
struct elf_link_hash_table root;
};
#define sh64_elf64_link_hash_traverse(table, func, info) \
(elf_link_hash_traverse \
(&(table)->root, \
(bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \
(info)))
#define sh64_elf64_hash_table(p) \
((struct elf_sh64_link_hash_table *) ((p)->hash))
static bfd_reloc_status_type sh_elf64_ignore_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_reloc_status_type sh_elf64_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static reloc_howto_type sh_elf64_howto_table[] = {
HOWTO (R_SH_NONE,
0,
0,
0,
FALSE,
0,
complain_overflow_dont,
sh_elf64_ignore_reloc,
"R_SH_NONE",
FALSE,
0,
0,
FALSE),
HOWTO (R_SH_DIR32,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
sh_elf64_reloc,
"R_SH_DIR32",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_SH_REL32,
0,
2,
32,
TRUE,
0,
complain_overflow_signed,
sh_elf64_ignore_reloc,
"R_SH_REL32",
FALSE,
0,
0xffffffff,
TRUE),
EMPTY_HOWTO (3),
EMPTY_HOWTO (4),
EMPTY_HOWTO (5),
EMPTY_HOWTO (6),
EMPTY_HOWTO (7),
EMPTY_HOWTO (8),
EMPTY_HOWTO (9),
EMPTY_HOWTO (10),
EMPTY_HOWTO (11),
EMPTY_HOWTO (12),
EMPTY_HOWTO (13),
EMPTY_HOWTO (14),
EMPTY_HOWTO (15),
EMPTY_HOWTO (16),
EMPTY_HOWTO (17),
EMPTY_HOWTO (18),
EMPTY_HOWTO (19),
EMPTY_HOWTO (20),
EMPTY_HOWTO (21),
EMPTY_HOWTO (22),
EMPTY_HOWTO (23),
EMPTY_HOWTO (24),
HOWTO (R_SH_SWITCH16,
0,
1,
16,
FALSE,
0,
complain_overflow_unsigned,
sh_elf64_ignore_reloc,
"R_SH_SWITCH16",
FALSE,
0,
0,
TRUE),
HOWTO (R_SH_SWITCH32,
0,
2,
32,
FALSE,
0,
complain_overflow_unsigned,
sh_elf64_ignore_reloc,
"R_SH_SWITCH32",
FALSE,
0,
0,
TRUE),
EMPTY_HOWTO (27),
EMPTY_HOWTO (28),
EMPTY_HOWTO (29),
EMPTY_HOWTO (30),
EMPTY_HOWTO (31),
EMPTY_HOWTO (32),
HOWTO (R_SH_SWITCH8,
0,
0,
8,
FALSE,
0,
complain_overflow_unsigned,
sh_elf64_ignore_reloc,
"R_SH_SWITCH8",
FALSE,
0,
0,
TRUE),
HOWTO (R_SH_GNU_VTINHERIT,
0,
2,
0,
FALSE,
0,
complain_overflow_dont,
NULL,
"R_SH_GNU_VTINHERIT",
FALSE,
0,
0,
FALSE),
HOWTO (R_SH_GNU_VTENTRY,
0,
2,
0,
FALSE,
0,
complain_overflow_dont,
_bfd_elf_rel_vtable_reloc_fn,
"R_SH_GNU_VTENTRY",
FALSE,
0,
0,
FALSE),
EMPTY_HOWTO (36),
EMPTY_HOWTO (37),
EMPTY_HOWTO (38),
EMPTY_HOWTO (39),
EMPTY_HOWTO (40),
EMPTY_HOWTO (41),
EMPTY_HOWTO (42),
EMPTY_HOWTO (43),
EMPTY_HOWTO (44),
HOWTO (R_SH_DIR5U,
0,
2,
5,
FALSE,
10,
complain_overflow_unsigned,
bfd_elf_generic_reloc,
"R_SH_DIR5U",
FALSE,
0,
0xfc00,
FALSE),
HOWTO (R_SH_DIR6U,
0,
2,
6,
FALSE,
10,
complain_overflow_unsigned,
bfd_elf_generic_reloc,
"R_SH_DIR6U",
FALSE,
0,
0xfc00,
FALSE),
HOWTO (R_SH_DIR6S,
0,
2,
6,
FALSE,
10,
complain_overflow_signed,
bfd_elf_generic_reloc,
"R_SH_DIR6S",
FALSE,
0,
0xfc00,
FALSE),
HOWTO (R_SH_DIR10S,
0,
2,
10,
FALSE,
10,
complain_overflow_signed,
bfd_elf_generic_reloc,
"R_SH_DIR10S",
FALSE,
0,
0xffc00,
FALSE),
HOWTO (R_SH_DIR10SW,
1,
2,
11,
FALSE,
10,
complain_overflow_signed,
bfd_elf_generic_reloc,
"R_SH_DIR10SW",
FALSE,
0,
0xffc00,
FALSE),
HOWTO (R_SH_DIR10SL,
2,
2,
12,
FALSE,
10,
complain_overflow_signed,
bfd_elf_generic_reloc,
"R_SH_DIR10SL",
FALSE,
0,
0xffc00,
FALSE),
HOWTO (R_SH_DIR10SQ,
3,
2,
13,
FALSE,
10,
complain_overflow_signed,
bfd_elf_generic_reloc,
"R_SH_DIR10SQ",
FALSE,
0,
0xffc00,
FALSE),
EMPTY_HOWTO (52),
EMPTY_HOWTO (53),
EMPTY_HOWTO (54),
EMPTY_HOWTO (55),
EMPTY_HOWTO (56),
EMPTY_HOWTO (57),
EMPTY_HOWTO (58),
EMPTY_HOWTO (59),
EMPTY_HOWTO (60),
EMPTY_HOWTO (61),
EMPTY_HOWTO (62),
EMPTY_HOWTO (63),
EMPTY_HOWTO (64),
EMPTY_HOWTO (65),
EMPTY_HOWTO (66),
EMPTY_HOWTO (67),
EMPTY_HOWTO (68),
EMPTY_HOWTO (69),
EMPTY_HOWTO (70),
EMPTY_HOWTO (71),
EMPTY_HOWTO (72),
EMPTY_HOWTO (73),
EMPTY_HOWTO (74),
EMPTY_HOWTO (75),
EMPTY_HOWTO (76),
EMPTY_HOWTO (77),
EMPTY_HOWTO (78),
EMPTY_HOWTO (79),
EMPTY_HOWTO (80),
EMPTY_HOWTO (81),
EMPTY_HOWTO (82),
EMPTY_HOWTO (83),
EMPTY_HOWTO (84),
EMPTY_HOWTO (85),
EMPTY_HOWTO (86),
EMPTY_HOWTO (87),
EMPTY_HOWTO (88),
EMPTY_HOWTO (89),
EMPTY_HOWTO (90),
EMPTY_HOWTO (91),
EMPTY_HOWTO (92),
EMPTY_HOWTO (93),
EMPTY_HOWTO (94),
EMPTY_HOWTO (95),
EMPTY_HOWTO (96),
EMPTY_HOWTO (97),
EMPTY_HOWTO (98),
EMPTY_HOWTO (99),
EMPTY_HOWTO (100),
EMPTY_HOWTO (101),
EMPTY_HOWTO (102),
EMPTY_HOWTO (103),
EMPTY_HOWTO (104),
EMPTY_HOWTO (105),
EMPTY_HOWTO (106),
EMPTY_HOWTO (107),
EMPTY_HOWTO (108),
EMPTY_HOWTO (109),
EMPTY_HOWTO (110),
EMPTY_HOWTO (111),
EMPTY_HOWTO (112),
EMPTY_HOWTO (113),
EMPTY_HOWTO (114),
EMPTY_HOWTO (115),
EMPTY_HOWTO (116),
EMPTY_HOWTO (117),
EMPTY_HOWTO (118),
EMPTY_HOWTO (119),
EMPTY_HOWTO (120),
EMPTY_HOWTO (121),
EMPTY_HOWTO (122),
EMPTY_HOWTO (123),
EMPTY_HOWTO (124),
EMPTY_HOWTO (125),
EMPTY_HOWTO (126),
EMPTY_HOWTO (127),
EMPTY_HOWTO (128),
EMPTY_HOWTO (129),
EMPTY_HOWTO (130),
EMPTY_HOWTO (131),
EMPTY_HOWTO (132),
EMPTY_HOWTO (133),
EMPTY_HOWTO (134),
EMPTY_HOWTO (135),
EMPTY_HOWTO (136),
EMPTY_HOWTO (137),
EMPTY_HOWTO (138),
EMPTY_HOWTO (139),
EMPTY_HOWTO (140),
EMPTY_HOWTO (141),
EMPTY_HOWTO (142),
EMPTY_HOWTO (143),
EMPTY_HOWTO (144),
EMPTY_HOWTO (145),
EMPTY_HOWTO (146),
EMPTY_HOWTO (147),
EMPTY_HOWTO (148),
EMPTY_HOWTO (149),
EMPTY_HOWTO (150),
EMPTY_HOWTO (151),
EMPTY_HOWTO (152),
EMPTY_HOWTO (153),
EMPTY_HOWTO (154),
EMPTY_HOWTO (155),
EMPTY_HOWTO (156),
EMPTY_HOWTO (157),
EMPTY_HOWTO (158),
EMPTY_HOWTO (159),
EMPTY_HOWTO (160),
EMPTY_HOWTO (161),
EMPTY_HOWTO (162),
EMPTY_HOWTO (163),
EMPTY_HOWTO (164),
EMPTY_HOWTO (165),
EMPTY_HOWTO (166),
EMPTY_HOWTO (167),
EMPTY_HOWTO (168),
HOWTO (R_SH_GOT_LOW16,
0,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOT_LOW16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_GOT_MEDLOW16,
16,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOT_MEDLOW16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_GOT_MEDHI16,
32,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOT_MEDHI16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_GOT_HI16,
48,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOT_HI16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_GOTPLT_LOW16,
0,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOTPLT_LOW16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_GOTPLT_MEDLOW16,
16,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOTPLT_MEDLOW16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_GOTPLT_MEDHI16,
32,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOTPLT_MEDHI16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_GOTPLT_HI16,
48,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOTPLT_HI16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_PLT_LOW16,
0,
2,
64,
TRUE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_PLT_LOW16",
FALSE,
0,
0x3fffc00,
TRUE),
HOWTO (R_SH_PLT_MEDLOW16,
16,
2,
64,
TRUE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_PLT_MEDLOW16",
FALSE,
0,
0x3fffc00,
TRUE),
HOWTO (R_SH_PLT_MEDHI16,
32,
2,
64,
TRUE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_PLT_MEDHI16",
FALSE,
0,
0x3fffc00,
TRUE),
HOWTO (R_SH_PLT_HI16,
48,
2,
64,
TRUE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_PLT_HI16",
FALSE,
0,
0x3fffc00,
TRUE),
HOWTO (R_SH_GOTOFF_LOW16,
0,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOTOFF_LOW16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_GOTOFF_MEDLOW16,
16,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOTOFF_MEDLOW16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_GOTOFF_MEDHI16,
32,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOTOFF_MEDHI16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_GOTOFF_HI16,
48,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOTOFF_HI16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_GOTPC_LOW16,
0,
2,
64,
TRUE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOTPC_LOW16",
FALSE,
0,
0x3fffc00,
TRUE),
HOWTO (R_SH_GOTPC_MEDLOW16,
16,
2,
64,
TRUE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOTPC_MEDLOW16",
FALSE,
0,
0x3fffc00,
TRUE),
HOWTO (R_SH_GOTPC_MEDHI16,
32,
2,
64,
TRUE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOTPC_MEDHI16",
FALSE,
0,
0x3fffc00,
TRUE),
HOWTO (R_SH_GOTPC_HI16,
48,
2,
64,
TRUE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GOTPC_HI16",
FALSE,
0,
0x3fffc00,
TRUE),
HOWTO (R_SH_GOT10BY4,
2,
2,
12,
FALSE,
10,
complain_overflow_signed,
bfd_elf_generic_reloc,
"R_SH_GOT10BY4",
FALSE,
0,
0xffc00,
FALSE),
HOWTO (R_SH_GOTPLT10BY4,
2,
2,
12,
FALSE,
10,
complain_overflow_signed,
bfd_elf_generic_reloc,
"R_SH_GOTPLT10BY4",
FALSE,
0,
0xffc00,
FALSE),
HOWTO (R_SH_GOT10BY8,
3,
2,
13,
FALSE,
10,
complain_overflow_signed,
bfd_elf_generic_reloc,
"R_SH_GOT10BY8",
FALSE,
0,
0xffc00,
FALSE),
HOWTO (R_SH_GOTPLT10BY8,
3,
2,
13,
FALSE,
10,
complain_overflow_signed,
bfd_elf_generic_reloc,
"R_SH_GOTPLT10BY8",
FALSE,
0,
0xffc00,
FALSE),
HOWTO (R_SH_COPY64,
0,
4,
64,
FALSE,
0,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_COPY64",
FALSE,
0,
((bfd_vma) 0) - 1,
FALSE),
HOWTO (R_SH_GLOB_DAT64,
0,
4,
64,
FALSE,
0,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_GLOB_DAT64",
FALSE,
0,
((bfd_vma) 0) - 1,
FALSE),
HOWTO (R_SH_JMP_SLOT64,
0,
4,
64,
FALSE,
0,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_JMP_SLOT64",
FALSE,
0,
((bfd_vma) 0) - 1,
FALSE),
HOWTO (R_SH_RELATIVE64,
0,
4,
64,
FALSE,
0,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_RELATIVE64",
FALSE,
0,
((bfd_vma) 0) - 1,
FALSE),
EMPTY_HOWTO (197),
EMPTY_HOWTO (198),
EMPTY_HOWTO (199),
EMPTY_HOWTO (200),
EMPTY_HOWTO (201),
EMPTY_HOWTO (202),
EMPTY_HOWTO (203),
EMPTY_HOWTO (204),
EMPTY_HOWTO (205),
EMPTY_HOWTO (206),
EMPTY_HOWTO (207),
EMPTY_HOWTO (208),
EMPTY_HOWTO (209),
EMPTY_HOWTO (210),
EMPTY_HOWTO (211),
EMPTY_HOWTO (212),
EMPTY_HOWTO (213),
EMPTY_HOWTO (214),
EMPTY_HOWTO (215),
EMPTY_HOWTO (216),
EMPTY_HOWTO (217),
EMPTY_HOWTO (218),
EMPTY_HOWTO (219),
EMPTY_HOWTO (220),
EMPTY_HOWTO (221),
EMPTY_HOWTO (222),
EMPTY_HOWTO (223),
EMPTY_HOWTO (224),
EMPTY_HOWTO (225),
EMPTY_HOWTO (226),
EMPTY_HOWTO (227),
EMPTY_HOWTO (228),
EMPTY_HOWTO (229),
EMPTY_HOWTO (230),
EMPTY_HOWTO (231),
EMPTY_HOWTO (232),
EMPTY_HOWTO (233),
EMPTY_HOWTO (234),
EMPTY_HOWTO (235),
EMPTY_HOWTO (236),
EMPTY_HOWTO (237),
EMPTY_HOWTO (238),
EMPTY_HOWTO (239),
EMPTY_HOWTO (240),
EMPTY_HOWTO (241),
HOWTO (R_SH_SHMEDIA_CODE,
0,
1,
0,
FALSE,
0,
complain_overflow_unsigned,
sh_elf64_ignore_reloc,
"R_SH_SHMEDIA_CODE",
FALSE,
0,
0,
FALSE),
HOWTO (R_SH_PT_16,
2,
2,
18,
TRUE,
10,
complain_overflow_signed,
bfd_elf_generic_reloc,
"R_SH_PT_16",
FALSE,
0,
0x3fffc00,
TRUE),
HOWTO (R_SH_IMMS16,
0,
2,
16,
FALSE,
10,
complain_overflow_signed,
bfd_elf_generic_reloc,
"R_SH_IMMS16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_IMMU16,
0,
2,
16,
FALSE,
10,
complain_overflow_unsigned,
bfd_elf_generic_reloc,
"R_SH_IMMU16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_IMM_LOW16,
0,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_IMM_LOW16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_IMM_LOW16_PCREL,
0,
2,
64,
TRUE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_IMM_LOW16_PCREL",
FALSE,
0,
0x3fffc00,
TRUE),
HOWTO (R_SH_IMM_MEDLOW16,
16,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_IMM_MEDLOW16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_IMM_MEDLOW16_PCREL,
16,
2,
64,
TRUE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_IMM_MEDLOW16_PCREL",
FALSE,
0,
0x3fffc00,
TRUE),
HOWTO (R_SH_IMM_MEDHI16,
32,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_IMM_MEDHI16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_IMM_MEDHI16_PCREL,
32,
2,
64,
TRUE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_IMM_MEDHI16_PCREL",
FALSE,
0,
0x3fffc00,
TRUE),
HOWTO (R_SH_IMM_HI16,
48,
2,
64,
FALSE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_IMM_HI16",
FALSE,
0,
0x3fffc00,
FALSE),
HOWTO (R_SH_IMM_HI16_PCREL,
48,
2,
64,
TRUE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_IMM_HI16_PCREL",
FALSE,
0,
0x3fffc00,
TRUE),
HOWTO (R_SH_64,
0,
4,
64,
FALSE,
0,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_64",
FALSE,
0,
((bfd_vma) 0) - 1,
FALSE),
HOWTO (R_SH_64_PCREL,
48,
2,
64,
TRUE,
10,
complain_overflow_dont,
bfd_elf_generic_reloc,
"R_SH_64_PCREL",
FALSE,
0,
((bfd_vma) 0) - 1,
TRUE),
};
static bfd_reloc_status_type
sh_elf64_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
asymbol *symbol ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED, asection *input_section,
bfd *output_bfd,
char **error_message ATTRIBUTE_UNUSED)
{
if (output_bfd != NULL)
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
}
static bfd_reloc_status_type
sh_elf64_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol_in,
void *data, asection *input_section, bfd *output_bfd,
char **error_message ATTRIBUTE_UNUSED)
{
unsigned long insn;
bfd_vma sym_value;
enum elf_sh_reloc_type r_type;
bfd_vma addr = reloc_entry->address;
bfd_byte *hit_data = addr + (bfd_byte *) data;
r_type = (enum elf_sh_reloc_type) reloc_entry->howto->type;
if (output_bfd != NULL)
{
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
}
if (symbol_in != NULL
&& bfd_is_und_section (symbol_in->section))
return bfd_reloc_undefined;
if (bfd_is_com_section (symbol_in->section))
sym_value = 0;
else
sym_value = (symbol_in->value +
symbol_in->section->output_section->vma +
symbol_in->section->output_offset);
switch (r_type)
{
case R_SH_DIR32:
insn = bfd_get_32 (abfd, hit_data);
insn += sym_value + reloc_entry->addend;
bfd_put_32 (abfd, insn, hit_data);
break;
default:
abort ();
break;
}
return bfd_reloc_ok;
}
struct elf_reloc_map
{
bfd_reloc_code_real_type bfd_reloc_val;
unsigned char elf_reloc_val;
};
static const struct elf_reloc_map sh64_reloc_map[] =
{
{ BFD_RELOC_NONE, R_SH_NONE },
{ BFD_RELOC_32, R_SH_DIR32 },
{ BFD_RELOC_CTOR, R_SH_DIR32 },
{ BFD_RELOC_32_PCREL, R_SH_REL32 },
{ BFD_RELOC_8_PCREL, R_SH_SWITCH8 },
{ BFD_RELOC_SH_SWITCH16, R_SH_SWITCH16 },
{ BFD_RELOC_SH_SWITCH32, R_SH_SWITCH32 },
{ BFD_RELOC_VTABLE_INHERIT, R_SH_GNU_VTINHERIT },
{ BFD_RELOC_VTABLE_ENTRY, R_SH_GNU_VTENTRY },
{ BFD_RELOC_SH_GOT_LOW16, R_SH_GOT_LOW16 },
{ BFD_RELOC_SH_GOT_MEDLOW16, R_SH_GOT_MEDLOW16 },
{ BFD_RELOC_SH_GOT_MEDHI16, R_SH_GOT_MEDHI16 },
{ BFD_RELOC_SH_GOT_HI16, R_SH_GOT_HI16 },
{ BFD_RELOC_SH_GOTPLT_LOW16, R_SH_GOTPLT_LOW16 },
{ BFD_RELOC_SH_GOTPLT_MEDLOW16, R_SH_GOTPLT_MEDLOW16 },
{ BFD_RELOC_SH_GOTPLT_MEDHI16, R_SH_GOTPLT_MEDHI16 },
{ BFD_RELOC_SH_GOTPLT_HI16, R_SH_GOTPLT_HI16 },
{ BFD_RELOC_SH_PLT_LOW16, R_SH_PLT_LOW16 },
{ BFD_RELOC_SH_PLT_MEDLOW16, R_SH_PLT_MEDLOW16 },
{ BFD_RELOC_SH_PLT_MEDHI16, R_SH_PLT_MEDHI16 },
{ BFD_RELOC_SH_PLT_HI16, R_SH_PLT_HI16 },
{ BFD_RELOC_SH_GOTOFF_LOW16, R_SH_GOTOFF_LOW16 },
{ BFD_RELOC_SH_GOTOFF_MEDLOW16, R_SH_GOTOFF_MEDLOW16 },
{ BFD_RELOC_SH_GOTOFF_MEDHI16, R_SH_GOTOFF_MEDHI16 },
{ BFD_RELOC_SH_GOTOFF_HI16, R_SH_GOTOFF_HI16 },
{ BFD_RELOC_SH_GOTPC_LOW16, R_SH_GOTPC_LOW16 },
{ BFD_RELOC_SH_GOTPC_MEDLOW16, R_SH_GOTPC_MEDLOW16 },
{ BFD_RELOC_SH_GOTPC_MEDHI16, R_SH_GOTPC_MEDHI16 },
{ BFD_RELOC_SH_GOTPC_HI16, R_SH_GOTPC_HI16 },
{ BFD_RELOC_SH_COPY64, R_SH_COPY64 },
{ BFD_RELOC_SH_GLOB_DAT64, R_SH_GLOB_DAT64 },
{ BFD_RELOC_SH_JMP_SLOT64, R_SH_JMP_SLOT64 },
{ BFD_RELOC_SH_RELATIVE64, R_SH_RELATIVE64 },
{ BFD_RELOC_SH_GOT10BY4, R_SH_GOT10BY4 },
{ BFD_RELOC_SH_GOT10BY8, R_SH_GOT10BY8 },
{ BFD_RELOC_SH_GOTPLT10BY4, R_SH_GOTPLT10BY4 },
{ BFD_RELOC_SH_GOTPLT10BY8, R_SH_GOTPLT10BY8 },
{ BFD_RELOC_SH_PT_16, R_SH_PT_16 },
{ BFD_RELOC_SH_SHMEDIA_CODE, R_SH_SHMEDIA_CODE },
{ BFD_RELOC_SH_IMMU5, R_SH_DIR5U },
{ BFD_RELOC_SH_IMMS6, R_SH_DIR6S },
{ BFD_RELOC_SH_IMMU6, R_SH_DIR6U },
{ BFD_RELOC_SH_IMMS10, R_SH_DIR10S },
{ BFD_RELOC_SH_IMMS10BY2, R_SH_DIR10SW },
{ BFD_RELOC_SH_IMMS10BY4, R_SH_DIR10SL },
{ BFD_RELOC_SH_IMMS10BY8, R_SH_DIR10SQ },
{ BFD_RELOC_SH_IMMS16, R_SH_IMMS16 },
{ BFD_RELOC_SH_IMMU16, R_SH_IMMU16 },
{ BFD_RELOC_SH_IMM_LOW16, R_SH_IMM_LOW16 },
{ BFD_RELOC_SH_IMM_LOW16_PCREL, R_SH_IMM_LOW16_PCREL },
{ BFD_RELOC_SH_IMM_MEDLOW16, R_SH_IMM_MEDLOW16 },
{ BFD_RELOC_SH_IMM_MEDLOW16_PCREL, R_SH_IMM_MEDLOW16_PCREL },
{ BFD_RELOC_SH_IMM_MEDHI16, R_SH_IMM_MEDHI16 },
{ BFD_RELOC_SH_IMM_MEDHI16_PCREL, R_SH_IMM_MEDHI16_PCREL },
{ BFD_RELOC_SH_IMM_HI16, R_SH_IMM_HI16 },
{ BFD_RELOC_SH_IMM_HI16_PCREL, R_SH_IMM_HI16_PCREL },
{ BFD_RELOC_64, R_SH_64 },
{ BFD_RELOC_64_PCREL, R_SH_64_PCREL },
};
static reloc_howto_type *
sh_elf64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
bfd_reloc_code_real_type code)
{
unsigned int i;
for (i = 0; i < sizeof (sh64_reloc_map) / sizeof (struct elf_reloc_map); i++)
{
if (sh64_reloc_map[i].bfd_reloc_val == code)
return &sh_elf64_howto_table[(int) sh64_reloc_map[i].elf_reloc_val];
}
return NULL;
}
static void
sh_elf64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
Elf_Internal_Rela *dst)
{
unsigned int r;
r = ELF64_R_TYPE (dst->r_info);
BFD_ASSERT (r <= (unsigned int) R_SH_64_PCREL);
BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC || r > R_SH_LAST_INVALID_RELOC);
BFD_ASSERT (r < R_SH_DIR8WPN || r > R_SH_LAST_INVALID_RELOC_2);
BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_3 || r > R_SH_GOTPLT32);
BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_4 || r > R_SH_LAST_INVALID_RELOC_4);
cache_ptr->howto = &sh_elf64_howto_table[r];
}
static bfd_boolean
sh_elf64_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
struct bfd_link_info *info, bfd *input_bfd,
asection *input_section, bfd_byte *contents,
Elf_Internal_Rela *relocs,
Elf_Internal_Sym *local_syms,
asection **local_sections)
{
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
Elf_Internal_Rela *rel, *relend;
bfd *dynobj;
bfd_vma *local_got_offsets;
asection *sgot;
asection *sgotplt;
asection *splt;
asection *sreloc;
bfd_vma disp, dropped;
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
dynobj = elf_hash_table (info)->dynobj;
local_got_offsets = elf_local_got_offsets (input_bfd);
sgot = NULL;
sgotplt = NULL;
splt = NULL;
sreloc = NULL;
rel = relocs;
relend = relocs + input_section->reloc_count;
for (; rel < relend; rel++)
{
int r_type;
reloc_howto_type *howto;
unsigned long r_symndx;
Elf_Internal_Sym *sym;
asection *sec;
struct elf_link_hash_entry *h;
bfd_vma relocation;
bfd_vma addend = (bfd_vma)0;
bfd_reloc_status_type r;
int seen_stt_datalabel = 0;
r_symndx = ELF64_R_SYM (rel->r_info);
r_type = ELF64_R_TYPE (rel->r_info);
if (r_type == (int) R_SH_NONE)
continue;
if (r_type < 0
|| r_type > R_SH_64_PCREL
|| (r_type >= (int) R_SH_FIRST_INVALID_RELOC
&& r_type <= (int) R_SH_LAST_INVALID_RELOC)
|| (r_type >= (int) R_SH_DIR8WPN
&& r_type <= (int) R_SH_LAST_INVALID_RELOC)
|| (r_type >= (int) R_SH_GNU_VTINHERIT
&& r_type <= (int) R_SH_PSHL)
|| (r_type >= (int) R_SH_FIRST_INVALID_RELOC_2
&& r_type <= R_SH_GOTPLT32)
|| (r_type >= (int) R_SH_FIRST_INVALID_RELOC_4
&& r_type <= (int) R_SH_LAST_INVALID_RELOC_4))
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
howto = sh_elf64_howto_table + r_type;
h = NULL;
sym = NULL;
sec = NULL;
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
relocation = ((sec->output_section->vma
+ sec->output_offset
+ sym->st_value)
| ((sym->st_other & STO_SH5_ISA32) != 0));
if ((sym->st_other & STO_SH5_ISA32) != 0)
((*info->callbacks->reloc_dangerous)
(info,
_("Unexpected STO_SH5_ISA32 on local symbol is not handled"),
input_bfd, input_section, rel->r_offset));
if (info->relocatable)
{
sym = local_syms + r_symndx;
if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
goto final_link_relocate;
continue;
}
else if (! howto->partial_inplace)
{
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
relocation |= ((sym->st_other & STO_SH5_ISA32) != 0);
}
else if ((sec->flags & SEC_MERGE)
&& ELF_ST_TYPE (sym->st_info) == STT_SECTION)
{
asection *msec;
if (howto->rightshift || howto->src_mask != 0xffffffff)
{
(*_bfd_error_handler)
(_("%B(%A+0x%lx): %s relocation against SEC_MERGE section"),
input_bfd, input_section,
(long) rel->r_offset, howto->name);
return FALSE;
}
addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
msec = sec;
addend =
_bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend)
- relocation;
addend += msec->output_section->vma + msec->output_offset;
bfd_put_32 (input_bfd, addend, contents + rel->r_offset);
addend = 0;
}
}
else
{
if (info->relocatable)
continue;
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
{
seen_stt_datalabel |= h->type == STT_DATALABEL;
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
sec = h->root.u.def.section;
if (r_type == R_SH_GOTPC_LOW16
|| r_type == R_SH_GOTPC_MEDLOW16
|| r_type == R_SH_GOTPC_MEDHI16
|| r_type == R_SH_GOTPC_HI16
|| ((r_type == R_SH_PLT_LOW16
|| r_type == R_SH_PLT_MEDLOW16
|| r_type == R_SH_PLT_MEDHI16
|| r_type == R_SH_PLT_HI16)
&& h->plt.offset != (bfd_vma) -1)
|| ((r_type == R_SH_GOT_LOW16
|| r_type == R_SH_GOT_MEDLOW16
|| r_type == R_SH_GOT_MEDHI16
|| r_type == R_SH_GOT_HI16)
&& elf_hash_table (info)->dynamic_sections_created
&& (! info->shared
|| (! info->symbolic && h->dynindx != -1)
|| !h->def_regular))
|| (info->shared
&& ((! info->symbolic && h->dynindx != -1)
|| !h->def_regular)
&& ((r_type == R_SH_64
&& !(ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
|| ELF_ST_VISIBILITY (h->other) == STV_HIDDEN))
|| r_type == R_SH_64_PCREL)
&& ((input_section->flags & SEC_ALLOC) != 0
|| (input_section->flags & SEC_DEBUGGING) != 0))
|| (sec->output_section == NULL
&& ((input_section->flags & SEC_DEBUGGING) != 0
&& h->def_dynamic)))
relocation = 0;
else if (sec->output_section == NULL)
{
(*_bfd_error_handler)
(_("%s: warning: unresolvable relocation against symbol `%s' from %s section"),
bfd_get_filename (input_bfd), h->root.root.string,
bfd_get_section_name (input_bfd, input_section));
relocation = 0;
}
else
relocation = ((h->root.u.def.value
+ sec->output_section->vma
+ sec->output_offset)
| ((h->other & STO_SH5_ISA32) != 0
&& ! seen_stt_datalabel));
}
else if (h->root.type == bfd_link_hash_undefweak)
relocation = 0;
else if (info->unresolved_syms_in_objects == RM_IGNORE
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
relocation = 0;
else
{
if (! ((*info->callbacks->undefined_symbol)
(info, h->root.root.string, input_bfd,
input_section, rel->r_offset,
(info->unresolved_syms_in_objects == RM_GENERATE_ERROR
|| ELF_ST_VISIBILITY (h->other)))))
return FALSE;
relocation = 0;
}
}
disp = (relocation
- input_section->output_section->vma
- input_section->output_offset
- rel->r_offset);
dropped = 0;
switch ((int)r_type)
{
case R_SH_PT_16: dropped = disp & 2; break;
case R_SH_DIR10SW: dropped = disp & 1; break;
case R_SH_DIR10SL: dropped = disp & 3; break;
case R_SH_DIR10SQ: dropped = disp & 7; break;
}
if (dropped != 0)
{
(*_bfd_error_handler)
(_("%s: error: unaligned relocation type %d at %08x reloc %08x\n"),
bfd_get_filename (input_bfd), (int)r_type, (unsigned)rel->r_offset, (unsigned)relocation);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
switch ((int)r_type)
{
case R_SH_64:
case R_SH_64_PCREL:
if (info->shared
&& (input_section->flags & SEC_ALLOC) != 0
&& (r_type != R_SH_64_PCREL
|| (h != NULL
&& h->dynindx != -1
&& (! info->symbolic
|| !h->def_regular))))
{
Elf_Internal_Rela outrel;
bfd_byte *loc;
bfd_boolean skip, relocate;
if (sreloc == NULL)
{
const char *name;
name = (bfd_elf_string_from_elf_section
(input_bfd,
elf_elfheader (input_bfd)->e_shstrndx,
elf_section_data (input_section)->rel_hdr.sh_name));
if (name == NULL)
return FALSE;
BFD_ASSERT (strncmp (name, ".rela", 5) == 0
&& strcmp (bfd_get_section_name (input_bfd,
input_section),
name + 5) == 0);
sreloc = bfd_get_section_by_name (dynobj, name);
BFD_ASSERT (sreloc != NULL);
}
skip = FALSE;
relocate = FALSE;
outrel.r_offset
= _bfd_elf_section_offset (output_bfd, info,
input_section, rel->r_offset);
if (outrel.r_offset == (bfd_vma) -1)
skip = TRUE;
else if (outrel.r_offset == (bfd_vma) -2)
skip = TRUE, relocate = TRUE;
outrel.r_offset += (input_section->output_section->vma
+ input_section->output_offset);
if (skip)
memset (&outrel, 0, sizeof outrel);
else if (r_type == R_SH_64_PCREL)
{
BFD_ASSERT (h != NULL && h->dynindx != -1);
outrel.r_info = ELF64_R_INFO (h->dynindx, R_SH_64_PCREL);
outrel.r_addend = rel->r_addend;
}
else
{
if (h == NULL
|| ((info->symbolic || h->dynindx == -1)
&& h->def_regular))
{
relocate = TRUE;
outrel.r_info = ELF64_R_INFO (0, R_SH_RELATIVE64);
outrel.r_addend = relocation + rel->r_addend;
}
else
{
BFD_ASSERT (h->dynindx != -1);
outrel.r_info = ELF64_R_INFO (h->dynindx, R_SH_64);
outrel.r_addend = relocation + rel->r_addend;
}
}
loc = sreloc->contents;
loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
if (! relocate)
continue;
}
else if (r_type == R_SH_64)
addend = rel->r_addend;
goto final_link_relocate;
case R_SH_GOTPLT_LOW16:
case R_SH_GOTPLT_MEDLOW16:
case R_SH_GOTPLT_MEDHI16:
case R_SH_GOTPLT_HI16:
case R_SH_GOTPLT10BY4:
case R_SH_GOTPLT10BY8:
if (h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
|| ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
|| ! info->shared
|| info->symbolic
|| h->dynindx == -1
|| h->plt.offset == (bfd_vma) -1
|| h->got.offset != (bfd_vma) -1)
goto force_got;
if (sgotplt == NULL)
{
sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
BFD_ASSERT (sgotplt != NULL);
}
relocation = (sgotplt->output_offset
+ ((h->plt.offset / elf_sh64_sizeof_plt (info)
- 1 + 3) * 8));
relocation -= GOT_BIAS;
goto final_link_relocate;
force_got:
case R_SH_GOT_LOW16:
case R_SH_GOT_MEDLOW16:
case R_SH_GOT_MEDHI16:
case R_SH_GOT_HI16:
case R_SH_GOT10BY4:
case R_SH_GOT10BY8:
if (sgot == NULL)
{
sgot = bfd_get_section_by_name (dynobj, ".got");
BFD_ASSERT (sgot != NULL);
}
if (h != NULL)
{
bfd_vma off;
off = h->got.offset;
if (seen_stt_datalabel)
{
struct elf_sh64_link_hash_entry *hsh;
hsh = (struct elf_sh64_link_hash_entry *)h;
off = hsh->datalabel_got_offset;
}
BFD_ASSERT (off != (bfd_vma) -1);
if (! elf_hash_table (info)->dynamic_sections_created
|| (info->shared
&& (info->symbolic || h->dynindx == -1
|| ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
|| ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
&& h->def_regular))
{
if ((off & 1) != 0)
off &= ~1;
else
{
bfd_put_64 (output_bfd, relocation,
sgot->contents + off);
if (seen_stt_datalabel)
{
struct elf_sh64_link_hash_entry *hsh;
hsh = (struct elf_sh64_link_hash_entry *)h;
hsh->datalabel_got_offset |= 1;
}
else
h->got.offset |= 1;
}
}
relocation = sgot->output_offset + off;
}
else
{
bfd_vma off;
if (rel->r_addend)
{
BFD_ASSERT (local_got_offsets != NULL
&& (local_got_offsets[symtab_hdr->sh_info
+ r_symndx]
!= (bfd_vma) -1));
off = local_got_offsets[symtab_hdr->sh_info
+ r_symndx];
}
else
{
BFD_ASSERT (local_got_offsets != NULL
&& local_got_offsets[r_symndx] != (bfd_vma) -1);
off = local_got_offsets[r_symndx];
}
if ((off & 1) != 0)
off &= ~1;
else
{
bfd_put_64 (output_bfd, relocation, sgot->contents + off);
if (info->shared)
{
asection *s;
Elf_Internal_Rela outrel;
bfd_byte *loc;
s = bfd_get_section_by_name (dynobj, ".rela.got");
BFD_ASSERT (s != NULL);
outrel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
+ off);
outrel.r_info = ELF64_R_INFO (0, R_SH_RELATIVE64);
outrel.r_addend = relocation;
loc = s->contents;
loc += s->reloc_count++ * sizeof (Elf64_External_Rela);
bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
}
if (rel->r_addend)
local_got_offsets[symtab_hdr->sh_info + r_symndx] |= 1;
else
local_got_offsets[r_symndx] |= 1;
}
relocation = sgot->output_offset + off;
}
relocation -= GOT_BIAS;
goto final_link_relocate;
case R_SH_GOTOFF_LOW16:
case R_SH_GOTOFF_MEDLOW16:
case R_SH_GOTOFF_MEDHI16:
case R_SH_GOTOFF_HI16:
if (sgot == NULL)
{
sgot = bfd_get_section_by_name (dynobj, ".got");
BFD_ASSERT (sgot != NULL);
}
relocation -= sgot->output_section->vma;
relocation -= GOT_BIAS;
addend = rel->r_addend;
goto final_link_relocate;
case R_SH_GOTPC_LOW16:
case R_SH_GOTPC_MEDLOW16:
case R_SH_GOTPC_MEDHI16:
case R_SH_GOTPC_HI16:
if (sgot == NULL)
{
sgot = bfd_get_section_by_name (dynobj, ".got");
BFD_ASSERT (sgot != NULL);
}
relocation = sgot->output_section->vma;
relocation += GOT_BIAS;
addend = rel->r_addend;
goto final_link_relocate;
case R_SH_PLT_LOW16:
case R_SH_PLT_MEDLOW16:
case R_SH_PLT_MEDHI16:
case R_SH_PLT_HI16:
if (h == NULL)
goto final_link_relocate;
if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
|| ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
goto final_link_relocate;
if (h->plt.offset == (bfd_vma) -1)
{
goto final_link_relocate;
}
if (splt == NULL)
{
splt = bfd_get_section_by_name (dynobj, ".plt");
BFD_ASSERT (splt != NULL);
}
relocation = (splt->output_section->vma
+ splt->output_offset
+ h->plt.offset);
relocation++;
addend = rel->r_addend;
goto final_link_relocate;
case R_SH_DIR32:
case R_SH_SHMEDIA_CODE:
case R_SH_PT_16:
case R_SH_DIR5U:
case R_SH_DIR6S:
case R_SH_DIR6U:
case R_SH_DIR10S:
case R_SH_DIR10SW:
case R_SH_DIR10SL:
case R_SH_DIR10SQ:
case R_SH_IMMS16:
case R_SH_IMMU16:
case R_SH_IMM_LOW16:
case R_SH_IMM_LOW16_PCREL:
case R_SH_IMM_MEDLOW16:
case R_SH_IMM_MEDLOW16_PCREL:
case R_SH_IMM_MEDHI16:
case R_SH_IMM_MEDHI16_PCREL:
case R_SH_IMM_HI16:
case R_SH_IMM_HI16_PCREL:
addend = rel->r_addend;
case R_SH_REL32:
final_link_relocate:
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
relocation, addend);
break;
default:
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
if (r != bfd_reloc_ok)
{
switch (r)
{
default:
case bfd_reloc_outofrange:
abort ();
case bfd_reloc_overflow:
{
const char *name;
if (h != NULL)
name = NULL;
else
{
name = (bfd_elf_string_from_elf_section
(input_bfd, symtab_hdr->sh_link, sym->st_name));
if (name == NULL)
return FALSE;
if (*name == '\0')
name = bfd_section_name (input_bfd, sec);
}
if (! ((*info->callbacks->reloc_overflow)
(info, (h ? &h->root : NULL), name, howto->name,
(bfd_vma) 0, input_bfd, input_section,
rel->r_offset)))
return FALSE;
}
break;
}
}
}
return TRUE;
}
static bfd_byte *
sh_elf64_get_relocated_section_contents (bfd *output_bfd,
struct bfd_link_info *link_info,
struct bfd_link_order *link_order,
bfd_byte *data,
bfd_boolean relocatable,
asymbol **symbols)
{
Elf_Internal_Shdr *symtab_hdr;
asection *input_section = link_order->u.indirect.section;
bfd *input_bfd = input_section->owner;
asection **sections = NULL;
Elf_Internal_Rela *internal_relocs = NULL;
Elf_Internal_Sym *isymbuf = NULL;
if (relocatable
|| elf_section_data (input_section)->this_hdr.contents == NULL)
return bfd_generic_get_relocated_section_contents (output_bfd, link_info,
link_order, data,
relocatable,
symbols);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
memcpy (data, elf_section_data (input_section)->this_hdr.contents,
input_section->size);
if ((input_section->flags & SEC_RELOC) != 0
&& input_section->reloc_count > 0)
{
Elf_Internal_Sym *isymp;
Elf_Internal_Sym *isymend;
asection **secpp;
if (symtab_hdr->sh_info != 0)
{
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
if (isymbuf == NULL)
isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
symtab_hdr->sh_info, 0,
NULL, NULL, NULL);
if (isymbuf == NULL)
goto error_return;
}
internal_relocs = (_bfd_elf_link_read_relocs
(input_bfd, input_section, NULL,
(Elf_Internal_Rela *) NULL, FALSE));
if (internal_relocs == NULL)
goto error_return;
sections = (asection **) bfd_malloc (symtab_hdr->sh_info
* sizeof (asection *));
if (sections == NULL && symtab_hdr->sh_info > 0)
goto error_return;
secpp = sections;
isymend = isymbuf + symtab_hdr->sh_info;
for (isymp = isymbuf; isymp < isymend; ++isymp, ++secpp)
{
asection *isec;
if (isymp->st_shndx == SHN_UNDEF)
isec = bfd_und_section_ptr;
else if (isymp->st_shndx > 0 && isymp->st_shndx < SHN_LORESERVE)
isec = bfd_section_from_elf_index (input_bfd, isymp->st_shndx);
else if (isymp->st_shndx == SHN_ABS)
isec = bfd_abs_section_ptr;
else if (isymp->st_shndx == SHN_COMMON)
isec = bfd_com_section_ptr;
else
{
isec = NULL;
}
*secpp = isec;
}
if (! sh_elf64_relocate_section (output_bfd, link_info, input_bfd,
input_section, data, internal_relocs,
isymbuf, sections))
goto error_return;
if (sections != NULL)
free (sections);
if (internal_relocs != elf_section_data (input_section)->relocs)
free (internal_relocs);
if (isymbuf != NULL
&& (unsigned char *) isymbuf != symtab_hdr->contents)
free (isymbuf);
}
return data;
error_return:
if (sections != NULL)
free (sections);
if (internal_relocs != NULL
&& internal_relocs != elf_section_data (input_section)->relocs)
free (internal_relocs);
if (isymbuf != NULL
&& (unsigned char *) isymbuf != symtab_hdr->contents)
free (isymbuf);
return NULL;
}
static bfd_boolean
sh64_elf64_fake_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
Elf_Internal_Shdr *elf_section_hdr,
asection *asect)
{
if (bfd_get_section_flags (output_bfd, asect) & SEC_CODE)
elf_section_hdr->sh_flags |= SHF_SH5_ISA32;
return TRUE;
}
static bfd_boolean
sh_elf64_set_mach_from_flags (bfd *abfd)
{
flagword flags = elf_elfheader (abfd)->e_flags;
switch (flags & EF_SH_MACH_MASK)
{
case EF_SH5:
bfd_default_set_arch_mach (abfd, bfd_arch_sh, bfd_mach_sh5);
break;
default:
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
return TRUE;
}
static bfd_boolean
sh_elf64_set_private_flags (bfd *abfd, flagword flags)
{
BFD_ASSERT (! elf_flags_init (abfd)
|| elf_elfheader (abfd)->e_flags == flags);
elf_elfheader (abfd)->e_flags = flags;
elf_flags_init (abfd) = TRUE;
return sh_elf64_set_mach_from_flags (abfd);
}
static bfd_boolean
sh_elf64_copy_private_data_internal (bfd *ibfd, bfd *obfd)
{
Elf_Internal_Shdr **o_shdrp;
asection *isec;
asection *osec;
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return TRUE;
o_shdrp = elf_elfsections (obfd);
for (osec = obfd->sections; osec; osec = osec->next)
{
int oIndex = ((struct bfd_elf_section_data *) elf_section_data (osec))->this_idx;
for (isec = ibfd->sections; isec; isec = isec->next)
{
if (strcmp (osec->name, isec->name) == 0)
{
if ((elf_section_data (isec)->this_hdr.sh_flags
& SHF_SH5_ISA32) != 0)
o_shdrp[oIndex]->sh_flags |= SHF_SH5_ISA32;
break;
}
}
}
return sh_elf64_set_private_flags (obfd, elf_elfheader (ibfd)->e_flags);
}
static bfd_boolean
sh_elf64_copy_private_data (bfd *ibfd, bfd *obfd)
{
return sh_elf64_copy_private_data_internal (ibfd, obfd);
}
static bfd_boolean
sh_elf64_merge_private_data (bfd *ibfd, bfd *obfd)
{
flagword old_flags, new_flags;
if (! _bfd_generic_verify_endian_match (ibfd, obfd))
return FALSE;
if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return TRUE;
if (bfd_get_arch_size (ibfd) != bfd_get_arch_size (obfd))
{
const char *msg;
if (bfd_get_arch_size (ibfd) == 32
&& bfd_get_arch_size (obfd) == 64)
msg = _("%s: compiled as 32-bit object and %s is 64-bit");
else if (bfd_get_arch_size (ibfd) == 64
&& bfd_get_arch_size (obfd) == 32)
msg = _("%s: compiled as 64-bit object and %s is 32-bit");
else
msg = _("%s: object size does not match that of target %s");
(*_bfd_error_handler) (msg, bfd_get_filename (ibfd),
bfd_get_filename (obfd));
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
old_flags = elf_elfheader (obfd)->e_flags;
new_flags = elf_elfheader (ibfd)->e_flags;
if (! elf_flags_init (obfd))
{
elf_flags_init (obfd) = TRUE;
elf_elfheader (obfd)->e_flags = old_flags = new_flags;
}
else if ((new_flags & EF_SH_MACH_MASK) != EF_SH5)
{
(*_bfd_error_handler)
("%s: does not use the SH64 64-bit ABI as previous modules do",
bfd_get_filename (ibfd));
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
sh_elf64_copy_private_data_internal (ibfd, obfd);
elf_elfheader (obfd)->e_flags = old_flags;
return sh_elf64_set_mach_from_flags (obfd);
}
static asection *
sh_elf64_gc_mark_hook (asection *sec,
struct bfd_link_info *info ATTRIBUTE_UNUSED,
Elf_Internal_Rela *rel,
struct elf_link_hash_entry *h,
Elf_Internal_Sym *sym)
{
if (h != NULL)
{
switch (ELF64_R_TYPE (rel->r_info))
{
case R_SH_GNU_VTINHERIT:
case R_SH_GNU_VTENTRY:
break;
default:
while (h->root.type == bfd_link_hash_indirect
&& h->root.u.i.link)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
switch (h->root.type)
{
case bfd_link_hash_defined:
case bfd_link_hash_defweak:
return h->root.u.def.section;
case bfd_link_hash_common:
return h->root.u.c.p->section;
default:
break;
}
}
}
else
return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
return NULL;
}
static bfd_boolean
sh_elf64_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED,
struct bfd_link_info *info ATTRIBUTE_UNUSED,
asection *sec ATTRIBUTE_UNUSED,
const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED)
{
return TRUE;
}
static bfd_boolean
sh_elf64_check_relocs (bfd *abfd, struct bfd_link_info *info,
asection *sec, const Elf_Internal_Rela *relocs)
{
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
const Elf_Internal_Rela *rel;
const Elf_Internal_Rela *rel_end;
bfd *dynobj;
bfd_vma *local_got_offsets;
asection *sgot;
asection *srelgot;
asection *sreloc;
sgot = NULL;
srelgot = NULL;
sreloc = NULL;
if (info->relocatable)
return TRUE;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf64_External_Sym);
if (!elf_bad_symtab (abfd))
sym_hashes_end -= symtab_hdr->sh_info;
dynobj = elf_hash_table (info)->dynobj;
local_got_offsets = elf_local_got_offsets (abfd);
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
{
struct elf_link_hash_entry *h;
unsigned long r_symndx;
r_symndx = ELF64_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
h = NULL;
else
{
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
if (dynobj == NULL)
{
switch (ELF64_R_TYPE (rel->r_info))
{
case R_SH_GOTPLT_LOW16:
case R_SH_GOTPLT_MEDLOW16:
case R_SH_GOTPLT_MEDHI16:
case R_SH_GOTPLT_HI16:
case R_SH_GOTPLT10BY4:
case R_SH_GOTPLT10BY8:
case R_SH_GOT_LOW16:
case R_SH_GOT_MEDLOW16:
case R_SH_GOT_MEDHI16:
case R_SH_GOT_HI16:
case R_SH_GOT10BY4:
case R_SH_GOT10BY8:
case R_SH_GOTOFF_LOW16:
case R_SH_GOTOFF_MEDLOW16:
case R_SH_GOTOFF_MEDHI16:
case R_SH_GOTOFF_HI16:
case R_SH_GOTPC_LOW16:
case R_SH_GOTPC_MEDLOW16:
case R_SH_GOTPC_MEDHI16:
case R_SH_GOTPC_HI16:
elf_hash_table (info)->dynobj = dynobj = abfd;
if (! _bfd_elf_create_got_section (dynobj, info))
return FALSE;
break;
default:
break;
}
}
switch (ELF64_R_TYPE (rel->r_info))
{
case R_SH_GNU_VTINHERIT:
if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
return FALSE;
break;
case R_SH_GNU_VTENTRY:
if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
return FALSE;
break;
force_got:
case R_SH_GOT_LOW16:
case R_SH_GOT_MEDLOW16:
case R_SH_GOT_MEDHI16:
case R_SH_GOT_HI16:
case R_SH_GOT10BY4:
case R_SH_GOT10BY8:
if (sgot == NULL)
{
sgot = bfd_get_section_by_name (dynobj, ".got");
BFD_ASSERT (sgot != NULL);
}
if (srelgot == NULL
&& (h != NULL || info->shared))
{
srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
if (srelgot == NULL)
{
srelgot = bfd_make_section_with_flags (dynobj,
".rela.got",
(SEC_ALLOC
| SEC_LOAD
| SEC_HAS_CONTENTS
| SEC_IN_MEMORY
| SEC_LINKER_CREATED
| SEC_READONLY));
if (srelgot == NULL
|| ! bfd_set_section_alignment (dynobj, srelgot, 2))
return FALSE;
}
}
if (h != NULL)
{
if (h->type == STT_DATALABEL)
{
struct elf_sh64_link_hash_entry *hsh;
h = (struct elf_link_hash_entry *) h->root.u.i.link;
hsh = (struct elf_sh64_link_hash_entry *)h;
if (hsh->datalabel_got_offset != (bfd_vma) -1)
break;
hsh->datalabel_got_offset = sgot->size;
}
else
{
if (h->got.offset != (bfd_vma) -1)
{
break;
}
h->got.offset = sgot->size;
}
if (h->dynindx == -1)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
srelgot->size += sizeof (Elf64_External_Rela);
}
else
{
if (local_got_offsets == NULL)
{
size_t size;
register unsigned int i;
size = symtab_hdr->sh_info * sizeof (bfd_vma);
size *= 2;
local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size);
if (local_got_offsets == NULL)
return FALSE;
elf_local_got_offsets (abfd) = local_got_offsets;
for (i = 0; i < symtab_hdr->sh_info; i++)
local_got_offsets[i] = (bfd_vma) -1;
for (; i < 2 * symtab_hdr->sh_info; i++)
local_got_offsets[i] = (bfd_vma) -1;
}
if ((rel->r_addend & 1) != 0)
{
if (local_got_offsets[symtab_hdr->sh_info
+ r_symndx] != (bfd_vma) -1)
{
break;
}
local_got_offsets[symtab_hdr->sh_info
+ r_symndx] = sgot->size;
}
else
{
if (local_got_offsets[r_symndx] != (bfd_vma) -1)
{
break;
}
local_got_offsets[r_symndx] = sgot->size;
}
if (info->shared)
{
srelgot->size += sizeof (Elf64_External_Rela);
}
}
sgot->size += 8;
break;
case R_SH_GOTPLT_LOW16:
case R_SH_GOTPLT_MEDLOW16:
case R_SH_GOTPLT_MEDHI16:
case R_SH_GOTPLT_HI16:
case R_SH_GOTPLT10BY4:
case R_SH_GOTPLT10BY8:
if (h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
|| ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
|| ! info->shared
|| info->symbolic
|| h->dynindx == -1
|| h->got.offset != (bfd_vma) -1)
goto force_got;
if (h->dynindx == -1)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
h->needs_plt = 1;
break;
case R_SH_PLT_LOW16:
case R_SH_PLT_MEDLOW16:
case R_SH_PLT_MEDHI16:
case R_SH_PLT_HI16:
if (h == NULL)
continue;
if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
|| ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
break;
h->needs_plt = 1;
break;
case R_SH_64:
case R_SH_64_PCREL:
if (h != NULL)
h->non_got_ref = 1;
if (info->shared
&& (sec->flags & SEC_ALLOC) != 0
&& (ELF32_R_TYPE (rel->r_info) != R_SH_64_PCREL
|| (h != NULL
&& (! info->symbolic
|| !h->def_regular))))
{
if (sreloc == NULL)
{
const char *name;
name = (bfd_elf_string_from_elf_section
(abfd,
elf_elfheader (abfd)->e_shstrndx,
elf_section_data (sec)->rel_hdr.sh_name));
if (name == NULL)
return FALSE;
BFD_ASSERT (strncmp (name, ".rela", 5) == 0
&& strcmp (bfd_get_section_name (abfd, sec),
name + 5) == 0);
sreloc = bfd_get_section_by_name (dynobj, name);
if (sreloc == NULL)
{
flagword flags;
flags = (SEC_HAS_CONTENTS | SEC_READONLY
| SEC_IN_MEMORY | SEC_LINKER_CREATED);
if ((sec->flags & SEC_ALLOC) != 0)
flags |= SEC_ALLOC | SEC_LOAD;
sreloc = bfd_make_section_with_flags (dynobj,
name,
flags);
if (sreloc == NULL
|| ! bfd_set_section_alignment (dynobj, sreloc, 2))
return FALSE;
}
}
sreloc->size += sizeof (Elf64_External_Rela);
if (h != NULL && info->symbolic
&& ELF64_R_TYPE (rel->r_info) == R_SH_64_PCREL)
{
struct elf_sh64_link_hash_entry *eh;
struct elf_sh64_pcrel_relocs_copied *p;
eh = (struct elf_sh64_link_hash_entry *) h;
for (p = eh->pcrel_relocs_copied; p != NULL; p = p->next)
if (p->section == sreloc)
break;
if (p == NULL)
{
p = ((struct elf_sh64_pcrel_relocs_copied *)
bfd_alloc (dynobj, sizeof *p));
if (p == NULL)
return FALSE;
p->next = eh->pcrel_relocs_copied;
eh->pcrel_relocs_copied = p;
p->section = sreloc;
p->count = 0;
}
++p->count;
}
}
break;
}
}
return TRUE;
}
static int
sh64_elf64_get_symbol_type (Elf_Internal_Sym * elf_sym, int type)
{
if (ELF_ST_TYPE (elf_sym->st_info) == STT_DATALABEL)
return STT_DATALABEL;
return type;
}
static bfd_boolean
sh64_elf64_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
Elf_Internal_Sym *sym, const char **namep,
flagword *flagsp ATTRIBUTE_UNUSED,
asection **secp, bfd_vma *valp)
{
if (ELF_ST_TYPE (sym->st_info) == STT_DATALABEL
&& is_elf_hash_table (info->hash))
{
struct elf_link_hash_entry *h;
flagword flags
= info->relocatable || info->emitrelocations
? BSF_GLOBAL : BSF_GLOBAL | BSF_INDIRECT;
char *dl_name
= bfd_malloc (strlen (*namep) + sizeof (DATALABEL_SUFFIX));
struct elf_link_hash_entry ** sym_hash = elf_sym_hashes (abfd);
BFD_ASSERT (sym_hash != NULL);
if (dl_name == NULL)
return FALSE;
strcpy (dl_name, *namep);
strcat (dl_name, DATALABEL_SUFFIX);
h = (struct elf_link_hash_entry *)
bfd_link_hash_lookup (info->hash, dl_name, FALSE, FALSE, FALSE);
if (h == NULL)
{
struct bfd_link_hash_entry *bh = NULL;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
if (! _bfd_generic_link_add_one_symbol (info, abfd, dl_name,
flags, *secp, *valp,
*namep, FALSE,
bed->collect, &bh))
{
free (dl_name);
return FALSE;
}
h = (struct elf_link_hash_entry *) bh;
h->non_elf = 0;
h->type = STT_DATALABEL;
}
else
free (dl_name);
if (h->type != STT_DATALABEL
|| ((info->relocatable || info->emitrelocations)
&& h->root.type != bfd_link_hash_undefined)
|| (! info->relocatable && !info->emitrelocations
&& h->root.type != bfd_link_hash_indirect))
{
(*_bfd_error_handler)
(_("%s: encountered datalabel symbol in input"),
bfd_get_filename (abfd));
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
while (*sym_hash != NULL)
sym_hash++;
*sym_hash = h;
*namep = NULL;
}
return TRUE;
}
static bfd_boolean
sh64_elf64_link_output_symbol_hook (struct bfd_link_info *info,
const char *cname,
Elf_Internal_Sym *sym,
asection *input_sec ATTRIBUTE_UNUSED,
struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
{
char *name = (char *) cname;
if (info->relocatable || info->emitrelocations)
{
if (ELF_ST_TYPE (sym->st_info) == STT_DATALABEL)
name[strlen (name) - strlen (DATALABEL_SUFFIX)] = 0;
}
return TRUE;
}
static void
sh64_elf64_final_write_processing (bfd *abfd,
bfd_boolean linker ATTRIBUTE_UNUSED)
{
if (elf_elfheader (abfd)->e_type == ET_EXEC)
elf_elfheader (abfd)->e_entry |= 1;
}
static const bfd_byte elf_sh64_plt0_entry_be[PLT_ENTRY_SIZE] =
{
0xcc, 0x00, 0x01, 0x10,
0xc8, 0x00, 0x01, 0x10,
0xc8, 0x00, 0x01, 0x10,
0xc8, 0x00, 0x01, 0x10,
0x8d, 0x10, 0x09, 0x90,
0x6b, 0xf1, 0x66, 0x00,
0x8d, 0x10, 0x05, 0x10,
0x44, 0x01, 0xff, 0xf0,
0x6f, 0xf0, 0xff, 0xf0,
0x6f, 0xf0, 0xff, 0xf0,
0x6f, 0xf0, 0xff, 0xf0,
0x6f, 0xf0, 0xff, 0xf0,
0x6f, 0xf0, 0xff, 0xf0,
0x6f, 0xf0, 0xff, 0xf0,
0x6f, 0xf0, 0xff, 0xf0,
0x6f, 0xf0, 0xff, 0xf0,
};
static const bfd_byte elf_sh64_plt0_entry_le[PLT_ENTRY_SIZE] =
{
0x10, 0x01, 0x00, 0xcc,
0x10, 0x01, 0x00, 0xc8,
0x10, 0x01, 0x00, 0xc8,
0x10, 0x01, 0x00, 0xc8,
0x90, 0x09, 0x10, 0x8d,
0x00, 0x66, 0xf1, 0x6b,
0x10, 0x05, 0x10, 0x8d,
0xf0, 0xff, 0x01, 0x44,
0xf0, 0xff, 0xf0, 0x6f,
0xf0, 0xff, 0xf0, 0x6f,
0xf0, 0xff, 0xf0, 0x6f,
0xf0, 0xff, 0xf0, 0x6f,
0xf0, 0xff, 0xf0, 0x6f,
0xf0, 0xff, 0xf0, 0x6f,
0xf0, 0xff, 0xf0, 0x6f,
0xf0, 0xff, 0xf0, 0x6f,
};
static const bfd_byte elf_sh64_plt_entry_be[PLT_ENTRY_SIZE] =
{
0xcc, 0x00, 0x01, 0x90,
0xc8, 0x00, 0x01, 0x90,
0xc8, 0x00, 0x01, 0x90,
0xc8, 0x00, 0x01, 0x90,
0x8d, 0x90, 0x01, 0x90,
0x6b, 0xf1, 0x66, 0x00,
0x44, 0x01, 0xff, 0xf0,
0x6f, 0xf0, 0xff, 0xf0,
0xcc, 0x00, 0x01, 0x90,
0xc8, 0x00, 0x01, 0x90,
0x6b, 0xf5, 0x66, 0x00,
0xcc, 0x00, 0x01, 0x50,
0xc8, 0x00, 0x01, 0x50,
0x44, 0x01, 0xff, 0xf0,
0x6f, 0xf0, 0xff, 0xf0,
0x6f, 0xf0, 0xff, 0xf0,
};
static const bfd_byte elf_sh64_plt_entry_le[PLT_ENTRY_SIZE] =
{
0x90, 0x01, 0x00, 0xcc,
0x90, 0x01, 0x00, 0xc8,
0x90, 0x01, 0x00, 0xc8,
0x90, 0x01, 0x00, 0xc8,
0x90, 0x01, 0x90, 0x8d,
0x00, 0x66, 0xf1, 0x6b,
0xf0, 0xff, 0x01, 0x44,
0xf0, 0xff, 0xf0, 0x6f,
0x90, 0x01, 0x00, 0xcc,
0x90, 0x01, 0x00, 0xc8,
0x00, 0x66, 0xf5, 0x6b,
0x50, 0x01, 0x00, 0xcc,
0x50, 0x01, 0x00, 0xc8,
0xf0, 0xff, 0x01, 0x44,
0xf0, 0xff, 0xf0, 0x6f,
0xf0, 0xff, 0xf0, 0x6f,
};
static const bfd_byte elf_sh64_pic_plt_entry_be[PLT_ENTRY_SIZE] =
{
0xcc, 0x00, 0x01, 0x90,
0xc8, 0x00, 0x01, 0x90,
0x40, 0xc3, 0x65, 0x90,
0x6b, 0xf1, 0x66, 0x00,
0x44, 0x01, 0xff, 0xf0,
0x6f, 0xf0, 0xff, 0xf0,
0x6f, 0xf0, 0xff, 0xf0,
0x6f, 0xf0, 0xff, 0xf0,
0xce, 0x00, 0x01, 0x10,
0x00, 0xc9, 0x45, 0x10,
0x8d, 0x10, 0x09, 0x90,
0x6b, 0xf1, 0x66, 0x00,
0x8d, 0x10, 0x05, 0x10,
0xcc, 0x00, 0x01, 0x50,
0xc8, 0x00, 0x01, 0x50,
0x44, 0x01, 0xff, 0xf0,
};
static const bfd_byte elf_sh64_pic_plt_entry_le[PLT_ENTRY_SIZE] =
{
0x90, 0x01, 0x00, 0xcc,
0x90, 0x01, 0x00, 0xc8,
0x90, 0x65, 0xc3, 0x40,
0x00, 0x66, 0xf1, 0x6b,
0xf0, 0xff, 0x01, 0x44,
0xf0, 0xff, 0xf0, 0x6f,
0xf0, 0xff, 0xf0, 0x6f,
0xf0, 0xff, 0xf0, 0x6f,
0x10, 0x01, 0x00, 0xce,
0x10, 0x45, 0xc9, 0x00,
0x90, 0x09, 0x10, 0x8d,
0x00, 0x66, 0xf1, 0x6b,
0x10, 0x05, 0x10, 0x8d,
0x50, 0x01, 0x00, 0xcc,
0x50, 0x01, 0x00, 0xc8,
0xf0, 0xff, 0x01, 0x44,
};
static const bfd_byte *elf_sh64_plt0_entry;
static const bfd_byte *elf_sh64_plt_entry;
static const bfd_byte *elf_sh64_pic_plt_entry;
static struct bfd_hash_entry *
sh64_elf64_link_hash_newfunc (struct bfd_hash_entry *entry,
struct bfd_hash_table *table,
const char *string)
{
struct elf_sh64_link_hash_entry *ret =
(struct elf_sh64_link_hash_entry *) entry;
if (ret == (struct elf_sh64_link_hash_entry *) NULL)
ret = ((struct elf_sh64_link_hash_entry *)
bfd_hash_allocate (table,
sizeof (struct elf_sh64_link_hash_entry)));
if (ret == (struct elf_sh64_link_hash_entry *) NULL)
return (struct bfd_hash_entry *) ret;
ret = ((struct elf_sh64_link_hash_entry *)
_bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
table, string));
if (ret != (struct elf_sh64_link_hash_entry *) NULL)
{
ret->pcrel_relocs_copied = NULL;
ret->datalabel_got_offset = (bfd_vma) -1;
}
return (struct bfd_hash_entry *) ret;
}
static struct bfd_link_hash_table *
sh64_elf64_link_hash_table_create (bfd *abfd)
{
struct elf_sh64_link_hash_table *ret;
ret = ((struct elf_sh64_link_hash_table *)
bfd_malloc (sizeof (struct elf_sh64_link_hash_table)));
if (ret == (struct elf_sh64_link_hash_table *) NULL)
return NULL;
if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
sh64_elf64_link_hash_newfunc))
{
free (ret);
return NULL;
}
return &ret->root.root;
}
inline static void
movi_shori_putval (bfd *output_bfd, unsigned long value, bfd_byte *addr)
{
bfd_put_32 (output_bfd,
bfd_get_32 (output_bfd, addr)
| ((value >> 6) & 0x3fffc00),
addr);
bfd_put_32 (output_bfd,
bfd_get_32 (output_bfd, addr + 4)
| ((value << 10) & 0x3fffc00),
addr + 4);
}
inline static void
movi_3shori_putval (bfd *output_bfd, bfd_vma value, bfd_byte *addr)
{
bfd_put_32 (output_bfd,
bfd_get_32 (output_bfd, addr)
| ((value >> 38) & 0x3fffc00),
addr);
bfd_put_32 (output_bfd,
bfd_get_32 (output_bfd, addr + 4)
| ((value >> 22) & 0x3fffc00),
addr + 4);
bfd_put_32 (output_bfd,
bfd_get_32 (output_bfd, addr + 8)
| ((value >> 6) & 0x3fffc00),
addr + 8);
bfd_put_32 (output_bfd,
bfd_get_32 (output_bfd, addr + 12)
| ((value << 10) & 0x3fffc00),
addr + 12);
}
static bfd_boolean
sh64_elf64_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
{
flagword flags, pltflags;
register asection *s;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
int ptralign = 0;
switch (bed->s->arch_size)
{
case 32:
ptralign = 2;
break;
case 64:
ptralign = 3;
break;
default:
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
| SEC_LINKER_CREATED);
pltflags = flags;
pltflags |= SEC_CODE;
if (bed->plt_not_loaded)
pltflags &= ~ (SEC_LOAD | SEC_HAS_CONTENTS);
if (bed->plt_readonly)
pltflags |= SEC_READONLY;
s = bfd_make_section_with_flags (abfd, ".plt", pltflags);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
return FALSE;
if (bed->want_plt_sym)
{
struct elf_link_hash_entry *h;
struct bfd_link_hash_entry *bh = NULL;
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s,
(bfd_vma) 0, (const char *) NULL, FALSE, bed->collect, &bh)))
return FALSE;
h = (struct elf_link_hash_entry *) bh;
h->def_regular = 1;
h->type = STT_OBJECT;
if (info->shared
&& ! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
s = bfd_make_section_with_flags (abfd,
bed->default_use_rela_p ? ".rela.plt" : ".rel.plt",
flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, ptralign))
return FALSE;
if (! _bfd_elf_create_got_section (abfd, info))
return FALSE;
{
const char *secname;
char *relname;
flagword secflags;
asection *sec;
for (sec = abfd->sections; sec; sec = sec->next)
{
secflags = bfd_get_section_flags (abfd, sec);
if ((secflags & (SEC_DATA | SEC_LINKER_CREATED))
|| ((secflags & SEC_HAS_CONTENTS) != SEC_HAS_CONTENTS))
continue;
secname = bfd_get_section_name (abfd, sec);
relname = (char *) bfd_malloc (strlen (secname) + 6);
strcpy (relname, ".rela");
strcat (relname, secname);
s = bfd_make_section_with_flags (abfd, relname,
flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, ptralign))
return FALSE;
}
}
if (bed->want_dynbss)
{
s = bfd_make_section_with_flags (abfd, ".dynbss",
SEC_ALLOC | SEC_LINKER_CREATED);
if (s == NULL)
return FALSE;
if (! info->shared)
{
s = bfd_make_section_with_flags (abfd,
(bed->default_use_rela_p
? ".rela.bss" : ".rel.bss"),
flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, ptralign))
return FALSE;
}
}
return TRUE;
}
static bfd_boolean
sh64_elf64_adjust_dynamic_symbol (struct bfd_link_info *info,
struct elf_link_hash_entry *h)
{
bfd *dynobj;
asection *s;
unsigned int power_of_two;
dynobj = elf_hash_table (info)->dynobj;
BFD_ASSERT (dynobj != NULL
&& (h->needs_plt
|| h->u.weakdef != NULL
|| (h->def_dynamic
&& h->ref_regular
&& !h->def_regular)));
if (h->type == STT_FUNC
|| h->needs_plt)
{
if (! info->shared
&& !h->def_dynamic
&& !h->ref_dynamic)
{
BFD_ASSERT (h->needs_plt);
return TRUE;
}
if (h->dynindx == -1)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
s = bfd_get_section_by_name (dynobj, ".plt");
BFD_ASSERT (s != NULL);
if (s->size == 0)
s->size += PLT_ENTRY_SIZE;
if (! info->shared
&& !h->def_regular)
{
h->root.u.def.section = s;
h->root.u.def.value = s->size;
}
h->plt.offset = s->size;
s->size += elf_sh64_sizeof_plt (info);
s = bfd_get_section_by_name (dynobj, ".got.plt");
BFD_ASSERT (s != NULL);
s->size += 8;
s = bfd_get_section_by_name (dynobj, ".rela.plt");
BFD_ASSERT (s != NULL);
s->size += sizeof (Elf64_External_Rela);
return TRUE;
}
if (h->u.weakdef != NULL)
{
BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
|| h->u.weakdef->root.type == bfd_link_hash_defweak);
h->root.u.def.section = h->u.weakdef->root.u.def.section;
h->root.u.def.value = h->u.weakdef->root.u.def.value;
return TRUE;
}
if (info->shared)
return TRUE;
if (!h->non_got_ref)
return TRUE;
s = bfd_get_section_by_name (dynobj, ".dynbss");
BFD_ASSERT (s != NULL);
if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
{
asection *srel;
srel = bfd_get_section_by_name (dynobj, ".rela.bss");
BFD_ASSERT (srel != NULL);
srel->size += sizeof (Elf64_External_Rela);
h->needs_copy = 1;
}
power_of_two = bfd_log2 (h->size);
if (power_of_two > 3)
power_of_two = 3;
s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two));
if (power_of_two > bfd_get_section_alignment (dynobj, s))
{
if (! bfd_set_section_alignment (dynobj, s, power_of_two))
return FALSE;
}
h->root.u.def.section = s;
h->root.u.def.value = s->size;
s->size += h->size;
return TRUE;
}
static bfd_boolean
sh64_elf64_discard_copies (struct elf_sh64_link_hash_entry *h,
void *ignore ATTRIBUTE_UNUSED)
{
struct elf_sh64_pcrel_relocs_copied *s;
if (h->root.root.type == bfd_link_hash_warning)
h = (struct elf_sh64_link_hash_entry *) h->root.root.u.i.link;
if (!h->root.def_regular)
return TRUE;
for (s = h->pcrel_relocs_copied; s != NULL; s = s->next)
s->section->size -= s->count * sizeof (Elf64_External_Rela);
return TRUE;
}
static bfd_boolean
sh64_elf64_size_dynamic_sections (bfd *output_bfd,
struct bfd_link_info *info)
{
bfd *dynobj;
asection *s;
bfd_boolean plt;
bfd_boolean relocs;
bfd_boolean reltext;
dynobj = elf_hash_table (info)->dynobj;
BFD_ASSERT (dynobj != NULL);
if (elf_hash_table (info)->dynamic_sections_created)
{
if (info->executable)
{
s = bfd_get_section_by_name (dynobj, ".interp");
BFD_ASSERT (s != NULL);
s->size = sizeof ELF_DYNAMIC_INTERPRETER;
s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
}
}
else
{
s = bfd_get_section_by_name (dynobj, ".rela.got");
if (s != NULL)
s->size = 0;
}
if (info->shared && info->symbolic)
sh64_elf64_link_hash_traverse (sh64_elf64_hash_table (info),
sh64_elf64_discard_copies, NULL);
plt = FALSE;
relocs = FALSE;
reltext = FALSE;
for (s = dynobj->sections; s != NULL; s = s->next)
{
const char *name;
if ((s->flags & SEC_LINKER_CREATED) == 0)
continue;
name = bfd_get_section_name (dynobj, s);
if (strcmp (name, ".plt") == 0)
{
plt = s->size != 0;
}
else if (strncmp (name, ".rela", 5) == 0)
{
if (s->size != 0)
{
asection *target;
if (strcmp (name, ".rela.plt") != 0)
{
const char *outname;
relocs = TRUE;
outname = bfd_get_section_name (output_bfd,
s->output_section);
target = bfd_get_section_by_name (output_bfd, outname + 5);
if (target != NULL
&& (target->flags & SEC_READONLY) != 0
&& (target->flags & SEC_ALLOC) != 0)
reltext = TRUE;
}
s->reloc_count = 0;
}
}
else if (strncmp (name, ".got", 4) != 0
&& strcmp (name, ".dynbss") != 0)
{
continue;
}
if (s->size == 0)
{
s->flags |= SEC_EXCLUDE;
continue;
}
if ((s->flags & SEC_HAS_CONTENTS) == 0)
continue;
s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
if (s->contents == NULL)
return FALSE;
}
if (elf_hash_table (info)->dynamic_sections_created)
{
if (info->executable)
{
if (!_bfd_elf_add_dynamic_entry (info, DT_DEBUG, 0))
return FALSE;
}
if (plt)
{
if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_PLTRELSZ, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
|| !_bfd_elf_add_dynamic_entry (info, DT_JMPREL, 0))
return FALSE;
}
if (relocs)
{
if (!_bfd_elf_add_dynamic_entry (info, DT_RELA, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_RELASZ, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_RELAENT,
sizeof (Elf64_External_Rela)))
return FALSE;
}
if (reltext)
{
if (!_bfd_elf_add_dynamic_entry (info, DT_TEXTREL, 0))
return FALSE;
}
}
return TRUE;
}
static bfd_boolean
sh64_elf64_finish_dynamic_symbol (bfd *output_bfd,
struct bfd_link_info *info,
struct elf_link_hash_entry *h,
Elf_Internal_Sym *sym)
{
bfd *dynobj;
dynobj = elf_hash_table (info)->dynobj;
if (h->plt.offset != (bfd_vma) -1)
{
asection *splt;
asection *sgot;
asection *srel;
bfd_vma plt_index;
bfd_vma got_offset;
Elf_Internal_Rela rel;
bfd_byte *loc;
BFD_ASSERT (h->dynindx != -1);
splt = bfd_get_section_by_name (dynobj, ".plt");
sgot = bfd_get_section_by_name (dynobj, ".got.plt");
srel = bfd_get_section_by_name (dynobj, ".rela.plt");
BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
plt_index = h->plt.offset / elf_sh64_sizeof_plt (info) - 1;
got_offset = (plt_index + 3) * 8;
if (info->shared)
got_offset -= GOT_BIAS;
if (! info->shared)
{
if (elf_sh64_plt_entry == NULL)
{
elf_sh64_plt_entry = (bfd_big_endian (output_bfd) ?
elf_sh64_plt_entry_be : elf_sh64_plt_entry_le);
}
memcpy (splt->contents + h->plt.offset, elf_sh64_plt_entry,
elf_sh64_sizeof_plt (info));
movi_3shori_putval (output_bfd,
(sgot->output_section->vma
+ sgot->output_offset
+ got_offset),
(splt->contents + h->plt.offset
+ elf_sh64_plt_symbol_offset (info)));
movi_shori_putval (output_bfd,
-(h->plt.offset
+ elf_sh64_plt_plt0_offset (info) + 8)
| 1,
(splt->contents + h->plt.offset
+ elf_sh64_plt_plt0_offset (info)));
}
else
{
if (elf_sh64_pic_plt_entry == NULL)
{
elf_sh64_pic_plt_entry = (bfd_big_endian (output_bfd) ?
elf_sh64_pic_plt_entry_be :
elf_sh64_pic_plt_entry_le);
}
memcpy (splt->contents + h->plt.offset, elf_sh64_pic_plt_entry,
elf_sh64_sizeof_plt (info));
movi_shori_putval (output_bfd, got_offset,
(splt->contents + h->plt.offset
+ elf_sh64_plt_symbol_offset (info)));
}
if (info->shared)
got_offset += GOT_BIAS;
movi_shori_putval (output_bfd,
plt_index * sizeof (Elf64_External_Rela),
(splt->contents + h->plt.offset
+ elf_sh64_plt_reloc_offset (info)));
bfd_put_64 (output_bfd,
(splt->output_section->vma
+ splt->output_offset
+ h->plt.offset
+ elf_sh64_plt_temp_offset (info)),
sgot->contents + got_offset);
rel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
+ got_offset);
rel.r_info = ELF64_R_INFO (h->dynindx, R_SH_JMP_SLOT64);
rel.r_addend = 0;
rel.r_addend = GOT_BIAS;
loc = srel->contents + plt_index * sizeof (Elf64_External_Rela);
bfd_elf64_swap_reloca_out (output_bfd, &rel, loc);
if (!h->def_regular)
{
sym->st_shndx = SHN_UNDEF;
}
}
if (h->got.offset != (bfd_vma) -1)
{
asection *sgot;
asection *srel;
Elf_Internal_Rela rel;
bfd_byte *loc;
sgot = bfd_get_section_by_name (dynobj, ".got");
srel = bfd_get_section_by_name (dynobj, ".rela.got");
BFD_ASSERT (sgot != NULL && srel != NULL);
rel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
+ (h->got.offset &~ 1));
if (info->shared
&& (info->symbolic || h->dynindx == -1)
&& h->def_regular)
{
rel.r_info = ELF64_R_INFO (0, R_SH_RELATIVE64);
rel.r_addend = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
}
else
{
bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset);
rel.r_info = ELF64_R_INFO (h->dynindx, R_SH_GLOB_DAT64);
rel.r_addend = 0;
}
loc = srel->contents;
loc += srel->reloc_count++ * sizeof (Elf64_External_Rela);
bfd_elf64_swap_reloca_out (output_bfd, &rel, loc);
}
if (h->needs_copy)
{
asection *s;
Elf_Internal_Rela rel;
bfd_byte *loc;
BFD_ASSERT (h->dynindx != -1
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak));
s = bfd_get_section_by_name (h->root.u.def.section->owner,
".rela.bss");
BFD_ASSERT (s != NULL);
rel.r_offset = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
rel.r_info = ELF64_R_INFO (h->dynindx, R_SH_COPY64);
rel.r_addend = 0;
loc = s->contents;
loc += s->reloc_count++ * sizeof (Elf64_External_Rela);
bfd_elf64_swap_reloca_out (output_bfd, &rel, loc);
}
if (strcmp (h->root.root.string, "_DYNAMIC") == 0
|| strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
sym->st_shndx = SHN_ABS;
return TRUE;
}
static bfd_boolean
sh64_elf64_finish_dynamic_sections (bfd *output_bfd,
struct bfd_link_info *info)
{
bfd *dynobj;
asection *sgot;
asection *sdyn;
dynobj = elf_hash_table (info)->dynobj;
sgot = bfd_get_section_by_name (dynobj, ".got.plt");
BFD_ASSERT (sgot != NULL);
sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
if (elf_hash_table (info)->dynamic_sections_created)
{
asection *splt;
Elf64_External_Dyn *dyncon, *dynconend;
BFD_ASSERT (sdyn != NULL);
dyncon = (Elf64_External_Dyn *) sdyn->contents;
dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size);
for (; dyncon < dynconend; dyncon++)
{
Elf_Internal_Dyn dyn;
const char *name;
asection *s;
struct elf_link_hash_entry *h;
bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn);
switch (dyn.d_tag)
{
default:
break;
case DT_INIT:
name = info->init_function;
goto get_sym;
case DT_FINI:
name = info->fini_function;
get_sym:
if (dyn.d_un.d_val != 0)
{
h = elf_link_hash_lookup (elf_hash_table (info), name,
FALSE, FALSE, TRUE);
if (h != NULL && (h->other & STO_SH5_ISA32))
{
dyn.d_un.d_val |= 1;
bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
}
}
break;
case DT_PLTGOT:
name = ".got";
goto get_vma;
case DT_JMPREL:
name = ".rela.plt";
get_vma:
s = bfd_get_section_by_name (output_bfd, name);
BFD_ASSERT (s != NULL);
dyn.d_un.d_ptr = s->vma;
bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
case DT_PLTRELSZ:
s = bfd_get_section_by_name (output_bfd, ".rela.plt");
BFD_ASSERT (s != NULL);
dyn.d_un.d_val = s->size;
bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
case DT_RELASZ:
s = bfd_get_section_by_name (output_bfd, ".rela.plt");
if (s != NULL)
dyn.d_un.d_val -= s->size;
bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
}
}
splt = bfd_get_section_by_name (dynobj, ".plt");
if (splt && splt->size > 0)
{
if (info->shared)
{
if (elf_sh64_pic_plt_entry == NULL)
{
elf_sh64_pic_plt_entry = (bfd_big_endian (output_bfd) ?
elf_sh64_pic_plt_entry_be :
elf_sh64_pic_plt_entry_le);
}
memcpy (splt->contents, elf_sh64_pic_plt_entry,
elf_sh64_sizeof_plt (info));
}
else
{
if (elf_sh64_plt0_entry == NULL)
{
elf_sh64_plt0_entry = (bfd_big_endian (output_bfd) ?
elf_sh64_plt0_entry_be :
elf_sh64_plt0_entry_le);
}
memcpy (splt->contents, elf_sh64_plt0_entry, PLT_ENTRY_SIZE);
movi_3shori_putval (output_bfd,
sgot->output_section->vma
+ sgot->output_offset,
splt->contents
+ elf_sh64_plt0_gotplt_offset (info));
}
elf_section_data (splt->output_section)->this_hdr.sh_entsize = 8;
}
}
if (sgot->size > 0)
{
if (sdyn == NULL)
bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents);
else
bfd_put_64 (output_bfd,
sdyn->output_section->vma + sdyn->output_offset,
sgot->contents);
bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents + 8);
bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents + 16);
}
elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 8;
return TRUE;
}
static void
sh64_elf64_merge_symbol_attribute (struct elf_link_hash_entry *h,
const Elf_Internal_Sym *isym,
bfd_boolean definition,
bfd_boolean dynamic)
{
if (isym->st_other != 0 && dynamic)
{
unsigned char other;
other = (definition ? isym->st_other : h->other);
other &= ~ ELF_ST_VISIBILITY (-1);
h->other = other | ELF_ST_VISIBILITY (h->other);
}
return;
}
static const struct bfd_elf_special_section sh64_elf64_special_sections[]=
{
{ ".cranges", 8, 0, SHT_PROGBITS, 0 },
{ NULL, 0, 0, 0, 0 }
};
#define TARGET_BIG_SYM bfd_elf64_sh64_vec
#define TARGET_BIG_NAME "elf64-sh64"
#define TARGET_LITTLE_SYM bfd_elf64_sh64l_vec
#define TARGET_LITTLE_NAME "elf64-sh64l"
#define ELF_ARCH bfd_arch_sh
#define ELF_MACHINE_CODE EM_SH
#define ELF_MAXPAGESIZE 128
#define elf_symbol_leading_char '_'
#define bfd_elf64_bfd_reloc_type_lookup sh_elf64_reloc_type_lookup
#define elf_info_to_howto sh_elf64_info_to_howto
#define elf_backend_relocate_section sh_elf64_relocate_section
#define bfd_elf64_bfd_get_relocated_section_contents \
sh_elf64_get_relocated_section_contents
#define elf_backend_object_p sh_elf64_set_mach_from_flags
#define bfd_elf64_bfd_set_private_flags \
sh_elf64_set_private_flags
#define bfd_elf64_bfd_copy_private_bfd_data \
sh_elf64_copy_private_data
#define bfd_elf64_bfd_merge_private_bfd_data \
sh_elf64_merge_private_data
#define elf_backend_fake_sections sh64_elf64_fake_sections
#define elf_backend_gc_mark_hook sh_elf64_gc_mark_hook
#define elf_backend_gc_sweep_hook sh_elf64_gc_sweep_hook
#define elf_backend_check_relocs sh_elf64_check_relocs
#define elf_backend_can_gc_sections 1
#define elf_backend_get_symbol_type sh64_elf64_get_symbol_type
#define elf_backend_add_symbol_hook sh64_elf64_add_symbol_hook
#define elf_backend_link_output_symbol_hook \
sh64_elf64_link_output_symbol_hook
#define elf_backend_merge_symbol_attribute \
sh64_elf64_merge_symbol_attribute
#define elf_backend_final_write_processing \
sh64_elf64_final_write_processing
#define elf_backend_create_dynamic_sections \
sh64_elf64_create_dynamic_sections
#define bfd_elf64_bfd_link_hash_table_create \
sh64_elf64_link_hash_table_create
#define elf_backend_adjust_dynamic_symbol \
sh64_elf64_adjust_dynamic_symbol
#define elf_backend_size_dynamic_sections \
sh64_elf64_size_dynamic_sections
#define elf_backend_finish_dynamic_symbol \
sh64_elf64_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \
sh64_elf64_finish_dynamic_sections
#define elf_backend_special_sections sh64_elf64_special_sections
#define elf_backend_want_got_plt 1
#define elf_backend_plt_readonly 1
#define elf_backend_want_plt_sym 0
#define elf_backend_got_header_size 24
#include "elf64-target.h"
#undef TARGET_BIG_SYM
#define TARGET_BIG_SYM bfd_elf64_sh64nbsd_vec
#undef TARGET_BIG_NAME
#define TARGET_BIG_NAME "elf64-sh64-nbsd"
#undef TARGET_LITTLE_SYM
#define TARGET_LITTLE_SYM bfd_elf64_sh64lnbsd_vec
#undef TARGET_LITTLE_NAME
#define TARGET_LITTLE_NAME "elf64-sh64l-nbsd"
#undef ELF_MAXPAGESIZE
#define ELF_MAXPAGESIZE 0x10000
#undef elf_symbol_leading_char
#define elf_symbol_leading_char 0
#define elf64_bed elf64_sh64_nbsd_bed
#include "elf64-target.h"
#undef TARGET_BIG_SYM
#define TARGET_BIG_SYM bfd_elf64_sh64blin_vec
#undef TARGET_BIG_NAME
#define TARGET_BIG_NAME "elf64-sh64big-linux"
#undef TARGET_LITTLE_SYM
#define TARGET_LITTLE_SYM bfd_elf64_sh64lin_vec
#undef TARGET_LITTLE_NAME
#define TARGET_LITTLE_NAME "elf64-sh64-linux"
#define INCLUDED_TARGET_FILE
#include "elf64-target.h"