1 |
/* Scenix IP2xxx specific support for 32-bit ELF |
/* Ubicom IP2xxx specific support for 32-bit ELF |
2 |
Copyright 2000, 2001, 2002 Free Software Foundation, Inc. |
Copyright 2000, 2001, 2002, 2003, 2004, 2005 |
3 |
|
Free Software Foundation, Inc. |
4 |
|
|
5 |
This file is part of BFD, the Binary File Descriptor library. |
This file is part of BFD, the Binary File Descriptor library. |
6 |
|
|
31 |
Elf_Internal_Shdr * symtab_hdr; |
Elf_Internal_Shdr * symtab_hdr; |
32 |
Elf_Internal_Rela * irelbase; |
Elf_Internal_Rela * irelbase; |
33 |
bfd_byte * contents; |
bfd_byte * contents; |
34 |
bfd_byte * free_contents; |
Elf_Internal_Sym * isymbuf; |
|
Elf32_External_Sym * extsyms; |
|
|
Elf32_External_Sym * free_extsyms; |
|
|
Elf_Internal_Rela * free_relocs; |
|
35 |
}; |
}; |
36 |
|
|
37 |
|
struct ip2k_opcode |
38 |
|
{ |
39 |
|
unsigned short opcode; |
40 |
|
unsigned short mask; |
41 |
|
}; |
42 |
|
|
43 |
/* Prototypes. */ |
/* Prototypes. */ |
44 |
static reloc_howto_type * ip2k_reloc_type_lookup PARAMS ((bfd *, bfd_reloc_code_real_type)); |
static reloc_howto_type *ip2k_reloc_type_lookup |
45 |
static void ip2k_info_to_howto_rela PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *)); |
PARAMS ((bfd *, bfd_reloc_code_real_type)); |
46 |
static asection * ip2k_elf_gc_mark_hook PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *, struct elf_link_hash_entry *, Elf_Internal_Sym *)); |
static int ip2k_is_opcode |
47 |
static boolean ip2k_elf_gc_sweep_hook PARAMS ((bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *)); |
PARAMS ((bfd_byte *, const struct ip2k_opcode *)); |
48 |
static bfd_vma symbol_value PARAMS ((bfd *, Elf_Internal_Shdr *, Elf32_External_Sym *, Elf_Internal_Rela *)); |
static bfd_vma symbol_value |
49 |
static void adjust_all_relocations PARAMS ((bfd *, asection *, bfd_vma, bfd_vma, int, int)); |
PARAMS ((bfd *, Elf_Internal_Shdr *, Elf_Internal_Sym *, |
50 |
static boolean ip2k_elf_relax_delete_bytes PARAMS ((bfd *, asection *, bfd_vma, int)); |
Elf_Internal_Rela *)); |
51 |
static boolean ip2k_elf_relax_add_bytes PARAMS ((bfd *, asection *, bfd_vma, const bfd_byte *, int, int)); |
static void ip2k_get_mem |
52 |
static boolean add_page_insn PARAMS ((bfd *, asection *, Elf_Internal_Rela *, struct misc *)); |
PARAMS ((bfd *, bfd_byte *, int, bfd_byte *)); |
53 |
static boolean ip2k_elf_relax_section PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *)); |
static bfd_vma ip2k_nominal_page_bits |
54 |
static boolean relax_switch_dispatch_tables_pass1 PARAMS ((bfd *, asection *, bfd_vma, struct misc *)); |
PARAMS ((bfd *, asection *, bfd_vma, bfd_byte *)); |
55 |
static boolean unrelax_dispatch_table_entries PARAMS ((bfd *, asection *, bfd_vma, bfd_vma, boolean *, struct misc *)); |
static bfd_boolean ip2k_test_page_insn |
56 |
static boolean unrelax_switch_dispatch_tables_passN PARAMS ((bfd *, asection *, bfd_vma, boolean *, struct misc *)); |
PARAMS ((bfd *, asection *, Elf_Internal_Rela *, struct misc *)); |
57 |
static boolean is_switch_128_dispatch_table_p PARAMS ((bfd *, bfd_vma, boolean, struct misc *)); |
static bfd_boolean ip2k_delete_page_insn |
58 |
static boolean is_switch_256_dispatch_table_p PARAMS ((bfd *, bfd_vma, boolean, struct misc *)); |
PARAMS ((bfd *, asection *, Elf_Internal_Rela *, bfd_boolean *, struct misc *)); |
59 |
static void tidyup_after_error PARAMS ((struct misc *)); |
static int ip2k_is_switch_table_128 |
60 |
static boolean ip2k_elf_relax_section_pass1 PARAMS ((bfd *, asection *, boolean *, struct misc *)); |
PARAMS ((bfd *, asection *, bfd_vma, bfd_byte *)); |
61 |
static boolean ip2k_elf_relax_section_passN PARAMS ((bfd *, asection *, boolean *, boolean *, struct misc *)); |
static bfd_boolean ip2k_relax_switch_table_128 |
62 |
static bfd_reloc_status_type ip2k_final_link_relocate PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, bfd_vma)); |
PARAMS ((bfd *, asection *, Elf_Internal_Rela *, bfd_boolean *, struct misc *)); |
63 |
static boolean ip2k_elf_relocate_section PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); |
static int ip2k_is_switch_table_256 |
64 |
|
PARAMS ((bfd *, asection *, bfd_vma, bfd_byte *)); |
65 |
#define IS_OPCODE(CODE0,CODE1,OPCODE) \ |
static bfd_boolean ip2k_relax_switch_table_256 |
66 |
((CODE0) == (OPCODE)[0] && (CODE1) == (OPCODE)[1]) |
PARAMS ((bfd *, asection *, Elf_Internal_Rela *, bfd_boolean *, struct misc *)); |
67 |
|
static bfd_boolean ip2k_elf_relax_section |
68 |
|
PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *)); |
69 |
|
static bfd_boolean ip2k_elf_relax_section_page |
70 |
|
PARAMS ((bfd *, asection *, bfd_boolean *, struct misc *, unsigned long, unsigned long)); |
71 |
|
static void adjust_all_relocations |
72 |
|
PARAMS ((bfd *, asection *, bfd_vma, bfd_vma, int, int)); |
73 |
|
static bfd_boolean ip2k_elf_relax_delete_bytes |
74 |
|
PARAMS ((bfd *, asection *, bfd_vma, int)); |
75 |
|
static void ip2k_info_to_howto_rela |
76 |
|
PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); |
77 |
|
static bfd_reloc_status_type ip2k_final_link_relocate |
78 |
|
PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *, |
79 |
|
Elf_Internal_Rela *, bfd_vma)); |
80 |
|
static bfd_boolean ip2k_elf_relocate_section |
81 |
|
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, |
82 |
|
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); |
83 |
|
static asection *ip2k_elf_gc_mark_hook |
84 |
|
PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *, |
85 |
|
struct elf_link_hash_entry *, Elf_Internal_Sym *)); |
86 |
|
static bfd_boolean ip2k_elf_gc_sweep_hook |
87 |
|
PARAMS ((bfd *, struct bfd_link_info *, asection *, |
88 |
|
const Elf_Internal_Rela *)); |
89 |
|
|
90 |
#define PAGE_INSN_0 0x00 |
static bfd_boolean ip2k_relaxed = FALSE; |
|
#define PAGE_INSN_1 0x10 |
|
91 |
|
|
92 |
static const bfd_byte page_opcode[] = |
static const struct ip2k_opcode ip2k_page_opcode[] = |
93 |
{ |
{ |
94 |
PAGE_INSN_0, PAGE_INSN_1 |
{0x0010, 0xFFF8}, /* page */ |
95 |
|
{0x0000, 0x0000}, |
96 |
}; |
}; |
97 |
|
|
98 |
#define IS_PAGE_OPCODE(CODE0,CODE1) \ |
#define IS_PAGE_OPCODE(code) \ |
99 |
IS_OPCODE (CODE0, CODE1, page_opcode) |
ip2k_is_opcode (code, ip2k_page_opcode) |
100 |
|
|
101 |
#define JMP_INSN_0 0xE0 |
static const struct ip2k_opcode ip2k_jmp_opcode[] = |
|
#define JMP_INSN_1 0x00 |
|
|
|
|
|
static const bfd_byte jmp_opcode[] = |
|
102 |
{ |
{ |
103 |
JMP_INSN_0, JMP_INSN_1 |
{0xE000, 0xE000}, /* jmp */ |
104 |
|
{0x0000, 0x0000}, |
105 |
}; |
}; |
106 |
|
|
107 |
#define IS_JMP_OPCODE(CODE0,CODE1) \ |
#define IS_JMP_OPCODE(code) \ |
108 |
IS_OPCODE (CODE0, CODE1, jmp_opcode) |
ip2k_is_opcode (code, ip2k_jmp_opcode) |
|
|
|
|
#define CALL_INSN_0 0xC0 |
|
|
#define CALL_INSN_1 0x00 |
|
109 |
|
|
110 |
static const bfd_byte call_opcode[] = |
static const struct ip2k_opcode ip2k_snc_opcode[] = |
111 |
{ |
{ |
112 |
CALL_INSN_0, CALL_INSN_1 |
{0xA00B, 0xFFFF}, /* snc */ |
113 |
|
{0x0000, 0x0000}, |
114 |
}; |
}; |
115 |
|
|
116 |
#define IS_CALL_OPCODE(CODE0,CODE1) \ |
#define IS_SNC_OPCODE(code) \ |
117 |
IS_OPCODE (CODE0, CODE1, call_opcode) |
ip2k_is_opcode (code, ip2k_snc_opcode) |
|
|
|
|
#define ADD_PCL_W_INSN_0 0x1E |
|
|
#define ADD_PCL_W_INSN_1 0x09 |
|
118 |
|
|
119 |
static const bfd_byte add_pcl_w_opcode[] = |
static const struct ip2k_opcode ip2k_inc_1sp_opcode[] = |
120 |
{ |
{ |
121 |
ADD_PCL_W_INSN_0, ADD_PCL_W_INSN_1 |
{0x2B81, 0xFFFF}, /* inc 1(SP) */ |
122 |
|
{0x0000, 0x0000}, |
123 |
}; |
}; |
124 |
|
|
125 |
#define IS_ADD_PCL_W_OPCODE(CODE0,CODE1) \ |
#define IS_INC_1SP_OPCODE(code) \ |
126 |
IS_OPCODE (CODE0, CODE1, add_pcl_w_opcode) |
ip2k_is_opcode (code, ip2k_inc_1sp_opcode) |
127 |
|
|
128 |
#define ADD_W_WREG_INSN_0 0x1C |
static const struct ip2k_opcode ip2k_add_2sp_w_opcode[] = |
|
#define ADD_W_WREG_INSN_1 0x0A |
|
|
|
|
|
static const bfd_byte add_w_wreg_opcode[] = |
|
129 |
{ |
{ |
130 |
ADD_W_WREG_INSN_0, ADD_W_WREG_INSN_1 |
{0x1F82, 0xFFFF}, /* add 2(SP),w */ |
131 |
|
{0x0000, 0x0000}, |
132 |
}; |
}; |
133 |
|
|
134 |
#define IS_ADD_W_WREG_OPCODE(CODE0,CODE1) \ |
#define IS_ADD_2SP_W_OPCODE(code) \ |
135 |
IS_OPCODE (CODE0, CODE1, add_w_wreg_opcode) |
ip2k_is_opcode (code, ip2k_add_2sp_w_opcode) |
|
|
|
|
#define SNC_INSN_0 0xA0 |
|
|
#define SNC_INSN_1 0x0B |
|
136 |
|
|
137 |
static const bfd_byte snc_opcode[] = |
static const struct ip2k_opcode ip2k_add_w_wreg_opcode[] = |
138 |
{ |
{ |
139 |
SNC_INSN_0, SNC_INSN_1 |
{0x1C0A, 0xFFFF}, /* add w,wreg */ |
140 |
|
{0x1E0A, 0xFFFF}, /* add wreg,w */ |
141 |
|
{0x0000, 0x0000}, |
142 |
}; |
}; |
143 |
|
|
144 |
#define IS_SNC_OPCODE(CODE0,CODE1) \ |
#define IS_ADD_W_WREG_OPCODE(code) \ |
145 |
IS_OPCODE (CODE0, CODE1, snc_opcode) |
ip2k_is_opcode (code, ip2k_add_w_wreg_opcode) |
|
|
|
|
#define INC_1_SP_INSN_0 0x2B |
|
|
#define INC_1_SP_INSN_1 0x81 |
|
146 |
|
|
147 |
static const bfd_byte inc_1_sp_opcode[] = |
static const struct ip2k_opcode ip2k_add_pcl_w_opcode[] = |
148 |
{ |
{ |
149 |
INC_1_SP_INSN_0, INC_1_SP_INSN_1 |
{0x1E09, 0xFFFF}, /* add pcl,w */ |
150 |
|
{0x0000, 0x0000}, |
151 |
}; |
}; |
152 |
|
|
153 |
#define IS_INC_1_SP_OPCODE(CODE0,CODE1) \ |
#define IS_ADD_PCL_W_OPCODE(code) \ |
154 |
IS_OPCODE (CODE0, CODE1, inc_1_sp_opcode) |
ip2k_is_opcode (code, ip2k_add_pcl_w_opcode) |
155 |
|
|
156 |
#define ADD_2_SP_W_INSN_0 0x1F |
static const struct ip2k_opcode ip2k_skip_opcodes[] = |
|
#define ADD_2_SP_W_INSN_1 0x82 |
|
|
|
|
|
static const bfd_byte add_2_sp_w_opcode[] = |
|
157 |
{ |
{ |
158 |
ADD_2_SP_W_INSN_0, ADD_2_SP_W_INSN_1 |
{0xB000, 0xF000}, /* sb */ |
159 |
|
{0xA000, 0xF000}, /* snb */ |
160 |
|
{0x7600, 0xFE00}, /* cse/csne #lit */ |
161 |
|
{0x5800, 0xFC00}, /* incsnz */ |
162 |
|
{0x4C00, 0xFC00}, /* decsnz */ |
163 |
|
{0x4000, 0xFC00}, /* cse/csne */ |
164 |
|
{0x3C00, 0xFC00}, /* incsz */ |
165 |
|
{0x2C00, 0xFC00}, /* decsz */ |
166 |
|
{0x0000, 0x0000}, |
167 |
}; |
}; |
168 |
|
|
169 |
#define IS_ADD_2_SP_W_OPCODE(CODE0,CODE1) \ |
#define IS_SKIP_OPCODE(code) \ |
170 |
IS_OPCODE (CODE0, CODE1, add_2_sp_w_opcode) |
ip2k_is_opcode (code, ip2k_skip_opcodes) |
171 |
|
|
172 |
/* Relocation tables. */ |
/* Relocation tables. */ |
173 |
static reloc_howto_type ip2k_elf_howto_table [] = |
static reloc_howto_type ip2k_elf_howto_table [] = |
174 |
{ |
{ |
175 |
#define IP2K_HOWTO(t,rs,s,bs,pr,bp,name,sm,dm) \ |
#define IP2K_HOWTO(t,rs,s,bs,pr,bp,name,sm,dm) \ |
182 |
complain_overflow_dont,/* complain_on_overflow */ \ |
complain_overflow_dont,/* complain_on_overflow */ \ |
183 |
bfd_elf_generic_reloc,/* special_function */ \ |
bfd_elf_generic_reloc,/* special_function */ \ |
184 |
name, /* name */ \ |
name, /* name */ \ |
185 |
false, /* partial_inplace */ \ |
FALSE, /* partial_inplace */ \ |
186 |
sm, /* src_mask */ \ |
sm, /* src_mask */ \ |
187 |
dm, /* dst_mask */ \ |
dm, /* dst_mask */ \ |
188 |
pr) /* pcrel_offset */ |
pr) /* pcrel_offset */ |
189 |
|
|
190 |
/* This reloc does nothing. */ |
/* This reloc does nothing. */ |
191 |
IP2K_HOWTO (R_IP2K_NONE, 0,2,32, false, 0, "R_IP2K_NONE", 0, 0), |
IP2K_HOWTO (R_IP2K_NONE, 0,2,32, FALSE, 0, "R_IP2K_NONE", 0, 0), |
192 |
/* A 16 bit absolute relocation. */ |
/* A 16 bit absolute relocation. */ |
193 |
IP2K_HOWTO (R_IP2K_16, 0,1,16, false, 0, "R_IP2K_16", 0, 0xffff), |
IP2K_HOWTO (R_IP2K_16, 0,1,16, FALSE, 0, "R_IP2K_16", 0, 0xffff), |
194 |
/* A 32 bit absolute relocation. */ |
/* A 32 bit absolute relocation. */ |
195 |
IP2K_HOWTO (R_IP2K_32, 0,2,32, false, 0, "R_IP2K_32", 0, 0xffffffff), |
IP2K_HOWTO (R_IP2K_32, 0,2,32, FALSE, 0, "R_IP2K_32", 0, 0xffffffff), |
196 |
/* A 8-bit data relocation for the FR9 field. Ninth bit is computed specially. */ |
/* A 8-bit data relocation for the FR9 field. Ninth bit is computed specially. */ |
197 |
IP2K_HOWTO (R_IP2K_FR9, 0,1,9, false, 0, "R_IP2K_FR9", 0, 0x00ff), |
IP2K_HOWTO (R_IP2K_FR9, 0,1,9, FALSE, 0, "R_IP2K_FR9", 0, 0x00ff), |
198 |
/* A 4-bit data relocation. */ |
/* A 4-bit data relocation. */ |
199 |
IP2K_HOWTO (R_IP2K_BANK, 8,1,4, false, 0, "R_IP2K_BANK", 0, 0x000f), |
IP2K_HOWTO (R_IP2K_BANK, 8,1,4, FALSE, 0, "R_IP2K_BANK", 0, 0x000f), |
200 |
/* A 13-bit insn relocation - word address => right-shift 1 bit extra. */ |
/* A 13-bit insn relocation - word address => right-shift 1 bit extra. */ |
201 |
IP2K_HOWTO (R_IP2K_ADDR16CJP, 1,1,13, false, 0, "R_IP2K_ADDR16CJP", 0, 0x1fff), |
IP2K_HOWTO (R_IP2K_ADDR16CJP, 1,1,13, FALSE, 0, "R_IP2K_ADDR16CJP", 0, 0x1fff), |
202 |
/* A 3-bit insn relocation - word address => right-shift 1 bit extra. */ |
/* A 3-bit insn relocation - word address => right-shift 1 bit extra. */ |
203 |
IP2K_HOWTO (R_IP2K_PAGE3, 14,1,3, false, 0, "R_IP2K_PAGE3", 0, 0x0007), |
IP2K_HOWTO (R_IP2K_PAGE3, 14,1,3, FALSE, 0, "R_IP2K_PAGE3", 0, 0x0007), |
204 |
/* Two 8-bit data relocations. */ |
/* Two 8-bit data relocations. */ |
205 |
IP2K_HOWTO (R_IP2K_LO8DATA, 0,1,8, false, 0, "R_IP2K_LO8DATA", 0, 0x00ff), |
IP2K_HOWTO (R_IP2K_LO8DATA, 0,1,8, FALSE, 0, "R_IP2K_LO8DATA", 0, 0x00ff), |
206 |
IP2K_HOWTO (R_IP2K_HI8DATA, 8,1,8, false, 0, "R_IP2K_HI8DATA", 0, 0x00ff), |
IP2K_HOWTO (R_IP2K_HI8DATA, 8,1,8, FALSE, 0, "R_IP2K_HI8DATA", 0, 0x00ff), |
207 |
/* Two 8-bit insn relocations. word address => right-shift 1 bit extra. */ |
/* Two 8-bit insn relocations. word address => right-shift 1 bit extra. */ |
208 |
IP2K_HOWTO (R_IP2K_LO8INSN, 1,1,8, false, 0, "R_IP2K_LO8INSN", 0, 0x00ff), |
IP2K_HOWTO (R_IP2K_LO8INSN, 1,1,8, FALSE, 0, "R_IP2K_LO8INSN", 0, 0x00ff), |
209 |
IP2K_HOWTO (R_IP2K_HI8INSN, 9,1,8, false, 0, "R_IP2K_HI8INSN", 0, 0x00ff), |
IP2K_HOWTO (R_IP2K_HI8INSN, 9,1,8, FALSE, 0, "R_IP2K_HI8INSN", 0, 0x00ff), |
210 |
|
|
211 |
/* Special 1 bit relocation for SKIP instructions. */ |
/* Special 1 bit relocation for SKIP instructions. */ |
212 |
IP2K_HOWTO (R_IP2K_PC_SKIP, 1,1,1, false, 12, "R_IP2K_PC_SKIP", 0xfffe, 0x1000), |
IP2K_HOWTO (R_IP2K_PC_SKIP, 1,1,1, FALSE, 12, "R_IP2K_PC_SKIP", 0xfffe, 0x1000), |
213 |
/* 16 bit word address. */ |
/* 16 bit word address. */ |
214 |
IP2K_HOWTO (R_IP2K_TEXT, 1,1,16, false, 0, "R_IP2K_TEXT", 0, 0xffff), |
IP2K_HOWTO (R_IP2K_TEXT, 1,1,16, FALSE, 0, "R_IP2K_TEXT", 0, 0xffff), |
215 |
/* A 7-bit offset relocation for the FR9 field. Eigth and ninth bit comes from insn. */ |
/* A 7-bit offset relocation for the FR9 field. Eigth and ninth bit comes from insn. */ |
216 |
IP2K_HOWTO (R_IP2K_FR_OFFSET, 0,1,9, false, 0, "R_IP2K_FR_OFFSET", 0x180, 0x007f), |
IP2K_HOWTO (R_IP2K_FR_OFFSET, 0,1,9, FALSE, 0, "R_IP2K_FR_OFFSET", 0x180, 0x007f), |
217 |
/* Bits 23:16 of an address. */ |
/* Bits 23:16 of an address. */ |
218 |
IP2K_HOWTO (R_IP2K_EX8DATA, 16,1,8, false, 0, "R_IP2K_EX8DATA", 0, 0x00ff), |
IP2K_HOWTO (R_IP2K_EX8DATA, 16,1,8, FALSE, 0, "R_IP2K_EX8DATA", 0, 0x00ff), |
219 |
}; |
}; |
220 |
|
|
221 |
|
|
222 |
/* Map BFD reloc types to IP2K ELF reloc types. */ |
/* Map BFD reloc types to IP2K ELF reloc types. */ |
223 |
static reloc_howto_type * |
static reloc_howto_type * |
224 |
ip2k_reloc_type_lookup (abfd, code) |
ip2k_reloc_type_lookup (abfd, code) |
225 |
bfd * abfd ATTRIBUTE_UNUSED; |
bfd * abfd ATTRIBUTE_UNUSED; |
228 |
/* Note that the ip2k_elf_howto_table is indxed by the R_ |
/* Note that the ip2k_elf_howto_table is indxed by the R_ |
229 |
constants. Thus, the order that the howto records appear in the |
constants. Thus, the order that the howto records appear in the |
230 |
table *must* match the order of the relocation types defined in |
table *must* match the order of the relocation types defined in |
231 |
include/elf/ip2k.h. */ |
include/elf/ip2k.h. */ |
232 |
|
|
233 |
switch (code) |
switch (code) |
234 |
{ |
{ |
263 |
case BFD_RELOC_IP2K_EX8DATA: |
case BFD_RELOC_IP2K_EX8DATA: |
264 |
return &ip2k_elf_howto_table[ (int) R_IP2K_EX8DATA]; |
return &ip2k_elf_howto_table[ (int) R_IP2K_EX8DATA]; |
265 |
default: |
default: |
266 |
/* Pacify gcc -Wall. */ |
/* Pacify gcc -Wall. */ |
267 |
return NULL; |
return NULL; |
268 |
} |
} |
269 |
return NULL; |
return NULL; |
270 |
} |
} |
271 |
|
|
272 |
#define PAGENO(ABSADDR) ((ABSADDR) & 0x1C000) |
static void |
273 |
|
ip2k_get_mem (abfd, addr, length, ptr) |
274 |
|
bfd *abfd ATTRIBUTE_UNUSED; |
275 |
|
bfd_byte *addr; |
276 |
|
int length; |
277 |
|
bfd_byte *ptr; |
278 |
|
{ |
279 |
|
while (length --) |
280 |
|
* ptr ++ = bfd_get_8 (abfd, addr ++); |
281 |
|
} |
282 |
|
|
283 |
|
static bfd_boolean |
284 |
|
ip2k_is_opcode (code, opcodes) |
285 |
|
bfd_byte *code; |
286 |
|
const struct ip2k_opcode *opcodes; |
287 |
|
{ |
288 |
|
unsigned short insn = (code[0] << 8) | code[1]; |
289 |
|
|
290 |
|
while (opcodes->mask != 0) |
291 |
|
{ |
292 |
|
if ((insn & opcodes->mask) == opcodes->opcode) |
293 |
|
return TRUE; |
294 |
|
|
295 |
|
opcodes ++; |
296 |
|
} |
297 |
|
|
298 |
|
return FALSE; |
299 |
|
} |
300 |
|
|
301 |
|
#define PAGENO(ABSADDR) ((ABSADDR) & 0xFFFFC000) |
302 |
#define BASEADDR(SEC) ((SEC)->output_section->vma + (SEC)->output_offset) |
#define BASEADDR(SEC) ((SEC)->output_section->vma + (SEC)->output_offset) |
303 |
|
|
304 |
#define UNDEFINED_SYMBOL (~(bfd_vma)0) |
#define UNDEFINED_SYMBOL (~(bfd_vma)0) |
306 |
/* Return the value of the symbol associated with the relocation IREL. */ |
/* Return the value of the symbol associated with the relocation IREL. */ |
307 |
|
|
308 |
static bfd_vma |
static bfd_vma |
309 |
symbol_value (abfd, symtab_hdr, extsyms, irel) |
symbol_value (abfd, symtab_hdr, isymbuf, irel) |
310 |
bfd *abfd; |
bfd *abfd; |
311 |
Elf_Internal_Shdr *symtab_hdr; |
Elf_Internal_Shdr *symtab_hdr; |
312 |
Elf32_External_Sym *extsyms; |
Elf_Internal_Sym *isymbuf; |
313 |
Elf_Internal_Rela *irel; |
Elf_Internal_Rela *irel; |
314 |
{ |
{ |
315 |
if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) |
if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) |
316 |
{ |
{ |
317 |
Elf_External_Sym_Shndx *sym_shndx; |
Elf_Internal_Sym *isym; |
|
Elf_Internal_Shdr *shndx_hdr; |
|
|
Elf_Internal_Sym isym; |
|
318 |
asection *sym_sec; |
asection *sym_sec; |
319 |
|
|
320 |
shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; |
isym = isymbuf + ELF32_R_SYM (irel->r_info); |
321 |
sym_shndx = (Elf_External_Sym_Shndx *) shndx_hdr->contents; |
if (isym->st_shndx == SHN_UNDEF) |
|
sym_shndx = sym_shndx ? sym_shndx + ELF32_R_SYM (irel->r_info) : NULL; |
|
|
bfd_elf32_swap_symbol_in (abfd, extsyms + ELF32_R_SYM (irel->r_info), |
|
|
sym_shndx, &isym); |
|
|
if (isym.st_shndx == SHN_UNDEF) |
|
322 |
sym_sec = bfd_und_section_ptr; |
sym_sec = bfd_und_section_ptr; |
323 |
else if (isym.st_shndx == SHN_ABS) |
else if (isym->st_shndx == SHN_ABS) |
324 |
sym_sec = bfd_abs_section_ptr; |
sym_sec = bfd_abs_section_ptr; |
325 |
else if (isym.st_shndx == SHN_COMMON) |
else if (isym->st_shndx == SHN_COMMON) |
326 |
sym_sec = bfd_com_section_ptr; |
sym_sec = bfd_com_section_ptr; |
327 |
else |
else |
328 |
sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx); |
sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); |
329 |
|
|
330 |
return isym.st_value + BASEADDR (sym_sec); |
return isym->st_value + BASEADDR (sym_sec); |
331 |
} |
} |
332 |
else |
else |
333 |
{ |
{ |
346 |
} |
} |
347 |
} |
} |
348 |
|
|
349 |
|
/* Returns the expected page state for the given instruction not including |
350 |
|
the effect of page instructions. */ |
351 |
|
|
352 |
|
static bfd_vma |
353 |
|
ip2k_nominal_page_bits (abfd, sec, addr, contents) |
354 |
|
bfd *abfd ATTRIBUTE_UNUSED; |
355 |
|
asection *sec; |
356 |
|
bfd_vma addr; |
357 |
|
bfd_byte *contents; |
358 |
|
{ |
359 |
|
bfd_vma page = PAGENO (BASEADDR (sec) + addr); |
360 |
|
|
361 |
|
/* Check if section flows into this page. If not then the page |
362 |
|
bits are assumed to match the PC. This will be true unless |
363 |
|
the user has a page instruction without a call/jump, in which |
364 |
|
case they are on their own. */ |
365 |
|
if (PAGENO (BASEADDR (sec)) == page) |
366 |
|
return page; |
367 |
|
|
368 |
|
/* Section flows across page boundary. The page bits should match |
369 |
|
the PC unless there is a possible flow from the previous page, |
370 |
|
in which case it is not possible to determine the value of the |
371 |
|
page bits. */ |
372 |
|
while (PAGENO (BASEADDR (sec) + addr - 2) == page) |
373 |
|
{ |
374 |
|
bfd_byte code[2]; |
375 |
|
|
376 |
|
addr -= 2; |
377 |
|
ip2k_get_mem (abfd, contents + addr, 2, code); |
378 |
|
if (!IS_PAGE_OPCODE (code)) |
379 |
|
continue; |
380 |
|
|
381 |
|
/* Found a page instruction, check if jump table. */ |
382 |
|
if (ip2k_is_switch_table_128 (abfd, sec, addr, contents) != -1) |
383 |
|
/* Jump table => page is conditional. */ |
384 |
|
continue; |
385 |
|
|
386 |
|
if (ip2k_is_switch_table_256 (abfd, sec, addr, contents) != -1) |
387 |
|
/* Jump table => page is conditional. */ |
388 |
|
continue; |
389 |
|
|
390 |
|
/* Found a page instruction, check if conditional. */ |
391 |
|
if (addr >= 2) |
392 |
|
{ |
393 |
|
ip2k_get_mem (abfd, contents + addr - 2, 2, code); |
394 |
|
if (IS_SKIP_OPCODE (code)) |
395 |
|
/* Page is conditional. */ |
396 |
|
continue; |
397 |
|
} |
398 |
|
|
399 |
|
/* Unconditional page instruction => page bits should be correct. */ |
400 |
|
return page; |
401 |
|
} |
402 |
|
|
403 |
|
/* Flow from previous page => page bits are impossible to determine. */ |
404 |
|
return 0; |
405 |
|
} |
406 |
|
|
407 |
|
static bfd_boolean |
408 |
|
ip2k_test_page_insn (abfd, sec, irel, misc) |
409 |
|
bfd *abfd ATTRIBUTE_UNUSED; |
410 |
|
asection *sec; |
411 |
|
Elf_Internal_Rela *irel; |
412 |
|
struct misc *misc; |
413 |
|
{ |
414 |
|
bfd_vma symval; |
415 |
|
|
416 |
|
/* Get the value of the symbol referred to by the reloc. */ |
417 |
|
symval = symbol_value (abfd, misc->symtab_hdr, misc->isymbuf, irel); |
418 |
|
if (symval == UNDEFINED_SYMBOL) |
419 |
|
/* This appears to be a reference to an undefined |
420 |
|
symbol. Just ignore it--it will be caught by the |
421 |
|
regular reloc processing. */ |
422 |
|
return FALSE; |
423 |
|
|
424 |
|
/* Test if we can delete this page instruction. */ |
425 |
|
if (PAGENO (symval + irel->r_addend) != |
426 |
|
ip2k_nominal_page_bits (abfd, sec, irel->r_offset, misc->contents)) |
427 |
|
return FALSE; |
428 |
|
|
429 |
|
return TRUE; |
430 |
|
} |
431 |
|
|
432 |
|
static bfd_boolean |
433 |
|
ip2k_delete_page_insn (abfd, sec, irel, again, misc) |
434 |
|
bfd *abfd ATTRIBUTE_UNUSED; |
435 |
|
asection *sec; |
436 |
|
Elf_Internal_Rela *irel; |
437 |
|
bfd_boolean *again; |
438 |
|
struct misc *misc; |
439 |
|
{ |
440 |
|
/* Note that we've changed the relocs, section contents, etc. */ |
441 |
|
elf_section_data (sec)->relocs = misc->irelbase; |
442 |
|
elf_section_data (sec)->this_hdr.contents = misc->contents; |
443 |
|
misc->symtab_hdr->contents = (bfd_byte *) misc->isymbuf; |
444 |
|
|
445 |
|
/* Fix the relocation's type. */ |
446 |
|
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_IP2K_NONE); |
447 |
|
|
448 |
|
/* Delete the PAGE insn. */ |
449 |
|
if (!ip2k_elf_relax_delete_bytes (abfd, sec, irel->r_offset, 2)) |
450 |
|
return FALSE; |
451 |
|
|
452 |
|
/* Modified => will need to iterate relaxation again. */ |
453 |
|
*again = TRUE; |
454 |
|
|
455 |
|
return TRUE; |
456 |
|
} |
457 |
|
|
458 |
/* Determine if the instruction sequence matches that for |
/* Determine if the instruction sequence matches that for |
459 |
the prologue of a switch dispatch table with fewer than |
the prologue of a switch dispatch table with fewer than |
460 |
128 entries. |
128 entries. |
461 |
|
|
462 |
sc |
sc |
463 |
page $nnn0 |
page $nnn0 |
464 |
jmp $nnn0 |
jmp $nnn0 |
472 |
... |
... |
473 |
page $nnnN |
page $nnnN |
474 |
jmp $nnnN |
jmp $nnnN |
475 |
|
|
476 |
After relaxation. |
After relaxation. |
477 |
sc |
sc |
478 |
page $nnn0 |
page $nnn0 |
484 |
... |
... |
485 |
jmp $nnnN */ |
jmp $nnnN */ |
486 |
|
|
487 |
static boolean |
static int |
488 |
is_switch_128_dispatch_table_p (abfd, addr, relaxed, misc) |
ip2k_is_switch_table_128 (abfd, sec, addr, contents) |
489 |
bfd *abfd ATTRIBUTE_UNUSED; |
bfd *abfd ATTRIBUTE_UNUSED; |
490 |
|
asection *sec; |
491 |
bfd_vma addr; |
bfd_vma addr; |
492 |
boolean relaxed; |
bfd_byte *contents; |
|
struct misc *misc; |
|
493 |
{ |
{ |
494 |
bfd_byte code0, code1; |
bfd_byte code[4]; |
495 |
|
int index = 0; |
496 |
|
|
497 |
|
/* Check current page-jmp. */ |
498 |
|
if (addr + 4 > sec->size) |
499 |
|
return -1; |
500 |
|
|
501 |
|
ip2k_get_mem (abfd, contents + addr, 4, code); |
502 |
|
|
503 |
|
if ((! IS_PAGE_OPCODE (code + 0)) |
504 |
|
|| (! IS_JMP_OPCODE (code + 2))) |
505 |
|
return -1; |
506 |
|
|
507 |
|
/* Search back. */ |
508 |
|
while (1) |
509 |
|
{ |
510 |
|
if (addr < 4) |
511 |
|
return -1; |
512 |
|
|
513 |
if (addr < (3 * 2)) |
/* Check previous 2 instructions. */ |
514 |
return false; |
ip2k_get_mem (abfd, contents + addr - 4, 4, code); |
515 |
|
if ((IS_ADD_W_WREG_OPCODE (code + 0)) |
516 |
|
&& (IS_ADD_PCL_W_OPCODE (code + 2))) |
517 |
|
return index; |
518 |
|
|
519 |
|
if ((! IS_PAGE_OPCODE (code + 0)) |
520 |
|
|| (! IS_JMP_OPCODE (code + 2))) |
521 |
|
return -1; |
522 |
|
|
523 |
code0 = bfd_get_8 (abfd, misc->contents + addr - 2); |
index++; |
524 |
code1 = bfd_get_8 (abfd, misc->contents + addr - 1); |
addr -= 4; |
525 |
|
} |
526 |
|
} |
527 |
|
|
528 |
/* Is it ADD PCL,W */ |
static bfd_boolean |
529 |
if (! IS_ADD_PCL_W_OPCODE (code0, code1)) |
ip2k_relax_switch_table_128 (abfd, sec, irel, again, misc) |
530 |
return false; |
bfd *abfd ATTRIBUTE_UNUSED; |
531 |
|
asection *sec; |
532 |
|
Elf_Internal_Rela *irel; |
533 |
|
bfd_boolean *again; |
534 |
|
struct misc *misc; |
535 |
|
{ |
536 |
|
Elf_Internal_Rela *irelend = misc->irelbase + sec->reloc_count; |
537 |
|
Elf_Internal_Rela *ireltest = irel; |
538 |
|
bfd_byte code[4]; |
539 |
|
bfd_vma addr; |
540 |
|
|
541 |
|
/* Test all page instructions. */ |
542 |
|
addr = irel->r_offset; |
543 |
|
while (1) |
544 |
|
{ |
545 |
|
if (addr + 4 > sec->size) |
546 |
|
break; |
547 |
|
|
548 |
|
ip2k_get_mem (abfd, misc->contents + addr, 4, code); |
549 |
|
if ((! IS_PAGE_OPCODE (code + 0)) |
550 |
|
|| (! IS_JMP_OPCODE (code + 2))) |
551 |
|
break; |
552 |
|
|
553 |
|
/* Validate relocation entry (every entry should have a matching |
554 |
|
relocation entry). */ |
555 |
|
if (ireltest >= irelend) |
556 |
|
{ |
557 |
|
_bfd_error_handler (_("ip2k relaxer: switch table without complete matching relocation information.")); |
558 |
|
return FALSE; |
559 |
|
} |
560 |
|
|
561 |
|
if (ireltest->r_offset != addr) |
562 |
|
{ |
563 |
|
_bfd_error_handler (_("ip2k relaxer: switch table without complete matching relocation information.")); |
564 |
|
return FALSE; |
565 |
|
} |
566 |
|
|
567 |
code0 = bfd_get_8 (abfd, misc->contents + addr - 4); |
if (! ip2k_test_page_insn (abfd, sec, ireltest, misc)) |
568 |
code1 = bfd_get_8 (abfd, misc->contents + addr - 3); |
/* Un-removable page insn => nothing can be done. */ |
569 |
|
return TRUE; |
570 |
|
|
571 |
if (relaxed) |
addr += 4; |
572 |
/* Is it ADD W,WREG */ |
ireltest += 2; |
573 |
return ! IS_ADD_W_WREG_OPCODE (code0, code1); |
} |
574 |
|
|
575 |
else |
/* Relaxable. Adjust table header. */ |
576 |
|
ip2k_get_mem (abfd, misc->contents + irel->r_offset - 4, 4, code); |
577 |
|
if ((! IS_ADD_W_WREG_OPCODE (code + 0)) |
578 |
|
|| (! IS_ADD_PCL_W_OPCODE (code + 2))) |
579 |
{ |
{ |
580 |
/* Is it ADD W,WREG */ |
_bfd_error_handler (_("ip2k relaxer: switch table header corrupt.")); |
581 |
if (! IS_ADD_W_WREG_OPCODE (code0, code1)) |
return FALSE; |
582 |
return false; |
} |
583 |
|
|
584 |
|
if (!ip2k_elf_relax_delete_bytes (abfd, sec, irel->r_offset - 4, 2)) |
585 |
|
return FALSE; |
586 |
|
|
587 |
code0 = bfd_get_8 (abfd, misc->contents + addr - 6); |
*again = TRUE; |
|
code1 = bfd_get_8 (abfd, misc->contents + addr - 5); |
|
588 |
|
|
589 |
/* Is it JMP $nnnn */ |
/* Delete all page instructions in table. */ |
590 |
if (! IS_JMP_OPCODE (code0, code1)) |
while (irel < ireltest) |
591 |
return false; |
{ |
592 |
|
if (!ip2k_delete_page_insn (abfd, sec, irel, again, misc)) |
593 |
|
return FALSE; |
594 |
|
irel += 2; |
595 |
} |
} |
596 |
|
|
597 |
/* It looks like we've found the prologue for |
return TRUE; |
|
a 1-127 entry switch dispatch table. */ |
|
|
return true; |
|
598 |
} |
} |
599 |
|
|
600 |
/* Determine if the instruction sequence matches that for |
/* Determine if the instruction sequence matches that for |
601 |
the prologue switch dispatch table with fewer than |
the prologue switch dispatch table with fewer than |
602 |
256 entries but more than 127. |
256 entries but more than 127. |
603 |
|
|
604 |
Before relaxation. |
Before relaxation. |
605 |
push %lo8insn(label) ; Push address of table |
push %lo8insn(label) ; Push address of table |
606 |
push %hi8insn(label) |
push %hi8insn(label) |
621 |
... |
... |
622 |
page $nnnN |
page $nnnN |
623 |
jmp $nnnN |
jmp $nnnN |
624 |
|
|
625 |
After relaxation. |
After relaxation. |
626 |
push %lo8insn(label) ; Push address of table |
push %lo8insn(label) ; Push address of table |
627 |
push %hi8insn(label) |
push %hi8insn(label) |
637 |
... |
... |
638 |
jmp $nnnN */ |
jmp $nnnN */ |
639 |
|
|
640 |
static boolean |
static int |
641 |
is_switch_256_dispatch_table_p (abfd, addr, relaxed, misc) |
ip2k_is_switch_table_256 (abfd, sec, addr, contents) |
642 |
bfd *abfd ATTRIBUTE_UNUSED; |
bfd *abfd ATTRIBUTE_UNUSED; |
|
bfd_vma addr; |
|
|
boolean relaxed; |
|
|
struct misc *misc; |
|
|
{ |
|
|
bfd_byte code0, code1; |
|
|
|
|
|
if (addr < (8 * 2)) |
|
|
return false; |
|
|
|
|
|
code0 = bfd_get_8 (abfd, misc->contents + addr - 2); |
|
|
code1 = bfd_get_8 (abfd, misc->contents + addr - 1); |
|
|
|
|
|
/* Is it INC 1(SP). */ |
|
|
if (! IS_INC_1_SP_OPCODE (code0, code1)) |
|
|
return false; |
|
|
|
|
|
code0 = bfd_get_8 (abfd, misc->contents + addr - 4); |
|
|
code1 = bfd_get_8 (abfd, misc->contents + addr - 3); |
|
|
|
|
|
/* Is it SNC. */ |
|
|
if (! IS_SNC_OPCODE (code0, code1)) |
|
|
return false; |
|
|
|
|
|
code0 = bfd_get_8 (abfd, misc->contents + addr - 6); |
|
|
code1 = bfd_get_8 (abfd, misc->contents + addr - 5); |
|
|
|
|
|
/* Is it ADD 2(SP),W. */ |
|
|
if (! IS_ADD_2_SP_W_OPCODE (code0, code1)) |
|
|
return false; |
|
|
|
|
|
code0 = bfd_get_8 (abfd, misc->contents + addr - 8); |
|
|
code1 = bfd_get_8 (abfd, misc->contents + addr - 7); |
|
|
|
|
|
if (relaxed) |
|
|
/* Is it INC 1(SP). */ |
|
|
return ! IS_INC_1_SP_OPCODE (code0, code1); |
|
|
|
|
|
else |
|
|
{ |
|
|
/* Is it INC 1(SP). */ |
|
|
if (! IS_INC_1_SP_OPCODE (code0, code1)) |
|
|
return false; |
|
|
|
|
|
code0 = bfd_get_8 (abfd, misc->contents + addr - 10); |
|
|
code1 = bfd_get_8 (abfd, misc->contents + addr - 9); |
|
|
|
|
|
/* Is it SNC. */ |
|
|
if (! IS_SNC_OPCODE (code0, code1)) |
|
|
return false; |
|
|
|
|
|
code0 = bfd_get_8 (abfd, misc->contents + addr - 12); |
|
|
code1 = bfd_get_8 (abfd, misc->contents + addr - 11); |
|
|
|
|
|
/* Is it ADD W,WREG. */ |
|
|
if (! IS_ADD_W_WREG_OPCODE (code0, code1)) |
|
|
return false; |
|
|
} |
|
|
|
|
|
/* It looks like we've found the prologue for |
|
|
a 128-255 entry switch dispatch table. */ |
|
|
return true; |
|
|
} |
|
|
|
|
|
static boolean |
|
|
relax_switch_dispatch_tables_pass1 (abfd, sec, addr, misc) |
|
|
bfd *abfd; |
|
643 |
asection *sec; |
asection *sec; |
644 |
bfd_vma addr; |
bfd_vma addr; |
645 |
struct misc *misc; |
bfd_byte *contents; |
646 |
{ |
{ |
647 |
if (addr + 3 < sec->_cooked_size) |
bfd_byte code[16]; |
648 |
|
int index = 0; |
649 |
|
|
650 |
|
/* Check current page-jmp. */ |
651 |
|
if (addr + 4 > sec->size) |
652 |
|
return -1; |
653 |
|
|
654 |
|
ip2k_get_mem (abfd, contents + addr, 4, code); |
655 |
|
if ((! IS_PAGE_OPCODE (code + 0)) |
656 |
|
|| (! IS_JMP_OPCODE (code + 2))) |
657 |
|
return -1; |
658 |
|
|
659 |
|
/* Search back. */ |
660 |
|
while (1) |
661 |
{ |
{ |
662 |
bfd_byte code0 = bfd_get_8 (abfd, misc->contents + addr + 2); |
if (addr < 16) |
663 |
bfd_byte code1 = bfd_get_8 (abfd, misc->contents + addr + 3); |
return -1; |
664 |
|
|
665 |
if (IS_JMP_OPCODE (code0, code1) |
/* Check previous 8 instructions. */ |
666 |
&& is_switch_128_dispatch_table_p (abfd, addr, false, misc)) |
ip2k_get_mem (abfd, contents + addr - 16, 16, code); |
667 |
{ |
if ((IS_ADD_W_WREG_OPCODE (code + 0)) |
668 |
/* Delete ADD W,WREG from prologue. */ |
&& (IS_SNC_OPCODE (code + 2)) |
669 |
ip2k_elf_relax_delete_bytes (abfd, sec, addr - (2 * 2), (1 * 2)); |
&& (IS_INC_1SP_OPCODE (code + 4)) |
670 |
return true; |
&& (IS_ADD_2SP_W_OPCODE (code + 6)) |
671 |
} |
&& (IS_SNC_OPCODE (code + 8)) |
672 |
|
&& (IS_INC_1SP_OPCODE (code + 10)) |
673 |
|
&& (IS_PAGE_OPCODE (code + 12)) |
674 |
|
&& (IS_JMP_OPCODE (code + 14))) |
675 |
|
return index; |
676 |
|
|
677 |
|
if ((IS_ADD_W_WREG_OPCODE (code + 2)) |
678 |
|
&& (IS_SNC_OPCODE (code + 4)) |
679 |
|
&& (IS_INC_1SP_OPCODE (code + 6)) |
680 |
|
&& (IS_ADD_2SP_W_OPCODE (code + 8)) |
681 |
|
&& (IS_SNC_OPCODE (code + 10)) |
682 |
|
&& (IS_INC_1SP_OPCODE (code + 12)) |
683 |
|
&& (IS_JMP_OPCODE (code + 14))) |
684 |
|
return index; |
685 |
|
|
686 |
|
if ((! IS_PAGE_OPCODE (code + 0)) |
687 |
|
|| (! IS_JMP_OPCODE (code + 2))) |
688 |
|
return -1; |
689 |
|
|
690 |
if (IS_JMP_OPCODE (code0, code1) |
index++; |
691 |
&& is_switch_256_dispatch_table_p (abfd, addr, false, misc)) |
addr -= 4; |
|
{ |
|
|
/* Delete ADD W,WREG; SNC ; INC 1(SP) from prologue. */ |
|
|
ip2k_elf_relax_delete_bytes (abfd, sec, addr - 6 * 2, 3 * 2); |
|
|
return true; |
|
|
} |
|
692 |
} |
} |
|
|
|
|
return true; |
|
693 |
} |
} |
694 |
|
|
695 |
static boolean |
static bfd_boolean |
696 |
unrelax_dispatch_table_entries (abfd, sec, first, last, changed, misc) |
ip2k_relax_switch_table_256 (abfd, sec, irel, again, misc) |
697 |
bfd *abfd; |
bfd *abfd ATTRIBUTE_UNUSED; |
698 |
asection *sec; |
asection *sec; |
699 |
bfd_vma first; |
Elf_Internal_Rela *irel; |
700 |
bfd_vma last; |
bfd_boolean *again; |
|
boolean *changed; |
|
701 |
struct misc *misc; |
struct misc *misc; |
702 |
{ |
{ |
703 |
bfd_vma addr = first; |
Elf_Internal_Rela *irelend = misc->irelbase + sec->reloc_count; |
704 |
|
Elf_Internal_Rela *ireltest = irel; |
705 |
|
bfd_byte code[12]; |
706 |
|
bfd_vma addr; |
707 |
|
|
708 |
|
/* Test all page instructions. */ |
709 |
|
addr = irel->r_offset; |
710 |
|
|
711 |
while (addr < last) |
while (1) |
712 |
{ |
{ |
713 |
bfd_byte code0 = bfd_get_8 (abfd, misc->contents + addr); |
if (addr + 4 > sec->size) |
714 |
bfd_byte code1 = bfd_get_8 (abfd, misc->contents + addr + 1); |
break; |
715 |
|
|
716 |
/* We are only expecting to find PAGE or JMP insns |
ip2k_get_mem (abfd, misc->contents + addr, 4, code); |
|
in the dispatch table. If we find anything else |
|
|
something has gone wrong failed the relaxation |
|
|
which will cause the link to be aborted. */ |
|
|
|
|
|
if (IS_PAGE_OPCODE (code0, code1)) |
|
|
/* Skip the PAGE and JMP insns. */ |
|
|
addr += 4; |
|
|
else if (IS_JMP_OPCODE (code0, code1)) |
|
|
{ |
|
|
Elf_Internal_Rela * irelend = misc->irelbase |
|
|
+ sec->reloc_count; |
|
|
Elf_Internal_Rela * irel; |
|
|
|
|
|
/* Find the relocation entry. */ |
|
|
for (irel = misc->irelbase; irel < irelend; irel++) |
|
|
{ |
|
|
if (irel->r_offset == addr |
|
|
&& ELF32_R_TYPE (irel->r_info) == R_IP2K_ADDR16CJP) |
|
|
{ |
|
|
if (! add_page_insn (abfd, sec, irel, misc)) |
|
|
/* Something has gone wrong. */ |
|
|
return false; |
|
|
|
|
|
*changed = true; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
/* If we fell off the end something has gone wrong. */ |
|
|
if (irel >= irelend) |
|
|
/* Something has gone wrong. */ |
|
|
return false; |
|
|
|
|
|
/* Skip the PAGE and JMP isns. */ |
|
|
addr += 4; |
|
|
/* Acount for the new PAGE insn. */ |
|
|
last += 2; |
|
|
} |
|
|
else |
|
|
/* Something has gone wrong. */ |
|
|
return false; |
|
|
} |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
static boolean |
|
|
unrelax_switch_dispatch_tables_passN (abfd, sec, addr, changed, misc) |
|
|
bfd *abfd; |
|
|
asection *sec; |
|
|
bfd_vma addr; |
|
|
boolean *changed; |
|
|
struct misc *misc; |
|
|
{ |
|
|
if (2 <= addr && (addr + 3) < sec->_cooked_size) |
|
|
{ |
|
|
bfd_byte code0 = bfd_get_8 (abfd, misc->contents + addr - 2); |
|
|
bfd_byte code1 = bfd_get_8 (abfd, misc->contents + addr - 1); |
|
717 |
|
|
718 |
if (IS_PAGE_OPCODE (code0, code1)) |
if ((! IS_PAGE_OPCODE (code + 0)) |
719 |
{ |
|| (! IS_JMP_OPCODE (code + 2))) |
720 |
addr -= 2; |
break; |
|
code0 = bfd_get_8 (abfd, misc->contents + addr + 2); |
|
|
code1 = bfd_get_8 (abfd, misc->contents + addr + 3); |
|
|
} |
|
|
else |
|
|
{ |
|
|
code0 = bfd_get_8 (abfd, misc->contents + addr); |
|
|
code1 = bfd_get_8 (abfd, misc->contents + addr + 1); |
|
|
} |
|
721 |
|
|
722 |
if (IS_JMP_OPCODE (code0, code1) |
/* Validate relocation entry (every entry should have a matching |
723 |
&& is_switch_128_dispatch_table_p (abfd, addr, true, misc)) |
relocation entry). */ |
724 |
|
if (ireltest >= irelend) |
725 |
{ |
{ |
726 |
bfd_vma first = addr; |
_bfd_error_handler (_("ip2k relaxer: switch table without complete matching relocation information.")); |
727 |
bfd_vma last = first; |
return FALSE; |
|
boolean relaxed = true; |
|
|
|
|
|
/* On the final pass we must check if *all* entries in the |
|
|
dispatch table are relaxed. If *any* are not relaxed |
|
|
then we must unrelax *all* the entries in the dispach |
|
|
table and also unrelax the dispatch table prologue. */ |
|
|
|
|
|
/* Find the last entry in the dispach table. */ |
|
|
while (last < sec->_cooked_size) |
|
|
{ |
|
|
code0 = bfd_get_8 (abfd, misc->contents + last); |
|
|
code1 = bfd_get_8 (abfd, misc->contents + last + 1); |
|
|
|
|
|
if (IS_PAGE_OPCODE (code0, code1)) |
|
|
relaxed = false; |
|
|
else if (! IS_JMP_OPCODE (code0, code1)) |
|
|
break; |
|
|
|
|
|
last += 2; |
|
|
} |
|
|
|
|
|
/* We should have found the end of the dispatch table |
|
|
before reaching the end of the section. If we've have |
|
|
reached the end then fail the relaxation which will |
|
|
cause the link to be aborted. */ |
|
|
if (last >= sec->_cooked_size) |
|
|
/* Something has gone wrong. */ |
|
|
return false; |
|
|
|
|
|
/* If we found an unrelaxed entry then |
|
|
unlrelax all the switch table entries. */ |
|
|
if (! relaxed ) |
|
|
{ |
|
|
if (! unrelax_dispatch_table_entries (abfd, sec, first, |
|
|
last, changed, misc)) |
|
|
/* Something has gone wrong. */ |
|
|
return false; |
|
|
|
|
|
if (! is_switch_128_dispatch_table_p (abfd, addr, true, misc)) |
|
|
/* Something has gone wrong. */ |
|
|
return false; |
|
|
|
|
|
/* Unrelax the prologue. */ |
|
|
|
|
|
/* Insert an ADD W,WREG insnstruction. */ |
|
|
if (! ip2k_elf_relax_add_bytes (abfd, sec, |
|
|
addr - 2, |
|
|
add_w_wreg_opcode, |
|
|
sizeof (add_w_wreg_opcode), |
|
|
0)) |
|
|
/* Something has gone wrong. */ |
|
|
return false; |
|
|
} |
|
|
|
|
|
return true; |
|
728 |
} |
} |
729 |
|
|
730 |
if (IS_JMP_OPCODE (code0, code1) |
if (ireltest->r_offset != addr) |
|
&& is_switch_256_dispatch_table_p (abfd, addr, true, misc)) |
|
731 |
{ |
{ |
732 |
bfd_vma first = addr; |
_bfd_error_handler (_("ip2k relaxer: switch table without complete matching relocation information.")); |
733 |
bfd_vma last; |
return FALSE; |
734 |
boolean relaxed = true; |
} |
|
|
|
|
/* On the final pass we must check if *all* entries in the |
|
|
dispatch table are relaxed. If *any* are not relaxed |
|
|
then we must unrelax *all* the entries in the dispach |
|
|
table and also unrelax the dispatch table prologue. */ |
|
735 |
|
|
736 |
/* Note the 1st PAGE/JMP instructions are part of the |
if (!ip2k_test_page_insn (abfd, sec, ireltest, misc)) |
737 |
prologue and can safely be relaxed. */ |
/* Un-removable page insn => nothing can be done. */ |
738 |
|
return TRUE; |
739 |
|
|
740 |
|
addr += 4; |
741 |
|
ireltest += 2; |
742 |
|
} |
743 |
|
|
744 |
code0 = bfd_get_8 (abfd, misc->contents + first); |
/* Relaxable. Adjust table header. */ |
745 |
code1 = bfd_get_8 (abfd, misc->contents + first + 1); |
ip2k_get_mem (abfd, misc->contents + irel->r_offset - 4, 2, code); |
746 |
|
if (IS_PAGE_OPCODE (code)) |
747 |
|
addr = irel->r_offset - 16; |
748 |
|
else |
749 |
|
addr = irel->r_offset - 14; |
750 |
|
|
751 |
if (IS_PAGE_OPCODE (code0, code1)) |
ip2k_get_mem (abfd, misc->contents + addr, 12, code); |
752 |
{ |
if ((!IS_ADD_W_WREG_OPCODE (code + 0)) |
753 |
first += 2; |
|| (!IS_SNC_OPCODE (code + 2)) |
754 |
code0 = bfd_get_8 (abfd, misc->contents + first); |
|| (!IS_INC_1SP_OPCODE (code + 4)) |
755 |
code1 = bfd_get_8 (abfd, misc->contents + first + 1); |
|| (!IS_ADD_2SP_W_OPCODE (code + 6)) |
756 |
} |
|| (!IS_SNC_OPCODE (code + 8)) |
757 |
|
|| (!IS_INC_1SP_OPCODE (code + 10))) |
758 |
|
{ |
759 |
|
_bfd_error_handler (_("ip2k relaxer: switch table header corrupt.")); |
760 |
|
return FALSE; |
761 |
|
} |
762 |
|
|
763 |
if (! IS_JMP_OPCODE (code0, code1)) |
/* Delete first 3 opcodes. */ |
764 |
/* Something has gone wrong. */ |
if (!ip2k_elf_relax_delete_bytes (abfd, sec, addr + 0, 6)) |
765 |
return false; |
return FALSE; |
|
|
|
|
first += 2; |
|
|
last = first; |
|
|
|
|
|
/* Find the last entry in the dispach table. */ |
|
|
while (last < sec->_cooked_size) |
|
|
{ |
|
|
code0 = bfd_get_8 (abfd, misc->contents + last); |
|
|
code1 = bfd_get_8 (abfd, misc->contents + last + 1); |
|
|
|
|
|
if (IS_PAGE_OPCODE (code0, code1)) |
|
|
relaxed = false; |
|
|
else if (! IS_JMP_OPCODE (code0, code1)) |
|
|
break; |
|
|
|
|
|
last += 2; |
|
|
} |
|
|
|
|
|
/* We should have found the end of the dispatch table |
|
|
before reaching the end of the section. If we have |
|
|
reached the end of the section then fail the |
|
|
relaxation. */ |
|
|
if (last >= sec->_cooked_size) |
|
|
return false; |
|
|
|
|
|
/* If we found an unrelaxed entry then |
|
|
unrelax all the switch table entries. */ |
|
|
if (! relaxed) |
|
|
{ |
|
|
if (! unrelax_dispatch_table_entries (abfd, sec, first, |
|
|
last, changed, misc)) |
|
|
return false; |
|
|
|
|
|
if (! is_switch_256_dispatch_table_p (abfd, addr, true, misc)) |
|
|
return false; |
|
|
|
|
|
/* Unrelax the prologue. */ |
|
|
|
|
|
/* Insert an INC 1(SP) insnstruction. */ |
|
|
if (! ip2k_elf_relax_add_bytes (abfd, sec, |
|
|
addr - 6, |
|
|
inc_1_sp_opcode, |
|
|
sizeof (inc_1_sp_opcode), |
|
|
0)) |
|
|
return false; |
|
|
|
|
|
/* Insert an SNC insnstruction. */ |
|
|
if (! ip2k_elf_relax_add_bytes (abfd, sec, |
|
|
addr - 6, |
|
|
snc_opcode, |
|
|
sizeof (snc_opcode), |
|
|
0)) |
|
|
return false; |
|
|
|
|
|
/* Insert an ADD W,WREG insnstruction. */ |
|
|
if (! ip2k_elf_relax_add_bytes (abfd, sec, |
|
|
addr - 6, |
|
|
add_w_wreg_opcode, |
|
|
sizeof (add_w_wreg_opcode), |
|
|
0)) |
|
|
return false; |
|
|
} |
|
766 |
|
|
767 |
return true; |
*again = TRUE; |
768 |
} |
|
769 |
|
/* Delete all page instructions in table. */ |
770 |
|
while (irel < ireltest) |
771 |
|
{ |
772 |
|
if (!ip2k_delete_page_insn (abfd, sec, irel, again, misc)) |
773 |
|
return FALSE; |
774 |
|
irel += 2; |
775 |
} |
} |
776 |
|
|
777 |
return true; |
return TRUE; |
778 |
} |
} |
779 |
|
|
780 |
/* This function handles relaxing for the ip2k. */ |
/* This function handles relaxing for the ip2k. |
781 |
|
|
782 |
|
Principle: Start with the first page and remove page instructions that |
783 |
|
are not require on this first page. By removing page instructions more |
784 |
|
code will fit into this page - repeat until nothing more can be achieved |
785 |
|
for this page. Move on to the next page. |
786 |
|
|
787 |
static boolean |
Processing the pages one at a time from the lowest page allows a removal |
788 |
|
only policy to be used - pages can be removed but are never reinserted. */ |
789 |
|
|
790 |
|
static bfd_boolean |
791 |
ip2k_elf_relax_section (abfd, sec, link_info, again) |
ip2k_elf_relax_section (abfd, sec, link_info, again) |
792 |
bfd *abfd; |
bfd *abfd; |
793 |
asection *sec; |
asection *sec; |
794 |
struct bfd_link_info *link_info; |
struct bfd_link_info *link_info; |
795 |
boolean *again; |
bfd_boolean *again; |
796 |
{ |
{ |
797 |
Elf_External_Sym_Shndx *shndx_buf; |
Elf_Internal_Shdr *symtab_hdr; |
798 |
Elf_Internal_Shdr *shndx_hdr; |
Elf_Internal_Rela *internal_relocs; |
799 |
|
bfd_byte *contents = NULL; |
800 |
|
Elf_Internal_Sym *isymbuf = NULL; |
801 |
static asection * first_section = NULL; |
static asection * first_section = NULL; |
802 |
static asection * last_section = NULL; |
static unsigned long search_addr; |
803 |
static boolean changed = false; |
static unsigned long page_start = 0; |
804 |
static boolean final_pass = false; |
static unsigned long page_end = 0; |
805 |
static unsigned int pass = 0; |
static unsigned int pass = 0; |
806 |
|
static bfd_boolean new_pass = FALSE; |
807 |
|
static bfd_boolean changed = FALSE; |
808 |
struct misc misc; |
struct misc misc; |
809 |
asection *stab; |
asection *stab; |
810 |
|
|
811 |
/* Assume nothing changes. */ |
/* Assume nothing changes. */ |
812 |
*again = false; |
*again = FALSE; |
813 |
|
|
814 |
if (first_section == NULL) |
if (first_section == NULL) |
815 |
first_section = sec; |
{ |
816 |
|
ip2k_relaxed = TRUE; |
817 |
|
first_section = sec; |
818 |
|
} |
819 |
|
|
820 |
if (first_section == sec) |
if (first_section == sec) |
821 |
{ |
{ |
|
changed = false; |
|
822 |
pass++; |
pass++; |
823 |
|
new_pass = TRUE; |
824 |
} |
} |
825 |
|
|
|
/* If we make too many passes then it's a sign that |
|
|
something is wrong and we fail the relaxation. |
|
|
Note if everything is working correctly then the |
|
|
relaxation should converge reasonably quickly. */ |
|
|
if (pass == 4096) |
|
|
return false; |
|
|
|
|
826 |
/* We don't have to do anything for a relocatable link, |
/* We don't have to do anything for a relocatable link, |
827 |
if this section does not have relocs, or if this is |
if this section does not have relocs, or if this is |
828 |
not a code section. */ |
not a code section. */ |
829 |
if (link_info->relocateable |
if (link_info->relocatable |
830 |
|| (sec->flags & SEC_RELOC) == 0 |
|| (sec->flags & SEC_RELOC) == 0 |
831 |
|| sec->reloc_count == 0 |
|| sec->reloc_count == 0 |
832 |
|| (sec->flags & SEC_CODE) == 0) |
|| (sec->flags & SEC_CODE) == 0) |
833 |
return true; |
return TRUE; |
|
|
|
|
if (pass == 1) |
|
|
last_section = sec; |
|
834 |
|
|
835 |
misc.symtab_hdr = NULL; |
symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
|
misc.irelbase = NULL; |
|
|
misc.contents = NULL; |
|
|
misc.free_contents = NULL; |
|
|
misc.extsyms = NULL; |
|
|
misc.free_extsyms = NULL; |
|
|
misc.free_relocs = NULL; |
|
|
|
|
|
/* If this is the first time we have been called |
|
|
for this section, initialise the cooked size. */ |
|
|
if (sec->_cooked_size == 0) |
|
|
sec->_cooked_size = sec->_raw_size; |
|
|
|
|
|
misc.symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
|
|
shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; |
|
|
|
|
|
misc.irelbase = _bfd_elf32_link_read_relocs (abfd, sec, NULL, |
|
|
(Elf_Internal_Rela *)NULL, |
|
|
link_info->keep_memory); |
|
|
if (misc.irelbase == NULL) |
|
|
{ |
|
|
tidyup_after_error (&misc); |
|
|
return false; |
|
|
} |
|
836 |
|
|
837 |
if (! link_info->keep_memory) |
internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, |
838 |
misc.free_relocs = misc.irelbase; |
(Elf_Internal_Rela *)NULL, |
839 |
|
link_info->keep_memory); |
840 |
|
if (internal_relocs == NULL) |
841 |
|
goto error_return; |
842 |
|
|
843 |
/* Make sure the stac.rela stuff gets read in. */ |
/* Make sure the stac.rela stuff gets read in. */ |
844 |
stab = bfd_get_section_by_name (abfd, ".stab"); |
stab = bfd_get_section_by_name (abfd, ".stab"); |
848 |
/* So stab does exits. */ |
/* So stab does exits. */ |
849 |
Elf_Internal_Rela * irelbase; |
Elf_Internal_Rela * irelbase; |
850 |
|
|
851 |
irelbase = _bfd_elf32_link_read_relocs (abfd, stab, NULL, |
irelbase = _bfd_elf_link_read_relocs (abfd, stab, NULL, |
852 |
(Elf_Internal_Rela *)NULL, |
(Elf_Internal_Rela *)NULL, |
853 |
link_info->keep_memory); |
link_info->keep_memory); |
854 |
} |
} |
855 |
|
|
856 |
/* Get section contents cached copy if it exists. */ |
/* Get section contents cached copy if it exists. */ |
857 |
if (elf_section_data (sec)->this_hdr.contents != NULL) |
if (contents == NULL) |
|
misc.contents = elf_section_data (sec)->this_hdr.contents; |
|
|
else |
|
858 |
{ |
{ |
859 |
/* Go get them of disk. */ |
/* Get cached copy if it exists. */ |
860 |
misc.contents = (bfd_byte *) bfd_malloc (sec->_raw_size); |
if (elf_section_data (sec)->this_hdr.contents != NULL) |
861 |
if (misc.contents == NULL) |
contents = elf_section_data (sec)->this_hdr.contents; |
862 |
{ |
else |
|
tidyup_after_error (&misc); |
|
|
return false; |
|
|
} |
|
|
|
|
|
misc.free_contents = misc.contents; |
|
|
if (! bfd_get_section_contents (abfd, sec, misc.contents, |
|
|
(file_ptr)0, |
|
|
sec->_raw_size)) |
|
863 |
{ |
{ |
864 |
tidyup_after_error (&misc); |
/* Go get them off disk. */ |
865 |
return false; |
if (!bfd_malloc_and_get_section (abfd, sec, &contents)) |
866 |
|
goto error_return; |
867 |
} |
} |
868 |
} |
} |
869 |
|
|
870 |
/* Read this BFD's symbols cached copy if it exists. */ |
/* Read this BFD's symbols cached copy if it exists. */ |
871 |
if (misc.symtab_hdr->contents != NULL) |
if (isymbuf == NULL && symtab_hdr->sh_info != 0) |
|
misc.extsyms = (Elf32_External_Sym *) misc.symtab_hdr->contents; |
|
|
else |
|
872 |
{ |
{ |
873 |
/* Go get them off disk. */ |
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; |
874 |
misc.extsyms = ((Elf32_External_Sym *)bfd_malloc (misc.symtab_hdr->sh_size)); |
if (isymbuf == NULL) |
875 |
if (misc.extsyms == NULL) |
isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, |
876 |
{ |
symtab_hdr->sh_info, 0, |
877 |
tidyup_after_error (&misc); |
NULL, NULL, NULL); |
878 |
return false; |
if (isymbuf == NULL) |
879 |
} |
goto error_return; |
|
|
|
|
misc.free_extsyms = misc.extsyms; |
|
|
if (bfd_seek (abfd, misc.symtab_hdr->sh_offset, SEEK_SET) != 0 |
|
|
|| (bfd_read (misc.extsyms, 1, misc.symtab_hdr->sh_size, abfd) |
|
|
!= misc.symtab_hdr->sh_size)) |
|
|
{ |
|
|
tidyup_after_error (&misc); |
|
|
return false; |
|
|
} |
|
880 |
} |
} |
881 |
|
|
882 |
if (shndx_hdr->sh_size != 0) |
misc.symtab_hdr = symtab_hdr; |
883 |
{ |
misc.isymbuf = isymbuf; |
884 |
bfd_size_type amt; |
misc.irelbase = internal_relocs; |
885 |
|
misc.contents = contents; |
|
amt = misc.symtab_hdr->sh_info * sizeof (Elf_External_Sym_Shndx); |
|
|
shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt); |
|
|
if (shndx_buf == NULL) |
|
|
{ |
|
|
tidyup_after_error (&misc); |
|
|
return false; |
|
|
} |
|
|
if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0 |
|
|
|| bfd_bread ((PTR) shndx_buf, amt, abfd) != amt) |
|
|
{ |
|
|
tidyup_after_error (&misc); |
|
|
return false; |
|
|
} |
|
|
shndx_hdr->contents = (PTR) shndx_buf; |
|
|
} |
|
886 |
|
|
887 |
/* This is where all the relaxation actually get done. */ |
/* This is where all the relaxation actually get done. */ |
888 |
|
if ((pass == 1) || (new_pass && !changed)) |
|
if (pass == 1) |
|
889 |
{ |
{ |
890 |
/* On the first pass we remove *all* page instructions and |
/* On the first pass we simply search for the lowest page that |
891 |
relax the prolog for switch dispatch tables. This gets |
we havn't relaxed yet. Note that the pass count is reset |
892 |
us to the starting point for subsequent passes where |
each time a page is complete in order to move on to the next page. |
893 |
we add page instructions back in as needed. */ |
If we can't find any more pages then we are finished. */ |
894 |
|
if (new_pass) |
895 |
|
{ |
896 |
|
pass = 1; |
897 |
|
new_pass = FALSE; |
898 |
|
changed = TRUE; /* Pre-initialize to break out of pass 1. */ |
899 |
|
search_addr = 0xFFFFFFFF; |
900 |
|
} |
901 |
|
|
902 |
if (! ip2k_elf_relax_section_pass1 (abfd, sec, again, &misc)) |
if ((BASEADDR (sec) + sec->size < search_addr) |
903 |
{ |
&& (BASEADDR (sec) + sec->size > page_end)) |
904 |
tidyup_after_error (&misc); |
{ |
905 |
return false; |
if (BASEADDR (sec) <= page_end) |
906 |
} |
search_addr = page_end + 1; |
907 |
|
else |
908 |
|
search_addr = BASEADDR (sec); |
909 |
|
|
910 |
changed |= *again; |
/* Found a page => more work to do. */ |
911 |
|
*again = TRUE; |
912 |
|
} |
913 |
} |
} |
914 |
else |
else |
915 |
{ |
{ |
916 |
/* Add page instructions back in as needed but we ignore |
if (new_pass) |
|
the issue with sections (functions) crossing a page |
|
|
boundary until we have converged to an approximate |
|
|
solution (i.e. nothing has changed on this relaxation |
|
|
pass) and we then know roughly where the page boundaries |
|
|
will end up. |
|
|
|
|
|
After we have have converged to an approximate solution |
|
|
we set the final pass flag and continue relaxing. On these |
|
|
final passes if a section (function) cross page boundary |
|
|
we will add *all* the page instructions back into such |
|
|
sections. |
|
|
|
|
|
After adding *all* page instructions back into a section |
|
|
which crosses a page bounbdary we reset the final pass flag |
|
|
so the we will again interate until we find a new approximate |
|
|
solution which is closer to the final solution. */ |
|
|
|
|
|
if (! ip2k_elf_relax_section_passN (abfd, sec, again, |
|
|
&final_pass, &misc)) |
|
917 |
{ |
{ |
918 |
tidyup_after_error (&misc); |
new_pass = FALSE; |
919 |
return false; |
changed = FALSE; |
920 |
|
page_start = PAGENO (search_addr); |
921 |
|
page_end = page_start | 0x00003FFF; |
922 |
} |
} |
923 |
|
|
924 |
changed |= *again; |
/* Only process sections in range. */ |
925 |
|
if ((BASEADDR (sec) + sec->size >= page_start) |
926 |
/* If nothing has changed on this relaxation |
&& (BASEADDR (sec) <= page_end)) |
|
pass restart the final relaxaton pass. */ |
|
|
if (! changed && last_section == sec) |
|
927 |
{ |
{ |
928 |
/* If this was the final pass and we didn't reset |
if (!ip2k_elf_relax_section_page (abfd, sec, &changed, &misc, page_start, page_end)) |
929 |
the final pass flag then we are done, otherwise |
return FALSE; |
|
do another final pass. */ |
|
|
if (! final_pass) |
|
|
{ |
|
|
final_pass = true; |
|
|
*again = true; |
|
|
} |
|
930 |
} |
} |
931 |
|
*again = TRUE; |
932 |
} |
} |
933 |
|
|
934 |
/* Perform some house keeping after relaxing the section. */ |
/* Perform some house keeping after relaxing the section. */ |
935 |
|
|
936 |
if (misc.free_relocs != NULL) |
if (isymbuf != NULL |
937 |
{ |
&& symtab_hdr->contents != (unsigned char *) isymbuf) |
|
free (misc.free_relocs); |
|
|
misc.free_relocs = NULL; |
|
|
} |
|
|
|
|
|
if (misc.free_contents != NULL) |
|
938 |
{ |
{ |
939 |
if (! link_info->keep_memory) |
if (! link_info->keep_memory) |
940 |
free (misc.free_contents); |
free (isymbuf); |
941 |
else |
else |
942 |
{ |
symtab_hdr->contents = (unsigned char *) isymbuf; |
|
/* Cache the section contents for elf_link_input_bfd. */ |
|
|
elf_section_data (sec)->this_hdr.contents = misc.contents; |
|
|
} |
|
|
|
|
|
misc.free_contents = NULL; |
|
943 |
} |
} |
944 |
|
|
945 |
if (misc.free_extsyms != NULL) |
if (contents != NULL |
946 |
|
&& elf_section_data (sec)->this_hdr.contents != contents) |
947 |
{ |
{ |
948 |
if (! link_info->keep_memory) |
if (! link_info->keep_memory) |
949 |
free (misc.free_extsyms); |
free (contents); |
950 |
else |
else |
951 |
{ |
{ |
952 |
/* Cache the symbols for elf_link_input_bfd. */ |
/* Cache the section contents for elf_link_input_bfd. */ |
953 |
misc.symtab_hdr->contents = misc.extsyms; |
elf_section_data (sec)->this_hdr.contents = contents; |
954 |
} |
} |
|
|
|
|
misc.free_extsyms = NULL; |
|
955 |
} |
} |
956 |
|
|
957 |
return true; |
if (internal_relocs != NULL |
958 |
|
&& elf_section_data (sec)->relocs != internal_relocs) |
959 |
|
free (internal_relocs); |
960 |
|
|
961 |
|
return TRUE; |
962 |
|
|
963 |
|
error_return: |
964 |
|
if (isymbuf != NULL |
965 |
|
&& symtab_hdr->contents != (unsigned char *) isymbuf) |
966 |
|
free (isymbuf); |
967 |
|
if (contents != NULL |
968 |
|
&& elf_section_data (sec)->this_hdr.contents != contents) |
969 |
|
free (contents); |
970 |
|
if (internal_relocs != NULL |
971 |
|
&& elf_section_data (sec)->relocs != internal_relocs) |
972 |
|
free (internal_relocs); |
973 |
|
return FALSE; |
974 |
} |
} |
975 |
|
|
976 |
static void |
/* This function handles relaxation of a section in a specific page. */ |
|
tidyup_after_error (misc) |
|
|
struct misc *misc; |
|
|
{ |
|
|
if (misc->free_relocs != NULL) |
|
|
{ |
|
|
free (misc->free_relocs); |
|
|
misc->free_relocs = NULL; |
|
|
} |
|
|
|
|
|
if (misc->free_contents != NULL) |
|
|
{ |
|
|
free (misc->free_contents); |
|
|
misc->free_contents = NULL; |
|
|
} |
|
|
|
|
|
if (misc->free_extsyms != NULL) |
|
|
{ |
|
|
free (misc->free_extsyms); |
|
|
misc->free_extsyms = NULL; |
|
|
} |
|
|
|
|
|
return; |
|
|
} |
|
977 |
|
|
978 |
/* This function handles relaxation during the first pass. */ |
static bfd_boolean |
979 |
|
ip2k_elf_relax_section_page (abfd, sec, again, misc, page_start, page_end) |
|
static boolean |
|
|
ip2k_elf_relax_section_pass1 (abfd, sec, again, misc) |
|
980 |
bfd *abfd; |
bfd *abfd; |
981 |
asection *sec; |
asection *sec; |
982 |
boolean *again; |
bfd_boolean *again; |
983 |
struct misc * misc; |
struct misc *misc; |
984 |
|
unsigned long page_start; |
985 |
|
unsigned long page_end; |
986 |
{ |
{ |
987 |
Elf_Internal_Rela *irelend = misc->irelbase + sec->reloc_count; |
Elf_Internal_Rela *irelend = misc->irelbase + sec->reloc_count; |
988 |
Elf_Internal_Rela *irel; |
Elf_Internal_Rela *irel; |
989 |
|
int switch_table_128; |
990 |
/* Walk thru the section looking for relaxation opertunities. */ |
int switch_table_256; |
991 |
|
|
992 |
|
/* Walk thru the section looking for relaxation opportunities. */ |
993 |
for (irel = misc->irelbase; irel < irelend; irel++) |
for (irel = misc->irelbase; irel < irelend; irel++) |
994 |
{ |
{ |
995 |
if (ELF32_R_TYPE (irel->r_info) == (int) R_IP2K_PAGE3) |
if (ELF32_R_TYPE (irel->r_info) != (int) R_IP2K_PAGE3) |
996 |
{ |
/* Ignore non page instructions. */ |
997 |
bfd_byte code0 = bfd_get_8 (abfd, |
continue; |
998 |
misc->contents + irel->r_offset); |
|
999 |
bfd_byte code1 = bfd_get_8 (abfd, |
if (BASEADDR (sec) + irel->r_offset < page_start) |
1000 |
misc->contents + irel->r_offset + 1); |
/* Ignore page instructions on earlier page - they have |
1001 |
|
already been processed. Remember that there is code flow |
1002 |
/* Verify that this is the PAGE opcode. */ |
that crosses a page boundary. */ |
1003 |
if (IS_PAGE_OPCODE (code0, code1)) |
continue; |
1004 |
{ |
|
1005 |
/* Note that we've changed the relocs, section contents, etc. */ |
if (BASEADDR (sec) + irel->r_offset > page_end) |
1006 |
elf_section_data (sec)->relocs = misc->irelbase; |
/* Flow beyond end of page => nothing more to do for this page. */ |
1007 |
misc->free_relocs = NULL; |
return TRUE; |
1008 |
|
|
1009 |
elf_section_data (sec)->this_hdr.contents = misc->contents; |
/* Detect switch tables. */ |
1010 |
misc->free_contents = NULL; |
switch_table_128 = ip2k_is_switch_table_128 (abfd, sec, irel->r_offset, misc->contents); |
1011 |
|
switch_table_256 = ip2k_is_switch_table_256 (abfd, sec, irel->r_offset, misc->contents); |
1012 |
misc->symtab_hdr->contents = (bfd_byte *) misc->extsyms; |
|
1013 |
misc->free_extsyms = NULL; |
if ((switch_table_128 > 0) || (switch_table_256 > 0)) |
1014 |
|
/* If the index is greater than 0 then it has already been processed. */ |
1015 |
/* Handle switch dispatch tables/prologues. */ |
continue; |
|
if (! relax_switch_dispatch_tables_pass1 (abfd, sec, |
|
|
irel->r_offset, misc)) |
|
|
return false; |
|
|
|
|
|
/* Fix the relocation's type. */ |
|
|
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), |
|
|
R_IP2K_NONE); |
|
|
|
|
|
/* Delete the PAGE insn. */ |
|
|
if (! ip2k_elf_relax_delete_bytes (abfd, sec, |
|
|
irel->r_offset, |
|
|
sizeof (page_opcode))) |
|
|
return false; |
|
|
|
|
|
/* That will change things, so, we should relax again. |
|
|
Note that this is not required, and it may be slow. */ |
|
|
*again = true; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
return true; |
|
|
} |
|
1016 |
|
|
1017 |
/* This function handles relaxation for 2nd and subsequent passes. */ |
if (switch_table_128 == 0) |
1018 |
|
{ |
1019 |
|
if (!ip2k_relax_switch_table_128 (abfd, sec, irel, again, misc)) |
1020 |
|
return FALSE; |
1021 |
|
|
1022 |
static boolean |
continue; |
1023 |
ip2k_elf_relax_section_passN (abfd, sec, again, final_pass, misc) |
} |
|
bfd *abfd; |
|
|
asection *sec; |
|
|
boolean *again; |
|
|
boolean *final_pass; |
|
|
struct misc * misc; |
|
|
{ |
|
|
Elf_Internal_Rela *irelend = misc->irelbase + sec->reloc_count; |
|
|
Elf_Internal_Rela *irel; |
|
|
boolean add_all; |
|
1024 |
|
|
1025 |
/* If we are on the final relaxation pass and the section crosses |
if (switch_table_256 == 0) |
|
then set a flag to indicate that *all* page instructions need |
|
|
to be added back into this section. */ |
|
|
if (*final_pass) |
|
|
{ |
|
|
add_all = (PAGENO (BASEADDR (sec)) |
|
|
!= PAGENO (BASEADDR (sec) + sec->_cooked_size)); |
|
|
|
|
|
/* If this section crosses a page boundary set the crossed |
|
|
page boundary flag. */ |
|
|
if (add_all) |
|
|
sec->userdata = sec; |
|
|
else |
|
1026 |
{ |
{ |
1027 |
/* If the section had previously crossed a page boundary |
if (!ip2k_relax_switch_table_256 (abfd, sec, irel, again, misc)) |
1028 |
but on this pass does not then reset crossed page |
return FALSE; |
1029 |
boundary flag and rerun the 1st relaxation pass on |
|
1030 |
this section. */ |
continue; |
|
if (sec->userdata) |
|
|
{ |
|
|
sec->userdata = NULL; |
|
|
if (! ip2k_elf_relax_section_pass1 (abfd, sec, again, misc)) |
|
|
return false; |
|
|
} |
|
1031 |
} |
} |
|
} |
|
|
else |
|
|
add_all = false; |
|
1032 |
|
|
1033 |
/* Walk thru the section looking for call/jmp |
/* Simple relax. */ |
1034 |
instructions which need a page instruction. */ |
if (ip2k_test_page_insn (abfd, sec, irel, misc)) |
1035 |
for (irel = misc->irelbase; irel < irelend; irel++) |
{ |
1036 |
{ |
if (!ip2k_delete_page_insn (abfd, sec, irel, again, misc)) |
1037 |
if (ELF32_R_TYPE (irel->r_info) == (int) R_IP2K_ADDR16CJP) |
return FALSE; |
|
{ |
|
|
/* Get the value of the symbol referred to by the reloc. */ |
|
|
bfd_vma symval = symbol_value (abfd, misc->symtab_hdr, misc->extsyms, |
|
|
irel); |
|
|
bfd_byte code0, code1; |
|
|
|
|
|
if (symval == UNDEFINED_SYMBOL) |
|
|
{ |
|
|
/* This appears to be a reference to an undefined |
|
|
symbol. Just ignore it--it will be caught by the |
|
|
regular reloc processing. */ |
|
|
continue; |
|
|
} |
|
1038 |
|
|
1039 |
/* For simplicity of coding, we are going to modify the section |
continue; |
1040 |
contents, the section relocs, and the BFD symbol table. We |
} |
|
must tell the rest of the code not to free up this |
|
|
information. It would be possible to instead create a table |
|
|
of changes which have to be made, as is done in coff-mips.c; |
|
|
that would be more work, but would require less memory when |
|
|
the linker is run. */ |
|
|
|
|
|
/* Get the opcode. */ |
|
|
code0 = bfd_get_8 (abfd, misc->contents + irel->r_offset); |
|
|
code1 = bfd_get_8 (abfd, misc->contents + irel->r_offset + 1); |
|
|
|
|
|
if (IS_JMP_OPCODE (code0, code1) || IS_CALL_OPCODE (code0, code1)) |
|
|
{ |
|
|
if (*final_pass) |
|
|
{ |
|
|
if (! unrelax_switch_dispatch_tables_passN (abfd, sec, |
|
|
irel->r_offset, |
|
|
again, misc)) |
|
|
return false; |
|
|
|
|
|
if (*again) |
|
|
add_all = false; |
|
|
} |
|
|
|
|
|
code0 = bfd_get_8 (abfd, misc->contents + irel->r_offset - 2); |
|
|
code1 = bfd_get_8 (abfd, misc->contents + irel->r_offset - 1); |
|
|
|
|
|
if (! IS_PAGE_OPCODE (code0, code1)) |
|
|
{ |
|
|
bfd_vma value = symval + irel->r_addend; |
|
|
bfd_vma addr = BASEADDR (sec) + irel->r_offset; |
|
|
|
|
|
if (add_all || PAGENO (addr) != PAGENO (value)) |
|
|
{ |
|
|
if (! add_page_insn (abfd, sec, irel, misc)) |
|
|
return false; |
|
|
|
|
|
/* That will have changed things, so, we must relax again. */ |
|
|
*again = true; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
1041 |
} |
} |
|
|
|
|
/* If anything changed reset the final pass flag. */ |
|
|
if (*again) |
|
|
*final_pass = false; |
|
1042 |
|
|
1043 |
return true; |
return TRUE; |
1044 |
} |
} |
1045 |
|
|
1046 |
/* Parts of a Stabs entry. */ |
/* Parts of a Stabs entry. */ |
1064 |
int noadj; |
int noadj; |
1065 |
{ |
{ |
1066 |
Elf_Internal_Shdr *symtab_hdr; |
Elf_Internal_Shdr *symtab_hdr; |
1067 |
Elf32_External_Sym *extsyms; |
Elf_Internal_Sym *isymbuf, *isym, *isymend; |
1068 |
int shndx, index; |
unsigned int shndx; |
1069 |
bfd_byte *contents; |
bfd_byte *contents; |
1070 |
Elf_Internal_Rela *irel, *irelend, *irelbase; |
Elf_Internal_Rela *irel, *irelend, *irelbase; |
1071 |
Elf32_External_Sym *esym, *esymend; |
struct elf_link_hash_entry **sym_hashes; |
1072 |
|
struct elf_link_hash_entry **end_hashes; |
1073 |
|
unsigned int symcount; |
1074 |
asection *stab; |
asection *stab; |
1075 |
bfd_byte *stabp, *stabend, *stabcontents; |
|
|
Elf_Internal_Shdr *shndx_hdr; |
|
|
Elf_External_Sym_Shndx *sym_shndx; |
|
|
|
|
1076 |
symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
1077 |
extsyms = (Elf32_External_Sym *) symtab_hdr->contents; |
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; |
1078 |
|
|
1079 |
shndx = _bfd_elf_section_from_bfd_section (abfd, sec); |
shndx = _bfd_elf_section_from_bfd_section (abfd, sec); |
1080 |
|
|
1090 |
/* Get the value of the symbol referred to by the reloc. */ |
/* Get the value of the symbol referred to by the reloc. */ |
1091 |
if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) |
if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) |
1092 |
{ |
{ |
|
Elf_Internal_Sym isym; |
|
1093 |
asection *sym_sec; |
asection *sym_sec; |
|
Elf_External_Sym_Shndx *sym_shndx; |
|
|
Elf_Internal_Shdr *shndx_hdr; |
|
1094 |
|
|
1095 |
/* A local symbol. */ |
/* A local symbol. */ |
1096 |
|
isym = isymbuf + ELF32_R_SYM (irel->r_info); |
1097 |
shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; |
sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); |
|
sym_shndx = (Elf_External_Sym_Shndx *) shndx_hdr->contents; |
|
|
sym_shndx = (sym_shndx |
|
|
? sym_shndx + ELF32_R_SYM (irel->r_info) : NULL); |
|
|
bfd_elf32_swap_symbol_in (abfd, |
|
|
extsyms + ELF32_R_SYM (irel->r_info), |
|
|
sym_shndx, &isym); |
|
|
|
|
|
if (isym.st_shndx == SHN_UNDEF) |
|
|
sym_sec = bfd_und_section_ptr; |
|
|
else if (isym.st_shndx == SHN_ABS) |
|
|
sym_sec = bfd_abs_section_ptr; |
|
|
else if (isym.st_shndx == SHN_COMMON) |
|
|
sym_sec = bfd_com_section_ptr; |
|
|
else |
|
|
sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx); |
|
1098 |
|
|
1099 |
if (sym_sec == sec) |
if (isym->st_shndx == shndx) |
1100 |
{ |
{ |
1101 |
bfd_vma baseaddr = BASEADDR (sec); |
bfd_vma baseaddr = BASEADDR (sec); |
1102 |
bfd_vma symval = BASEADDR (sym_sec) + isym.st_value |
bfd_vma symval = BASEADDR (sym_sec) + isym->st_value |
1103 |
+ irel->r_addend; |
+ irel->r_addend; |
1104 |
|
|
1105 |
if ((baseaddr + addr + noadj) <= symval |
if ((baseaddr + addr + noadj) <= symval |
1118 |
stab = bfd_get_section_by_name (abfd, ".stab"); |
stab = bfd_get_section_by_name (abfd, ".stab"); |
1119 |
if (stab) |
if (stab) |
1120 |
{ |
{ |
1121 |
|
bfd_byte *stabcontents, *stabend, *stabp; |
1122 |
|
bfd_size_type stab_size = stab->rawsize ? stab->rawsize : stab->size; |
1123 |
|
|
1124 |
irelbase = elf_section_data (stab)->relocs; |
irelbase = elf_section_data (stab)->relocs; |
1125 |
irelend = irelbase + stab->reloc_count; |
irelend = irelbase + stab->reloc_count; |
1126 |
|
|
1129 |
stabcontents = elf_section_data (stab)->this_hdr.contents; |
stabcontents = elf_section_data (stab)->this_hdr.contents; |
1130 |
else |
else |
1131 |
{ |
{ |
1132 |
stabcontents = (bfd_byte *) bfd_alloc (abfd, stab->_raw_size); |
if (!bfd_malloc_and_get_section (abfd, stab, &stabcontents)) |
1133 |
if (stabcontents == NULL) |
{ |
1134 |
return; |
if (stabcontents != NULL) |
1135 |
if (! bfd_get_section_contents (abfd, stab, stabcontents, |
free (stabcontents); |
1136 |
(file_ptr) 0, stab->_raw_size)) |
return; |
1137 |
return; |
} |
1138 |
|
|
1139 |
/* We need to remember this. */ |
/* We need to remember this. */ |
1140 |
elf_section_data (stab)->this_hdr.contents = stabcontents; |
elf_section_data (stab)->this_hdr.contents = stabcontents; |
1141 |
} |
} |
1142 |
|
|
1143 |
stabend = stabcontents + stab->_raw_size; |
stabend = stabcontents + stab_size; |
1144 |
|
|
1145 |
for (irel = irelbase; irel < irelend; irel++) |
for (irel = irelbase; irel < irelend; irel++) |
1146 |
{ |
{ |
1149 |
/* Get the value of the symbol referred to by the reloc. */ |
/* Get the value of the symbol referred to by the reloc. */ |
1150 |
if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) |
if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) |
1151 |
{ |
{ |
|
Elf_Internal_Sym isym; |
|
1152 |
asection *sym_sec; |
asection *sym_sec; |
|
Elf_External_Sym_Shndx *sym_shndx; |
|
|
Elf_Internal_Shdr *shndx_hdr; |
|
1153 |
|
|
1154 |
/* A local symbol. */ |
/* A local symbol. */ |
1155 |
shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; |
isym = isymbuf + ELF32_R_SYM (irel->r_info); |
1156 |
sym_shndx = (Elf_External_Sym_Shndx *) shndx_hdr->contents; |
sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); |
|
sym_shndx = (sym_shndx |
|
|
? sym_shndx + ELF32_R_SYM (irel->r_info) |
|
|
: NULL); |
|
|
|
|
|
bfd_elf32_swap_symbol_in (abfd, |
|
|
(extsyms |
|
|
+ ELF32_R_SYM (irel->r_info)), |
|
|
sym_shndx, &isym); |
|
|
|
|
|
if (isym.st_shndx == SHN_UNDEF) |
|
|
sym_sec = bfd_und_section_ptr; |
|
|
else if (isym.st_shndx == SHN_ABS) |
|
|
sym_sec = bfd_abs_section_ptr; |
|
|
else if (isym.st_shndx == SHN_COMMON) |
|
|
sym_sec = bfd_com_section_ptr; |
|
|
else |
|
|
sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx); |
|
1157 |
|
|
1158 |
if (sym_sec == sec) |
if (sym_sec == sec) |
1159 |
{ |
{ |
1163 |
unsigned short desc; |
unsigned short desc; |
1164 |
bfd_vma value; |
bfd_vma value; |
1165 |
bfd_vma baseaddr = BASEADDR (sec); |
bfd_vma baseaddr = BASEADDR (sec); |
1166 |
bfd_vma symval = BASEADDR (sym_sec) + isym.st_value |
bfd_vma symval = BASEADDR (sym_sec) + isym->st_value |
1167 |
+ irel->r_addend; |
+ irel->r_addend; |
1168 |
|
|
1169 |
if ((baseaddr + addr) <= symval |
if ((baseaddr + addr) <= symval |
1174 |
stabp = stabcontents + irel->r_offset - 8; |
stabp = stabcontents + irel->r_offset - 8; |
1175 |
|
|
1176 |
/* Go pullout the stab entry. */ |
/* Go pullout the stab entry. */ |
1177 |
strx = bfd_h_get_32 (abfd, stabp + STRDXOFF); |
strx = bfd_h_get_32 (abfd, stabp + STRDXOFF); |
1178 |
type = bfd_h_get_8 (abfd, stabp + TYPEOFF); |
type = bfd_h_get_8 (abfd, stabp + TYPEOFF); |
1179 |
other = bfd_h_get_8 (abfd, stabp + OTHEROFF); |
other = bfd_h_get_8 (abfd, stabp + OTHEROFF); |
1180 |
desc = bfd_h_get_16 (abfd, stabp + DESCOFF); |
desc = bfd_h_get_16 (abfd, stabp + DESCOFF); |
1181 |
value = bfd_h_get_32 (abfd, stabp + VALOFF); |
value = bfd_h_get_32 (abfd, stabp + VALOFF); |
1182 |
|
|
1183 |
name = bfd_get_stab_name (type); |
name = bfd_get_stab_name (type); |
1195 |
for (;stabp < stabend; stabp += STABSIZE) |
for (;stabp < stabend; stabp += STABSIZE) |
1196 |
{ |
{ |
1197 |
/* Go pullout the stab entry. */ |
/* Go pullout the stab entry. */ |
1198 |
strx = bfd_h_get_32 (abfd, stabp + STRDXOFF); |
strx = bfd_h_get_32 (abfd, stabp + STRDXOFF); |
1199 |
type = bfd_h_get_8 (abfd, stabp + TYPEOFF); |
type = bfd_h_get_8 (abfd, stabp + TYPEOFF); |
1200 |
other = bfd_h_get_8 (abfd, stabp + OTHEROFF); |
other = bfd_h_get_8 (abfd, stabp + OTHEROFF); |
1201 |
desc = bfd_h_get_16 (abfd, stabp + DESCOFF); |
desc = bfd_h_get_16 (abfd, stabp + DESCOFF); |
1202 |
value = bfd_h_get_32 (abfd, stabp + VALOFF); |
value = bfd_h_get_32 (abfd, stabp + VALOFF); |
1203 |
|
|
1204 |
name = bfd_get_stab_name (type); |
name = bfd_get_stab_name (type); |
1205 |
|
|
1206 |
if (strcmp (name, "FUN") == 0) |
if (strcmp (name, "FUN") == 0) |
1249 |
addr += noadj; |
addr += noadj; |
1250 |
|
|
1251 |
/* Adjust the local symbols defined in this section. */ |
/* Adjust the local symbols defined in this section. */ |
1252 |
shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; |
isymend = isymbuf + symtab_hdr->sh_info; |
1253 |
sym_shndx = (Elf_External_Sym_Shndx *) shndx_hdr->contents; |
for (isym = isymbuf; isym < isymend; isym++) |
|
esym = extsyms; |
|
|
esymend = esym + symtab_hdr->sh_info; |
|
|
for (; esym < esymend; esym++, sym_shndx = (sym_shndx ? sym_shndx + 1: NULL)) |
|
1254 |
{ |
{ |
1255 |
Elf_Internal_Sym isym; |
if (isym->st_shndx == shndx |
1256 |
Elf_External_Sym_Shndx dummy; |
&& addr <= isym->st_value |
1257 |
|
&& isym->st_value < endaddr) |
1258 |
bfd_elf32_swap_symbol_in (abfd, esym, sym_shndx, &isym); |
isym->st_value += count; |
1259 |
|
} |
1260 |
if (isym.st_shndx == shndx) |
|
1261 |
{ |
/* Now adjust the global symbols defined in this section. */ |
1262 |
if (addr <= isym.st_value && isym.st_value < endaddr) |
symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) |
1263 |
{ |
- symtab_hdr->sh_info); |
1264 |
isym.st_value += count; |
sym_hashes = elf_sym_hashes (abfd); |
1265 |
bfd_elf32_swap_symbol_out (abfd, &isym, esym, &dummy); |
end_hashes = sym_hashes + symcount; |
1266 |
} |
for (; sym_hashes < end_hashes; sym_hashes++) |
1267 |
} |
{ |
1268 |
} |
struct elf_link_hash_entry *sym_hash = *sym_hashes; |
1269 |
|
|
1270 |
/* Now adjust the global symbols defined in this section. */ |
if ((sym_hash->root.type == bfd_link_hash_defined |
1271 |
shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; |
|| sym_hash->root.type == bfd_link_hash_defweak) |
1272 |
sym_shndx = (Elf_External_Sym_Shndx *) shndx_hdr->contents; |
&& sym_hash->root.u.def.section == sec) |
1273 |
esym = extsyms + symtab_hdr->sh_info; |
{ |
|
esymend = extsyms + (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)); |
|
|
for (index = 0; esym < esymend; |
|
|
esym++, index++, sym_shndx = (sym_shndx ? sym_shndx + 1: NULL)) |
|
|
{ |
|
|
Elf_Internal_Sym isym; |
|
|
struct elf_link_hash_entry *sym_hash; |
|
|
|
|
|
bfd_elf32_swap_symbol_in (abfd, esym, sym_shndx, &isym); |
|
|
sym_hash = elf_sym_hashes (abfd)[index]; |
|
|
|
|
|
if (isym.st_shndx == shndx |
|
|
&& (sym_hash->root.type == bfd_link_hash_defined |
|
|
|| sym_hash->root.type == bfd_link_hash_defweak) |
|
|
&& sym_hash->root.u.def.section == sec) |
|
|
{ |
|
1274 |
if (addr <= sym_hash->root.u.def.value |
if (addr <= sym_hash->root.u.def.value |
1275 |
&& sym_hash->root.u.def.value < endaddr) |
&& sym_hash->root.u.def.value < endaddr) |
1276 |
{ |
sym_hash->root.u.def.value += count; |
1277 |
Elf_External_Sym_Shndx dummy; |
} |
|
|
|
|
sym_hash->root.u.def.value += count; |
|
|
bfd_elf32_swap_symbol_out (abfd, &isym, esym, &dummy); |
|
|
} |
|
|
} |
|
1278 |
} |
} |
1279 |
|
|
1280 |
return; |
return; |
1281 |
} |
} |
1282 |
|
|
|
static boolean |
|
|
add_page_insn (abfd, sec, irel, misc) |
|
|
bfd *abfd; |
|
|
asection *sec; |
|
|
Elf_Internal_Rela *irel; |
|
|
struct misc *misc; |
|
|
{ |
|
|
/* Note that we've changed the relocs, section contents, etc. */ |
|
|
elf_section_data (sec)->relocs = misc->irelbase; |
|
|
misc->free_relocs = NULL; |
|
|
|
|
|
elf_section_data (sec)->this_hdr.contents = misc->contents; |
|
|
misc->free_contents = NULL; |
|
|
|
|
|
misc->symtab_hdr->contents = (bfd_byte *) misc->extsyms; |
|
|
misc->free_extsyms = NULL; |
|
|
|
|
|
/* Add the PAGE insn. */ |
|
|
if (! ip2k_elf_relax_add_bytes (abfd, sec, irel->r_offset, |
|
|
page_opcode, |
|
|
sizeof (page_opcode), |
|
|
sizeof (page_opcode))) |
|
|
return false; |
|
|
else |
|
|
{ |
|
|
Elf32_Internal_Rela * jrel = irel - 1; |
|
|
|
|
|
/* Add relocation for PAGE insn added. */ |
|
|
if (ELF32_R_TYPE (jrel->r_info) != R_IP2K_NONE) |
|
|
{ |
|
|
bfd_byte code0, code1; |
|
|
char *msg = NULL; |
|
|
|
|
|
/* Get the opcode. */ |
|
|
code0 = bfd_get_8 (abfd, misc->contents + irel->r_offset); |
|
|
code1 = bfd_get_8 (abfd, misc->contents + irel->r_offset + 1); |
|
|
|
|
|
if (IS_JMP_OPCODE (code0, code1)) |
|
|
msg = "\tJMP instruction missing a preceeding PAGE instruction in %s\n\n"; |
|
|
|
|
|
else if (IS_CALL_OPCODE (code0, code1)) |
|
|
msg = "\tCALL instruction missing a preceeding PAGE instruction in %s\n\n"; |
|
|
|
|
|
if (msg) |
|
|
{ |
|
|
fprintf (stderr, "\n\t *** LINKER RELAXATION failure ***\n"); |
|
|
fprintf (stderr, msg, sec->owner->filename); |
|
|
} |
|
|
|
|
|
return false; |
|
|
} |
|
|
|
|
|
jrel->r_addend = irel->r_addend; |
|
|
jrel->r_offset = irel->r_offset - sizeof (page_opcode); |
|
|
jrel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), |
|
|
R_IP2K_PAGE3); |
|
|
} |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
/* Insert bytes into a section while relaxing. */ |
|
|
|
|
|
static boolean |
|
|
ip2k_elf_relax_add_bytes (abfd, sec, addr, bytes, count, noadj) |
|
|
bfd *abfd; |
|
|
asection *sec; |
|
|
bfd_vma addr; |
|
|
const bfd_byte *bytes; |
|
|
int count; |
|
|
int noadj; |
|
|
{ |
|
|
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; |
|
|
bfd_vma endaddr = sec->_cooked_size; |
|
|
|
|
|
/* Make room to insert the bytes. */ |
|
|
memmove (contents + addr + count, contents + addr, endaddr - addr); |
|
|
|
|
|
/* Insert the bytes into the section. */ |
|
|
memcpy (contents + addr, bytes, count); |
|
|
|
|
|
sec->_cooked_size += count; |
|
|
|
|
|
adjust_all_relocations (abfd, sec, addr, endaddr, count, noadj); |
|
|
return true; |
|
|
} |
|
|
|
|
1283 |
/* Delete some bytes from a section while relaxing. */ |
/* Delete some bytes from a section while relaxing. */ |
1284 |
|
|
1285 |
static boolean |
static bfd_boolean |
1286 |
ip2k_elf_relax_delete_bytes (abfd, sec, addr, count) |
ip2k_elf_relax_delete_bytes (abfd, sec, addr, count) |
1287 |
bfd *abfd; |
bfd *abfd; |
1288 |
asection *sec; |
asection *sec; |
1290 |
int count; |
int count; |
1291 |
{ |
{ |
1292 |
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; |
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; |
1293 |
bfd_vma endaddr = sec->_cooked_size; |
bfd_vma endaddr = sec->size; |
1294 |
|
|
1295 |
/* Actually delete the bytes. */ |
/* Actually delete the bytes. */ |
1296 |
memmove (contents + addr, contents + addr + count, |
memmove (contents + addr, contents + addr + count, |
1297 |
endaddr - addr - count); |
endaddr - addr - count); |
1298 |
|
|
1299 |
sec->_cooked_size -= count; |
sec->size -= count; |
1300 |
|
|
1301 |
adjust_all_relocations (abfd, sec, addr + count, endaddr, -count, 0); |
adjust_all_relocations (abfd, sec, addr + count, endaddr, -count, 0); |
1302 |
return true; |
return TRUE; |
1303 |
} |
} |
1304 |
|
|
1305 |
/* -------------------------------------------------------------------- */ |
/* -------------------------------------------------------------------- */ |
1313 |
ip2k_info_to_howto_rela (abfd, cache_ptr, dst) |
ip2k_info_to_howto_rela (abfd, cache_ptr, dst) |
1314 |
bfd * abfd ATTRIBUTE_UNUSED; |
bfd * abfd ATTRIBUTE_UNUSED; |
1315 |
arelent * cache_ptr; |
arelent * cache_ptr; |
1316 |
Elf32_Internal_Rela * dst; |
Elf_Internal_Rela * dst; |
1317 |
{ |
{ |
1318 |
unsigned int r_type; |
unsigned int r_type; |
1319 |
|
|
1339 |
Elf_Internal_Rela * rel; |
Elf_Internal_Rela * rel; |
1340 |
bfd_vma relocation; |
bfd_vma relocation; |
1341 |
{ |
{ |
1342 |
bfd_reloc_status_type r = bfd_reloc_ok; |
static bfd_vma page_addr = 0; |
1343 |
|
|
1344 |
|
bfd_reloc_status_type r = bfd_reloc_ok; |
1345 |
switch (howto->type) |
switch (howto->type) |
1346 |
{ |
{ |
1347 |
/* Handle data space relocations. */ |
/* Handle data space relocations. */ |
1359 |
break; |
break; |
1360 |
|
|
1361 |
/* Handle insn space relocations. */ |
/* Handle insn space relocations. */ |
|
case R_IP2K_ADDR16CJP: |
|
1362 |
case R_IP2K_PAGE3: |
case R_IP2K_PAGE3: |
1363 |
|
page_addr = BASEADDR (input_section) + rel->r_offset; |
1364 |
|
if ((relocation & IP2K_INSN_MASK) == IP2K_INSN_VALUE) |
1365 |
|
relocation &= ~IP2K_INSN_MASK; |
1366 |
|
else |
1367 |
|
r = bfd_reloc_notsupported; |
1368 |
|
break; |
1369 |
|
|
1370 |
|
case R_IP2K_ADDR16CJP: |
1371 |
|
if (BASEADDR (input_section) + rel->r_offset != page_addr + 2) |
1372 |
|
{ |
1373 |
|
/* No preceding page instruction, verify that it isn't needed. */ |
1374 |
|
if (PAGENO (relocation + rel->r_addend) != |
1375 |
|
ip2k_nominal_page_bits (input_bfd, input_section, |
1376 |
|
rel->r_offset, contents)) |
1377 |
|
_bfd_error_handler (_("ip2k linker: missing page instruction at 0x%08lx (dest = 0x%08lx)."), |
1378 |
|
BASEADDR (input_section) + rel->r_offset, |
1379 |
|
relocation + rel->r_addend); |
1380 |
|
} |
1381 |
|
else if (ip2k_relaxed) |
1382 |
|
{ |
1383 |
|
/* Preceding page instruction. Verify that the page instruction is |
1384 |
|
really needed. One reason for the relaxation to miss a page is if |
1385 |
|
the section is not marked as executable. */ |
1386 |
|
if (!ip2k_is_switch_table_128 (input_bfd, input_section, rel->r_offset - 2, contents) && |
1387 |
|
!ip2k_is_switch_table_256 (input_bfd, input_section, rel->r_offset - 2, contents) && |
1388 |
|
(PAGENO (relocation + rel->r_addend) == |
1389 |
|
ip2k_nominal_page_bits (input_bfd, input_section, |
1390 |
|
rel->r_offset - 2, contents))) |
1391 |
|
_bfd_error_handler (_("ip2k linker: redundant page instruction at 0x%08lx (dest = 0x%08lx)."), |
1392 |
|
page_addr, |
1393 |
|
relocation + rel->r_addend); |
1394 |
|
} |
1395 |
|
if ((relocation & IP2K_INSN_MASK) == IP2K_INSN_VALUE) |
1396 |
|
relocation &= ~IP2K_INSN_MASK; |
1397 |
|
else |
1398 |
|
r = bfd_reloc_notsupported; |
1399 |
|
break; |
1400 |
|
|
1401 |
case R_IP2K_LO8INSN: |
case R_IP2K_LO8INSN: |
1402 |
case R_IP2K_HI8INSN: |
case R_IP2K_HI8INSN: |
1403 |
case R_IP2K_PC_SKIP: |
case R_IP2K_PC_SKIP: |
1429 |
} |
} |
1430 |
|
|
1431 |
/* Relocate a IP2K ELF section. |
/* Relocate a IP2K ELF section. |
|
There is some attempt to make this function usable for many architectures, |
|
|
both USE_REL and USE_RELA ['twould be nice if such a critter existed], |
|
|
if only to serve as a learning tool. |
|
1432 |
|
|
1433 |
The RELOCATE_SECTION function is called by the new ELF backend linker |
The RELOCATE_SECTION function is called by the new ELF backend linker |
1434 |
to handle the relocations for a section. |
to handle the relocations for a section. |
1438 |
zero. |
zero. |
1439 |
|
|
1440 |
This function is responsible for adjusting the section contents as |
This function is responsible for adjusting the section contents as |
1441 |
necessary, and (if using Rela relocs and generating a relocateable |
necessary, and (if using Rela relocs and generating a relocatable |
1442 |
output file) adjusting the reloc addend as necessary. |
output file) adjusting the reloc addend as necessary. |
1443 |
|
|
1444 |
This function does not have to worry about setting the reloc |
This function does not have to worry about setting the reloc |
1452 |
The global hash table entry for the global symbols can be found |
The global hash table entry for the global symbols can be found |
1453 |
via elf_sym_hashes (input_bfd). |
via elf_sym_hashes (input_bfd). |
1454 |
|
|
1455 |
When generating relocateable output, this function must handle |
When generating relocatable output, this function must handle |
1456 |
STB_LOCAL/STT_SECTION symbols specially. The output symbol is |
STB_LOCAL/STT_SECTION symbols specially. The output symbol is |
1457 |
going to be the section symbol corresponding to the output |
going to be the section symbol corresponding to the output |
1458 |
section, which means that the addend must be adjusted |
section, which means that the addend must be adjusted |
1459 |
accordingly. */ |
accordingly. */ |
1460 |
|
|
1461 |
static boolean |
static bfd_boolean |
1462 |
ip2k_elf_relocate_section (output_bfd, info, input_bfd, input_section, |
ip2k_elf_relocate_section (output_bfd, info, input_bfd, input_section, |
1463 |
contents, relocs, local_syms, local_sections) |
contents, relocs, local_syms, local_sections) |
1464 |
bfd * output_bfd ATTRIBUTE_UNUSED; |
bfd *output_bfd ATTRIBUTE_UNUSED; |
1465 |
struct bfd_link_info * info; |
struct bfd_link_info *info; |
1466 |
bfd * input_bfd; |
bfd *input_bfd; |
1467 |
asection * input_section; |
asection *input_section; |
1468 |
bfd_byte * contents; |
bfd_byte *contents; |
1469 |
Elf_Internal_Rela * relocs; |
Elf_Internal_Rela *relocs; |
1470 |
Elf_Internal_Sym * local_syms; |
Elf_Internal_Sym *local_syms; |
1471 |
asection ** local_sections; |
asection **local_sections; |
1472 |
{ |
{ |
1473 |
Elf_Internal_Shdr * symtab_hdr; |
Elf_Internal_Shdr *symtab_hdr; |
1474 |
struct elf_link_hash_entry ** sym_hashes; |
struct elf_link_hash_entry **sym_hashes; |
1475 |
Elf_Internal_Rela * rel; |
Elf_Internal_Rela *rel; |
1476 |
Elf_Internal_Rela * relend; |
Elf_Internal_Rela *relend; |
1477 |
|
|
1478 |
|
if (info->relocatable) |
1479 |
|
return TRUE; |
1480 |
|
|
1481 |
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; |
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; |
1482 |
sym_hashes = elf_sym_hashes (input_bfd); |
sym_hashes = elf_sym_hashes (input_bfd); |
1493 |
bfd_reloc_status_type r; |
bfd_reloc_status_type r; |
1494 |
const char * name = NULL; |
const char * name = NULL; |
1495 |
int r_type; |
int r_type; |
|
|
|
|
r_type = ELF32_R_TYPE (rel->r_info); |
|
|
|
|
|
r_symndx = ELF32_R_SYM (rel->r_info); |
|
|
|
|
|
if (info->relocateable) |
|
|
{ |
|
|
/* This is a relocateable link. We don't have to change |
|
|
anything, unless the reloc is against a section symbol, |
|
|
in which case we have to adjust according to where the |
|
|
section symbol winds up in the output section. */ |
|
|
if (r_symndx < symtab_hdr->sh_info) |
|
|
{ |
|
|
sym = local_syms + r_symndx; |
|
|
|
|
|
if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) |
|
|
{ |
|
|
sec = local_sections [r_symndx]; |
|
|
rel->r_addend += sec->output_offset + sym->st_value; |
|
|
} |
|
|
} |
|
|
|
|
|
continue; |
|
|
} |
|
1496 |
|
|
1497 |
/* This is a final link. */ |
/* This is a final link. */ |
1498 |
|
r_type = ELF32_R_TYPE (rel->r_info); |
1499 |
|
r_symndx = ELF32_R_SYM (rel->r_info); |
1500 |
howto = ip2k_elf_howto_table + ELF32_R_TYPE (rel->r_info); |
howto = ip2k_elf_howto_table + ELF32_R_TYPE (rel->r_info); |
1501 |
h = NULL; |
h = NULL; |
1502 |
sym = NULL; |
sym = NULL; |
1503 |
sec = NULL; |
sec = NULL; |
1504 |
|
|
1505 |
if (r_symndx < symtab_hdr->sh_info) |
if (r_symndx < symtab_hdr->sh_info) |
1506 |
{ |
{ |
1507 |
sym = local_syms + r_symndx; |
sym = local_syms + r_symndx; |
1508 |
sec = local_sections [r_symndx]; |
sec = local_sections [r_symndx]; |
1509 |
relocation = BASEADDR (sec) + sym->st_value; |
relocation = BASEADDR (sec) + sym->st_value; |
1510 |
|
|
1511 |
name = bfd_elf_string_from_elf_section |
name = bfd_elf_string_from_elf_section |
1512 |
(input_bfd, symtab_hdr->sh_link, sym->st_name); |
(input_bfd, symtab_hdr->sh_link, sym->st_name); |
1513 |
name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; |
name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; |
1514 |
} |
} |
1515 |
else |
else |
1516 |
{ |
{ |
1517 |
h = sym_hashes [r_symndx - symtab_hdr->sh_info]; |
bfd_boolean warned; |
1518 |
|
bfd_boolean unresolved_reloc; |
1519 |
while (h->root.type == bfd_link_hash_indirect |
|
1520 |
|| h->root.type == bfd_link_hash_warning) |
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, |
1521 |
h = (struct elf_link_hash_entry *) h->root.u.i.link; |
r_symndx, symtab_hdr, sym_hashes, |
1522 |
|
h, sec, relocation, |
1523 |
|
unresolved_reloc, warned); |
1524 |
|
|
1525 |
name = h->root.root.string; |
name = h->root.root.string; |
|
|
|
|
if (h->root.type == bfd_link_hash_defined |
|
|
|| h->root.type == bfd_link_hash_defweak) |
|
|
{ |
|
|
sec = h->root.u.def.section; |
|
|
relocation = h->root.u.def.value + BASEADDR (sec); |
|
|
} |
|
|
else if (h->root.type == bfd_link_hash_undefweak) |
|
|
{ |
|
|
relocation = 0; |
|
|
} |
|
|
else |
|
|
{ |
|
|
if (! ((*info->callbacks->undefined_symbol) |
|
|
(info, h->root.root.string, input_bfd, |
|
|
input_section, rel->r_offset, |
|
|
(! info->shared || info->no_undefined)))) |
|
|
return false; |
|
|
relocation = 0; |
|
|
} |
|
1526 |
} |
} |
1527 |
|
|
1528 |
/* Finally, the sole IP2K-specific part. */ |
/* Finally, the sole IP2K-specific part. */ |
1537 |
{ |
{ |
1538 |
case bfd_reloc_overflow: |
case bfd_reloc_overflow: |
1539 |
r = info->callbacks->reloc_overflow |
r = info->callbacks->reloc_overflow |
1540 |
(info, name, howto->name, (bfd_vma) 0, |
(info, (h ? &h->root : NULL), name, howto->name, |
1541 |
input_bfd, input_section, rel->r_offset); |
(bfd_vma) 0, input_bfd, input_section, rel->r_offset); |
1542 |
break; |
break; |
1543 |
|
|
1544 |
case bfd_reloc_undefined: |
case bfd_reloc_undefined: |
1545 |
r = info->callbacks->undefined_symbol |
r = info->callbacks->undefined_symbol |
1546 |
(info, name, input_bfd, input_section, rel->r_offset, true); |
(info, name, input_bfd, input_section, rel->r_offset, TRUE); |
1547 |
break; |
break; |
1548 |
|
|
1549 |
case bfd_reloc_outofrange: |
case bfd_reloc_outofrange: |
1550 |
msg = _("internal error: out of range error"); |
msg = _("internal error: out of range error"); |
1551 |
break; |
break; |
1571 |
(info, msg, name, input_bfd, input_section, rel->r_offset); |
(info, msg, name, input_bfd, input_section, rel->r_offset); |
1572 |
|
|
1573 |
if (! r) |
if (! r) |
1574 |
return false; |
return FALSE; |
1575 |
} |
} |
1576 |
} |
} |
1577 |
|
|
1578 |
return true; |
return TRUE; |
1579 |
} |
} |
1580 |
|
|
1581 |
static asection * |
static asection * |
1590 |
{ |
{ |
1591 |
switch (ELF32_R_TYPE (rel->r_info)) |
switch (ELF32_R_TYPE (rel->r_info)) |
1592 |
{ |
{ |
|
#if 0 |
|
|
case R_IP2K_GNU_VTINHERIT: |
|
|
case R_IP2K_GNU_VTENTRY: |
|
|
break; |
|
|
#endif |
|
|
|
|
1593 |
default: |
default: |
1594 |
switch (h->root.type) |
switch (h->root.type) |
1595 |
{ |
{ |
1611 |
&& ELF_ST_BIND (sym->st_info) != STB_LOCAL) |
&& ELF_ST_BIND (sym->st_info) != STB_LOCAL) |
1612 |
&& ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE) |
&& ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE) |
1613 |
&& sym->st_shndx != SHN_COMMON)) |
&& sym->st_shndx != SHN_COMMON)) |
1614 |
{ |
return bfd_section_from_elf_index (sec->owner, sym->st_shndx); |
|
return bfd_section_from_elf_index (sec->owner, sym->st_shndx); |
|
|
} |
|
1615 |
} |
} |
1616 |
return NULL; |
return NULL; |
1617 |
} |
} |
1618 |
|
|
1619 |
static boolean |
static bfd_boolean |
1620 |
ip2k_elf_gc_sweep_hook (abfd, info, sec, relocs) |
ip2k_elf_gc_sweep_hook (abfd, info, sec, relocs) |
1621 |
bfd *abfd ATTRIBUTE_UNUSED; |
bfd *abfd ATTRIBUTE_UNUSED; |
1622 |
struct bfd_link_info *info ATTRIBUTE_UNUSED; |
struct bfd_link_info *info ATTRIBUTE_UNUSED; |
1623 |
asection *sec ATTRIBUTE_UNUSED; |
asection *sec ATTRIBUTE_UNUSED; |
1624 |
const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED; |
const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED; |
1625 |
{ |
{ |
1626 |
/* we don't use got and plt entries for ip2k */ |
/* We don't use got and plt entries for ip2k. */ |
1627 |
return true; |
return TRUE; |
1628 |
} |
} |
1629 |
|
|
|
|
|
|
/* -------------------------------------------------------------------- */ |
|
|
|
|
|
|
|
1630 |
#define TARGET_BIG_SYM bfd_elf32_ip2k_vec |
#define TARGET_BIG_SYM bfd_elf32_ip2k_vec |
1631 |
#define TARGET_BIG_NAME "elf32-ip2k" |
#define TARGET_BIG_NAME "elf32-ip2k" |
1632 |
|
|
1633 |
#define ELF_ARCH bfd_arch_ip2k |
#define ELF_ARCH bfd_arch_ip2k |
1634 |
#define ELF_MACHINE_CODE EM_IP2K |
#define ELF_MACHINE_CODE EM_IP2K |
1635 |
#define ELF_MAXPAGESIZE 1 /* No pages on the IP2K */ |
#define ELF_MACHINE_ALT1 EM_IP2K_OLD |
1636 |
|
#define ELF_MAXPAGESIZE 1 /* No pages on the IP2K. */ |
|
#undef USE_REL |
|
|
#define USE_RELA |
|
1637 |
|
|
1638 |
#define elf_info_to_howto_rel NULL |
#define elf_info_to_howto_rel NULL |
1639 |
#define elf_info_to_howto ip2k_info_to_howto_rela |
#define elf_info_to_howto ip2k_info_to_howto_rela |
1640 |
|
|
1641 |
#define elf_backend_can_gc_sections 1 |
#define elf_backend_can_gc_sections 1 |
1642 |
|
#define elf_backend_rela_normal 1 |
1643 |
#define elf_backend_gc_mark_hook ip2k_elf_gc_mark_hook |
#define elf_backend_gc_mark_hook ip2k_elf_gc_mark_hook |
1644 |
#define elf_backend_gc_sweep_hook ip2k_elf_gc_sweep_hook |
#define elf_backend_gc_sweep_hook ip2k_elf_gc_sweep_hook |
|
|
|
1645 |
#define elf_backend_relocate_section ip2k_elf_relocate_section |
#define elf_backend_relocate_section ip2k_elf_relocate_section |
1646 |
|
|
1647 |
#define elf_symbol_leading_char '_' |
#define elf_symbol_leading_char '_' |
1648 |
#define bfd_elf32_bfd_reloc_type_lookup ip2k_reloc_type_lookup |
#define bfd_elf32_bfd_reloc_type_lookup ip2k_reloc_type_lookup |
1649 |
#define bfd_elf32_bfd_relax_section ip2k_elf_relax_section |
#define bfd_elf32_bfd_relax_section ip2k_elf_relax_section |
1650 |
|
|
|
|
|
1651 |
#include "elf32-target.h" |
#include "elf32-target.h" |
|
|
|