xref: /openbsd-src/gnu/usr.bin/binutils-2.17/bfd/elf32-avr.c (revision 3d8817e467ea46cf4772788d6804dd293abfb01a)
1*3d8817e4Smiod /* AVR-specific support for 32-bit ELF
2*3d8817e4Smiod    Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2006
3*3d8817e4Smiod    Free Software Foundation, Inc.
4*3d8817e4Smiod    Contributed by Denis Chertykov <denisc@overta.ru>
5*3d8817e4Smiod 
6*3d8817e4Smiod    This file is part of BFD, the Binary File Descriptor library.
7*3d8817e4Smiod 
8*3d8817e4Smiod    This program is free software; you can redistribute it and/or modify
9*3d8817e4Smiod    it under the terms of the GNU General Public License as published by
10*3d8817e4Smiod    the Free Software Foundation; either version 2 of the License, or
11*3d8817e4Smiod    (at your option) any later version.
12*3d8817e4Smiod 
13*3d8817e4Smiod    This program is distributed in the hope that it will be useful,
14*3d8817e4Smiod    but WITHOUT ANY WARRANTY; without even the implied warranty of
15*3d8817e4Smiod    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*3d8817e4Smiod    GNU General Public License for more details.
17*3d8817e4Smiod 
18*3d8817e4Smiod    You should have received a copy of the GNU General Public License
19*3d8817e4Smiod    along with this program; if not, write to the Free Software
20*3d8817e4Smiod    Foundation, Inc., 51 Franklin Street - Fifth Floor,
21*3d8817e4Smiod    Boston, MA 02110-1301, USA.  */
22*3d8817e4Smiod 
23*3d8817e4Smiod #include "bfd.h"
24*3d8817e4Smiod #include "sysdep.h"
25*3d8817e4Smiod #include "libbfd.h"
26*3d8817e4Smiod #include "elf-bfd.h"
27*3d8817e4Smiod #include "elf/avr.h"
28*3d8817e4Smiod 
29*3d8817e4Smiod static reloc_howto_type elf_avr_howto_table[] =
30*3d8817e4Smiod {
31*3d8817e4Smiod   HOWTO (R_AVR_NONE,		/* type */
32*3d8817e4Smiod 	 0,			/* rightshift */
33*3d8817e4Smiod 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
34*3d8817e4Smiod 	 32,			/* bitsize */
35*3d8817e4Smiod 	 FALSE,			/* pc_relative */
36*3d8817e4Smiod 	 0,			/* bitpos */
37*3d8817e4Smiod 	 complain_overflow_bitfield, /* complain_on_overflow */
38*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
39*3d8817e4Smiod 	 "R_AVR_NONE",		/* name */
40*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
41*3d8817e4Smiod 	 0,			/* src_mask */
42*3d8817e4Smiod 	 0,			/* dst_mask */
43*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
44*3d8817e4Smiod 
45*3d8817e4Smiod   HOWTO (R_AVR_32,		/* type */
46*3d8817e4Smiod 	 0,			/* rightshift */
47*3d8817e4Smiod 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
48*3d8817e4Smiod 	 32,			/* bitsize */
49*3d8817e4Smiod 	 FALSE,			/* pc_relative */
50*3d8817e4Smiod 	 0,			/* bitpos */
51*3d8817e4Smiod 	 complain_overflow_bitfield, /* complain_on_overflow */
52*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
53*3d8817e4Smiod 	 "R_AVR_32",		/* name */
54*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
55*3d8817e4Smiod 	 0xffffffff,		/* src_mask */
56*3d8817e4Smiod 	 0xffffffff,		/* dst_mask */
57*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
58*3d8817e4Smiod 
59*3d8817e4Smiod   /* A 7 bit PC relative relocation.  */
60*3d8817e4Smiod   HOWTO (R_AVR_7_PCREL,		/* type */
61*3d8817e4Smiod 	 1,			/* rightshift */
62*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
63*3d8817e4Smiod 	 7,			/* bitsize */
64*3d8817e4Smiod 	 TRUE,			/* pc_relative */
65*3d8817e4Smiod 	 3,			/* bitpos */
66*3d8817e4Smiod 	 complain_overflow_bitfield, /* complain_on_overflow */
67*3d8817e4Smiod 	 bfd_elf_generic_reloc, /* special_function */
68*3d8817e4Smiod 	 "R_AVR_7_PCREL",	/* name */
69*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
70*3d8817e4Smiod 	 0xffff,		/* src_mask */
71*3d8817e4Smiod 	 0xffff,		/* dst_mask */
72*3d8817e4Smiod 	 TRUE),			/* pcrel_offset */
73*3d8817e4Smiod 
74*3d8817e4Smiod   /* A 13 bit PC relative relocation.  */
75*3d8817e4Smiod   HOWTO (R_AVR_13_PCREL,	/* type */
76*3d8817e4Smiod 	 1,			/* rightshift */
77*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
78*3d8817e4Smiod 	 13,			/* bitsize */
79*3d8817e4Smiod 	 TRUE,			/* pc_relative */
80*3d8817e4Smiod 	 0,			/* bitpos */
81*3d8817e4Smiod 	 complain_overflow_bitfield, /* complain_on_overflow */
82*3d8817e4Smiod 	 bfd_elf_generic_reloc, /* special_function */
83*3d8817e4Smiod 	 "R_AVR_13_PCREL",	/* name */
84*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
85*3d8817e4Smiod 	 0xfff,			/* src_mask */
86*3d8817e4Smiod 	 0xfff,			/* dst_mask */
87*3d8817e4Smiod 	 TRUE),			/* pcrel_offset */
88*3d8817e4Smiod 
89*3d8817e4Smiod   /* A 16 bit absolute relocation.  */
90*3d8817e4Smiod   HOWTO (R_AVR_16,		/* type */
91*3d8817e4Smiod 	 0,			/* rightshift */
92*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
93*3d8817e4Smiod 	 16,			/* bitsize */
94*3d8817e4Smiod 	 FALSE,			/* pc_relative */
95*3d8817e4Smiod 	 0,			/* bitpos */
96*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
97*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
98*3d8817e4Smiod 	 "R_AVR_16",		/* name */
99*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
100*3d8817e4Smiod 	 0xffff,		/* src_mask */
101*3d8817e4Smiod 	 0xffff,		/* dst_mask */
102*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
103*3d8817e4Smiod 
104*3d8817e4Smiod   /* A 16 bit absolute relocation for command address.  */
105*3d8817e4Smiod   HOWTO (R_AVR_16_PM,		/* type */
106*3d8817e4Smiod 	 1,			/* rightshift */
107*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
108*3d8817e4Smiod 	 16,			/* bitsize */
109*3d8817e4Smiod 	 FALSE,			/* pc_relative */
110*3d8817e4Smiod 	 0,			/* bitpos */
111*3d8817e4Smiod 	 complain_overflow_bitfield, /* complain_on_overflow */
112*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
113*3d8817e4Smiod 	 "R_AVR_16_PM",		/* name */
114*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
115*3d8817e4Smiod 	 0xffff,		/* src_mask */
116*3d8817e4Smiod 	 0xffff,		/* dst_mask */
117*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
118*3d8817e4Smiod   /* A low 8 bit absolute relocation of 16 bit address.
119*3d8817e4Smiod      For LDI command.  */
120*3d8817e4Smiod   HOWTO (R_AVR_LO8_LDI,		/* type */
121*3d8817e4Smiod 	 0,			/* rightshift */
122*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
123*3d8817e4Smiod 	 8,			/* bitsize */
124*3d8817e4Smiod 	 FALSE,			/* pc_relative */
125*3d8817e4Smiod 	 0,			/* bitpos */
126*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
127*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
128*3d8817e4Smiod 	 "R_AVR_LO8_LDI",	/* name */
129*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
130*3d8817e4Smiod 	 0xffff,		/* src_mask */
131*3d8817e4Smiod 	 0xffff,		/* dst_mask */
132*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
133*3d8817e4Smiod   /* A high 8 bit absolute relocation of 16 bit address.
134*3d8817e4Smiod      For LDI command.  */
135*3d8817e4Smiod   HOWTO (R_AVR_HI8_LDI,		/* type */
136*3d8817e4Smiod 	 8,			/* rightshift */
137*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
138*3d8817e4Smiod 	 8,			/* bitsize */
139*3d8817e4Smiod 	 FALSE,			/* pc_relative */
140*3d8817e4Smiod 	 0,			/* bitpos */
141*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
142*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
143*3d8817e4Smiod 	 "R_AVR_HI8_LDI",	/* name */
144*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
145*3d8817e4Smiod 	 0xffff,		/* src_mask */
146*3d8817e4Smiod 	 0xffff,		/* dst_mask */
147*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
148*3d8817e4Smiod   /* A high 6 bit absolute relocation of 22 bit address.
149*3d8817e4Smiod      For LDI command.  As well second most significant 8 bit value of
150*3d8817e4Smiod      a 32 bit link-time constant.  */
151*3d8817e4Smiod   HOWTO (R_AVR_HH8_LDI,		/* type */
152*3d8817e4Smiod 	 16,			/* rightshift */
153*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
154*3d8817e4Smiod 	 8,			/* bitsize */
155*3d8817e4Smiod 	 FALSE,			/* pc_relative */
156*3d8817e4Smiod 	 0,			/* bitpos */
157*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
158*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
159*3d8817e4Smiod 	 "R_AVR_HH8_LDI",	/* name */
160*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
161*3d8817e4Smiod 	 0xffff,		/* src_mask */
162*3d8817e4Smiod 	 0xffff,		/* dst_mask */
163*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
164*3d8817e4Smiod   /* A negative low 8 bit absolute relocation of 16 bit address.
165*3d8817e4Smiod      For LDI command.  */
166*3d8817e4Smiod   HOWTO (R_AVR_LO8_LDI_NEG,	/* type */
167*3d8817e4Smiod 	 0,			/* rightshift */
168*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
169*3d8817e4Smiod 	 8,			/* bitsize */
170*3d8817e4Smiod 	 FALSE,			/* pc_relative */
171*3d8817e4Smiod 	 0,			/* bitpos */
172*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
173*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
174*3d8817e4Smiod 	 "R_AVR_LO8_LDI_NEG",	/* name */
175*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
176*3d8817e4Smiod 	 0xffff,		/* src_mask */
177*3d8817e4Smiod 	 0xffff,		/* dst_mask */
178*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
179*3d8817e4Smiod   /* A negative high 8 bit absolute relocation of 16 bit address.
180*3d8817e4Smiod      For LDI command.  */
181*3d8817e4Smiod   HOWTO (R_AVR_HI8_LDI_NEG,	/* type */
182*3d8817e4Smiod 	 8,			/* rightshift */
183*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
184*3d8817e4Smiod 	 8,			/* bitsize */
185*3d8817e4Smiod 	 FALSE,			/* pc_relative */
186*3d8817e4Smiod 	 0,			/* bitpos */
187*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
188*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
189*3d8817e4Smiod 	 "R_AVR_HI8_LDI_NEG",	/* name */
190*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
191*3d8817e4Smiod 	 0xffff,		/* src_mask */
192*3d8817e4Smiod 	 0xffff,		/* dst_mask */
193*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
194*3d8817e4Smiod   /* A negative high 6 bit absolute relocation of 22 bit address.
195*3d8817e4Smiod      For LDI command.  */
196*3d8817e4Smiod   HOWTO (R_AVR_HH8_LDI_NEG,	/* type */
197*3d8817e4Smiod 	 16,			/* rightshift */
198*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
199*3d8817e4Smiod 	 8,			/* bitsize */
200*3d8817e4Smiod 	 FALSE,			/* pc_relative */
201*3d8817e4Smiod 	 0,			/* bitpos */
202*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
203*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
204*3d8817e4Smiod 	 "R_AVR_HH8_LDI_NEG",	/* name */
205*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
206*3d8817e4Smiod 	 0xffff,		/* src_mask */
207*3d8817e4Smiod 	 0xffff,		/* dst_mask */
208*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
209*3d8817e4Smiod   /* A low 8 bit absolute relocation of 24 bit program memory address.
210*3d8817e4Smiod      For LDI command.  */
211*3d8817e4Smiod   HOWTO (R_AVR_LO8_LDI_PM,	/* type */
212*3d8817e4Smiod 	 1,			/* rightshift */
213*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
214*3d8817e4Smiod 	 8,			/* bitsize */
215*3d8817e4Smiod 	 FALSE,			/* pc_relative */
216*3d8817e4Smiod 	 0,			/* bitpos */
217*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
218*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
219*3d8817e4Smiod 	 "R_AVR_LO8_LDI_PM",	/* name */
220*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
221*3d8817e4Smiod 	 0xffff,		/* src_mask */
222*3d8817e4Smiod 	 0xffff,		/* dst_mask */
223*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
224*3d8817e4Smiod   /* A high 8 bit absolute relocation of 16 bit program memory address.
225*3d8817e4Smiod      For LDI command.  */
226*3d8817e4Smiod   HOWTO (R_AVR_HI8_LDI_PM,	/* type */
227*3d8817e4Smiod 	 9,			/* rightshift */
228*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
229*3d8817e4Smiod 	 8,			/* bitsize */
230*3d8817e4Smiod 	 FALSE,			/* pc_relative */
231*3d8817e4Smiod 	 0,			/* bitpos */
232*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
233*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
234*3d8817e4Smiod 	 "R_AVR_HI8_LDI_PM",	/* name */
235*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
236*3d8817e4Smiod 	 0xffff,		/* src_mask */
237*3d8817e4Smiod 	 0xffff,		/* dst_mask */
238*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
239*3d8817e4Smiod   /* A high 8 bit absolute relocation of 24 bit program memory address.
240*3d8817e4Smiod      For LDI command.  */
241*3d8817e4Smiod   HOWTO (R_AVR_HH8_LDI_PM,	/* type */
242*3d8817e4Smiod 	 17,			/* rightshift */
243*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
244*3d8817e4Smiod 	 8,			/* bitsize */
245*3d8817e4Smiod 	 FALSE,			/* pc_relative */
246*3d8817e4Smiod 	 0,			/* bitpos */
247*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
248*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
249*3d8817e4Smiod 	 "R_AVR_HH8_LDI_PM",	/* name */
250*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
251*3d8817e4Smiod 	 0xffff,		/* src_mask */
252*3d8817e4Smiod 	 0xffff,		/* dst_mask */
253*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
254*3d8817e4Smiod   /* A low 8 bit absolute relocation of a negative 24 bit
255*3d8817e4Smiod      program memory address.  For LDI command.  */
256*3d8817e4Smiod   HOWTO (R_AVR_LO8_LDI_PM_NEG,	/* type */
257*3d8817e4Smiod 	 1,			/* rightshift */
258*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
259*3d8817e4Smiod 	 8,			/* bitsize */
260*3d8817e4Smiod 	 FALSE,			/* pc_relative */
261*3d8817e4Smiod 	 0,			/* bitpos */
262*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
263*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
264*3d8817e4Smiod 	 "R_AVR_LO8_LDI_PM_NEG", /* name */
265*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
266*3d8817e4Smiod 	 0xffff,		/* src_mask */
267*3d8817e4Smiod 	 0xffff,		/* dst_mask */
268*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
269*3d8817e4Smiod   /* A high 8 bit absolute relocation of a negative 16 bit
270*3d8817e4Smiod      program memory address.  For LDI command.  */
271*3d8817e4Smiod   HOWTO (R_AVR_HI8_LDI_PM_NEG,	/* type */
272*3d8817e4Smiod 	 9,			/* rightshift */
273*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
274*3d8817e4Smiod 	 8,			/* bitsize */
275*3d8817e4Smiod 	 FALSE,			/* pc_relative */
276*3d8817e4Smiod 	 0,			/* bitpos */
277*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
278*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
279*3d8817e4Smiod 	 "R_AVR_HI8_LDI_PM_NEG", /* name */
280*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
281*3d8817e4Smiod 	 0xffff,		/* src_mask */
282*3d8817e4Smiod 	 0xffff,		/* dst_mask */
283*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
284*3d8817e4Smiod   /* A high 8 bit absolute relocation of a negative 24 bit
285*3d8817e4Smiod      program memory address.  For LDI command.  */
286*3d8817e4Smiod   HOWTO (R_AVR_HH8_LDI_PM_NEG,	/* type */
287*3d8817e4Smiod 	 17,			/* rightshift */
288*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
289*3d8817e4Smiod 	 8,			/* bitsize */
290*3d8817e4Smiod 	 FALSE,			/* pc_relative */
291*3d8817e4Smiod 	 0,			/* bitpos */
292*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
293*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
294*3d8817e4Smiod 	 "R_AVR_HH8_LDI_PM_NEG", /* name */
295*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
296*3d8817e4Smiod 	 0xffff,		/* src_mask */
297*3d8817e4Smiod 	 0xffff,		/* dst_mask */
298*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
299*3d8817e4Smiod   /* Relocation for CALL command in ATmega.  */
300*3d8817e4Smiod   HOWTO (R_AVR_CALL,		/* type */
301*3d8817e4Smiod 	 1,			/* rightshift */
302*3d8817e4Smiod 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
303*3d8817e4Smiod 	 23,			/* bitsize */
304*3d8817e4Smiod 	 FALSE,			/* pc_relative */
305*3d8817e4Smiod 	 0,			/* bitpos */
306*3d8817e4Smiod 	 complain_overflow_dont,/* complain_on_overflow */
307*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
308*3d8817e4Smiod 	 "R_AVR_CALL",		/* name */
309*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
310*3d8817e4Smiod 	 0xffffffff,		/* src_mask */
311*3d8817e4Smiod 	 0xffffffff,		/* dst_mask */
312*3d8817e4Smiod 	 FALSE),			/* pcrel_offset */
313*3d8817e4Smiod   /* A 16 bit absolute relocation of 16 bit address.
314*3d8817e4Smiod      For LDI command.  */
315*3d8817e4Smiod   HOWTO (R_AVR_LDI,		/* type */
316*3d8817e4Smiod 	 0,			/* rightshift */
317*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
318*3d8817e4Smiod 	 16,			/* bitsize */
319*3d8817e4Smiod 	 FALSE,			/* pc_relative */
320*3d8817e4Smiod 	 0,			/* bitpos */
321*3d8817e4Smiod 	 complain_overflow_dont,/* complain_on_overflow */
322*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
323*3d8817e4Smiod 	 "R_AVR_LDI",		/* name */
324*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
325*3d8817e4Smiod 	 0xffff,		/* src_mask */
326*3d8817e4Smiod 	 0xffff,		/* dst_mask */
327*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
328*3d8817e4Smiod   /* A 6 bit absolute relocation of 6 bit offset.
329*3d8817e4Smiod      For ldd/sdd command.  */
330*3d8817e4Smiod   HOWTO (R_AVR_6,		/* type */
331*3d8817e4Smiod 	 0,			/* rightshift */
332*3d8817e4Smiod 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
333*3d8817e4Smiod 	 6,			/* bitsize */
334*3d8817e4Smiod 	 FALSE,			/* pc_relative */
335*3d8817e4Smiod 	 0,			/* bitpos */
336*3d8817e4Smiod 	 complain_overflow_dont,/* complain_on_overflow */
337*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
338*3d8817e4Smiod 	 "R_AVR_6",		/* name */
339*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
340*3d8817e4Smiod 	 0xffff,		/* src_mask */
341*3d8817e4Smiod 	 0xffff,		/* dst_mask */
342*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
343*3d8817e4Smiod   /* A 6 bit absolute relocation of 6 bit offset.
344*3d8817e4Smiod      For sbiw/adiw command.  */
345*3d8817e4Smiod   HOWTO (R_AVR_6_ADIW,		/* type */
346*3d8817e4Smiod 	 0,			/* rightshift */
347*3d8817e4Smiod 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
348*3d8817e4Smiod 	 6,			/* bitsize */
349*3d8817e4Smiod 	 FALSE,			/* pc_relative */
350*3d8817e4Smiod 	 0,			/* bitpos */
351*3d8817e4Smiod 	 complain_overflow_dont,/* complain_on_overflow */
352*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
353*3d8817e4Smiod 	 "R_AVR_6_ADIW",	/* name */
354*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
355*3d8817e4Smiod 	 0xffff,		/* src_mask */
356*3d8817e4Smiod 	 0xffff,		/* dst_mask */
357*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
358*3d8817e4Smiod   /* Most significant 8 bit value of a 32 bit link-time constant.  */
359*3d8817e4Smiod   HOWTO (R_AVR_MS8_LDI,		/* type */
360*3d8817e4Smiod 	 24,			/* rightshift */
361*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
362*3d8817e4Smiod 	 8,			/* bitsize */
363*3d8817e4Smiod 	 FALSE,			/* pc_relative */
364*3d8817e4Smiod 	 0,			/* bitpos */
365*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
366*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
367*3d8817e4Smiod 	 "R_AVR_MS8_LDI",	/* name */
368*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
369*3d8817e4Smiod 	 0xffff,		/* src_mask */
370*3d8817e4Smiod 	 0xffff,		/* dst_mask */
371*3d8817e4Smiod 	 FALSE),		/* pcrel_offset */
372*3d8817e4Smiod   /* Negative most significant 8 bit value of a 32 bit link-time constant.  */
373*3d8817e4Smiod   HOWTO (R_AVR_MS8_LDI_NEG,	/* type */
374*3d8817e4Smiod 	 24,			/* rightshift */
375*3d8817e4Smiod 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
376*3d8817e4Smiod 	 8,			/* bitsize */
377*3d8817e4Smiod 	 FALSE,			/* pc_relative */
378*3d8817e4Smiod 	 0,			/* bitpos */
379*3d8817e4Smiod 	 complain_overflow_dont, /* complain_on_overflow */
380*3d8817e4Smiod 	 bfd_elf_generic_reloc,	/* special_function */
381*3d8817e4Smiod 	 "R_AVR_MS8_LDI_NEG",	/* name */
382*3d8817e4Smiod 	 FALSE,			/* partial_inplace */
383*3d8817e4Smiod 	 0xffff,		/* src_mask */
384*3d8817e4Smiod 	 0xffff,		/* dst_mask */
385*3d8817e4Smiod 	 FALSE) 		/* pcrel_offset */
386*3d8817e4Smiod };
387*3d8817e4Smiod 
388*3d8817e4Smiod /* Map BFD reloc types to AVR ELF reloc types.  */
389*3d8817e4Smiod 
390*3d8817e4Smiod struct avr_reloc_map
391*3d8817e4Smiod {
392*3d8817e4Smiod   bfd_reloc_code_real_type bfd_reloc_val;
393*3d8817e4Smiod   unsigned int elf_reloc_val;
394*3d8817e4Smiod };
395*3d8817e4Smiod 
396*3d8817e4Smiod  static const struct avr_reloc_map avr_reloc_map[] =
397*3d8817e4Smiod {
398*3d8817e4Smiod   { BFD_RELOC_NONE,                 R_AVR_NONE },
399*3d8817e4Smiod   { BFD_RELOC_32,                   R_AVR_32 },
400*3d8817e4Smiod   { BFD_RELOC_AVR_7_PCREL,          R_AVR_7_PCREL },
401*3d8817e4Smiod   { BFD_RELOC_AVR_13_PCREL,         R_AVR_13_PCREL },
402*3d8817e4Smiod   { BFD_RELOC_16,                   R_AVR_16 },
403*3d8817e4Smiod   { BFD_RELOC_AVR_16_PM,            R_AVR_16_PM },
404*3d8817e4Smiod   { BFD_RELOC_AVR_LO8_LDI,          R_AVR_LO8_LDI},
405*3d8817e4Smiod   { BFD_RELOC_AVR_HI8_LDI,          R_AVR_HI8_LDI },
406*3d8817e4Smiod   { BFD_RELOC_AVR_HH8_LDI,          R_AVR_HH8_LDI },
407*3d8817e4Smiod   { BFD_RELOC_AVR_MS8_LDI,          R_AVR_MS8_LDI },
408*3d8817e4Smiod   { BFD_RELOC_AVR_LO8_LDI_NEG,      R_AVR_LO8_LDI_NEG },
409*3d8817e4Smiod   { BFD_RELOC_AVR_HI8_LDI_NEG,      R_AVR_HI8_LDI_NEG },
410*3d8817e4Smiod   { BFD_RELOC_AVR_HH8_LDI_NEG,      R_AVR_HH8_LDI_NEG },
411*3d8817e4Smiod   { BFD_RELOC_AVR_MS8_LDI_NEG,      R_AVR_MS8_LDI_NEG },
412*3d8817e4Smiod   { BFD_RELOC_AVR_LO8_LDI_PM,       R_AVR_LO8_LDI_PM },
413*3d8817e4Smiod   { BFD_RELOC_AVR_HI8_LDI_PM,       R_AVR_HI8_LDI_PM },
414*3d8817e4Smiod   { BFD_RELOC_AVR_HH8_LDI_PM,       R_AVR_HH8_LDI_PM },
415*3d8817e4Smiod   { BFD_RELOC_AVR_LO8_LDI_PM_NEG,   R_AVR_LO8_LDI_PM_NEG },
416*3d8817e4Smiod   { BFD_RELOC_AVR_HI8_LDI_PM_NEG,   R_AVR_HI8_LDI_PM_NEG },
417*3d8817e4Smiod   { BFD_RELOC_AVR_HH8_LDI_PM_NEG,   R_AVR_HH8_LDI_PM_NEG },
418*3d8817e4Smiod   { BFD_RELOC_AVR_CALL,             R_AVR_CALL },
419*3d8817e4Smiod   { BFD_RELOC_AVR_LDI,              R_AVR_LDI  },
420*3d8817e4Smiod   { BFD_RELOC_AVR_6,                R_AVR_6    },
421*3d8817e4Smiod   { BFD_RELOC_AVR_6_ADIW,           R_AVR_6_ADIW }
422*3d8817e4Smiod };
423*3d8817e4Smiod 
424*3d8817e4Smiod /* Meant to be filled one day with the wrap around address for the
425*3d8817e4Smiod    specific device.  I.e. should get the value 0x4000 for 16k devices,
426*3d8817e4Smiod    0x8000 for 32k devices and so on.
427*3d8817e4Smiod 
428*3d8817e4Smiod    We initialize it here with a value of 0x1000000 resulting in
429*3d8817e4Smiod    that we will never suggest a wrap-around jump during relaxation.
430*3d8817e4Smiod    The logic of the source code later on assumes that in
431*3d8817e4Smiod    avr_pc_wrap_around one single bit is set.  */
432*3d8817e4Smiod 
433*3d8817e4Smiod unsigned int avr_pc_wrap_around = 0x10000000;
434*3d8817e4Smiod 
435*3d8817e4Smiod /* Calculates the effective distance of a pc relative jump/call.  */
436*3d8817e4Smiod static int
avr_relative_distance_considering_wrap_around(unsigned int distance)437*3d8817e4Smiod avr_relative_distance_considering_wrap_around (unsigned int distance)
438*3d8817e4Smiod {
439*3d8817e4Smiod   unsigned int wrap_around_mask = avr_pc_wrap_around - 1;
440*3d8817e4Smiod   int dist_with_wrap_around = distance & wrap_around_mask;
441*3d8817e4Smiod 
442*3d8817e4Smiod   if (dist_with_wrap_around > ((int) (avr_pc_wrap_around >> 1)))
443*3d8817e4Smiod     dist_with_wrap_around -= avr_pc_wrap_around;
444*3d8817e4Smiod 
445*3d8817e4Smiod   return dist_with_wrap_around;
446*3d8817e4Smiod }
447*3d8817e4Smiod 
448*3d8817e4Smiod 
449*3d8817e4Smiod static reloc_howto_type *
bfd_elf32_bfd_reloc_type_lookup(bfd * abfd ATTRIBUTE_UNUSED,bfd_reloc_code_real_type code)450*3d8817e4Smiod bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
451*3d8817e4Smiod 				 bfd_reloc_code_real_type code)
452*3d8817e4Smiod {
453*3d8817e4Smiod   unsigned int i;
454*3d8817e4Smiod 
455*3d8817e4Smiod   for (i = 0;
456*3d8817e4Smiod        i < sizeof (avr_reloc_map) / sizeof (struct avr_reloc_map);
457*3d8817e4Smiod        i++)
458*3d8817e4Smiod     {
459*3d8817e4Smiod       if (avr_reloc_map[i].bfd_reloc_val == code)
460*3d8817e4Smiod 	return &elf_avr_howto_table[avr_reloc_map[i].elf_reloc_val];
461*3d8817e4Smiod     }
462*3d8817e4Smiod 
463*3d8817e4Smiod   return NULL;
464*3d8817e4Smiod }
465*3d8817e4Smiod 
466*3d8817e4Smiod /* Set the howto pointer for an AVR ELF reloc.  */
467*3d8817e4Smiod 
468*3d8817e4Smiod static void
avr_info_to_howto_rela(bfd * abfd ATTRIBUTE_UNUSED,arelent * cache_ptr,Elf_Internal_Rela * dst)469*3d8817e4Smiod avr_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
470*3d8817e4Smiod 			arelent *cache_ptr,
471*3d8817e4Smiod 			Elf_Internal_Rela *dst)
472*3d8817e4Smiod {
473*3d8817e4Smiod   unsigned int r_type;
474*3d8817e4Smiod 
475*3d8817e4Smiod   r_type = ELF32_R_TYPE (dst->r_info);
476*3d8817e4Smiod   BFD_ASSERT (r_type < (unsigned int) R_AVR_max);
477*3d8817e4Smiod   cache_ptr->howto = &elf_avr_howto_table[r_type];
478*3d8817e4Smiod }
479*3d8817e4Smiod 
480*3d8817e4Smiod static asection *
elf32_avr_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)481*3d8817e4Smiod elf32_avr_gc_mark_hook (asection *sec,
482*3d8817e4Smiod 			struct bfd_link_info *info ATTRIBUTE_UNUSED,
483*3d8817e4Smiod 			Elf_Internal_Rela *rel,
484*3d8817e4Smiod 			struct elf_link_hash_entry *h,
485*3d8817e4Smiod 			Elf_Internal_Sym *sym)
486*3d8817e4Smiod {
487*3d8817e4Smiod   if (h != NULL)
488*3d8817e4Smiod     {
489*3d8817e4Smiod       switch (ELF32_R_TYPE (rel->r_info))
490*3d8817e4Smiod 	{
491*3d8817e4Smiod 	default:
492*3d8817e4Smiod 	  switch (h->root.type)
493*3d8817e4Smiod 	    {
494*3d8817e4Smiod 	    case bfd_link_hash_defined:
495*3d8817e4Smiod 	    case bfd_link_hash_defweak:
496*3d8817e4Smiod 	      return h->root.u.def.section;
497*3d8817e4Smiod 
498*3d8817e4Smiod 	    case bfd_link_hash_common:
499*3d8817e4Smiod 	      return h->root.u.c.p->section;
500*3d8817e4Smiod 
501*3d8817e4Smiod 	    default:
502*3d8817e4Smiod 	      break;
503*3d8817e4Smiod 	    }
504*3d8817e4Smiod 	}
505*3d8817e4Smiod     }
506*3d8817e4Smiod   else
507*3d8817e4Smiod     return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
508*3d8817e4Smiod 
509*3d8817e4Smiod   return NULL;
510*3d8817e4Smiod }
511*3d8817e4Smiod 
512*3d8817e4Smiod static bfd_boolean
elf32_avr_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)513*3d8817e4Smiod elf32_avr_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED,
514*3d8817e4Smiod 			 struct bfd_link_info *info ATTRIBUTE_UNUSED,
515*3d8817e4Smiod 			 asection *sec ATTRIBUTE_UNUSED,
516*3d8817e4Smiod 			 const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED)
517*3d8817e4Smiod {
518*3d8817e4Smiod   /* We don't use got and plt entries for avr.  */
519*3d8817e4Smiod   return TRUE;
520*3d8817e4Smiod }
521*3d8817e4Smiod 
522*3d8817e4Smiod /* Look through the relocs for a section during the first phase.
523*3d8817e4Smiod    Since we don't do .gots or .plts, we just need to consider the
524*3d8817e4Smiod    virtual table relocs for gc.  */
525*3d8817e4Smiod 
526*3d8817e4Smiod static bfd_boolean
elf32_avr_check_relocs(bfd * abfd,struct bfd_link_info * info,asection * sec,const Elf_Internal_Rela * relocs)527*3d8817e4Smiod elf32_avr_check_relocs (bfd *abfd,
528*3d8817e4Smiod 			struct bfd_link_info *info,
529*3d8817e4Smiod 			asection *sec,
530*3d8817e4Smiod 			const Elf_Internal_Rela *relocs)
531*3d8817e4Smiod {
532*3d8817e4Smiod   Elf_Internal_Shdr *symtab_hdr;
533*3d8817e4Smiod   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
534*3d8817e4Smiod   const Elf_Internal_Rela *rel;
535*3d8817e4Smiod   const Elf_Internal_Rela *rel_end;
536*3d8817e4Smiod 
537*3d8817e4Smiod   if (info->relocatable)
538*3d8817e4Smiod     return TRUE;
539*3d8817e4Smiod 
540*3d8817e4Smiod   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
541*3d8817e4Smiod   sym_hashes = elf_sym_hashes (abfd);
542*3d8817e4Smiod   sym_hashes_end = sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
543*3d8817e4Smiod   if (!elf_bad_symtab (abfd))
544*3d8817e4Smiod     sym_hashes_end -= symtab_hdr->sh_info;
545*3d8817e4Smiod 
546*3d8817e4Smiod   rel_end = relocs + sec->reloc_count;
547*3d8817e4Smiod   for (rel = relocs; rel < rel_end; rel++)
548*3d8817e4Smiod     {
549*3d8817e4Smiod       struct elf_link_hash_entry *h;
550*3d8817e4Smiod       unsigned long r_symndx;
551*3d8817e4Smiod 
552*3d8817e4Smiod       r_symndx = ELF32_R_SYM (rel->r_info);
553*3d8817e4Smiod       if (r_symndx < symtab_hdr->sh_info)
554*3d8817e4Smiod         h = NULL;
555*3d8817e4Smiod       else
556*3d8817e4Smiod 	{
557*3d8817e4Smiod 	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
558*3d8817e4Smiod 	  while (h->root.type == bfd_link_hash_indirect
559*3d8817e4Smiod 		 || h->root.type == bfd_link_hash_warning)
560*3d8817e4Smiod 	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
561*3d8817e4Smiod 	}
562*3d8817e4Smiod     }
563*3d8817e4Smiod 
564*3d8817e4Smiod   return TRUE;
565*3d8817e4Smiod }
566*3d8817e4Smiod 
567*3d8817e4Smiod /* Perform a single relocation.  By default we use the standard BFD
568*3d8817e4Smiod    routines, but a few relocs, we have to do them ourselves.  */
569*3d8817e4Smiod 
570*3d8817e4Smiod static bfd_reloc_status_type
avr_final_link_relocate(reloc_howto_type * howto,bfd * input_bfd,asection * input_section,bfd_byte * contents,Elf_Internal_Rela * rel,bfd_vma relocation)571*3d8817e4Smiod avr_final_link_relocate (reloc_howto_type *  howto,
572*3d8817e4Smiod 			 bfd *               input_bfd,
573*3d8817e4Smiod 			 asection *          input_section,
574*3d8817e4Smiod 			 bfd_byte *          contents,
575*3d8817e4Smiod 			 Elf_Internal_Rela * rel,
576*3d8817e4Smiod 			 bfd_vma             relocation)
577*3d8817e4Smiod {
578*3d8817e4Smiod   bfd_reloc_status_type r = bfd_reloc_ok;
579*3d8817e4Smiod   bfd_vma               x;
580*3d8817e4Smiod   bfd_signed_vma	srel;
581*3d8817e4Smiod 
582*3d8817e4Smiod   switch (howto->type)
583*3d8817e4Smiod     {
584*3d8817e4Smiod     case R_AVR_7_PCREL:
585*3d8817e4Smiod       contents += rel->r_offset;
586*3d8817e4Smiod       srel = (bfd_signed_vma) relocation;
587*3d8817e4Smiod       srel += rel->r_addend;
588*3d8817e4Smiod       srel -= rel->r_offset;
589*3d8817e4Smiod       srel -= 2;	/* Branch instructions add 2 to the PC...  */
590*3d8817e4Smiod       srel -= (input_section->output_section->vma +
591*3d8817e4Smiod 	       input_section->output_offset);
592*3d8817e4Smiod 
593*3d8817e4Smiod       if (srel & 1)
594*3d8817e4Smiod 	return bfd_reloc_outofrange;
595*3d8817e4Smiod       if (srel > ((1 << 7) - 1) || (srel < - (1 << 7)))
596*3d8817e4Smiod 	return bfd_reloc_overflow;
597*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
598*3d8817e4Smiod       x = (x & 0xfc07) | (((srel >> 1) << 3) & 0x3f8);
599*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
600*3d8817e4Smiod       break;
601*3d8817e4Smiod 
602*3d8817e4Smiod     case R_AVR_13_PCREL:
603*3d8817e4Smiod       contents   += rel->r_offset;
604*3d8817e4Smiod       srel = (bfd_signed_vma) relocation;
605*3d8817e4Smiod       srel += rel->r_addend;
606*3d8817e4Smiod       srel -= rel->r_offset;
607*3d8817e4Smiod       srel -= 2;	/* Branch instructions add 2 to the PC...  */
608*3d8817e4Smiod       srel -= (input_section->output_section->vma +
609*3d8817e4Smiod 	       input_section->output_offset);
610*3d8817e4Smiod 
611*3d8817e4Smiod       if (srel & 1)
612*3d8817e4Smiod 	return bfd_reloc_outofrange;
613*3d8817e4Smiod 
614*3d8817e4Smiod       srel = avr_relative_distance_considering_wrap_around (srel);
615*3d8817e4Smiod 
616*3d8817e4Smiod       /* AVR addresses commands as words.  */
617*3d8817e4Smiod       srel >>= 1;
618*3d8817e4Smiod 
619*3d8817e4Smiod       /* Check for overflow.  */
620*3d8817e4Smiod       if (srel < -2048 || srel > 2047)
621*3d8817e4Smiod 	{
622*3d8817e4Smiod           /* Relative distance is too large.  */
623*3d8817e4Smiod 
624*3d8817e4Smiod 	  /* Always apply WRAPAROUND for avr2 and avr4.  */
625*3d8817e4Smiod 	  switch (bfd_get_mach (input_bfd))
626*3d8817e4Smiod 	    {
627*3d8817e4Smiod 	    case bfd_mach_avr2:
628*3d8817e4Smiod 	    case bfd_mach_avr4:
629*3d8817e4Smiod 	      break;
630*3d8817e4Smiod 
631*3d8817e4Smiod 	    default:
632*3d8817e4Smiod 	      return bfd_reloc_overflow;
633*3d8817e4Smiod 	    }
634*3d8817e4Smiod 	}
635*3d8817e4Smiod 
636*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
637*3d8817e4Smiod       x = (x & 0xf000) | (srel & 0xfff);
638*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
639*3d8817e4Smiod       break;
640*3d8817e4Smiod 
641*3d8817e4Smiod     case R_AVR_LO8_LDI:
642*3d8817e4Smiod       contents += rel->r_offset;
643*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
644*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
645*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
646*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
647*3d8817e4Smiod       break;
648*3d8817e4Smiod 
649*3d8817e4Smiod     case R_AVR_LDI:
650*3d8817e4Smiod       contents += rel->r_offset;
651*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
652*3d8817e4Smiod       if (((srel > 0) && (srel & 0xffff) > 255)
653*3d8817e4Smiod 	  || ((srel < 0) && ((-srel) & 0xffff) > 128))
654*3d8817e4Smiod         /* Remove offset for data/eeprom section.  */
655*3d8817e4Smiod         return bfd_reloc_overflow;
656*3d8817e4Smiod 
657*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
658*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
659*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
660*3d8817e4Smiod       break;
661*3d8817e4Smiod 
662*3d8817e4Smiod     case R_AVR_6:
663*3d8817e4Smiod       contents += rel->r_offset;
664*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
665*3d8817e4Smiod       if (((srel & 0xffff) > 63) || (srel < 0))
666*3d8817e4Smiod 	/* Remove offset for data/eeprom section.  */
667*3d8817e4Smiod 	return bfd_reloc_overflow;
668*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
669*3d8817e4Smiod       x = (x & 0xd3f8) | ((srel & 7) | ((srel & (3 << 3)) << 7)
670*3d8817e4Smiod                        | ((srel & (1 << 5)) << 8));
671*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
672*3d8817e4Smiod       break;
673*3d8817e4Smiod 
674*3d8817e4Smiod     case R_AVR_6_ADIW:
675*3d8817e4Smiod       contents += rel->r_offset;
676*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
677*3d8817e4Smiod       if (((srel & 0xffff) > 63) || (srel < 0))
678*3d8817e4Smiod 	/* Remove offset for data/eeprom section.  */
679*3d8817e4Smiod 	return bfd_reloc_overflow;
680*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
681*3d8817e4Smiod       x = (x & 0xff30) | (srel & 0xf) | ((srel & 0x30) << 2);
682*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
683*3d8817e4Smiod       break;
684*3d8817e4Smiod 
685*3d8817e4Smiod     case R_AVR_HI8_LDI:
686*3d8817e4Smiod       contents += rel->r_offset;
687*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
688*3d8817e4Smiod       srel = (srel >> 8) & 0xff;
689*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
690*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
691*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
692*3d8817e4Smiod       break;
693*3d8817e4Smiod 
694*3d8817e4Smiod     case R_AVR_HH8_LDI:
695*3d8817e4Smiod       contents += rel->r_offset;
696*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
697*3d8817e4Smiod       srel = (srel >> 16) & 0xff;
698*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
699*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
700*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
701*3d8817e4Smiod       break;
702*3d8817e4Smiod 
703*3d8817e4Smiod     case R_AVR_MS8_LDI:
704*3d8817e4Smiod       contents += rel->r_offset;
705*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
706*3d8817e4Smiod       srel = (srel >> 24) & 0xff;
707*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
708*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
709*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
710*3d8817e4Smiod       break;
711*3d8817e4Smiod 
712*3d8817e4Smiod     case R_AVR_LO8_LDI_NEG:
713*3d8817e4Smiod       contents += rel->r_offset;
714*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
715*3d8817e4Smiod       srel = -srel;
716*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
717*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
718*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
719*3d8817e4Smiod       break;
720*3d8817e4Smiod 
721*3d8817e4Smiod     case R_AVR_HI8_LDI_NEG:
722*3d8817e4Smiod       contents += rel->r_offset;
723*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
724*3d8817e4Smiod       srel = -srel;
725*3d8817e4Smiod       srel = (srel >> 8) & 0xff;
726*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
727*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
728*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
729*3d8817e4Smiod       break;
730*3d8817e4Smiod 
731*3d8817e4Smiod     case R_AVR_HH8_LDI_NEG:
732*3d8817e4Smiod       contents += rel->r_offset;
733*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
734*3d8817e4Smiod       srel = -srel;
735*3d8817e4Smiod       srel = (srel >> 16) & 0xff;
736*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
737*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
738*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
739*3d8817e4Smiod       break;
740*3d8817e4Smiod 
741*3d8817e4Smiod     case R_AVR_MS8_LDI_NEG:
742*3d8817e4Smiod       contents += rel->r_offset;
743*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
744*3d8817e4Smiod       srel = -srel;
745*3d8817e4Smiod       srel = (srel >> 24) & 0xff;
746*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
747*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
748*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
749*3d8817e4Smiod       break;
750*3d8817e4Smiod 
751*3d8817e4Smiod     case R_AVR_LO8_LDI_PM:
752*3d8817e4Smiod       contents += rel->r_offset;
753*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
754*3d8817e4Smiod       if (srel & 1)
755*3d8817e4Smiod 	return bfd_reloc_outofrange;
756*3d8817e4Smiod       srel = srel >> 1;
757*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
758*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
759*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
760*3d8817e4Smiod       break;
761*3d8817e4Smiod 
762*3d8817e4Smiod     case R_AVR_HI8_LDI_PM:
763*3d8817e4Smiod       contents += rel->r_offset;
764*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
765*3d8817e4Smiod       if (srel & 1)
766*3d8817e4Smiod 	return bfd_reloc_outofrange;
767*3d8817e4Smiod       srel = srel >> 1;
768*3d8817e4Smiod       srel = (srel >> 8) & 0xff;
769*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
770*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
771*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
772*3d8817e4Smiod       break;
773*3d8817e4Smiod 
774*3d8817e4Smiod     case R_AVR_HH8_LDI_PM:
775*3d8817e4Smiod       contents += rel->r_offset;
776*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
777*3d8817e4Smiod       if (srel & 1)
778*3d8817e4Smiod 	return bfd_reloc_outofrange;
779*3d8817e4Smiod       srel = srel >> 1;
780*3d8817e4Smiod       srel = (srel >> 16) & 0xff;
781*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
782*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
783*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
784*3d8817e4Smiod       break;
785*3d8817e4Smiod 
786*3d8817e4Smiod     case R_AVR_LO8_LDI_PM_NEG:
787*3d8817e4Smiod       contents += rel->r_offset;
788*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
789*3d8817e4Smiod       srel = -srel;
790*3d8817e4Smiod       if (srel & 1)
791*3d8817e4Smiod 	return bfd_reloc_outofrange;
792*3d8817e4Smiod       srel = srel >> 1;
793*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
794*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
795*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
796*3d8817e4Smiod       break;
797*3d8817e4Smiod 
798*3d8817e4Smiod     case R_AVR_HI8_LDI_PM_NEG:
799*3d8817e4Smiod       contents += rel->r_offset;
800*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
801*3d8817e4Smiod       srel = -srel;
802*3d8817e4Smiod       if (srel & 1)
803*3d8817e4Smiod 	return bfd_reloc_outofrange;
804*3d8817e4Smiod       srel = srel >> 1;
805*3d8817e4Smiod       srel = (srel >> 8) & 0xff;
806*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
807*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
808*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
809*3d8817e4Smiod       break;
810*3d8817e4Smiod 
811*3d8817e4Smiod     case R_AVR_HH8_LDI_PM_NEG:
812*3d8817e4Smiod       contents += rel->r_offset;
813*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
814*3d8817e4Smiod       srel = -srel;
815*3d8817e4Smiod       if (srel & 1)
816*3d8817e4Smiod 	return bfd_reloc_outofrange;
817*3d8817e4Smiod       srel = srel >> 1;
818*3d8817e4Smiod       srel = (srel >> 16) & 0xff;
819*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
820*3d8817e4Smiod       x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00);
821*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
822*3d8817e4Smiod       break;
823*3d8817e4Smiod 
824*3d8817e4Smiod     case R_AVR_CALL:
825*3d8817e4Smiod       contents += rel->r_offset;
826*3d8817e4Smiod       srel = (bfd_signed_vma) relocation + rel->r_addend;
827*3d8817e4Smiod       if (srel & 1)
828*3d8817e4Smiod 	return bfd_reloc_outofrange;
829*3d8817e4Smiod       srel = srel >> 1;
830*3d8817e4Smiod       x = bfd_get_16 (input_bfd, contents);
831*3d8817e4Smiod       x |= ((srel & 0x10000) | ((srel << 3) & 0x1f00000)) >> 16;
832*3d8817e4Smiod       bfd_put_16 (input_bfd, x, contents);
833*3d8817e4Smiod       bfd_put_16 (input_bfd, (bfd_vma) srel & 0xffff, contents+2);
834*3d8817e4Smiod       break;
835*3d8817e4Smiod 
836*3d8817e4Smiod     default:
837*3d8817e4Smiod       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
838*3d8817e4Smiod 				    contents, rel->r_offset,
839*3d8817e4Smiod 				    relocation, rel->r_addend);
840*3d8817e4Smiod     }
841*3d8817e4Smiod 
842*3d8817e4Smiod   return r;
843*3d8817e4Smiod }
844*3d8817e4Smiod 
845*3d8817e4Smiod /* Relocate an AVR ELF section.  */
846*3d8817e4Smiod 
847*3d8817e4Smiod static bfd_boolean
elf32_avr_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)848*3d8817e4Smiod elf32_avr_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
849*3d8817e4Smiod 			    struct bfd_link_info *info,
850*3d8817e4Smiod 			    bfd *input_bfd,
851*3d8817e4Smiod 			    asection *input_section,
852*3d8817e4Smiod 			    bfd_byte *contents,
853*3d8817e4Smiod 			    Elf_Internal_Rela *relocs,
854*3d8817e4Smiod 			    Elf_Internal_Sym *local_syms,
855*3d8817e4Smiod 			    asection **local_sections)
856*3d8817e4Smiod {
857*3d8817e4Smiod   Elf_Internal_Shdr *           symtab_hdr;
858*3d8817e4Smiod   struct elf_link_hash_entry ** sym_hashes;
859*3d8817e4Smiod   Elf_Internal_Rela *           rel;
860*3d8817e4Smiod   Elf_Internal_Rela *           relend;
861*3d8817e4Smiod 
862*3d8817e4Smiod   if (info->relocatable)
863*3d8817e4Smiod     return TRUE;
864*3d8817e4Smiod 
865*3d8817e4Smiod   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
866*3d8817e4Smiod   sym_hashes = elf_sym_hashes (input_bfd);
867*3d8817e4Smiod   relend     = relocs + input_section->reloc_count;
868*3d8817e4Smiod 
869*3d8817e4Smiod   for (rel = relocs; rel < relend; rel ++)
870*3d8817e4Smiod     {
871*3d8817e4Smiod       reloc_howto_type *           howto;
872*3d8817e4Smiod       unsigned long                r_symndx;
873*3d8817e4Smiod       Elf_Internal_Sym *           sym;
874*3d8817e4Smiod       asection *                   sec;
875*3d8817e4Smiod       struct elf_link_hash_entry * h;
876*3d8817e4Smiod       bfd_vma                      relocation;
877*3d8817e4Smiod       bfd_reloc_status_type        r;
878*3d8817e4Smiod       const char *                 name;
879*3d8817e4Smiod       int                          r_type;
880*3d8817e4Smiod 
881*3d8817e4Smiod       /* This is a final link.  */
882*3d8817e4Smiod       r_type = ELF32_R_TYPE (rel->r_info);
883*3d8817e4Smiod       r_symndx = ELF32_R_SYM (rel->r_info);
884*3d8817e4Smiod       howto  = elf_avr_howto_table + ELF32_R_TYPE (rel->r_info);
885*3d8817e4Smiod       h      = NULL;
886*3d8817e4Smiod       sym    = NULL;
887*3d8817e4Smiod       sec    = NULL;
888*3d8817e4Smiod 
889*3d8817e4Smiod       if (r_symndx < symtab_hdr->sh_info)
890*3d8817e4Smiod 	{
891*3d8817e4Smiod 	  sym = local_syms + r_symndx;
892*3d8817e4Smiod 	  sec = local_sections [r_symndx];
893*3d8817e4Smiod 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
894*3d8817e4Smiod 
895*3d8817e4Smiod 	  name = bfd_elf_string_from_elf_section
896*3d8817e4Smiod 	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
897*3d8817e4Smiod 	  name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
898*3d8817e4Smiod 	}
899*3d8817e4Smiod       else
900*3d8817e4Smiod 	{
901*3d8817e4Smiod 	  bfd_boolean unresolved_reloc, warned;
902*3d8817e4Smiod 
903*3d8817e4Smiod 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
904*3d8817e4Smiod 				   r_symndx, symtab_hdr, sym_hashes,
905*3d8817e4Smiod 				   h, sec, relocation,
906*3d8817e4Smiod 				   unresolved_reloc, warned);
907*3d8817e4Smiod 
908*3d8817e4Smiod 	  name = h->root.root.string;
909*3d8817e4Smiod 	}
910*3d8817e4Smiod 
911*3d8817e4Smiod       r = avr_final_link_relocate (howto, input_bfd, input_section,
912*3d8817e4Smiod 				   contents, rel, relocation);
913*3d8817e4Smiod 
914*3d8817e4Smiod       if (r != bfd_reloc_ok)
915*3d8817e4Smiod 	{
916*3d8817e4Smiod 	  const char * msg = (const char *) NULL;
917*3d8817e4Smiod 
918*3d8817e4Smiod 	  switch (r)
919*3d8817e4Smiod 	    {
920*3d8817e4Smiod 	    case bfd_reloc_overflow:
921*3d8817e4Smiod 	      r = info->callbacks->reloc_overflow
922*3d8817e4Smiod 		(info, (h ? &h->root : NULL),
923*3d8817e4Smiod 		 name, howto->name, (bfd_vma) 0,
924*3d8817e4Smiod 		 input_bfd, input_section, rel->r_offset);
925*3d8817e4Smiod 	      break;
926*3d8817e4Smiod 
927*3d8817e4Smiod 	    case bfd_reloc_undefined:
928*3d8817e4Smiod 	      r = info->callbacks->undefined_symbol
929*3d8817e4Smiod 		(info, name, input_bfd, input_section, rel->r_offset, TRUE);
930*3d8817e4Smiod 	      break;
931*3d8817e4Smiod 
932*3d8817e4Smiod 	    case bfd_reloc_outofrange:
933*3d8817e4Smiod 	      msg = _("internal error: out of range error");
934*3d8817e4Smiod 	      break;
935*3d8817e4Smiod 
936*3d8817e4Smiod 	    case bfd_reloc_notsupported:
937*3d8817e4Smiod 	      msg = _("internal error: unsupported relocation error");
938*3d8817e4Smiod 	      break;
939*3d8817e4Smiod 
940*3d8817e4Smiod 	    case bfd_reloc_dangerous:
941*3d8817e4Smiod 	      msg = _("internal error: dangerous relocation");
942*3d8817e4Smiod 	      break;
943*3d8817e4Smiod 
944*3d8817e4Smiod 	    default:
945*3d8817e4Smiod 	      msg = _("internal error: unknown error");
946*3d8817e4Smiod 	      break;
947*3d8817e4Smiod 	    }
948*3d8817e4Smiod 
949*3d8817e4Smiod 	  if (msg)
950*3d8817e4Smiod 	    r = info->callbacks->warning
951*3d8817e4Smiod 	      (info, msg, name, input_bfd, input_section, rel->r_offset);
952*3d8817e4Smiod 
953*3d8817e4Smiod 	  if (! r)
954*3d8817e4Smiod 	    return FALSE;
955*3d8817e4Smiod 	}
956*3d8817e4Smiod     }
957*3d8817e4Smiod 
958*3d8817e4Smiod   return TRUE;
959*3d8817e4Smiod }
960*3d8817e4Smiod 
961*3d8817e4Smiod /* The final processing done just before writing out a AVR ELF object
962*3d8817e4Smiod    file.  This gets the AVR architecture right based on the machine
963*3d8817e4Smiod    number.  */
964*3d8817e4Smiod 
965*3d8817e4Smiod static void
bfd_elf_avr_final_write_processing(bfd * abfd,bfd_boolean linker ATTRIBUTE_UNUSED)966*3d8817e4Smiod bfd_elf_avr_final_write_processing (bfd *abfd,
967*3d8817e4Smiod 				    bfd_boolean linker ATTRIBUTE_UNUSED)
968*3d8817e4Smiod {
969*3d8817e4Smiod   unsigned long val;
970*3d8817e4Smiod 
971*3d8817e4Smiod   switch (bfd_get_mach (abfd))
972*3d8817e4Smiod     {
973*3d8817e4Smiod     default:
974*3d8817e4Smiod     case bfd_mach_avr2:
975*3d8817e4Smiod       val = E_AVR_MACH_AVR2;
976*3d8817e4Smiod       break;
977*3d8817e4Smiod 
978*3d8817e4Smiod     case bfd_mach_avr1:
979*3d8817e4Smiod       val = E_AVR_MACH_AVR1;
980*3d8817e4Smiod       break;
981*3d8817e4Smiod 
982*3d8817e4Smiod     case bfd_mach_avr3:
983*3d8817e4Smiod       val = E_AVR_MACH_AVR3;
984*3d8817e4Smiod       break;
985*3d8817e4Smiod 
986*3d8817e4Smiod     case bfd_mach_avr4:
987*3d8817e4Smiod       val = E_AVR_MACH_AVR4;
988*3d8817e4Smiod       break;
989*3d8817e4Smiod 
990*3d8817e4Smiod     case bfd_mach_avr5:
991*3d8817e4Smiod       val = E_AVR_MACH_AVR5;
992*3d8817e4Smiod       break;
993*3d8817e4Smiod     }
994*3d8817e4Smiod 
995*3d8817e4Smiod   elf_elfheader (abfd)->e_machine = EM_AVR;
996*3d8817e4Smiod   elf_elfheader (abfd)->e_flags &= ~ EF_AVR_MACH;
997*3d8817e4Smiod   elf_elfheader (abfd)->e_flags |= val;
998*3d8817e4Smiod   elf_elfheader (abfd)->e_flags |= EF_AVR_LINKRELAX_PREPARED;
999*3d8817e4Smiod }
1000*3d8817e4Smiod 
1001*3d8817e4Smiod /* Set the right machine number.  */
1002*3d8817e4Smiod 
1003*3d8817e4Smiod static bfd_boolean
elf32_avr_object_p(bfd * abfd)1004*3d8817e4Smiod elf32_avr_object_p (bfd *abfd)
1005*3d8817e4Smiod {
1006*3d8817e4Smiod   unsigned int e_set = bfd_mach_avr2;
1007*3d8817e4Smiod 
1008*3d8817e4Smiod   if (elf_elfheader (abfd)->e_machine == EM_AVR
1009*3d8817e4Smiod       || elf_elfheader (abfd)->e_machine == EM_AVR_OLD)
1010*3d8817e4Smiod     {
1011*3d8817e4Smiod       int e_mach = elf_elfheader (abfd)->e_flags & EF_AVR_MACH;
1012*3d8817e4Smiod 
1013*3d8817e4Smiod       switch (e_mach)
1014*3d8817e4Smiod 	{
1015*3d8817e4Smiod 	default:
1016*3d8817e4Smiod 	case E_AVR_MACH_AVR2:
1017*3d8817e4Smiod 	  e_set = bfd_mach_avr2;
1018*3d8817e4Smiod 	  break;
1019*3d8817e4Smiod 
1020*3d8817e4Smiod 	case E_AVR_MACH_AVR1:
1021*3d8817e4Smiod 	  e_set = bfd_mach_avr1;
1022*3d8817e4Smiod 	  break;
1023*3d8817e4Smiod 
1024*3d8817e4Smiod 	case E_AVR_MACH_AVR3:
1025*3d8817e4Smiod 	  e_set = bfd_mach_avr3;
1026*3d8817e4Smiod 	  break;
1027*3d8817e4Smiod 
1028*3d8817e4Smiod 	case E_AVR_MACH_AVR4:
1029*3d8817e4Smiod 	  e_set = bfd_mach_avr4;
1030*3d8817e4Smiod 	  break;
1031*3d8817e4Smiod 
1032*3d8817e4Smiod 	case E_AVR_MACH_AVR5:
1033*3d8817e4Smiod 	  e_set = bfd_mach_avr5;
1034*3d8817e4Smiod 	  break;
1035*3d8817e4Smiod 	}
1036*3d8817e4Smiod     }
1037*3d8817e4Smiod   return bfd_default_set_arch_mach (abfd, bfd_arch_avr,
1038*3d8817e4Smiod 				    e_set);
1039*3d8817e4Smiod }
1040*3d8817e4Smiod 
1041*3d8817e4Smiod 
1042*3d8817e4Smiod /* Enable debugging printout at stdout with a value of 1.  */
1043*3d8817e4Smiod #define DEBUG_RELAX 0
1044*3d8817e4Smiod 
1045*3d8817e4Smiod /* Delete some bytes from a section while changing the size of an instruction.
1046*3d8817e4Smiod    The parameter "addr" denotes the section-relative offset pointing just
1047*3d8817e4Smiod    behind the shrinked instruction. "addr+count" point at the first
1048*3d8817e4Smiod    byte just behind the original unshrinked instruction.  */
1049*3d8817e4Smiod 
1050*3d8817e4Smiod static bfd_boolean
elf32_avr_relax_delete_bytes(bfd * abfd,asection * sec,bfd_vma addr,int count)1051*3d8817e4Smiod elf32_avr_relax_delete_bytes (bfd *abfd,
1052*3d8817e4Smiod 			      asection *sec,
1053*3d8817e4Smiod                               bfd_vma addr,
1054*3d8817e4Smiod 			      int count)
1055*3d8817e4Smiod {
1056*3d8817e4Smiod   Elf_Internal_Shdr *symtab_hdr;
1057*3d8817e4Smiod   unsigned int sec_shndx;
1058*3d8817e4Smiod   bfd_byte *contents;
1059*3d8817e4Smiod   Elf_Internal_Rela *irel, *irelend;
1060*3d8817e4Smiod   Elf_Internal_Rela *irelalign;
1061*3d8817e4Smiod   Elf_Internal_Sym *isym;
1062*3d8817e4Smiod   Elf_Internal_Sym *isymbuf = NULL;
1063*3d8817e4Smiod   Elf_Internal_Sym *isymend;
1064*3d8817e4Smiod   bfd_vma toaddr;
1065*3d8817e4Smiod   struct elf_link_hash_entry **sym_hashes;
1066*3d8817e4Smiod   struct elf_link_hash_entry **end_hashes;
1067*3d8817e4Smiod   unsigned int symcount;
1068*3d8817e4Smiod 
1069*3d8817e4Smiod   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
1070*3d8817e4Smiod   sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
1071*3d8817e4Smiod   contents = elf_section_data (sec)->this_hdr.contents;
1072*3d8817e4Smiod 
1073*3d8817e4Smiod   /* The deletion must stop at the next ALIGN reloc for an aligment
1074*3d8817e4Smiod      power larger than the number of bytes we are deleting.  */
1075*3d8817e4Smiod 
1076*3d8817e4Smiod   irelalign = NULL;
1077*3d8817e4Smiod   toaddr = sec->size;
1078*3d8817e4Smiod 
1079*3d8817e4Smiod   irel = elf_section_data (sec)->relocs;
1080*3d8817e4Smiod   irelend = irel + sec->reloc_count;
1081*3d8817e4Smiod 
1082*3d8817e4Smiod   /* Actually delete the bytes.  */
1083*3d8817e4Smiod   if (toaddr - addr - count > 0)
1084*3d8817e4Smiod     memmove (contents + addr, contents + addr + count,
1085*3d8817e4Smiod              (size_t) (toaddr - addr - count));
1086*3d8817e4Smiod   sec->size -= count;
1087*3d8817e4Smiod 
1088*3d8817e4Smiod   /* Adjust all the relocs.  */
1089*3d8817e4Smiod   for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
1090*3d8817e4Smiod     {
1091*3d8817e4Smiod       bfd_vma symval;
1092*3d8817e4Smiod       bfd_vma old_reloc_address;
1093*3d8817e4Smiod       bfd_vma shrinked_insn_address;
1094*3d8817e4Smiod 
1095*3d8817e4Smiod       old_reloc_address = (sec->output_section->vma
1096*3d8817e4Smiod                            + sec->output_offset + irel->r_offset);
1097*3d8817e4Smiod       shrinked_insn_address = (sec->output_section->vma
1098*3d8817e4Smiod                               + sec->output_offset + addr - count);
1099*3d8817e4Smiod 
1100*3d8817e4Smiod       /* Get the new reloc address.  */
1101*3d8817e4Smiod       if ((irel->r_offset > addr
1102*3d8817e4Smiod            && irel->r_offset < toaddr))
1103*3d8817e4Smiod         {
1104*3d8817e4Smiod           if (DEBUG_RELAX)
1105*3d8817e4Smiod             printf ("Relocation at address 0x%x needs to be moved.\n"
1106*3d8817e4Smiod                     "Old section offset: 0x%x, New section offset: 0x%x \n",
1107*3d8817e4Smiod                     (unsigned int) old_reloc_address,
1108*3d8817e4Smiod                     (unsigned int) irel->r_offset,
1109*3d8817e4Smiod                     (unsigned int) ((irel->r_offset) - count));
1110*3d8817e4Smiod 
1111*3d8817e4Smiod           irel->r_offset -= count;
1112*3d8817e4Smiod         }
1113*3d8817e4Smiod 
1114*3d8817e4Smiod       /* The reloc's own addresses are now ok. However, we need to readjust
1115*3d8817e4Smiod          the reloc's addend if two conditions are met:
1116*3d8817e4Smiod          1.) the reloc is relative to a symbol in this section that
1117*3d8817e4Smiod              is located in front of the shrinked instruction
1118*3d8817e4Smiod          2.) symbol plus addend end up behind the shrinked instruction.
1119*3d8817e4Smiod 
1120*3d8817e4Smiod          This should happen only for local symbols that are progmem related.  */
1121*3d8817e4Smiod 
1122*3d8817e4Smiod       /* Read this BFD's local symbols if we haven't done so already.  */
1123*3d8817e4Smiod       if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1124*3d8817e4Smiod         {
1125*3d8817e4Smiod           isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1126*3d8817e4Smiod           if (isymbuf == NULL)
1127*3d8817e4Smiod             isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1128*3d8817e4Smiod                                             symtab_hdr->sh_info, 0,
1129*3d8817e4Smiod                                             NULL, NULL, NULL);
1130*3d8817e4Smiod           if (isymbuf == NULL)
1131*3d8817e4Smiod              return FALSE;
1132*3d8817e4Smiod          }
1133*3d8817e4Smiod 
1134*3d8817e4Smiod       /* Get the value of the symbol referred to by the reloc.  */
1135*3d8817e4Smiod       if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
1136*3d8817e4Smiod         {
1137*3d8817e4Smiod           /* A local symbol.  */
1138*3d8817e4Smiod           Elf_Internal_Sym *isym;
1139*3d8817e4Smiod           asection *sym_sec;
1140*3d8817e4Smiod 
1141*3d8817e4Smiod           isym = isymbuf + ELF32_R_SYM (irel->r_info);
1142*3d8817e4Smiod           sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1143*3d8817e4Smiod           symval = isym->st_value;
1144*3d8817e4Smiod           /* If the reloc is absolute, it will not have
1145*3d8817e4Smiod              a symbol or section associated with it.  */
1146*3d8817e4Smiod           if (sym_sec)
1147*3d8817e4Smiod             {
1148*3d8817e4Smiod                symval += sym_sec->output_section->vma
1149*3d8817e4Smiod                          + sym_sec->output_offset;
1150*3d8817e4Smiod 
1151*3d8817e4Smiod                if (DEBUG_RELAX)
1152*3d8817e4Smiod                 printf ("Checking if the relocation's "
1153*3d8817e4Smiod                         "addend needs corrections.\n"
1154*3d8817e4Smiod                         "Address of anchor symbol: 0x%x \n"
1155*3d8817e4Smiod                         "Address of relocation target: 0x%x \n"
1156*3d8817e4Smiod                         "Address of relaxed insn: 0x%x \n",
1157*3d8817e4Smiod                         (unsigned int) symval,
1158*3d8817e4Smiod                         (unsigned int) (symval + irel->r_addend),
1159*3d8817e4Smiod                         (unsigned int) shrinked_insn_address);
1160*3d8817e4Smiod 
1161*3d8817e4Smiod                if (symval <= shrinked_insn_address
1162*3d8817e4Smiod                    && (symval + irel->r_addend) > shrinked_insn_address)
1163*3d8817e4Smiod                  {
1164*3d8817e4Smiod                    irel->r_addend -= count;
1165*3d8817e4Smiod 
1166*3d8817e4Smiod                    if (DEBUG_RELAX)
1167*3d8817e4Smiod                      printf ("Anchor symbol and relocation target bracket "
1168*3d8817e4Smiod                              "shrinked insn address.\n"
1169*3d8817e4Smiod                              "Need for new addend : 0x%x\n",
1170*3d8817e4Smiod                              (unsigned int) irel->r_addend);
1171*3d8817e4Smiod                  }
1172*3d8817e4Smiod             }
1173*3d8817e4Smiod 	  /* else ... Reference symbol is absolute.  No adjustment needed.  */
1174*3d8817e4Smiod         }
1175*3d8817e4Smiod       /* else ... Reference symbol is extern. No need for adjusting the addend.  */
1176*3d8817e4Smiod     }
1177*3d8817e4Smiod 
1178*3d8817e4Smiod   /* Adjust the local symbols defined in this section.  */
1179*3d8817e4Smiod   isym = (Elf_Internal_Sym *) symtab_hdr->contents;
1180*3d8817e4Smiod   isymend = isym + symtab_hdr->sh_info;
1181*3d8817e4Smiod   for (; isym < isymend; isym++)
1182*3d8817e4Smiod     {
1183*3d8817e4Smiod       if (isym->st_shndx == sec_shndx
1184*3d8817e4Smiod           && isym->st_value > addr
1185*3d8817e4Smiod           && isym->st_value < toaddr)
1186*3d8817e4Smiod         isym->st_value -= count;
1187*3d8817e4Smiod     }
1188*3d8817e4Smiod 
1189*3d8817e4Smiod   /* Now adjust the global symbols defined in this section.  */
1190*3d8817e4Smiod   symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
1191*3d8817e4Smiod               - symtab_hdr->sh_info);
1192*3d8817e4Smiod   sym_hashes = elf_sym_hashes (abfd);
1193*3d8817e4Smiod   end_hashes = sym_hashes + symcount;
1194*3d8817e4Smiod   for (; sym_hashes < end_hashes; sym_hashes++)
1195*3d8817e4Smiod     {
1196*3d8817e4Smiod       struct elf_link_hash_entry *sym_hash = *sym_hashes;
1197*3d8817e4Smiod       if ((sym_hash->root.type == bfd_link_hash_defined
1198*3d8817e4Smiod            || sym_hash->root.type == bfd_link_hash_defweak)
1199*3d8817e4Smiod           && sym_hash->root.u.def.section == sec
1200*3d8817e4Smiod           && sym_hash->root.u.def.value > addr
1201*3d8817e4Smiod           && sym_hash->root.u.def.value < toaddr)
1202*3d8817e4Smiod         {
1203*3d8817e4Smiod           sym_hash->root.u.def.value -= count;
1204*3d8817e4Smiod         }
1205*3d8817e4Smiod     }
1206*3d8817e4Smiod 
1207*3d8817e4Smiod   return TRUE;
1208*3d8817e4Smiod }
1209*3d8817e4Smiod 
1210*3d8817e4Smiod /* This function handles relaxing for the avr.
1211*3d8817e4Smiod    Many important relaxing opportunities within functions are already
1212*3d8817e4Smiod    realized by the compiler itself.
1213*3d8817e4Smiod    Here we try to replace  call (4 bytes) ->  rcall (2 bytes)
1214*3d8817e4Smiod    and jump -> rjmp (safes also 2 bytes).
1215*3d8817e4Smiod    As well we now optimize seqences of
1216*3d8817e4Smiod      - call/rcall function
1217*3d8817e4Smiod      - ret
1218*3d8817e4Smiod    to yield
1219*3d8817e4Smiod      - jmp/rjmp function
1220*3d8817e4Smiod      - ret
1221*3d8817e4Smiod    . In case that within a sequence
1222*3d8817e4Smiod      - jmp/rjmp label
1223*3d8817e4Smiod      - ret
1224*3d8817e4Smiod    the ret could no longer be reached it is optimized away. In order
1225*3d8817e4Smiod    to check if the ret is no longer needed, it is checked that the ret's address
1226*3d8817e4Smiod    is not the target of a branch or jump within the same section, it is checked
1227*3d8817e4Smiod    that there is no skip instruction before the jmp/rjmp and that there
1228*3d8817e4Smiod    is no local or global label place at the address of the ret.
1229*3d8817e4Smiod 
1230*3d8817e4Smiod    We refrain from relaxing within sections ".vectors" and
1231*3d8817e4Smiod    ".jumptables" in order to maintain the position of the instructions.
1232*3d8817e4Smiod    There, however, we substitute jmp/call by a sequence rjmp,nop/rcall,nop
1233*3d8817e4Smiod    if possible. (In future one could possibly use the space of the nop
1234*3d8817e4Smiod    for the first instruction of the irq service function.
1235*3d8817e4Smiod 
1236*3d8817e4Smiod    The .jumptables sections is meant to be used for a future tablejump variant
1237*3d8817e4Smiod    for the devices with 3-byte program counter where the table itself
1238*3d8817e4Smiod    contains 4-byte jump instructions whose relative offset must not
1239*3d8817e4Smiod    be changed.  */
1240*3d8817e4Smiod 
1241*3d8817e4Smiod static  bfd_boolean
elf32_avr_relax_section(bfd * abfd,asection * sec,struct bfd_link_info * link_info,bfd_boolean * again)1242*3d8817e4Smiod elf32_avr_relax_section (bfd *abfd,
1243*3d8817e4Smiod 			 asection *sec,
1244*3d8817e4Smiod                          struct bfd_link_info *link_info,
1245*3d8817e4Smiod                          bfd_boolean *again)
1246*3d8817e4Smiod {
1247*3d8817e4Smiod   Elf_Internal_Shdr *symtab_hdr;
1248*3d8817e4Smiod   Elf_Internal_Rela *internal_relocs;
1249*3d8817e4Smiod   Elf_Internal_Rela *irel, *irelend;
1250*3d8817e4Smiod   bfd_byte *contents = NULL;
1251*3d8817e4Smiod   Elf_Internal_Sym *isymbuf = NULL;
1252*3d8817e4Smiod   static asection *last_input_section = NULL;
1253*3d8817e4Smiod   static Elf_Internal_Rela *last_reloc = NULL;
1254*3d8817e4Smiod 
1255*3d8817e4Smiod   /* Assume nothing changes.  */
1256*3d8817e4Smiod   *again = FALSE;
1257*3d8817e4Smiod 
1258*3d8817e4Smiod   /* We don't have to do anything for a relocatable link, if
1259*3d8817e4Smiod      this section does not have relocs, or if this is not a
1260*3d8817e4Smiod      code section.  */
1261*3d8817e4Smiod   if (link_info->relocatable
1262*3d8817e4Smiod       || (sec->flags & SEC_RELOC) == 0
1263*3d8817e4Smiod       || sec->reloc_count == 0
1264*3d8817e4Smiod       || (sec->flags & SEC_CODE) == 0)
1265*3d8817e4Smiod     return TRUE;
1266*3d8817e4Smiod 
1267*3d8817e4Smiod   /* Check if the object file to relax uses internal symbols so that we
1268*3d8817e4Smiod      could fix up the relocations.  */
1269*3d8817e4Smiod   if (!(elf_elfheader (abfd)->e_flags & EF_AVR_LINKRELAX_PREPARED))
1270*3d8817e4Smiod     return TRUE;
1271*3d8817e4Smiod 
1272*3d8817e4Smiod   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
1273*3d8817e4Smiod 
1274*3d8817e4Smiod   /* Get a copy of the native relocations.  */
1275*3d8817e4Smiod   internal_relocs = (_bfd_elf_link_read_relocs
1276*3d8817e4Smiod                      (abfd, sec, NULL, NULL, link_info->keep_memory));
1277*3d8817e4Smiod   if (internal_relocs == NULL)
1278*3d8817e4Smiod     goto error_return;
1279*3d8817e4Smiod 
1280*3d8817e4Smiod   if (sec != last_input_section)
1281*3d8817e4Smiod     last_reloc = NULL;
1282*3d8817e4Smiod 
1283*3d8817e4Smiod   last_input_section = sec;
1284*3d8817e4Smiod 
1285*3d8817e4Smiod   /* Walk through the relocs looking for relaxing opportunities.  */
1286*3d8817e4Smiod   irelend = internal_relocs + sec->reloc_count;
1287*3d8817e4Smiod   for (irel = internal_relocs; irel < irelend; irel++)
1288*3d8817e4Smiod     {
1289*3d8817e4Smiod       bfd_vma symval;
1290*3d8817e4Smiod 
1291*3d8817e4Smiod       if (   ELF32_R_TYPE (irel->r_info) != R_AVR_13_PCREL
1292*3d8817e4Smiod           && ELF32_R_TYPE (irel->r_info) != R_AVR_7_PCREL
1293*3d8817e4Smiod           && ELF32_R_TYPE (irel->r_info) != R_AVR_CALL)
1294*3d8817e4Smiod         continue;
1295*3d8817e4Smiod 
1296*3d8817e4Smiod       /* Get the section contents if we haven't done so already.  */
1297*3d8817e4Smiod       if (contents == NULL)
1298*3d8817e4Smiod         {
1299*3d8817e4Smiod           /* Get cached copy if it exists.  */
1300*3d8817e4Smiod           if (elf_section_data (sec)->this_hdr.contents != NULL)
1301*3d8817e4Smiod             contents = elf_section_data (sec)->this_hdr.contents;
1302*3d8817e4Smiod           else
1303*3d8817e4Smiod             {
1304*3d8817e4Smiod               /* Go get them off disk.  */
1305*3d8817e4Smiod               if (! bfd_malloc_and_get_section (abfd, sec, &contents))
1306*3d8817e4Smiod                 goto error_return;
1307*3d8817e4Smiod             }
1308*3d8817e4Smiod         }
1309*3d8817e4Smiod 
1310*3d8817e4Smiod      /* Read this BFD's local symbols if we haven't done so already.  */
1311*3d8817e4Smiod       if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1312*3d8817e4Smiod         {
1313*3d8817e4Smiod           isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1314*3d8817e4Smiod           if (isymbuf == NULL)
1315*3d8817e4Smiod             isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1316*3d8817e4Smiod                                             symtab_hdr->sh_info, 0,
1317*3d8817e4Smiod                                             NULL, NULL, NULL);
1318*3d8817e4Smiod           if (isymbuf == NULL)
1319*3d8817e4Smiod             goto error_return;
1320*3d8817e4Smiod         }
1321*3d8817e4Smiod 
1322*3d8817e4Smiod 
1323*3d8817e4Smiod       /* Get the value of the symbol referred to by the reloc.  */
1324*3d8817e4Smiod       if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
1325*3d8817e4Smiod         {
1326*3d8817e4Smiod           /* A local symbol.  */
1327*3d8817e4Smiod           Elf_Internal_Sym *isym;
1328*3d8817e4Smiod           asection *sym_sec;
1329*3d8817e4Smiod 
1330*3d8817e4Smiod           isym = isymbuf + ELF32_R_SYM (irel->r_info);
1331*3d8817e4Smiod           sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1332*3d8817e4Smiod           symval = isym->st_value;
1333*3d8817e4Smiod           /* If the reloc is absolute, it will not have
1334*3d8817e4Smiod              a symbol or section associated with it.  */
1335*3d8817e4Smiod           if (sym_sec)
1336*3d8817e4Smiod             symval += sym_sec->output_section->vma
1337*3d8817e4Smiod               + sym_sec->output_offset;
1338*3d8817e4Smiod         }
1339*3d8817e4Smiod       else
1340*3d8817e4Smiod         {
1341*3d8817e4Smiod           unsigned long indx;
1342*3d8817e4Smiod           struct elf_link_hash_entry *h;
1343*3d8817e4Smiod 
1344*3d8817e4Smiod           /* An external symbol.  */
1345*3d8817e4Smiod           indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
1346*3d8817e4Smiod           h = elf_sym_hashes (abfd)[indx];
1347*3d8817e4Smiod           BFD_ASSERT (h != NULL);
1348*3d8817e4Smiod           if (h->root.type != bfd_link_hash_defined
1349*3d8817e4Smiod               && h->root.type != bfd_link_hash_defweak)
1350*3d8817e4Smiod 	    /* This appears to be a reference to an undefined
1351*3d8817e4Smiod 	       symbol.  Just ignore it--it will be caught by the
1352*3d8817e4Smiod 	       regular reloc processing.  */
1353*3d8817e4Smiod 	    continue;
1354*3d8817e4Smiod 
1355*3d8817e4Smiod           symval = (h->root.u.def.value
1356*3d8817e4Smiod                     + h->root.u.def.section->output_section->vma
1357*3d8817e4Smiod                     + h->root.u.def.section->output_offset);
1358*3d8817e4Smiod         }
1359*3d8817e4Smiod 
1360*3d8817e4Smiod       /* For simplicity of coding, we are going to modify the section
1361*3d8817e4Smiod          contents, the section relocs, and the BFD symbol table.  We
1362*3d8817e4Smiod          must tell the rest of the code not to free up this
1363*3d8817e4Smiod          information.  It would be possible to instead create a table
1364*3d8817e4Smiod          of changes which have to be made, as is done in coff-mips.c;
1365*3d8817e4Smiod          that would be more work, but would require less memory when
1366*3d8817e4Smiod          the linker is run.  */
1367*3d8817e4Smiod       switch (ELF32_R_TYPE (irel->r_info))
1368*3d8817e4Smiod         {
1369*3d8817e4Smiod          /* Try to turn a 22-bit absolute call/jump into an 13-bit
1370*3d8817e4Smiod             pc-relative rcall/rjmp.  */
1371*3d8817e4Smiod          case R_AVR_CALL:
1372*3d8817e4Smiod           {
1373*3d8817e4Smiod             bfd_vma value = symval + irel->r_addend;
1374*3d8817e4Smiod             bfd_vma dot, gap;
1375*3d8817e4Smiod             int distance_short_enough = 0;
1376*3d8817e4Smiod 
1377*3d8817e4Smiod             /* Get the address of this instruction.  */
1378*3d8817e4Smiod             dot = (sec->output_section->vma
1379*3d8817e4Smiod                    + sec->output_offset + irel->r_offset);
1380*3d8817e4Smiod 
1381*3d8817e4Smiod             /* Compute the distance from this insn to the branch target.  */
1382*3d8817e4Smiod             gap = value - dot;
1383*3d8817e4Smiod 
1384*3d8817e4Smiod             /* If the distance is within -4094..+4098 inclusive, then we can
1385*3d8817e4Smiod                relax this jump/call.  +4098 because the call/jump target
1386*3d8817e4Smiod                will be closer after the relaxation.  */
1387*3d8817e4Smiod             if ((int) gap >= -4094 && (int) gap <= 4098)
1388*3d8817e4Smiod               distance_short_enough = 1;
1389*3d8817e4Smiod 
1390*3d8817e4Smiod             /* Here we handle the wrap-around case.  E.g. for a 16k device
1391*3d8817e4Smiod                we could use a rjmp to jump from address 0x100 to 0x3d00!
1392*3d8817e4Smiod                In order to make this work properly, we need to fill the
1393*3d8817e4Smiod                vaiable avr_pc_wrap_around with the appropriate value.
1394*3d8817e4Smiod                I.e. 0x4000 for a 16k device.  */
1395*3d8817e4Smiod             {
1396*3d8817e4Smiod                /* Shrinking the code size makes the gaps larger in the
1397*3d8817e4Smiod                   case of wrap-arounds.  So we use a heuristical safety
1398*3d8817e4Smiod                   margin to avoid that during relax the distance gets
1399*3d8817e4Smiod                   again too large for the short jumps.  Let's assume
1400*3d8817e4Smiod                   a typical code-size reduction due to relax for a
1401*3d8817e4Smiod                   16k device of 600 bytes.  So let's use twice the
1402*3d8817e4Smiod                   typical value as safety margin.  */
1403*3d8817e4Smiod                int rgap;
1404*3d8817e4Smiod                int safety_margin;
1405*3d8817e4Smiod 
1406*3d8817e4Smiod                int assumed_shrink = 600;
1407*3d8817e4Smiod                if (avr_pc_wrap_around > 0x4000)
1408*3d8817e4Smiod                  assumed_shrink = 900;
1409*3d8817e4Smiod 
1410*3d8817e4Smiod                safety_margin = 2 * assumed_shrink;
1411*3d8817e4Smiod 
1412*3d8817e4Smiod                rgap = avr_relative_distance_considering_wrap_around (gap);
1413*3d8817e4Smiod 
1414*3d8817e4Smiod                if (rgap >= (-4092 + safety_margin)
1415*3d8817e4Smiod                    && rgap <= (4094 - safety_margin))
1416*3d8817e4Smiod 		 distance_short_enough = 1;
1417*3d8817e4Smiod             }
1418*3d8817e4Smiod 
1419*3d8817e4Smiod             if (distance_short_enough)
1420*3d8817e4Smiod               {
1421*3d8817e4Smiod                 unsigned char code_msb;
1422*3d8817e4Smiod                 unsigned char code_lsb;
1423*3d8817e4Smiod 
1424*3d8817e4Smiod                 if (DEBUG_RELAX)
1425*3d8817e4Smiod                   printf ("shrinking jump/call instruction at address 0x%x"
1426*3d8817e4Smiod                           " in section %s\n\n",
1427*3d8817e4Smiod                           (int) dot, sec->name);
1428*3d8817e4Smiod 
1429*3d8817e4Smiod                 /* Note that we've changed the relocs, section contents,
1430*3d8817e4Smiod                    etc.  */
1431*3d8817e4Smiod                 elf_section_data (sec)->relocs = internal_relocs;
1432*3d8817e4Smiod                 elf_section_data (sec)->this_hdr.contents = contents;
1433*3d8817e4Smiod                 symtab_hdr->contents = (unsigned char *) isymbuf;
1434*3d8817e4Smiod 
1435*3d8817e4Smiod                 /* Get the instruction code for relaxing.  */
1436*3d8817e4Smiod                 code_lsb = bfd_get_8 (abfd, contents + irel->r_offset);
1437*3d8817e4Smiod                 code_msb = bfd_get_8 (abfd, contents + irel->r_offset + 1);
1438*3d8817e4Smiod 
1439*3d8817e4Smiod                 /* Mask out the relocation bits.  */
1440*3d8817e4Smiod                 code_msb &= 0x94;
1441*3d8817e4Smiod                 code_lsb &= 0x0E;
1442*3d8817e4Smiod                 if (code_msb == 0x94 && code_lsb == 0x0E)
1443*3d8817e4Smiod                   {
1444*3d8817e4Smiod                     /* we are changing call -> rcall .  */
1445*3d8817e4Smiod                     bfd_put_8 (abfd, 0x00, contents + irel->r_offset);
1446*3d8817e4Smiod                     bfd_put_8 (abfd, 0xD0, contents + irel->r_offset + 1);
1447*3d8817e4Smiod                   }
1448*3d8817e4Smiod                 else if (code_msb == 0x94 && code_lsb == 0x0C)
1449*3d8817e4Smiod                   {
1450*3d8817e4Smiod                     /* we are changeing jump -> rjmp.  */
1451*3d8817e4Smiod                     bfd_put_8 (abfd, 0x00, contents + irel->r_offset);
1452*3d8817e4Smiod                     bfd_put_8 (abfd, 0xC0, contents + irel->r_offset + 1);
1453*3d8817e4Smiod                   }
1454*3d8817e4Smiod                 else
1455*3d8817e4Smiod                   abort ();
1456*3d8817e4Smiod 
1457*3d8817e4Smiod                 /* Fix the relocation's type.  */
1458*3d8817e4Smiod                 irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1459*3d8817e4Smiod                                              R_AVR_13_PCREL);
1460*3d8817e4Smiod 
1461*3d8817e4Smiod                 /* Check for the vector section. There we don't want to
1462*3d8817e4Smiod                    modify the ordering!  */
1463*3d8817e4Smiod 
1464*3d8817e4Smiod                 if (!strcmp (sec->name,".vectors")
1465*3d8817e4Smiod                     || !strcmp (sec->name,".jumptables"))
1466*3d8817e4Smiod                   {
1467*3d8817e4Smiod                     /* Let's insert a nop.  */
1468*3d8817e4Smiod                     bfd_put_8 (abfd, 0x00, contents + irel->r_offset + 2);
1469*3d8817e4Smiod                     bfd_put_8 (abfd, 0x00, contents + irel->r_offset + 3);
1470*3d8817e4Smiod                   }
1471*3d8817e4Smiod                 else
1472*3d8817e4Smiod                   {
1473*3d8817e4Smiod                     /* Delete two bytes of data.  */
1474*3d8817e4Smiod                     if (!elf32_avr_relax_delete_bytes (abfd, sec,
1475*3d8817e4Smiod                                                        irel->r_offset + 2, 2))
1476*3d8817e4Smiod                       goto error_return;
1477*3d8817e4Smiod 
1478*3d8817e4Smiod                     /* That will change things, so, we should relax again.
1479*3d8817e4Smiod                        Note that this is not required, and it may be slow.  */
1480*3d8817e4Smiod                     *again = TRUE;
1481*3d8817e4Smiod                   }
1482*3d8817e4Smiod               }
1483*3d8817e4Smiod           }
1484*3d8817e4Smiod 
1485*3d8817e4Smiod         default:
1486*3d8817e4Smiod           {
1487*3d8817e4Smiod             unsigned char code_msb;
1488*3d8817e4Smiod             unsigned char code_lsb;
1489*3d8817e4Smiod             bfd_vma dot;
1490*3d8817e4Smiod 
1491*3d8817e4Smiod             code_msb = bfd_get_8 (abfd, contents + irel->r_offset + 1);
1492*3d8817e4Smiod             code_lsb = bfd_get_8 (abfd, contents + irel->r_offset + 0);
1493*3d8817e4Smiod 
1494*3d8817e4Smiod             /* Get the address of this instruction.  */
1495*3d8817e4Smiod             dot = (sec->output_section->vma
1496*3d8817e4Smiod                    + sec->output_offset + irel->r_offset);
1497*3d8817e4Smiod 
1498*3d8817e4Smiod             /* Here we look for rcall/ret or call/ret sequences that could be
1499*3d8817e4Smiod                safely replaced by rjmp/ret or jmp/ret */
1500*3d8817e4Smiod             if (0xd0 == (code_msb & 0xf0))
1501*3d8817e4Smiod               {
1502*3d8817e4Smiod                 /* This insn is a rcall.  */
1503*3d8817e4Smiod                 unsigned char next_insn_msb = 0;
1504*3d8817e4Smiod                 unsigned char next_insn_lsb = 0;
1505*3d8817e4Smiod 
1506*3d8817e4Smiod                 if (irel->r_offset + 3 < sec->size)
1507*3d8817e4Smiod                   {
1508*3d8817e4Smiod                     next_insn_msb =
1509*3d8817e4Smiod                         bfd_get_8 (abfd, contents + irel->r_offset + 3);
1510*3d8817e4Smiod                     next_insn_lsb =
1511*3d8817e4Smiod                         bfd_get_8 (abfd, contents + irel->r_offset + 2);
1512*3d8817e4Smiod                   }
1513*3d8817e4Smiod 
1514*3d8817e4Smiod 		if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb))
1515*3d8817e4Smiod                   {
1516*3d8817e4Smiod                     /* The next insn is a ret. We now convert the rcall insn
1517*3d8817e4Smiod                        into a rjmp instruction.  */
1518*3d8817e4Smiod                     code_msb &= 0xef;
1519*3d8817e4Smiod                     bfd_put_8 (abfd, code_msb, contents + irel->r_offset + 1);
1520*3d8817e4Smiod                     if (DEBUG_RELAX)
1521*3d8817e4Smiod                       printf ("converted rcall/ret sequence at address 0x%x"
1522*3d8817e4Smiod                               " into rjmp/ret sequence. Section is %s\n\n",
1523*3d8817e4Smiod                               (int) dot, sec->name);
1524*3d8817e4Smiod                     *again = TRUE;
1525*3d8817e4Smiod                     break;
1526*3d8817e4Smiod                   }
1527*3d8817e4Smiod               }
1528*3d8817e4Smiod             else if ((0x94 == (code_msb & 0xfe))
1529*3d8817e4Smiod                       && (0x0e == (code_lsb & 0x0e)))
1530*3d8817e4Smiod               {
1531*3d8817e4Smiod                 /* This insn is a call.  */
1532*3d8817e4Smiod                 unsigned char next_insn_msb = 0;
1533*3d8817e4Smiod                 unsigned char next_insn_lsb = 0;
1534*3d8817e4Smiod 
1535*3d8817e4Smiod                 if (irel->r_offset + 5 < sec->size)
1536*3d8817e4Smiod                   {
1537*3d8817e4Smiod                     next_insn_msb =
1538*3d8817e4Smiod                         bfd_get_8 (abfd, contents + irel->r_offset + 5);
1539*3d8817e4Smiod                     next_insn_lsb =
1540*3d8817e4Smiod                         bfd_get_8 (abfd, contents + irel->r_offset + 4);
1541*3d8817e4Smiod                   }
1542*3d8817e4Smiod 
1543*3d8817e4Smiod                 if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb))
1544*3d8817e4Smiod                   {
1545*3d8817e4Smiod                     /* The next insn is a ret. We now convert the call insn
1546*3d8817e4Smiod                        into a jmp instruction.  */
1547*3d8817e4Smiod 
1548*3d8817e4Smiod                     code_lsb &= 0xfd;
1549*3d8817e4Smiod                     bfd_put_8 (abfd, code_lsb, contents + irel->r_offset);
1550*3d8817e4Smiod                     if (DEBUG_RELAX)
1551*3d8817e4Smiod                       printf ("converted call/ret sequence at address 0x%x"
1552*3d8817e4Smiod                               " into jmp/ret sequence. Section is %s\n\n",
1553*3d8817e4Smiod                               (int) dot, sec->name);
1554*3d8817e4Smiod                     *again = TRUE;
1555*3d8817e4Smiod                     break;
1556*3d8817e4Smiod                   }
1557*3d8817e4Smiod               }
1558*3d8817e4Smiod             else if ((0xc0 == (code_msb & 0xf0))
1559*3d8817e4Smiod                      || ((0x94 == (code_msb & 0xfe))
1560*3d8817e4Smiod                          && (0x0c == (code_lsb & 0x0e))))
1561*3d8817e4Smiod               {
1562*3d8817e4Smiod                 /* This insn is a rjmp or a jmp.  */
1563*3d8817e4Smiod                 unsigned char next_insn_msb = 0;
1564*3d8817e4Smiod                 unsigned char next_insn_lsb = 0;
1565*3d8817e4Smiod                 int insn_size;
1566*3d8817e4Smiod 
1567*3d8817e4Smiod                 if (0xc0 == (code_msb & 0xf0))
1568*3d8817e4Smiod                   insn_size = 2; /* rjmp insn */
1569*3d8817e4Smiod                 else
1570*3d8817e4Smiod                   insn_size = 4; /* jmp insn */
1571*3d8817e4Smiod 
1572*3d8817e4Smiod                 if (irel->r_offset + insn_size + 1 < sec->size)
1573*3d8817e4Smiod                   {
1574*3d8817e4Smiod                     next_insn_msb =
1575*3d8817e4Smiod                         bfd_get_8 (abfd, contents + irel->r_offset
1576*3d8817e4Smiod                                          + insn_size + 1);
1577*3d8817e4Smiod                     next_insn_lsb =
1578*3d8817e4Smiod                         bfd_get_8 (abfd, contents + irel->r_offset
1579*3d8817e4Smiod                                          + insn_size);
1580*3d8817e4Smiod                   }
1581*3d8817e4Smiod 
1582*3d8817e4Smiod                 if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb))
1583*3d8817e4Smiod                   {
1584*3d8817e4Smiod                     /* The next insn is a ret. We possibly could delete
1585*3d8817e4Smiod                        this ret. First we need to check for preceeding
1586*3d8817e4Smiod                        sbis/sbic/sbrs or cpse "skip" instructions.  */
1587*3d8817e4Smiod 
1588*3d8817e4Smiod                     int there_is_preceeding_non_skip_insn = 1;
1589*3d8817e4Smiod                     bfd_vma address_of_ret;
1590*3d8817e4Smiod 
1591*3d8817e4Smiod                     address_of_ret = dot + insn_size;
1592*3d8817e4Smiod 
1593*3d8817e4Smiod                     if (DEBUG_RELAX && (insn_size == 2))
1594*3d8817e4Smiod                       printf ("found rjmp / ret sequence at address 0x%x\n",
1595*3d8817e4Smiod                               (int) dot);
1596*3d8817e4Smiod                     if (DEBUG_RELAX && (insn_size == 4))
1597*3d8817e4Smiod                       printf ("found jmp / ret sequence at address 0x%x\n",
1598*3d8817e4Smiod                               (int) dot);
1599*3d8817e4Smiod 
1600*3d8817e4Smiod                     /* We have to make sure that there is a preceeding insn.  */
1601*3d8817e4Smiod                     if (irel->r_offset >= 2)
1602*3d8817e4Smiod                       {
1603*3d8817e4Smiod                         unsigned char preceeding_msb;
1604*3d8817e4Smiod                         unsigned char preceeding_lsb;
1605*3d8817e4Smiod                         preceeding_msb =
1606*3d8817e4Smiod                             bfd_get_8 (abfd, contents + irel->r_offset - 1);
1607*3d8817e4Smiod                         preceeding_lsb =
1608*3d8817e4Smiod                             bfd_get_8 (abfd, contents + irel->r_offset - 2);
1609*3d8817e4Smiod 
1610*3d8817e4Smiod                         /* sbic.  */
1611*3d8817e4Smiod                         if (0x99 == preceeding_msb)
1612*3d8817e4Smiod                           there_is_preceeding_non_skip_insn = 0;
1613*3d8817e4Smiod 
1614*3d8817e4Smiod                         /* sbis.  */
1615*3d8817e4Smiod                         if (0x9b == preceeding_msb)
1616*3d8817e4Smiod                           there_is_preceeding_non_skip_insn = 0;
1617*3d8817e4Smiod 
1618*3d8817e4Smiod                         /* sbrc */
1619*3d8817e4Smiod                         if ((0xfc == (preceeding_msb & 0xfe)
1620*3d8817e4Smiod                             && (0x00 == (preceeding_lsb & 0x08))))
1621*3d8817e4Smiod                           there_is_preceeding_non_skip_insn = 0;
1622*3d8817e4Smiod 
1623*3d8817e4Smiod                         /* sbrs */
1624*3d8817e4Smiod                         if ((0xfe == (preceeding_msb & 0xfe)
1625*3d8817e4Smiod                             && (0x00 == (preceeding_lsb & 0x08))))
1626*3d8817e4Smiod                           there_is_preceeding_non_skip_insn = 0;
1627*3d8817e4Smiod 
1628*3d8817e4Smiod                         /* cpse */
1629*3d8817e4Smiod                         if (0x10 == (preceeding_msb & 0xfc))
1630*3d8817e4Smiod                           there_is_preceeding_non_skip_insn = 0;
1631*3d8817e4Smiod 
1632*3d8817e4Smiod                         if (there_is_preceeding_non_skip_insn == 0)
1633*3d8817e4Smiod                           if (DEBUG_RELAX)
1634*3d8817e4Smiod                             printf ("preceeding skip insn prevents deletion of"
1635*3d8817e4Smiod                                     " ret insn at addr 0x%x in section %s\n",
1636*3d8817e4Smiod                                     (int) dot + 2, sec->name);
1637*3d8817e4Smiod                       }
1638*3d8817e4Smiod                     else
1639*3d8817e4Smiod                       {
1640*3d8817e4Smiod                         /* There is no previous instruction.  */
1641*3d8817e4Smiod                         there_is_preceeding_non_skip_insn = 0;
1642*3d8817e4Smiod                       }
1643*3d8817e4Smiod 
1644*3d8817e4Smiod                     if (there_is_preceeding_non_skip_insn)
1645*3d8817e4Smiod                       {
1646*3d8817e4Smiod                         /* We now only have to make sure that there is no
1647*3d8817e4Smiod                            local label defined at the address of the ret
1648*3d8817e4Smiod                            instruction and that there is no local relocation
1649*3d8817e4Smiod                            in this section pointing to the ret.  */
1650*3d8817e4Smiod 
1651*3d8817e4Smiod                         int deleting_ret_is_safe = 1;
1652*3d8817e4Smiod                         unsigned int section_offset_of_ret_insn =
1653*3d8817e4Smiod                                           irel->r_offset + insn_size;
1654*3d8817e4Smiod                         Elf_Internal_Sym *isym, *isymend;
1655*3d8817e4Smiod                         unsigned int sec_shndx;
1656*3d8817e4Smiod 
1657*3d8817e4Smiod                         sec_shndx =
1658*3d8817e4Smiod 			  _bfd_elf_section_from_bfd_section (abfd, sec);
1659*3d8817e4Smiod 
1660*3d8817e4Smiod                         /* Check for local symbols.  */
1661*3d8817e4Smiod                         isym = (Elf_Internal_Sym *) symtab_hdr->contents;
1662*3d8817e4Smiod                         isymend = isym + symtab_hdr->sh_info;
1663*3d8817e4Smiod                         for (; isym < isymend; isym++)
1664*3d8817e4Smiod                          {
1665*3d8817e4Smiod                            if (isym->st_value == section_offset_of_ret_insn
1666*3d8817e4Smiod                                && isym->st_shndx == sec_shndx)
1667*3d8817e4Smiod                              {
1668*3d8817e4Smiod                                deleting_ret_is_safe = 0;
1669*3d8817e4Smiod                                if (DEBUG_RELAX)
1670*3d8817e4Smiod                                  printf ("local label prevents deletion of ret "
1671*3d8817e4Smiod                                          "insn at address 0x%x\n",
1672*3d8817e4Smiod                                          (int) dot + insn_size);
1673*3d8817e4Smiod                              }
1674*3d8817e4Smiod                          }
1675*3d8817e4Smiod 
1676*3d8817e4Smiod                          /* Now check for global symbols.  */
1677*3d8817e4Smiod                          {
1678*3d8817e4Smiod                            int symcount;
1679*3d8817e4Smiod                            struct elf_link_hash_entry **sym_hashes;
1680*3d8817e4Smiod                            struct elf_link_hash_entry **end_hashes;
1681*3d8817e4Smiod 
1682*3d8817e4Smiod                            symcount = (symtab_hdr->sh_size
1683*3d8817e4Smiod                                        / sizeof (Elf32_External_Sym)
1684*3d8817e4Smiod                                        - symtab_hdr->sh_info);
1685*3d8817e4Smiod                            sym_hashes = elf_sym_hashes (abfd);
1686*3d8817e4Smiod                            end_hashes = sym_hashes + symcount;
1687*3d8817e4Smiod                            for (; sym_hashes < end_hashes; sym_hashes++)
1688*3d8817e4Smiod                             {
1689*3d8817e4Smiod                               struct elf_link_hash_entry *sym_hash =
1690*3d8817e4Smiod                                                                  *sym_hashes;
1691*3d8817e4Smiod                               if ((sym_hash->root.type == bfd_link_hash_defined
1692*3d8817e4Smiod                                   || sym_hash->root.type ==
1693*3d8817e4Smiod 				   bfd_link_hash_defweak)
1694*3d8817e4Smiod                                   && sym_hash->root.u.def.section == sec
1695*3d8817e4Smiod                                   && sym_hash->root.u.def.value == section_offset_of_ret_insn)
1696*3d8817e4Smiod                                 {
1697*3d8817e4Smiod                                   deleting_ret_is_safe = 0;
1698*3d8817e4Smiod                                   if (DEBUG_RELAX)
1699*3d8817e4Smiod                                     printf ("global label prevents deletion of "
1700*3d8817e4Smiod                                             "ret insn at address 0x%x\n",
1701*3d8817e4Smiod                                             (int) dot + insn_size);
1702*3d8817e4Smiod                                 }
1703*3d8817e4Smiod                             }
1704*3d8817e4Smiod                          }
1705*3d8817e4Smiod                          /* Now we check for relocations pointing to ret.  */
1706*3d8817e4Smiod                          {
1707*3d8817e4Smiod                            Elf_Internal_Rela *irel;
1708*3d8817e4Smiod                            Elf_Internal_Rela *relend;
1709*3d8817e4Smiod                            Elf_Internal_Shdr *symtab_hdr;
1710*3d8817e4Smiod 
1711*3d8817e4Smiod                            symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
1712*3d8817e4Smiod                            relend = elf_section_data (sec)->relocs
1713*3d8817e4Smiod                                     + sec->reloc_count;
1714*3d8817e4Smiod 
1715*3d8817e4Smiod                            for (irel = elf_section_data (sec)->relocs;
1716*3d8817e4Smiod                                 irel < relend; irel++)
1717*3d8817e4Smiod                              {
1718*3d8817e4Smiod                                bfd_vma reloc_target = 0;
1719*3d8817e4Smiod                                bfd_vma symval;
1720*3d8817e4Smiod                                Elf_Internal_Sym *isymbuf = NULL;
1721*3d8817e4Smiod 
1722*3d8817e4Smiod                                /* Read this BFD's local symbols if we haven't
1723*3d8817e4Smiod                                   done so already.  */
1724*3d8817e4Smiod                                if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1725*3d8817e4Smiod                                  {
1726*3d8817e4Smiod                                    isymbuf = (Elf_Internal_Sym *)
1727*3d8817e4Smiod                                              symtab_hdr->contents;
1728*3d8817e4Smiod                                    if (isymbuf == NULL)
1729*3d8817e4Smiod                                      isymbuf = bfd_elf_get_elf_syms
1730*3d8817e4Smiod 				       (abfd,
1731*3d8817e4Smiod 					symtab_hdr,
1732*3d8817e4Smiod 					symtab_hdr->sh_info, 0,
1733*3d8817e4Smiod 					NULL, NULL, NULL);
1734*3d8817e4Smiod                                    if (isymbuf == NULL)
1735*3d8817e4Smiod                                      break;
1736*3d8817e4Smiod                                   }
1737*3d8817e4Smiod 
1738*3d8817e4Smiod                                /* Get the value of the symbol referred to
1739*3d8817e4Smiod                                   by the reloc.  */
1740*3d8817e4Smiod                                if (ELF32_R_SYM (irel->r_info)
1741*3d8817e4Smiod                                    < symtab_hdr->sh_info)
1742*3d8817e4Smiod                                  {
1743*3d8817e4Smiod                                    /* A local symbol.  */
1744*3d8817e4Smiod                                    Elf_Internal_Sym *isym;
1745*3d8817e4Smiod                                    asection *sym_sec;
1746*3d8817e4Smiod 
1747*3d8817e4Smiod                                    isym = isymbuf
1748*3d8817e4Smiod                                           + ELF32_R_SYM (irel->r_info);
1749*3d8817e4Smiod                                    sym_sec = bfd_section_from_elf_index
1750*3d8817e4Smiod 				     (abfd, isym->st_shndx);
1751*3d8817e4Smiod                                    symval = isym->st_value;
1752*3d8817e4Smiod 
1753*3d8817e4Smiod                                    /* If the reloc is absolute, it will not
1754*3d8817e4Smiod                                       have a symbol or section associated
1755*3d8817e4Smiod                                       with it.  */
1756*3d8817e4Smiod 
1757*3d8817e4Smiod                                    if (sym_sec)
1758*3d8817e4Smiod                                      {
1759*3d8817e4Smiod                                        symval +=
1760*3d8817e4Smiod                                            sym_sec->output_section->vma
1761*3d8817e4Smiod                                            + sym_sec->output_offset;
1762*3d8817e4Smiod                                        reloc_target = symval + irel->r_addend;
1763*3d8817e4Smiod                                      }
1764*3d8817e4Smiod                                    else
1765*3d8817e4Smiod                                      {
1766*3d8817e4Smiod                                        reloc_target = symval + irel->r_addend;
1767*3d8817e4Smiod                                        /* Reference symbol is absolute.  */
1768*3d8817e4Smiod                                      }
1769*3d8817e4Smiod                                  }
1770*3d8817e4Smiod 			       /* else ... reference symbol is extern.  */
1771*3d8817e4Smiod 
1772*3d8817e4Smiod                                if (address_of_ret == reloc_target)
1773*3d8817e4Smiod                                  {
1774*3d8817e4Smiod                                    deleting_ret_is_safe = 0;
1775*3d8817e4Smiod                                    if (DEBUG_RELAX)
1776*3d8817e4Smiod                                      printf ("ret from "
1777*3d8817e4Smiod                                              "rjmp/jmp ret sequence at address"
1778*3d8817e4Smiod                                              " 0x%x could not be deleted. ret"
1779*3d8817e4Smiod                                              " is target of a relocation.\n",
1780*3d8817e4Smiod                                              (int) address_of_ret);
1781*3d8817e4Smiod                                  }
1782*3d8817e4Smiod                              }
1783*3d8817e4Smiod                          }
1784*3d8817e4Smiod 
1785*3d8817e4Smiod                          if (deleting_ret_is_safe)
1786*3d8817e4Smiod                            {
1787*3d8817e4Smiod                              if (DEBUG_RELAX)
1788*3d8817e4Smiod                                printf ("unreachable ret instruction "
1789*3d8817e4Smiod                                        "at address 0x%x deleted.\n",
1790*3d8817e4Smiod                                        (int) dot + insn_size);
1791*3d8817e4Smiod 
1792*3d8817e4Smiod                              /* Delete two bytes of data.  */
1793*3d8817e4Smiod                              if (!elf32_avr_relax_delete_bytes (abfd, sec,
1794*3d8817e4Smiod                                         irel->r_offset + insn_size, 2))
1795*3d8817e4Smiod                                goto error_return;
1796*3d8817e4Smiod 
1797*3d8817e4Smiod                              /* That will change things, so, we should relax
1798*3d8817e4Smiod                                 again. Note that this is not required, and it
1799*3d8817e4Smiod                                 may be slow.  */
1800*3d8817e4Smiod                              *again = TRUE;
1801*3d8817e4Smiod                              break;
1802*3d8817e4Smiod                            }
1803*3d8817e4Smiod                       }
1804*3d8817e4Smiod 
1805*3d8817e4Smiod                   }
1806*3d8817e4Smiod               }
1807*3d8817e4Smiod             break;
1808*3d8817e4Smiod           }
1809*3d8817e4Smiod         }
1810*3d8817e4Smiod     }
1811*3d8817e4Smiod 
1812*3d8817e4Smiod   if (contents != NULL
1813*3d8817e4Smiod       && elf_section_data (sec)->this_hdr.contents != contents)
1814*3d8817e4Smiod     {
1815*3d8817e4Smiod       if (! link_info->keep_memory)
1816*3d8817e4Smiod         free (contents);
1817*3d8817e4Smiod       else
1818*3d8817e4Smiod         {
1819*3d8817e4Smiod           /* Cache the section contents for elf_link_input_bfd.  */
1820*3d8817e4Smiod           elf_section_data (sec)->this_hdr.contents = contents;
1821*3d8817e4Smiod         }
1822*3d8817e4Smiod     }
1823*3d8817e4Smiod 
1824*3d8817e4Smiod   if (internal_relocs != NULL
1825*3d8817e4Smiod       && elf_section_data (sec)->relocs != internal_relocs)
1826*3d8817e4Smiod     free (internal_relocs);
1827*3d8817e4Smiod 
1828*3d8817e4Smiod   return TRUE;
1829*3d8817e4Smiod 
1830*3d8817e4Smiod  error_return:
1831*3d8817e4Smiod   if (isymbuf != NULL
1832*3d8817e4Smiod       && symtab_hdr->contents != (unsigned char *) isymbuf)
1833*3d8817e4Smiod     free (isymbuf);
1834*3d8817e4Smiod   if (contents != NULL
1835*3d8817e4Smiod       && elf_section_data (sec)->this_hdr.contents != contents)
1836*3d8817e4Smiod     free (contents);
1837*3d8817e4Smiod   if (internal_relocs != NULL
1838*3d8817e4Smiod       && elf_section_data (sec)->relocs != internal_relocs)
1839*3d8817e4Smiod     free (internal_relocs);
1840*3d8817e4Smiod 
1841*3d8817e4Smiod   return FALSE;
1842*3d8817e4Smiod }
1843*3d8817e4Smiod 
1844*3d8817e4Smiod /* This is a version of bfd_generic_get_relocated_section_contents
1845*3d8817e4Smiod    which uses elf32_avr_relocate_section.
1846*3d8817e4Smiod 
1847*3d8817e4Smiod    For avr it's essentially a cut and paste taken from the H8300 port.
1848*3d8817e4Smiod    The author of the relaxation support patch for avr had absolutely no
1849*3d8817e4Smiod    clue what is happening here but found out that this part of the code
1850*3d8817e4Smiod    seems to be important.  */
1851*3d8817e4Smiod 
1852*3d8817e4Smiod static bfd_byte *
elf32_avr_get_relocated_section_contents(bfd * output_bfd,struct bfd_link_info * link_info,struct bfd_link_order * link_order,bfd_byte * data,bfd_boolean relocatable,asymbol ** symbols)1853*3d8817e4Smiod elf32_avr_get_relocated_section_contents (bfd *output_bfd,
1854*3d8817e4Smiod                                           struct bfd_link_info *link_info,
1855*3d8817e4Smiod                                           struct bfd_link_order *link_order,
1856*3d8817e4Smiod                                           bfd_byte *data,
1857*3d8817e4Smiod                                           bfd_boolean relocatable,
1858*3d8817e4Smiod                                           asymbol **symbols)
1859*3d8817e4Smiod {
1860*3d8817e4Smiod   Elf_Internal_Shdr *symtab_hdr;
1861*3d8817e4Smiod   asection *input_section = link_order->u.indirect.section;
1862*3d8817e4Smiod   bfd *input_bfd = input_section->owner;
1863*3d8817e4Smiod   asection **sections = NULL;
1864*3d8817e4Smiod   Elf_Internal_Rela *internal_relocs = NULL;
1865*3d8817e4Smiod   Elf_Internal_Sym *isymbuf = NULL;
1866*3d8817e4Smiod 
1867*3d8817e4Smiod   /* We only need to handle the case of relaxing, or of having a
1868*3d8817e4Smiod      particular set of section contents, specially.  */
1869*3d8817e4Smiod   if (relocatable
1870*3d8817e4Smiod       || elf_section_data (input_section)->this_hdr.contents == NULL)
1871*3d8817e4Smiod     return bfd_generic_get_relocated_section_contents (output_bfd, link_info,
1872*3d8817e4Smiod                                                        link_order, data,
1873*3d8817e4Smiod                                                        relocatable,
1874*3d8817e4Smiod                                                        symbols);
1875*3d8817e4Smiod   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
1876*3d8817e4Smiod 
1877*3d8817e4Smiod   memcpy (data, elf_section_data (input_section)->this_hdr.contents,
1878*3d8817e4Smiod           (size_t) input_section->size);
1879*3d8817e4Smiod 
1880*3d8817e4Smiod   if ((input_section->flags & SEC_RELOC) != 0
1881*3d8817e4Smiod       && input_section->reloc_count > 0)
1882*3d8817e4Smiod     {
1883*3d8817e4Smiod       asection **secpp;
1884*3d8817e4Smiod       Elf_Internal_Sym *isym, *isymend;
1885*3d8817e4Smiod       bfd_size_type amt;
1886*3d8817e4Smiod 
1887*3d8817e4Smiod       internal_relocs = (_bfd_elf_link_read_relocs
1888*3d8817e4Smiod                          (input_bfd, input_section, NULL, NULL, FALSE));
1889*3d8817e4Smiod       if (internal_relocs == NULL)
1890*3d8817e4Smiod         goto error_return;
1891*3d8817e4Smiod 
1892*3d8817e4Smiod       if (symtab_hdr->sh_info != 0)
1893*3d8817e4Smiod         {
1894*3d8817e4Smiod           isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1895*3d8817e4Smiod           if (isymbuf == NULL)
1896*3d8817e4Smiod             isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
1897*3d8817e4Smiod                                             symtab_hdr->sh_info, 0,
1898*3d8817e4Smiod                                             NULL, NULL, NULL);
1899*3d8817e4Smiod           if (isymbuf == NULL)
1900*3d8817e4Smiod             goto error_return;
1901*3d8817e4Smiod         }
1902*3d8817e4Smiod 
1903*3d8817e4Smiod       amt = symtab_hdr->sh_info;
1904*3d8817e4Smiod       amt *= sizeof (asection *);
1905*3d8817e4Smiod       sections = bfd_malloc (amt);
1906*3d8817e4Smiod       if (sections == NULL && amt != 0)
1907*3d8817e4Smiod         goto error_return;
1908*3d8817e4Smiod 
1909*3d8817e4Smiod       isymend = isymbuf + symtab_hdr->sh_info;
1910*3d8817e4Smiod       for (isym = isymbuf, secpp = sections; isym < isymend; ++isym, ++secpp)
1911*3d8817e4Smiod         {
1912*3d8817e4Smiod           asection *isec;
1913*3d8817e4Smiod 
1914*3d8817e4Smiod           if (isym->st_shndx == SHN_UNDEF)
1915*3d8817e4Smiod             isec = bfd_und_section_ptr;
1916*3d8817e4Smiod           else if (isym->st_shndx == SHN_ABS)
1917*3d8817e4Smiod             isec = bfd_abs_section_ptr;
1918*3d8817e4Smiod           else if (isym->st_shndx == SHN_COMMON)
1919*3d8817e4Smiod             isec = bfd_com_section_ptr;
1920*3d8817e4Smiod           else
1921*3d8817e4Smiod             isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx);
1922*3d8817e4Smiod 
1923*3d8817e4Smiod           *secpp = isec;
1924*3d8817e4Smiod         }
1925*3d8817e4Smiod 
1926*3d8817e4Smiod       if (! elf32_avr_relocate_section (output_bfd, link_info, input_bfd,
1927*3d8817e4Smiod                                         input_section, data, internal_relocs,
1928*3d8817e4Smiod                                         isymbuf, sections))
1929*3d8817e4Smiod         goto error_return;
1930*3d8817e4Smiod 
1931*3d8817e4Smiod       if (sections != NULL)
1932*3d8817e4Smiod         free (sections);
1933*3d8817e4Smiod       if (isymbuf != NULL
1934*3d8817e4Smiod           && symtab_hdr->contents != (unsigned char *) isymbuf)
1935*3d8817e4Smiod         free (isymbuf);
1936*3d8817e4Smiod       if (elf_section_data (input_section)->relocs != internal_relocs)
1937*3d8817e4Smiod         free (internal_relocs);
1938*3d8817e4Smiod     }
1939*3d8817e4Smiod 
1940*3d8817e4Smiod   return data;
1941*3d8817e4Smiod 
1942*3d8817e4Smiod  error_return:
1943*3d8817e4Smiod   if (sections != NULL)
1944*3d8817e4Smiod     free (sections);
1945*3d8817e4Smiod   if (isymbuf != NULL
1946*3d8817e4Smiod       && symtab_hdr->contents != (unsigned char *) isymbuf)
1947*3d8817e4Smiod     free (isymbuf);
1948*3d8817e4Smiod   if (internal_relocs != NULL
1949*3d8817e4Smiod       && elf_section_data (input_section)->relocs != internal_relocs)
1950*3d8817e4Smiod     free (internal_relocs);
1951*3d8817e4Smiod   return NULL;
1952*3d8817e4Smiod }
1953*3d8817e4Smiod 
1954*3d8817e4Smiod 
1955*3d8817e4Smiod #define ELF_ARCH		bfd_arch_avr
1956*3d8817e4Smiod #define ELF_MACHINE_CODE	EM_AVR
1957*3d8817e4Smiod #define ELF_MACHINE_ALT1	EM_AVR_OLD
1958*3d8817e4Smiod #define ELF_MAXPAGESIZE		1
1959*3d8817e4Smiod 
1960*3d8817e4Smiod #define TARGET_LITTLE_SYM       bfd_elf32_avr_vec
1961*3d8817e4Smiod #define TARGET_LITTLE_NAME	"elf32-avr"
1962*3d8817e4Smiod 
1963*3d8817e4Smiod #define elf_info_to_howto	             avr_info_to_howto_rela
1964*3d8817e4Smiod #define elf_info_to_howto_rel	             NULL
1965*3d8817e4Smiod #define elf_backend_relocate_section         elf32_avr_relocate_section
1966*3d8817e4Smiod #define elf_backend_gc_mark_hook             elf32_avr_gc_mark_hook
1967*3d8817e4Smiod #define elf_backend_gc_sweep_hook            elf32_avr_gc_sweep_hook
1968*3d8817e4Smiod #define elf_backend_check_relocs             elf32_avr_check_relocs
1969*3d8817e4Smiod #define elf_backend_can_gc_sections          1
1970*3d8817e4Smiod #define elf_backend_rela_normal		     1
1971*3d8817e4Smiod #define elf_backend_final_write_processing \
1972*3d8817e4Smiod 					bfd_elf_avr_final_write_processing
1973*3d8817e4Smiod #define elf_backend_object_p		elf32_avr_object_p
1974*3d8817e4Smiod 
1975*3d8817e4Smiod #define bfd_elf32_bfd_relax_section elf32_avr_relax_section
1976*3d8817e4Smiod #define bfd_elf32_bfd_get_relocated_section_contents \
1977*3d8817e4Smiod                                         elf32_avr_get_relocated_section_contents
1978*3d8817e4Smiod 
1979*3d8817e4Smiod #include "elf32-target.h"
1980