1 | /* Ubicom IP2xxx specific support for 32-bit ELF
|
---|
2 | Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
---|
3 |
|
---|
4 | This file is part of BFD, the Binary File Descriptor library.
|
---|
5 |
|
---|
6 | This program is free software; you can redistribute it and/or modify
|
---|
7 | it under the terms of the GNU General Public License as published by
|
---|
8 | the Free Software Foundation; either version 2 of the License, or
|
---|
9 | (at your option) any later version.
|
---|
10 |
|
---|
11 | This program is distributed in the hope that it will be useful,
|
---|
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | GNU General Public License for more details.
|
---|
15 |
|
---|
16 | You should have received a copy of the GNU General Public License
|
---|
17 | along with this program; if not, write to the Free Software
|
---|
18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
---|
19 |
|
---|
20 | #include "bfd.h"
|
---|
21 | #include "sysdep.h"
|
---|
22 | #include "libbfd.h"
|
---|
23 | #include "elf-bfd.h"
|
---|
24 | #include "elf/ip2k.h"
|
---|
25 |
|
---|
26 | /* Struct used to pass miscellaneous paramaters which
|
---|
27 | helps to avoid overly long parameter lists. */
|
---|
28 | struct misc
|
---|
29 | {
|
---|
30 | Elf_Internal_Shdr * symtab_hdr;
|
---|
31 | Elf_Internal_Rela * irelbase;
|
---|
32 | bfd_byte * contents;
|
---|
33 | Elf_Internal_Sym * isymbuf;
|
---|
34 | };
|
---|
35 |
|
---|
36 | struct ip2k_opcode
|
---|
37 | {
|
---|
38 | unsigned short opcode;
|
---|
39 | unsigned short mask;
|
---|
40 | };
|
---|
41 |
|
---|
42 | /* Prototypes. */
|
---|
43 | static reloc_howto_type *ip2k_reloc_type_lookup
|
---|
44 | PARAMS ((bfd *, bfd_reloc_code_real_type));
|
---|
45 | static int ip2k_is_opcode
|
---|
46 | PARAMS ((bfd_byte *, const struct ip2k_opcode *));
|
---|
47 | static bfd_vma symbol_value
|
---|
48 | PARAMS ((bfd *, Elf_Internal_Shdr *, Elf_Internal_Sym *,
|
---|
49 | Elf_Internal_Rela *));
|
---|
50 | static void ip2k_get_mem
|
---|
51 | PARAMS ((bfd *, bfd_byte *, int, bfd_byte *));
|
---|
52 | static bfd_vma ip2k_nominal_page_bits
|
---|
53 | PARAMS ((bfd *, asection *, bfd_vma, bfd_byte *));
|
---|
54 | static bfd_boolean ip2k_test_page_insn
|
---|
55 | PARAMS ((bfd *, asection *, Elf_Internal_Rela *, struct misc *));
|
---|
56 | static bfd_boolean ip2k_delete_page_insn
|
---|
57 | PARAMS ((bfd *, asection *, Elf_Internal_Rela *, bfd_boolean *, struct misc *));
|
---|
58 | static int ip2k_is_switch_table_128
|
---|
59 | PARAMS ((bfd *, asection *, bfd_vma, bfd_byte *));
|
---|
60 | static bfd_boolean ip2k_relax_switch_table_128
|
---|
61 | PARAMS ((bfd *, asection *, Elf_Internal_Rela *, bfd_boolean *, struct misc *));
|
---|
62 | static int ip2k_is_switch_table_256
|
---|
63 | PARAMS ((bfd *, asection *, bfd_vma, bfd_byte *));
|
---|
64 | static bfd_boolean ip2k_relax_switch_table_256
|
---|
65 | PARAMS ((bfd *, asection *, Elf_Internal_Rela *, bfd_boolean *, struct misc *));
|
---|
66 | static bfd_boolean ip2k_elf_relax_section
|
---|
67 | PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *));
|
---|
68 | static bfd_boolean ip2k_elf_relax_section_page
|
---|
69 | PARAMS ((bfd *, asection *, bfd_boolean *, struct misc *, unsigned long, unsigned long));
|
---|
70 | static void adjust_all_relocations
|
---|
71 | PARAMS ((bfd *, asection *, bfd_vma, bfd_vma, int, int));
|
---|
72 | static bfd_boolean ip2k_elf_relax_delete_bytes
|
---|
73 | PARAMS ((bfd *, asection *, bfd_vma, int));
|
---|
74 | static void ip2k_info_to_howto_rela
|
---|
75 | PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
|
---|
76 | static bfd_reloc_status_type ip2k_final_link_relocate
|
---|
77 | PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *,
|
---|
78 | Elf_Internal_Rela *, bfd_vma));
|
---|
79 | static bfd_boolean ip2k_elf_relocate_section
|
---|
80 | PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
|
---|
81 | Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
|
---|
82 | static asection *ip2k_elf_gc_mark_hook
|
---|
83 | PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
|
---|
84 | struct elf_link_hash_entry *, Elf_Internal_Sym *));
|
---|
85 | static bfd_boolean ip2k_elf_gc_sweep_hook
|
---|
86 | PARAMS ((bfd *, struct bfd_link_info *, asection *,
|
---|
87 | const Elf_Internal_Rela *));
|
---|
88 |
|
---|
89 | static bfd_boolean ip2k_relaxed = FALSE;
|
---|
90 |
|
---|
91 | static const struct ip2k_opcode ip2k_page_opcode[] =
|
---|
92 | {
|
---|
93 | {0x0010, 0xFFF8}, /* page */
|
---|
94 | {0x0000, 0x0000},
|
---|
95 | };
|
---|
96 |
|
---|
97 | #define IS_PAGE_OPCODE(code) \
|
---|
98 | ip2k_is_opcode (code, ip2k_page_opcode)
|
---|
99 |
|
---|
100 | static const struct ip2k_opcode ip2k_jmp_opcode[] =
|
---|
101 | {
|
---|
102 | {0xE000, 0xE000}, /* jmp */
|
---|
103 | {0x0000, 0x0000},
|
---|
104 | };
|
---|
105 |
|
---|
106 | #define IS_JMP_OPCODE(code) \
|
---|
107 | ip2k_is_opcode (code, ip2k_jmp_opcode)
|
---|
108 |
|
---|
109 | static const struct ip2k_opcode ip2k_call_opcode[] =
|
---|
110 | {
|
---|
111 | {0xC000, 0xE000}, /* call */
|
---|
112 | {0x0000, 0x0000},
|
---|
113 | };
|
---|
114 |
|
---|
115 | #define IS_CALL_OPCODE(code) \
|
---|
116 | ip2k_is_opcode (code, ip2k_call_opcode)
|
---|
117 |
|
---|
118 | static const struct ip2k_opcode ip2k_snc_opcode[] =
|
---|
119 | {
|
---|
120 | {0xA00B, 0xFFFF}, /* snc */
|
---|
121 | {0x0000, 0x0000},
|
---|
122 | };
|
---|
123 |
|
---|
124 | #define IS_SNC_OPCODE(code) \
|
---|
125 | ip2k_is_opcode (code, ip2k_snc_opcode)
|
---|
126 |
|
---|
127 | static const struct ip2k_opcode ip2k_inc_1sp_opcode[] =
|
---|
128 | {
|
---|
129 | {0x2B81, 0xFFFF}, /* inc 1(SP) */
|
---|
130 | {0x0000, 0x0000},
|
---|
131 | };
|
---|
132 |
|
---|
133 | #define IS_INC_1SP_OPCODE(code) \
|
---|
134 | ip2k_is_opcode (code, ip2k_inc_1sp_opcode)
|
---|
135 |
|
---|
136 | static const struct ip2k_opcode ip2k_add_2sp_w_opcode[] =
|
---|
137 | {
|
---|
138 | {0x1F82, 0xFFFF}, /* add 2(SP),w */
|
---|
139 | {0x0000, 0x0000},
|
---|
140 | };
|
---|
141 |
|
---|
142 | #define IS_ADD_2SP_W_OPCODE(code) \
|
---|
143 | ip2k_is_opcode (code, ip2k_add_2sp_w_opcode)
|
---|
144 |
|
---|
145 | static const struct ip2k_opcode ip2k_add_w_wreg_opcode[] =
|
---|
146 | {
|
---|
147 | {0x1C0A, 0xFFFF}, /* add w,wreg */
|
---|
148 | {0x1E0A, 0xFFFF}, /* add wreg,w */
|
---|
149 | {0x0000, 0x0000},
|
---|
150 | };
|
---|
151 |
|
---|
152 | #define IS_ADD_W_WREG_OPCODE(code) \
|
---|
153 | ip2k_is_opcode (code, ip2k_add_w_wreg_opcode)
|
---|
154 |
|
---|
155 | static const struct ip2k_opcode ip2k_add_pcl_w_opcode[] =
|
---|
156 | {
|
---|
157 | {0x1E09, 0xFFFF}, /* add pcl,w */
|
---|
158 | {0x0000, 0x0000},
|
---|
159 | };
|
---|
160 |
|
---|
161 | #define IS_ADD_PCL_W_OPCODE(code) \
|
---|
162 | ip2k_is_opcode (code, ip2k_add_pcl_w_opcode)
|
---|
163 |
|
---|
164 | static const struct ip2k_opcode ip2k_skip_opcodes[] =
|
---|
165 | {
|
---|
166 | {0xB000, 0xF000}, /* sb */
|
---|
167 | {0xA000, 0xF000}, /* snb */
|
---|
168 | {0x7600, 0xFE00}, /* cse/csne #lit */
|
---|
169 | {0x5800, 0xFC00}, /* incsnz */
|
---|
170 | {0x4C00, 0xFC00}, /* decsnz */
|
---|
171 | {0x4000, 0xFC00}, /* cse/csne */
|
---|
172 | {0x3C00, 0xFC00}, /* incsz */
|
---|
173 | {0x2C00, 0xFC00}, /* decsz */
|
---|
174 | {0x0000, 0x0000},
|
---|
175 | };
|
---|
176 |
|
---|
177 | #define IS_SKIP_OPCODE(code) \
|
---|
178 | ip2k_is_opcode (code, ip2k_skip_opcodes)
|
---|
179 |
|
---|
180 | /* Relocation tables. */
|
---|
181 | static reloc_howto_type ip2k_elf_howto_table [] =
|
---|
182 | {
|
---|
183 | #define IP2K_HOWTO(t,rs,s,bs,pr,bp,name,sm,dm) \
|
---|
184 | HOWTO(t, /* type */ \
|
---|
185 | rs, /* rightshift */ \
|
---|
186 | s, /* size (0 = byte, 1 = short, 2 = long) */ \
|
---|
187 | bs, /* bitsize */ \
|
---|
188 | pr, /* pc_relative */ \
|
---|
189 | bp, /* bitpos */ \
|
---|
190 | complain_overflow_dont,/* complain_on_overflow */ \
|
---|
191 | bfd_elf_generic_reloc,/* special_function */ \
|
---|
192 | name, /* name */ \
|
---|
193 | FALSE, /* partial_inplace */ \
|
---|
194 | sm, /* src_mask */ \
|
---|
195 | dm, /* dst_mask */ \
|
---|
196 | pr) /* pcrel_offset */
|
---|
197 |
|
---|
198 | /* This reloc does nothing. */
|
---|
199 | IP2K_HOWTO (R_IP2K_NONE, 0,2,32, FALSE, 0, "R_IP2K_NONE", 0, 0),
|
---|
200 | /* A 16 bit absolute relocation. */
|
---|
201 | IP2K_HOWTO (R_IP2K_16, 0,1,16, FALSE, 0, "R_IP2K_16", 0, 0xffff),
|
---|
202 | /* A 32 bit absolute relocation. */
|
---|
203 | IP2K_HOWTO (R_IP2K_32, 0,2,32, FALSE, 0, "R_IP2K_32", 0, 0xffffffff),
|
---|
204 | /* A 8-bit data relocation for the FR9 field. Ninth bit is computed specially. */
|
---|
205 | IP2K_HOWTO (R_IP2K_FR9, 0,1,9, FALSE, 0, "R_IP2K_FR9", 0, 0x00ff),
|
---|
206 | /* A 4-bit data relocation. */
|
---|
207 | IP2K_HOWTO (R_IP2K_BANK, 8,1,4, FALSE, 0, "R_IP2K_BANK", 0, 0x000f),
|
---|
208 | /* A 13-bit insn relocation - word address => right-shift 1 bit extra. */
|
---|
209 | IP2K_HOWTO (R_IP2K_ADDR16CJP, 1,1,13, FALSE, 0, "R_IP2K_ADDR16CJP", 0, 0x1fff),
|
---|
210 | /* A 3-bit insn relocation - word address => right-shift 1 bit extra. */
|
---|
211 | IP2K_HOWTO (R_IP2K_PAGE3, 14,1,3, FALSE, 0, "R_IP2K_PAGE3", 0, 0x0007),
|
---|
212 | /* Two 8-bit data relocations. */
|
---|
213 | IP2K_HOWTO (R_IP2K_LO8DATA, 0,1,8, FALSE, 0, "R_IP2K_LO8DATA", 0, 0x00ff),
|
---|
214 | IP2K_HOWTO (R_IP2K_HI8DATA, 8,1,8, FALSE, 0, "R_IP2K_HI8DATA", 0, 0x00ff),
|
---|
215 | /* Two 8-bit insn relocations. word address => right-shift 1 bit extra. */
|
---|
216 | IP2K_HOWTO (R_IP2K_LO8INSN, 1,1,8, FALSE, 0, "R_IP2K_LO8INSN", 0, 0x00ff),
|
---|
217 | IP2K_HOWTO (R_IP2K_HI8INSN, 9,1,8, FALSE, 0, "R_IP2K_HI8INSN", 0, 0x00ff),
|
---|
218 |
|
---|
219 | /* Special 1 bit relocation for SKIP instructions. */
|
---|
220 | IP2K_HOWTO (R_IP2K_PC_SKIP, 1,1,1, FALSE, 12, "R_IP2K_PC_SKIP", 0xfffe, 0x1000),
|
---|
221 | /* 16 bit word address. */
|
---|
222 | IP2K_HOWTO (R_IP2K_TEXT, 1,1,16, FALSE, 0, "R_IP2K_TEXT", 0, 0xffff),
|
---|
223 | /* A 7-bit offset relocation for the FR9 field. Eigth and ninth bit comes from insn. */
|
---|
224 | IP2K_HOWTO (R_IP2K_FR_OFFSET, 0,1,9, FALSE, 0, "R_IP2K_FR_OFFSET", 0x180, 0x007f),
|
---|
225 | /* Bits 23:16 of an address. */
|
---|
226 | IP2K_HOWTO (R_IP2K_EX8DATA, 16,1,8, FALSE, 0, "R_IP2K_EX8DATA", 0, 0x00ff),
|
---|
227 | };
|
---|
228 |
|
---|
229 |
|
---|
230 | /* Map BFD reloc types to IP2K ELF reloc types. */
|
---|
231 | static reloc_howto_type *
|
---|
232 | ip2k_reloc_type_lookup (abfd, code)
|
---|
233 | bfd * abfd ATTRIBUTE_UNUSED;
|
---|
234 | bfd_reloc_code_real_type code;
|
---|
235 | {
|
---|
236 | /* Note that the ip2k_elf_howto_table is indxed by the R_
|
---|
237 | constants. Thus, the order that the howto records appear in the
|
---|
238 | table *must* match the order of the relocation types defined in
|
---|
239 | include/elf/ip2k.h. */
|
---|
240 |
|
---|
241 | switch (code)
|
---|
242 | {
|
---|
243 | case BFD_RELOC_NONE:
|
---|
244 | return &ip2k_elf_howto_table[ (int) R_IP2K_NONE];
|
---|
245 | case BFD_RELOC_16:
|
---|
246 | return &ip2k_elf_howto_table[ (int) R_IP2K_16];
|
---|
247 | case BFD_RELOC_32:
|
---|
248 | return &ip2k_elf_howto_table[ (int) R_IP2K_32];
|
---|
249 | case BFD_RELOC_IP2K_FR9:
|
---|
250 | return &ip2k_elf_howto_table[ (int) R_IP2K_FR9];
|
---|
251 | case BFD_RELOC_IP2K_BANK:
|
---|
252 | return &ip2k_elf_howto_table[ (int) R_IP2K_BANK];
|
---|
253 | case BFD_RELOC_IP2K_ADDR16CJP:
|
---|
254 | return &ip2k_elf_howto_table[ (int) R_IP2K_ADDR16CJP];
|
---|
255 | case BFD_RELOC_IP2K_PAGE3:
|
---|
256 | return &ip2k_elf_howto_table[ (int) R_IP2K_PAGE3];
|
---|
257 | case BFD_RELOC_IP2K_LO8DATA:
|
---|
258 | return &ip2k_elf_howto_table[ (int) R_IP2K_LO8DATA];
|
---|
259 | case BFD_RELOC_IP2K_HI8DATA:
|
---|
260 | return &ip2k_elf_howto_table[ (int) R_IP2K_HI8DATA];
|
---|
261 | case BFD_RELOC_IP2K_LO8INSN:
|
---|
262 | return &ip2k_elf_howto_table[ (int) R_IP2K_LO8INSN];
|
---|
263 | case BFD_RELOC_IP2K_HI8INSN:
|
---|
264 | return &ip2k_elf_howto_table[ (int) R_IP2K_HI8INSN];
|
---|
265 | case BFD_RELOC_IP2K_PC_SKIP:
|
---|
266 | return &ip2k_elf_howto_table[ (int) R_IP2K_PC_SKIP];
|
---|
267 | case BFD_RELOC_IP2K_TEXT:
|
---|
268 | return &ip2k_elf_howto_table[ (int) R_IP2K_TEXT];
|
---|
269 | case BFD_RELOC_IP2K_FR_OFFSET:
|
---|
270 | return &ip2k_elf_howto_table[ (int) R_IP2K_FR_OFFSET];
|
---|
271 | case BFD_RELOC_IP2K_EX8DATA:
|
---|
272 | return &ip2k_elf_howto_table[ (int) R_IP2K_EX8DATA];
|
---|
273 | default:
|
---|
274 | /* Pacify gcc -Wall. */
|
---|
275 | return NULL;
|
---|
276 | }
|
---|
277 | return NULL;
|
---|
278 | }
|
---|
279 |
|
---|
280 | static void
|
---|
281 | ip2k_get_mem (abfd, addr, length, ptr)
|
---|
282 | bfd *abfd ATTRIBUTE_UNUSED;
|
---|
283 | bfd_byte *addr;
|
---|
284 | int length;
|
---|
285 | bfd_byte *ptr;
|
---|
286 | {
|
---|
287 | while (length --)
|
---|
288 | * ptr ++ = bfd_get_8 (abfd, addr ++);
|
---|
289 | }
|
---|
290 |
|
---|
291 | static bfd_boolean
|
---|
292 | ip2k_is_opcode (code, opcodes)
|
---|
293 | bfd_byte *code;
|
---|
294 | const struct ip2k_opcode *opcodes;
|
---|
295 | {
|
---|
296 | unsigned short insn = (code[0] << 8) | code[1];
|
---|
297 |
|
---|
298 | while (opcodes->mask != 0)
|
---|
299 | {
|
---|
300 | if ((insn & opcodes->mask) == opcodes->opcode)
|
---|
301 | return TRUE;
|
---|
302 |
|
---|
303 | opcodes ++;
|
---|
304 | }
|
---|
305 |
|
---|
306 | return FALSE;
|
---|
307 | }
|
---|
308 |
|
---|
309 | #define PAGENO(ABSADDR) ((ABSADDR) & 0xFFFFC000)
|
---|
310 | #define BASEADDR(SEC) ((SEC)->output_section->vma + (SEC)->output_offset)
|
---|
311 |
|
---|
312 | #define UNDEFINED_SYMBOL (~(bfd_vma)0)
|
---|
313 |
|
---|
314 | /* Return the value of the symbol associated with the relocation IREL. */
|
---|
315 |
|
---|
316 | static bfd_vma
|
---|
317 | symbol_value (abfd, symtab_hdr, isymbuf, irel)
|
---|
318 | bfd *abfd;
|
---|
319 | Elf_Internal_Shdr *symtab_hdr;
|
---|
320 | Elf_Internal_Sym *isymbuf;
|
---|
321 | Elf_Internal_Rela *irel;
|
---|
322 | {
|
---|
323 | if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
|
---|
324 | {
|
---|
325 | Elf_Internal_Sym *isym;
|
---|
326 | asection *sym_sec;
|
---|
327 |
|
---|
328 | isym = isymbuf + ELF32_R_SYM (irel->r_info);
|
---|
329 | if (isym->st_shndx == SHN_UNDEF)
|
---|
330 | sym_sec = bfd_und_section_ptr;
|
---|
331 | else if (isym->st_shndx == SHN_ABS)
|
---|
332 | sym_sec = bfd_abs_section_ptr;
|
---|
333 | else if (isym->st_shndx == SHN_COMMON)
|
---|
334 | sym_sec = bfd_com_section_ptr;
|
---|
335 | else
|
---|
336 | sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
|
---|
337 |
|
---|
338 | return isym->st_value + BASEADDR (sym_sec);
|
---|
339 | }
|
---|
340 | else
|
---|
341 | {
|
---|
342 | unsigned long indx;
|
---|
343 | struct elf_link_hash_entry *h;
|
---|
344 |
|
---|
345 | indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
|
---|
346 | h = elf_sym_hashes (abfd)[indx];
|
---|
347 | BFD_ASSERT (h != NULL);
|
---|
348 |
|
---|
349 | if (h->root.type != bfd_link_hash_defined
|
---|
350 | && h->root.type != bfd_link_hash_defweak)
|
---|
351 | return UNDEFINED_SYMBOL;
|
---|
352 |
|
---|
353 | return (h->root.u.def.value + BASEADDR (h->root.u.def.section));
|
---|
354 | }
|
---|
355 | }
|
---|
356 |
|
---|
357 | /* Returns the expected page state for the given instruction not including
|
---|
358 | the effect of page instructions. */
|
---|
359 |
|
---|
360 | static bfd_vma
|
---|
361 | ip2k_nominal_page_bits (abfd, sec, addr, contents)
|
---|
362 | bfd *abfd ATTRIBUTE_UNUSED;
|
---|
363 | asection *sec;
|
---|
364 | bfd_vma addr;
|
---|
365 | bfd_byte *contents;
|
---|
366 | {
|
---|
367 | bfd_vma page = PAGENO (BASEADDR (sec) + addr);
|
---|
368 |
|
---|
369 | /* Check if section flows into this page. If not then the page
|
---|
370 | bits are assumed to match the PC. This will be true unless
|
---|
371 | the user has a page instruction without a call/jump, in which
|
---|
372 | case they are on their own. */
|
---|
373 | if (PAGENO (BASEADDR (sec)) == page)
|
---|
374 | return page;
|
---|
375 |
|
---|
376 | /* Section flows across page boundary. The page bits should match
|
---|
377 | the PC unless there is a possible flow from the previous page,
|
---|
378 | in which case it is not possible to determine the value of the
|
---|
379 | page bits. */
|
---|
380 | while (PAGENO (BASEADDR (sec) + addr - 2) == page)
|
---|
381 | {
|
---|
382 | bfd_byte code[2];
|
---|
383 |
|
---|
384 | addr -= 2;
|
---|
385 | ip2k_get_mem (abfd, contents + addr, 2, code);
|
---|
386 | if (!IS_PAGE_OPCODE (code))
|
---|
387 | continue;
|
---|
388 |
|
---|
389 | /* Found a page instruction, check if jump table. */
|
---|
390 | if (ip2k_is_switch_table_128 (abfd, sec, addr, contents) != -1)
|
---|
391 | /* Jump table => page is conditional. */
|
---|
392 | continue;
|
---|
393 |
|
---|
394 | if (ip2k_is_switch_table_256 (abfd, sec, addr, contents) != -1)
|
---|
395 | /* Jump table => page is conditional. */
|
---|
396 | continue;
|
---|
397 |
|
---|
398 | /* Found a page instruction, check if conditional. */
|
---|
399 | if (addr >= 2)
|
---|
400 | {
|
---|
401 | ip2k_get_mem (abfd, contents + addr - 2, 2, code);
|
---|
402 | if (IS_SKIP_OPCODE (code))
|
---|
403 | /* Page is conditional. */
|
---|
404 | continue;
|
---|
405 | }
|
---|
406 |
|
---|
407 | /* Unconditional page instruction => page bits should be correct. */
|
---|
408 | return page;
|
---|
409 | }
|
---|
410 |
|
---|
411 | /* Flow from previous page => page bits are impossible to determine. */
|
---|
412 | return 0;
|
---|
413 | }
|
---|
414 |
|
---|
415 | static bfd_boolean
|
---|
416 | ip2k_test_page_insn (abfd, sec, irel, misc)
|
---|
417 | bfd *abfd ATTRIBUTE_UNUSED;
|
---|
418 | asection *sec;
|
---|
419 | Elf_Internal_Rela *irel;
|
---|
420 | struct misc *misc;
|
---|
421 | {
|
---|
422 | bfd_vma symval;
|
---|
423 |
|
---|
424 | /* Get the value of the symbol referred to by the reloc. */
|
---|
425 | symval = symbol_value (abfd, misc->symtab_hdr, misc->isymbuf, irel);
|
---|
426 | if (symval == UNDEFINED_SYMBOL)
|
---|
427 | /* This appears to be a reference to an undefined
|
---|
428 | symbol. Just ignore it--it will be caught by the
|
---|
429 | regular reloc processing. */
|
---|
430 | return FALSE;
|
---|
431 |
|
---|
432 | /* Test if we can delete this page instruction. */
|
---|
433 | if (PAGENO (symval + irel->r_addend) !=
|
---|
434 | ip2k_nominal_page_bits (abfd, sec, irel->r_offset, misc->contents))
|
---|
435 | return FALSE;
|
---|
436 |
|
---|
437 | return TRUE;
|
---|
438 | }
|
---|
439 |
|
---|
440 | static bfd_boolean
|
---|
441 | ip2k_delete_page_insn (abfd, sec, irel, again, misc)
|
---|
442 | bfd *abfd ATTRIBUTE_UNUSED;
|
---|
443 | asection *sec;
|
---|
444 | Elf_Internal_Rela *irel;
|
---|
445 | bfd_boolean *again;
|
---|
446 | struct misc *misc;
|
---|
447 | {
|
---|
448 | /* Note that we've changed the relocs, section contents, etc. */
|
---|
449 | elf_section_data (sec)->relocs = misc->irelbase;
|
---|
450 | elf_section_data (sec)->this_hdr.contents = misc->contents;
|
---|
451 | misc->symtab_hdr->contents = (bfd_byte *) misc->isymbuf;
|
---|
452 |
|
---|
453 | /* Fix the relocation's type. */
|
---|
454 | irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_IP2K_NONE);
|
---|
455 |
|
---|
456 | /* Delete the PAGE insn. */
|
---|
457 | if (!ip2k_elf_relax_delete_bytes (abfd, sec, irel->r_offset, 2))
|
---|
458 | return FALSE;
|
---|
459 |
|
---|
460 | /* Modified => will need to iterate relaxation again. */
|
---|
461 | *again = TRUE;
|
---|
462 |
|
---|
463 | return TRUE;
|
---|
464 | }
|
---|
465 |
|
---|
466 | /* Determine if the instruction sequence matches that for
|
---|
467 | the prologue of a switch dispatch table with fewer than
|
---|
468 | 128 entries.
|
---|
469 |
|
---|
470 | sc
|
---|
471 | page $nnn0
|
---|
472 | jmp $nnn0
|
---|
473 | add w,wreg
|
---|
474 | add pcl,w
|
---|
475 | addr=>
|
---|
476 | page $nnn1
|
---|
477 | jmp $nnn1
|
---|
478 | page $nnn2
|
---|
479 | jmp $nnn2
|
---|
480 | ...
|
---|
481 | page $nnnN
|
---|
482 | jmp $nnnN
|
---|
483 |
|
---|
484 | After relaxation.
|
---|
485 | sc
|
---|
486 | page $nnn0
|
---|
487 | jmp $nnn0
|
---|
488 | add pcl,w
|
---|
489 | addr=>
|
---|
490 | jmp $nnn1
|
---|
491 | jmp $nnn2
|
---|
492 | ...
|
---|
493 | jmp $nnnN */
|
---|
494 |
|
---|
495 | static int
|
---|
496 | ip2k_is_switch_table_128 (abfd, sec, addr, contents)
|
---|
497 | bfd *abfd ATTRIBUTE_UNUSED;
|
---|
498 | asection *sec;
|
---|
499 | bfd_vma addr;
|
---|
500 | bfd_byte *contents;
|
---|
501 | {
|
---|
502 | bfd_byte code[4];
|
---|
503 | int index = 0;
|
---|
504 |
|
---|
505 | /* Check current page-jmp. */
|
---|
506 | if (addr + 4 > sec->_cooked_size)
|
---|
507 | return -1;
|
---|
508 |
|
---|
509 | ip2k_get_mem (abfd, contents + addr, 4, code);
|
---|
510 |
|
---|
511 | if ((! IS_PAGE_OPCODE (code + 0))
|
---|
512 | || (! IS_JMP_OPCODE (code + 2)))
|
---|
513 | return -1;
|
---|
514 |
|
---|
515 | /* Search back. */
|
---|
516 | while (1)
|
---|
517 | {
|
---|
518 | if (addr < 4)
|
---|
519 | return -1;
|
---|
520 |
|
---|
521 | /* Check previous 2 instructions. */
|
---|
522 | ip2k_get_mem (abfd, contents + addr - 4, 4, code);
|
---|
523 | if ((IS_ADD_W_WREG_OPCODE (code + 0))
|
---|
524 | && (IS_ADD_PCL_W_OPCODE (code + 2)))
|
---|
525 | return index;
|
---|
526 |
|
---|
527 | if ((! IS_PAGE_OPCODE (code + 0))
|
---|
528 | || (! IS_JMP_OPCODE (code + 2)))
|
---|
529 | return -1;
|
---|
530 |
|
---|
531 | index++;
|
---|
532 | addr -= 4;
|
---|
533 | }
|
---|
534 | }
|
---|
535 |
|
---|
536 | static bfd_boolean
|
---|
537 | ip2k_relax_switch_table_128 (abfd, sec, irel, again, misc)
|
---|
538 | bfd *abfd ATTRIBUTE_UNUSED;
|
---|
539 | asection *sec;
|
---|
540 | Elf_Internal_Rela *irel;
|
---|
541 | bfd_boolean *again;
|
---|
542 | struct misc *misc;
|
---|
543 | {
|
---|
544 | Elf_Internal_Rela *irelend = misc->irelbase + sec->reloc_count;
|
---|
545 | Elf_Internal_Rela *ireltest = irel;
|
---|
546 | bfd_byte code[4];
|
---|
547 | bfd_vma addr;
|
---|
548 |
|
---|
549 | /* Test all page instructions. */
|
---|
550 | addr = irel->r_offset;
|
---|
551 | while (1)
|
---|
552 | {
|
---|
553 | if (addr + 4 > sec->_cooked_size)
|
---|
554 | break;
|
---|
555 |
|
---|
556 | ip2k_get_mem (abfd, misc->contents + addr, 4, code);
|
---|
557 | if ((! IS_PAGE_OPCODE (code + 0))
|
---|
558 | || (! IS_JMP_OPCODE (code + 2)))
|
---|
559 | break;
|
---|
560 |
|
---|
561 | /* Validate relocation entry (every entry should have a matching
|
---|
562 | relocation entry). */
|
---|
563 | if (ireltest >= irelend)
|
---|
564 | {
|
---|
565 | _bfd_error_handler (_("ip2k relaxer: switch table without complete matching relocation information."));
|
---|
566 | return FALSE;
|
---|
567 | }
|
---|
568 |
|
---|
569 | if (ireltest->r_offset != addr)
|
---|
570 | {
|
---|
571 | _bfd_error_handler (_("ip2k relaxer: switch table without complete matching relocation information."));
|
---|
572 | return FALSE;
|
---|
573 | }
|
---|
574 |
|
---|
575 | if (! ip2k_test_page_insn (abfd, sec, ireltest, misc))
|
---|
576 | /* Un-removable page insn => nothing can be done. */
|
---|
577 | return TRUE;
|
---|
578 |
|
---|
579 | addr += 4;
|
---|
580 | ireltest += 2;
|
---|
581 | }
|
---|
582 |
|
---|
583 | /* Relaxable. Adjust table header. */
|
---|
584 | ip2k_get_mem (abfd, misc->contents + irel->r_offset - 4, 4, code);
|
---|
585 | if ((! IS_ADD_W_WREG_OPCODE (code + 0))
|
---|
586 | || (! IS_ADD_PCL_W_OPCODE (code + 2)))
|
---|
587 | {
|
---|
588 | _bfd_error_handler (_("ip2k relaxer: switch table header corrupt."));
|
---|
589 | return FALSE;
|
---|
590 | }
|
---|
591 |
|
---|
592 | if (!ip2k_elf_relax_delete_bytes (abfd, sec, irel->r_offset - 4, 2))
|
---|
593 | return FALSE;
|
---|
594 |
|
---|
595 | *again = TRUE;
|
---|
596 |
|
---|
597 | /* Delete all page instructions in table. */
|
---|
598 | while (irel < ireltest)
|
---|
599 | {
|
---|
600 | if (!ip2k_delete_page_insn (abfd, sec, irel, again, misc))
|
---|
601 | return FALSE;
|
---|
602 | irel += 2;
|
---|
603 | }
|
---|
604 |
|
---|
605 | return TRUE;
|
---|
606 | }
|
---|
607 |
|
---|
608 | /* Determine if the instruction sequence matches that for
|
---|
609 | the prologue switch dispatch table with fewer than
|
---|
610 | 256 entries but more than 127.
|
---|
611 |
|
---|
612 | Before relaxation.
|
---|
613 | push %lo8insn(label) ; Push address of table
|
---|
614 | push %hi8insn(label)
|
---|
615 | add w,wreg ; index*2 => offset
|
---|
616 | snc ; CARRY SET?
|
---|
617 | inc 1(sp) ; Propagate MSB into table address
|
---|
618 | add 2(sp),w ; Add low bits of offset to table address
|
---|
619 | snc ; and handle any carry-out
|
---|
620 | inc 1(sp)
|
---|
621 | addr=>
|
---|
622 | page __indjmp ; Do an indirect jump to that location
|
---|
623 | jmp __indjmp
|
---|
624 | label: ; case dispatch table starts here
|
---|
625 | page $nnn1
|
---|
626 | jmp $nnn1
|
---|
627 | page $nnn2
|
---|
628 | jmp $nnn2
|
---|
629 | ...
|
---|
630 | page $nnnN
|
---|
631 | jmp $nnnN
|
---|
632 |
|
---|
633 | After relaxation.
|
---|
634 | push %lo8insn(label) ; Push address of table
|
---|
635 | push %hi8insn(label)
|
---|
636 | add 2(sp),w ; Add low bits of offset to table address
|
---|
637 | snc ; and handle any carry-out
|
---|
638 | inc 1(sp)
|
---|
639 | addr=>
|
---|
640 | page __indjmp ; Do an indirect jump to that location
|
---|
641 | jmp __indjmp
|
---|
642 | label: ; case dispatch table starts here
|
---|
643 | jmp $nnn1
|
---|
644 | jmp $nnn2
|
---|
645 | ...
|
---|
646 | jmp $nnnN */
|
---|
647 |
|
---|
648 | static int
|
---|
649 | ip2k_is_switch_table_256 (abfd, sec, addr, contents)
|
---|
650 | bfd *abfd ATTRIBUTE_UNUSED;
|
---|
651 | asection *sec;
|
---|
652 | bfd_vma addr;
|
---|
653 | bfd_byte *contents;
|
---|
654 | {
|
---|
655 | bfd_byte code[16];
|
---|
656 | int index = 0;
|
---|
657 |
|
---|
658 | /* Check current page-jmp. */
|
---|
659 | if (addr + 4 > sec->_cooked_size)
|
---|
660 | return -1;
|
---|
661 |
|
---|
662 | ip2k_get_mem (abfd, contents + addr, 4, code);
|
---|
663 | if ((! IS_PAGE_OPCODE (code + 0))
|
---|
664 | || (! IS_JMP_OPCODE (code + 2)))
|
---|
665 | return -1;
|
---|
666 |
|
---|
667 | /* Search back. */
|
---|
668 | while (1)
|
---|
669 | {
|
---|
670 | if (addr < 16)
|
---|
671 | return -1;
|
---|
672 |
|
---|
673 | /* Check previous 8 instructions. */
|
---|
674 | ip2k_get_mem (abfd, contents + addr - 16, 16, code);
|
---|
675 | if ((IS_ADD_W_WREG_OPCODE (code + 0))
|
---|
676 | && (IS_SNC_OPCODE (code + 2))
|
---|
677 | && (IS_INC_1SP_OPCODE (code + 4))
|
---|
678 | && (IS_ADD_2SP_W_OPCODE (code + 6))
|
---|
679 | && (IS_SNC_OPCODE (code + 8))
|
---|
680 | && (IS_INC_1SP_OPCODE (code + 10))
|
---|
681 | && (IS_PAGE_OPCODE (code + 12))
|
---|
682 | && (IS_JMP_OPCODE (code + 14)))
|
---|
683 | return index;
|
---|
684 |
|
---|
685 | if ((IS_ADD_W_WREG_OPCODE (code + 2))
|
---|
686 | && (IS_SNC_OPCODE (code + 4))
|
---|
687 | && (IS_INC_1SP_OPCODE (code + 6))
|
---|
688 | && (IS_ADD_2SP_W_OPCODE (code + 8))
|
---|
689 | && (IS_SNC_OPCODE (code + 10))
|
---|
690 | && (IS_INC_1SP_OPCODE (code + 12))
|
---|
691 | && (IS_JMP_OPCODE (code + 14)))
|
---|
692 | return index;
|
---|
693 |
|
---|
694 | if ((! IS_PAGE_OPCODE (code + 0))
|
---|
695 | || (! IS_JMP_OPCODE (code + 2)))
|
---|
696 | return -1;
|
---|
697 |
|
---|
698 | index++;
|
---|
699 | addr -= 4;
|
---|
700 | }
|
---|
701 | }
|
---|
702 |
|
---|
703 | static bfd_boolean
|
---|
704 | ip2k_relax_switch_table_256 (abfd, sec, irel, again, misc)
|
---|
705 | bfd *abfd ATTRIBUTE_UNUSED;
|
---|
706 | asection *sec;
|
---|
707 | Elf_Internal_Rela *irel;
|
---|
708 | bfd_boolean *again;
|
---|
709 | struct misc *misc;
|
---|
710 | {
|
---|
711 | Elf_Internal_Rela *irelend = misc->irelbase + sec->reloc_count;
|
---|
712 | Elf_Internal_Rela *ireltest = irel;
|
---|
713 | bfd_byte code[12];
|
---|
714 | bfd_vma addr;
|
---|
715 |
|
---|
716 | /* Test all page instructions. */
|
---|
717 | addr = irel->r_offset;
|
---|
718 |
|
---|
719 | while (1)
|
---|
720 | {
|
---|
721 | if (addr + 4 > sec->_cooked_size)
|
---|
722 | break;
|
---|
723 |
|
---|
724 | ip2k_get_mem (abfd, misc->contents + addr, 4, code);
|
---|
725 |
|
---|
726 | if ((! IS_PAGE_OPCODE (code + 0))
|
---|
727 | || (! IS_JMP_OPCODE (code + 2)))
|
---|
728 | break;
|
---|
729 |
|
---|
730 | /* Validate relocation entry (every entry should have a matching
|
---|
731 | relocation entry). */
|
---|
732 | if (ireltest >= irelend)
|
---|
733 | {
|
---|
734 | _bfd_error_handler (_("ip2k relaxer: switch table without complete matching relocation information."));
|
---|
735 | return FALSE;
|
---|
736 | }
|
---|
737 |
|
---|
738 | if (ireltest->r_offset != addr)
|
---|
739 | {
|
---|
740 | _bfd_error_handler (_("ip2k relaxer: switch table without complete matching relocation information."));
|
---|
741 | return FALSE;
|
---|
742 | }
|
---|
743 |
|
---|
744 | if (!ip2k_test_page_insn (abfd, sec, ireltest, misc))
|
---|
745 | /* Un-removable page insn => nothing can be done. */
|
---|
746 | return TRUE;
|
---|
747 |
|
---|
748 | addr += 4;
|
---|
749 | ireltest += 2;
|
---|
750 | }
|
---|
751 |
|
---|
752 | /* Relaxable. Adjust table header. */
|
---|
753 | ip2k_get_mem (abfd, misc->contents + irel->r_offset - 4, 2, code);
|
---|
754 | if (IS_PAGE_OPCODE (code))
|
---|
755 | addr = irel->r_offset - 16;
|
---|
756 | else
|
---|
757 | addr = irel->r_offset - 14;
|
---|
758 |
|
---|
759 | ip2k_get_mem (abfd, misc->contents + addr, 12, code);
|
---|
760 | if ((!IS_ADD_W_WREG_OPCODE (code + 0))
|
---|
761 | || (!IS_SNC_OPCODE (code + 2))
|
---|
762 | || (!IS_INC_1SP_OPCODE (code + 4))
|
---|
763 | || (!IS_ADD_2SP_W_OPCODE (code + 6))
|
---|
764 | || (!IS_SNC_OPCODE (code + 8))
|
---|
765 | || (!IS_INC_1SP_OPCODE (code + 10)))
|
---|
766 | {
|
---|
767 | _bfd_error_handler (_("ip2k relaxer: switch table header corrupt."));
|
---|
768 | return FALSE;
|
---|
769 | }
|
---|
770 |
|
---|
771 | /* Delete first 3 opcodes. */
|
---|
772 | if (!ip2k_elf_relax_delete_bytes (abfd, sec, addr + 0, 6))
|
---|
773 | return FALSE;
|
---|
774 |
|
---|
775 | *again = TRUE;
|
---|
776 |
|
---|
777 | /* Delete all page instructions in table. */
|
---|
778 | while (irel < ireltest)
|
---|
779 | {
|
---|
780 | if (!ip2k_delete_page_insn (abfd, sec, irel, again, misc))
|
---|
781 | return FALSE;
|
---|
782 | irel += 2;
|
---|
783 | }
|
---|
784 |
|
---|
785 | return TRUE;
|
---|
786 | }
|
---|
787 |
|
---|
788 | /* This function handles relaxing for the ip2k.
|
---|
789 |
|
---|
790 | Principle: Start with the first page and remove page instructions that
|
---|
791 | are not require on this first page. By removing page instructions more
|
---|
792 | code will fit into this page - repeat until nothing more can be achieved
|
---|
793 | for this page. Move on to the next page.
|
---|
794 |
|
---|
795 | Processing the pages one at a time from the lowest page allows a removal
|
---|
796 | only policy to be used - pages can be removed but are never reinserted. */
|
---|
797 |
|
---|
798 | static bfd_boolean
|
---|
799 | ip2k_elf_relax_section (abfd, sec, link_info, again)
|
---|
800 | bfd *abfd;
|
---|
801 | asection *sec;
|
---|
802 | struct bfd_link_info *link_info;
|
---|
803 | bfd_boolean *again;
|
---|
804 | {
|
---|
805 | Elf_Internal_Shdr *symtab_hdr;
|
---|
806 | Elf_Internal_Rela *internal_relocs;
|
---|
807 | bfd_byte *contents = NULL;
|
---|
808 | Elf_Internal_Sym *isymbuf = NULL;
|
---|
809 | static asection * first_section = NULL;
|
---|
810 | static unsigned long search_addr;
|
---|
811 | static unsigned long page_start = 0;
|
---|
812 | static unsigned long page_end = 0;
|
---|
813 | static unsigned int pass = 0;
|
---|
814 | static bfd_boolean new_pass = FALSE;
|
---|
815 | static bfd_boolean changed = FALSE;
|
---|
816 | struct misc misc;
|
---|
817 | asection *stab;
|
---|
818 |
|
---|
819 | /* Assume nothing changes. */
|
---|
820 | *again = FALSE;
|
---|
821 |
|
---|
822 | if (first_section == NULL)
|
---|
823 | {
|
---|
824 | ip2k_relaxed = TRUE;
|
---|
825 | first_section = sec;
|
---|
826 | }
|
---|
827 |
|
---|
828 | if (first_section == sec)
|
---|
829 | {
|
---|
830 | pass++;
|
---|
831 | new_pass = TRUE;
|
---|
832 | }
|
---|
833 |
|
---|
834 | /* We don't have to do anything for a relocatable link,
|
---|
835 | if this section does not have relocs, or if this is
|
---|
836 | not a code section. */
|
---|
837 | if (link_info->relocateable
|
---|
838 | || (sec->flags & SEC_RELOC) == 0
|
---|
839 | || sec->reloc_count == 0
|
---|
840 | || (sec->flags & SEC_CODE) == 0)
|
---|
841 | return TRUE;
|
---|
842 |
|
---|
843 | /* If this is the first time we have been called
|
---|
844 | for this section, initialise the cooked size. */
|
---|
845 | if (sec->_cooked_size == 0)
|
---|
846 | sec->_cooked_size = sec->_raw_size;
|
---|
847 |
|
---|
848 | symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
|
---|
849 |
|
---|
850 | internal_relocs = _bfd_elf32_link_read_relocs (abfd, sec, NULL,
|
---|
851 | (Elf_Internal_Rela *)NULL,
|
---|
852 | link_info->keep_memory);
|
---|
853 | if (internal_relocs == NULL)
|
---|
854 | goto error_return;
|
---|
855 |
|
---|
856 | /* Make sure the stac.rela stuff gets read in. */
|
---|
857 | stab = bfd_get_section_by_name (abfd, ".stab");
|
---|
858 |
|
---|
859 | if (stab)
|
---|
860 | {
|
---|
861 | /* So stab does exits. */
|
---|
862 | Elf_Internal_Rela * irelbase;
|
---|
863 |
|
---|
864 | irelbase = _bfd_elf32_link_read_relocs (abfd, stab, NULL,
|
---|
865 | (Elf_Internal_Rela *)NULL,
|
---|
866 | link_info->keep_memory);
|
---|
867 | }
|
---|
868 |
|
---|
869 | /* Get section contents cached copy if it exists. */
|
---|
870 | if (contents == NULL)
|
---|
871 | {
|
---|
872 | /* Get cached copy if it exists. */
|
---|
873 | if (elf_section_data (sec)->this_hdr.contents != NULL)
|
---|
874 | contents = elf_section_data (sec)->this_hdr.contents;
|
---|
875 | else
|
---|
876 | {
|
---|
877 | /* Go get them off disk. */
|
---|
878 | contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
|
---|
879 | if (contents == NULL)
|
---|
880 | goto error_return;
|
---|
881 |
|
---|
882 | if (! bfd_get_section_contents (abfd, sec, contents,
|
---|
883 | (file_ptr) 0, sec->_raw_size))
|
---|
884 | goto error_return;
|
---|
885 | }
|
---|
886 | }
|
---|
887 |
|
---|
888 | /* Read this BFD's symbols cached copy if it exists. */
|
---|
889 | if (isymbuf == NULL && symtab_hdr->sh_info != 0)
|
---|
890 | {
|
---|
891 | isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
|
---|
892 | if (isymbuf == NULL)
|
---|
893 | isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
|
---|
894 | symtab_hdr->sh_info, 0,
|
---|
895 | NULL, NULL, NULL);
|
---|
896 | if (isymbuf == NULL)
|
---|
897 | goto error_return;
|
---|
898 | }
|
---|
899 |
|
---|
900 | misc.symtab_hdr = symtab_hdr;
|
---|
901 | misc.isymbuf = isymbuf;
|
---|
902 | misc.irelbase = internal_relocs;
|
---|
903 | misc.contents = contents;
|
---|
904 |
|
---|
905 | /* This is where all the relaxation actually get done. */
|
---|
906 | if ((pass == 1) || (new_pass && !changed))
|
---|
907 | {
|
---|
908 | /* On the first pass we simply search for the lowest page that
|
---|
909 | we havn't relaxed yet. Note that the pass count is reset
|
---|
910 | each time a page is complete in order to move on to the next page.
|
---|
911 | If we can't find any more pages then we are finished. */
|
---|
912 | if (new_pass)
|
---|
913 | {
|
---|
914 | pass = 1;
|
---|
915 | new_pass = FALSE;
|
---|
916 | changed = TRUE; /* Pre-initialize to break out of pass 1. */
|
---|
917 | search_addr = 0xFFFFFFFF;
|
---|
918 | }
|
---|
919 |
|
---|
920 | if ((BASEADDR (sec) + sec->_cooked_size < search_addr)
|
---|
921 | && (BASEADDR (sec) + sec->_cooked_size > page_end))
|
---|
922 | {
|
---|
923 | if (BASEADDR (sec) <= page_end)
|
---|
924 | search_addr = page_end + 1;
|
---|
925 | else
|
---|
926 | search_addr = BASEADDR (sec);
|
---|
927 |
|
---|
928 | /* Found a page => more work to do. */
|
---|
929 | *again = TRUE;
|
---|
930 | }
|
---|
931 | }
|
---|
932 | else
|
---|
933 | {
|
---|
934 | if (new_pass)
|
---|
935 | {
|
---|
936 | new_pass = FALSE;
|
---|
937 | changed = FALSE;
|
---|
938 | page_start = PAGENO (search_addr);
|
---|
939 | page_end = page_start | 0x00003FFF;
|
---|
940 | }
|
---|
941 |
|
---|
942 | /* Only process sections in range. */
|
---|
943 | if ((BASEADDR (sec) + sec->_cooked_size >= page_start)
|
---|
944 | && (BASEADDR (sec) <= page_end))
|
---|
945 | {
|
---|
946 | if (!ip2k_elf_relax_section_page (abfd, sec, &changed, &misc, page_start, page_end))
|
---|
947 | return FALSE;
|
---|
948 | }
|
---|
949 | *again = TRUE;
|
---|
950 | }
|
---|
951 |
|
---|
952 | /* Perform some house keeping after relaxing the section. */
|
---|
953 |
|
---|
954 | if (isymbuf != NULL
|
---|
955 | && symtab_hdr->contents != (unsigned char *) isymbuf)
|
---|
956 | {
|
---|
957 | if (! link_info->keep_memory)
|
---|
958 | free (isymbuf);
|
---|
959 | else
|
---|
960 | symtab_hdr->contents = (unsigned char *) isymbuf;
|
---|
961 | }
|
---|
962 |
|
---|
963 | if (contents != NULL
|
---|
964 | && elf_section_data (sec)->this_hdr.contents != contents)
|
---|
965 | {
|
---|
966 | if (! link_info->keep_memory)
|
---|
967 | free (contents);
|
---|
968 | else
|
---|
969 | {
|
---|
970 | /* Cache the section contents for elf_link_input_bfd. */
|
---|
971 | elf_section_data (sec)->this_hdr.contents = contents;
|
---|
972 | }
|
---|
973 | }
|
---|
974 |
|
---|
975 | if (internal_relocs != NULL
|
---|
976 | && elf_section_data (sec)->relocs != internal_relocs)
|
---|
977 | free (internal_relocs);
|
---|
978 |
|
---|
979 | return TRUE;
|
---|
980 |
|
---|
981 | error_return:
|
---|
982 | if (isymbuf != NULL
|
---|
983 | && symtab_hdr->contents != (unsigned char *) isymbuf)
|
---|
984 | free (isymbuf);
|
---|
985 | if (contents != NULL
|
---|
986 | && elf_section_data (sec)->this_hdr.contents != contents)
|
---|
987 | free (contents);
|
---|
988 | if (internal_relocs != NULL
|
---|
989 | && elf_section_data (sec)->relocs != internal_relocs)
|
---|
990 | free (internal_relocs);
|
---|
991 | return FALSE;
|
---|
992 | }
|
---|
993 |
|
---|
994 | /* This function handles relaxation of a section in a specific page. */
|
---|
995 |
|
---|
996 | static bfd_boolean
|
---|
997 | ip2k_elf_relax_section_page (abfd, sec, again, misc, page_start, page_end)
|
---|
998 | bfd *abfd;
|
---|
999 | asection *sec;
|
---|
1000 | bfd_boolean *again;
|
---|
1001 | struct misc *misc;
|
---|
1002 | unsigned long page_start;
|
---|
1003 | unsigned long page_end;
|
---|
1004 | {
|
---|
1005 | Elf_Internal_Rela *irelend = misc->irelbase + sec->reloc_count;
|
---|
1006 | Elf_Internal_Rela *irel;
|
---|
1007 | int switch_table_128;
|
---|
1008 | int switch_table_256;
|
---|
1009 |
|
---|
1010 | /* Walk thru the section looking for relaxation opertunities. */
|
---|
1011 | for (irel = misc->irelbase; irel < irelend; irel++)
|
---|
1012 | {
|
---|
1013 | if (ELF32_R_TYPE (irel->r_info) != (int) R_IP2K_PAGE3)
|
---|
1014 | /* Ignore non page instructions. */
|
---|
1015 | continue;
|
---|
1016 |
|
---|
1017 | if (BASEADDR (sec) + irel->r_offset < page_start)
|
---|
1018 | /* Ignore page instructions on earlier page - they have
|
---|
1019 | already been processed. Remember that there is code flow
|
---|
1020 | that crosses a page boundary. */
|
---|
1021 | continue;
|
---|
1022 |
|
---|
1023 | if (BASEADDR (sec) + irel->r_offset > page_end)
|
---|
1024 | /* Flow beyond end of page => nothing more to do for this page. */
|
---|
1025 | return TRUE;
|
---|
1026 |
|
---|
1027 | /* Detect switch tables. */
|
---|
1028 | switch_table_128 = ip2k_is_switch_table_128 (abfd, sec, irel->r_offset, misc->contents);
|
---|
1029 | switch_table_256 = ip2k_is_switch_table_256 (abfd, sec, irel->r_offset, misc->contents);
|
---|
1030 |
|
---|
1031 | if ((switch_table_128 > 0) || (switch_table_256 > 0))
|
---|
1032 | /* If the index is greater than 0 then it has already been processed. */
|
---|
1033 | continue;
|
---|
1034 |
|
---|
1035 | if (switch_table_128 == 0)
|
---|
1036 | {
|
---|
1037 | if (!ip2k_relax_switch_table_128 (abfd, sec, irel, again, misc))
|
---|
1038 | return FALSE;
|
---|
1039 |
|
---|
1040 | continue;
|
---|
1041 | }
|
---|
1042 |
|
---|
1043 | if (switch_table_256 == 0)
|
---|
1044 | {
|
---|
1045 | if (!ip2k_relax_switch_table_256 (abfd, sec, irel, again, misc))
|
---|
1046 | return FALSE;
|
---|
1047 |
|
---|
1048 | continue;
|
---|
1049 | }
|
---|
1050 |
|
---|
1051 | /* Simple relax. */
|
---|
1052 | if (ip2k_test_page_insn (abfd, sec, irel, misc))
|
---|
1053 | {
|
---|
1054 | if (!ip2k_delete_page_insn (abfd, sec, irel, again, misc))
|
---|
1055 | return FALSE;
|
---|
1056 |
|
---|
1057 | continue;
|
---|
1058 | }
|
---|
1059 | }
|
---|
1060 |
|
---|
1061 | return TRUE;
|
---|
1062 | }
|
---|
1063 |
|
---|
1064 | /* Parts of a Stabs entry. */
|
---|
1065 |
|
---|
1066 | #define STRDXOFF (0)
|
---|
1067 | #define TYPEOFF (4)
|
---|
1068 | #define OTHEROFF (5)
|
---|
1069 | #define DESCOFF (6)
|
---|
1070 | #define VALOFF (8)
|
---|
1071 | #define STABSIZE (12)
|
---|
1072 |
|
---|
1073 | /* Adjust all the relocations entries after adding or inserting instructions. */
|
---|
1074 |
|
---|
1075 | static void
|
---|
1076 | adjust_all_relocations (abfd, sec, addr, endaddr, count, noadj)
|
---|
1077 | bfd *abfd;
|
---|
1078 | asection *sec;
|
---|
1079 | bfd_vma addr;
|
---|
1080 | bfd_vma endaddr;
|
---|
1081 | int count;
|
---|
1082 | int noadj;
|
---|
1083 | {
|
---|
1084 | Elf_Internal_Shdr *symtab_hdr;
|
---|
1085 | Elf_Internal_Sym *isymbuf, *isym, *isymend;
|
---|
1086 | unsigned int shndx;
|
---|
1087 | bfd_byte *contents;
|
---|
1088 | Elf_Internal_Rela *irel, *irelend, *irelbase;
|
---|
1089 | struct elf_link_hash_entry **sym_hashes;
|
---|
1090 | struct elf_link_hash_entry **end_hashes;
|
---|
1091 | unsigned int symcount;
|
---|
1092 | asection *stab;
|
---|
1093 |
|
---|
1094 | symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
|
---|
1095 | isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
|
---|
1096 |
|
---|
1097 | shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
|
---|
1098 |
|
---|
1099 | contents = elf_section_data (sec)->this_hdr.contents;
|
---|
1100 |
|
---|
1101 | irelbase = elf_section_data (sec)->relocs;
|
---|
1102 | irelend = irelbase + sec->reloc_count;
|
---|
1103 |
|
---|
1104 | for (irel = irelbase; irel < irelend; irel++)
|
---|
1105 | {
|
---|
1106 | if (ELF32_R_TYPE (irel->r_info) != R_IP2K_NONE)
|
---|
1107 | {
|
---|
1108 | /* Get the value of the symbol referred to by the reloc. */
|
---|
1109 | if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
|
---|
1110 | {
|
---|
1111 | asection *sym_sec;
|
---|
1112 |
|
---|
1113 | /* A local symbol. */
|
---|
1114 | isym = isymbuf + ELF32_R_SYM (irel->r_info);
|
---|
1115 | sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
|
---|
1116 |
|
---|
1117 | if (isym->st_shndx == shndx)
|
---|
1118 | {
|
---|
1119 | bfd_vma baseaddr = BASEADDR (sec);
|
---|
1120 | bfd_vma symval = BASEADDR (sym_sec) + isym->st_value
|
---|
1121 | + irel->r_addend;
|
---|
1122 |
|
---|
1123 | if ((baseaddr + addr + noadj) <= symval
|
---|
1124 | && symval < (baseaddr + endaddr))
|
---|
1125 | irel->r_addend += count;
|
---|
1126 | }
|
---|
1127 | }
|
---|
1128 | }
|
---|
1129 |
|
---|
1130 | /* Do this only for PC space relocations. */
|
---|
1131 | if (addr <= irel->r_offset && irel->r_offset < endaddr)
|
---|
1132 | irel->r_offset += count;
|
---|
1133 | }
|
---|
1134 |
|
---|
1135 | /* Now fix the stab relocations. */
|
---|
1136 | stab = bfd_get_section_by_name (abfd, ".stab");
|
---|
1137 | if (stab)
|
---|
1138 | {
|
---|
1139 | bfd_byte *stabcontents, *stabend, *stabp;
|
---|
1140 |
|
---|
1141 | irelbase = elf_section_data (stab)->relocs;
|
---|
1142 | irelend = irelbase + stab->reloc_count;
|
---|
1143 |
|
---|
1144 | /* Pull out the contents of the stab section. */
|
---|
1145 | if (elf_section_data (stab)->this_hdr.contents != NULL)
|
---|
1146 | stabcontents = elf_section_data (stab)->this_hdr.contents;
|
---|
1147 | else
|
---|
1148 | {
|
---|
1149 | stabcontents = (bfd_byte *) bfd_alloc (abfd, stab->_raw_size);
|
---|
1150 | if (stabcontents == NULL)
|
---|
1151 | return;
|
---|
1152 |
|
---|
1153 | if (! bfd_get_section_contents (abfd, stab, stabcontents,
|
---|
1154 | (file_ptr) 0, stab->_raw_size))
|
---|
1155 | return;
|
---|
1156 |
|
---|
1157 | /* We need to remember this. */
|
---|
1158 | elf_section_data (stab)->this_hdr.contents = stabcontents;
|
---|
1159 | }
|
---|
1160 |
|
---|
1161 | stabend = stabcontents + stab->_raw_size;
|
---|
1162 |
|
---|
1163 | for (irel = irelbase; irel < irelend; irel++)
|
---|
1164 | {
|
---|
1165 | if (ELF32_R_TYPE (irel->r_info) != R_IP2K_NONE)
|
---|
1166 | {
|
---|
1167 | /* Get the value of the symbol referred to by the reloc. */
|
---|
1168 | if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
|
---|
1169 | {
|
---|
1170 | asection *sym_sec;
|
---|
1171 |
|
---|
1172 | /* A local symbol. */
|
---|
1173 | isym = isymbuf + ELF32_R_SYM (irel->r_info);
|
---|
1174 | sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
|
---|
1175 |
|
---|
1176 | if (sym_sec == sec)
|
---|
1177 | {
|
---|
1178 | const char *name;
|
---|
1179 | unsigned long strx;
|
---|
1180 | unsigned char type, other;
|
---|
1181 | unsigned short desc;
|
---|
1182 | bfd_vma value;
|
---|
1183 | bfd_vma baseaddr = BASEADDR (sec);
|
---|
1184 | bfd_vma symval = BASEADDR (sym_sec) + isym->st_value
|
---|
1185 | + irel->r_addend;
|
---|
1186 |
|
---|
1187 | if ((baseaddr + addr) <= symval
|
---|
1188 | && symval <= (baseaddr + endaddr))
|
---|
1189 | irel->r_addend += count;
|
---|
1190 |
|
---|
1191 | /* Go hunt up a function and fix its line info if needed. */
|
---|
1192 | stabp = stabcontents + irel->r_offset - 8;
|
---|
1193 |
|
---|
1194 | /* Go pullout the stab entry. */
|
---|
1195 | strx = bfd_h_get_32 (abfd, stabp + STRDXOFF);
|
---|
1196 | type = bfd_h_get_8 (abfd, stabp + TYPEOFF);
|
---|
1197 | other = bfd_h_get_8 (abfd, stabp + OTHEROFF);
|
---|
1198 | desc = bfd_h_get_16 (abfd, stabp + DESCOFF);
|
---|
1199 | value = bfd_h_get_32 (abfd, stabp + VALOFF);
|
---|
1200 |
|
---|
1201 | name = bfd_get_stab_name (type);
|
---|
1202 |
|
---|
1203 | if (strcmp (name, "FUN") == 0)
|
---|
1204 | {
|
---|
1205 | int function_adjusted = 0;
|
---|
1206 |
|
---|
1207 | if (symval > (baseaddr + addr))
|
---|
1208 | /* Not in this function. */
|
---|
1209 | continue;
|
---|
1210 |
|
---|
1211 | /* Hey we got a function hit. */
|
---|
1212 | stabp += STABSIZE;
|
---|
1213 | for (;stabp < stabend; stabp += STABSIZE)
|
---|
1214 | {
|
---|
1215 | /* Go pullout the stab entry. */
|
---|
1216 | strx = bfd_h_get_32 (abfd, stabp + STRDXOFF);
|
---|
1217 | type = bfd_h_get_8 (abfd, stabp + TYPEOFF);
|
---|
1218 | other = bfd_h_get_8 (abfd, stabp + OTHEROFF);
|
---|
1219 | desc = bfd_h_get_16 (abfd, stabp + DESCOFF);
|
---|
1220 | value = bfd_h_get_32 (abfd, stabp + VALOFF);
|
---|
1221 |
|
---|
1222 | name = bfd_get_stab_name (type);
|
---|
1223 |
|
---|
1224 | if (strcmp (name, "FUN") == 0)
|
---|
1225 | {
|
---|
1226 | /* Hit another function entry. */
|
---|
1227 | if (function_adjusted)
|
---|
1228 | {
|
---|
1229 | /* Adjust the value. */
|
---|
1230 | value += count;
|
---|
1231 |
|
---|
1232 | /* We need to put it back. */
|
---|
1233 | bfd_h_put_32 (abfd, value,stabp + VALOFF);
|
---|
1234 | }
|
---|
1235 |
|
---|
1236 | /* And then bale out. */
|
---|
1237 | break;
|
---|
1238 | }
|
---|
1239 |
|
---|
1240 | if (strcmp (name, "SLINE") == 0)
|
---|
1241 | {
|
---|
1242 | /* Got a line entry. */
|
---|
1243 | if ((baseaddr + addr) <= (symval + value))
|
---|
1244 | {
|
---|
1245 | /* Adjust the line entry. */
|
---|
1246 | value += count;
|
---|
1247 |
|
---|
1248 | /* We need to put it back. */
|
---|
1249 | bfd_h_put_32 (abfd, value,stabp + VALOFF);
|
---|
1250 | function_adjusted = 1;
|
---|
1251 | }
|
---|
1252 | }
|
---|
1253 | }
|
---|
1254 | }
|
---|
1255 | }
|
---|
1256 | }
|
---|
1257 | }
|
---|
1258 | }
|
---|
1259 | }
|
---|
1260 |
|
---|
1261 | /* When adding an instruction back it is sometimes necessary to move any
|
---|
1262 | global or local symbol that was referencing the first instruction of
|
---|
1263 | the moved block to refer to the first instruction of the inserted block.
|
---|
1264 |
|
---|
1265 | For example adding a PAGE instruction before a CALL or JMP requires
|
---|
1266 | that any label on the CALL or JMP is moved to the PAGE insn. */
|
---|
1267 | addr += noadj;
|
---|
1268 |
|
---|
1269 | /* Adjust the local symbols defined in this section. */
|
---|
1270 | isymend = isymbuf + symtab_hdr->sh_info;
|
---|
1271 | for (isym = isymbuf; isym < isymend; isym++)
|
---|
1272 | {
|
---|
1273 | if (isym->st_shndx == shndx
|
---|
1274 | && addr <= isym->st_value
|
---|
1275 | && isym->st_value < endaddr)
|
---|
1276 | isym->st_value += count;
|
---|
1277 | }
|
---|
1278 |
|
---|
1279 | /* Now adjust the global symbols defined in this section. */
|
---|
1280 | symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
|
---|
1281 | - symtab_hdr->sh_info);
|
---|
1282 | sym_hashes = elf_sym_hashes (abfd);
|
---|
1283 | end_hashes = sym_hashes + symcount;
|
---|
1284 | for (; sym_hashes < end_hashes; sym_hashes++)
|
---|
1285 | {
|
---|
1286 | struct elf_link_hash_entry *sym_hash = *sym_hashes;
|
---|
1287 |
|
---|
1288 | if ((sym_hash->root.type == bfd_link_hash_defined
|
---|
1289 | || sym_hash->root.type == bfd_link_hash_defweak)
|
---|
1290 | && sym_hash->root.u.def.section == sec)
|
---|
1291 | {
|
---|
1292 | if (addr <= sym_hash->root.u.def.value
|
---|
1293 | && sym_hash->root.u.def.value < endaddr)
|
---|
1294 | sym_hash->root.u.def.value += count;
|
---|
1295 | }
|
---|
1296 | }
|
---|
1297 |
|
---|
1298 | return;
|
---|
1299 | }
|
---|
1300 |
|
---|
1301 | /* Delete some bytes from a section while relaxing. */
|
---|
1302 |
|
---|
1303 | static bfd_boolean
|
---|
1304 | ip2k_elf_relax_delete_bytes (abfd, sec, addr, count)
|
---|
1305 | bfd *abfd;
|
---|
1306 | asection *sec;
|
---|
1307 | bfd_vma addr;
|
---|
1308 | int count;
|
---|
1309 | {
|
---|
1310 | bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
|
---|
1311 | bfd_vma endaddr = sec->_cooked_size;
|
---|
1312 |
|
---|
1313 | /* Actually delete the bytes. */
|
---|
1314 | memmove (contents + addr, contents + addr + count,
|
---|
1315 | endaddr - addr - count);
|
---|
1316 |
|
---|
1317 | sec->_cooked_size -= count;
|
---|
1318 |
|
---|
1319 | adjust_all_relocations (abfd, sec, addr + count, endaddr, -count, 0);
|
---|
1320 | return TRUE;
|
---|
1321 | }
|
---|
1322 |
|
---|
1323 | /* -------------------------------------------------------------------- */
|
---|
1324 |
|
---|
1325 | /* XXX: The following code is the result of a cut&paste. This unfortunate
|
---|
1326 | practice is very widespread in the various target back-end files. */
|
---|
1327 |
|
---|
1328 | /* Set the howto pointer for a IP2K ELF reloc. */
|
---|
1329 |
|
---|
1330 | static void
|
---|
1331 | ip2k_info_to_howto_rela (abfd, cache_ptr, dst)
|
---|
1332 | bfd * abfd ATTRIBUTE_UNUSED;
|
---|
1333 | arelent * cache_ptr;
|
---|
1334 | Elf_Internal_Rela * dst;
|
---|
1335 | {
|
---|
1336 | unsigned int r_type;
|
---|
1337 |
|
---|
1338 | r_type = ELF32_R_TYPE (dst->r_info);
|
---|
1339 | switch (r_type)
|
---|
1340 | {
|
---|
1341 | default:
|
---|
1342 | cache_ptr->howto = & ip2k_elf_howto_table [r_type];
|
---|
1343 | break;
|
---|
1344 | }
|
---|
1345 | }
|
---|
1346 |
|
---|
1347 | /* Perform a single relocation.
|
---|
1348 | By default we use the standard BFD routines. */
|
---|
1349 |
|
---|
1350 | static bfd_reloc_status_type
|
---|
1351 | ip2k_final_link_relocate (howto, input_bfd, input_section, contents, rel,
|
---|
1352 | relocation)
|
---|
1353 | reloc_howto_type * howto;
|
---|
1354 | bfd * input_bfd;
|
---|
1355 | asection * input_section;
|
---|
1356 | bfd_byte * contents;
|
---|
1357 | Elf_Internal_Rela * rel;
|
---|
1358 | bfd_vma relocation;
|
---|
1359 | {
|
---|
1360 | static bfd_vma page_addr = 0;
|
---|
1361 |
|
---|
1362 | bfd_reloc_status_type r = bfd_reloc_ok;
|
---|
1363 | switch (howto->type)
|
---|
1364 | {
|
---|
1365 | /* Handle data space relocations. */
|
---|
1366 | case R_IP2K_FR9:
|
---|
1367 | case R_IP2K_BANK:
|
---|
1368 | if ((relocation & IP2K_DATA_MASK) == IP2K_DATA_VALUE)
|
---|
1369 | relocation &= ~IP2K_DATA_MASK;
|
---|
1370 | else
|
---|
1371 | r = bfd_reloc_notsupported;
|
---|
1372 | break;
|
---|
1373 |
|
---|
1374 | case R_IP2K_LO8DATA:
|
---|
1375 | case R_IP2K_HI8DATA:
|
---|
1376 | case R_IP2K_EX8DATA:
|
---|
1377 | break;
|
---|
1378 |
|
---|
1379 | /* Handle insn space relocations. */
|
---|
1380 | case R_IP2K_PAGE3:
|
---|
1381 | page_addr = BASEADDR (input_section) + rel->r_offset;
|
---|
1382 | if ((relocation & IP2K_INSN_MASK) == IP2K_INSN_VALUE)
|
---|
1383 | relocation &= ~IP2K_INSN_MASK;
|
---|
1384 | else
|
---|
1385 | r = bfd_reloc_notsupported;
|
---|
1386 | break;
|
---|
1387 |
|
---|
1388 | case R_IP2K_ADDR16CJP:
|
---|
1389 | if (BASEADDR (input_section) + rel->r_offset != page_addr + 2)
|
---|
1390 | {
|
---|
1391 | /* No preceeding page instruction, verify that it isn't needed. */
|
---|
1392 | if (PAGENO (relocation + rel->r_addend) !=
|
---|
1393 | ip2k_nominal_page_bits (input_bfd, input_section,
|
---|
1394 | rel->r_offset, contents))
|
---|
1395 | _bfd_error_handler (_("ip2k linker: missing page instruction at 0x%08lx (dest = 0x%08lx)."),
|
---|
1396 | BASEADDR (input_section) + rel->r_offset,
|
---|
1397 | relocation + rel->r_addend);
|
---|
1398 | }
|
---|
1399 | else if (ip2k_relaxed)
|
---|
1400 | {
|
---|
1401 | /* Preceeding page instruction. Verify that the page instruction is
|
---|
1402 | really needed. One reason for the relaxation to miss a page is if
|
---|
1403 | the section is not marked as executable. */
|
---|
1404 | if (!ip2k_is_switch_table_128 (input_bfd, input_section, rel->r_offset - 2, contents) &&
|
---|
1405 | !ip2k_is_switch_table_256 (input_bfd, input_section, rel->r_offset - 2, contents) &&
|
---|
1406 | (PAGENO (relocation + rel->r_addend) ==
|
---|
1407 | ip2k_nominal_page_bits (input_bfd, input_section,
|
---|
1408 | rel->r_offset - 2, contents)))
|
---|
1409 | _bfd_error_handler (_("ip2k linker: redundant page instruction at 0x%08lx (dest = 0x%08lx)."),
|
---|
1410 | page_addr,
|
---|
1411 | relocation + rel->r_addend);
|
---|
1412 | }
|
---|
1413 | if ((relocation & IP2K_INSN_MASK) == IP2K_INSN_VALUE)
|
---|
1414 | relocation &= ~IP2K_INSN_MASK;
|
---|
1415 | else
|
---|
1416 | r = bfd_reloc_notsupported;
|
---|
1417 | break;
|
---|
1418 |
|
---|
1419 | case R_IP2K_LO8INSN:
|
---|
1420 | case R_IP2K_HI8INSN:
|
---|
1421 | case R_IP2K_PC_SKIP:
|
---|
1422 | if ((relocation & IP2K_INSN_MASK) == IP2K_INSN_VALUE)
|
---|
1423 | relocation &= ~IP2K_INSN_MASK;
|
---|
1424 | else
|
---|
1425 | r = bfd_reloc_notsupported;
|
---|
1426 | break;
|
---|
1427 |
|
---|
1428 | case R_IP2K_16:
|
---|
1429 | /* If this is a relocation involving a TEXT
|
---|
1430 | symbol, reduce it to a word address. */
|
---|
1431 | if ((relocation & IP2K_INSN_MASK) == IP2K_INSN_VALUE)
|
---|
1432 | howto = &ip2k_elf_howto_table[ (int) R_IP2K_TEXT];
|
---|
1433 | break;
|
---|
1434 |
|
---|
1435 | /* Pass others through. */
|
---|
1436 | default:
|
---|
1437 | break;
|
---|
1438 | }
|
---|
1439 |
|
---|
1440 | /* Only install relocation if above tests did not disqualify it. */
|
---|
1441 | if (r == bfd_reloc_ok)
|
---|
1442 | r = _bfd_final_link_relocate (howto, input_bfd, input_section,
|
---|
1443 | contents, rel->r_offset,
|
---|
1444 | relocation, rel->r_addend);
|
---|
1445 |
|
---|
1446 | return r;
|
---|
1447 | }
|
---|
1448 |
|
---|
1449 | /* Relocate a IP2K ELF section.
|
---|
1450 |
|
---|
1451 | The RELOCATE_SECTION function is called by the new ELF backend linker
|
---|
1452 | to handle the relocations for a section.
|
---|
1453 |
|
---|
1454 | The relocs are always passed as Rela structures; if the section
|
---|
1455 | actually uses Rel structures, the r_addend field will always be
|
---|
1456 | zero.
|
---|
1457 |
|
---|
1458 | This function is responsible for adjusting the section contents as
|
---|
1459 | necessary, and (if using Rela relocs and generating a relocateable
|
---|
1460 | output file) adjusting the reloc addend as necessary.
|
---|
1461 |
|
---|
1462 | This function does not have to worry about setting the reloc
|
---|
1463 | address or the reloc symbol index.
|
---|
1464 |
|
---|
1465 | LOCAL_SYMS is a pointer to the swapped in local symbols.
|
---|
1466 |
|
---|
1467 | LOCAL_SECTIONS is an array giving the section in the input file
|
---|
1468 | corresponding to the st_shndx field of each local symbol.
|
---|
1469 |
|
---|
1470 | The global hash table entry for the global symbols can be found
|
---|
1471 | via elf_sym_hashes (input_bfd).
|
---|
1472 |
|
---|
1473 | When generating relocateable output, this function must handle
|
---|
1474 | STB_LOCAL/STT_SECTION symbols specially. The output symbol is
|
---|
1475 | going to be the section symbol corresponding to the output
|
---|
1476 | section, which means that the addend must be adjusted
|
---|
1477 | accordingly. */
|
---|
1478 |
|
---|
1479 | static bfd_boolean
|
---|
1480 | ip2k_elf_relocate_section (output_bfd, info, input_bfd, input_section,
|
---|
1481 | contents, relocs, local_syms, local_sections)
|
---|
1482 | bfd *output_bfd ATTRIBUTE_UNUSED;
|
---|
1483 | struct bfd_link_info *info;
|
---|
1484 | bfd *input_bfd;
|
---|
1485 | asection *input_section;
|
---|
1486 | bfd_byte *contents;
|
---|
1487 | Elf_Internal_Rela *relocs;
|
---|
1488 | Elf_Internal_Sym *local_syms;
|
---|
1489 | asection **local_sections;
|
---|
1490 | {
|
---|
1491 | Elf_Internal_Shdr *symtab_hdr;
|
---|
1492 | struct elf_link_hash_entry **sym_hashes;
|
---|
1493 | Elf_Internal_Rela *rel;
|
---|
1494 | Elf_Internal_Rela *relend;
|
---|
1495 |
|
---|
1496 | if (info->relocateable)
|
---|
1497 | return TRUE;
|
---|
1498 |
|
---|
1499 | symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
|
---|
1500 | sym_hashes = elf_sym_hashes (input_bfd);
|
---|
1501 | relend = relocs + input_section->reloc_count;
|
---|
1502 |
|
---|
1503 | for (rel = relocs; rel < relend; rel ++)
|
---|
1504 | {
|
---|
1505 | reloc_howto_type * howto;
|
---|
1506 | unsigned long r_symndx;
|
---|
1507 | Elf_Internal_Sym * sym;
|
---|
1508 | asection * sec;
|
---|
1509 | struct elf_link_hash_entry * h;
|
---|
1510 | bfd_vma relocation;
|
---|
1511 | bfd_reloc_status_type r;
|
---|
1512 | const char * name = NULL;
|
---|
1513 | int r_type;
|
---|
1514 |
|
---|
1515 | /* This is a final link. */
|
---|
1516 | r_type = ELF32_R_TYPE (rel->r_info);
|
---|
1517 | r_symndx = ELF32_R_SYM (rel->r_info);
|
---|
1518 | howto = ip2k_elf_howto_table + ELF32_R_TYPE (rel->r_info);
|
---|
1519 | h = NULL;
|
---|
1520 | sym = NULL;
|
---|
1521 | sec = NULL;
|
---|
1522 |
|
---|
1523 | if (r_symndx < symtab_hdr->sh_info)
|
---|
1524 | {
|
---|
1525 | sym = local_syms + r_symndx;
|
---|
1526 | sec = local_sections [r_symndx];
|
---|
1527 | relocation = BASEADDR (sec) + sym->st_value;
|
---|
1528 |
|
---|
1529 | name = bfd_elf_string_from_elf_section
|
---|
1530 | (input_bfd, symtab_hdr->sh_link, sym->st_name);
|
---|
1531 | name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
|
---|
1532 | }
|
---|
1533 | else
|
---|
1534 | {
|
---|
1535 | h = sym_hashes [r_symndx - symtab_hdr->sh_info];
|
---|
1536 |
|
---|
1537 | while (h->root.type == bfd_link_hash_indirect
|
---|
1538 | || h->root.type == bfd_link_hash_warning)
|
---|
1539 | h = (struct elf_link_hash_entry *) h->root.u.i.link;
|
---|
1540 |
|
---|
1541 | name = h->root.root.string;
|
---|
1542 |
|
---|
1543 | if (h->root.type == bfd_link_hash_defined
|
---|
1544 | || h->root.type == bfd_link_hash_defweak)
|
---|
1545 | {
|
---|
1546 | sec = h->root.u.def.section;
|
---|
1547 | relocation = h->root.u.def.value + BASEADDR (sec);
|
---|
1548 | }
|
---|
1549 |
|
---|
1550 | else if (h->root.type == bfd_link_hash_undefweak)
|
---|
1551 | relocation = 0;
|
---|
1552 |
|
---|
1553 | else
|
---|
1554 | {
|
---|
1555 | if (! ((*info->callbacks->undefined_symbol)
|
---|
1556 | (info, h->root.root.string, input_bfd,
|
---|
1557 | input_section, rel->r_offset,
|
---|
1558 | (! info->shared || info->no_undefined))))
|
---|
1559 | return FALSE;
|
---|
1560 | relocation = 0;
|
---|
1561 | }
|
---|
1562 | }
|
---|
1563 |
|
---|
1564 | /* Finally, the sole IP2K-specific part. */
|
---|
1565 | r = ip2k_final_link_relocate (howto, input_bfd, input_section,
|
---|
1566 | contents, rel, relocation);
|
---|
1567 |
|
---|
1568 | if (r != bfd_reloc_ok)
|
---|
1569 | {
|
---|
1570 | const char * msg = (const char *) NULL;
|
---|
1571 |
|
---|
1572 | switch (r)
|
---|
1573 | {
|
---|
1574 | case bfd_reloc_overflow:
|
---|
1575 | r = info->callbacks->reloc_overflow
|
---|
1576 | (info, name, howto->name, (bfd_vma) 0,
|
---|
1577 | input_bfd, input_section, rel->r_offset);
|
---|
1578 | break;
|
---|
1579 |
|
---|
1580 | case bfd_reloc_undefined:
|
---|
1581 | r = info->callbacks->undefined_symbol
|
---|
1582 | (info, name, input_bfd, input_section, rel->r_offset, TRUE);
|
---|
1583 | break;
|
---|
1584 |
|
---|
1585 | case bfd_reloc_outofrange:
|
---|
1586 | msg = _("internal error: out of range error");
|
---|
1587 | break;
|
---|
1588 |
|
---|
1589 | /* This is how ip2k_final_link_relocate tells us of a non-kosher
|
---|
1590 | reference between insn & data address spaces. */
|
---|
1591 | case bfd_reloc_notsupported:
|
---|
1592 | if (sym != NULL) /* Only if it's not an unresolved symbol. */
|
---|
1593 | msg = _("unsupported relocation between data/insn address spaces");
|
---|
1594 | break;
|
---|
1595 |
|
---|
1596 | case bfd_reloc_dangerous:
|
---|
1597 | msg = _("internal error: dangerous relocation");
|
---|
1598 | break;
|
---|
1599 |
|
---|
1600 | default:
|
---|
1601 | msg = _("internal error: unknown error");
|
---|
1602 | break;
|
---|
1603 | }
|
---|
1604 |
|
---|
1605 | if (msg)
|
---|
1606 | r = info->callbacks->warning
|
---|
1607 | (info, msg, name, input_bfd, input_section, rel->r_offset);
|
---|
1608 |
|
---|
1609 | if (! r)
|
---|
1610 | return FALSE;
|
---|
1611 | }
|
---|
1612 | }
|
---|
1613 |
|
---|
1614 | return TRUE;
|
---|
1615 | }
|
---|
1616 |
|
---|
1617 | static asection *
|
---|
1618 | ip2k_elf_gc_mark_hook (sec, info, rel, h, sym)
|
---|
1619 | asection *sec;
|
---|
1620 | struct bfd_link_info *info ATTRIBUTE_UNUSED;
|
---|
1621 | Elf_Internal_Rela *rel;
|
---|
1622 | struct elf_link_hash_entry *h;
|
---|
1623 | Elf_Internal_Sym *sym;
|
---|
1624 | {
|
---|
1625 | if (h != NULL)
|
---|
1626 | {
|
---|
1627 | switch (ELF32_R_TYPE (rel->r_info))
|
---|
1628 | {
|
---|
1629 | #if 0
|
---|
1630 | case R_IP2K_GNU_VTINHERIT:
|
---|
1631 | case R_IP2K_GNU_VTENTRY:
|
---|
1632 | break;
|
---|
1633 | #endif
|
---|
1634 |
|
---|
1635 | default:
|
---|
1636 | switch (h->root.type)
|
---|
1637 | {
|
---|
1638 | case bfd_link_hash_defined:
|
---|
1639 | case bfd_link_hash_defweak:
|
---|
1640 | return h->root.u.def.section;
|
---|
1641 |
|
---|
1642 | case bfd_link_hash_common:
|
---|
1643 | return h->root.u.c.p->section;
|
---|
1644 |
|
---|
1645 | default:
|
---|
1646 | break;
|
---|
1647 | }
|
---|
1648 | }
|
---|
1649 | }
|
---|
1650 | else
|
---|
1651 | {
|
---|
1652 | if (!(elf_bad_symtab (sec->owner)
|
---|
1653 | && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
|
---|
1654 | && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
|
---|
1655 | && sym->st_shndx != SHN_COMMON))
|
---|
1656 | return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
|
---|
1657 | }
|
---|
1658 | return NULL;
|
---|
1659 | }
|
---|
1660 |
|
---|
1661 | static bfd_boolean
|
---|
1662 | ip2k_elf_gc_sweep_hook (abfd, info, sec, relocs)
|
---|
1663 | bfd *abfd ATTRIBUTE_UNUSED;
|
---|
1664 | struct bfd_link_info *info ATTRIBUTE_UNUSED;
|
---|
1665 | asection *sec ATTRIBUTE_UNUSED;
|
---|
1666 | const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
|
---|
1667 | {
|
---|
1668 | /* We don't use got and plt entries for ip2k. */
|
---|
1669 | return TRUE;
|
---|
1670 | }
|
---|
1671 |
|
---|
1672 | #define TARGET_BIG_SYM bfd_elf32_ip2k_vec
|
---|
1673 | #define TARGET_BIG_NAME "elf32-ip2k"
|
---|
1674 |
|
---|
1675 | #define ELF_ARCH bfd_arch_ip2k
|
---|
1676 | #define ELF_MACHINE_CODE EM_IP2K
|
---|
1677 | #define ELF_MACHINE_ALT1 EM_IP2K_OLD
|
---|
1678 | #define ELF_MAXPAGESIZE 1 /* No pages on the IP2K. */
|
---|
1679 |
|
---|
1680 | #define elf_info_to_howto_rel NULL
|
---|
1681 | #define elf_info_to_howto ip2k_info_to_howto_rela
|
---|
1682 |
|
---|
1683 | #define elf_backend_can_gc_sections 1
|
---|
1684 | #define elf_backend_rela_normal 1
|
---|
1685 | #define elf_backend_gc_mark_hook ip2k_elf_gc_mark_hook
|
---|
1686 | #define elf_backend_gc_sweep_hook ip2k_elf_gc_sweep_hook
|
---|
1687 | #define elf_backend_relocate_section ip2k_elf_relocate_section
|
---|
1688 |
|
---|
1689 | #define elf_symbol_leading_char '_'
|
---|
1690 | #define bfd_elf32_bfd_reloc_type_lookup ip2k_reloc_type_lookup
|
---|
1691 | #define bfd_elf32_bfd_relax_section ip2k_elf_relax_section
|
---|
1692 |
|
---|
1693 | #include "elf32-target.h"
|
---|