1*3d8817e4Smiod /* BFD back-end for ARM COFF files.
2*3d8817e4Smiod    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3*3d8817e4Smiod    2000, 2001, 2002, 2003, 2004, 2005, 2006
4*3d8817e4Smiod    Free Software Foundation, Inc.
5*3d8817e4Smiod    Written by Cygnus Support.
6*3d8817e4Smiod 
7*3d8817e4Smiod    This file is part of BFD, the Binary File Descriptor library.
8*3d8817e4Smiod 
9*3d8817e4Smiod    This program is free software; you can redistribute it and/or modify
10*3d8817e4Smiod    it under the terms of the GNU General Public License as published by
11*3d8817e4Smiod    the Free Software Foundation; either version 2 of the License, or
12*3d8817e4Smiod    (at your option) any later version.
13*3d8817e4Smiod 
14*3d8817e4Smiod    This program is distributed in the hope that it will be useful,
15*3d8817e4Smiod    but WITHOUT ANY WARRANTY; without even the implied warranty of
16*3d8817e4Smiod    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17*3d8817e4Smiod    GNU General Public License for more details.
18*3d8817e4Smiod 
19*3d8817e4Smiod    You should have received a copy of the GNU General Public License
20*3d8817e4Smiod    along with this program; if not, write to the Free Software
21*3d8817e4Smiod    Foundation, Inc., 51 Franklin Street - Fifth Floor, 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 "coff/arm.h"
27*3d8817e4Smiod #include "coff/internal.h"
28*3d8817e4Smiod 
29*3d8817e4Smiod #ifdef COFF_WITH_PE
30*3d8817e4Smiod #include "coff/pe.h"
31*3d8817e4Smiod #endif
32*3d8817e4Smiod 
33*3d8817e4Smiod #include "libcoff.h"
34*3d8817e4Smiod 
35*3d8817e4Smiod /* Macros for manipulation the bits in the flags field of the coff data
36*3d8817e4Smiod    structure.  */
37*3d8817e4Smiod #define APCS_26_FLAG(abfd) \
38*3d8817e4Smiod   (coff_data (abfd)->flags & F_APCS_26)
39*3d8817e4Smiod 
40*3d8817e4Smiod #define APCS_FLOAT_FLAG(abfd) \
41*3d8817e4Smiod   (coff_data (abfd)->flags & F_APCS_FLOAT)
42*3d8817e4Smiod 
43*3d8817e4Smiod #define PIC_FLAG(abfd) \
44*3d8817e4Smiod   (coff_data (abfd)->flags & F_PIC)
45*3d8817e4Smiod 
46*3d8817e4Smiod #define APCS_SET(abfd) \
47*3d8817e4Smiod   (coff_data (abfd)->flags & F_APCS_SET)
48*3d8817e4Smiod 
49*3d8817e4Smiod #define SET_APCS_FLAGS(abfd, flgs) \
50*3d8817e4Smiod   do									\
51*3d8817e4Smiod     {									\
52*3d8817e4Smiod       coff_data (abfd)->flags &= ~(F_APCS_26 | F_APCS_FLOAT | F_PIC);	\
53*3d8817e4Smiod       coff_data (abfd)->flags |= (flgs) | F_APCS_SET;			\
54*3d8817e4Smiod     }									\
55*3d8817e4Smiod   while (0)
56*3d8817e4Smiod 
57*3d8817e4Smiod #define INTERWORK_FLAG(abfd) \
58*3d8817e4Smiod   (coff_data (abfd)->flags & F_INTERWORK)
59*3d8817e4Smiod 
60*3d8817e4Smiod #define INTERWORK_SET(abfd) \
61*3d8817e4Smiod   (coff_data (abfd)->flags & F_INTERWORK_SET)
62*3d8817e4Smiod 
63*3d8817e4Smiod #define SET_INTERWORK_FLAG(abfd, flg) \
64*3d8817e4Smiod   do									\
65*3d8817e4Smiod     {									\
66*3d8817e4Smiod       coff_data (abfd)->flags &= ~F_INTERWORK;				\
67*3d8817e4Smiod       coff_data (abfd)->flags |= (flg) | F_INTERWORK_SET;		\
68*3d8817e4Smiod     }									\
69*3d8817e4Smiod   while (0)
70*3d8817e4Smiod 
71*3d8817e4Smiod #ifndef NUM_ELEM
72*3d8817e4Smiod #define NUM_ELEM(a) ((sizeof (a)) / sizeof ((a)[0]))
73*3d8817e4Smiod #endif
74*3d8817e4Smiod 
75*3d8817e4Smiod typedef enum {bunknown, b9, b12, b23} thumb_pcrel_branchtype;
76*3d8817e4Smiod /* Some typedefs for holding instructions.  */
77*3d8817e4Smiod typedef unsigned long int insn32;
78*3d8817e4Smiod typedef unsigned short int insn16;
79*3d8817e4Smiod 
80*3d8817e4Smiod /* The linker script knows the section names for placement.
81*3d8817e4Smiod    The entry_names are used to do simple name mangling on the stubs.
82*3d8817e4Smiod    Given a function name, and its type, the stub can be found. The
83*3d8817e4Smiod    name can be changed. The only requirement is the %s be present.  */
84*3d8817e4Smiod 
85*3d8817e4Smiod #define THUMB2ARM_GLUE_SECTION_NAME ".glue_7t"
86*3d8817e4Smiod #define THUMB2ARM_GLUE_ENTRY_NAME   "__%s_from_thumb"
87*3d8817e4Smiod 
88*3d8817e4Smiod #define ARM2THUMB_GLUE_SECTION_NAME ".glue_7"
89*3d8817e4Smiod #define ARM2THUMB_GLUE_ENTRY_NAME   "__%s_from_arm"
90*3d8817e4Smiod 
91*3d8817e4Smiod /* Used by the assembler.  */
92*3d8817e4Smiod 
93*3d8817e4Smiod static bfd_reloc_status_type
coff_arm_reloc(bfd * abfd,arelent * reloc_entry,asymbol * symbol ATTRIBUTE_UNUSED,void * data,asection * input_section ATTRIBUTE_UNUSED,bfd * output_bfd,char ** error_message ATTRIBUTE_UNUSED)94*3d8817e4Smiod coff_arm_reloc (bfd *abfd,
95*3d8817e4Smiod 		arelent *reloc_entry,
96*3d8817e4Smiod 		asymbol *symbol ATTRIBUTE_UNUSED,
97*3d8817e4Smiod 		void * data,
98*3d8817e4Smiod 		asection *input_section ATTRIBUTE_UNUSED,
99*3d8817e4Smiod 		bfd *output_bfd,
100*3d8817e4Smiod 		char **error_message ATTRIBUTE_UNUSED)
101*3d8817e4Smiod {
102*3d8817e4Smiod   symvalue diff;
103*3d8817e4Smiod 
104*3d8817e4Smiod   if (output_bfd == NULL)
105*3d8817e4Smiod     return bfd_reloc_continue;
106*3d8817e4Smiod 
107*3d8817e4Smiod   diff = reloc_entry->addend;
108*3d8817e4Smiod 
109*3d8817e4Smiod #define DOIT(x)							\
110*3d8817e4Smiod   x = ((x & ~howto->dst_mask)					\
111*3d8817e4Smiod        | (((x & howto->src_mask) + diff) & howto->dst_mask))
112*3d8817e4Smiod 
113*3d8817e4Smiod     if (diff != 0)
114*3d8817e4Smiod       {
115*3d8817e4Smiod 	reloc_howto_type *howto = reloc_entry->howto;
116*3d8817e4Smiod 	unsigned char *addr = (unsigned char *) data + reloc_entry->address;
117*3d8817e4Smiod 
118*3d8817e4Smiod 	switch (howto->size)
119*3d8817e4Smiod 	  {
120*3d8817e4Smiod 	  case 0:
121*3d8817e4Smiod 	    {
122*3d8817e4Smiod 	      char x = bfd_get_8 (abfd, addr);
123*3d8817e4Smiod 	      DOIT (x);
124*3d8817e4Smiod 	      bfd_put_8 (abfd, x, addr);
125*3d8817e4Smiod 	    }
126*3d8817e4Smiod 	    break;
127*3d8817e4Smiod 
128*3d8817e4Smiod 	  case 1:
129*3d8817e4Smiod 	    {
130*3d8817e4Smiod 	      short x = bfd_get_16 (abfd, addr);
131*3d8817e4Smiod 	      DOIT (x);
132*3d8817e4Smiod 	      bfd_put_16 (abfd, (bfd_vma) x, addr);
133*3d8817e4Smiod 	    }
134*3d8817e4Smiod 	    break;
135*3d8817e4Smiod 
136*3d8817e4Smiod 	  case 2:
137*3d8817e4Smiod 	    {
138*3d8817e4Smiod 	      long x = bfd_get_32 (abfd, addr);
139*3d8817e4Smiod 	      DOIT (x);
140*3d8817e4Smiod 	      bfd_put_32 (abfd, (bfd_vma) x, addr);
141*3d8817e4Smiod 	    }
142*3d8817e4Smiod 	    break;
143*3d8817e4Smiod 
144*3d8817e4Smiod 	  default:
145*3d8817e4Smiod 	    abort ();
146*3d8817e4Smiod 	  }
147*3d8817e4Smiod       }
148*3d8817e4Smiod 
149*3d8817e4Smiod   /* Now let bfd_perform_relocation finish everything up.  */
150*3d8817e4Smiod   return bfd_reloc_continue;
151*3d8817e4Smiod }
152*3d8817e4Smiod 
153*3d8817e4Smiod /* If USER_LABEL_PREFIX is defined as "_" (see coff_arm_is_local_label_name()
154*3d8817e4Smiod    in this file), then TARGET_UNDERSCORE should be defined, otherwise it
155*3d8817e4Smiod    should not.  */
156*3d8817e4Smiod #ifndef TARGET_UNDERSCORE
157*3d8817e4Smiod #define TARGET_UNDERSCORE '_'
158*3d8817e4Smiod #endif
159*3d8817e4Smiod 
160*3d8817e4Smiod #ifndef PCRELOFFSET
161*3d8817e4Smiod #define PCRELOFFSET TRUE
162*3d8817e4Smiod #endif
163*3d8817e4Smiod 
164*3d8817e4Smiod /* These most certainly belong somewhere else. Just had to get rid of
165*3d8817e4Smiod    the manifest constants in the code.  */
166*3d8817e4Smiod #define ARM_8        0
167*3d8817e4Smiod #define ARM_16       1
168*3d8817e4Smiod #define ARM_32       2
169*3d8817e4Smiod #define ARM_26       3
170*3d8817e4Smiod #define ARM_DISP8    4
171*3d8817e4Smiod #define ARM_DISP16   5
172*3d8817e4Smiod #define ARM_DISP32   6
173*3d8817e4Smiod #define ARM_26D      7
174*3d8817e4Smiod /* 8 is unused.  */
175*3d8817e4Smiod #define ARM_NEG16    9
176*3d8817e4Smiod #define ARM_NEG32   10
177*3d8817e4Smiod #define ARM_RVA32   11
178*3d8817e4Smiod #define ARM_THUMB9  12
179*3d8817e4Smiod #define ARM_THUMB12 13
180*3d8817e4Smiod #define ARM_THUMB23 14
181*3d8817e4Smiod 
182*3d8817e4Smiod #ifdef ARM_WINCE
183*3d8817e4Smiod #undef  ARM_32
184*3d8817e4Smiod #undef  ARM_RVA32
185*3d8817e4Smiod #undef  ARM_26
186*3d8817e4Smiod #undef  ARM_THUMB12
187*3d8817e4Smiod #undef  ARM_26D
188*3d8817e4Smiod 
189*3d8817e4Smiod #define ARM_26D      0
190*3d8817e4Smiod #define ARM_32       1
191*3d8817e4Smiod #define ARM_RVA32    2
192*3d8817e4Smiod #define ARM_26	     3
193*3d8817e4Smiod #define ARM_THUMB12  4
194*3d8817e4Smiod #define ARM_SECTION  14
195*3d8817e4Smiod #define ARM_SECREL   15
196*3d8817e4Smiod #endif
197*3d8817e4Smiod 
198*3d8817e4Smiod static bfd_reloc_status_type aoutarm_fix_pcrel_26_done
199*3d8817e4Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
200*3d8817e4Smiod static bfd_reloc_status_type aoutarm_fix_pcrel_26
201*3d8817e4Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
202*3d8817e4Smiod static bfd_reloc_status_type coff_thumb_pcrel_12
203*3d8817e4Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
204*3d8817e4Smiod #ifndef ARM_WINCE
205*3d8817e4Smiod static bfd_reloc_status_type coff_thumb_pcrel_9
206*3d8817e4Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
207*3d8817e4Smiod static bfd_reloc_status_type coff_thumb_pcrel_23
208*3d8817e4Smiod   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
209*3d8817e4Smiod #endif
210*3d8817e4Smiod 
211*3d8817e4Smiod static reloc_howto_type aoutarm_std_reloc_howto[] =
212*3d8817e4Smiod   {
213*3d8817e4Smiod #ifdef ARM_WINCE
214*3d8817e4Smiod     HOWTO (ARM_26D,
215*3d8817e4Smiod 	   2,
216*3d8817e4Smiod 	   2,
217*3d8817e4Smiod 	   24,
218*3d8817e4Smiod 	   TRUE,
219*3d8817e4Smiod 	   0,
220*3d8817e4Smiod 	   complain_overflow_dont,
221*3d8817e4Smiod 	   aoutarm_fix_pcrel_26_done,
222*3d8817e4Smiod 	   "ARM_26D",
223*3d8817e4Smiod 	   FALSE,
224*3d8817e4Smiod 	   0x00ffffff,
225*3d8817e4Smiod 	   0x0,
226*3d8817e4Smiod 	   PCRELOFFSET),
227*3d8817e4Smiod     HOWTO (ARM_32,
228*3d8817e4Smiod 	   0,
229*3d8817e4Smiod 	   2,
230*3d8817e4Smiod 	   32,
231*3d8817e4Smiod 	   FALSE,
232*3d8817e4Smiod 	   0,
233*3d8817e4Smiod 	   complain_overflow_bitfield,
234*3d8817e4Smiod 	   coff_arm_reloc,
235*3d8817e4Smiod 	   "ARM_32",
236*3d8817e4Smiod 	   FALSE,
237*3d8817e4Smiod 	   0xffffffff,
238*3d8817e4Smiod 	   0xffffffff,
239*3d8817e4Smiod 	   PCRELOFFSET),
240*3d8817e4Smiod     HOWTO (ARM_RVA32,
241*3d8817e4Smiod 	   0,
242*3d8817e4Smiod 	   2,
243*3d8817e4Smiod 	   32,
244*3d8817e4Smiod 	   FALSE,
245*3d8817e4Smiod 	   0,
246*3d8817e4Smiod 	   complain_overflow_bitfield,
247*3d8817e4Smiod 	   coff_arm_reloc,
248*3d8817e4Smiod 	   "ARM_RVA32",
249*3d8817e4Smiod 	   FALSE,
250*3d8817e4Smiod 	   0xffffffff,
251*3d8817e4Smiod 	   0xffffffff,
252*3d8817e4Smiod 	   PCRELOFFSET),
253*3d8817e4Smiod     HOWTO (ARM_26,
254*3d8817e4Smiod 	   2,
255*3d8817e4Smiod 	   2,
256*3d8817e4Smiod 	   24,
257*3d8817e4Smiod 	   TRUE,
258*3d8817e4Smiod 	   0,
259*3d8817e4Smiod 	   complain_overflow_signed,
260*3d8817e4Smiod 	   aoutarm_fix_pcrel_26 ,
261*3d8817e4Smiod 	   "ARM_26",
262*3d8817e4Smiod 	   FALSE,
263*3d8817e4Smiod 	   0x00ffffff,
264*3d8817e4Smiod 	   0x00ffffff,
265*3d8817e4Smiod 	   PCRELOFFSET),
266*3d8817e4Smiod     HOWTO (ARM_THUMB12,
267*3d8817e4Smiod 	   1,
268*3d8817e4Smiod 	   1,
269*3d8817e4Smiod 	   11,
270*3d8817e4Smiod 	   TRUE,
271*3d8817e4Smiod 	   0,
272*3d8817e4Smiod 	   complain_overflow_signed,
273*3d8817e4Smiod 	   coff_thumb_pcrel_12 ,
274*3d8817e4Smiod 	   "ARM_THUMB12",
275*3d8817e4Smiod 	   FALSE,
276*3d8817e4Smiod 	   0x000007ff,
277*3d8817e4Smiod 	   0x000007ff,
278*3d8817e4Smiod 	   PCRELOFFSET),
279*3d8817e4Smiod     EMPTY_HOWTO (-1),
280*3d8817e4Smiod     EMPTY_HOWTO (-1),
281*3d8817e4Smiod     EMPTY_HOWTO (-1),
282*3d8817e4Smiod     EMPTY_HOWTO (-1),
283*3d8817e4Smiod     EMPTY_HOWTO (-1),
284*3d8817e4Smiod     EMPTY_HOWTO (-1),
285*3d8817e4Smiod     EMPTY_HOWTO (-1),
286*3d8817e4Smiod     EMPTY_HOWTO (-1),
287*3d8817e4Smiod     EMPTY_HOWTO (-1),
288*3d8817e4Smiod     HOWTO (ARM_SECTION,
289*3d8817e4Smiod 	   0,
290*3d8817e4Smiod 	   1,
291*3d8817e4Smiod 	   16,
292*3d8817e4Smiod 	   FALSE,
293*3d8817e4Smiod 	   0,
294*3d8817e4Smiod 	   complain_overflow_bitfield,
295*3d8817e4Smiod 	   coff_arm_reloc,
296*3d8817e4Smiod 	   "ARM_SECTION",
297*3d8817e4Smiod 	   FALSE,
298*3d8817e4Smiod 	   0x0000ffff,
299*3d8817e4Smiod 	   0x0000ffff,
300*3d8817e4Smiod 	   PCRELOFFSET),
301*3d8817e4Smiod     HOWTO (ARM_SECREL,
302*3d8817e4Smiod 	   0,
303*3d8817e4Smiod 	   2,
304*3d8817e4Smiod 	   32,
305*3d8817e4Smiod 	   FALSE,
306*3d8817e4Smiod 	   0,
307*3d8817e4Smiod 	   complain_overflow_bitfield,
308*3d8817e4Smiod 	   coff_arm_reloc,
309*3d8817e4Smiod 	   "ARM_SECREL",
310*3d8817e4Smiod 	   FALSE,
311*3d8817e4Smiod 	   0xffffffff,
312*3d8817e4Smiod 	   0xffffffff,
313*3d8817e4Smiod 	   PCRELOFFSET),
314*3d8817e4Smiod #else /* not ARM_WINCE */
315*3d8817e4Smiod     HOWTO (ARM_8,
316*3d8817e4Smiod 	   0,
317*3d8817e4Smiod 	   0,
318*3d8817e4Smiod 	   8,
319*3d8817e4Smiod 	   FALSE,
320*3d8817e4Smiod 	   0,
321*3d8817e4Smiod 	   complain_overflow_bitfield,
322*3d8817e4Smiod 	   coff_arm_reloc,
323*3d8817e4Smiod 	   "ARM_8",
324*3d8817e4Smiod 	   TRUE,
325*3d8817e4Smiod 	   0x000000ff,
326*3d8817e4Smiod 	   0x000000ff,
327*3d8817e4Smiod 	   PCRELOFFSET),
328*3d8817e4Smiod     HOWTO (ARM_16,
329*3d8817e4Smiod 	   0,
330*3d8817e4Smiod 	   1,
331*3d8817e4Smiod 	   16,
332*3d8817e4Smiod 	   FALSE,
333*3d8817e4Smiod 	   0,
334*3d8817e4Smiod 	   complain_overflow_bitfield,
335*3d8817e4Smiod 	   coff_arm_reloc,
336*3d8817e4Smiod 	   "ARM_16",
337*3d8817e4Smiod 	   TRUE,
338*3d8817e4Smiod 	   0x0000ffff,
339*3d8817e4Smiod 	   0x0000ffff,
340*3d8817e4Smiod 	   PCRELOFFSET),
341*3d8817e4Smiod     HOWTO (ARM_32,
342*3d8817e4Smiod 	   0,
343*3d8817e4Smiod 	   2,
344*3d8817e4Smiod 	   32,
345*3d8817e4Smiod 	   FALSE,
346*3d8817e4Smiod 	   0,
347*3d8817e4Smiod 	   complain_overflow_bitfield,
348*3d8817e4Smiod 	   coff_arm_reloc,
349*3d8817e4Smiod 	   "ARM_32",
350*3d8817e4Smiod 	   TRUE,
351*3d8817e4Smiod 	   0xffffffff,
352*3d8817e4Smiod 	   0xffffffff,
353*3d8817e4Smiod 	   PCRELOFFSET),
354*3d8817e4Smiod     HOWTO (ARM_26,
355*3d8817e4Smiod 	   2,
356*3d8817e4Smiod 	   2,
357*3d8817e4Smiod 	   24,
358*3d8817e4Smiod 	   TRUE,
359*3d8817e4Smiod 	   0,
360*3d8817e4Smiod 	   complain_overflow_signed,
361*3d8817e4Smiod 	   aoutarm_fix_pcrel_26 ,
362*3d8817e4Smiod 	   "ARM_26",
363*3d8817e4Smiod 	   FALSE,
364*3d8817e4Smiod 	   0x00ffffff,
365*3d8817e4Smiod 	   0x00ffffff,
366*3d8817e4Smiod 	   PCRELOFFSET),
367*3d8817e4Smiod     HOWTO (ARM_DISP8,
368*3d8817e4Smiod 	   0,
369*3d8817e4Smiod 	   0,
370*3d8817e4Smiod 	   8,
371*3d8817e4Smiod 	   TRUE,
372*3d8817e4Smiod 	   0,
373*3d8817e4Smiod 	   complain_overflow_signed,
374*3d8817e4Smiod 	   coff_arm_reloc,
375*3d8817e4Smiod 	   "ARM_DISP8",
376*3d8817e4Smiod 	   TRUE,
377*3d8817e4Smiod 	   0x000000ff,
378*3d8817e4Smiod 	   0x000000ff,
379*3d8817e4Smiod 	   TRUE),
380*3d8817e4Smiod     HOWTO (ARM_DISP16,
381*3d8817e4Smiod 	   0,
382*3d8817e4Smiod 	   1,
383*3d8817e4Smiod 	   16,
384*3d8817e4Smiod 	   TRUE,
385*3d8817e4Smiod 	   0,
386*3d8817e4Smiod 	   complain_overflow_signed,
387*3d8817e4Smiod 	   coff_arm_reloc,
388*3d8817e4Smiod 	   "ARM_DISP16",
389*3d8817e4Smiod 	   TRUE,
390*3d8817e4Smiod 	   0x0000ffff,
391*3d8817e4Smiod 	   0x0000ffff,
392*3d8817e4Smiod 	   TRUE),
393*3d8817e4Smiod     HOWTO (ARM_DISP32,
394*3d8817e4Smiod 	   0,
395*3d8817e4Smiod 	   2,
396*3d8817e4Smiod 	   32,
397*3d8817e4Smiod 	   TRUE,
398*3d8817e4Smiod 	   0,
399*3d8817e4Smiod 	   complain_overflow_signed,
400*3d8817e4Smiod 	   coff_arm_reloc,
401*3d8817e4Smiod 	   "ARM_DISP32",
402*3d8817e4Smiod 	   TRUE,
403*3d8817e4Smiod 	   0xffffffff,
404*3d8817e4Smiod 	   0xffffffff,
405*3d8817e4Smiod 	   TRUE),
406*3d8817e4Smiod     HOWTO (ARM_26D,
407*3d8817e4Smiod 	   2,
408*3d8817e4Smiod 	   2,
409*3d8817e4Smiod 	   24,
410*3d8817e4Smiod 	   FALSE,
411*3d8817e4Smiod 	   0,
412*3d8817e4Smiod 	   complain_overflow_dont,
413*3d8817e4Smiod 	   aoutarm_fix_pcrel_26_done,
414*3d8817e4Smiod 	   "ARM_26D",
415*3d8817e4Smiod 	   TRUE,
416*3d8817e4Smiod 	   0x00ffffff,
417*3d8817e4Smiod 	   0x0,
418*3d8817e4Smiod 	   FALSE),
419*3d8817e4Smiod     /* 8 is unused */
420*3d8817e4Smiod     EMPTY_HOWTO (-1),
421*3d8817e4Smiod     HOWTO (ARM_NEG16,
422*3d8817e4Smiod 	   0,
423*3d8817e4Smiod 	   -1,
424*3d8817e4Smiod 	   16,
425*3d8817e4Smiod 	   FALSE,
426*3d8817e4Smiod 	   0,
427*3d8817e4Smiod 	   complain_overflow_bitfield,
428*3d8817e4Smiod 	   coff_arm_reloc,
429*3d8817e4Smiod 	   "ARM_NEG16",
430*3d8817e4Smiod 	   TRUE,
431*3d8817e4Smiod 	   0x0000ffff,
432*3d8817e4Smiod 	   0x0000ffff,
433*3d8817e4Smiod 	   FALSE),
434*3d8817e4Smiod     HOWTO (ARM_NEG32,
435*3d8817e4Smiod 	   0,
436*3d8817e4Smiod 	   -2,
437*3d8817e4Smiod 	   32,
438*3d8817e4Smiod 	   FALSE,
439*3d8817e4Smiod 	   0,
440*3d8817e4Smiod 	   complain_overflow_bitfield,
441*3d8817e4Smiod 	   coff_arm_reloc,
442*3d8817e4Smiod 	   "ARM_NEG32",
443*3d8817e4Smiod 	   TRUE,
444*3d8817e4Smiod 	   0xffffffff,
445*3d8817e4Smiod 	   0xffffffff,
446*3d8817e4Smiod 	   FALSE),
447*3d8817e4Smiod     HOWTO (ARM_RVA32,
448*3d8817e4Smiod 	   0,
449*3d8817e4Smiod 	   2,
450*3d8817e4Smiod 	   32,
451*3d8817e4Smiod 	   FALSE,
452*3d8817e4Smiod 	   0,
453*3d8817e4Smiod 	   complain_overflow_bitfield,
454*3d8817e4Smiod 	   coff_arm_reloc,
455*3d8817e4Smiod 	   "ARM_RVA32",
456*3d8817e4Smiod 	   TRUE,
457*3d8817e4Smiod 	   0xffffffff,
458*3d8817e4Smiod 	   0xffffffff,
459*3d8817e4Smiod 	   PCRELOFFSET),
460*3d8817e4Smiod     HOWTO (ARM_THUMB9,
461*3d8817e4Smiod 	   1,
462*3d8817e4Smiod 	   1,
463*3d8817e4Smiod 	   8,
464*3d8817e4Smiod 	   TRUE,
465*3d8817e4Smiod 	   0,
466*3d8817e4Smiod 	   complain_overflow_signed,
467*3d8817e4Smiod 	   coff_thumb_pcrel_9 ,
468*3d8817e4Smiod 	   "ARM_THUMB9",
469*3d8817e4Smiod 	   FALSE,
470*3d8817e4Smiod 	   0x000000ff,
471*3d8817e4Smiod 	   0x000000ff,
472*3d8817e4Smiod 	   PCRELOFFSET),
473*3d8817e4Smiod     HOWTO (ARM_THUMB12,
474*3d8817e4Smiod 	   1,
475*3d8817e4Smiod 	   1,
476*3d8817e4Smiod 	   11,
477*3d8817e4Smiod 	   TRUE,
478*3d8817e4Smiod 	   0,
479*3d8817e4Smiod 	   complain_overflow_signed,
480*3d8817e4Smiod 	   coff_thumb_pcrel_12 ,
481*3d8817e4Smiod 	   "ARM_THUMB12",
482*3d8817e4Smiod 	   FALSE,
483*3d8817e4Smiod 	   0x000007ff,
484*3d8817e4Smiod 	   0x000007ff,
485*3d8817e4Smiod 	   PCRELOFFSET),
486*3d8817e4Smiod     HOWTO (ARM_THUMB23,
487*3d8817e4Smiod 	   1,
488*3d8817e4Smiod 	   2,
489*3d8817e4Smiod 	   22,
490*3d8817e4Smiod 	   TRUE,
491*3d8817e4Smiod 	   0,
492*3d8817e4Smiod 	   complain_overflow_signed,
493*3d8817e4Smiod 	   coff_thumb_pcrel_23 ,
494*3d8817e4Smiod 	   "ARM_THUMB23",
495*3d8817e4Smiod 	   FALSE,
496*3d8817e4Smiod 	   0x07ff07ff,
497*3d8817e4Smiod 	   0x07ff07ff,
498*3d8817e4Smiod 	   PCRELOFFSET)
499*3d8817e4Smiod #endif /* not ARM_WINCE */
500*3d8817e4Smiod   };
501*3d8817e4Smiod 
502*3d8817e4Smiod #define NUM_RELOCS NUM_ELEM (aoutarm_std_reloc_howto)
503*3d8817e4Smiod 
504*3d8817e4Smiod #ifdef COFF_WITH_PE
505*3d8817e4Smiod /* Return TRUE if this relocation should
506*3d8817e4Smiod    appear in the output .reloc section.  */
507*3d8817e4Smiod 
508*3d8817e4Smiod static bfd_boolean
in_reloc_p(bfd * abfd ATTRIBUTE_UNUSED,reloc_howto_type * howto)509*3d8817e4Smiod in_reloc_p (bfd * abfd ATTRIBUTE_UNUSED,
510*3d8817e4Smiod 	    reloc_howto_type * howto)
511*3d8817e4Smiod {
512*3d8817e4Smiod   return !howto->pc_relative && howto->type != ARM_RVA32;
513*3d8817e4Smiod }
514*3d8817e4Smiod #endif
515*3d8817e4Smiod 
516*3d8817e4Smiod #define RTYPE2HOWTO(cache_ptr, dst)		\
517*3d8817e4Smiod   (cache_ptr)->howto =				\
518*3d8817e4Smiod     (dst)->r_type < NUM_RELOCS			\
519*3d8817e4Smiod     ? aoutarm_std_reloc_howto + (dst)->r_type	\
520*3d8817e4Smiod     : NULL
521*3d8817e4Smiod 
522*3d8817e4Smiod #define coff_rtype_to_howto coff_arm_rtype_to_howto
523*3d8817e4Smiod 
524*3d8817e4Smiod static reloc_howto_type *
coff_arm_rtype_to_howto(bfd * abfd ATTRIBUTE_UNUSED,asection * sec,struct internal_reloc * rel,struct coff_link_hash_entry * h ATTRIBUTE_UNUSED,struct internal_syment * sym ATTRIBUTE_UNUSED,bfd_vma * addendp)525*3d8817e4Smiod coff_arm_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
526*3d8817e4Smiod 			 asection *sec,
527*3d8817e4Smiod 			 struct internal_reloc *rel,
528*3d8817e4Smiod 			 struct coff_link_hash_entry *h ATTRIBUTE_UNUSED,
529*3d8817e4Smiod 			 struct internal_syment *sym ATTRIBUTE_UNUSED,
530*3d8817e4Smiod 			 bfd_vma *addendp)
531*3d8817e4Smiod {
532*3d8817e4Smiod   reloc_howto_type * howto;
533*3d8817e4Smiod 
534*3d8817e4Smiod   if (rel->r_type >= NUM_RELOCS)
535*3d8817e4Smiod     return NULL;
536*3d8817e4Smiod 
537*3d8817e4Smiod   howto = aoutarm_std_reloc_howto + rel->r_type;
538*3d8817e4Smiod 
539*3d8817e4Smiod   if (rel->r_type == ARM_RVA32)
540*3d8817e4Smiod     *addendp -= pe_data (sec->output_section->owner)->pe_opthdr.ImageBase;
541*3d8817e4Smiod 
542*3d8817e4Smiod   return howto;
543*3d8817e4Smiod }
544*3d8817e4Smiod 
545*3d8817e4Smiod /* Used by the assembler.  */
546*3d8817e4Smiod 
547*3d8817e4Smiod static bfd_reloc_status_type
aoutarm_fix_pcrel_26_done(bfd * abfd ATTRIBUTE_UNUSED,arelent * reloc_entry ATTRIBUTE_UNUSED,asymbol * symbol ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED,asection * input_section ATTRIBUTE_UNUSED,bfd * output_bfd ATTRIBUTE_UNUSED,char ** error_message ATTRIBUTE_UNUSED)548*3d8817e4Smiod aoutarm_fix_pcrel_26_done (bfd *abfd ATTRIBUTE_UNUSED,
549*3d8817e4Smiod 			   arelent *reloc_entry ATTRIBUTE_UNUSED,
550*3d8817e4Smiod 			   asymbol *symbol ATTRIBUTE_UNUSED,
551*3d8817e4Smiod 			   void * data ATTRIBUTE_UNUSED,
552*3d8817e4Smiod 			   asection *input_section ATTRIBUTE_UNUSED,
553*3d8817e4Smiod 			   bfd *output_bfd ATTRIBUTE_UNUSED,
554*3d8817e4Smiod 			   char **error_message ATTRIBUTE_UNUSED)
555*3d8817e4Smiod {
556*3d8817e4Smiod   /* This is dead simple at present.  */
557*3d8817e4Smiod   return bfd_reloc_ok;
558*3d8817e4Smiod }
559*3d8817e4Smiod 
560*3d8817e4Smiod /* Used by the assembler.  */
561*3d8817e4Smiod 
562*3d8817e4Smiod static bfd_reloc_status_type
aoutarm_fix_pcrel_26(bfd * abfd,arelent * reloc_entry,asymbol * symbol,void * data,asection * input_section,bfd * output_bfd,char ** error_message ATTRIBUTE_UNUSED)563*3d8817e4Smiod aoutarm_fix_pcrel_26 (bfd *abfd,
564*3d8817e4Smiod 		      arelent *reloc_entry,
565*3d8817e4Smiod 		      asymbol *symbol,
566*3d8817e4Smiod 		      void * data,
567*3d8817e4Smiod 		      asection *input_section,
568*3d8817e4Smiod 		      bfd *output_bfd,
569*3d8817e4Smiod 		      char **error_message ATTRIBUTE_UNUSED)
570*3d8817e4Smiod {
571*3d8817e4Smiod   bfd_vma relocation;
572*3d8817e4Smiod   bfd_size_type addr = reloc_entry->address;
573*3d8817e4Smiod   long target = bfd_get_32 (abfd, (bfd_byte *) data + addr);
574*3d8817e4Smiod   bfd_reloc_status_type flag = bfd_reloc_ok;
575*3d8817e4Smiod 
576*3d8817e4Smiod   /* If this is an undefined symbol, return error.  */
577*3d8817e4Smiod   if (symbol->section == &bfd_und_section
578*3d8817e4Smiod       && (symbol->flags & BSF_WEAK) == 0)
579*3d8817e4Smiod     return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined;
580*3d8817e4Smiod 
581*3d8817e4Smiod   /* If the sections are different, and we are doing a partial relocation,
582*3d8817e4Smiod      just ignore it for now.  */
583*3d8817e4Smiod   if (symbol->section->name != input_section->name
584*3d8817e4Smiod       && output_bfd != (bfd *)NULL)
585*3d8817e4Smiod     return bfd_reloc_continue;
586*3d8817e4Smiod 
587*3d8817e4Smiod   relocation = (target & 0x00ffffff) << 2;
588*3d8817e4Smiod   relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend.  */
589*3d8817e4Smiod   relocation += symbol->value;
590*3d8817e4Smiod   relocation += symbol->section->output_section->vma;
591*3d8817e4Smiod   relocation += symbol->section->output_offset;
592*3d8817e4Smiod   relocation += reloc_entry->addend;
593*3d8817e4Smiod   relocation -= input_section->output_section->vma;
594*3d8817e4Smiod   relocation -= input_section->output_offset;
595*3d8817e4Smiod   relocation -= addr;
596*3d8817e4Smiod 
597*3d8817e4Smiod   if (relocation & 3)
598*3d8817e4Smiod     return bfd_reloc_overflow;
599*3d8817e4Smiod 
600*3d8817e4Smiod   /* Check for overflow.  */
601*3d8817e4Smiod   if (relocation & 0x02000000)
602*3d8817e4Smiod     {
603*3d8817e4Smiod       if ((relocation & ~ (bfd_vma) 0x03ffffff) != ~ (bfd_vma) 0x03ffffff)
604*3d8817e4Smiod 	flag = bfd_reloc_overflow;
605*3d8817e4Smiod     }
606*3d8817e4Smiod   else if (relocation & ~(bfd_vma) 0x03ffffff)
607*3d8817e4Smiod     flag = bfd_reloc_overflow;
608*3d8817e4Smiod 
609*3d8817e4Smiod   target &= ~0x00ffffff;
610*3d8817e4Smiod   target |= (relocation >> 2) & 0x00ffffff;
611*3d8817e4Smiod   bfd_put_32 (abfd, (bfd_vma) target, (bfd_byte *) data + addr);
612*3d8817e4Smiod 
613*3d8817e4Smiod   /* Now the ARM magic... Change the reloc type so that it is marked as done.
614*3d8817e4Smiod      Strictly this is only necessary if we are doing a partial relocation.  */
615*3d8817e4Smiod   reloc_entry->howto = &aoutarm_std_reloc_howto[ARM_26D];
616*3d8817e4Smiod 
617*3d8817e4Smiod   return flag;
618*3d8817e4Smiod }
619*3d8817e4Smiod 
620*3d8817e4Smiod static bfd_reloc_status_type
coff_thumb_pcrel_common(bfd * abfd,arelent * reloc_entry,asymbol * symbol,void * data,asection * input_section,bfd * output_bfd,char ** error_message ATTRIBUTE_UNUSED,thumb_pcrel_branchtype btype)621*3d8817e4Smiod coff_thumb_pcrel_common (bfd *abfd,
622*3d8817e4Smiod 			 arelent *reloc_entry,
623*3d8817e4Smiod 			 asymbol *symbol,
624*3d8817e4Smiod 			 void * data,
625*3d8817e4Smiod 			 asection *input_section,
626*3d8817e4Smiod 			 bfd *output_bfd,
627*3d8817e4Smiod 			 char **error_message ATTRIBUTE_UNUSED,
628*3d8817e4Smiod 			 thumb_pcrel_branchtype btype)
629*3d8817e4Smiod {
630*3d8817e4Smiod   bfd_vma relocation = 0;
631*3d8817e4Smiod   bfd_size_type addr = reloc_entry->address;
632*3d8817e4Smiod   long target = bfd_get_32 (abfd, (bfd_byte *) data + addr);
633*3d8817e4Smiod   bfd_reloc_status_type flag = bfd_reloc_ok;
634*3d8817e4Smiod   bfd_vma dstmsk;
635*3d8817e4Smiod   bfd_vma offmsk;
636*3d8817e4Smiod   bfd_vma signbit;
637*3d8817e4Smiod 
638*3d8817e4Smiod   /* NOTE: This routine is currently used by GAS, but not by the link
639*3d8817e4Smiod      phase.  */
640*3d8817e4Smiod   switch (btype)
641*3d8817e4Smiod     {
642*3d8817e4Smiod     case b9:
643*3d8817e4Smiod       dstmsk  = 0x000000ff;
644*3d8817e4Smiod       offmsk  = 0x000001fe;
645*3d8817e4Smiod       signbit = 0x00000100;
646*3d8817e4Smiod       break;
647*3d8817e4Smiod 
648*3d8817e4Smiod     case b12:
649*3d8817e4Smiod       dstmsk  = 0x000007ff;
650*3d8817e4Smiod       offmsk  = 0x00000ffe;
651*3d8817e4Smiod       signbit = 0x00000800;
652*3d8817e4Smiod       break;
653*3d8817e4Smiod 
654*3d8817e4Smiod     case b23:
655*3d8817e4Smiod       dstmsk  = 0x07ff07ff;
656*3d8817e4Smiod       offmsk  = 0x007fffff;
657*3d8817e4Smiod       signbit = 0x00400000;
658*3d8817e4Smiod       break;
659*3d8817e4Smiod 
660*3d8817e4Smiod     default:
661*3d8817e4Smiod       abort ();
662*3d8817e4Smiod     }
663*3d8817e4Smiod 
664*3d8817e4Smiod   /* If this is an undefined symbol, return error.  */
665*3d8817e4Smiod   if (symbol->section == &bfd_und_section
666*3d8817e4Smiod       && (symbol->flags & BSF_WEAK) == 0)
667*3d8817e4Smiod     return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined;
668*3d8817e4Smiod 
669*3d8817e4Smiod   /* If the sections are different, and we are doing a partial relocation,
670*3d8817e4Smiod      just ignore it for now.  */
671*3d8817e4Smiod   if (symbol->section->name != input_section->name
672*3d8817e4Smiod       && output_bfd != (bfd *)NULL)
673*3d8817e4Smiod     return bfd_reloc_continue;
674*3d8817e4Smiod 
675*3d8817e4Smiod   switch (btype)
676*3d8817e4Smiod     {
677*3d8817e4Smiod     case b9:
678*3d8817e4Smiod     case b12:
679*3d8817e4Smiod       relocation = ((target & dstmsk) << 1);
680*3d8817e4Smiod       break;
681*3d8817e4Smiod 
682*3d8817e4Smiod     case b23:
683*3d8817e4Smiod       if (bfd_big_endian (abfd))
684*3d8817e4Smiod 	relocation = ((target & 0x7ff) << 1)  | ((target & 0x07ff0000) >> 4);
685*3d8817e4Smiod       else
686*3d8817e4Smiod 	relocation = ((target & 0x7ff) << 12) | ((target & 0x07ff0000) >> 15);
687*3d8817e4Smiod       break;
688*3d8817e4Smiod 
689*3d8817e4Smiod     default:
690*3d8817e4Smiod       abort ();
691*3d8817e4Smiod     }
692*3d8817e4Smiod 
693*3d8817e4Smiod   relocation = (relocation ^ signbit) - signbit; /* Sign extend.  */
694*3d8817e4Smiod   relocation += symbol->value;
695*3d8817e4Smiod   relocation += symbol->section->output_section->vma;
696*3d8817e4Smiod   relocation += symbol->section->output_offset;
697*3d8817e4Smiod   relocation += reloc_entry->addend;
698*3d8817e4Smiod   relocation -= input_section->output_section->vma;
699*3d8817e4Smiod   relocation -= input_section->output_offset;
700*3d8817e4Smiod   relocation -= addr;
701*3d8817e4Smiod 
702*3d8817e4Smiod   if (relocation & 1)
703*3d8817e4Smiod     return bfd_reloc_overflow;
704*3d8817e4Smiod 
705*3d8817e4Smiod   /* Check for overflow.  */
706*3d8817e4Smiod   if (relocation & signbit)
707*3d8817e4Smiod     {
708*3d8817e4Smiod       if ((relocation & ~offmsk) != ~offmsk)
709*3d8817e4Smiod 	flag = bfd_reloc_overflow;
710*3d8817e4Smiod     }
711*3d8817e4Smiod   else if (relocation & ~offmsk)
712*3d8817e4Smiod     flag = bfd_reloc_overflow;
713*3d8817e4Smiod 
714*3d8817e4Smiod   target &= ~dstmsk;
715*3d8817e4Smiod   switch (btype)
716*3d8817e4Smiod    {
717*3d8817e4Smiod    case b9:
718*3d8817e4Smiod    case b12:
719*3d8817e4Smiod      target |= (relocation >> 1);
720*3d8817e4Smiod      break;
721*3d8817e4Smiod 
722*3d8817e4Smiod    case b23:
723*3d8817e4Smiod      if (bfd_big_endian (abfd))
724*3d8817e4Smiod        target |= (((relocation & 0xfff) >> 1)
725*3d8817e4Smiod 		  | ((relocation << 4)  & 0x07ff0000));
726*3d8817e4Smiod      else
727*3d8817e4Smiod        target |= (((relocation & 0xffe) << 15)
728*3d8817e4Smiod 		  | ((relocation >> 12) & 0x7ff));
729*3d8817e4Smiod      break;
730*3d8817e4Smiod 
731*3d8817e4Smiod    default:
732*3d8817e4Smiod      abort ();
733*3d8817e4Smiod    }
734*3d8817e4Smiod 
735*3d8817e4Smiod   bfd_put_32 (abfd, (bfd_vma) target, (bfd_byte *) data + addr);
736*3d8817e4Smiod 
737*3d8817e4Smiod   /* Now the ARM magic... Change the reloc type so that it is marked as done.
738*3d8817e4Smiod      Strictly this is only necessary if we are doing a partial relocation.  */
739*3d8817e4Smiod   reloc_entry->howto = & aoutarm_std_reloc_howto [ARM_26D];
740*3d8817e4Smiod 
741*3d8817e4Smiod   /* TODO: We should possibly have DONE entries for the THUMB PCREL relocations.  */
742*3d8817e4Smiod   return flag;
743*3d8817e4Smiod }
744*3d8817e4Smiod 
745*3d8817e4Smiod #ifndef ARM_WINCE
746*3d8817e4Smiod static bfd_reloc_status_type
coff_thumb_pcrel_23(bfd * abfd,arelent * reloc_entry,asymbol * symbol,void * data,asection * input_section,bfd * output_bfd,char ** error_message)747*3d8817e4Smiod coff_thumb_pcrel_23 (bfd *abfd,
748*3d8817e4Smiod 		     arelent *reloc_entry,
749*3d8817e4Smiod 		     asymbol *symbol,
750*3d8817e4Smiod 		     void * data,
751*3d8817e4Smiod 		     asection *input_section,
752*3d8817e4Smiod 		     bfd *output_bfd,
753*3d8817e4Smiod 		     char **error_message)
754*3d8817e4Smiod {
755*3d8817e4Smiod   return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data,
756*3d8817e4Smiod                                   input_section, output_bfd, error_message,
757*3d8817e4Smiod 				  b23);
758*3d8817e4Smiod }
759*3d8817e4Smiod 
760*3d8817e4Smiod static bfd_reloc_status_type
coff_thumb_pcrel_9(bfd * abfd,arelent * reloc_entry,asymbol * symbol,void * data,asection * input_section,bfd * output_bfd,char ** error_message)761*3d8817e4Smiod coff_thumb_pcrel_9 (bfd *abfd,
762*3d8817e4Smiod 		    arelent *reloc_entry,
763*3d8817e4Smiod 		    asymbol *symbol,
764*3d8817e4Smiod 		    void * data,
765*3d8817e4Smiod 		    asection *input_section,
766*3d8817e4Smiod 		    bfd *output_bfd,
767*3d8817e4Smiod 		    char **error_message)
768*3d8817e4Smiod {
769*3d8817e4Smiod   return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data,
770*3d8817e4Smiod                                   input_section, output_bfd, error_message,
771*3d8817e4Smiod 				  b9);
772*3d8817e4Smiod }
773*3d8817e4Smiod #endif /* not ARM_WINCE */
774*3d8817e4Smiod 
775*3d8817e4Smiod static bfd_reloc_status_type
coff_thumb_pcrel_12(bfd * abfd,arelent * reloc_entry,asymbol * symbol,void * data,asection * input_section,bfd * output_bfd,char ** error_message)776*3d8817e4Smiod coff_thumb_pcrel_12 (bfd *abfd,
777*3d8817e4Smiod 		     arelent *reloc_entry,
778*3d8817e4Smiod 		     asymbol *symbol,
779*3d8817e4Smiod 		     void * data,
780*3d8817e4Smiod 		     asection *input_section,
781*3d8817e4Smiod 		     bfd *output_bfd,
782*3d8817e4Smiod 		     char **error_message)
783*3d8817e4Smiod {
784*3d8817e4Smiod   return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data,
785*3d8817e4Smiod                                   input_section, output_bfd, error_message,
786*3d8817e4Smiod 				  b12);
787*3d8817e4Smiod }
788*3d8817e4Smiod 
789*3d8817e4Smiod static const struct reloc_howto_struct *
coff_arm_reloc_type_lookup(bfd * abfd,bfd_reloc_code_real_type code)790*3d8817e4Smiod coff_arm_reloc_type_lookup (bfd * abfd, bfd_reloc_code_real_type code)
791*3d8817e4Smiod {
792*3d8817e4Smiod #define ASTD(i,j)       case i: return aoutarm_std_reloc_howto + j
793*3d8817e4Smiod 
794*3d8817e4Smiod   if (code == BFD_RELOC_CTOR)
795*3d8817e4Smiod     switch (bfd_get_arch_info (abfd)->bits_per_address)
796*3d8817e4Smiod       {
797*3d8817e4Smiod       case 32:
798*3d8817e4Smiod         code = BFD_RELOC_32;
799*3d8817e4Smiod         break;
800*3d8817e4Smiod       default:
801*3d8817e4Smiod 	return NULL;
802*3d8817e4Smiod       }
803*3d8817e4Smiod 
804*3d8817e4Smiod   switch (code)
805*3d8817e4Smiod     {
806*3d8817e4Smiod #ifdef ARM_WINCE
807*3d8817e4Smiod       ASTD (BFD_RELOC_32,                   ARM_32);
808*3d8817e4Smiod       ASTD (BFD_RELOC_RVA,                  ARM_RVA32);
809*3d8817e4Smiod       ASTD (BFD_RELOC_ARM_PCREL_BRANCH,     ARM_26);
810*3d8817e4Smiod       ASTD (BFD_RELOC_THUMB_PCREL_BRANCH12, ARM_THUMB12);
811*3d8817e4Smiod #else
812*3d8817e4Smiod       ASTD (BFD_RELOC_8,                    ARM_8);
813*3d8817e4Smiod       ASTD (BFD_RELOC_16,                   ARM_16);
814*3d8817e4Smiod       ASTD (BFD_RELOC_32,                   ARM_32);
815*3d8817e4Smiod       ASTD (BFD_RELOC_ARM_PCREL_BRANCH,     ARM_26);
816*3d8817e4Smiod       ASTD (BFD_RELOC_ARM_PCREL_BLX,        ARM_26);
817*3d8817e4Smiod       ASTD (BFD_RELOC_8_PCREL,              ARM_DISP8);
818*3d8817e4Smiod       ASTD (BFD_RELOC_16_PCREL,             ARM_DISP16);
819*3d8817e4Smiod       ASTD (BFD_RELOC_32_PCREL,             ARM_DISP32);
820*3d8817e4Smiod       ASTD (BFD_RELOC_RVA,                  ARM_RVA32);
821*3d8817e4Smiod       ASTD (BFD_RELOC_THUMB_PCREL_BRANCH9,  ARM_THUMB9);
822*3d8817e4Smiod       ASTD (BFD_RELOC_THUMB_PCREL_BRANCH12, ARM_THUMB12);
823*3d8817e4Smiod       ASTD (BFD_RELOC_THUMB_PCREL_BRANCH23, ARM_THUMB23);
824*3d8817e4Smiod       ASTD (BFD_RELOC_THUMB_PCREL_BLX,      ARM_THUMB23);
825*3d8817e4Smiod #endif
826*3d8817e4Smiod     default: return NULL;
827*3d8817e4Smiod     }
828*3d8817e4Smiod }
829*3d8817e4Smiod 
830*3d8817e4Smiod #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER  2
831*3d8817e4Smiod #define COFF_PAGE_SIZE                        0x1000
832*3d8817e4Smiod 
833*3d8817e4Smiod /* Turn a howto into a reloc  nunmber.  */
834*3d8817e4Smiod #define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
835*3d8817e4Smiod #define BADMAG(x)             ARMBADMAG(x)
836*3d8817e4Smiod #define ARM                   1			/* Customize coffcode.h.  */
837*3d8817e4Smiod 
838*3d8817e4Smiod #ifndef ARM_WINCE
839*3d8817e4Smiod /* Make sure that the 'r_offset' field is copied properly
840*3d8817e4Smiod    so that identical binaries will compare the same.  */
841*3d8817e4Smiod #define SWAP_IN_RELOC_OFFSET	H_GET_32
842*3d8817e4Smiod #define SWAP_OUT_RELOC_OFFSET	H_PUT_32
843*3d8817e4Smiod #endif
844*3d8817e4Smiod 
845*3d8817e4Smiod /* Extend the coff_link_hash_table structure with a few ARM specific fields.
846*3d8817e4Smiod    This allows us to store global data here without actually creating any
847*3d8817e4Smiod    global variables, which is a no-no in the BFD world.  */
848*3d8817e4Smiod struct coff_arm_link_hash_table
849*3d8817e4Smiod   {
850*3d8817e4Smiod     /* The original coff_link_hash_table structure.  MUST be first field.  */
851*3d8817e4Smiod     struct coff_link_hash_table	root;
852*3d8817e4Smiod 
853*3d8817e4Smiod     /* The size in bytes of the section containing the Thumb-to-ARM glue.  */
854*3d8817e4Smiod     bfd_size_type		thumb_glue_size;
855*3d8817e4Smiod 
856*3d8817e4Smiod     /* The size in bytes of the section containing the ARM-to-Thumb glue.  */
857*3d8817e4Smiod     bfd_size_type		arm_glue_size;
858*3d8817e4Smiod 
859*3d8817e4Smiod     /* An arbitrary input BFD chosen to hold the glue sections.  */
860*3d8817e4Smiod     bfd *			bfd_of_glue_owner;
861*3d8817e4Smiod 
862*3d8817e4Smiod     /* Support interworking with old, non-interworking aware ARM code.  */
863*3d8817e4Smiod     int 			support_old_code;
864*3d8817e4Smiod };
865*3d8817e4Smiod 
866*3d8817e4Smiod /* Get the ARM coff linker hash table from a link_info structure.  */
867*3d8817e4Smiod #define coff_arm_hash_table(info) \
868*3d8817e4Smiod   ((struct coff_arm_link_hash_table *) ((info)->hash))
869*3d8817e4Smiod 
870*3d8817e4Smiod /* Create an ARM coff linker hash table.  */
871*3d8817e4Smiod 
872*3d8817e4Smiod static struct bfd_link_hash_table *
coff_arm_link_hash_table_create(bfd * abfd)873*3d8817e4Smiod coff_arm_link_hash_table_create (bfd * abfd)
874*3d8817e4Smiod {
875*3d8817e4Smiod   struct coff_arm_link_hash_table * ret;
876*3d8817e4Smiod   bfd_size_type amt = sizeof (struct coff_arm_link_hash_table);
877*3d8817e4Smiod 
878*3d8817e4Smiod   ret = bfd_malloc (amt);
879*3d8817e4Smiod   if (ret == NULL)
880*3d8817e4Smiod     return NULL;
881*3d8817e4Smiod 
882*3d8817e4Smiod   if (!_bfd_coff_link_hash_table_init (&ret->root,
883*3d8817e4Smiod 				       abfd,
884*3d8817e4Smiod 				       _bfd_coff_link_hash_newfunc,
885*3d8817e4Smiod 				       sizeof (struct coff_link_hash_entry)))
886*3d8817e4Smiod     {
887*3d8817e4Smiod       free (ret);
888*3d8817e4Smiod       return NULL;
889*3d8817e4Smiod     }
890*3d8817e4Smiod 
891*3d8817e4Smiod   ret->thumb_glue_size   = 0;
892*3d8817e4Smiod   ret->arm_glue_size     = 0;
893*3d8817e4Smiod   ret->bfd_of_glue_owner = NULL;
894*3d8817e4Smiod 
895*3d8817e4Smiod   return & ret->root.root;
896*3d8817e4Smiod }
897*3d8817e4Smiod 
898*3d8817e4Smiod static void
arm_emit_base_file_entry(struct bfd_link_info * info,bfd * output_bfd,asection * input_section,bfd_vma reloc_offset)899*3d8817e4Smiod arm_emit_base_file_entry (struct bfd_link_info *info,
900*3d8817e4Smiod 			  bfd *output_bfd,
901*3d8817e4Smiod 			  asection *input_section,
902*3d8817e4Smiod 			  bfd_vma reloc_offset)
903*3d8817e4Smiod {
904*3d8817e4Smiod   bfd_vma addr = reloc_offset
905*3d8817e4Smiod                 - input_section->vma
906*3d8817e4Smiod                 + input_section->output_offset
907*3d8817e4Smiod                   + input_section->output_section->vma;
908*3d8817e4Smiod 
909*3d8817e4Smiod   if (coff_data (output_bfd)->pe)
910*3d8817e4Smiod      addr -= pe_data (output_bfd)->pe_opthdr.ImageBase;
911*3d8817e4Smiod   fwrite (& addr, 1, sizeof (addr), (FILE *) info->base_file);
912*3d8817e4Smiod 
913*3d8817e4Smiod }
914*3d8817e4Smiod 
915*3d8817e4Smiod #ifndef ARM_WINCE
916*3d8817e4Smiod /* The thumb form of a long branch is a bit finicky, because the offset
917*3d8817e4Smiod    encoding is split over two fields, each in it's own instruction. They
918*3d8817e4Smiod    can occur in any order. So given a thumb form of long branch, and an
919*3d8817e4Smiod    offset, insert the offset into the thumb branch and return finished
920*3d8817e4Smiod    instruction.
921*3d8817e4Smiod 
922*3d8817e4Smiod    It takes two thumb instructions to encode the target address. Each has
923*3d8817e4Smiod    11 bits to invest. The upper 11 bits are stored in one (identified by
924*3d8817e4Smiod    H-0.. see below), the lower 11 bits are stored in the other (identified
925*3d8817e4Smiod    by H-1).
926*3d8817e4Smiod 
927*3d8817e4Smiod    Combine together and shifted left by 1 (it's a half word address) and
928*3d8817e4Smiod    there you have it.
929*3d8817e4Smiod 
930*3d8817e4Smiod      Op: 1111 = F,
931*3d8817e4Smiod      H-0, upper address-0 = 000
932*3d8817e4Smiod      Op: 1111 = F,
933*3d8817e4Smiod      H-1, lower address-0 = 800
934*3d8817e4Smiod 
935*3d8817e4Smiod    They can be ordered either way, but the arm tools I've seen always put
936*3d8817e4Smiod    the lower one first. It probably doesn't matter. krk@cygnus.com
937*3d8817e4Smiod 
938*3d8817e4Smiod    XXX:  Actually the order does matter.  The second instruction (H-1)
939*3d8817e4Smiod    moves the computed address into the PC, so it must be the second one
940*3d8817e4Smiod    in the sequence.  The problem, however is that whilst little endian code
941*3d8817e4Smiod    stores the instructions in HI then LOW order, big endian code does the
942*3d8817e4Smiod    reverse.  nickc@cygnus.com.  */
943*3d8817e4Smiod 
944*3d8817e4Smiod #define LOW_HI_ORDER 0xF800F000
945*3d8817e4Smiod #define HI_LOW_ORDER 0xF000F800
946*3d8817e4Smiod 
947*3d8817e4Smiod static insn32
insert_thumb_branch(insn32 br_insn,int rel_off)948*3d8817e4Smiod insert_thumb_branch (insn32 br_insn, int rel_off)
949*3d8817e4Smiod {
950*3d8817e4Smiod   unsigned int low_bits;
951*3d8817e4Smiod   unsigned int high_bits;
952*3d8817e4Smiod 
953*3d8817e4Smiod   BFD_ASSERT ((rel_off & 1) != 1);
954*3d8817e4Smiod 
955*3d8817e4Smiod   rel_off >>= 1;                              /* Half word aligned address.  */
956*3d8817e4Smiod   low_bits = rel_off & 0x000007FF;            /* The bottom 11 bits.  */
957*3d8817e4Smiod   high_bits = (rel_off >> 11) & 0x000007FF;   /* The top 11 bits.  */
958*3d8817e4Smiod 
959*3d8817e4Smiod   if ((br_insn & LOW_HI_ORDER) == LOW_HI_ORDER)
960*3d8817e4Smiod     br_insn = LOW_HI_ORDER | (low_bits << 16) | high_bits;
961*3d8817e4Smiod   else if ((br_insn & HI_LOW_ORDER) == HI_LOW_ORDER)
962*3d8817e4Smiod     br_insn = HI_LOW_ORDER | (high_bits << 16) | low_bits;
963*3d8817e4Smiod   else
964*3d8817e4Smiod     /* FIXME: the BFD library should never abort except for internal errors
965*3d8817e4Smiod        - it should return an error status.  */
966*3d8817e4Smiod     abort (); /* Error - not a valid branch instruction form.  */
967*3d8817e4Smiod 
968*3d8817e4Smiod   return br_insn;
969*3d8817e4Smiod }
970*3d8817e4Smiod 
971*3d8817e4Smiod 
972*3d8817e4Smiod static struct coff_link_hash_entry *
find_thumb_glue(struct bfd_link_info * info,const char * name,bfd * input_bfd)973*3d8817e4Smiod find_thumb_glue (struct bfd_link_info *info,
974*3d8817e4Smiod 		 const char *name,
975*3d8817e4Smiod 		 bfd *input_bfd)
976*3d8817e4Smiod {
977*3d8817e4Smiod   char *tmp_name;
978*3d8817e4Smiod   struct coff_link_hash_entry *myh;
979*3d8817e4Smiod   bfd_size_type amt = strlen (name) + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1;
980*3d8817e4Smiod 
981*3d8817e4Smiod   tmp_name = bfd_malloc (amt);
982*3d8817e4Smiod 
983*3d8817e4Smiod   BFD_ASSERT (tmp_name);
984*3d8817e4Smiod 
985*3d8817e4Smiod   sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name);
986*3d8817e4Smiod 
987*3d8817e4Smiod   myh = coff_link_hash_lookup
988*3d8817e4Smiod     (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE);
989*3d8817e4Smiod 
990*3d8817e4Smiod   if (myh == NULL)
991*3d8817e4Smiod     /* xgettext:c-format */
992*3d8817e4Smiod     _bfd_error_handler (_("%B: unable to find THUMB glue '%s' for `%s'"),
993*3d8817e4Smiod 			input_bfd, tmp_name, name);
994*3d8817e4Smiod 
995*3d8817e4Smiod   free (tmp_name);
996*3d8817e4Smiod 
997*3d8817e4Smiod   return myh;
998*3d8817e4Smiod }
999*3d8817e4Smiod #endif /* not ARM_WINCE */
1000*3d8817e4Smiod 
1001*3d8817e4Smiod static struct coff_link_hash_entry *
find_arm_glue(struct bfd_link_info * info,const char * name,bfd * input_bfd)1002*3d8817e4Smiod find_arm_glue (struct bfd_link_info *info,
1003*3d8817e4Smiod 	       const char *name,
1004*3d8817e4Smiod 	       bfd *input_bfd)
1005*3d8817e4Smiod {
1006*3d8817e4Smiod   char *tmp_name;
1007*3d8817e4Smiod   struct coff_link_hash_entry * myh;
1008*3d8817e4Smiod   bfd_size_type amt = strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1;
1009*3d8817e4Smiod 
1010*3d8817e4Smiod   tmp_name = bfd_malloc (amt);
1011*3d8817e4Smiod 
1012*3d8817e4Smiod   BFD_ASSERT (tmp_name);
1013*3d8817e4Smiod 
1014*3d8817e4Smiod   sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name);
1015*3d8817e4Smiod 
1016*3d8817e4Smiod   myh = coff_link_hash_lookup
1017*3d8817e4Smiod     (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE);
1018*3d8817e4Smiod 
1019*3d8817e4Smiod   if (myh == NULL)
1020*3d8817e4Smiod     /* xgettext:c-format */
1021*3d8817e4Smiod     _bfd_error_handler (_("%B: unable to find ARM glue '%s' for `%s'"),
1022*3d8817e4Smiod 			input_bfd, tmp_name, name);
1023*3d8817e4Smiod 
1024*3d8817e4Smiod   free (tmp_name);
1025*3d8817e4Smiod 
1026*3d8817e4Smiod   return myh;
1027*3d8817e4Smiod }
1028*3d8817e4Smiod 
1029*3d8817e4Smiod /*
1030*3d8817e4Smiod   ARM->Thumb glue:
1031*3d8817e4Smiod 
1032*3d8817e4Smiod        .arm
1033*3d8817e4Smiod        __func_from_arm:
1034*3d8817e4Smiod 	     ldr r12, __func_addr
1035*3d8817e4Smiod 	     bx  r12
1036*3d8817e4Smiod        __func_addr:
1037*3d8817e4Smiod             .word func    @ behave as if you saw a ARM_32 reloc
1038*3d8817e4Smiod */
1039*3d8817e4Smiod 
1040*3d8817e4Smiod #define ARM2THUMB_GLUE_SIZE 12
1041*3d8817e4Smiod static const insn32 a2t1_ldr_insn       = 0xe59fc000;
1042*3d8817e4Smiod static const insn32 a2t2_bx_r12_insn    = 0xe12fff1c;
1043*3d8817e4Smiod static const insn32 a2t3_func_addr_insn = 0x00000001;
1044*3d8817e4Smiod 
1045*3d8817e4Smiod /*
1046*3d8817e4Smiod    Thumb->ARM:				Thumb->(non-interworking aware) ARM
1047*3d8817e4Smiod 
1048*3d8817e4Smiod    .thumb				.thumb
1049*3d8817e4Smiod    .align 2				.align 2
1050*3d8817e4Smiod       __func_from_thumb:		   __func_from_thumb:
1051*3d8817e4Smiod 	   bx pc				push {r6, lr}
1052*3d8817e4Smiod 	   nop					ldr  r6, __func_addr
1053*3d8817e4Smiod    .arm						mov  lr, pc
1054*3d8817e4Smiod       __func_change_to_arm:			bx   r6
1055*3d8817e4Smiod 	   b func   			.arm
1056*3d8817e4Smiod 					   __func_back_to_thumb:
1057*3d8817e4Smiod    		  				ldmia r13! {r6, lr}
1058*3d8817e4Smiod    					        bx    lr
1059*3d8817e4Smiod    					   __func_addr:
1060*3d8817e4Smiod 					        .word	func
1061*3d8817e4Smiod */
1062*3d8817e4Smiod 
1063*3d8817e4Smiod #define THUMB2ARM_GLUE_SIZE (globals->support_old_code ? 20 : 8)
1064*3d8817e4Smiod #ifndef ARM_WINCE
1065*3d8817e4Smiod static const insn16 t2a1_bx_pc_insn = 0x4778;
1066*3d8817e4Smiod static const insn16 t2a2_noop_insn  = 0x46c0;
1067*3d8817e4Smiod static const insn32 t2a3_b_insn     = 0xea000000;
1068*3d8817e4Smiod 
1069*3d8817e4Smiod static const insn16 t2a1_push_insn  = 0xb540;
1070*3d8817e4Smiod static const insn16 t2a2_ldr_insn   = 0x4e03;
1071*3d8817e4Smiod static const insn16 t2a3_mov_insn   = 0x46fe;
1072*3d8817e4Smiod static const insn16 t2a4_bx_insn    = 0x4730;
1073*3d8817e4Smiod static const insn32 t2a5_pop_insn   = 0xe8bd4040;
1074*3d8817e4Smiod static const insn32 t2a6_bx_insn    = 0xe12fff1e;
1075*3d8817e4Smiod #endif
1076*3d8817e4Smiod 
1077*3d8817e4Smiod /* TODO:
1078*3d8817e4Smiod      We should really create new local (static) symbols in destination
1079*3d8817e4Smiod      object for each stub we create.  We should also create local
1080*3d8817e4Smiod      (static) symbols within the stubs when switching between ARM and
1081*3d8817e4Smiod      Thumb code.  This will ensure that the debugger and disassembler
1082*3d8817e4Smiod      can present a better view of stubs.
1083*3d8817e4Smiod 
1084*3d8817e4Smiod      We can treat stubs like literal sections, and for the THUMB9 ones
1085*3d8817e4Smiod      (short addressing range) we should be able to insert the stubs
1086*3d8817e4Smiod      between sections. i.e. the simplest approach (since relocations
1087*3d8817e4Smiod      are done on a section basis) is to dump the stubs at the end of
1088*3d8817e4Smiod      processing a section. That way we can always try and minimise the
1089*3d8817e4Smiod      offset to and from a stub. However, this does not map well onto
1090*3d8817e4Smiod      the way that the linker/BFD does its work: mapping all input
1091*3d8817e4Smiod      sections to output sections via the linker script before doing
1092*3d8817e4Smiod      all the processing.
1093*3d8817e4Smiod 
1094*3d8817e4Smiod      Unfortunately it may be easier to just to disallow short range
1095*3d8817e4Smiod      Thumb->ARM stubs (i.e. no conditional inter-working branches,
1096*3d8817e4Smiod      only branch-and-link (BL) calls.  This will simplify the processing
1097*3d8817e4Smiod      since we can then put all of the stubs into their own section.
1098*3d8817e4Smiod 
1099*3d8817e4Smiod   TODO:
1100*3d8817e4Smiod      On a different subject, rather than complaining when a
1101*3d8817e4Smiod      branch cannot fit in the number of bits available for the
1102*3d8817e4Smiod      instruction we should generate a trampoline stub (needed to
1103*3d8817e4Smiod      address the complete 32bit address space).  */
1104*3d8817e4Smiod 
1105*3d8817e4Smiod /* The standard COFF backend linker does not cope with the special
1106*3d8817e4Smiod    Thumb BRANCH23 relocation.  The alternative would be to split the
1107*3d8817e4Smiod    BRANCH23 into seperate HI23 and LO23 relocations. However, it is a
1108*3d8817e4Smiod    bit simpler simply providing our own relocation driver.  */
1109*3d8817e4Smiod 
1110*3d8817e4Smiod /* The reloc processing routine for the ARM/Thumb COFF linker.  NOTE:
1111*3d8817e4Smiod    This code is a very slightly modified copy of
1112*3d8817e4Smiod    _bfd_coff_generic_relocate_section.  It would be a much more
1113*3d8817e4Smiod    maintainable solution to have a MACRO that could be expanded within
1114*3d8817e4Smiod    _bfd_coff_generic_relocate_section that would only be provided for
1115*3d8817e4Smiod    ARM/Thumb builds.  It is only the code marked THUMBEXTENSION that
1116*3d8817e4Smiod    is different from the original.  */
1117*3d8817e4Smiod 
1118*3d8817e4Smiod static bfd_boolean
coff_arm_relocate_section(bfd * output_bfd,struct bfd_link_info * info,bfd * input_bfd,asection * input_section,bfd_byte * contents,struct internal_reloc * relocs,struct internal_syment * syms,asection ** sections)1119*3d8817e4Smiod coff_arm_relocate_section (bfd *output_bfd,
1120*3d8817e4Smiod 			   struct bfd_link_info *info,
1121*3d8817e4Smiod 			   bfd *input_bfd,
1122*3d8817e4Smiod 			   asection *input_section,
1123*3d8817e4Smiod 			   bfd_byte *contents,
1124*3d8817e4Smiod 			   struct internal_reloc *relocs,
1125*3d8817e4Smiod 			   struct internal_syment *syms,
1126*3d8817e4Smiod 			   asection **sections)
1127*3d8817e4Smiod {
1128*3d8817e4Smiod   struct internal_reloc * rel;
1129*3d8817e4Smiod   struct internal_reloc * relend;
1130*3d8817e4Smiod #ifndef ARM_WINCE
1131*3d8817e4Smiod   bfd_vma high_address = bfd_get_section_limit (input_bfd, input_section);
1132*3d8817e4Smiod #endif
1133*3d8817e4Smiod 
1134*3d8817e4Smiod   rel = relocs;
1135*3d8817e4Smiod   relend = rel + input_section->reloc_count;
1136*3d8817e4Smiod 
1137*3d8817e4Smiod   for (; rel < relend; rel++)
1138*3d8817e4Smiod     {
1139*3d8817e4Smiod       int                            done = 0;
1140*3d8817e4Smiod       long                           symndx;
1141*3d8817e4Smiod       struct coff_link_hash_entry *  h;
1142*3d8817e4Smiod       struct internal_syment *       sym;
1143*3d8817e4Smiod       bfd_vma                        addend;
1144*3d8817e4Smiod       bfd_vma                        val;
1145*3d8817e4Smiod       reloc_howto_type *             howto;
1146*3d8817e4Smiod       bfd_reloc_status_type          rstat;
1147*3d8817e4Smiod       bfd_vma                        h_val;
1148*3d8817e4Smiod 
1149*3d8817e4Smiod       symndx = rel->r_symndx;
1150*3d8817e4Smiod 
1151*3d8817e4Smiod       if (symndx == -1)
1152*3d8817e4Smiod 	{
1153*3d8817e4Smiod 	  h = NULL;
1154*3d8817e4Smiod 	  sym = NULL;
1155*3d8817e4Smiod 	}
1156*3d8817e4Smiod       else
1157*3d8817e4Smiod 	{
1158*3d8817e4Smiod 	  h = obj_coff_sym_hashes (input_bfd)[symndx];
1159*3d8817e4Smiod 	  sym = syms + symndx;
1160*3d8817e4Smiod 	}
1161*3d8817e4Smiod 
1162*3d8817e4Smiod       /* COFF treats common symbols in one of two ways.  Either the
1163*3d8817e4Smiod          size of the symbol is included in the section contents, or it
1164*3d8817e4Smiod          is not.  We assume that the size is not included, and force
1165*3d8817e4Smiod          the rtype_to_howto function to adjust the addend as needed.  */
1166*3d8817e4Smiod 
1167*3d8817e4Smiod       if (sym != NULL && sym->n_scnum != 0)
1168*3d8817e4Smiod 	addend = - sym->n_value;
1169*3d8817e4Smiod       else
1170*3d8817e4Smiod 	addend = 0;
1171*3d8817e4Smiod 
1172*3d8817e4Smiod       howto = coff_rtype_to_howto (input_bfd, input_section, rel, h,
1173*3d8817e4Smiod 				       sym, &addend);
1174*3d8817e4Smiod       if (howto == NULL)
1175*3d8817e4Smiod 	return FALSE;
1176*3d8817e4Smiod 
1177*3d8817e4Smiod       /* The relocation_section function will skip pcrel_offset relocs
1178*3d8817e4Smiod          when doing a relocatable link.  However, we want to convert
1179*3d8817e4Smiod          ARM_26 to ARM_26D relocs if possible.  We return a fake howto in
1180*3d8817e4Smiod          this case without pcrel_offset set, and adjust the addend to
1181*3d8817e4Smiod          compensate.  'partial_inplace' is also set, since we want 'done'
1182*3d8817e4Smiod          relocations to be reflected in section's data.  */
1183*3d8817e4Smiod       if (rel->r_type == ARM_26
1184*3d8817e4Smiod           && h != NULL
1185*3d8817e4Smiod           && info->relocatable
1186*3d8817e4Smiod           && (h->root.type == bfd_link_hash_defined
1187*3d8817e4Smiod 	      || h->root.type == bfd_link_hash_defweak)
1188*3d8817e4Smiod           && (h->root.u.def.section->output_section
1189*3d8817e4Smiod 	      == input_section->output_section))
1190*3d8817e4Smiod         {
1191*3d8817e4Smiod           static reloc_howto_type fake_arm26_reloc =
1192*3d8817e4Smiod 	    HOWTO (ARM_26,
1193*3d8817e4Smiod     	       2,
1194*3d8817e4Smiod     	       2,
1195*3d8817e4Smiod     	       24,
1196*3d8817e4Smiod     	       TRUE,
1197*3d8817e4Smiod     	       0,
1198*3d8817e4Smiod     	       complain_overflow_signed,
1199*3d8817e4Smiod     	       aoutarm_fix_pcrel_26 ,
1200*3d8817e4Smiod     	       "ARM_26",
1201*3d8817e4Smiod     	       TRUE,
1202*3d8817e4Smiod     	       0x00ffffff,
1203*3d8817e4Smiod     	       0x00ffffff,
1204*3d8817e4Smiod     	       FALSE);
1205*3d8817e4Smiod 
1206*3d8817e4Smiod           addend -= rel->r_vaddr - input_section->vma;
1207*3d8817e4Smiod #ifdef ARM_WINCE
1208*3d8817e4Smiod           /* FIXME: I don't know why, but the hack is necessary for correct
1209*3d8817e4Smiod                     generation of bl's instruction offset.  */
1210*3d8817e4Smiod           addend -= 8;
1211*3d8817e4Smiod #endif
1212*3d8817e4Smiod           howto = &fake_arm26_reloc;
1213*3d8817e4Smiod         }
1214*3d8817e4Smiod 
1215*3d8817e4Smiod #ifdef ARM_WINCE
1216*3d8817e4Smiod       /* MS ARM-CE makes the reloc relative to the opcode's pc, not
1217*3d8817e4Smiod 	 the next opcode's pc, so is off by one.  */
1218*3d8817e4Smiod #endif
1219*3d8817e4Smiod 
1220*3d8817e4Smiod       /* If we are doing a relocatable link, then we can just ignore
1221*3d8817e4Smiod          a PC relative reloc that is pcrel_offset.  It will already
1222*3d8817e4Smiod          have the correct value.  If this is not a relocatable link,
1223*3d8817e4Smiod          then we should ignore the symbol value.  */
1224*3d8817e4Smiod       if (howto->pc_relative && howto->pcrel_offset)
1225*3d8817e4Smiod         {
1226*3d8817e4Smiod           if (info->relocatable)
1227*3d8817e4Smiod             continue;
1228*3d8817e4Smiod 	  /* FIXME - it is not clear which targets need this next test
1229*3d8817e4Smiod 	     and which do not.  It is known that it is needed for the
1230*3d8817e4Smiod 	     VxWorks and EPOC-PE targets, but it is also known that it
1231*3d8817e4Smiod 	     was suppressed for other ARM targets.  This ought to be
1232*3d8817e4Smiod 	     sorted out one day.  */
1233*3d8817e4Smiod #ifdef ARM_COFF_BUGFIX
1234*3d8817e4Smiod 	  /* We must not ignore the symbol value.  If the symbol is
1235*3d8817e4Smiod 	     within the same section, the relocation should have already
1236*3d8817e4Smiod 	     been fixed, but if it is not, we'll be handed a reloc into
1237*3d8817e4Smiod 	     the beginning of the symbol's section, so we must not cancel
1238*3d8817e4Smiod 	     out the symbol's value, otherwise we'll be adding it in
1239*3d8817e4Smiod 	     twice.  */
1240*3d8817e4Smiod           if (sym != NULL && sym->n_scnum != 0)
1241*3d8817e4Smiod             addend += sym->n_value;
1242*3d8817e4Smiod #endif
1243*3d8817e4Smiod         }
1244*3d8817e4Smiod 
1245*3d8817e4Smiod       val = 0;
1246*3d8817e4Smiod 
1247*3d8817e4Smiod       if (h == NULL)
1248*3d8817e4Smiod 	{
1249*3d8817e4Smiod 	  asection *sec;
1250*3d8817e4Smiod 
1251*3d8817e4Smiod 	  if (symndx == -1)
1252*3d8817e4Smiod 	    {
1253*3d8817e4Smiod 	      sec = bfd_abs_section_ptr;
1254*3d8817e4Smiod 	      val = 0;
1255*3d8817e4Smiod 	    }
1256*3d8817e4Smiod 	  else
1257*3d8817e4Smiod 	    {
1258*3d8817e4Smiod 	      sec = sections[symndx];
1259*3d8817e4Smiod               val = (sec->output_section->vma
1260*3d8817e4Smiod 		     + sec->output_offset
1261*3d8817e4Smiod 		     + sym->n_value
1262*3d8817e4Smiod 		     - sec->vma);
1263*3d8817e4Smiod 	    }
1264*3d8817e4Smiod 	}
1265*3d8817e4Smiod       else
1266*3d8817e4Smiod 	{
1267*3d8817e4Smiod           /* We don't output the stubs if we are generating a
1268*3d8817e4Smiod              relocatable output file, since we may as well leave the
1269*3d8817e4Smiod              stub generation to the final linker pass. If we fail to
1270*3d8817e4Smiod 	     verify that the name is defined, we'll try to build stubs
1271*3d8817e4Smiod 	     for an undefined name...  */
1272*3d8817e4Smiod           if (! info->relocatable
1273*3d8817e4Smiod 	      && (   h->root.type == bfd_link_hash_defined
1274*3d8817e4Smiod 		  || h->root.type == bfd_link_hash_defweak))
1275*3d8817e4Smiod             {
1276*3d8817e4Smiod 	      asection *   h_sec = h->root.u.def.section;
1277*3d8817e4Smiod 	      const char * name  = h->root.root.string;
1278*3d8817e4Smiod 
1279*3d8817e4Smiod 	      /* h locates the symbol referenced in the reloc.  */
1280*3d8817e4Smiod 	      h_val = (h->root.u.def.value
1281*3d8817e4Smiod 		       + h_sec->output_section->vma
1282*3d8817e4Smiod 		       + h_sec->output_offset);
1283*3d8817e4Smiod 
1284*3d8817e4Smiod               if (howto->type == ARM_26)
1285*3d8817e4Smiod                 {
1286*3d8817e4Smiod                   if (   h->class == C_THUMBSTATFUNC
1287*3d8817e4Smiod 		      || h->class == C_THUMBEXTFUNC)
1288*3d8817e4Smiod 		    {
1289*3d8817e4Smiod 		      /* Arm code calling a Thumb function.  */
1290*3d8817e4Smiod 		      unsigned long int                 tmp;
1291*3d8817e4Smiod 		      bfd_vma                           my_offset;
1292*3d8817e4Smiod 		      asection *                        s;
1293*3d8817e4Smiod 		      long int                          ret_offset;
1294*3d8817e4Smiod 		      struct coff_link_hash_entry *     myh;
1295*3d8817e4Smiod 		      struct coff_arm_link_hash_table * globals;
1296*3d8817e4Smiod 
1297*3d8817e4Smiod 		      myh = find_arm_glue (info, name, input_bfd);
1298*3d8817e4Smiod 		      if (myh == NULL)
1299*3d8817e4Smiod 			return FALSE;
1300*3d8817e4Smiod 
1301*3d8817e4Smiod 		      globals = coff_arm_hash_table (info);
1302*3d8817e4Smiod 
1303*3d8817e4Smiod 		      BFD_ASSERT (globals != NULL);
1304*3d8817e4Smiod 		      BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
1305*3d8817e4Smiod 
1306*3d8817e4Smiod 		      my_offset = myh->root.u.def.value;
1307*3d8817e4Smiod 
1308*3d8817e4Smiod 		      s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
1309*3d8817e4Smiod 						  ARM2THUMB_GLUE_SECTION_NAME);
1310*3d8817e4Smiod 		      BFD_ASSERT (s != NULL);
1311*3d8817e4Smiod 		      BFD_ASSERT (s->contents != NULL);
1312*3d8817e4Smiod 		      BFD_ASSERT (s->output_section != NULL);
1313*3d8817e4Smiod 
1314*3d8817e4Smiod 		      if ((my_offset & 0x01) == 0x01)
1315*3d8817e4Smiod 			{
1316*3d8817e4Smiod 			  if (h_sec->owner != NULL
1317*3d8817e4Smiod 			      && INTERWORK_SET (h_sec->owner)
1318*3d8817e4Smiod 			      && ! INTERWORK_FLAG (h_sec->owner))
1319*3d8817e4Smiod 			    _bfd_error_handler
1320*3d8817e4Smiod 			      /* xgettext:c-format */
1321*3d8817e4Smiod 			      (_("%B(%s): warning: interworking not enabled.\n"
1322*3d8817e4Smiod 				 "  first occurrence: %B: arm call to thumb"),
1323*3d8817e4Smiod 			       h_sec->owner, input_bfd, name);
1324*3d8817e4Smiod 
1325*3d8817e4Smiod 			  --my_offset;
1326*3d8817e4Smiod 			  myh->root.u.def.value = my_offset;
1327*3d8817e4Smiod 
1328*3d8817e4Smiod 			  bfd_put_32 (output_bfd, (bfd_vma) a2t1_ldr_insn,
1329*3d8817e4Smiod 				      s->contents + my_offset);
1330*3d8817e4Smiod 
1331*3d8817e4Smiod 			  bfd_put_32 (output_bfd, (bfd_vma) a2t2_bx_r12_insn,
1332*3d8817e4Smiod 				      s->contents + my_offset + 4);
1333*3d8817e4Smiod 
1334*3d8817e4Smiod 			  /* It's a thumb address.  Add the low order bit.  */
1335*3d8817e4Smiod 			  bfd_put_32 (output_bfd, h_val | a2t3_func_addr_insn,
1336*3d8817e4Smiod 				      s->contents + my_offset + 8);
1337*3d8817e4Smiod 
1338*3d8817e4Smiod                           if (info->base_file)
1339*3d8817e4Smiod                             arm_emit_base_file_entry (info, output_bfd, s,
1340*3d8817e4Smiod                                                       my_offset + 8);
1341*3d8817e4Smiod 
1342*3d8817e4Smiod 			}
1343*3d8817e4Smiod 
1344*3d8817e4Smiod 		      BFD_ASSERT (my_offset <= globals->arm_glue_size);
1345*3d8817e4Smiod 
1346*3d8817e4Smiod 		      tmp = bfd_get_32 (input_bfd, contents + rel->r_vaddr
1347*3d8817e4Smiod 					- input_section->vma);
1348*3d8817e4Smiod 
1349*3d8817e4Smiod 		      tmp = tmp & 0xFF000000;
1350*3d8817e4Smiod 
1351*3d8817e4Smiod 		      /* Somehow these are both 4 too far, so subtract 8.  */
1352*3d8817e4Smiod 		      ret_offset =
1353*3d8817e4Smiod 			s->output_offset
1354*3d8817e4Smiod 			+ my_offset
1355*3d8817e4Smiod 			+ s->output_section->vma
1356*3d8817e4Smiod 			- (input_section->output_offset
1357*3d8817e4Smiod 			   + input_section->output_section->vma
1358*3d8817e4Smiod 			   + rel->r_vaddr)
1359*3d8817e4Smiod 			- 8;
1360*3d8817e4Smiod 
1361*3d8817e4Smiod 		      tmp = tmp | ((ret_offset >> 2) & 0x00FFFFFF);
1362*3d8817e4Smiod 
1363*3d8817e4Smiod 		      bfd_put_32 (output_bfd, (bfd_vma) tmp,
1364*3d8817e4Smiod 				  contents + rel->r_vaddr - input_section->vma);
1365*3d8817e4Smiod 		      done = 1;
1366*3d8817e4Smiod 		    }
1367*3d8817e4Smiod                 }
1368*3d8817e4Smiod 
1369*3d8817e4Smiod #ifndef ARM_WINCE
1370*3d8817e4Smiod 	      /* Note: We used to check for ARM_THUMB9 and ARM_THUMB12.  */
1371*3d8817e4Smiod               else if (howto->type == ARM_THUMB23)
1372*3d8817e4Smiod                 {
1373*3d8817e4Smiod                   if (   h->class == C_EXT
1374*3d8817e4Smiod 		      || h->class == C_STAT
1375*3d8817e4Smiod 		      || h->class == C_LABEL)
1376*3d8817e4Smiod 		    {
1377*3d8817e4Smiod 		      /* Thumb code calling an ARM function.  */
1378*3d8817e4Smiod 		      asection *                         s = 0;
1379*3d8817e4Smiod 		      bfd_vma                            my_offset;
1380*3d8817e4Smiod 		      unsigned long int                  tmp;
1381*3d8817e4Smiod 		      long int                           ret_offset;
1382*3d8817e4Smiod 		      struct coff_link_hash_entry *      myh;
1383*3d8817e4Smiod 		      struct coff_arm_link_hash_table *  globals;
1384*3d8817e4Smiod 
1385*3d8817e4Smiod 		      myh = find_thumb_glue (info, name, input_bfd);
1386*3d8817e4Smiod 		      if (myh == NULL)
1387*3d8817e4Smiod 			return FALSE;
1388*3d8817e4Smiod 
1389*3d8817e4Smiod 		      globals = coff_arm_hash_table (info);
1390*3d8817e4Smiod 
1391*3d8817e4Smiod 		      BFD_ASSERT (globals != NULL);
1392*3d8817e4Smiod 		      BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
1393*3d8817e4Smiod 
1394*3d8817e4Smiod 		      my_offset = myh->root.u.def.value;
1395*3d8817e4Smiod 
1396*3d8817e4Smiod 		      s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
1397*3d8817e4Smiod 						   THUMB2ARM_GLUE_SECTION_NAME);
1398*3d8817e4Smiod 
1399*3d8817e4Smiod 		      BFD_ASSERT (s != NULL);
1400*3d8817e4Smiod 		      BFD_ASSERT (s->contents != NULL);
1401*3d8817e4Smiod 		      BFD_ASSERT (s->output_section != NULL);
1402*3d8817e4Smiod 
1403*3d8817e4Smiod 		      if ((my_offset & 0x01) == 0x01)
1404*3d8817e4Smiod 			{
1405*3d8817e4Smiod 			  if (h_sec->owner != NULL
1406*3d8817e4Smiod 			      && INTERWORK_SET (h_sec->owner)
1407*3d8817e4Smiod 			      && ! INTERWORK_FLAG (h_sec->owner)
1408*3d8817e4Smiod 			      && ! globals->support_old_code)
1409*3d8817e4Smiod 			    _bfd_error_handler
1410*3d8817e4Smiod 			      /* xgettext:c-format */
1411*3d8817e4Smiod 			      (_("%B(%s): warning: interworking not enabled.\n"
1412*3d8817e4Smiod 				 "  first occurrence: %B: thumb call to arm\n"
1413*3d8817e4Smiod 				 "  consider relinking with --support-old-code enabled"),
1414*3d8817e4Smiod 			       h_sec->owner, input_bfd, name);
1415*3d8817e4Smiod 
1416*3d8817e4Smiod 			  -- my_offset;
1417*3d8817e4Smiod 			  myh->root.u.def.value = my_offset;
1418*3d8817e4Smiod 
1419*3d8817e4Smiod 			  if (globals->support_old_code)
1420*3d8817e4Smiod 			    {
1421*3d8817e4Smiod 			      bfd_put_16 (output_bfd, (bfd_vma) t2a1_push_insn,
1422*3d8817e4Smiod 					  s->contents + my_offset);
1423*3d8817e4Smiod 
1424*3d8817e4Smiod 			      bfd_put_16 (output_bfd, (bfd_vma) t2a2_ldr_insn,
1425*3d8817e4Smiod 					  s->contents + my_offset + 2);
1426*3d8817e4Smiod 
1427*3d8817e4Smiod 			      bfd_put_16 (output_bfd, (bfd_vma) t2a3_mov_insn,
1428*3d8817e4Smiod 					  s->contents + my_offset + 4);
1429*3d8817e4Smiod 
1430*3d8817e4Smiod 			      bfd_put_16 (output_bfd, (bfd_vma) t2a4_bx_insn,
1431*3d8817e4Smiod 					  s->contents + my_offset + 6);
1432*3d8817e4Smiod 
1433*3d8817e4Smiod 			      bfd_put_32 (output_bfd, (bfd_vma) t2a5_pop_insn,
1434*3d8817e4Smiod 					  s->contents + my_offset + 8);
1435*3d8817e4Smiod 
1436*3d8817e4Smiod 			      bfd_put_32 (output_bfd, (bfd_vma) t2a6_bx_insn,
1437*3d8817e4Smiod 					  s->contents + my_offset + 12);
1438*3d8817e4Smiod 
1439*3d8817e4Smiod 			      /* Store the address of the function in the last word of the stub.  */
1440*3d8817e4Smiod 			      bfd_put_32 (output_bfd, h_val,
1441*3d8817e4Smiod 					  s->contents + my_offset + 16);
1442*3d8817e4Smiod 
1443*3d8817e4Smiod                               if (info->base_file)
1444*3d8817e4Smiod                                 arm_emit_base_file_entry (info, output_bfd, s,
1445*3d8817e4Smiod 							  my_offset + 16);
1446*3d8817e4Smiod 			    }
1447*3d8817e4Smiod 			  else
1448*3d8817e4Smiod 			    {
1449*3d8817e4Smiod 			      bfd_put_16 (output_bfd, (bfd_vma) t2a1_bx_pc_insn,
1450*3d8817e4Smiod 					  s->contents + my_offset);
1451*3d8817e4Smiod 
1452*3d8817e4Smiod 			      bfd_put_16 (output_bfd, (bfd_vma) t2a2_noop_insn,
1453*3d8817e4Smiod 					  s->contents + my_offset + 2);
1454*3d8817e4Smiod 
1455*3d8817e4Smiod 			      ret_offset =
1456*3d8817e4Smiod 		/* Address of destination of the stub.  */
1457*3d8817e4Smiod 				((bfd_signed_vma) h_val)
1458*3d8817e4Smiod 				- ((bfd_signed_vma)
1459*3d8817e4Smiod 		/* Offset from the start of the current section to the start of the stubs.  */
1460*3d8817e4Smiod 				   (s->output_offset
1461*3d8817e4Smiod 		/* Offset of the start of this stub from the start of the stubs.  */
1462*3d8817e4Smiod 				    + my_offset
1463*3d8817e4Smiod 		/* Address of the start of the current section.  */
1464*3d8817e4Smiod 				    + s->output_section->vma)
1465*3d8817e4Smiod 		/* The branch instruction is 4 bytes into the stub.  */
1466*3d8817e4Smiod 				   + 4
1467*3d8817e4Smiod 		/* ARM branches work from the pc of the instruction + 8.  */
1468*3d8817e4Smiod 				   + 8);
1469*3d8817e4Smiod 
1470*3d8817e4Smiod 			      bfd_put_32 (output_bfd,
1471*3d8817e4Smiod 					  (bfd_vma) t2a3_b_insn | ((ret_offset >> 2) & 0x00FFFFFF),
1472*3d8817e4Smiod 					  s->contents + my_offset + 4);
1473*3d8817e4Smiod 
1474*3d8817e4Smiod 			    }
1475*3d8817e4Smiod 			}
1476*3d8817e4Smiod 
1477*3d8817e4Smiod 		      BFD_ASSERT (my_offset <= globals->thumb_glue_size);
1478*3d8817e4Smiod 
1479*3d8817e4Smiod 		      /* Now go back and fix up the original BL insn to point
1480*3d8817e4Smiod 			 to here.  */
1481*3d8817e4Smiod 		      ret_offset =
1482*3d8817e4Smiod 			s->output_offset
1483*3d8817e4Smiod 			+ my_offset
1484*3d8817e4Smiod 			- (input_section->output_offset
1485*3d8817e4Smiod 			   + rel->r_vaddr)
1486*3d8817e4Smiod 			-4;
1487*3d8817e4Smiod 
1488*3d8817e4Smiod 		      tmp = bfd_get_32 (input_bfd, contents + rel->r_vaddr
1489*3d8817e4Smiod 					- input_section->vma);
1490*3d8817e4Smiod 
1491*3d8817e4Smiod 		      bfd_put_32 (output_bfd,
1492*3d8817e4Smiod 				  (bfd_vma) insert_thumb_branch (tmp,
1493*3d8817e4Smiod 								 ret_offset),
1494*3d8817e4Smiod 				  contents + rel->r_vaddr - input_section->vma);
1495*3d8817e4Smiod 
1496*3d8817e4Smiod 		      done = 1;
1497*3d8817e4Smiod                     }
1498*3d8817e4Smiod                 }
1499*3d8817e4Smiod #endif
1500*3d8817e4Smiod             }
1501*3d8817e4Smiod 
1502*3d8817e4Smiod           /* If the relocation type and destination symbol does not
1503*3d8817e4Smiod              fall into one of the above categories, then we can just
1504*3d8817e4Smiod              perform a direct link.  */
1505*3d8817e4Smiod 
1506*3d8817e4Smiod 	  if (done)
1507*3d8817e4Smiod 	    rstat = bfd_reloc_ok;
1508*3d8817e4Smiod 	  else
1509*3d8817e4Smiod 	    if (   h->root.type == bfd_link_hash_defined
1510*3d8817e4Smiod 		|| h->root.type == bfd_link_hash_defweak)
1511*3d8817e4Smiod 	    {
1512*3d8817e4Smiod 	      asection *sec;
1513*3d8817e4Smiod 
1514*3d8817e4Smiod 	      sec = h->root.u.def.section;
1515*3d8817e4Smiod 	      val = (h->root.u.def.value
1516*3d8817e4Smiod 		     + sec->output_section->vma
1517*3d8817e4Smiod 		     + sec->output_offset);
1518*3d8817e4Smiod 	      }
1519*3d8817e4Smiod 
1520*3d8817e4Smiod 	  else if (! info->relocatable)
1521*3d8817e4Smiod 	    {
1522*3d8817e4Smiod 	      if (! ((*info->callbacks->undefined_symbol)
1523*3d8817e4Smiod 		     (info, h->root.root.string, input_bfd, input_section,
1524*3d8817e4Smiod 		      rel->r_vaddr - input_section->vma, TRUE)))
1525*3d8817e4Smiod 		return FALSE;
1526*3d8817e4Smiod 	    }
1527*3d8817e4Smiod 	}
1528*3d8817e4Smiod 
1529*3d8817e4Smiod       if (info->base_file)
1530*3d8817e4Smiod 	{
1531*3d8817e4Smiod 	  /* Emit a reloc if the backend thinks it needs it.  */
1532*3d8817e4Smiod 	  if (sym && pe_data(output_bfd)->in_reloc_p(output_bfd, howto))
1533*3d8817e4Smiod             arm_emit_base_file_entry (info, output_bfd, input_section,
1534*3d8817e4Smiod 				      rel->r_vaddr);
1535*3d8817e4Smiod 	}
1536*3d8817e4Smiod 
1537*3d8817e4Smiod       if (done)
1538*3d8817e4Smiod 	rstat = bfd_reloc_ok;
1539*3d8817e4Smiod #ifndef ARM_WINCE
1540*3d8817e4Smiod       /* Only perform this fix during the final link, not a relocatable link.  */
1541*3d8817e4Smiod       else if (! info->relocatable
1542*3d8817e4Smiod 	       && howto->type == ARM_THUMB23)
1543*3d8817e4Smiod         {
1544*3d8817e4Smiod           /* This is pretty much a copy of what the default
1545*3d8817e4Smiod              _bfd_final_link_relocate and _bfd_relocate_contents
1546*3d8817e4Smiod              routines do to perform a relocation, with special
1547*3d8817e4Smiod              processing for the split addressing of the Thumb BL
1548*3d8817e4Smiod              instruction.  Again, it would probably be simpler adding a
1549*3d8817e4Smiod              ThumbBRANCH23 specific macro expansion into the default
1550*3d8817e4Smiod              code.  */
1551*3d8817e4Smiod 
1552*3d8817e4Smiod           bfd_vma address = rel->r_vaddr - input_section->vma;
1553*3d8817e4Smiod 
1554*3d8817e4Smiod 	  if (address > high_address)
1555*3d8817e4Smiod 	    rstat = bfd_reloc_outofrange;
1556*3d8817e4Smiod           else
1557*3d8817e4Smiod             {
1558*3d8817e4Smiod               bfd_vma relocation = val + addend;
1559*3d8817e4Smiod 	      int size = bfd_get_reloc_size (howto);
1560*3d8817e4Smiod 	      bfd_boolean overflow = FALSE;
1561*3d8817e4Smiod 	      bfd_byte *location = contents + address;
1562*3d8817e4Smiod 	      bfd_vma x = bfd_get_32 (input_bfd, location);
1563*3d8817e4Smiod 	      bfd_vma src_mask = 0x007FFFFE;
1564*3d8817e4Smiod 	      bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1;
1565*3d8817e4Smiod 	      bfd_signed_vma reloc_signed_min = ~reloc_signed_max;
1566*3d8817e4Smiod 	      bfd_vma check;
1567*3d8817e4Smiod 	      bfd_signed_vma signed_check;
1568*3d8817e4Smiod 	      bfd_vma add;
1569*3d8817e4Smiod 	      bfd_signed_vma signed_add;
1570*3d8817e4Smiod 
1571*3d8817e4Smiod 	      BFD_ASSERT (size == 4);
1572*3d8817e4Smiod 
1573*3d8817e4Smiod               /* howto->pc_relative should be TRUE for type 14 BRANCH23.  */
1574*3d8817e4Smiod               relocation -= (input_section->output_section->vma
1575*3d8817e4Smiod                              + input_section->output_offset);
1576*3d8817e4Smiod 
1577*3d8817e4Smiod               /* howto->pcrel_offset should be TRUE for type 14 BRANCH23.  */
1578*3d8817e4Smiod               relocation -= address;
1579*3d8817e4Smiod 
1580*3d8817e4Smiod 	      /* No need to negate the relocation with BRANCH23.  */
1581*3d8817e4Smiod 	      /* howto->complain_on_overflow == complain_overflow_signed for BRANCH23.  */
1582*3d8817e4Smiod 	      /* howto->rightshift == 1 */
1583*3d8817e4Smiod 
1584*3d8817e4Smiod 	      /* Drop unwanted bits from the value we are relocating to.  */
1585*3d8817e4Smiod 	      check = relocation >> howto->rightshift;
1586*3d8817e4Smiod 
1587*3d8817e4Smiod 	      /* If this is a signed value, the rightshift just dropped
1588*3d8817e4Smiod 		 leading 1 bits (assuming twos complement).  */
1589*3d8817e4Smiod 	      if ((bfd_signed_vma) relocation >= 0)
1590*3d8817e4Smiod 		signed_check = check;
1591*3d8817e4Smiod 	      else
1592*3d8817e4Smiod 		signed_check = (check
1593*3d8817e4Smiod 				| ((bfd_vma) - 1
1594*3d8817e4Smiod 				   & ~((bfd_vma) - 1 >> howto->rightshift)));
1595*3d8817e4Smiod 
1596*3d8817e4Smiod 	      /* Get the value from the object file.  */
1597*3d8817e4Smiod 	      if (bfd_big_endian (input_bfd))
1598*3d8817e4Smiod 		add = (((x) & 0x07ff0000) >> 4) | (((x) & 0x7ff) << 1);
1599*3d8817e4Smiod 	      else
1600*3d8817e4Smiod 		add = ((((x) & 0x7ff) << 12) | (((x) & 0x07ff0000) >> 15));
1601*3d8817e4Smiod 
1602*3d8817e4Smiod 	      /* Get the value from the object file with an appropriate sign.
1603*3d8817e4Smiod 		 The expression involving howto->src_mask isolates the upper
1604*3d8817e4Smiod 		 bit of src_mask.  If that bit is set in the value we are
1605*3d8817e4Smiod 		 adding, it is negative, and we subtract out that number times
1606*3d8817e4Smiod 		 two.  If src_mask includes the highest possible bit, then we
1607*3d8817e4Smiod 		 can not get the upper bit, but that does not matter since
1608*3d8817e4Smiod 		 signed_add needs no adjustment to become negative in that
1609*3d8817e4Smiod 		 case.  */
1610*3d8817e4Smiod 	      signed_add = add;
1611*3d8817e4Smiod 
1612*3d8817e4Smiod 	      if ((add & (((~ src_mask) >> 1) & src_mask)) != 0)
1613*3d8817e4Smiod 		signed_add -= (((~ src_mask) >> 1) & src_mask) << 1;
1614*3d8817e4Smiod 
1615*3d8817e4Smiod 	      /* howto->bitpos == 0 */
1616*3d8817e4Smiod 	      /* Add the value from the object file, shifted so that it is a
1617*3d8817e4Smiod 		 straight number.  */
1618*3d8817e4Smiod 	      signed_check += signed_add;
1619*3d8817e4Smiod 	      relocation   += signed_add;
1620*3d8817e4Smiod 
1621*3d8817e4Smiod 	      BFD_ASSERT (howto->complain_on_overflow == complain_overflow_signed);
1622*3d8817e4Smiod 
1623*3d8817e4Smiod 	      /* Assumes two's complement.  */
1624*3d8817e4Smiod 	      if (   signed_check > reloc_signed_max
1625*3d8817e4Smiod 		  || signed_check < reloc_signed_min)
1626*3d8817e4Smiod 		overflow = TRUE;
1627*3d8817e4Smiod 
1628*3d8817e4Smiod 	      /* Put the relocation into the correct bits.
1629*3d8817e4Smiod 		 For a BLX instruction, make sure that the relocation is rounded up
1630*3d8817e4Smiod 		 to a word boundary.  This follows the semantics of the instruction
1631*3d8817e4Smiod 		 which specifies that bit 1 of the target address will come from bit
1632*3d8817e4Smiod 		 1 of the base address.  */
1633*3d8817e4Smiod 	      if (bfd_big_endian (input_bfd))
1634*3d8817e4Smiod 	        {
1635*3d8817e4Smiod 		  if ((x & 0x1800) == 0x0800 && (relocation & 0x02))
1636*3d8817e4Smiod 		    relocation += 2;
1637*3d8817e4Smiod 		  relocation = (((relocation & 0xffe) >> 1)  | ((relocation << 4) & 0x07ff0000));
1638*3d8817e4Smiod 		}
1639*3d8817e4Smiod 	      else
1640*3d8817e4Smiod 	        {
1641*3d8817e4Smiod 		  if ((x & 0x18000000) == 0x08000000 && (relocation & 0x02))
1642*3d8817e4Smiod 		    relocation += 2;
1643*3d8817e4Smiod 		  relocation = (((relocation & 0xffe) << 15) | ((relocation >> 12) & 0x7ff));
1644*3d8817e4Smiod 		}
1645*3d8817e4Smiod 
1646*3d8817e4Smiod 	      /* Add the relocation to the correct bits of X.  */
1647*3d8817e4Smiod 	      x = ((x & ~howto->dst_mask) | relocation);
1648*3d8817e4Smiod 
1649*3d8817e4Smiod 	      /* Put the relocated value back in the object file.  */
1650*3d8817e4Smiod 	      bfd_put_32 (input_bfd, x, location);
1651*3d8817e4Smiod 
1652*3d8817e4Smiod 	      rstat = overflow ? bfd_reloc_overflow : bfd_reloc_ok;
1653*3d8817e4Smiod             }
1654*3d8817e4Smiod         }
1655*3d8817e4Smiod #endif
1656*3d8817e4Smiod       else
1657*3d8817e4Smiod         if (info->relocatable && ! howto->partial_inplace)
1658*3d8817e4Smiod             rstat = bfd_reloc_ok;
1659*3d8817e4Smiod         else
1660*3d8817e4Smiod 	  rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
1661*3d8817e4Smiod 					    contents,
1662*3d8817e4Smiod 					    rel->r_vaddr - input_section->vma,
1663*3d8817e4Smiod 					    val, addend);
1664*3d8817e4Smiod       /* Only perform this fix during the final link, not a relocatable link.  */
1665*3d8817e4Smiod       if (! info->relocatable
1666*3d8817e4Smiod 	  && (rel->r_type == ARM_32 || rel->r_type == ARM_RVA32))
1667*3d8817e4Smiod 	{
1668*3d8817e4Smiod 	  /* Determine if we need to set the bottom bit of a relocated address
1669*3d8817e4Smiod 	     because the address is the address of a Thumb code symbol.  */
1670*3d8817e4Smiod 	  int patchit = FALSE;
1671*3d8817e4Smiod 
1672*3d8817e4Smiod 	  if (h != NULL
1673*3d8817e4Smiod 	      && (   h->class == C_THUMBSTATFUNC
1674*3d8817e4Smiod 		  || h->class == C_THUMBEXTFUNC))
1675*3d8817e4Smiod 	    {
1676*3d8817e4Smiod 	      patchit = TRUE;
1677*3d8817e4Smiod 	    }
1678*3d8817e4Smiod 	  else if (sym != NULL
1679*3d8817e4Smiod 		   && sym->n_scnum > N_UNDEF)
1680*3d8817e4Smiod 	    {
1681*3d8817e4Smiod 	      /* No hash entry - use the symbol instead.  */
1682*3d8817e4Smiod 	      if (   sym->n_sclass == C_THUMBSTATFUNC
1683*3d8817e4Smiod 		  || sym->n_sclass == C_THUMBEXTFUNC)
1684*3d8817e4Smiod 		patchit = TRUE;
1685*3d8817e4Smiod 	    }
1686*3d8817e4Smiod 
1687*3d8817e4Smiod 	  if (patchit)
1688*3d8817e4Smiod 	    {
1689*3d8817e4Smiod 	      bfd_byte * location = contents + rel->r_vaddr - input_section->vma;
1690*3d8817e4Smiod 	      bfd_vma    x        = bfd_get_32 (input_bfd, location);
1691*3d8817e4Smiod 
1692*3d8817e4Smiod 	      bfd_put_32 (input_bfd, x | 1, location);
1693*3d8817e4Smiod 	    }
1694*3d8817e4Smiod 	}
1695*3d8817e4Smiod 
1696*3d8817e4Smiod       switch (rstat)
1697*3d8817e4Smiod 	{
1698*3d8817e4Smiod 	default:
1699*3d8817e4Smiod 	  abort ();
1700*3d8817e4Smiod 	case bfd_reloc_ok:
1701*3d8817e4Smiod 	  break;
1702*3d8817e4Smiod 	case bfd_reloc_outofrange:
1703*3d8817e4Smiod 	  (*_bfd_error_handler)
1704*3d8817e4Smiod 	    (_("%B: bad reloc address 0x%lx in section `%A'"),
1705*3d8817e4Smiod 	     input_bfd, input_section, (unsigned long) rel->r_vaddr);
1706*3d8817e4Smiod 	  return FALSE;
1707*3d8817e4Smiod 	case bfd_reloc_overflow:
1708*3d8817e4Smiod 	  {
1709*3d8817e4Smiod 	    const char *name;
1710*3d8817e4Smiod 	    char buf[SYMNMLEN + 1];
1711*3d8817e4Smiod 
1712*3d8817e4Smiod 	    if (symndx == -1)
1713*3d8817e4Smiod 	      name = "*ABS*";
1714*3d8817e4Smiod 	    else if (h != NULL)
1715*3d8817e4Smiod 	      name = NULL;
1716*3d8817e4Smiod 	    else
1717*3d8817e4Smiod 	      {
1718*3d8817e4Smiod 		name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
1719*3d8817e4Smiod 		if (name == NULL)
1720*3d8817e4Smiod 		  return FALSE;
1721*3d8817e4Smiod 	      }
1722*3d8817e4Smiod 
1723*3d8817e4Smiod 	    if (! ((*info->callbacks->reloc_overflow)
1724*3d8817e4Smiod 		   (info, (h ? &h->root : NULL), name, howto->name,
1725*3d8817e4Smiod 		    (bfd_vma) 0, input_bfd, input_section,
1726*3d8817e4Smiod 		    rel->r_vaddr - input_section->vma)))
1727*3d8817e4Smiod 	      return FALSE;
1728*3d8817e4Smiod 	  }
1729*3d8817e4Smiod 	}
1730*3d8817e4Smiod     }
1731*3d8817e4Smiod 
1732*3d8817e4Smiod   return TRUE;
1733*3d8817e4Smiod }
1734*3d8817e4Smiod 
1735*3d8817e4Smiod #ifndef COFF_IMAGE_WITH_PE
1736*3d8817e4Smiod 
1737*3d8817e4Smiod bfd_boolean
bfd_arm_allocate_interworking_sections(struct bfd_link_info * info)1738*3d8817e4Smiod bfd_arm_allocate_interworking_sections (struct bfd_link_info * info)
1739*3d8817e4Smiod {
1740*3d8817e4Smiod   asection *                        s;
1741*3d8817e4Smiod   bfd_byte *                        foo;
1742*3d8817e4Smiod   struct coff_arm_link_hash_table * globals;
1743*3d8817e4Smiod 
1744*3d8817e4Smiod   globals = coff_arm_hash_table (info);
1745*3d8817e4Smiod 
1746*3d8817e4Smiod   BFD_ASSERT (globals != NULL);
1747*3d8817e4Smiod 
1748*3d8817e4Smiod   if (globals->arm_glue_size != 0)
1749*3d8817e4Smiod     {
1750*3d8817e4Smiod       BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
1751*3d8817e4Smiod 
1752*3d8817e4Smiod       s = bfd_get_section_by_name
1753*3d8817e4Smiod 	(globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME);
1754*3d8817e4Smiod 
1755*3d8817e4Smiod       BFD_ASSERT (s != NULL);
1756*3d8817e4Smiod 
1757*3d8817e4Smiod       foo = bfd_alloc (globals->bfd_of_glue_owner, globals->arm_glue_size);
1758*3d8817e4Smiod 
1759*3d8817e4Smiod       s->size = globals->arm_glue_size;
1760*3d8817e4Smiod       s->contents = foo;
1761*3d8817e4Smiod     }
1762*3d8817e4Smiod 
1763*3d8817e4Smiod   if (globals->thumb_glue_size != 0)
1764*3d8817e4Smiod     {
1765*3d8817e4Smiod       BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
1766*3d8817e4Smiod 
1767*3d8817e4Smiod       s = bfd_get_section_by_name
1768*3d8817e4Smiod 	(globals->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME);
1769*3d8817e4Smiod 
1770*3d8817e4Smiod       BFD_ASSERT (s != NULL);
1771*3d8817e4Smiod 
1772*3d8817e4Smiod       foo = bfd_alloc (globals->bfd_of_glue_owner, globals->thumb_glue_size);
1773*3d8817e4Smiod 
1774*3d8817e4Smiod       s->size = globals->thumb_glue_size;
1775*3d8817e4Smiod       s->contents = foo;
1776*3d8817e4Smiod     }
1777*3d8817e4Smiod 
1778*3d8817e4Smiod   return TRUE;
1779*3d8817e4Smiod }
1780*3d8817e4Smiod 
1781*3d8817e4Smiod static void
record_arm_to_thumb_glue(struct bfd_link_info * info,struct coff_link_hash_entry * h)1782*3d8817e4Smiod record_arm_to_thumb_glue (struct bfd_link_info *        info,
1783*3d8817e4Smiod 			  struct coff_link_hash_entry * h)
1784*3d8817e4Smiod {
1785*3d8817e4Smiod   const char *                      name = h->root.root.string;
1786*3d8817e4Smiod   register asection *               s;
1787*3d8817e4Smiod   char *                            tmp_name;
1788*3d8817e4Smiod   struct coff_link_hash_entry *     myh;
1789*3d8817e4Smiod   struct bfd_link_hash_entry *      bh;
1790*3d8817e4Smiod   struct coff_arm_link_hash_table * globals;
1791*3d8817e4Smiod   bfd_vma val;
1792*3d8817e4Smiod   bfd_size_type amt;
1793*3d8817e4Smiod 
1794*3d8817e4Smiod   globals = coff_arm_hash_table (info);
1795*3d8817e4Smiod 
1796*3d8817e4Smiod   BFD_ASSERT (globals != NULL);
1797*3d8817e4Smiod   BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
1798*3d8817e4Smiod 
1799*3d8817e4Smiod   s = bfd_get_section_by_name
1800*3d8817e4Smiod     (globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME);
1801*3d8817e4Smiod 
1802*3d8817e4Smiod   BFD_ASSERT (s != NULL);
1803*3d8817e4Smiod 
1804*3d8817e4Smiod   amt = strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1;
1805*3d8817e4Smiod   tmp_name = bfd_malloc (amt);
1806*3d8817e4Smiod 
1807*3d8817e4Smiod   BFD_ASSERT (tmp_name);
1808*3d8817e4Smiod 
1809*3d8817e4Smiod   sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name);
1810*3d8817e4Smiod 
1811*3d8817e4Smiod   myh = coff_link_hash_lookup
1812*3d8817e4Smiod     (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE);
1813*3d8817e4Smiod 
1814*3d8817e4Smiod   if (myh != NULL)
1815*3d8817e4Smiod     {
1816*3d8817e4Smiod       free (tmp_name);
1817*3d8817e4Smiod       /* We've already seen this guy.  */
1818*3d8817e4Smiod       return;
1819*3d8817e4Smiod     }
1820*3d8817e4Smiod 
1821*3d8817e4Smiod   /* The only trick here is using globals->arm_glue_size as the value. Even
1822*3d8817e4Smiod      though the section isn't allocated yet, this is where we will be putting
1823*3d8817e4Smiod      it.  */
1824*3d8817e4Smiod   bh = NULL;
1825*3d8817e4Smiod   val = globals->arm_glue_size + 1;
1826*3d8817e4Smiod   bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name,
1827*3d8817e4Smiod 				BSF_GLOBAL, s, val, NULL, TRUE, FALSE, &bh);
1828*3d8817e4Smiod 
1829*3d8817e4Smiod   free (tmp_name);
1830*3d8817e4Smiod 
1831*3d8817e4Smiod   globals->arm_glue_size += ARM2THUMB_GLUE_SIZE;
1832*3d8817e4Smiod 
1833*3d8817e4Smiod   return;
1834*3d8817e4Smiod }
1835*3d8817e4Smiod 
1836*3d8817e4Smiod #ifndef ARM_WINCE
1837*3d8817e4Smiod static void
record_thumb_to_arm_glue(struct bfd_link_info * info,struct coff_link_hash_entry * h)1838*3d8817e4Smiod record_thumb_to_arm_glue (struct bfd_link_info *        info,
1839*3d8817e4Smiod 			  struct coff_link_hash_entry * h)
1840*3d8817e4Smiod {
1841*3d8817e4Smiod   const char *                       name = h->root.root.string;
1842*3d8817e4Smiod   asection *                         s;
1843*3d8817e4Smiod   char *                             tmp_name;
1844*3d8817e4Smiod   struct coff_link_hash_entry *      myh;
1845*3d8817e4Smiod   struct bfd_link_hash_entry *       bh;
1846*3d8817e4Smiod   struct coff_arm_link_hash_table *  globals;
1847*3d8817e4Smiod   bfd_vma val;
1848*3d8817e4Smiod   bfd_size_type amt;
1849*3d8817e4Smiod 
1850*3d8817e4Smiod   globals = coff_arm_hash_table (info);
1851*3d8817e4Smiod 
1852*3d8817e4Smiod   BFD_ASSERT (globals != NULL);
1853*3d8817e4Smiod   BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
1854*3d8817e4Smiod 
1855*3d8817e4Smiod   s = bfd_get_section_by_name
1856*3d8817e4Smiod     (globals->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME);
1857*3d8817e4Smiod 
1858*3d8817e4Smiod   BFD_ASSERT (s != NULL);
1859*3d8817e4Smiod 
1860*3d8817e4Smiod   amt = strlen (name) + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1;
1861*3d8817e4Smiod   tmp_name = bfd_malloc (amt);
1862*3d8817e4Smiod 
1863*3d8817e4Smiod   BFD_ASSERT (tmp_name);
1864*3d8817e4Smiod 
1865*3d8817e4Smiod   sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name);
1866*3d8817e4Smiod 
1867*3d8817e4Smiod   myh = coff_link_hash_lookup
1868*3d8817e4Smiod     (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE);
1869*3d8817e4Smiod 
1870*3d8817e4Smiod   if (myh != NULL)
1871*3d8817e4Smiod     {
1872*3d8817e4Smiod       free (tmp_name);
1873*3d8817e4Smiod       /* We've already seen this guy.  */
1874*3d8817e4Smiod       return;
1875*3d8817e4Smiod     }
1876*3d8817e4Smiod 
1877*3d8817e4Smiod   bh = NULL;
1878*3d8817e4Smiod   val = globals->thumb_glue_size + 1;
1879*3d8817e4Smiod   bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name,
1880*3d8817e4Smiod 				BSF_GLOBAL, s, val, NULL, TRUE, FALSE, &bh);
1881*3d8817e4Smiod 
1882*3d8817e4Smiod   /* If we mark it 'thumb', the disassembler will do a better job.  */
1883*3d8817e4Smiod   myh = (struct coff_link_hash_entry *) bh;
1884*3d8817e4Smiod   myh->class = C_THUMBEXTFUNC;
1885*3d8817e4Smiod 
1886*3d8817e4Smiod   free (tmp_name);
1887*3d8817e4Smiod 
1888*3d8817e4Smiod   /* Allocate another symbol to mark where we switch to arm mode.  */
1889*3d8817e4Smiod 
1890*3d8817e4Smiod #define CHANGE_TO_ARM "__%s_change_to_arm"
1891*3d8817e4Smiod #define BACK_FROM_ARM "__%s_back_from_arm"
1892*3d8817e4Smiod 
1893*3d8817e4Smiod   amt = strlen (name) + strlen (CHANGE_TO_ARM) + 1;
1894*3d8817e4Smiod   tmp_name = bfd_malloc (amt);
1895*3d8817e4Smiod 
1896*3d8817e4Smiod   BFD_ASSERT (tmp_name);
1897*3d8817e4Smiod 
1898*3d8817e4Smiod   sprintf (tmp_name, globals->support_old_code ? BACK_FROM_ARM : CHANGE_TO_ARM, name);
1899*3d8817e4Smiod 
1900*3d8817e4Smiod   bh = NULL;
1901*3d8817e4Smiod   val = globals->thumb_glue_size + (globals->support_old_code ? 8 : 4);
1902*3d8817e4Smiod   bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name,
1903*3d8817e4Smiod 				BSF_LOCAL, s, val, NULL, TRUE, FALSE, &bh);
1904*3d8817e4Smiod 
1905*3d8817e4Smiod   free (tmp_name);
1906*3d8817e4Smiod 
1907*3d8817e4Smiod   globals->thumb_glue_size += THUMB2ARM_GLUE_SIZE;
1908*3d8817e4Smiod 
1909*3d8817e4Smiod   return;
1910*3d8817e4Smiod }
1911*3d8817e4Smiod #endif /* not ARM_WINCE */
1912*3d8817e4Smiod 
1913*3d8817e4Smiod /* Select a BFD to be used to hold the sections used by the glue code.
1914*3d8817e4Smiod    This function is called from the linker scripts in ld/emultempl/
1915*3d8817e4Smiod    {armcoff/pe}.em  */
1916*3d8817e4Smiod 
1917*3d8817e4Smiod bfd_boolean
bfd_arm_get_bfd_for_interworking(bfd * abfd,struct bfd_link_info * info)1918*3d8817e4Smiod bfd_arm_get_bfd_for_interworking (bfd * 		 abfd,
1919*3d8817e4Smiod 				  struct bfd_link_info * info)
1920*3d8817e4Smiod {
1921*3d8817e4Smiod   struct coff_arm_link_hash_table * globals;
1922*3d8817e4Smiod   flagword   			    flags;
1923*3d8817e4Smiod   asection * 			    sec;
1924*3d8817e4Smiod 
1925*3d8817e4Smiod   /* If we are only performing a partial link do not bother
1926*3d8817e4Smiod      getting a bfd to hold the glue.  */
1927*3d8817e4Smiod   if (info->relocatable)
1928*3d8817e4Smiod     return TRUE;
1929*3d8817e4Smiod 
1930*3d8817e4Smiod   globals = coff_arm_hash_table (info);
1931*3d8817e4Smiod 
1932*3d8817e4Smiod   BFD_ASSERT (globals != NULL);
1933*3d8817e4Smiod 
1934*3d8817e4Smiod   if (globals->bfd_of_glue_owner != NULL)
1935*3d8817e4Smiod     return TRUE;
1936*3d8817e4Smiod 
1937*3d8817e4Smiod   sec = bfd_get_section_by_name (abfd, ARM2THUMB_GLUE_SECTION_NAME);
1938*3d8817e4Smiod 
1939*3d8817e4Smiod   if (sec == NULL)
1940*3d8817e4Smiod     {
1941*3d8817e4Smiod       flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_CODE | SEC_READONLY;
1942*3d8817e4Smiod 
1943*3d8817e4Smiod       sec = bfd_make_section (abfd, ARM2THUMB_GLUE_SECTION_NAME);
1944*3d8817e4Smiod 
1945*3d8817e4Smiod       if (sec == NULL
1946*3d8817e4Smiod 	  || ! bfd_set_section_flags (abfd, sec, flags)
1947*3d8817e4Smiod 	  || ! bfd_set_section_alignment (abfd, sec, 2))
1948*3d8817e4Smiod 	return FALSE;
1949*3d8817e4Smiod     }
1950*3d8817e4Smiod 
1951*3d8817e4Smiod   sec = bfd_get_section_by_name (abfd, THUMB2ARM_GLUE_SECTION_NAME);
1952*3d8817e4Smiod 
1953*3d8817e4Smiod   if (sec == NULL)
1954*3d8817e4Smiod     {
1955*3d8817e4Smiod       flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_CODE | SEC_READONLY;
1956*3d8817e4Smiod 
1957*3d8817e4Smiod       sec = bfd_make_section (abfd, THUMB2ARM_GLUE_SECTION_NAME);
1958*3d8817e4Smiod 
1959*3d8817e4Smiod       if (sec == NULL
1960*3d8817e4Smiod 	  || ! bfd_set_section_flags (abfd, sec, flags)
1961*3d8817e4Smiod 	  || ! bfd_set_section_alignment (abfd, sec, 2))
1962*3d8817e4Smiod 	return FALSE;
1963*3d8817e4Smiod     }
1964*3d8817e4Smiod 
1965*3d8817e4Smiod   /* Save the bfd for later use.  */
1966*3d8817e4Smiod   globals->bfd_of_glue_owner = abfd;
1967*3d8817e4Smiod 
1968*3d8817e4Smiod   return TRUE;
1969*3d8817e4Smiod }
1970*3d8817e4Smiod 
1971*3d8817e4Smiod bfd_boolean
bfd_arm_process_before_allocation(bfd * abfd,struct bfd_link_info * info,int support_old_code)1972*3d8817e4Smiod bfd_arm_process_before_allocation (bfd *                   abfd,
1973*3d8817e4Smiod 				   struct bfd_link_info *  info,
1974*3d8817e4Smiod 				   int		           support_old_code)
1975*3d8817e4Smiod {
1976*3d8817e4Smiod   asection * sec;
1977*3d8817e4Smiod   struct coff_arm_link_hash_table * globals;
1978*3d8817e4Smiod 
1979*3d8817e4Smiod   /* If we are only performing a partial link do not bother
1980*3d8817e4Smiod      to construct any glue.  */
1981*3d8817e4Smiod   if (info->relocatable)
1982*3d8817e4Smiod     return TRUE;
1983*3d8817e4Smiod 
1984*3d8817e4Smiod   /* Here we have a bfd that is to be included on the link.  We have a hook
1985*3d8817e4Smiod      to do reloc rummaging, before section sizes are nailed down.  */
1986*3d8817e4Smiod   _bfd_coff_get_external_symbols (abfd);
1987*3d8817e4Smiod 
1988*3d8817e4Smiod   globals = coff_arm_hash_table (info);
1989*3d8817e4Smiod 
1990*3d8817e4Smiod   BFD_ASSERT (globals != NULL);
1991*3d8817e4Smiod   BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
1992*3d8817e4Smiod 
1993*3d8817e4Smiod   globals->support_old_code = support_old_code;
1994*3d8817e4Smiod 
1995*3d8817e4Smiod   /* Rummage around all the relocs and map the glue vectors.  */
1996*3d8817e4Smiod   sec = abfd->sections;
1997*3d8817e4Smiod 
1998*3d8817e4Smiod   if (sec == NULL)
1999*3d8817e4Smiod     return TRUE;
2000*3d8817e4Smiod 
2001*3d8817e4Smiod   for (; sec != NULL; sec = sec->next)
2002*3d8817e4Smiod     {
2003*3d8817e4Smiod       struct internal_reloc * i;
2004*3d8817e4Smiod       struct internal_reloc * rel;
2005*3d8817e4Smiod 
2006*3d8817e4Smiod       if (sec->reloc_count == 0)
2007*3d8817e4Smiod 	continue;
2008*3d8817e4Smiod 
2009*3d8817e4Smiod       /* Load the relocs.  */
2010*3d8817e4Smiod       /* FIXME: there may be a storage leak here.  */
2011*3d8817e4Smiod       i = _bfd_coff_read_internal_relocs (abfd, sec, 1, 0, 0, 0);
2012*3d8817e4Smiod 
2013*3d8817e4Smiod       BFD_ASSERT (i != 0);
2014*3d8817e4Smiod 
2015*3d8817e4Smiod       for (rel = i; rel < i + sec->reloc_count; ++rel)
2016*3d8817e4Smiod 	{
2017*3d8817e4Smiod 	  unsigned short                 r_type  = rel->r_type;
2018*3d8817e4Smiod 	  long                           symndx;
2019*3d8817e4Smiod 	  struct coff_link_hash_entry *  h;
2020*3d8817e4Smiod 
2021*3d8817e4Smiod 	  symndx = rel->r_symndx;
2022*3d8817e4Smiod 
2023*3d8817e4Smiod 	  /* If the relocation is not against a symbol it cannot concern us.  */
2024*3d8817e4Smiod 	  if (symndx == -1)
2025*3d8817e4Smiod 	    continue;
2026*3d8817e4Smiod 
2027*3d8817e4Smiod 	  /* If the index is outside of the range of our table, something has gone wrong.  */
2028*3d8817e4Smiod 	  if (symndx >= obj_conv_table_size (abfd))
2029*3d8817e4Smiod 	    {
2030*3d8817e4Smiod 	      _bfd_error_handler (_("%B: illegal symbol index in reloc: %d"),
2031*3d8817e4Smiod 				  abfd, symndx);
2032*3d8817e4Smiod 	      continue;
2033*3d8817e4Smiod 	    }
2034*3d8817e4Smiod 
2035*3d8817e4Smiod 	  h = obj_coff_sym_hashes (abfd)[symndx];
2036*3d8817e4Smiod 
2037*3d8817e4Smiod 	  /* If the relocation is against a static symbol it must be within
2038*3d8817e4Smiod 	     the current section and so cannot be a cross ARM/Thumb relocation.  */
2039*3d8817e4Smiod 	  if (h == NULL)
2040*3d8817e4Smiod 	    continue;
2041*3d8817e4Smiod 
2042*3d8817e4Smiod 	  switch (r_type)
2043*3d8817e4Smiod 	    {
2044*3d8817e4Smiod 	    case ARM_26:
2045*3d8817e4Smiod 	      /* This one is a call from arm code.  We need to look up
2046*3d8817e4Smiod 		 the target of the call. If it is a thumb target, we
2047*3d8817e4Smiod 		 insert glue.  */
2048*3d8817e4Smiod 
2049*3d8817e4Smiod 	      if (h->class == C_THUMBEXTFUNC)
2050*3d8817e4Smiod 		record_arm_to_thumb_glue (info, h);
2051*3d8817e4Smiod 	      break;
2052*3d8817e4Smiod 
2053*3d8817e4Smiod #ifndef ARM_WINCE
2054*3d8817e4Smiod 	    case ARM_THUMB23:
2055*3d8817e4Smiod 	      /* This one is a call from thumb code.  We used to look
2056*3d8817e4Smiod 		 for ARM_THUMB9 and ARM_THUMB12 as well.  We need to look
2057*3d8817e4Smiod 		 up the target of the call. If it is an arm target, we
2058*3d8817e4Smiod 		 insert glue.  If the symbol does not exist it will be
2059*3d8817e4Smiod 		 given a class of C_EXT and so we will generate a stub
2060*3d8817e4Smiod 		 for it.  This is not really a problem, since the link
2061*3d8817e4Smiod 		 is doomed anyway.  */
2062*3d8817e4Smiod 
2063*3d8817e4Smiod 	      switch (h->class)
2064*3d8817e4Smiod 		{
2065*3d8817e4Smiod 		case C_EXT:
2066*3d8817e4Smiod 		case C_STAT:
2067*3d8817e4Smiod 		case C_LABEL:
2068*3d8817e4Smiod 		  record_thumb_to_arm_glue (info, h);
2069*3d8817e4Smiod 		  break;
2070*3d8817e4Smiod 		default:
2071*3d8817e4Smiod 		  ;
2072*3d8817e4Smiod 		}
2073*3d8817e4Smiod 	      break;
2074*3d8817e4Smiod #endif
2075*3d8817e4Smiod 
2076*3d8817e4Smiod 	    default:
2077*3d8817e4Smiod 	      break;
2078*3d8817e4Smiod 	    }
2079*3d8817e4Smiod 	}
2080*3d8817e4Smiod     }
2081*3d8817e4Smiod 
2082*3d8817e4Smiod   return TRUE;
2083*3d8817e4Smiod }
2084*3d8817e4Smiod 
2085*3d8817e4Smiod #endif /* ! defined (COFF_IMAGE_WITH_PE) */
2086*3d8817e4Smiod 
2087*3d8817e4Smiod #define coff_bfd_reloc_type_lookup 		coff_arm_reloc_type_lookup
2088*3d8817e4Smiod #define coff_relocate_section 			coff_arm_relocate_section
2089*3d8817e4Smiod #define coff_bfd_is_local_label_name 		coff_arm_is_local_label_name
2090*3d8817e4Smiod #define coff_adjust_symndx			coff_arm_adjust_symndx
2091*3d8817e4Smiod #define coff_link_output_has_begun 		coff_arm_link_output_has_begun
2092*3d8817e4Smiod #define coff_final_link_postscript		coff_arm_final_link_postscript
2093*3d8817e4Smiod #define coff_bfd_merge_private_bfd_data		coff_arm_merge_private_bfd_data
2094*3d8817e4Smiod #define coff_bfd_print_private_bfd_data		coff_arm_print_private_bfd_data
2095*3d8817e4Smiod #define coff_bfd_set_private_flags              _bfd_coff_arm_set_private_flags
2096*3d8817e4Smiod #define coff_bfd_copy_private_bfd_data          coff_arm_copy_private_bfd_data
2097*3d8817e4Smiod #define coff_bfd_link_hash_table_create		coff_arm_link_hash_table_create
2098*3d8817e4Smiod 
2099*3d8817e4Smiod /* When doing a relocatable link, we want to convert ARM_26 relocs
2100*3d8817e4Smiod    into ARM_26D relocs.  */
2101*3d8817e4Smiod 
2102*3d8817e4Smiod static bfd_boolean
coff_arm_adjust_symndx(bfd * obfd ATTRIBUTE_UNUSED,struct bfd_link_info * info ATTRIBUTE_UNUSED,bfd * ibfd,asection * sec,struct internal_reloc * irel,bfd_boolean * adjustedp)2103*3d8817e4Smiod coff_arm_adjust_symndx (bfd *obfd ATTRIBUTE_UNUSED,
2104*3d8817e4Smiod 			struct bfd_link_info *info ATTRIBUTE_UNUSED,
2105*3d8817e4Smiod 			bfd *ibfd,
2106*3d8817e4Smiod 			asection *sec,
2107*3d8817e4Smiod 			struct internal_reloc *irel,
2108*3d8817e4Smiod 			bfd_boolean *adjustedp)
2109*3d8817e4Smiod {
2110*3d8817e4Smiod   if (irel->r_type == ARM_26)
2111*3d8817e4Smiod     {
2112*3d8817e4Smiod       struct coff_link_hash_entry *h;
2113*3d8817e4Smiod 
2114*3d8817e4Smiod       h = obj_coff_sym_hashes (ibfd)[irel->r_symndx];
2115*3d8817e4Smiod       if (h != NULL
2116*3d8817e4Smiod 	  && (h->root.type == bfd_link_hash_defined
2117*3d8817e4Smiod 	      || h->root.type == bfd_link_hash_defweak)
2118*3d8817e4Smiod 	  && h->root.u.def.section->output_section == sec->output_section)
2119*3d8817e4Smiod 	irel->r_type = ARM_26D;
2120*3d8817e4Smiod     }
2121*3d8817e4Smiod   *adjustedp = FALSE;
2122*3d8817e4Smiod   return TRUE;
2123*3d8817e4Smiod }
2124*3d8817e4Smiod 
2125*3d8817e4Smiod /* Called when merging the private data areas of two BFDs.
2126*3d8817e4Smiod    This is important as it allows us to detect if we are
2127*3d8817e4Smiod    attempting to merge binaries compiled for different ARM
2128*3d8817e4Smiod    targets, eg different CPUs or different APCS's.     */
2129*3d8817e4Smiod 
2130*3d8817e4Smiod static bfd_boolean
coff_arm_merge_private_bfd_data(bfd * ibfd,bfd * obfd)2131*3d8817e4Smiod coff_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd)
2132*3d8817e4Smiod {
2133*3d8817e4Smiod   BFD_ASSERT (ibfd != NULL && obfd != NULL);
2134*3d8817e4Smiod 
2135*3d8817e4Smiod   if (ibfd == obfd)
2136*3d8817e4Smiod     return TRUE;
2137*3d8817e4Smiod 
2138*3d8817e4Smiod   /* If the two formats are different we cannot merge anything.
2139*3d8817e4Smiod      This is not an error, since it is permissable to change the
2140*3d8817e4Smiod      input and output formats.  */
2141*3d8817e4Smiod   if (   ibfd->xvec->flavour != bfd_target_coff_flavour
2142*3d8817e4Smiod       || obfd->xvec->flavour != bfd_target_coff_flavour)
2143*3d8817e4Smiod     return TRUE;
2144*3d8817e4Smiod 
2145*3d8817e4Smiod   /* Determine what should happen if the input ARM architecture
2146*3d8817e4Smiod      does not match the output ARM architecture.  */
2147*3d8817e4Smiod   if (! bfd_arm_merge_machines (ibfd, obfd))
2148*3d8817e4Smiod     return FALSE;
2149*3d8817e4Smiod 
2150*3d8817e4Smiod   /* Verify that the APCS is the same for the two BFDs.  */
2151*3d8817e4Smiod   if (APCS_SET (ibfd))
2152*3d8817e4Smiod     {
2153*3d8817e4Smiod       if (APCS_SET (obfd))
2154*3d8817e4Smiod 	{
2155*3d8817e4Smiod 	  /* If the src and dest have different APCS flag bits set, fail.  */
2156*3d8817e4Smiod 	  if (APCS_26_FLAG (obfd) != APCS_26_FLAG (ibfd))
2157*3d8817e4Smiod 	    {
2158*3d8817e4Smiod 	      _bfd_error_handler
2159*3d8817e4Smiod 		/* xgettext: c-format */
2160*3d8817e4Smiod 		(_("ERROR: %B is compiled for APCS-%d, whereas %B is compiled for APCS-%d"),
2161*3d8817e4Smiod 		 ibfd, obfd,
2162*3d8817e4Smiod 		 APCS_26_FLAG (ibfd) ? 26 : 32,
2163*3d8817e4Smiod 		 APCS_26_FLAG (obfd) ? 26 : 32
2164*3d8817e4Smiod 		 );
2165*3d8817e4Smiod 
2166*3d8817e4Smiod 	      bfd_set_error (bfd_error_wrong_format);
2167*3d8817e4Smiod 	      return FALSE;
2168*3d8817e4Smiod 	    }
2169*3d8817e4Smiod 
2170*3d8817e4Smiod 	  if (APCS_FLOAT_FLAG (obfd) != APCS_FLOAT_FLAG (ibfd))
2171*3d8817e4Smiod 	    {
2172*3d8817e4Smiod 	      const char *msg;
2173*3d8817e4Smiod 
2174*3d8817e4Smiod 	      if (APCS_FLOAT_FLAG (ibfd))
2175*3d8817e4Smiod 		/* xgettext: c-format */
2176*3d8817e4Smiod 		msg = _("ERROR: %B passes floats in float registers, whereas %B passes them in integer registers");
2177*3d8817e4Smiod 	      else
2178*3d8817e4Smiod 		/* xgettext: c-format */
2179*3d8817e4Smiod 		msg = _("ERROR: %B passes floats in integer registers, whereas %B passes them in float registers");
2180*3d8817e4Smiod 
2181*3d8817e4Smiod 	      _bfd_error_handler (msg, ibfd, obfd);
2182*3d8817e4Smiod 
2183*3d8817e4Smiod 	      bfd_set_error (bfd_error_wrong_format);
2184*3d8817e4Smiod 	      return FALSE;
2185*3d8817e4Smiod 	    }
2186*3d8817e4Smiod 
2187*3d8817e4Smiod 	  if (PIC_FLAG (obfd) != PIC_FLAG (ibfd))
2188*3d8817e4Smiod 	    {
2189*3d8817e4Smiod 	      const char * msg;
2190*3d8817e4Smiod 
2191*3d8817e4Smiod 	      if (PIC_FLAG (ibfd))
2192*3d8817e4Smiod 		/* xgettext: c-format */
2193*3d8817e4Smiod 		msg = _("ERROR: %B is compiled as position independent code, whereas target %B is absolute position");
2194*3d8817e4Smiod 	      else
2195*3d8817e4Smiod 		/* xgettext: c-format */
2196*3d8817e4Smiod 		msg = _("ERROR: %B is compiled as absolute position code, whereas target %B is position independent");
2197*3d8817e4Smiod 	      _bfd_error_handler (msg, ibfd, obfd);
2198*3d8817e4Smiod 
2199*3d8817e4Smiod 	      bfd_set_error (bfd_error_wrong_format);
2200*3d8817e4Smiod 	      return FALSE;
2201*3d8817e4Smiod 	    }
2202*3d8817e4Smiod 	}
2203*3d8817e4Smiod       else
2204*3d8817e4Smiod 	{
2205*3d8817e4Smiod 	  SET_APCS_FLAGS (obfd, APCS_26_FLAG (ibfd) | APCS_FLOAT_FLAG (ibfd) | PIC_FLAG (ibfd));
2206*3d8817e4Smiod 
2207*3d8817e4Smiod 	  /* Set up the arch and fields as well as these are probably wrong.  */
2208*3d8817e4Smiod 	  bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd));
2209*3d8817e4Smiod 	}
2210*3d8817e4Smiod     }
2211*3d8817e4Smiod 
2212*3d8817e4Smiod   /* Check the interworking support.  */
2213*3d8817e4Smiod   if (INTERWORK_SET (ibfd))
2214*3d8817e4Smiod     {
2215*3d8817e4Smiod       if (INTERWORK_SET (obfd))
2216*3d8817e4Smiod 	{
2217*3d8817e4Smiod 	  /* If the src and dest differ in their interworking issue a warning.  */
2218*3d8817e4Smiod 	  if (INTERWORK_FLAG (obfd) != INTERWORK_FLAG (ibfd))
2219*3d8817e4Smiod 	    {
2220*3d8817e4Smiod 	      const char * msg;
2221*3d8817e4Smiod 
2222*3d8817e4Smiod 	      if (INTERWORK_FLAG (ibfd))
2223*3d8817e4Smiod 		/* xgettext: c-format */
2224*3d8817e4Smiod 		msg = _("Warning: %B supports interworking, whereas %B does not");
2225*3d8817e4Smiod 	      else
2226*3d8817e4Smiod 		/* xgettext: c-format */
2227*3d8817e4Smiod 		msg = _("Warning: %B does not support interworking, whereas %B does");
2228*3d8817e4Smiod 
2229*3d8817e4Smiod 	      _bfd_error_handler (msg, ibfd, obfd);
2230*3d8817e4Smiod 	    }
2231*3d8817e4Smiod 	}
2232*3d8817e4Smiod       else
2233*3d8817e4Smiod 	{
2234*3d8817e4Smiod 	  SET_INTERWORK_FLAG (obfd, INTERWORK_FLAG (ibfd));
2235*3d8817e4Smiod 	}
2236*3d8817e4Smiod     }
2237*3d8817e4Smiod 
2238*3d8817e4Smiod   return TRUE;
2239*3d8817e4Smiod }
2240*3d8817e4Smiod 
2241*3d8817e4Smiod /* Display the flags field.  */
2242*3d8817e4Smiod 
2243*3d8817e4Smiod static bfd_boolean
coff_arm_print_private_bfd_data(bfd * abfd,void * ptr)2244*3d8817e4Smiod coff_arm_print_private_bfd_data (bfd * abfd, void * ptr)
2245*3d8817e4Smiod {
2246*3d8817e4Smiod   FILE * file = (FILE *) ptr;
2247*3d8817e4Smiod 
2248*3d8817e4Smiod   BFD_ASSERT (abfd != NULL && ptr != NULL);
2249*3d8817e4Smiod 
2250*3d8817e4Smiod   /* xgettext:c-format */
2251*3d8817e4Smiod   fprintf (file, _("private flags = %x:"), coff_data (abfd)->flags);
2252*3d8817e4Smiod 
2253*3d8817e4Smiod   if (APCS_SET (abfd))
2254*3d8817e4Smiod     {
2255*3d8817e4Smiod       /* xgettext: APCS is ARM Procedure Call Standard, it should not be translated.  */
2256*3d8817e4Smiod       fprintf (file, " [APCS-%d]", APCS_26_FLAG (abfd) ? 26 : 32);
2257*3d8817e4Smiod 
2258*3d8817e4Smiod       if (APCS_FLOAT_FLAG (abfd))
2259*3d8817e4Smiod 	fprintf (file, _(" [floats passed in float registers]"));
2260*3d8817e4Smiod       else
2261*3d8817e4Smiod 	fprintf (file, _(" [floats passed in integer registers]"));
2262*3d8817e4Smiod 
2263*3d8817e4Smiod       if (PIC_FLAG (abfd))
2264*3d8817e4Smiod 	fprintf (file, _(" [position independent]"));
2265*3d8817e4Smiod       else
2266*3d8817e4Smiod 	fprintf (file, _(" [absolute position]"));
2267*3d8817e4Smiod     }
2268*3d8817e4Smiod 
2269*3d8817e4Smiod   if (! INTERWORK_SET (abfd))
2270*3d8817e4Smiod     fprintf (file, _(" [interworking flag not initialised]"));
2271*3d8817e4Smiod   else if (INTERWORK_FLAG (abfd))
2272*3d8817e4Smiod     fprintf (file, _(" [interworking supported]"));
2273*3d8817e4Smiod   else
2274*3d8817e4Smiod     fprintf (file, _(" [interworking not supported]"));
2275*3d8817e4Smiod 
2276*3d8817e4Smiod   fputc ('\n', file);
2277*3d8817e4Smiod 
2278*3d8817e4Smiod   return TRUE;
2279*3d8817e4Smiod }
2280*3d8817e4Smiod 
2281*3d8817e4Smiod /* Copies the given flags into the coff_tdata.flags field.
2282*3d8817e4Smiod    Typically these flags come from the f_flags[] field of
2283*3d8817e4Smiod    the COFF filehdr structure, which contains important,
2284*3d8817e4Smiod    target specific information.
2285*3d8817e4Smiod    Note: Although this function is static, it is explicitly
2286*3d8817e4Smiod    called from both coffcode.h and peicode.h.  */
2287*3d8817e4Smiod 
2288*3d8817e4Smiod static bfd_boolean
_bfd_coff_arm_set_private_flags(bfd * abfd,flagword flags)2289*3d8817e4Smiod _bfd_coff_arm_set_private_flags (bfd * abfd, flagword flags)
2290*3d8817e4Smiod {
2291*3d8817e4Smiod   flagword flag;
2292*3d8817e4Smiod 
2293*3d8817e4Smiod   BFD_ASSERT (abfd != NULL);
2294*3d8817e4Smiod 
2295*3d8817e4Smiod   flag = (flags & F_APCS26) ? F_APCS_26 : 0;
2296*3d8817e4Smiod 
2297*3d8817e4Smiod   /* Make sure that the APCS field has not been initialised to the opposite
2298*3d8817e4Smiod      value.  */
2299*3d8817e4Smiod   if (APCS_SET (abfd)
2300*3d8817e4Smiod       && (   (APCS_26_FLAG    (abfd) != flag)
2301*3d8817e4Smiod 	  || (APCS_FLOAT_FLAG (abfd) != (flags & F_APCS_FLOAT))
2302*3d8817e4Smiod 	  || (PIC_FLAG        (abfd) != (flags & F_PIC))
2303*3d8817e4Smiod 	  ))
2304*3d8817e4Smiod     return FALSE;
2305*3d8817e4Smiod 
2306*3d8817e4Smiod   flag |= (flags & (F_APCS_FLOAT | F_PIC));
2307*3d8817e4Smiod 
2308*3d8817e4Smiod   SET_APCS_FLAGS (abfd, flag);
2309*3d8817e4Smiod 
2310*3d8817e4Smiod   flag = (flags & F_INTERWORK);
2311*3d8817e4Smiod 
2312*3d8817e4Smiod   /* If the BFD has already had its interworking flag set, but it
2313*3d8817e4Smiod      is different from the value that we have been asked to set,
2314*3d8817e4Smiod      then assume that that merged code will not support interworking
2315*3d8817e4Smiod      and set the flag accordingly.  */
2316*3d8817e4Smiod   if (INTERWORK_SET (abfd) && (INTERWORK_FLAG (abfd) != flag))
2317*3d8817e4Smiod     {
2318*3d8817e4Smiod       if (flag)
2319*3d8817e4Smiod 	/* xgettext: c-format */
2320*3d8817e4Smiod 	_bfd_error_handler (_("Warning: Not setting interworking flag of %B since it has already been specified as non-interworking"),
2321*3d8817e4Smiod 			    abfd);
2322*3d8817e4Smiod       else
2323*3d8817e4Smiod 	/* xgettext: c-format */
2324*3d8817e4Smiod 	_bfd_error_handler (_("Warning: Clearing the interworking flag of %B due to outside request"),
2325*3d8817e4Smiod 			    abfd);
2326*3d8817e4Smiod       flag = 0;
2327*3d8817e4Smiod     }
2328*3d8817e4Smiod 
2329*3d8817e4Smiod   SET_INTERWORK_FLAG (abfd, flag);
2330*3d8817e4Smiod 
2331*3d8817e4Smiod   return TRUE;
2332*3d8817e4Smiod }
2333*3d8817e4Smiod 
2334*3d8817e4Smiod /* Copy the important parts of the target specific data
2335*3d8817e4Smiod    from one instance of a BFD to another.  */
2336*3d8817e4Smiod 
2337*3d8817e4Smiod static bfd_boolean
coff_arm_copy_private_bfd_data(bfd * src,bfd * dest)2338*3d8817e4Smiod coff_arm_copy_private_bfd_data (bfd * src, bfd * dest)
2339*3d8817e4Smiod {
2340*3d8817e4Smiod   BFD_ASSERT (src != NULL && dest != NULL);
2341*3d8817e4Smiod 
2342*3d8817e4Smiod   if (src == dest)
2343*3d8817e4Smiod     return TRUE;
2344*3d8817e4Smiod 
2345*3d8817e4Smiod   /* If the destination is not in the same format as the source, do not do
2346*3d8817e4Smiod      the copy.  */
2347*3d8817e4Smiod   if (src->xvec != dest->xvec)
2348*3d8817e4Smiod     return TRUE;
2349*3d8817e4Smiod 
2350*3d8817e4Smiod   /* Copy the flags field.  */
2351*3d8817e4Smiod   if (APCS_SET (src))
2352*3d8817e4Smiod     {
2353*3d8817e4Smiod       if (APCS_SET (dest))
2354*3d8817e4Smiod 	{
2355*3d8817e4Smiod 	  /* If the src and dest have different APCS flag bits set, fail.  */
2356*3d8817e4Smiod 	  if (APCS_26_FLAG (dest) != APCS_26_FLAG (src))
2357*3d8817e4Smiod 	    return FALSE;
2358*3d8817e4Smiod 
2359*3d8817e4Smiod 	  if (APCS_FLOAT_FLAG (dest) != APCS_FLOAT_FLAG (src))
2360*3d8817e4Smiod 	    return FALSE;
2361*3d8817e4Smiod 
2362*3d8817e4Smiod 	  if (PIC_FLAG (dest) != PIC_FLAG (src))
2363*3d8817e4Smiod 	    return FALSE;
2364*3d8817e4Smiod 	}
2365*3d8817e4Smiod       else
2366*3d8817e4Smiod 	SET_APCS_FLAGS (dest, APCS_26_FLAG (src) | APCS_FLOAT_FLAG (src)
2367*3d8817e4Smiod 			| PIC_FLAG (src));
2368*3d8817e4Smiod     }
2369*3d8817e4Smiod 
2370*3d8817e4Smiod   if (INTERWORK_SET (src))
2371*3d8817e4Smiod     {
2372*3d8817e4Smiod       if (INTERWORK_SET (dest))
2373*3d8817e4Smiod 	{
2374*3d8817e4Smiod 	  /* If the src and dest have different interworking flags then turn
2375*3d8817e4Smiod 	     off the interworking bit.  */
2376*3d8817e4Smiod 	  if (INTERWORK_FLAG (dest) != INTERWORK_FLAG (src))
2377*3d8817e4Smiod 	    {
2378*3d8817e4Smiod 	      if (INTERWORK_FLAG (dest))
2379*3d8817e4Smiod 		{
2380*3d8817e4Smiod 		  /* xgettext:c-format */
2381*3d8817e4Smiod 		  _bfd_error_handler (("\
2382*3d8817e4Smiod Warning: Clearing the interworking flag of %B because non-interworking code in %B has been linked with it"),
2383*3d8817e4Smiod 				      dest, src);
2384*3d8817e4Smiod 		}
2385*3d8817e4Smiod 
2386*3d8817e4Smiod 	      SET_INTERWORK_FLAG (dest, 0);
2387*3d8817e4Smiod 	    }
2388*3d8817e4Smiod 	}
2389*3d8817e4Smiod       else
2390*3d8817e4Smiod 	{
2391*3d8817e4Smiod 	  SET_INTERWORK_FLAG (dest, INTERWORK_FLAG (src));
2392*3d8817e4Smiod 	}
2393*3d8817e4Smiod     }
2394*3d8817e4Smiod 
2395*3d8817e4Smiod   return TRUE;
2396*3d8817e4Smiod }
2397*3d8817e4Smiod 
2398*3d8817e4Smiod /* Note:  the definitions here of LOCAL_LABEL_PREFIX and USER_LABEL_PREIFX
2399*3d8817e4Smiod    *must* match the definitions in gcc/config/arm/{coff|semi|aout}.h.  */
2400*3d8817e4Smiod #define LOCAL_LABEL_PREFIX ""
2401*3d8817e4Smiod #ifndef USER_LABEL_PREFIX
2402*3d8817e4Smiod #define USER_LABEL_PREFIX "_"
2403*3d8817e4Smiod #endif
2404*3d8817e4Smiod 
2405*3d8817e4Smiod /* Like _bfd_coff_is_local_label_name, but
2406*3d8817e4Smiod    a) test against USER_LABEL_PREFIX, to avoid stripping labels known to be
2407*3d8817e4Smiod       non-local.
2408*3d8817e4Smiod    b) Allow other prefixes than ".", e.g. an empty prefix would cause all
2409*3d8817e4Smiod       labels of the form Lxxx to be stripped.  */
2410*3d8817e4Smiod 
2411*3d8817e4Smiod static bfd_boolean
coff_arm_is_local_label_name(bfd * abfd ATTRIBUTE_UNUSED,const char * name)2412*3d8817e4Smiod coff_arm_is_local_label_name (bfd *        abfd ATTRIBUTE_UNUSED,
2413*3d8817e4Smiod 			      const char * name)
2414*3d8817e4Smiod {
2415*3d8817e4Smiod #ifdef USER_LABEL_PREFIX
2416*3d8817e4Smiod   if (USER_LABEL_PREFIX[0] != 0)
2417*3d8817e4Smiod     {
2418*3d8817e4Smiod       size_t len = strlen (USER_LABEL_PREFIX);
2419*3d8817e4Smiod 
2420*3d8817e4Smiod       if (strncmp (name, USER_LABEL_PREFIX, len) == 0)
2421*3d8817e4Smiod 	return FALSE;
2422*3d8817e4Smiod     }
2423*3d8817e4Smiod #endif
2424*3d8817e4Smiod 
2425*3d8817e4Smiod #ifdef LOCAL_LABEL_PREFIX
2426*3d8817e4Smiod   /* If there is a prefix for local labels then look for this.
2427*3d8817e4Smiod      If the prefix exists, but it is empty, then ignore the test.  */
2428*3d8817e4Smiod 
2429*3d8817e4Smiod   if (LOCAL_LABEL_PREFIX[0] != 0)
2430*3d8817e4Smiod     {
2431*3d8817e4Smiod       size_t len = strlen (LOCAL_LABEL_PREFIX);
2432*3d8817e4Smiod 
2433*3d8817e4Smiod       if (strncmp (name, LOCAL_LABEL_PREFIX, len) != 0)
2434*3d8817e4Smiod 	return FALSE;
2435*3d8817e4Smiod 
2436*3d8817e4Smiod       /* Perform the checks below for the rest of the name.  */
2437*3d8817e4Smiod       name += len;
2438*3d8817e4Smiod     }
2439*3d8817e4Smiod #endif
2440*3d8817e4Smiod 
2441*3d8817e4Smiod   return name[0] == 'L';
2442*3d8817e4Smiod }
2443*3d8817e4Smiod 
2444*3d8817e4Smiod /* This piece of machinery exists only to guarantee that the bfd that holds
2445*3d8817e4Smiod    the glue section is written last.
2446*3d8817e4Smiod 
2447*3d8817e4Smiod    This does depend on bfd_make_section attaching a new section to the
2448*3d8817e4Smiod    end of the section list for the bfd.  */
2449*3d8817e4Smiod 
2450*3d8817e4Smiod static bfd_boolean
coff_arm_link_output_has_begun(bfd * sub,struct coff_final_link_info * info)2451*3d8817e4Smiod coff_arm_link_output_has_begun (bfd * sub, struct coff_final_link_info * info)
2452*3d8817e4Smiod {
2453*3d8817e4Smiod   return (sub->output_has_begun
2454*3d8817e4Smiod 	  || sub == coff_arm_hash_table (info->info)->bfd_of_glue_owner);
2455*3d8817e4Smiod }
2456*3d8817e4Smiod 
2457*3d8817e4Smiod static bfd_boolean
coff_arm_final_link_postscript(bfd * abfd ATTRIBUTE_UNUSED,struct coff_final_link_info * pfinfo)2458*3d8817e4Smiod coff_arm_final_link_postscript (bfd * abfd ATTRIBUTE_UNUSED,
2459*3d8817e4Smiod 				struct coff_final_link_info * pfinfo)
2460*3d8817e4Smiod {
2461*3d8817e4Smiod   struct coff_arm_link_hash_table * globals;
2462*3d8817e4Smiod 
2463*3d8817e4Smiod   globals = coff_arm_hash_table (pfinfo->info);
2464*3d8817e4Smiod 
2465*3d8817e4Smiod   BFD_ASSERT (globals != NULL);
2466*3d8817e4Smiod 
2467*3d8817e4Smiod   if (globals->bfd_of_glue_owner != NULL)
2468*3d8817e4Smiod     {
2469*3d8817e4Smiod       if (! _bfd_coff_link_input_bfd (pfinfo, globals->bfd_of_glue_owner))
2470*3d8817e4Smiod 	return FALSE;
2471*3d8817e4Smiod 
2472*3d8817e4Smiod       globals->bfd_of_glue_owner->output_has_begun = TRUE;
2473*3d8817e4Smiod     }
2474*3d8817e4Smiod 
2475*3d8817e4Smiod   return bfd_arm_update_notes (abfd, ARM_NOTE_SECTION);
2476*3d8817e4Smiod }
2477*3d8817e4Smiod 
2478*3d8817e4Smiod #include "coffcode.h"
2479*3d8817e4Smiod 
2480*3d8817e4Smiod #ifndef TARGET_LITTLE_SYM
2481*3d8817e4Smiod #define TARGET_LITTLE_SYM armcoff_little_vec
2482*3d8817e4Smiod #endif
2483*3d8817e4Smiod #ifndef TARGET_LITTLE_NAME
2484*3d8817e4Smiod #define TARGET_LITTLE_NAME "coff-arm-little"
2485*3d8817e4Smiod #endif
2486*3d8817e4Smiod #ifndef TARGET_BIG_SYM
2487*3d8817e4Smiod #define TARGET_BIG_SYM armcoff_big_vec
2488*3d8817e4Smiod #endif
2489*3d8817e4Smiod #ifndef TARGET_BIG_NAME
2490*3d8817e4Smiod #define TARGET_BIG_NAME "coff-arm-big"
2491*3d8817e4Smiod #endif
2492*3d8817e4Smiod 
2493*3d8817e4Smiod #ifndef TARGET_UNDERSCORE
2494*3d8817e4Smiod #define TARGET_UNDERSCORE 0
2495*3d8817e4Smiod #endif
2496*3d8817e4Smiod 
2497*3d8817e4Smiod #ifndef EXTRA_S_FLAGS
2498*3d8817e4Smiod #ifdef COFF_WITH_PE
2499*3d8817e4Smiod #define EXTRA_S_FLAGS (SEC_CODE | SEC_LINK_ONCE | SEC_LINK_DUPLICATES)
2500*3d8817e4Smiod #else
2501*3d8817e4Smiod #define EXTRA_S_FLAGS SEC_CODE
2502*3d8817e4Smiod #endif
2503*3d8817e4Smiod #endif
2504*3d8817e4Smiod 
2505*3d8817e4Smiod /* Forward declaration for use initialising alternative_target field.  */
2506*3d8817e4Smiod extern const bfd_target TARGET_BIG_SYM ;
2507*3d8817e4Smiod 
2508*3d8817e4Smiod /* Target vectors.  */
2509*3d8817e4Smiod CREATE_LITTLE_COFF_TARGET_VEC (TARGET_LITTLE_SYM, TARGET_LITTLE_NAME, D_PAGED, EXTRA_S_FLAGS, TARGET_UNDERSCORE, & TARGET_BIG_SYM, COFF_SWAP_TABLE)
2510*3d8817e4Smiod CREATE_BIG_COFF_TARGET_VEC (TARGET_BIG_SYM, TARGET_BIG_NAME, D_PAGED, EXTRA_S_FLAGS, TARGET_UNDERSCORE, & TARGET_LITTLE_SYM, COFF_SWAP_TABLE)
2511