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