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