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