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