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