1214571Sdim/* BFD back-end for National Semiconductor's CR16 ELF
2214571Sdim   Copyright 2007 Free Software Foundation, Inc.
3214571Sdim   Written by M R Swami Reddy.
4214571Sdim
5214571Sdim   This file is part of BFD, the Binary File Descriptor library.
6214571Sdim
7214571Sdim   This program is free software; you can redistribute it and/or modify
8214571Sdim   it under the terms of the GNU General Public License as published by
9214571Sdim   the Free Software Foundation; either version 2 of the License, or
10214571Sdim   (at your option) any later version.
11214571Sdim
12214571Sdim   This program is distributed in the hope that it will be useful,
13214571Sdim   but WITHOUT ANY WARRANTY; without even the implied warranty of
14214571Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15214571Sdim   GNU General Public License for more details.
16214571Sdim
17214571Sdim   You should have received a copy of the GNU General Public License
18214571Sdim   along with this program; if not, write to the Free Software Foundation,
19214571Sdim   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
20214571Sdim
21214571Sdim#include "sysdep.h"
22214571Sdim#include "bfd.h"
23214571Sdim#include "bfdlink.h"
24214571Sdim#include "libbfd.h"
25214571Sdim#include "libiberty.h"
26214571Sdim#include "elf-bfd.h"
27214571Sdim#include "elf/cr16.h"
28214571Sdim
29214571Sdim/* cr16_reloc_map array maps BFD relocation enum into a CRGAS relocation type.  */
30214571Sdim
31214571Sdimstruct cr16_reloc_map
32214571Sdim{
33214571Sdim  bfd_reloc_code_real_type bfd_reloc_enum; /* BFD relocation enum.  */
34214571Sdim  unsigned short cr16_reloc_type;          /* CR16 relocation type.  */
35214571Sdim};
36214571Sdim
37214571Sdimstatic const struct cr16_reloc_map cr16_reloc_map[R_CR16_MAX] =
38214571Sdim{
39214571Sdim  {BFD_RELOC_NONE,           R_CR16_NONE},
40214571Sdim  {BFD_RELOC_CR16_NUM8,      R_CR16_NUM8},
41214571Sdim  {BFD_RELOC_CR16_NUM16,     R_CR16_NUM16},
42214571Sdim  {BFD_RELOC_CR16_NUM32,     R_CR16_NUM32},
43214571Sdim  {BFD_RELOC_CR16_NUM32a,    R_CR16_NUM32a},
44214571Sdim  {BFD_RELOC_CR16_REGREL4,   R_CR16_REGREL4},
45214571Sdim  {BFD_RELOC_CR16_REGREL4a,  R_CR16_REGREL4a},
46214571Sdim  {BFD_RELOC_CR16_REGREL14,  R_CR16_REGREL14},
47214571Sdim  {BFD_RELOC_CR16_REGREL14a, R_CR16_REGREL14a},
48214571Sdim  {BFD_RELOC_CR16_REGREL16,  R_CR16_REGREL16},
49214571Sdim  {BFD_RELOC_CR16_REGREL20,  R_CR16_REGREL20},
50214571Sdim  {BFD_RELOC_CR16_REGREL20a, R_CR16_REGREL20a},
51214571Sdim  {BFD_RELOC_CR16_ABS20,     R_CR16_ABS20},
52214571Sdim  {BFD_RELOC_CR16_ABS24,     R_CR16_ABS24},
53214571Sdim  {BFD_RELOC_CR16_IMM4,      R_CR16_IMM4},
54214571Sdim  {BFD_RELOC_CR16_IMM8,      R_CR16_IMM8},
55214571Sdim  {BFD_RELOC_CR16_IMM16,     R_CR16_IMM16},
56214571Sdim  {BFD_RELOC_CR16_IMM20,     R_CR16_IMM20},
57214571Sdim  {BFD_RELOC_CR16_IMM24,     R_CR16_IMM24},
58214571Sdim  {BFD_RELOC_CR16_IMM32,     R_CR16_IMM32},
59214571Sdim  {BFD_RELOC_CR16_IMM32a,    R_CR16_IMM32a},
60214571Sdim  {BFD_RELOC_CR16_DISP4,     R_CR16_DISP4},
61214571Sdim  {BFD_RELOC_CR16_DISP8,     R_CR16_DISP8},
62214571Sdim  {BFD_RELOC_CR16_DISP16,    R_CR16_DISP16},
63214571Sdim  {BFD_RELOC_CR16_DISP24,    R_CR16_DISP24},
64214571Sdim  {BFD_RELOC_CR16_DISP24a,   R_CR16_DISP24a}
65214571Sdim};
66214571Sdim
67214571Sdimstatic reloc_howto_type cr16_elf_howto_table[] =
68214571Sdim{
69214571Sdim  HOWTO (R_CR16_NONE,              /* type */
70214571Sdim         0,                        /* rightshift */
71214571Sdim         2,                        /* size */
72214571Sdim         32,                       /* bitsize */
73214571Sdim         FALSE,                    /* pc_relative */
74214571Sdim         0,                        /* bitpos */
75214571Sdim         complain_overflow_dont,   /* complain_on_overflow */
76214571Sdim         bfd_elf_generic_reloc,    /* special_function */
77214571Sdim         "R_CR16_NONE",            /* name */
78214571Sdim         FALSE,                    /* partial_inplace */
79214571Sdim         0,                        /* src_mask */
80214571Sdim         0,                        /* dst_mask */
81214571Sdim         FALSE),                   /* pcrel_offset */
82214571Sdim
83214571Sdim  HOWTO (R_CR16_NUM8,              /* type */
84214571Sdim         0,                        /* rightshift */
85214571Sdim         0,                        /* size */
86214571Sdim         8,                        /* bitsize */
87214571Sdim         FALSE,                    /* pc_relative */
88214571Sdim         0,                        /* bitpos */
89214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
90214571Sdim         bfd_elf_generic_reloc,    /* special_function */
91214571Sdim         "R_CR16_NUM8",            /* name */
92214571Sdim         FALSE,                    /* partial_inplace */
93214571Sdim         0xff,                     /* src_mask */
94214571Sdim         0xff,                     /* dst_mask */
95214571Sdim         FALSE),                   /* pcrel_offset */
96214571Sdim
97214571Sdim  HOWTO (R_CR16_NUM16,             /* type */
98214571Sdim         0,                        /* rightshift */
99214571Sdim         1,                        /* size */
100214571Sdim         16,                       /* bitsize */
101214571Sdim         FALSE,                    /* pc_relative */
102214571Sdim         0,                        /* bitpos */
103214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
104214571Sdim         bfd_elf_generic_reloc,    /* special_function */
105214571Sdim         "R_CR16_NUM16",           /* name */
106214571Sdim         FALSE,                    /* partial_inplace */
107214571Sdim         0xffff,                   /* src_mask */
108214571Sdim         0xffff,                   /* dst_mask */
109214571Sdim         FALSE),                   /* pcrel_offset */
110214571Sdim
111214571Sdim  HOWTO (R_CR16_NUM32,             /* type */
112214571Sdim         0,                        /* rightshift */
113214571Sdim         2,                        /* size */
114214571Sdim         32,                       /* bitsize */
115214571Sdim         FALSE,                    /* pc_relative */
116214571Sdim         0,                        /* bitpos */
117214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
118214571Sdim         bfd_elf_generic_reloc,    /* special_function */
119214571Sdim         "R_CR16_NUM32",           /* name */
120214571Sdim         FALSE,                    /* partial_inplace */
121214571Sdim         0xffffffff,               /* src_mask */
122214571Sdim         0xffffffff,               /* dst_mask */
123214571Sdim         FALSE),                   /* pcrel_offset */
124214571Sdim
125214571Sdim  HOWTO (R_CR16_NUM32a,            /* type */
126214571Sdim         1,                        /* rightshift */
127214571Sdim         2,                        /* size */
128214571Sdim         32,                       /* bitsize */
129214571Sdim         FALSE,                    /* pc_relative */
130214571Sdim         0,                        /* bitpos */
131214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
132214571Sdim         bfd_elf_generic_reloc,    /* special_function */
133214571Sdim         "R_CR16_NUM32a",          /* name */
134214571Sdim         FALSE,                    /* partial_inplace */
135214571Sdim         0xffffffff,               /* src_mask */
136214571Sdim         0xffffffff,               /* dst_mask */
137214571Sdim         FALSE),                   /* pcrel_offset */
138214571Sdim
139214571Sdim  HOWTO (R_CR16_REGREL4,           /* type */
140214571Sdim         0,                        /* rightshift */
141214571Sdim         0,                        /* size */
142214571Sdim         4,                        /* bitsize */
143214571Sdim         FALSE,                    /* pc_relative */
144214571Sdim         0,                        /* bitpos */
145214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
146214571Sdim         bfd_elf_generic_reloc,    /* special_function */
147214571Sdim         "R_CR16_REGREL4",         /* name */
148214571Sdim         FALSE,                    /* partial_inplace */
149214571Sdim         0xf,                      /* src_mask */
150214571Sdim         0xf,                      /* dst_mask */
151214571Sdim         FALSE),                   /* pcrel_offset */
152214571Sdim
153214571Sdim  HOWTO (R_CR16_REGREL4a,          /* type */
154214571Sdim         0,                        /* rightshift */
155214571Sdim         0,                        /* size */
156214571Sdim         4,                        /* bitsize */
157214571Sdim         FALSE,                    /* pc_relative */
158214571Sdim         0,                        /* bitpos */
159214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
160214571Sdim         bfd_elf_generic_reloc,    /* special_function */
161214571Sdim         "R_CR16_REGREL4a",        /* name */
162214571Sdim         FALSE,                    /* partial_inplace */
163214571Sdim         0xf,                      /* src_mask */
164214571Sdim         0xf,                      /* dst_mask */
165214571Sdim         FALSE),                   /* pcrel_offset */
166214571Sdim
167214571Sdim  HOWTO (R_CR16_REGREL14,          /* type */
168214571Sdim         0,                        /* rightshift */
169214571Sdim         1,                        /* size */
170214571Sdim         14,                       /* bitsize */
171214571Sdim         FALSE,                    /* pc_relative */
172214571Sdim         0,                        /* bitpos */
173214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
174214571Sdim         bfd_elf_generic_reloc,    /* special_function */
175214571Sdim         "R_CR16_REGREL14",        /* name */
176214571Sdim         FALSE,                    /* partial_inplace */
177214571Sdim         0x3fff,                   /* src_mask */
178214571Sdim         0x3fff,                   /* dst_mask */
179214571Sdim         FALSE),                   /* pcrel_offset */
180214571Sdim
181214571Sdim  HOWTO (R_CR16_REGREL14a,         /* type */
182214571Sdim         0,                        /* rightshift */
183214571Sdim         1,                        /* size */
184214571Sdim         14,                       /* bitsize */
185214571Sdim         FALSE,                    /* pc_relative */
186214571Sdim         0,                        /* bitpos */
187214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
188214571Sdim         bfd_elf_generic_reloc,    /* special_function */
189214571Sdim         "R_CR16_REGREL14a",       /* name */
190214571Sdim         FALSE,                    /* partial_inplace */
191214571Sdim         0x3fff,                   /* src_mask */
192214571Sdim         0x3fff,                   /* dst_mask */
193214571Sdim         FALSE),                   /* pcrel_offset */
194214571Sdim
195214571Sdim  HOWTO (R_CR16_REGREL16,          /* type */
196214571Sdim         0,                        /* rightshift */
197214571Sdim         1,                        /* size */
198214571Sdim         16,                       /* bitsize */
199214571Sdim         FALSE,                    /* pc_relative */
200214571Sdim         0,                        /* bitpos */
201214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
202214571Sdim         bfd_elf_generic_reloc,    /* special_function */
203214571Sdim         "R_CR16_REGREL16",        /* name */
204214571Sdim         FALSE,                    /* partial_inplace */
205214571Sdim         0xffff,                   /* src_mask */
206214571Sdim         0xffff,                   /* dst_mask */
207214571Sdim         FALSE),                   /* pcrel_offset */
208214571Sdim
209214571Sdim  HOWTO (R_CR16_REGREL20,          /* type */
210214571Sdim         0,                        /* rightshift */
211214571Sdim         2,                        /* size */
212214571Sdim         20,                       /* bitsize */
213214571Sdim         FALSE,                    /* pc_relative */
214214571Sdim         0,                        /* bitpos */
215214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
216214571Sdim         bfd_elf_generic_reloc,    /* special_function */
217214571Sdim         "R_CR16_REGREL20",        /* name */
218214571Sdim         FALSE,                    /* partial_inplace */
219214571Sdim         0xfffff,                  /* src_mask */
220214571Sdim         0xfffff,                  /* dst_mask */
221214571Sdim         FALSE),                   /* pcrel_offset */
222214571Sdim
223214571Sdim  HOWTO (R_CR16_REGREL20a,         /* type */
224214571Sdim         0,                        /* rightshift */
225214571Sdim         2,                        /* size */
226214571Sdim         20,                       /* bitsize */
227214571Sdim         FALSE,                    /* pc_relative */
228214571Sdim         0,                        /* bitpos */
229214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
230214571Sdim         bfd_elf_generic_reloc,    /* special_function */
231214571Sdim         "R_CR16_REGREL20a",       /* name */
232214571Sdim         FALSE,                    /* partial_inplace */
233214571Sdim         0xfffff,                  /* src_mask */
234214571Sdim         0xfffff,                  /* dst_mask */
235214571Sdim         FALSE),                   /* pcrel_offset */
236214571Sdim
237214571Sdim  HOWTO (R_CR16_ABS20,             /* type */
238214571Sdim         0,                        /* rightshift */
239214571Sdim         2,                        /* size */
240214571Sdim         20,                       /* bitsize */
241214571Sdim         FALSE,                    /* pc_relative */
242214571Sdim         0,                        /* bitpos */
243214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
244214571Sdim         bfd_elf_generic_reloc,    /* special_function */
245214571Sdim         "R_CR16_ABS20",           /* name */
246214571Sdim         FALSE,                    /* partial_inplace */
247214571Sdim         0xfffff,                  /* src_mask */
248214571Sdim         0xfffff,                  /* dst_mask */
249214571Sdim         FALSE),                   /* pcrel_offset */
250214571Sdim
251214571Sdim  HOWTO (R_CR16_ABS24,             /* type */
252214571Sdim         0,                        /* rightshift */
253214571Sdim         2,                        /* size */
254214571Sdim         24,                       /* bitsize */
255214571Sdim         FALSE,                    /* pc_relative */
256214571Sdim         0,                        /* bitpos */
257214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
258214571Sdim         bfd_elf_generic_reloc,    /* special_function */
259214571Sdim         "R_CR16_ABS24",           /* name */
260214571Sdim         FALSE,                    /* partial_inplace */
261214571Sdim         0xffffff,                 /* src_mask */
262214571Sdim         0xffffff,                 /* dst_mask */
263214571Sdim         FALSE),                   /* pcrel_offset */
264214571Sdim
265214571Sdim  HOWTO (R_CR16_IMM4,              /* type */
266214571Sdim         0,                        /* rightshift */
267214571Sdim         0,                        /* size */
268214571Sdim         4,                        /* bitsize */
269214571Sdim         FALSE,                    /* pc_relative */
270214571Sdim         0,                        /* bitpos */
271214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
272214571Sdim         bfd_elf_generic_reloc,    /* special_function */
273214571Sdim         "R_CR16_IMM4",            /* name */
274214571Sdim         FALSE,                    /* partial_inplace */
275214571Sdim         0xf,                      /* src_mask */
276214571Sdim         0xf,                      /* dst_mask */
277214571Sdim         FALSE),                   /* pcrel_offset */
278214571Sdim
279214571Sdim  HOWTO (R_CR16_IMM8,              /* type */
280214571Sdim         0,                        /* rightshift */
281214571Sdim         0,                        /* size */
282214571Sdim         8,                        /* bitsize */
283214571Sdim         FALSE,                    /* pc_relative */
284214571Sdim         0,                        /* bitpos */
285214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
286214571Sdim         bfd_elf_generic_reloc,    /* special_function */
287214571Sdim         "R_CR16_IMM8",            /* name */
288214571Sdim         FALSE,                    /* partial_inplace */
289214571Sdim         0xff,                     /* src_mask */
290214571Sdim         0xff,                     /* dst_mask */
291214571Sdim         FALSE),                   /* pcrel_offset */
292214571Sdim
293214571Sdim  HOWTO (R_CR16_IMM16,             /* type */
294214571Sdim         0,                        /* rightshift */
295214571Sdim         1,                        /* size */
296214571Sdim         16,                       /* bitsize */
297214571Sdim         FALSE,                    /* pc_relative */
298214571Sdim         0,                        /* bitpos */
299214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
300214571Sdim         bfd_elf_generic_reloc,    /* special_function */
301214571Sdim         "R_CR16_IMM16",           /* name */
302214571Sdim         FALSE,                    /* partial_inplace */
303214571Sdim         0xffff,                   /* src_mask */
304214571Sdim         0xffff,                   /* dst_mask */
305214571Sdim         FALSE),                   /* pcrel_offset */
306214571Sdim
307214571Sdim  HOWTO (R_CR16_IMM20,             /* type */
308214571Sdim         0,                        /* rightshift */
309214571Sdim         2,                        /* size */
310214571Sdim         20,                       /* bitsize */
311214571Sdim         FALSE,                    /* pc_relative */
312214571Sdim         0,                        /* bitpos */
313214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
314214571Sdim         bfd_elf_generic_reloc,    /* special_function */
315214571Sdim         "R_CR16_IMM20",           /* name */
316214571Sdim         FALSE,                    /* partial_inplace */
317214571Sdim         0xfffff,                  /* src_mask */
318214571Sdim         0xfffff,                  /* dst_mask */
319214571Sdim         FALSE),                   /* pcrel_offset */
320214571Sdim
321214571Sdim  HOWTO (R_CR16_IMM24,             /* type */
322214571Sdim         0,                        /* rightshift */
323214571Sdim         2,                        /* size */
324214571Sdim         24,                       /* bitsize */
325214571Sdim         FALSE,                    /* pc_relative */
326214571Sdim         0,                        /* bitpos */
327214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
328214571Sdim         bfd_elf_generic_reloc,    /* special_function */
329214571Sdim         "R_CR16_IMM24",           /* name */
330214571Sdim         FALSE,                    /* partial_inplace */
331214571Sdim         0xffffff,                 /* src_mask */
332214571Sdim         0xffffff,                 /* dst_mask */
333214571Sdim         FALSE),                   /* pcrel_offset */
334214571Sdim
335214571Sdim  HOWTO (R_CR16_IMM32,             /* type */
336214571Sdim         0,                        /* rightshift */
337214571Sdim         2,                        /* size */
338214571Sdim         32,                       /* bitsize */
339214571Sdim         FALSE,                    /* pc_relative */
340214571Sdim         0,                        /* bitpos */
341214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
342214571Sdim         bfd_elf_generic_reloc,    /* special_function */
343214571Sdim         "R_CR16_IMM32",           /* name */
344214571Sdim         FALSE,                    /* partial_inplace */
345214571Sdim         0xffffffff,               /* src_mask */
346214571Sdim         0xffffffff,               /* dst_mask */
347214571Sdim         FALSE),                   /* pcrel_offset */
348214571Sdim
349214571Sdim  HOWTO (R_CR16_IMM32a,            /* type */
350214571Sdim         1,                        /* rightshift */
351214571Sdim         2,                        /* size */
352214571Sdim         32,                       /* bitsize */
353214571Sdim         FALSE,                    /* pc_relative */
354214571Sdim         0,                        /* bitpos */
355214571Sdim         complain_overflow_bitfield,/* complain_on_overflow */
356214571Sdim         bfd_elf_generic_reloc,    /* special_function */
357214571Sdim         "R_CR16_IMM32a",          /* name */
358214571Sdim         FALSE,                    /* partial_inplace */
359214571Sdim         0xffffffff,               /* src_mask */
360214571Sdim         0xffffffff,               /* dst_mask */
361214571Sdim         FALSE),                   /* pcrel_offset */
362214571Sdim
363214571Sdim  HOWTO (R_CR16_DISP4,             /* type */
364214571Sdim         1,                        /* rightshift */
365214571Sdim         0,                        /* size (0 = byte, 1 = short, 2 = long) */
366214571Sdim         4,                        /* bitsize */
367214571Sdim         TRUE,                     /* pc_relative */
368214571Sdim         0,                        /* bitpos */
369214571Sdim         complain_overflow_unsigned, /* complain_on_overflow */
370214571Sdim         bfd_elf_generic_reloc,    /* special_function */
371214571Sdim         "R_CR16_DISP4",           /* name */
372214571Sdim         FALSE,                    /* partial_inplace */
373214571Sdim         0xf,                      /* src_mask */
374214571Sdim         0xf,                      /* dst_mask */
375214571Sdim         FALSE),                   /* pcrel_offset */
376214571Sdim
377214571Sdim  HOWTO (R_CR16_DISP8,             /* type */
378214571Sdim         1,                        /* rightshift */
379214571Sdim         0,                        /* size (0 = byte, 1 = short, 2 = long) */
380214571Sdim         8,                        /* bitsize */
381214571Sdim         TRUE,                     /* pc_relative */
382214571Sdim         0,                        /* bitpos */
383214571Sdim         complain_overflow_unsigned, /* complain_on_overflow */
384214571Sdim         bfd_elf_generic_reloc,    /* special_function */
385214571Sdim         "R_CR16_DISP8",           /* name */
386214571Sdim         FALSE,                    /* partial_inplace */
387214571Sdim         0x1ff,                    /* src_mask */
388214571Sdim         0x1ff,                    /* dst_mask */
389214571Sdim         FALSE),                   /* pcrel_offset */
390214571Sdim
391214571Sdim  HOWTO (R_CR16_DISP16,            /* type */
392214571Sdim         0,                        /* rightshift REVIITS: To sync with WinIDEA*/
393214571Sdim         1,                        /* size (0 = byte, 1 = short, 2 = long) */
394214571Sdim         16,                       /* bitsize */
395214571Sdim         TRUE,                     /* pc_relative */
396214571Sdim         0,                        /* bitpos */
397214571Sdim         complain_overflow_unsigned, /* complain_on_overflow */
398214571Sdim         bfd_elf_generic_reloc,    /* special_function */
399214571Sdim         "R_CR16_DISP16",          /* name */
400214571Sdim         FALSE,                    /* partial_inplace */
401214571Sdim         0x1ffff,                  /* src_mask */
402214571Sdim         0x1ffff,                  /* dst_mask */
403214571Sdim         FALSE),                   /* pcrel_offset */
404214571Sdim  /* REVISIT: DISP24 should be left-shift by 2 as per ISA doc
405214571Sdim     but its not done, to sync with WinIDEA and CR16 4.1 tools */
406214571Sdim  HOWTO (R_CR16_DISP24,            /* type */
407214571Sdim         0,                        /* rightshift */
408214571Sdim         2,                        /* size (0 = byte, 1 = short, 2 = long) */
409214571Sdim         24,                       /* bitsize */
410214571Sdim         TRUE,                     /* pc_relative */
411214571Sdim         0,                        /* bitpos */
412214571Sdim         complain_overflow_unsigned, /* complain_on_overflow */
413214571Sdim         bfd_elf_generic_reloc,    /* special_function */
414214571Sdim         "R_CR16_DISP24",          /* name */
415214571Sdim         FALSE,                    /* partial_inplace */
416214571Sdim         0x1ffffff,                /* src_mask */
417214571Sdim         0x1ffffff,                /* dst_mask */
418214571Sdim         FALSE),                   /* pcrel_offset */
419214571Sdim
420214571Sdim  HOWTO (R_CR16_DISP24a,           /* type */
421214571Sdim         0,                        /* rightshift */
422214571Sdim         2,                        /* size (0 = byte, 1 = short, 2 = long) */
423214571Sdim         24,                       /* bitsize */
424214571Sdim         TRUE,                     /* pc_relative */
425214571Sdim         0,                        /* bitpos */
426214571Sdim         complain_overflow_unsigned, /* complain_on_overflow */
427214571Sdim         bfd_elf_generic_reloc,    /* special_function */
428214571Sdim         "R_CR16_DISP24a",         /* name */
429214571Sdim         FALSE,                    /* partial_inplace */
430214571Sdim         0xffffff,                 /* src_mask */
431214571Sdim         0xffffff,                 /* dst_mask */
432214571Sdim         FALSE)                    /* pcrel_offset */
433214571Sdim};
434214571Sdim
435214571Sdim/* Retrieve a howto ptr using a BFD reloc_code.  */
436214571Sdim
437214571Sdimstatic reloc_howto_type *
438214571Sdimelf_cr16_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
439214571Sdim                            bfd_reloc_code_real_type code)
440214571Sdim{
441214571Sdim  unsigned int i;
442214571Sdim
443214571Sdim  for (i = 0; i < R_CR16_MAX; i++)
444214571Sdim    if (code == cr16_reloc_map[i].bfd_reloc_enum)
445214571Sdim      return &cr16_elf_howto_table[cr16_reloc_map[i].cr16_reloc_type];
446214571Sdim
447214571Sdim  _bfd_error_handler ("Unsupported CR16 relocation type: 0x%x\n", code);
448214571Sdim  return NULL;
449214571Sdim}
450214571Sdim
451214571Sdimstatic reloc_howto_type *
452214571Sdimelf_cr16_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
453214571Sdim                            const char *r_name)
454214571Sdim{
455214571Sdim  unsigned int i;
456214571Sdim
457214571Sdim  for (i = 0; ARRAY_SIZE (cr16_elf_howto_table); i++)
458214571Sdim    if (cr16_elf_howto_table[i].name != NULL
459214571Sdim        && strcasecmp (cr16_elf_howto_table[i].name, r_name) == 0)
460214571Sdim      return cr16_elf_howto_table + i;
461214571Sdim
462214571Sdim  return NULL;
463214571Sdim}
464214571Sdim
465214571Sdim/* Retrieve a howto ptr using an internal relocation entry.  */
466214571Sdim
467214571Sdimstatic void
468214571Sdimelf_cr16_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
469214571Sdim                        Elf_Internal_Rela *dst)
470214571Sdim{
471214571Sdim  unsigned int r_type = ELF32_R_TYPE (dst->r_info);
472214571Sdim
473214571Sdim  BFD_ASSERT (r_type < (unsigned int) R_CR16_MAX);
474214571Sdim  cache_ptr->howto = &cr16_elf_howto_table[r_type];
475214571Sdim}
476214571Sdim
477214571Sdim/* Perform a relocation as part of a final link.  */
478214571Sdim
479214571Sdimstatic bfd_reloc_status_type
480214571Sdimcr16_elf_final_link_relocate (reloc_howto_type *howto,
481214571Sdim			      bfd *input_bfd,
482214571Sdim                              bfd *output_bfd ATTRIBUTE_UNUSED,
483214571Sdim                              asection *input_section,
484214571Sdim			      bfd_byte *contents,
485214571Sdim                              bfd_vma offset,
486214571Sdim			      bfd_vma Rvalue,
487214571Sdim			      bfd_vma addend,
488214571Sdim                              struct bfd_link_info *info ATTRIBUTE_UNUSED,
489214571Sdim                              asection *sec ATTRIBUTE_UNUSED,
490214571Sdim                              int is_local ATTRIBUTE_UNUSED)
491214571Sdim{
492214571Sdim  unsigned short r_type = howto->type;
493214571Sdim  bfd_byte *hit_data = contents + offset;
494214571Sdim  bfd_vma reloc_bits, check, Rvalue1;
495214571Sdim
496214571Sdim  switch (r_type)
497214571Sdim    {
498214571Sdim     case R_CR16_IMM4:
499214571Sdim     case R_CR16_IMM8:
500214571Sdim     case R_CR16_IMM16:
501214571Sdim     case R_CR16_IMM20:
502214571Sdim     case R_CR16_IMM32:
503214571Sdim     case R_CR16_IMM32a:
504214571Sdim     case R_CR16_REGREL4:
505214571Sdim     case R_CR16_REGREL4a:
506214571Sdim     case R_CR16_REGREL14:
507214571Sdim     case R_CR16_REGREL14a:
508214571Sdim     case R_CR16_REGREL16:
509214571Sdim     case R_CR16_REGREL20:
510214571Sdim     case R_CR16_ABS20:
511214571Sdim     case R_CR16_ABS24:
512214571Sdim     case R_CR16_DISP16:
513214571Sdim     case R_CR16_DISP24:
514214571Sdim       /* 'hit_data' is relative to the start of the instruction, not the
515214571Sdim           relocation offset. Advance it to account for the exact offset.  */
516214571Sdim       hit_data += 2;
517214571Sdim       break;
518214571Sdim
519214571Sdim     case R_CR16_NONE:
520214571Sdim       return bfd_reloc_ok;
521214571Sdim       break;
522214571Sdim
523214571Sdim     case R_CR16_DISP4:
524214571Sdim     case R_CR16_DISP8:
525214571Sdim     case R_CR16_DISP24a:
526214571Sdim       /* We only care about the addend, where the difference between
527214571Sdim          expressions is kept.  */
528214571Sdim       if (is_local) Rvalue -= -1;
529214571Sdim
530214571Sdim     default:
531214571Sdim       break;
532214571Sdim    }
533214571Sdim
534214571Sdim  if (howto->pc_relative)
535214571Sdim    {
536214571Sdim      /* Subtract the address of the section containing the location.  */
537214571Sdim      Rvalue -= (input_section->output_section->vma
538214571Sdim                 + input_section->output_offset);
539214571Sdim      /* Subtract the position of the location within the section.  */
540214571Sdim      Rvalue -= offset;
541214571Sdim    }
542214571Sdim
543214571Sdim  /* Add in supplied addend.  */
544214571Sdim  Rvalue += addend;
545214571Sdim
546214571Sdim  /* Complain if the bitfield overflows, whether it is considered
547214571Sdim     as signed or unsigned.  */
548214571Sdim  check = Rvalue >> howto->rightshift;
549214571Sdim
550214571Sdim  /* Assumes two's complement.  This expression avoids
551214571Sdim     overflow if howto->bitsize is the number of bits in
552214571Sdim     bfd_vma.  */
553214571Sdim  reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1;
554214571Sdim
555214571Sdim  if (((bfd_vma) check & ~reloc_bits) != 0
556214571Sdim      && (((bfd_vma) check & ~reloc_bits)
557214571Sdim      != (-(bfd_vma) 1 & ~reloc_bits)))
558214571Sdim    {
559214571Sdim      /* The above right shift is incorrect for a signed
560214571Sdim         value.  See if turning on the upper bits fixes the
561214571Sdim         overflow.  */
562214571Sdim      if (howto->rightshift && (bfd_signed_vma) Rvalue < 0)
563214571Sdim        {
564214571Sdim          check |= ((bfd_vma) - 1
565214571Sdim                    & ~((bfd_vma) - 1
566214571Sdim                     >> howto->rightshift));
567214571Sdim
568214571Sdim          if (((bfd_vma) check & ~reloc_bits)
569214571Sdim              != (-(bfd_vma) 1 & ~reloc_bits))
570214571Sdim             return bfd_reloc_overflow;
571214571Sdim        }
572214571Sdim      else
573214571Sdim        return bfd_reloc_overflow;
574214571Sdim    }
575214571Sdim
576214571Sdim  /* Drop unwanted bits from the value we are relocating to.  */
577214571Sdim  Rvalue >>= (bfd_vma) howto->rightshift;
578214571Sdim
579214571Sdim  /* Apply dst_mask to select only relocatable part of the insn.  */
580214571Sdim  Rvalue &= howto->dst_mask;
581214571Sdim
582214571Sdim  switch (howto->size)
583214571Sdim    {
584214571Sdim      case 0:
585214571Sdim        if ((r_type == R_CR16_IMM4)
586214571Sdim	    || (r_type == R_CR16_DISP4)
587214571Sdim	    || (r_type == R_CR16_DISP8))
588214571Sdim          {
589214571Sdim             Rvalue1 = bfd_get_16 (input_bfd, hit_data);
590214571Sdim             Rvalue = ((Rvalue1 & 0xf000) | ((Rvalue << 4) & 0xf00)
591214571Sdim		       | (Rvalue1 & 0x00f0) | (Rvalue & 0xf));
592214571Sdim             bfd_put_16 (input_bfd,  Rvalue, hit_data);
593214571Sdim          }
594214571Sdim        break;
595214571Sdim
596214571Sdim      case 1:
597214571Sdim        if (r_type == R_CR16_DISP16)
598214571Sdim          {
599214571Sdim            Rvalue |= (bfd_get_16 (input_bfd, hit_data));
600214571Sdim            Rvalue = ((Rvalue & 0xfffe) | ((Rvalue >> 16) & 0x1));
601214571Sdim
602214571Sdim            bfd_put_16 (input_bfd, Rvalue, hit_data);
603214571Sdim          }
604214571Sdim        break;
605214571Sdim
606214571Sdim      case 2:
607214571Sdim        if (r_type == R_CR16_ABS20)
608214571Sdim          {
609214571Sdim            Rvalue |= (((bfd_get_16 (input_bfd, hit_data) << 16)
610214571Sdim			| (bfd_get_16 (input_bfd, hit_data + 2)))
611214571Sdim		       & ~howto->dst_mask);
612214571Sdim            Rvalue |= (bfd_get_16 (input_bfd, hit_data + 2) << 16);
613214571Sdim
614214571Sdim            /* Relocation on INSTRUCTIONS is different : Instructions are
615214571Sdim               word-addressable, that is, each word itself is arranged according
616214571Sdim               to little-endian convention, whereas the words are arranged with
617214571Sdim               respect to one another in BIG ENDIAN fashion.
618214571Sdim               When there is an immediate value that spans a word boundary,
619214571Sdim               it is split in a big-endian way with respect to the words.  */
620214571Sdim            bfd_put_16 (input_bfd, (Rvalue) & 0xffff, hit_data);
621214571Sdim            bfd_put_16 (input_bfd, (Rvalue >> 16)& 0xffff, hit_data + 2);
622214571Sdim          }
623214571Sdim        else if (r_type == R_CR16_ABS24)
624214571Sdim          {
625214571Sdim            Rvalue = ((((Rvalue >> 20)& 0xf)
626214571Sdim		       | (((Rvalue >> 16) & 0xf) << 8)
627214571Sdim		       | (bfd_get_16 (input_bfd, hit_data)))
628214571Sdim		      | ((Rvalue & 0xffff) << 16));
629214571Sdim
630214571Sdim            bfd_put_32 (input_bfd, Rvalue, hit_data);
631214571Sdim          }
632214571Sdim        else if (r_type == R_CR16_DISP24)
633214571Sdim          {
634214571Sdim            Rvalue = ((((Rvalue >> 20)& 0xf) | (((Rvalue >> 16) & 0xf)<<8)
635214571Sdim		       | (bfd_get_16 (input_bfd, hit_data)))
636214571Sdim		      | (((Rvalue & 0xfffE) | ((Rvalue >> 24) & 0x1)) << 16));
637214571Sdim
638214571Sdim            bfd_put_32 (input_bfd, Rvalue, hit_data);
639214571Sdim          }
640214571Sdim        else if ((r_type == R_CR16_IMM32) || (r_type == R_CR16_IMM32a))
641214571Sdim          {
642214571Sdim            Rvalue = (((Rvalue >> 16)& 0xffff)
643214571Sdim		      | (bfd_get_16 (input_bfd, hit_data)))
644214571Sdim	      | ((Rvalue & 0xffff) << 16);
645214571Sdim            bfd_put_32 (input_bfd, Rvalue, hit_data);
646214571Sdim          }
647214571Sdim        else if (r_type == R_CR16_DISP24a)
648214571Sdim          {
649214571Sdim            Rvalue = (((Rvalue & 0xfffffe) | (Rvalue >> 23)));
650214571Sdim            Rvalue = ((Rvalue >> 16) & 0xff) | ((Rvalue & 0xffff) << 16)
651214571Sdim	      | (bfd_get_32 (input_bfd, hit_data));
652214571Sdim
653214571Sdim            bfd_put_32 (input_bfd, Rvalue, hit_data);
654214571Sdim          }
655214571Sdim        else if ((r_type == R_CR16_NUM32) || (r_type == R_CR16_NUM32a))
656214571Sdim          {
657214571Sdim            bfd_put_32 (input_bfd, Rvalue, hit_data);
658214571Sdim          }
659214571Sdim      break;
660214571Sdim
661214571Sdim      default:
662214571Sdim        return bfd_reloc_notsupported;
663214571Sdim    }
664214571Sdim
665214571Sdim  return bfd_reloc_ok;
666214571Sdim}
667214571Sdim
668214571Sdim/* Delete some bytes from a section while relaxing.  */
669214571Sdim
670214571Sdimstatic bfd_boolean
671214571Sdimelf32_cr16_relax_delete_bytes (struct bfd_link_info *link_info, bfd *abfd,
672214571Sdim                               asection *sec, bfd_vma addr, int count)
673214571Sdim{
674214571Sdim  Elf_Internal_Shdr *symtab_hdr;
675214571Sdim  unsigned int sec_shndx;
676214571Sdim  bfd_byte *contents;
677214571Sdim  Elf_Internal_Rela *irel, *irelend;
678214571Sdim  Elf_Internal_Rela *irelalign;
679214571Sdim  bfd_vma toaddr;
680214571Sdim  Elf_Internal_Sym *isym;
681214571Sdim  Elf_Internal_Sym *isymend;
682214571Sdim  struct elf_link_hash_entry **sym_hashes;
683214571Sdim  struct elf_link_hash_entry **end_hashes;
684214571Sdim  struct elf_link_hash_entry **start_hashes;
685214571Sdim  unsigned int symcount;
686214571Sdim
687214571Sdim  sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
688214571Sdim
689214571Sdim  contents = elf_section_data (sec)->this_hdr.contents;
690214571Sdim
691214571Sdim  /* The deletion must stop at the next ALIGN reloc for an aligment
692214571Sdim     power larger than the number of bytes we are deleting.  */
693214571Sdim  irelalign = NULL;
694214571Sdim  toaddr = sec->size;
695214571Sdim
696214571Sdim  irel = elf_section_data (sec)->relocs;
697214571Sdim  irelend = irel + sec->reloc_count;
698214571Sdim
699214571Sdim  /* Actually delete the bytes.  */
700214571Sdim  memmove (contents + addr, contents + addr + count,
701214571Sdim           (size_t) (toaddr - addr - count));
702214571Sdim  sec->size -= count;
703214571Sdim
704214571Sdim  /* Adjust all the relocs.  */
705214571Sdim  for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
706214571Sdim    /* Get the new reloc address.  */
707214571Sdim    if ((irel->r_offset > addr && irel->r_offset < toaddr))
708214571Sdim	irel->r_offset -= count;
709214571Sdim
710214571Sdim  /* Adjust the local symbols defined in this section.  */
711214571Sdim  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
712214571Sdim  isym = (Elf_Internal_Sym *) symtab_hdr->contents;
713214571Sdim  for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
714214571Sdim    {
715214571Sdim      if (isym->st_shndx == sec_shndx
716214571Sdim          && isym->st_value > addr
717214571Sdim          && isym->st_value < toaddr)
718214571Sdim        {
719214571Sdim          /* Adjust the addend of SWITCH relocations in this section,
720214571Sdim             which reference this local symbol.  */
721214571Sdim          for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
722214571Sdim            {
723214571Sdim              unsigned long r_symndx;
724214571Sdim              Elf_Internal_Sym *rsym;
725214571Sdim              bfd_vma addsym, subsym;
726214571Sdim
727214571Sdim              r_symndx = ELF32_R_SYM (irel->r_info);
728214571Sdim              rsym = (Elf_Internal_Sym *) symtab_hdr->contents + r_symndx;
729214571Sdim
730214571Sdim              /* Skip if not the local adjusted symbol.  */
731214571Sdim              if (rsym != isym)
732214571Sdim                continue;
733214571Sdim
734214571Sdim              addsym = isym->st_value;
735214571Sdim              subsym = addsym - irel->r_addend;
736214571Sdim
737214571Sdim              /* Fix the addend only when -->> (addsym > addr >= subsym).  */
738214571Sdim              if (subsym <= addr)
739214571Sdim                irel->r_addend -= count;
740214571Sdim              else
741214571Sdim                continue;
742214571Sdim            }
743214571Sdim
744214571Sdim          isym->st_value -= count;
745214571Sdim        }
746214571Sdim    }
747214571Sdim
748214571Sdim  /* Now adjust the global symbols defined in this section.  */
749214571Sdim  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
750214571Sdim               - symtab_hdr->sh_info);
751214571Sdim  sym_hashes = start_hashes = elf_sym_hashes (abfd);
752214571Sdim  end_hashes = sym_hashes + symcount;
753214571Sdim
754214571Sdim  for (; sym_hashes < end_hashes; sym_hashes++)
755214571Sdim    {
756214571Sdim      struct elf_link_hash_entry *sym_hash = *sym_hashes;
757214571Sdim
758214571Sdim      /* The '--wrap SYMBOL' option is causing a pain when the object file,
759214571Sdim         containing the definition of __wrap_SYMBOL, includes a direct
760214571Sdim         call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference
761214571Sdim         the same symbol (which is __wrap_SYMBOL), but still exist as two
762214571Sdim         different symbols in 'sym_hashes', we don't want to adjust
763214571Sdim         the global symbol __wrap_SYMBOL twice.
764214571Sdim         This check is only relevant when symbols are being wrapped.  */
765214571Sdim      if (link_info->wrap_hash != NULL)
766214571Sdim        {
767214571Sdim          struct elf_link_hash_entry **cur_sym_hashes;
768214571Sdim
769214571Sdim          /* Loop only over the symbols whom been already checked.  */
770214571Sdim          for (cur_sym_hashes = start_hashes; cur_sym_hashes < sym_hashes;
771214571Sdim               cur_sym_hashes++)
772214571Sdim	    /* If the current symbol is identical to 'sym_hash', that means
773214571Sdim	       the symbol was already adjusted (or at least checked).  */
774214571Sdim	    if (*cur_sym_hashes == sym_hash)
775214571Sdim	      break;
776214571Sdim
777214571Sdim          /* Don't adjust the symbol again.  */
778214571Sdim          if (cur_sym_hashes < sym_hashes)
779214571Sdim            continue;
780214571Sdim        }
781214571Sdim
782214571Sdim      if ((sym_hash->root.type == bfd_link_hash_defined
783214571Sdim          || sym_hash->root.type == bfd_link_hash_defweak)
784214571Sdim          && sym_hash->root.u.def.section == sec
785214571Sdim          && sym_hash->root.u.def.value > addr
786214571Sdim          && sym_hash->root.u.def.value < toaddr)
787214571Sdim        sym_hash->root.u.def.value -= count;
788214571Sdim    }
789214571Sdim
790214571Sdim  return TRUE;
791214571Sdim}
792214571Sdim
793214571Sdim/* Relocate a CR16 ELF section.  */
794214571Sdim
795214571Sdimstatic bfd_boolean
796214571Sdimelf32_cr16_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
797214571Sdim                            bfd *input_bfd, asection *input_section,
798214571Sdim                            bfd_byte *contents, Elf_Internal_Rela *relocs,
799214571Sdim                            Elf_Internal_Sym *local_syms,
800214571Sdim                            asection **local_sections)
801214571Sdim{
802214571Sdim  Elf_Internal_Shdr *symtab_hdr;
803214571Sdim  struct elf_link_hash_entry **sym_hashes;
804214571Sdim  Elf_Internal_Rela *rel, *relend;
805214571Sdim
806214571Sdim  if (info->relocatable)
807214571Sdim    return TRUE;
808214571Sdim
809214571Sdim  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
810214571Sdim  sym_hashes = elf_sym_hashes (input_bfd);
811214571Sdim
812214571Sdim  rel = relocs;
813214571Sdim  relend = relocs + input_section->reloc_count;
814214571Sdim  for (; rel < relend; rel++)
815214571Sdim    {
816214571Sdim      int r_type;
817214571Sdim      reloc_howto_type *howto;
818214571Sdim      unsigned long r_symndx;
819214571Sdim      Elf_Internal_Sym *sym;
820214571Sdim      asection *sec;
821214571Sdim      struct elf_link_hash_entry *h;
822214571Sdim      bfd_vma relocation;
823214571Sdim      bfd_reloc_status_type r;
824214571Sdim
825214571Sdim      r_symndx = ELF32_R_SYM (rel->r_info);
826214571Sdim      r_type = ELF32_R_TYPE (rel->r_info);
827214571Sdim      howto = cr16_elf_howto_table + (r_type);
828214571Sdim
829214571Sdim      h = NULL;
830214571Sdim      sym = NULL;
831214571Sdim      sec = NULL;
832214571Sdim      if (r_symndx < symtab_hdr->sh_info)
833214571Sdim        {
834214571Sdim          sym = local_syms + r_symndx;
835214571Sdim          sec = local_sections[r_symndx];
836214571Sdim          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
837214571Sdim        }
838214571Sdim      else
839214571Sdim        {
840214571Sdim          bfd_boolean unresolved_reloc, warned;
841214571Sdim
842214571Sdim          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
843214571Sdim                                   r_symndx, symtab_hdr, sym_hashes,
844214571Sdim                                   h, sec, relocation,
845214571Sdim                                   unresolved_reloc, warned);
846214571Sdim        }
847214571Sdim
848214571Sdim      r = cr16_elf_final_link_relocate (howto, input_bfd, output_bfd,
849214571Sdim                                        input_section,
850214571Sdim                                        contents, rel->r_offset,
851214571Sdim                                        relocation, rel->r_addend,
852214571Sdim                                        info, sec, h == NULL);
853214571Sdim
854214571Sdim      if (r != bfd_reloc_ok)
855214571Sdim        {
856214571Sdim          const char *name;
857214571Sdim          const char *msg = NULL;
858214571Sdim
859214571Sdim          if (h != NULL)
860214571Sdim            name = h->root.root.string;
861214571Sdim          else
862214571Sdim            {
863214571Sdim              name = (bfd_elf_string_from_elf_section
864214571Sdim                      (input_bfd, symtab_hdr->sh_link, sym->st_name));
865214571Sdim              if (name == NULL || *name == '\0')
866214571Sdim                name = bfd_section_name (input_bfd, sec);
867214571Sdim            }
868214571Sdim
869214571Sdim          switch (r)
870214571Sdim            {
871214571Sdim             case bfd_reloc_overflow:
872214571Sdim               if (!((*info->callbacks->reloc_overflow)
873214571Sdim                     (info, (h ? &h->root : NULL), name, howto->name,
874214571Sdim                      (bfd_vma) 0, input_bfd, input_section,
875214571Sdim                      rel->r_offset)))
876214571Sdim                 return FALSE;
877214571Sdim               break;
878214571Sdim
879214571Sdim             case bfd_reloc_undefined:
880214571Sdim               if (!((*info->callbacks->undefined_symbol)
881214571Sdim                     (info, name, input_bfd, input_section,
882214571Sdim                      rel->r_offset, TRUE)))
883214571Sdim                 return FALSE;
884214571Sdim               break;
885214571Sdim
886214571Sdim             case bfd_reloc_outofrange:
887214571Sdim               msg = _("internal error: out of range error");
888214571Sdim               goto common_error;
889214571Sdim
890214571Sdim             case bfd_reloc_notsupported:
891214571Sdim               msg = _("internal error: unsupported relocation error");
892214571Sdim               goto common_error;
893214571Sdim
894214571Sdim             case bfd_reloc_dangerous:
895214571Sdim               msg = _("internal error: dangerous error");
896214571Sdim               goto common_error;
897214571Sdim
898214571Sdim             default:
899214571Sdim               msg = _("internal error: unknown error");
900214571Sdim               /* Fall through.  */
901214571Sdim
902214571Sdim             common_error:
903214571Sdim               if (!((*info->callbacks->warning)
904214571Sdim                     (info, msg, name, input_bfd, input_section,
905214571Sdim                      rel->r_offset)))
906214571Sdim                 return FALSE;
907214571Sdim               break;
908214571Sdim            }
909214571Sdim        }
910214571Sdim    }
911214571Sdim
912214571Sdim  return TRUE;
913214571Sdim}
914214571Sdim
915214571Sdim/* This is a version of bfd_generic_get_relocated_section_contents
916214571Sdim   which uses elf32_cr16_relocate_section.  */
917214571Sdim
918214571Sdimstatic bfd_byte *
919214571Sdimelf32_cr16_get_relocated_section_contents (bfd *output_bfd,
920214571Sdim                                           struct bfd_link_info *link_info,
921214571Sdim                                           struct bfd_link_order *link_order,
922214571Sdim                                           bfd_byte *data,
923214571Sdim                                           bfd_boolean relocatable,
924214571Sdim                                           asymbol **symbols)
925214571Sdim{
926214571Sdim  Elf_Internal_Shdr *symtab_hdr;
927214571Sdim  asection *input_section = link_order->u.indirect.section;
928214571Sdim  bfd *input_bfd = input_section->owner;
929214571Sdim  asection **sections = NULL;
930214571Sdim  Elf_Internal_Rela *internal_relocs = NULL;
931214571Sdim  Elf_Internal_Sym *isymbuf = NULL;
932214571Sdim
933214571Sdim  /* We only need to handle the case of relaxing, or of having a
934214571Sdim     particular set of section contents, specially.  */
935214571Sdim  if (relocatable
936214571Sdim      || elf_section_data (input_section)->this_hdr.contents == NULL)
937214571Sdim    return bfd_generic_get_relocated_section_contents (output_bfd, link_info,
938214571Sdim                                                       link_order, data,
939214571Sdim                                                       relocatable,
940214571Sdim                                                       symbols);
941214571Sdim
942214571Sdim  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
943214571Sdim
944214571Sdim  memcpy (data, elf_section_data (input_section)->this_hdr.contents,
945214571Sdim          (size_t) input_section->size);
946214571Sdim
947214571Sdim  if ((input_section->flags & SEC_RELOC) != 0
948214571Sdim      && input_section->reloc_count > 0)
949214571Sdim    {
950214571Sdim      Elf_Internal_Sym *isym;
951214571Sdim      Elf_Internal_Sym *isymend;
952214571Sdim      asection **secpp;
953214571Sdim      bfd_size_type amt;
954214571Sdim
955214571Sdim      internal_relocs = _bfd_elf_link_read_relocs (input_bfd, input_section,
956214571Sdim						   NULL, NULL, FALSE);
957214571Sdim      if (internal_relocs == NULL)
958214571Sdim        goto error_return;
959214571Sdim
960214571Sdim      if (symtab_hdr->sh_info != 0)
961214571Sdim        {
962214571Sdim          isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
963214571Sdim          if (isymbuf == NULL)
964214571Sdim            isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
965214571Sdim                                            symtab_hdr->sh_info, 0,
966214571Sdim                                            NULL, NULL, NULL);
967214571Sdim          if (isymbuf == NULL)
968214571Sdim            goto error_return;
969214571Sdim        }
970214571Sdim
971214571Sdim      amt = symtab_hdr->sh_info;
972214571Sdim      amt *= sizeof (asection *);
973214571Sdim      sections = bfd_malloc (amt);
974214571Sdim      if (sections == NULL && amt != 0)
975214571Sdim        goto error_return;
976214571Sdim
977214571Sdim      isymend = isymbuf + symtab_hdr->sh_info;
978214571Sdim      for (isym = isymbuf, secpp = sections; isym < isymend; ++isym, ++secpp)
979214571Sdim        {
980214571Sdim          asection *isec;
981214571Sdim
982214571Sdim          if (isym->st_shndx == SHN_UNDEF)
983214571Sdim            isec = bfd_und_section_ptr;
984214571Sdim          else if (isym->st_shndx == SHN_ABS)
985214571Sdim            isec = bfd_abs_section_ptr;
986214571Sdim          else if (isym->st_shndx == SHN_COMMON)
987214571Sdim            isec = bfd_com_section_ptr;
988214571Sdim          else
989214571Sdim            isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx);
990214571Sdim
991214571Sdim          *secpp = isec;
992214571Sdim        }
993214571Sdim
994214571Sdim      if (! elf32_cr16_relocate_section (output_bfd, link_info, input_bfd,
995214571Sdim                                     input_section, data, internal_relocs,
996214571Sdim                                     isymbuf, sections))
997214571Sdim        goto error_return;
998214571Sdim
999214571Sdim      if (sections != NULL)
1000214571Sdim        free (sections);
1001214571Sdim      if (isymbuf != NULL
1002214571Sdim          && symtab_hdr->contents != (unsigned char *) isymbuf)
1003214571Sdim        free (isymbuf);
1004214571Sdim      if (elf_section_data (input_section)->relocs != internal_relocs)
1005214571Sdim        free (internal_relocs);
1006214571Sdim    }
1007214571Sdim
1008214571Sdim  return data;
1009214571Sdim
1010214571Sdim error_return:
1011214571Sdim  if (sections != NULL)
1012214571Sdim    free (sections);
1013214571Sdim  if (isymbuf != NULL
1014214571Sdim      && symtab_hdr->contents != (unsigned char *) isymbuf)
1015214571Sdim    free (isymbuf);
1016214571Sdim  if (internal_relocs != NULL
1017214571Sdim      && elf_section_data (input_section)->relocs != internal_relocs)
1018214571Sdim    free (internal_relocs);
1019214571Sdim  return NULL;
1020214571Sdim}
1021214571Sdim
1022214571Sdim/* This function handles relaxing for the CR16.
1023214571Sdim
1024214571Sdim   There's quite a few relaxing opportunites available on the CR16:
1025214571Sdim
1026214571Sdim        * bcond:24 -> bcond:16                                2 bytes
1027214571Sdim        * bcond:16 -> bcond:8                                2 bytes
1028214571Sdim        * arithmetic imm32 -> arithmetic imm16                2 bytes
1029214571Sdim
1030214571Sdim   Symbol- and reloc-reading infrastructure copied from elf-m10200.c.  */
1031214571Sdim
1032214571Sdimstatic bfd_boolean
1033214571Sdimelf32_cr16_relax_section (bfd *abfd, asection *sec,
1034214571Sdim                         struct bfd_link_info *link_info, bfd_boolean *again)
1035214571Sdim{
1036214571Sdim  Elf_Internal_Shdr *symtab_hdr;
1037214571Sdim  Elf_Internal_Rela *internal_relocs;
1038214571Sdim  Elf_Internal_Rela *irel, *irelend;
1039214571Sdim  bfd_byte *contents = NULL;
1040214571Sdim  Elf_Internal_Sym *isymbuf = NULL;
1041214571Sdim
1042214571Sdim  /* Assume nothing changes.  */
1043214571Sdim  *again = FALSE;
1044214571Sdim
1045214571Sdim  /* We don't have to do anything for a relocatable link, if
1046214571Sdim     this section does not have relocs, or if this is not a
1047214571Sdim     code section.  */
1048214571Sdim  if (link_info->relocatable
1049214571Sdim      || (sec->flags & SEC_RELOC) == 0
1050214571Sdim      || sec->reloc_count == 0
1051214571Sdim      || (sec->flags & SEC_CODE) == 0)
1052214571Sdim    return TRUE;
1053214571Sdim
1054214571Sdim  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
1055214571Sdim
1056214571Sdim  /* Get a copy of the native relocations.  */
1057214571Sdim  internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
1058214571Sdim					       link_info->keep_memory);
1059214571Sdim  if (internal_relocs == NULL)
1060214571Sdim    goto error_return;
1061214571Sdim
1062214571Sdim  /* Walk through them looking for relaxing opportunities.  */
1063214571Sdim  irelend = internal_relocs + sec->reloc_count;
1064214571Sdim  for (irel = internal_relocs; irel < irelend; irel++)
1065214571Sdim    {
1066214571Sdim      bfd_vma symval;
1067214571Sdim
1068214571Sdim      /* If this isn't something that can be relaxed, then ignore
1069214571Sdim         this reloc.  */
1070214571Sdim      if (ELF32_R_TYPE (irel->r_info) != (int) R_CR16_DISP16
1071214571Sdim          && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_DISP24)
1072214571Sdim        continue;
1073214571Sdim
1074214571Sdim      /* Get the section contents if we haven't done so already.  */
1075214571Sdim      if (contents == NULL)
1076214571Sdim        {
1077214571Sdim          /* Get cached copy if it exists.  */
1078214571Sdim          if (elf_section_data (sec)->this_hdr.contents != NULL)
1079214571Sdim            contents = elf_section_data (sec)->this_hdr.contents;
1080214571Sdim          /* Go get them off disk.  */
1081214571Sdim          else if (!bfd_malloc_and_get_section (abfd, sec, &contents))
1082214571Sdim            goto error_return;
1083214571Sdim        }
1084214571Sdim
1085214571Sdim      /* Read this BFD's local symbols if we haven't done so already.  */
1086214571Sdim      if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1087214571Sdim        {
1088214571Sdim          isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1089214571Sdim          if (isymbuf == NULL)
1090214571Sdim            isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1091214571Sdim                                            symtab_hdr->sh_info, 0,
1092214571Sdim                                            NULL, NULL, NULL);
1093214571Sdim          if (isymbuf == NULL)
1094214571Sdim            goto error_return;
1095214571Sdim        }
1096214571Sdim
1097214571Sdim      /* Get the value of the symbol referred to by the reloc.  */
1098214571Sdim      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
1099214571Sdim        {
1100214571Sdim          /* A local symbol.  */
1101214571Sdim          Elf_Internal_Sym *isym;
1102214571Sdim          asection *sym_sec;
1103214571Sdim
1104214571Sdim          isym = isymbuf + ELF32_R_SYM (irel->r_info);
1105214571Sdim          if (isym->st_shndx == SHN_UNDEF)
1106214571Sdim            sym_sec = bfd_und_section_ptr;
1107214571Sdim          else if (isym->st_shndx == SHN_ABS)
1108214571Sdim            sym_sec = bfd_abs_section_ptr;
1109214571Sdim          else if (isym->st_shndx == SHN_COMMON)
1110214571Sdim            sym_sec = bfd_com_section_ptr;
1111214571Sdim          else
1112214571Sdim            sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1113214571Sdim          symval = (isym->st_value
1114214571Sdim                    + sym_sec->output_section->vma
1115214571Sdim                    + sym_sec->output_offset);
1116214571Sdim        }
1117214571Sdim      else
1118214571Sdim        {
1119214571Sdim          unsigned long indx;
1120214571Sdim          struct elf_link_hash_entry *h;
1121214571Sdim
1122214571Sdim          /* An external symbol.  */
1123214571Sdim          indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
1124214571Sdim          h = elf_sym_hashes (abfd)[indx];
1125214571Sdim          BFD_ASSERT (h != NULL);
1126214571Sdim
1127214571Sdim          if (h->root.type != bfd_link_hash_defined
1128214571Sdim              && h->root.type != bfd_link_hash_defweak)
1129214571Sdim            /* This appears to be a reference to an undefined
1130214571Sdim               symbol.  Just ignore it--it will be caught by the
1131214571Sdim               regular reloc processing.  */
1132214571Sdim            continue;
1133214571Sdim
1134214571Sdim          symval = (h->root.u.def.value
1135214571Sdim                    + h->root.u.def.section->output_section->vma
1136214571Sdim                    + h->root.u.def.section->output_offset);
1137214571Sdim        }
1138214571Sdim
1139214571Sdim      /* For simplicity of coding, we are going to modify the section
1140214571Sdim         contents, the section relocs, and the BFD symbol table.  We
1141214571Sdim         must tell the rest of the code not to free up this
1142214571Sdim         information.  It would be possible to instead create a table
1143214571Sdim         of changes which have to be made, as is done in coff-mips.c;
1144214571Sdim         that would be more work, but would require less memory when
1145214571Sdim         the linker is run.  */
1146214571Sdim
1147214571Sdim      /* Try to turn a 24  branch/call into a 16bit relative
1148214571Sdim       * branch/call.  */
1149214571Sdim      if (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_DISP24)
1150214571Sdim        {
1151214571Sdim          bfd_vma value = symval;
1152214571Sdim
1153214571Sdim          /* Deal with pc-relative gunk.  */
1154214571Sdim          value -= (sec->output_section->vma + sec->output_offset);
1155214571Sdim          value -= irel->r_offset;
1156214571Sdim          value += irel->r_addend;
1157214571Sdim
1158214571Sdim          /* See if the value will fit in 16 bits, note the high value is
1159214571Sdim             0xfffe + 2 as the target will be two bytes closer if we are
1160214571Sdim             able to relax.  */
1161214571Sdim          if ((long) value < 0x10000 && (long) value > -0x10002)
1162214571Sdim            {
1163214571Sdim              unsigned int code;
1164214571Sdim
1165214571Sdim              /* Get the opcode.  */
1166214571Sdim              code = (unsigned int) bfd_get_32 (abfd, contents + irel->r_offset);
1167214571Sdim
1168214571Sdim              /* Verify it's a 'bcond' and fix the opcode.  */
1169214571Sdim              if ((code  & 0xffff) == 0x0010)
1170214571Sdim                {
1171214571Sdim                bfd_put_16 (abfd, 0x1800 | ((0xf & (code >>20))<<4), contents + irel->r_offset);
1172214571Sdim                bfd_put_16 (abfd, value, contents + irel->r_offset+2);
1173214571Sdim                }
1174214571Sdim              else
1175214571Sdim                continue;
1176214571Sdim
1177214571Sdim              /* Note that we've changed the relocs, section contents, etc.  */
1178214571Sdim              elf_section_data (sec)->relocs = internal_relocs;
1179214571Sdim              elf_section_data (sec)->this_hdr.contents = contents;
1180214571Sdim              symtab_hdr->contents = (unsigned char *) isymbuf;
1181214571Sdim
1182214571Sdim              /* Fix the relocation's type.  */
1183214571Sdim              irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1184214571Sdim                                           R_CR16_DISP16);
1185214571Sdim
1186214571Sdim              /* Delete two bytes of data.  */
1187214571Sdim              if (!elf32_cr16_relax_delete_bytes (link_info, abfd, sec,
1188214571Sdim                                                   irel->r_offset + 2, 2))
1189214571Sdim                goto error_return;
1190214571Sdim
1191214571Sdim              /* That will change things, so, we should relax again.
1192214571Sdim                 Note that this is not required, and it may be slow.  */
1193214571Sdim              *again = TRUE;
1194214571Sdim            }
1195214571Sdim        }
1196214571Sdim
1197214571Sdim      /* Try to turn a 16bit pc-relative branch into an
1198214571Sdim         8bit pc-relative branch.  */
1199214571Sdim      if (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_DISP16)
1200214571Sdim        {
1201214571Sdim          bfd_vma value = symval;
1202214571Sdim
1203214571Sdim          /* Deal with pc-relative gunk.  */
1204214571Sdim          value -= (sec->output_section->vma + sec->output_offset);
1205214571Sdim          value -= irel->r_offset;
1206214571Sdim          value += irel->r_addend;
1207214571Sdim
1208214571Sdim          /* See if the value will fit in 8 bits, note the high value is
1209214571Sdim             0xfc + 2 as the target will be two bytes closer if we are
1210214571Sdim             able to relax.  */
1211214571Sdim          if ((long) value < 0xfe && (long) value > -0x100)
1212214571Sdim            {
1213214571Sdim              unsigned short code;
1214214571Sdim
1215214571Sdim              /* Get the opcode.  */
1216214571Sdim              code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset);
1217214571Sdim
1218214571Sdim              /* Verify it's a 'bcond' opcode.  */
1219214571Sdim              if ((code & 0xff00) == 0x1800)
1220214571Sdim                {
1221214571Sdim                 bfd_put_8 (abfd, 0x1 | ((0xf & (code>>4))<<4), contents + irel->r_offset);
1222214571Sdim                 bfd_put_8 (abfd, value, contents + irel->r_offset+2);
1223214571Sdim                }
1224214571Sdim              else
1225214571Sdim                continue;
1226214571Sdim
1227214571Sdim              /* Note that we've changed the relocs, section contents, etc.  */
1228214571Sdim              elf_section_data (sec)->relocs = internal_relocs;
1229214571Sdim              elf_section_data (sec)->this_hdr.contents = contents;
1230214571Sdim              symtab_hdr->contents = (unsigned char *) isymbuf;
1231214571Sdim
1232214571Sdim              /* Fix the relocation's type.  */
1233214571Sdim              irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1234214571Sdim                                           R_CR16_DISP8);
1235214571Sdim
1236214571Sdim              /* Delete two bytes of data.  */
1237214571Sdim              if (!elf32_cr16_relax_delete_bytes (link_info, abfd, sec,
1238214571Sdim                                                   irel->r_offset + 2, 2))
1239214571Sdim                goto error_return;
1240214571Sdim
1241214571Sdim              /* That will change things, so, we should relax again.
1242214571Sdim                 Note that this is not required, and it may be slow.  */
1243214571Sdim              *again = TRUE;
1244214571Sdim            }
1245214571Sdim        }
1246214571Sdim
1247214571Sdim#if 0 // REVISIT: To support IMM relaxation in CR16 target
1248214571Sdim      /* Try to turn a 32bit immediate address into
1249214571Sdim         a 20bit immediate address.  */
1250214571Sdim      if (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM32)
1251214571Sdim        {
1252214571Sdim          bfd_vma value = symval;
1253214571Sdim
1254214571Sdim          /* See if the value will fit in 20 bits.  */
1255214571Sdim          if ((long) value < 0x7ffff && (long) value > -0x80000)
1256214571Sdim            {
1257214571Sdim              unsigned short code;
1258214571Sdim
1259214571Sdim              /* Get the opcode.  */
1260214571Sdim              code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset);
1261214571Sdim
1262214571Sdim              /* Verify it's a 'arithmetic double'.  */
1263214571Sdim              if ((code & 0xfff0) != 0x0070)
1264214571Sdim                continue;
1265214571Sdim
1266214571Sdim              /* Note that we've changed the relocs, section contents, etc.  */
1267214571Sdim              elf_section_data (sec)->relocs = internal_relocs;
1268214571Sdim              elf_section_data (sec)->this_hdr.contents = contents;
1269214571Sdim              symtab_hdr->contents = (unsigned char *) isymbuf;
1270214571Sdim
1271214571Sdim              /* Fix the opcode.  */
1272214571Sdim              bfd_put_8 (abfd, (code & 0xff) - 0x10, contents + irel->r_offset);
1273214571Sdim
1274214571Sdim              /* Fix the relocation's type.  */
1275214571Sdim              irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1276214571Sdim                                           R_CR16_IMM20);
1277214571Sdim
1278214571Sdim              /* Delete two bytes of data.  */
1279214571Sdim              if (!elf32_cr16_relax_delete_bytes (link_info, abfd, sec,
1280214571Sdim                                                   irel->r_offset + 2, 2))
1281214571Sdim                goto error_return;
1282214571Sdim
1283214571Sdim              /* That will change things, so, we should relax again.
1284214571Sdim                 Note that this is not required, and it may be slow.  */
1285214571Sdim              *again = TRUE;
1286214571Sdim            }
1287214571Sdim        }
1288214571Sdim      /* Try to turn a 20bit/16bit immediate address into
1289214571Sdim         a 4bit immediate address.  */
1290214571Sdim      if ((ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM20)
1291214571Sdim	  || (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM16))
1292214571Sdim        {
1293214571Sdim          bfd_vma value = symval;
1294214571Sdim
1295214571Sdim          /* See if the value will fit in 4 bits.  */
1296214571Sdim          if ((long) value < 0x7 && (long) value > -0x8)
1297214571Sdim            {
1298214571Sdim              unsigned short code;
1299214571Sdim
1300214571Sdim              /* Get the opcode.  */
1301214571Sdim              code = (unsigned short) bfd_get_8 (abfd, contents + irel->r_offset);
1302214571Sdim
1303214571Sdim              /* Verify it's a 'arithmetic double'.  */
1304214571Sdim              if (((code & 0xff) != 0x50) || ((code & 0xff) != 0x45))
1305214571Sdim                continue;
1306214571Sdim
1307214571Sdim              /* Note that we've changed the relocs, section contents, etc.  */
1308214571Sdim              elf_section_data (sec)->relocs = internal_relocs;
1309214571Sdim              elf_section_data (sec)->this_hdr.contents = contents;
1310214571Sdim              symtab_hdr->contents = (unsigned char *) isymbuf;
1311214571Sdim
1312214571Sdim              /* Fix the opcode.  */
1313214571Sdim              bfd_put_8 (abfd, (code & 0xff) - 0x10, contents + irel->r_offset);
1314214571Sdim
1315214571Sdim              /* Fix the relocation's type.  */
1316214571Sdim              irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1317214571Sdim                                           R_CR16_IMM4);
1318214571Sdim
1319214571Sdim              /* Delete two bytes of data.  */
1320214571Sdim              if (!elf32_cr16_relax_delete_bytes (link_info, abfd, sec,
1321214571Sdim                                                   irel->r_offset + 2, 2))
1322214571Sdim                goto error_return;
1323214571Sdim
1324214571Sdim              /* That will change things, so, we should relax again.
1325214571Sdim                 Note that this is not required, and it may be slow.  */
1326214571Sdim              *again = TRUE;
1327214571Sdim            }
1328214571Sdim        }
1329214571Sdim#endif
1330214571Sdim    }
1331214571Sdim
1332214571Sdim  if (isymbuf != NULL
1333214571Sdim      && symtab_hdr->contents != (unsigned char *) isymbuf)
1334214571Sdim    {
1335214571Sdim      if (! link_info->keep_memory)
1336214571Sdim        free (isymbuf);
1337214571Sdim      else
1338214571Sdim        {
1339214571Sdim          /* Cache the symbols for elf_link_input_bfd.  */
1340214571Sdim          symtab_hdr->contents = (unsigned char *) isymbuf;
1341214571Sdim        }
1342214571Sdim    }
1343214571Sdim
1344214571Sdim  if (contents != NULL
1345214571Sdim      && elf_section_data (sec)->this_hdr.contents != contents)
1346214571Sdim    {
1347214571Sdim      if (! link_info->keep_memory)
1348214571Sdim        free (contents);
1349214571Sdim      else
1350214571Sdim        {
1351214571Sdim          /* Cache the section contents for elf_link_input_bfd.  */
1352214571Sdim          elf_section_data (sec)->this_hdr.contents = contents;
1353214571Sdim        }
1354214571Sdim    }
1355214571Sdim
1356214571Sdim  if (internal_relocs != NULL
1357214571Sdim      && elf_section_data (sec)->relocs != internal_relocs)
1358214571Sdim    free (internal_relocs);
1359214571Sdim
1360214571Sdim  return TRUE;
1361214571Sdim
1362214571Sdim error_return:
1363214571Sdim  if (isymbuf != NULL
1364214571Sdim      && symtab_hdr->contents != (unsigned char *) isymbuf)
1365214571Sdim    free (isymbuf);
1366214571Sdim  if (contents != NULL
1367214571Sdim      && elf_section_data (sec)->this_hdr.contents != contents)
1368214571Sdim    free (contents);
1369214571Sdim  if (internal_relocs != NULL
1370214571Sdim      && elf_section_data (sec)->relocs != internal_relocs)
1371214571Sdim    free (internal_relocs);
1372214571Sdim
1373214571Sdim  return FALSE;
1374214571Sdim}
1375214571Sdim
1376214571Sdimstatic asection *
1377214571Sdimelf32_cr16_gc_mark_hook (asection *sec,
1378214571Sdim                        struct bfd_link_info *info ATTRIBUTE_UNUSED,
1379214571Sdim                        Elf_Internal_Rela *rel ATTRIBUTE_UNUSED,
1380214571Sdim                        struct elf_link_hash_entry *h,
1381214571Sdim                        Elf_Internal_Sym *sym)
1382214571Sdim{
1383214571Sdim  if (h == NULL)
1384214571Sdim    return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
1385214571Sdim
1386214571Sdim  switch (h->root.type)
1387214571Sdim    {
1388214571Sdim      case bfd_link_hash_defined:
1389214571Sdim      case bfd_link_hash_defweak:
1390214571Sdim        return h->root.u.def.section;
1391214571Sdim
1392214571Sdim      case bfd_link_hash_common:
1393214571Sdim        return h->root.u.c.p->section;
1394214571Sdim
1395214571Sdim      default:
1396214571Sdim        return NULL;
1397214571Sdim    }
1398214571Sdim}
1399214571Sdim
1400214571Sdim/* Update the got entry reference counts for the section being removed.  */
1401214571Sdim
1402214571Sdimstatic bfd_boolean
1403214571Sdimelf32_cr16_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED,
1404214571Sdim                         struct bfd_link_info *info ATTRIBUTE_UNUSED,
1405214571Sdim                         asection *sec ATTRIBUTE_UNUSED,
1406214571Sdim                         const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED)
1407214571Sdim{
1408214571Sdim  /* We don't support garbage collection of GOT and PLT relocs yet.  */
1409214571Sdim  return TRUE;
1410214571Sdim}
1411214571Sdim
1412214571Sdim/* Definitions for setting CR16 target vector.  */
1413214571Sdim#define TARGET_LITTLE_SYM                 bfd_elf32_cr16_vec
1414214571Sdim#define TARGET_LITTLE_NAME                "elf32-cr16"
1415214571Sdim#define ELF_ARCH                          bfd_arch_cr16
1416214571Sdim#define ELF_MACHINE_CODE                  EM_CR16
1417214571Sdim#define ELF_MAXPAGESIZE                   0x1
1418214571Sdim#define elf_symbol_leading_char           '_'
1419214571Sdim
1420214571Sdim#define bfd_elf32_bfd_reloc_type_lookup   elf_cr16_reloc_type_lookup
1421214571Sdim#define bfd_elf32_bfd_reloc_name_lookup   elf_cr16_reloc_name_lookup
1422214571Sdim#define elf_info_to_howto                 elf_cr16_info_to_howto
1423214571Sdim#define elf_info_to_howto_rel             0
1424214571Sdim#define elf_backend_relocate_section      elf32_cr16_relocate_section
1425214571Sdim#define bfd_elf32_bfd_relax_section       elf32_cr16_relax_section
1426214571Sdim#define bfd_elf32_bfd_get_relocated_section_contents \
1427214571Sdim                                elf32_cr16_get_relocated_section_contents
1428214571Sdim#define elf_backend_gc_mark_hook          elf32_cr16_gc_mark_hook
1429214571Sdim#define elf_backend_gc_sweep_hook         elf32_cr16_gc_sweep_hook
1430214571Sdim#define elf_backend_can_gc_sections       1
1431214571Sdim#define elf_backend_rela_normal           1
1432214571Sdim
1433214571Sdim#include "elf32-target.h"
1434