xref: /openbsd-src/gnu/usr.bin/binutils-2.17/bfd/elf32-ip2k.c (revision 3d8817e467ea46cf4772788d6804dd293abfb01a)
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