160484Sobrien/* BFD back-end for ARM COFF files.
278828Sobrien   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3218822Sdim   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
460484Sobrien   Free Software Foundation, Inc.
560484Sobrien   Written by Cygnus Support.
660484Sobrien
7130561Sobrien   This file is part of BFD, the Binary File Descriptor library.
860484Sobrien
9130561Sobrien   This program is free software; you can redistribute it and/or modify
10130561Sobrien   it under the terms of the GNU General Public License as published by
11130561Sobrien   the Free Software Foundation; either version 2 of the License, or
12130561Sobrien   (at your option) any later version.
1360484Sobrien
14130561Sobrien   This program is distributed in the hope that it will be useful,
15130561Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
16130561Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17130561Sobrien   GNU General Public License for more details.
1860484Sobrien
19130561Sobrien   You should have received a copy of the GNU General Public License
20130561Sobrien   along with this program; if not, write to the Free Software
21218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2260484Sobrien
23218822Sdim#include "sysdep.h"
2460484Sobrien#include "bfd.h"
2560484Sobrien#include "libbfd.h"
2660484Sobrien#include "coff/arm.h"
2760484Sobrien#include "coff/internal.h"
2860484Sobrien
2960484Sobrien#ifdef COFF_WITH_PE
3060484Sobrien#include "coff/pe.h"
3160484Sobrien#endif
3260484Sobrien
3360484Sobrien#include "libcoff.h"
3460484Sobrien
3560484Sobrien/* Macros for manipulation the bits in the flags field of the coff data
3660484Sobrien   structure.  */
3789857Sobrien#define APCS_26_FLAG(abfd) \
3889857Sobrien  (coff_data (abfd)->flags & F_APCS_26)
3960484Sobrien
4089857Sobrien#define APCS_FLOAT_FLAG(abfd) \
4189857Sobrien  (coff_data (abfd)->flags & F_APCS_FLOAT)
4289857Sobrien
4389857Sobrien#define PIC_FLAG(abfd) \
4489857Sobrien  (coff_data (abfd)->flags & F_PIC)
4589857Sobrien
4689857Sobrien#define APCS_SET(abfd) \
4789857Sobrien  (coff_data (abfd)->flags & F_APCS_SET)
4889857Sobrien
4989857Sobrien#define SET_APCS_FLAGS(abfd, flgs) \
5089857Sobrien  do									\
5189857Sobrien    {									\
5289857Sobrien      coff_data (abfd)->flags &= ~(F_APCS_26 | F_APCS_FLOAT | F_PIC);	\
5389857Sobrien      coff_data (abfd)->flags |= (flgs) | F_APCS_SET;			\
5489857Sobrien    }									\
5589857Sobrien  while (0)
5689857Sobrien
5789857Sobrien#define INTERWORK_FLAG(abfd) \
5889857Sobrien  (coff_data (abfd)->flags & F_INTERWORK)
5989857Sobrien
6089857Sobrien#define INTERWORK_SET(abfd) \
6189857Sobrien  (coff_data (abfd)->flags & F_INTERWORK_SET)
6289857Sobrien
6389857Sobrien#define SET_INTERWORK_FLAG(abfd, flg) \
6489857Sobrien  do									\
6589857Sobrien    {									\
6689857Sobrien      coff_data (abfd)->flags &= ~F_INTERWORK;				\
6789857Sobrien      coff_data (abfd)->flags |= (flg) | F_INTERWORK_SET;		\
6889857Sobrien    }									\
6989857Sobrien  while (0)
7089857Sobrien
7160484Sobrien#ifndef NUM_ELEM
7260484Sobrien#define NUM_ELEM(a) ((sizeof (a)) / sizeof ((a)[0]))
7360484Sobrien#endif
7477298Sobrien
7560484Sobrientypedef enum {bunknown, b9, b12, b23} thumb_pcrel_branchtype;
76218822Sdim/* Some typedefs for holding instructions.  */
7760484Sobrientypedef unsigned long int insn32;
7860484Sobrientypedef unsigned short int insn16;
7960484Sobrien
8060484Sobrien/* The linker script knows the section names for placement.
8160484Sobrien   The entry_names are used to do simple name mangling on the stubs.
8260484Sobrien   Given a function name, and its type, the stub can be found. The
8389857Sobrien   name can be changed. The only requirement is the %s be present.  */
8477298Sobrien
8560484Sobrien#define THUMB2ARM_GLUE_SECTION_NAME ".glue_7t"
8660484Sobrien#define THUMB2ARM_GLUE_ENTRY_NAME   "__%s_from_thumb"
8760484Sobrien
8860484Sobrien#define ARM2THUMB_GLUE_SECTION_NAME ".glue_7"
8960484Sobrien#define ARM2THUMB_GLUE_ENTRY_NAME   "__%s_from_arm"
9060484Sobrien
9177298Sobrien/* Used by the assembler.  */
9289857Sobrien
9360484Sobrienstatic bfd_reloc_status_type
94218822Sdimcoff_arm_reloc (bfd *abfd,
95218822Sdim		arelent *reloc_entry,
96218822Sdim		asymbol *symbol ATTRIBUTE_UNUSED,
97218822Sdim		void * data,
98218822Sdim		asection *input_section ATTRIBUTE_UNUSED,
99218822Sdim		bfd *output_bfd,
100218822Sdim		char **error_message ATTRIBUTE_UNUSED)
10160484Sobrien{
10260484Sobrien  symvalue diff;
103218822Sdim
104218822Sdim  if (output_bfd == NULL)
10560484Sobrien    return bfd_reloc_continue;
10660484Sobrien
10760484Sobrien  diff = reloc_entry->addend;
10860484Sobrien
10989857Sobrien#define DOIT(x)							\
11089857Sobrien  x = ((x & ~howto->dst_mask)					\
11189857Sobrien       | (((x & howto->src_mask) + diff) & howto->dst_mask))
11260484Sobrien
11360484Sobrien    if (diff != 0)
11460484Sobrien      {
11560484Sobrien	reloc_howto_type *howto = reloc_entry->howto;
11660484Sobrien	unsigned char *addr = (unsigned char *) data + reloc_entry->address;
11760484Sobrien
11860484Sobrien	switch (howto->size)
11960484Sobrien	  {
12060484Sobrien	  case 0:
12160484Sobrien	    {
12260484Sobrien	      char x = bfd_get_8 (abfd, addr);
12360484Sobrien	      DOIT (x);
12460484Sobrien	      bfd_put_8 (abfd, x, addr);
12560484Sobrien	    }
12660484Sobrien	    break;
12760484Sobrien
12860484Sobrien	  case 1:
12960484Sobrien	    {
13060484Sobrien	      short x = bfd_get_16 (abfd, addr);
13160484Sobrien	      DOIT (x);
13289857Sobrien	      bfd_put_16 (abfd, (bfd_vma) x, addr);
13360484Sobrien	    }
13460484Sobrien	    break;
13560484Sobrien
13660484Sobrien	  case 2:
13760484Sobrien	    {
13860484Sobrien	      long x = bfd_get_32 (abfd, addr);
13960484Sobrien	      DOIT (x);
14089857Sobrien	      bfd_put_32 (abfd, (bfd_vma) x, addr);
14160484Sobrien	    }
14260484Sobrien	    break;
14360484Sobrien
14460484Sobrien	  default:
14560484Sobrien	    abort ();
14660484Sobrien	  }
14760484Sobrien      }
14860484Sobrien
14960484Sobrien  /* Now let bfd_perform_relocation finish everything up.  */
15060484Sobrien  return bfd_reloc_continue;
15160484Sobrien}
15260484Sobrien
15360484Sobrien/* If USER_LABEL_PREFIX is defined as "_" (see coff_arm_is_local_label_name()
15460484Sobrien   in this file), then TARGET_UNDERSCORE should be defined, otherwise it
15560484Sobrien   should not.  */
15660484Sobrien#ifndef TARGET_UNDERSCORE
15760484Sobrien#define TARGET_UNDERSCORE '_'
15860484Sobrien#endif
15960484Sobrien
16060484Sobrien#ifndef PCRELOFFSET
161130561Sobrien#define PCRELOFFSET TRUE
16260484Sobrien#endif
16360484Sobrien
16460484Sobrien/* These most certainly belong somewhere else. Just had to get rid of
16560484Sobrien   the manifest constants in the code.  */
166218822Sdim
167218822Sdim#ifdef ARM_WINCE
168218822Sdim
169218822Sdim#define ARM_26D      0
170218822Sdim#define ARM_32       1
171218822Sdim#define ARM_RVA32    2
172218822Sdim#define ARM_26	     3
173218822Sdim#define ARM_THUMB12  4
174218822Sdim#define ARM_SECTION  14
175218822Sdim#define ARM_SECREL   15
176218822Sdim
177218822Sdim#else
178218822Sdim
17960484Sobrien#define ARM_8        0
18060484Sobrien#define ARM_16       1
18160484Sobrien#define ARM_32       2
18260484Sobrien#define ARM_26       3
18360484Sobrien#define ARM_DISP8    4
18460484Sobrien#define ARM_DISP16   5
18560484Sobrien#define ARM_DISP32   6
18660484Sobrien#define ARM_26D      7
187218822Sdim/* 8 is unused.  */
18860484Sobrien#define ARM_NEG16    9
18960484Sobrien#define ARM_NEG32   10
19060484Sobrien#define ARM_RVA32   11
19160484Sobrien#define ARM_THUMB9  12
19260484Sobrien#define ARM_THUMB12 13
19360484Sobrien#define ARM_THUMB23 14
19460484Sobrien
195218822Sdim#endif
19660484Sobrien
197218822Sdimstatic bfd_reloc_status_type aoutarm_fix_pcrel_26_done
198218822Sdim  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
199218822Sdimstatic bfd_reloc_status_type aoutarm_fix_pcrel_26
200218822Sdim  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
201218822Sdimstatic bfd_reloc_status_type coff_thumb_pcrel_12
202218822Sdim  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
203218822Sdim#ifndef ARM_WINCE
204218822Sdimstatic bfd_reloc_status_type coff_thumb_pcrel_9
205218822Sdim  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
206218822Sdimstatic bfd_reloc_status_type coff_thumb_pcrel_23
207218822Sdim  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
20860484Sobrien#endif
20960484Sobrien
21077298Sobrienstatic reloc_howto_type aoutarm_std_reloc_howto[] =
21189857Sobrien  {
21260484Sobrien#ifdef ARM_WINCE
213130561Sobrien    HOWTO (ARM_26D,
214130561Sobrien	   2,
215130561Sobrien	   2,
216130561Sobrien	   24,
217130561Sobrien	   TRUE,
218130561Sobrien	   0,
219130561Sobrien	   complain_overflow_dont,
220130561Sobrien	   aoutarm_fix_pcrel_26_done,
221130561Sobrien	   "ARM_26D",
222218822Sdim	   TRUE, 	/* partial_inplace.  */
223130561Sobrien	   0x00ffffff,
224130561Sobrien	   0x0,
225130561Sobrien	   PCRELOFFSET),
22689857Sobrien    HOWTO (ARM_32,
22789857Sobrien	   0,
22889857Sobrien	   2,
22989857Sobrien	   32,
230130561Sobrien	   FALSE,
23189857Sobrien	   0,
23289857Sobrien	   complain_overflow_bitfield,
23389857Sobrien	   coff_arm_reloc,
23489857Sobrien	   "ARM_32",
235218822Sdim	   TRUE, 	/* partial_inplace.  */
23689857Sobrien	   0xffffffff,
23789857Sobrien	   0xffffffff,
23889857Sobrien	   PCRELOFFSET),
23989857Sobrien    HOWTO (ARM_RVA32,
24089857Sobrien	   0,
24189857Sobrien	   2,
24289857Sobrien	   32,
243130561Sobrien	   FALSE,
24489857Sobrien	   0,
24589857Sobrien	   complain_overflow_bitfield,
24689857Sobrien	   coff_arm_reloc,
24789857Sobrien	   "ARM_RVA32",
248218822Sdim	   TRUE, 	/* partial_inplace.  */
24989857Sobrien	   0xffffffff,
25089857Sobrien	   0xffffffff,
25189857Sobrien	   PCRELOFFSET),
25289857Sobrien    HOWTO (ARM_26,
25389857Sobrien	   2,
25489857Sobrien	   2,
25589857Sobrien	   24,
256130561Sobrien	   TRUE,
25789857Sobrien	   0,
25889857Sobrien	   complain_overflow_signed,
25989857Sobrien	   aoutarm_fix_pcrel_26 ,
26089857Sobrien	   "ARM_26",
261130561Sobrien	   FALSE,
26289857Sobrien	   0x00ffffff,
26389857Sobrien	   0x00ffffff,
26489857Sobrien	   PCRELOFFSET),
26589857Sobrien    HOWTO (ARM_THUMB12,
26689857Sobrien	   1,
26789857Sobrien	   1,
26889857Sobrien	   11,
269130561Sobrien	   TRUE,
27089857Sobrien	   0,
27189857Sobrien	   complain_overflow_signed,
27289857Sobrien	   coff_thumb_pcrel_12 ,
27389857Sobrien	   "ARM_THUMB12",
274130561Sobrien	   FALSE,
27589857Sobrien	   0x000007ff,
27689857Sobrien	   0x000007ff,
27789857Sobrien	   PCRELOFFSET),
27889857Sobrien    EMPTY_HOWTO (-1),
27989857Sobrien    EMPTY_HOWTO (-1),
28089857Sobrien    EMPTY_HOWTO (-1),
28189857Sobrien    EMPTY_HOWTO (-1),
28289857Sobrien    EMPTY_HOWTO (-1),
28389857Sobrien    EMPTY_HOWTO (-1),
28489857Sobrien    EMPTY_HOWTO (-1),
28589857Sobrien    EMPTY_HOWTO (-1),
286130561Sobrien    EMPTY_HOWTO (-1),
28789857Sobrien    HOWTO (ARM_SECTION,
28889857Sobrien	   0,
28989857Sobrien	   1,
29089857Sobrien	   16,
291130561Sobrien	   FALSE,
29289857Sobrien	   0,
29389857Sobrien	   complain_overflow_bitfield,
29489857Sobrien	   coff_arm_reloc,
295130561Sobrien	   "ARM_SECTION",
296218822Sdim	   TRUE, 	/* partial_inplace.  */
29789857Sobrien	   0x0000ffff,
29889857Sobrien	   0x0000ffff,
29989857Sobrien	   PCRELOFFSET),
30089857Sobrien    HOWTO (ARM_SECREL,
30189857Sobrien	   0,
30289857Sobrien	   2,
30389857Sobrien	   32,
304130561Sobrien	   FALSE,
30589857Sobrien	   0,
30689857Sobrien	   complain_overflow_bitfield,
30789857Sobrien	   coff_arm_reloc,
308130561Sobrien	   "ARM_SECREL",
309218822Sdim	   TRUE, 	/* partial_inplace.  */
31089857Sobrien	   0xffffffff,
31189857Sobrien	   0xffffffff,
31289857Sobrien	   PCRELOFFSET),
31360484Sobrien#else /* not ARM_WINCE */
314218822Sdim    HOWTO (ARM_8,
315218822Sdim	   0,
316218822Sdim	   0,
317218822Sdim	   8,
318218822Sdim	   FALSE,
319218822Sdim	   0,
320218822Sdim	   complain_overflow_bitfield,
321218822Sdim	   coff_arm_reloc,
322218822Sdim	   "ARM_8",
323218822Sdim	   TRUE,
324218822Sdim	   0x000000ff,
325218822Sdim	   0x000000ff,
326218822Sdim	   PCRELOFFSET),
32789857Sobrien    HOWTO (ARM_16,
32889857Sobrien	   0,
32989857Sobrien	   1,
33089857Sobrien	   16,
331130561Sobrien	   FALSE,
33289857Sobrien	   0,
33389857Sobrien	   complain_overflow_bitfield,
33489857Sobrien	   coff_arm_reloc,
33589857Sobrien	   "ARM_16",
336130561Sobrien	   TRUE,
33789857Sobrien	   0x0000ffff,
33889857Sobrien	   0x0000ffff,
33989857Sobrien	   PCRELOFFSET),
34089857Sobrien    HOWTO (ARM_32,
34189857Sobrien	   0,
34289857Sobrien	   2,
34389857Sobrien	   32,
344130561Sobrien	   FALSE,
34589857Sobrien	   0,
34689857Sobrien	   complain_overflow_bitfield,
34789857Sobrien	   coff_arm_reloc,
34889857Sobrien	   "ARM_32",
349130561Sobrien	   TRUE,
35089857Sobrien	   0xffffffff,
35189857Sobrien	   0xffffffff,
35289857Sobrien	   PCRELOFFSET),
35389857Sobrien    HOWTO (ARM_26,
35489857Sobrien	   2,
35589857Sobrien	   2,
35689857Sobrien	   24,
357130561Sobrien	   TRUE,
35889857Sobrien	   0,
35989857Sobrien	   complain_overflow_signed,
36089857Sobrien	   aoutarm_fix_pcrel_26 ,
36189857Sobrien	   "ARM_26",
362130561Sobrien	   FALSE,
36389857Sobrien	   0x00ffffff,
36489857Sobrien	   0x00ffffff,
36589857Sobrien	   PCRELOFFSET),
36689857Sobrien    HOWTO (ARM_DISP8,
36789857Sobrien	   0,
36889857Sobrien	   0,
36989857Sobrien	   8,
370130561Sobrien	   TRUE,
37189857Sobrien	   0,
37289857Sobrien	   complain_overflow_signed,
37389857Sobrien	   coff_arm_reloc,
37489857Sobrien	   "ARM_DISP8",
375130561Sobrien	   TRUE,
37689857Sobrien	   0x000000ff,
37789857Sobrien	   0x000000ff,
378130561Sobrien	   TRUE),
37989857Sobrien    HOWTO (ARM_DISP16,
38089857Sobrien	   0,
38189857Sobrien	   1,
38289857Sobrien	   16,
383130561Sobrien	   TRUE,
38489857Sobrien	   0,
38589857Sobrien	   complain_overflow_signed,
38689857Sobrien	   coff_arm_reloc,
38789857Sobrien	   "ARM_DISP16",
388130561Sobrien	   TRUE,
38989857Sobrien	   0x0000ffff,
39089857Sobrien	   0x0000ffff,
391130561Sobrien	   TRUE),
39289857Sobrien    HOWTO (ARM_DISP32,
39389857Sobrien	   0,
39489857Sobrien	   2,
39589857Sobrien	   32,
396130561Sobrien	   TRUE,
39789857Sobrien	   0,
39889857Sobrien	   complain_overflow_signed,
39989857Sobrien	   coff_arm_reloc,
40089857Sobrien	   "ARM_DISP32",
401130561Sobrien	   TRUE,
40289857Sobrien	   0xffffffff,
40389857Sobrien	   0xffffffff,
404130561Sobrien	   TRUE),
40589857Sobrien    HOWTO (ARM_26D,
40689857Sobrien	   2,
40789857Sobrien	   2,
40889857Sobrien	   24,
409130561Sobrien	   FALSE,
41089857Sobrien	   0,
41189857Sobrien	   complain_overflow_dont,
41289857Sobrien	   aoutarm_fix_pcrel_26_done,
41389857Sobrien	   "ARM_26D",
414130561Sobrien	   TRUE,
41589857Sobrien	   0x00ffffff,
41689857Sobrien	   0x0,
417130561Sobrien	   FALSE),
41889857Sobrien    /* 8 is unused */
41989857Sobrien    EMPTY_HOWTO (-1),
42089857Sobrien    HOWTO (ARM_NEG16,
42189857Sobrien	   0,
42289857Sobrien	   -1,
42389857Sobrien	   16,
424130561Sobrien	   FALSE,
42589857Sobrien	   0,
42689857Sobrien	   complain_overflow_bitfield,
42789857Sobrien	   coff_arm_reloc,
42889857Sobrien	   "ARM_NEG16",
429130561Sobrien	   TRUE,
43089857Sobrien	   0x0000ffff,
43189857Sobrien	   0x0000ffff,
432130561Sobrien	   FALSE),
43389857Sobrien    HOWTO (ARM_NEG32,
43489857Sobrien	   0,
43589857Sobrien	   -2,
43689857Sobrien	   32,
437130561Sobrien	   FALSE,
43889857Sobrien	   0,
43989857Sobrien	   complain_overflow_bitfield,
44089857Sobrien	   coff_arm_reloc,
44189857Sobrien	   "ARM_NEG32",
442130561Sobrien	   TRUE,
44389857Sobrien	   0xffffffff,
44489857Sobrien	   0xffffffff,
445130561Sobrien	   FALSE),
44689857Sobrien    HOWTO (ARM_RVA32,
44789857Sobrien	   0,
44889857Sobrien	   2,
44989857Sobrien	   32,
450130561Sobrien	   FALSE,
45189857Sobrien	   0,
45289857Sobrien	   complain_overflow_bitfield,
45389857Sobrien	   coff_arm_reloc,
45489857Sobrien	   "ARM_RVA32",
455130561Sobrien	   TRUE,
45689857Sobrien	   0xffffffff,
45789857Sobrien	   0xffffffff,
45889857Sobrien	   PCRELOFFSET),
45989857Sobrien    HOWTO (ARM_THUMB9,
46089857Sobrien	   1,
46189857Sobrien	   1,
46289857Sobrien	   8,
463130561Sobrien	   TRUE,
46489857Sobrien	   0,
46589857Sobrien	   complain_overflow_signed,
46689857Sobrien	   coff_thumb_pcrel_9 ,
46789857Sobrien	   "ARM_THUMB9",
468130561Sobrien	   FALSE,
46989857Sobrien	   0x000000ff,
47089857Sobrien	   0x000000ff,
47189857Sobrien	   PCRELOFFSET),
47289857Sobrien    HOWTO (ARM_THUMB12,
47389857Sobrien	   1,
47489857Sobrien	   1,
47589857Sobrien	   11,
476130561Sobrien	   TRUE,
47789857Sobrien	   0,
47889857Sobrien	   complain_overflow_signed,
47989857Sobrien	   coff_thumb_pcrel_12 ,
48089857Sobrien	   "ARM_THUMB12",
481130561Sobrien	   FALSE,
48289857Sobrien	   0x000007ff,
48389857Sobrien	   0x000007ff,
48489857Sobrien	   PCRELOFFSET),
48589857Sobrien    HOWTO (ARM_THUMB23,
48689857Sobrien	   1,
48789857Sobrien	   2,
48889857Sobrien	   22,
489130561Sobrien	   TRUE,
49089857Sobrien	   0,
49189857Sobrien	   complain_overflow_signed,
49289857Sobrien	   coff_thumb_pcrel_23 ,
49389857Sobrien	   "ARM_THUMB23",
494130561Sobrien	   FALSE,
49589857Sobrien	   0x07ff07ff,
49689857Sobrien	   0x07ff07ff,
49789857Sobrien	   PCRELOFFSET)
49860484Sobrien#endif /* not ARM_WINCE */
49989857Sobrien  };
50060484Sobrien
50160484Sobrien#define NUM_RELOCS NUM_ELEM (aoutarm_std_reloc_howto)
50260484Sobrien
50360484Sobrien#ifdef COFF_WITH_PE
504130561Sobrien/* Return TRUE if this relocation should
50577298Sobrien   appear in the output .reloc section.  */
50660484Sobrien
507130561Sobrienstatic bfd_boolean
508218822Sdimin_reloc_p (bfd * abfd ATTRIBUTE_UNUSED,
509218822Sdim	    reloc_howto_type * howto)
51060484Sobrien{
51160484Sobrien  return !howto->pc_relative && howto->type != ARM_RVA32;
51277298Sobrien}
51360484Sobrien#endif
51460484Sobrien
51560484Sobrien#define RTYPE2HOWTO(cache_ptr, dst)		\
51660484Sobrien  (cache_ptr)->howto =				\
51760484Sobrien    (dst)->r_type < NUM_RELOCS			\
51860484Sobrien    ? aoutarm_std_reloc_howto + (dst)->r_type	\
51960484Sobrien    : NULL
52060484Sobrien
52160484Sobrien#define coff_rtype_to_howto coff_arm_rtype_to_howto
52260484Sobrien
52360484Sobrienstatic reloc_howto_type *
524218822Sdimcoff_arm_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
525218822Sdim			 asection *sec,
526218822Sdim			 struct internal_reloc *rel,
527218822Sdim			 struct coff_link_hash_entry *h ATTRIBUTE_UNUSED,
528218822Sdim			 struct internal_syment *sym ATTRIBUTE_UNUSED,
529218822Sdim			 bfd_vma *addendp)
53060484Sobrien{
53160484Sobrien  reloc_howto_type * howto;
53260484Sobrien
53360484Sobrien  if (rel->r_type >= NUM_RELOCS)
53460484Sobrien    return NULL;
53577298Sobrien
53660484Sobrien  howto = aoutarm_std_reloc_howto + rel->r_type;
53760484Sobrien
53860484Sobrien  if (rel->r_type == ARM_RVA32)
53960484Sobrien    *addendp -= pe_data (sec->output_section->owner)->pe_opthdr.ImageBase;
54060484Sobrien
541218822Sdim#if defined COFF_WITH_PE && defined ARM_WINCE
542218822Sdim  if (rel->r_type == ARM_SECREL)
543218822Sdim    {
544218822Sdim      bfd_vma osect_vma;
545218822Sdim
546218822Sdim      if (h && (h->type == bfd_link_hash_defined
547218822Sdim		|| h->type == bfd_link_hash_defweak))
548218822Sdim	osect_vma = h->root.u.def.section->output_section->vma;
549218822Sdim      else
550218822Sdim	{
551218822Sdim	  asection *sec;
552218822Sdim	  int i;
553218822Sdim
554218822Sdim	  /* Sigh, the only way to get the section to offset against
555218822Sdim	     is to find it the hard way.  */
556218822Sdim
557218822Sdim	  for (sec = abfd->sections, i = 1; i < sym->n_scnum; i++)
558218822Sdim	    sec = sec->next;
559218822Sdim
560218822Sdim	  osect_vma = sec->output_section->vma;
561218822Sdim	}
562218822Sdim
563218822Sdim      *addendp -= osect_vma;
564218822Sdim    }
565218822Sdim#endif
566218822Sdim
56760484Sobrien  return howto;
56860484Sobrien}
56989857Sobrien
57077298Sobrien/* Used by the assembler.  */
57160484Sobrien
57260484Sobrienstatic bfd_reloc_status_type
573218822Sdimaoutarm_fix_pcrel_26_done (bfd *abfd ATTRIBUTE_UNUSED,
574218822Sdim			   arelent *reloc_entry ATTRIBUTE_UNUSED,
575218822Sdim			   asymbol *symbol ATTRIBUTE_UNUSED,
576218822Sdim			   void * data ATTRIBUTE_UNUSED,
577218822Sdim			   asection *input_section ATTRIBUTE_UNUSED,
578218822Sdim			   bfd *output_bfd ATTRIBUTE_UNUSED,
579218822Sdim			   char **error_message ATTRIBUTE_UNUSED)
58060484Sobrien{
58160484Sobrien  /* This is dead simple at present.  */
58260484Sobrien  return bfd_reloc_ok;
58360484Sobrien}
58460484Sobrien
58577298Sobrien/* Used by the assembler.  */
58660484Sobrien
58760484Sobrienstatic bfd_reloc_status_type
588218822Sdimaoutarm_fix_pcrel_26 (bfd *abfd,
589218822Sdim		      arelent *reloc_entry,
590218822Sdim		      asymbol *symbol,
591218822Sdim		      void * data,
592218822Sdim		      asection *input_section,
593218822Sdim		      bfd *output_bfd,
594218822Sdim		      char **error_message ATTRIBUTE_UNUSED)
59560484Sobrien{
59660484Sobrien  bfd_vma relocation;
59760484Sobrien  bfd_size_type addr = reloc_entry->address;
59860484Sobrien  long target = bfd_get_32 (abfd, (bfd_byte *) data + addr);
59960484Sobrien  bfd_reloc_status_type flag = bfd_reloc_ok;
60077298Sobrien
60189857Sobrien  /* If this is an undefined symbol, return error.  */
60260484Sobrien  if (symbol->section == &bfd_und_section
60360484Sobrien      && (symbol->flags & BSF_WEAK) == 0)
60460484Sobrien    return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined;
60560484Sobrien
60660484Sobrien  /* If the sections are different, and we are doing a partial relocation,
60760484Sobrien     just ignore it for now.  */
60860484Sobrien  if (symbol->section->name != input_section->name
60960484Sobrien      && output_bfd != (bfd *)NULL)
61060484Sobrien    return bfd_reloc_continue;
61160484Sobrien
61260484Sobrien  relocation = (target & 0x00ffffff) << 2;
61389857Sobrien  relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend.  */
61460484Sobrien  relocation += symbol->value;
61560484Sobrien  relocation += symbol->section->output_section->vma;
61660484Sobrien  relocation += symbol->section->output_offset;
61760484Sobrien  relocation += reloc_entry->addend;
61860484Sobrien  relocation -= input_section->output_section->vma;
61960484Sobrien  relocation -= input_section->output_offset;
62060484Sobrien  relocation -= addr;
62177298Sobrien
62260484Sobrien  if (relocation & 3)
62360484Sobrien    return bfd_reloc_overflow;
62460484Sobrien
62589857Sobrien  /* Check for overflow.  */
62660484Sobrien  if (relocation & 0x02000000)
62760484Sobrien    {
62860484Sobrien      if ((relocation & ~ (bfd_vma) 0x03ffffff) != ~ (bfd_vma) 0x03ffffff)
62960484Sobrien	flag = bfd_reloc_overflow;
63060484Sobrien    }
63189857Sobrien  else if (relocation & ~(bfd_vma) 0x03ffffff)
63260484Sobrien    flag = bfd_reloc_overflow;
63360484Sobrien
63460484Sobrien  target &= ~0x00ffffff;
63560484Sobrien  target |= (relocation >> 2) & 0x00ffffff;
63689857Sobrien  bfd_put_32 (abfd, (bfd_vma) target, (bfd_byte *) data + addr);
63760484Sobrien
63860484Sobrien  /* Now the ARM magic... Change the reloc type so that it is marked as done.
63960484Sobrien     Strictly this is only necessary if we are doing a partial relocation.  */
64060484Sobrien  reloc_entry->howto = &aoutarm_std_reloc_howto[ARM_26D];
64160484Sobrien
64260484Sobrien  return flag;
64360484Sobrien}
64460484Sobrien
64560484Sobrienstatic bfd_reloc_status_type
646218822Sdimcoff_thumb_pcrel_common (bfd *abfd,
647218822Sdim			 arelent *reloc_entry,
648218822Sdim			 asymbol *symbol,
649218822Sdim			 void * data,
650218822Sdim			 asection *input_section,
651218822Sdim			 bfd *output_bfd,
652218822Sdim			 char **error_message ATTRIBUTE_UNUSED,
653218822Sdim			 thumb_pcrel_branchtype btype)
65460484Sobrien{
65560484Sobrien  bfd_vma relocation = 0;
65660484Sobrien  bfd_size_type addr = reloc_entry->address;
65760484Sobrien  long target = bfd_get_32 (abfd, (bfd_byte *) data + addr);
65860484Sobrien  bfd_reloc_status_type flag = bfd_reloc_ok;
65960484Sobrien  bfd_vma dstmsk;
66060484Sobrien  bfd_vma offmsk;
66160484Sobrien  bfd_vma signbit;
66260484Sobrien
66360484Sobrien  /* NOTE: This routine is currently used by GAS, but not by the link
66460484Sobrien     phase.  */
66560484Sobrien  switch (btype)
66660484Sobrien    {
66760484Sobrien    case b9:
66860484Sobrien      dstmsk  = 0x000000ff;
66960484Sobrien      offmsk  = 0x000001fe;
67060484Sobrien      signbit = 0x00000100;
67160484Sobrien      break;
67260484Sobrien
67360484Sobrien    case b12:
67460484Sobrien      dstmsk  = 0x000007ff;
67560484Sobrien      offmsk  = 0x00000ffe;
67660484Sobrien      signbit = 0x00000800;
67760484Sobrien      break;
67860484Sobrien
67960484Sobrien    case b23:
68060484Sobrien      dstmsk  = 0x07ff07ff;
68160484Sobrien      offmsk  = 0x007fffff;
68260484Sobrien      signbit = 0x00400000;
68360484Sobrien      break;
68460484Sobrien
68560484Sobrien    default:
68660484Sobrien      abort ();
68760484Sobrien    }
68877298Sobrien
68989857Sobrien  /* If this is an undefined symbol, return error.  */
69060484Sobrien  if (symbol->section == &bfd_und_section
69160484Sobrien      && (symbol->flags & BSF_WEAK) == 0)
69260484Sobrien    return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined;
69360484Sobrien
69460484Sobrien  /* If the sections are different, and we are doing a partial relocation,
69560484Sobrien     just ignore it for now.  */
69660484Sobrien  if (symbol->section->name != input_section->name
69760484Sobrien      && output_bfd != (bfd *)NULL)
69860484Sobrien    return bfd_reloc_continue;
69960484Sobrien
70060484Sobrien  switch (btype)
70160484Sobrien    {
70260484Sobrien    case b9:
70360484Sobrien    case b12:
70460484Sobrien      relocation = ((target & dstmsk) << 1);
70560484Sobrien      break;
70660484Sobrien
70760484Sobrien    case b23:
70860484Sobrien      if (bfd_big_endian (abfd))
70960484Sobrien	relocation = ((target & 0x7ff) << 1)  | ((target & 0x07ff0000) >> 4);
71060484Sobrien      else
71160484Sobrien	relocation = ((target & 0x7ff) << 12) | ((target & 0x07ff0000) >> 15);
71260484Sobrien      break;
71360484Sobrien
71460484Sobrien    default:
71560484Sobrien      abort ();
71660484Sobrien    }
71760484Sobrien
71889857Sobrien  relocation = (relocation ^ signbit) - signbit; /* Sign extend.  */
71960484Sobrien  relocation += symbol->value;
72060484Sobrien  relocation += symbol->section->output_section->vma;
72160484Sobrien  relocation += symbol->section->output_offset;
72260484Sobrien  relocation += reloc_entry->addend;
72360484Sobrien  relocation -= input_section->output_section->vma;
72460484Sobrien  relocation -= input_section->output_offset;
72560484Sobrien  relocation -= addr;
72660484Sobrien
72760484Sobrien  if (relocation & 1)
72860484Sobrien    return bfd_reloc_overflow;
72960484Sobrien
73089857Sobrien  /* Check for overflow.  */
73160484Sobrien  if (relocation & signbit)
73260484Sobrien    {
73360484Sobrien      if ((relocation & ~offmsk) != ~offmsk)
73460484Sobrien	flag = bfd_reloc_overflow;
73560484Sobrien    }
73660484Sobrien  else if (relocation & ~offmsk)
73760484Sobrien    flag = bfd_reloc_overflow;
73860484Sobrien
73960484Sobrien  target &= ~dstmsk;
74060484Sobrien  switch (btype)
74160484Sobrien   {
74260484Sobrien   case b9:
74360484Sobrien   case b12:
74460484Sobrien     target |= (relocation >> 1);
74560484Sobrien     break;
74660484Sobrien
74760484Sobrien   case b23:
74860484Sobrien     if (bfd_big_endian (abfd))
74989857Sobrien       target |= (((relocation & 0xfff) >> 1)
75089857Sobrien		  | ((relocation << 4)  & 0x07ff0000));
75160484Sobrien     else
75289857Sobrien       target |= (((relocation & 0xffe) << 15)
75389857Sobrien		  | ((relocation >> 12) & 0x7ff));
75460484Sobrien     break;
75560484Sobrien
75660484Sobrien   default:
75760484Sobrien     abort ();
75860484Sobrien   }
75960484Sobrien
76089857Sobrien  bfd_put_32 (abfd, (bfd_vma) target, (bfd_byte *) data + addr);
76160484Sobrien
76260484Sobrien  /* Now the ARM magic... Change the reloc type so that it is marked as done.
76360484Sobrien     Strictly this is only necessary if we are doing a partial relocation.  */
76460484Sobrien  reloc_entry->howto = & aoutarm_std_reloc_howto [ARM_26D];
76577298Sobrien
76689857Sobrien  /* TODO: We should possibly have DONE entries for the THUMB PCREL relocations.  */
76760484Sobrien  return flag;
76860484Sobrien}
76960484Sobrien
77099461Sobrien#ifndef ARM_WINCE
77160484Sobrienstatic bfd_reloc_status_type
772218822Sdimcoff_thumb_pcrel_23 (bfd *abfd,
773218822Sdim		     arelent *reloc_entry,
774218822Sdim		     asymbol *symbol,
775218822Sdim		     void * data,
776218822Sdim		     asection *input_section,
777218822Sdim		     bfd *output_bfd,
778218822Sdim		     char **error_message)
77960484Sobrien{
78060484Sobrien  return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data,
78189857Sobrien                                  input_section, output_bfd, error_message,
78289857Sobrien				  b23);
78360484Sobrien}
78460484Sobrien
78560484Sobrienstatic bfd_reloc_status_type
786218822Sdimcoff_thumb_pcrel_9 (bfd *abfd,
787218822Sdim		    arelent *reloc_entry,
788218822Sdim		    asymbol *symbol,
789218822Sdim		    void * data,
790218822Sdim		    asection *input_section,
791218822Sdim		    bfd *output_bfd,
792218822Sdim		    char **error_message)
79360484Sobrien{
79460484Sobrien  return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data,
79589857Sobrien                                  input_section, output_bfd, error_message,
79699461Sobrien				  b9);
79760484Sobrien}
79899461Sobrien#endif /* not ARM_WINCE */
79960484Sobrien
80060484Sobrienstatic bfd_reloc_status_type
801218822Sdimcoff_thumb_pcrel_12 (bfd *abfd,
802218822Sdim		     arelent *reloc_entry,
803218822Sdim		     asymbol *symbol,
804218822Sdim		     void * data,
805218822Sdim		     asection *input_section,
806218822Sdim		     bfd *output_bfd,
807218822Sdim		     char **error_message)
80860484Sobrien{
80960484Sobrien  return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data,
81089857Sobrien                                  input_section, output_bfd, error_message,
81199461Sobrien				  b12);
81260484Sobrien}
81360484Sobrien
81489857Sobrienstatic const struct reloc_howto_struct *
815218822Sdimcoff_arm_reloc_type_lookup (bfd * abfd, bfd_reloc_code_real_type code)
81660484Sobrien{
81760484Sobrien#define ASTD(i,j)       case i: return aoutarm_std_reloc_howto + j
81877298Sobrien
81960484Sobrien  if (code == BFD_RELOC_CTOR)
82060484Sobrien    switch (bfd_get_arch_info (abfd)->bits_per_address)
82160484Sobrien      {
82260484Sobrien      case 32:
82360484Sobrien        code = BFD_RELOC_32;
82460484Sobrien        break;
82589857Sobrien      default:
826218822Sdim	return NULL;
82760484Sobrien      }
82860484Sobrien
82960484Sobrien  switch (code)
83060484Sobrien    {
83160484Sobrien#ifdef ARM_WINCE
83260484Sobrien      ASTD (BFD_RELOC_32,                   ARM_32);
83360484Sobrien      ASTD (BFD_RELOC_RVA,                  ARM_RVA32);
83460484Sobrien      ASTD (BFD_RELOC_ARM_PCREL_BRANCH,     ARM_26);
83560484Sobrien      ASTD (BFD_RELOC_THUMB_PCREL_BRANCH12, ARM_THUMB12);
836218822Sdim      ASTD (BFD_RELOC_32_SECREL,            ARM_SECREL);
83760484Sobrien#else
83860484Sobrien      ASTD (BFD_RELOC_8,                    ARM_8);
83960484Sobrien      ASTD (BFD_RELOC_16,                   ARM_16);
84060484Sobrien      ASTD (BFD_RELOC_32,                   ARM_32);
84160484Sobrien      ASTD (BFD_RELOC_ARM_PCREL_BRANCH,     ARM_26);
84277298Sobrien      ASTD (BFD_RELOC_ARM_PCREL_BLX,        ARM_26);
84360484Sobrien      ASTD (BFD_RELOC_8_PCREL,              ARM_DISP8);
84460484Sobrien      ASTD (BFD_RELOC_16_PCREL,             ARM_DISP16);
84560484Sobrien      ASTD (BFD_RELOC_32_PCREL,             ARM_DISP32);
84660484Sobrien      ASTD (BFD_RELOC_RVA,                  ARM_RVA32);
84760484Sobrien      ASTD (BFD_RELOC_THUMB_PCREL_BRANCH9,  ARM_THUMB9);
84860484Sobrien      ASTD (BFD_RELOC_THUMB_PCREL_BRANCH12, ARM_THUMB12);
84960484Sobrien      ASTD (BFD_RELOC_THUMB_PCREL_BRANCH23, ARM_THUMB23);
85078828Sobrien      ASTD (BFD_RELOC_THUMB_PCREL_BLX,      ARM_THUMB23);
85177298Sobrien#endif
852218822Sdim    default: return NULL;
85360484Sobrien    }
85460484Sobrien}
85560484Sobrien
856218822Sdimstatic reloc_howto_type *
857218822Sdimcoff_arm_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
858218822Sdim			    const char *r_name)
859218822Sdim{
860218822Sdim  unsigned int i;
86160484Sobrien
862218822Sdim  for (i = 0;
863218822Sdim       i < (sizeof (aoutarm_std_reloc_howto)
864218822Sdim	    / sizeof (aoutarm_std_reloc_howto[0]));
865218822Sdim       i++)
866218822Sdim    if (aoutarm_std_reloc_howto[i].name != NULL
867218822Sdim	&& strcasecmp (aoutarm_std_reloc_howto[i].name, r_name) == 0)
868218822Sdim      return &aoutarm_std_reloc_howto[i];
869218822Sdim
870218822Sdim  return NULL;
871218822Sdim}
872218822Sdim
873218822Sdim#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER  2
874218822Sdim#define COFF_PAGE_SIZE                        0x1000
875218822Sdim
876218822Sdim/* Turn a howto into a reloc  nunmber.  */
87760484Sobrien#define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
878218822Sdim#define BADMAG(x)             ARMBADMAG(x)
879218822Sdim#define ARM                   1			/* Customize coffcode.h.  */
88060484Sobrien
88199461Sobrien#ifndef ARM_WINCE
88294536Sobrien/* Make sure that the 'r_offset' field is copied properly
88394536Sobrien   so that identical binaries will compare the same.  */
88494536Sobrien#define SWAP_IN_RELOC_OFFSET	H_GET_32
88594536Sobrien#define SWAP_OUT_RELOC_OFFSET	H_PUT_32
88699461Sobrien#endif
88794536Sobrien
88860484Sobrien/* Extend the coff_link_hash_table structure with a few ARM specific fields.
88960484Sobrien   This allows us to store global data here without actually creating any
89060484Sobrien   global variables, which is a no-no in the BFD world.  */
89160484Sobrienstruct coff_arm_link_hash_table
89289857Sobrien  {
89389857Sobrien    /* The original coff_link_hash_table structure.  MUST be first field.  */
89489857Sobrien    struct coff_link_hash_table	root;
89577298Sobrien
896130561Sobrien    /* The size in bytes of the section containing the Thumb-to-ARM glue.  */
89789857Sobrien    bfd_size_type		thumb_glue_size;
89877298Sobrien
899130561Sobrien    /* The size in bytes of the section containing the ARM-to-Thumb glue.  */
90089857Sobrien    bfd_size_type		arm_glue_size;
90160484Sobrien
902130561Sobrien    /* An arbitrary input BFD chosen to hold the glue sections.  */
90389857Sobrien    bfd *			bfd_of_glue_owner;
90460484Sobrien
90589857Sobrien    /* Support interworking with old, non-interworking aware ARM code.  */
90689857Sobrien    int 			support_old_code;
90760484Sobrien};
90860484Sobrien
90960484Sobrien/* Get the ARM coff linker hash table from a link_info structure.  */
91060484Sobrien#define coff_arm_hash_table(info) \
91160484Sobrien  ((struct coff_arm_link_hash_table *) ((info)->hash))
91260484Sobrien
91360484Sobrien/* Create an ARM coff linker hash table.  */
91460484Sobrien
91560484Sobrienstatic struct bfd_link_hash_table *
916218822Sdimcoff_arm_link_hash_table_create (bfd * abfd)
91760484Sobrien{
91860484Sobrien  struct coff_arm_link_hash_table * ret;
91989857Sobrien  bfd_size_type amt = sizeof (struct coff_arm_link_hash_table);
92060484Sobrien
921218822Sdim  ret = bfd_malloc (amt);
922218822Sdim  if (ret == NULL)
92360484Sobrien    return NULL;
92460484Sobrien
925218822Sdim  if (!_bfd_coff_link_hash_table_init (&ret->root,
926218822Sdim				       abfd,
927218822Sdim				       _bfd_coff_link_hash_newfunc,
928218822Sdim				       sizeof (struct coff_link_hash_entry)))
92960484Sobrien    {
930104834Sobrien      free (ret);
931218822Sdim      return NULL;
93260484Sobrien    }
93360484Sobrien
93460484Sobrien  ret->thumb_glue_size   = 0;
93560484Sobrien  ret->arm_glue_size     = 0;
93660484Sobrien  ret->bfd_of_glue_owner = NULL;
93760484Sobrien
93860484Sobrien  return & ret->root.root;
93960484Sobrien}
94060484Sobrien
94160484Sobrienstatic void
942218822Sdimarm_emit_base_file_entry (struct bfd_link_info *info,
943218822Sdim			  bfd *output_bfd,
944218822Sdim			  asection *input_section,
945218822Sdim			  bfd_vma reloc_offset)
94660484Sobrien{
94760484Sobrien  bfd_vma addr = reloc_offset
94860484Sobrien                - input_section->vma
94960484Sobrien                + input_section->output_offset
95060484Sobrien                  + input_section->output_section->vma;
95160484Sobrien
95289857Sobrien  if (coff_data (output_bfd)->pe)
95389857Sobrien     addr -= pe_data (output_bfd)->pe_opthdr.ImageBase;
95489857Sobrien  fwrite (& addr, 1, sizeof (addr), (FILE *) info->base_file);
95560484Sobrien
95660484Sobrien}
95760484Sobrien
95899461Sobrien#ifndef ARM_WINCE
95960484Sobrien/* The thumb form of a long branch is a bit finicky, because the offset
96060484Sobrien   encoding is split over two fields, each in it's own instruction. They
96177298Sobrien   can occur in any order. So given a thumb form of long branch, and an
96260484Sobrien   offset, insert the offset into the thumb branch and return finished
96377298Sobrien   instruction.
96460484Sobrien
96577298Sobrien   It takes two thumb instructions to encode the target address. Each has
966130561Sobrien   11 bits to invest. The upper 11 bits are stored in one (identified by
96777298Sobrien   H-0.. see below), the lower 11 bits are stored in the other (identified
96877298Sobrien   by H-1).
96960484Sobrien
97077298Sobrien   Combine together and shifted left by 1 (it's a half word address) and
97160484Sobrien   there you have it.
97260484Sobrien
97360484Sobrien     Op: 1111 = F,
97460484Sobrien     H-0, upper address-0 = 000
97560484Sobrien     Op: 1111 = F,
97660484Sobrien     H-1, lower address-0 = 800
97760484Sobrien
97877298Sobrien   They can be ordered either way, but the arm tools I've seen always put
97960484Sobrien   the lower one first. It probably doesn't matter. krk@cygnus.com
98060484Sobrien
98160484Sobrien   XXX:  Actually the order does matter.  The second instruction (H-1)
98260484Sobrien   moves the computed address into the PC, so it must be the second one
98360484Sobrien   in the sequence.  The problem, however is that whilst little endian code
98460484Sobrien   stores the instructions in HI then LOW order, big endian code does the
98589857Sobrien   reverse.  nickc@cygnus.com.  */
98660484Sobrien
98760484Sobrien#define LOW_HI_ORDER 0xF800F000
98860484Sobrien#define HI_LOW_ORDER 0xF000F800
98960484Sobrien
99060484Sobrienstatic insn32
991218822Sdiminsert_thumb_branch (insn32 br_insn, int rel_off)
99260484Sobrien{
99360484Sobrien  unsigned int low_bits;
99460484Sobrien  unsigned int high_bits;
99560484Sobrien
996218822Sdim  BFD_ASSERT ((rel_off & 1) != 1);
99760484Sobrien
998218822Sdim  rel_off >>= 1;                              /* Half word aligned address.  */
999218822Sdim  low_bits = rel_off & 0x000007FF;            /* The bottom 11 bits.  */
1000218822Sdim  high_bits = (rel_off >> 11) & 0x000007FF;   /* The top 11 bits.  */
100160484Sobrien
100260484Sobrien  if ((br_insn & LOW_HI_ORDER) == LOW_HI_ORDER)
100360484Sobrien    br_insn = LOW_HI_ORDER | (low_bits << 16) | high_bits;
100460484Sobrien  else if ((br_insn & HI_LOW_ORDER) == HI_LOW_ORDER)
100560484Sobrien    br_insn = HI_LOW_ORDER | (high_bits << 16) | low_bits;
100660484Sobrien  else
100789857Sobrien    /* FIXME: the BFD library should never abort except for internal errors
100889857Sobrien       - it should return an error status.  */
100989857Sobrien    abort (); /* Error - not a valid branch instruction form.  */
101060484Sobrien
101160484Sobrien  return br_insn;
101260484Sobrien}
101399461Sobrien
101460484Sobrien
101560484Sobrienstatic struct coff_link_hash_entry *
1016218822Sdimfind_thumb_glue (struct bfd_link_info *info,
1017218822Sdim		 const char *name,
1018218822Sdim		 bfd *input_bfd)
101960484Sobrien{
102089857Sobrien  char *tmp_name;
102189857Sobrien  struct coff_link_hash_entry *myh;
102289857Sobrien  bfd_size_type amt = strlen (name) + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1;
102360484Sobrien
1024218822Sdim  tmp_name = bfd_malloc (amt);
102560484Sobrien
102660484Sobrien  BFD_ASSERT (tmp_name);
102760484Sobrien
102860484Sobrien  sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name);
102977298Sobrien
103060484Sobrien  myh = coff_link_hash_lookup
1031130561Sobrien    (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE);
103277298Sobrien
103360484Sobrien  if (myh == NULL)
103460484Sobrien    /* xgettext:c-format */
1035218822Sdim    _bfd_error_handler (_("%B: unable to find THUMB glue '%s' for `%s'"),
1036218822Sdim			input_bfd, tmp_name, name);
103777298Sobrien
103860484Sobrien  free (tmp_name);
103960484Sobrien
104060484Sobrien  return myh;
104160484Sobrien}
104299461Sobrien#endif /* not ARM_WINCE */
104360484Sobrien
104460484Sobrienstatic struct coff_link_hash_entry *
1045218822Sdimfind_arm_glue (struct bfd_link_info *info,
1046218822Sdim	       const char *name,
1047218822Sdim	       bfd *input_bfd)
104860484Sobrien{
104989857Sobrien  char *tmp_name;
105060484Sobrien  struct coff_link_hash_entry * myh;
105189857Sobrien  bfd_size_type amt = strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1;
105260484Sobrien
1053218822Sdim  tmp_name = bfd_malloc (amt);
105460484Sobrien
105560484Sobrien  BFD_ASSERT (tmp_name);
105660484Sobrien
105760484Sobrien  sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name);
105877298Sobrien
105960484Sobrien  myh = coff_link_hash_lookup
1060130561Sobrien    (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE);
106160484Sobrien
106260484Sobrien  if (myh == NULL)
106360484Sobrien    /* xgettext:c-format */
1064218822Sdim    _bfd_error_handler (_("%B: unable to find ARM glue '%s' for `%s'"),
1065218822Sdim			input_bfd, tmp_name, name);
106677298Sobrien
106760484Sobrien  free (tmp_name);
106860484Sobrien
106960484Sobrien  return myh;
107060484Sobrien}
107160484Sobrien
107260484Sobrien/*
107360484Sobrien  ARM->Thumb glue:
107460484Sobrien
107560484Sobrien       .arm
107660484Sobrien       __func_from_arm:
107760484Sobrien	     ldr r12, __func_addr
107860484Sobrien	     bx  r12
107960484Sobrien       __func_addr:
108060484Sobrien            .word func    @ behave as if you saw a ARM_32 reloc
108160484Sobrien*/
108260484Sobrien
108360484Sobrien#define ARM2THUMB_GLUE_SIZE 12
108460484Sobrienstatic const insn32 a2t1_ldr_insn       = 0xe59fc000;
108560484Sobrienstatic const insn32 a2t2_bx_r12_insn    = 0xe12fff1c;
108660484Sobrienstatic const insn32 a2t3_func_addr_insn = 0x00000001;
108760484Sobrien
108860484Sobrien/*
108960484Sobrien   Thumb->ARM:				Thumb->(non-interworking aware) ARM
109060484Sobrien
109160484Sobrien   .thumb				.thumb
109260484Sobrien   .align 2				.align 2
109360484Sobrien      __func_from_thumb:		   __func_from_thumb:
109460484Sobrien	   bx pc				push {r6, lr}
109560484Sobrien	   nop					ldr  r6, __func_addr
109660484Sobrien   .arm						mov  lr, pc
109760484Sobrien      __func_change_to_arm:			bx   r6
109860484Sobrien	   b func   			.arm
109960484Sobrien					   __func_back_to_thumb:
110060484Sobrien   		  				ldmia r13! {r6, lr}
110160484Sobrien   					        bx    lr
110260484Sobrien   					   __func_addr:
110377298Sobrien					        .word	func
110460484Sobrien*/
110560484Sobrien
110660484Sobrien#define THUMB2ARM_GLUE_SIZE (globals->support_old_code ? 20 : 8)
1107218822Sdim#ifndef ARM_WINCE
110860484Sobrienstatic const insn16 t2a1_bx_pc_insn = 0x4778;
110960484Sobrienstatic const insn16 t2a2_noop_insn  = 0x46c0;
111060484Sobrienstatic const insn32 t2a3_b_insn     = 0xea000000;
111160484Sobrien
111260484Sobrienstatic const insn16 t2a1_push_insn  = 0xb540;
111360484Sobrienstatic const insn16 t2a2_ldr_insn   = 0x4e03;
111460484Sobrienstatic const insn16 t2a3_mov_insn   = 0x46fe;
111560484Sobrienstatic const insn16 t2a4_bx_insn    = 0x4730;
111660484Sobrienstatic const insn32 t2a5_pop_insn   = 0xe8bd4040;
111760484Sobrienstatic const insn32 t2a6_bx_insn    = 0xe12fff1e;
1118218822Sdim#endif
111960484Sobrien
112060484Sobrien/* TODO:
112160484Sobrien     We should really create new local (static) symbols in destination
112260484Sobrien     object for each stub we create.  We should also create local
112360484Sobrien     (static) symbols within the stubs when switching between ARM and
112460484Sobrien     Thumb code.  This will ensure that the debugger and disassembler
112560484Sobrien     can present a better view of stubs.
112660484Sobrien
112760484Sobrien     We can treat stubs like literal sections, and for the THUMB9 ones
112860484Sobrien     (short addressing range) we should be able to insert the stubs
112960484Sobrien     between sections. i.e. the simplest approach (since relocations
113060484Sobrien     are done on a section basis) is to dump the stubs at the end of
113160484Sobrien     processing a section. That way we can always try and minimise the
113260484Sobrien     offset to and from a stub. However, this does not map well onto
113360484Sobrien     the way that the linker/BFD does its work: mapping all input
113460484Sobrien     sections to output sections via the linker script before doing
113560484Sobrien     all the processing.
113660484Sobrien
113760484Sobrien     Unfortunately it may be easier to just to disallow short range
113860484Sobrien     Thumb->ARM stubs (i.e. no conditional inter-working branches,
113960484Sobrien     only branch-and-link (BL) calls.  This will simplify the processing
114060484Sobrien     since we can then put all of the stubs into their own section.
114160484Sobrien
114260484Sobrien  TODO:
114360484Sobrien     On a different subject, rather than complaining when a
114460484Sobrien     branch cannot fit in the number of bits available for the
114560484Sobrien     instruction we should generate a trampoline stub (needed to
114660484Sobrien     address the complete 32bit address space).  */
114760484Sobrien
114877298Sobrien/* The standard COFF backend linker does not cope with the special
114960484Sobrien   Thumb BRANCH23 relocation.  The alternative would be to split the
115060484Sobrien   BRANCH23 into seperate HI23 and LO23 relocations. However, it is a
115177298Sobrien   bit simpler simply providing our own relocation driver.  */
115260484Sobrien
115360484Sobrien/* The reloc processing routine for the ARM/Thumb COFF linker.  NOTE:
115460484Sobrien   This code is a very slightly modified copy of
115560484Sobrien   _bfd_coff_generic_relocate_section.  It would be a much more
115660484Sobrien   maintainable solution to have a MACRO that could be expanded within
115760484Sobrien   _bfd_coff_generic_relocate_section that would only be provided for
115860484Sobrien   ARM/Thumb builds.  It is only the code marked THUMBEXTENSION that
115960484Sobrien   is different from the original.  */
116060484Sobrien
1161130561Sobrienstatic bfd_boolean
1162218822Sdimcoff_arm_relocate_section (bfd *output_bfd,
1163218822Sdim			   struct bfd_link_info *info,
1164218822Sdim			   bfd *input_bfd,
1165218822Sdim			   asection *input_section,
1166218822Sdim			   bfd_byte *contents,
1167218822Sdim			   struct internal_reloc *relocs,
1168218822Sdim			   struct internal_syment *syms,
1169218822Sdim			   asection **sections)
117060484Sobrien{
117160484Sobrien  struct internal_reloc * rel;
117260484Sobrien  struct internal_reloc * relend;
1173218822Sdim#ifndef ARM_WINCE
1174218822Sdim  bfd_vma high_address = bfd_get_section_limit (input_bfd, input_section);
1175218822Sdim#endif
117660484Sobrien
117760484Sobrien  rel = relocs;
117860484Sobrien  relend = rel + input_section->reloc_count;
117960484Sobrien
118060484Sobrien  for (; rel < relend; rel++)
118160484Sobrien    {
118260484Sobrien      int                            done = 0;
118360484Sobrien      long                           symndx;
118460484Sobrien      struct coff_link_hash_entry *  h;
118560484Sobrien      struct internal_syment *       sym;
118660484Sobrien      bfd_vma                        addend;
118760484Sobrien      bfd_vma                        val;
118860484Sobrien      reloc_howto_type *             howto;
118960484Sobrien      bfd_reloc_status_type          rstat;
119060484Sobrien      bfd_vma                        h_val;
119160484Sobrien
119260484Sobrien      symndx = rel->r_symndx;
119360484Sobrien
119460484Sobrien      if (symndx == -1)
119560484Sobrien	{
119660484Sobrien	  h = NULL;
119760484Sobrien	  sym = NULL;
119860484Sobrien	}
119960484Sobrien      else
120077298Sobrien	{
120160484Sobrien	  h = obj_coff_sym_hashes (input_bfd)[symndx];
120260484Sobrien	  sym = syms + symndx;
120360484Sobrien	}
120460484Sobrien
120560484Sobrien      /* COFF treats common symbols in one of two ways.  Either the
120660484Sobrien         size of the symbol is included in the section contents, or it
120760484Sobrien         is not.  We assume that the size is not included, and force
120860484Sobrien         the rtype_to_howto function to adjust the addend as needed.  */
120960484Sobrien
121060484Sobrien      if (sym != NULL && sym->n_scnum != 0)
121160484Sobrien	addend = - sym->n_value;
121260484Sobrien      else
121360484Sobrien	addend = 0;
121460484Sobrien
121560484Sobrien      howto = coff_rtype_to_howto (input_bfd, input_section, rel, h,
121660484Sobrien				       sym, &addend);
121760484Sobrien      if (howto == NULL)
1218130561Sobrien	return FALSE;
121960484Sobrien
122060484Sobrien      /* The relocation_section function will skip pcrel_offset relocs
1221130561Sobrien         when doing a relocatable link.  However, we want to convert
1222130561Sobrien         ARM_26 to ARM_26D relocs if possible.  We return a fake howto in
122360484Sobrien         this case without pcrel_offset set, and adjust the addend to
1224130561Sobrien         compensate.  'partial_inplace' is also set, since we want 'done'
1225130561Sobrien         relocations to be reflected in section's data.  */
122660484Sobrien      if (rel->r_type == ARM_26
122760484Sobrien          && h != NULL
1228130561Sobrien          && info->relocatable
122960484Sobrien          && (h->root.type == bfd_link_hash_defined
123060484Sobrien	      || h->root.type == bfd_link_hash_defweak)
123189857Sobrien          && (h->root.u.def.section->output_section
123289857Sobrien	      == input_section->output_section))
123360484Sobrien        {
123477298Sobrien          static reloc_howto_type fake_arm26_reloc =
123560484Sobrien	    HOWTO (ARM_26,
123660484Sobrien    	       2,
123760484Sobrien    	       2,
123860484Sobrien    	       24,
1239130561Sobrien    	       TRUE,
124060484Sobrien    	       0,
124160484Sobrien    	       complain_overflow_signed,
124260484Sobrien    	       aoutarm_fix_pcrel_26 ,
124360484Sobrien    	       "ARM_26",
1244130561Sobrien    	       TRUE,
124560484Sobrien    	       0x00ffffff,
124677298Sobrien    	       0x00ffffff,
1247130561Sobrien    	       FALSE);
124860484Sobrien
124960484Sobrien          addend -= rel->r_vaddr - input_section->vma;
1250130561Sobrien#ifdef ARM_WINCE
1251130561Sobrien          /* FIXME: I don't know why, but the hack is necessary for correct
1252218822Sdim                    generation of bl's instruction offset.  */
1253130561Sobrien          addend -= 8;
1254130561Sobrien#endif
1255218822Sdim          howto = & fake_arm26_reloc;
125660484Sobrien        }
125760484Sobrien
125860484Sobrien#ifdef ARM_WINCE
125960484Sobrien      /* MS ARM-CE makes the reloc relative to the opcode's pc, not
126077298Sobrien	 the next opcode's pc, so is off by one.  */
1261130561Sobrien      if (howto->pc_relative && !info->relocatable)
126260484Sobrien	addend -= 8;
126360484Sobrien#endif
126477298Sobrien
1265130561Sobrien      /* If we are doing a relocatable link, then we can just ignore
126660484Sobrien         a PC relative reloc that is pcrel_offset.  It will already
1267130561Sobrien         have the correct value.  If this is not a relocatable link,
126860484Sobrien         then we should ignore the symbol value.  */
126960484Sobrien      if (howto->pc_relative && howto->pcrel_offset)
127060484Sobrien        {
1271130561Sobrien          if (info->relocatable)
127260484Sobrien            continue;
127378828Sobrien	  /* FIXME - it is not clear which targets need this next test
127478828Sobrien	     and which do not.  It is known that it is needed for the
127589857Sobrien	     VxWorks and EPOC-PE targets, but it is also known that it
1276130561Sobrien	     was suppressed for other ARM targets.  This ought to be
127789857Sobrien	     sorted out one day.  */
127889857Sobrien#ifdef ARM_COFF_BUGFIX
127978828Sobrien	  /* We must not ignore the symbol value.  If the symbol is
128078828Sobrien	     within the same section, the relocation should have already
128178828Sobrien	     been fixed, but if it is not, we'll be handed a reloc into
128278828Sobrien	     the beginning of the symbol's section, so we must not cancel
128378828Sobrien	     out the symbol's value, otherwise we'll be adding it in
128478828Sobrien	     twice.  */
128560484Sobrien          if (sym != NULL && sym->n_scnum != 0)
128660484Sobrien            addend += sym->n_value;
128777298Sobrien#endif
128860484Sobrien        }
128960484Sobrien
129060484Sobrien      val = 0;
129160484Sobrien
129260484Sobrien      if (h == NULL)
129360484Sobrien	{
129460484Sobrien	  asection *sec;
129560484Sobrien
129660484Sobrien	  if (symndx == -1)
129760484Sobrien	    {
129860484Sobrien	      sec = bfd_abs_section_ptr;
129960484Sobrien	      val = 0;
130060484Sobrien	    }
130160484Sobrien	  else
130260484Sobrien	    {
130360484Sobrien	      sec = sections[symndx];
130460484Sobrien              val = (sec->output_section->vma
130560484Sobrien		     + sec->output_offset
130660484Sobrien		     + sym->n_value
130760484Sobrien		     - sec->vma);
130860484Sobrien	    }
130960484Sobrien	}
131060484Sobrien      else
131160484Sobrien	{
131260484Sobrien          /* We don't output the stubs if we are generating a
131360484Sobrien             relocatable output file, since we may as well leave the
131460484Sobrien             stub generation to the final linker pass. If we fail to
131560484Sobrien	     verify that the name is defined, we'll try to build stubs
131677298Sobrien	     for an undefined name...  */
1317130561Sobrien          if (! info->relocatable
131860484Sobrien	      && (   h->root.type == bfd_link_hash_defined
131960484Sobrien		  || h->root.type == bfd_link_hash_defweak))
132060484Sobrien            {
132160484Sobrien	      asection *   h_sec = h->root.u.def.section;
132260484Sobrien	      const char * name  = h->root.root.string;
132377298Sobrien
132460484Sobrien	      /* h locates the symbol referenced in the reloc.  */
132560484Sobrien	      h_val = (h->root.u.def.value
132660484Sobrien		       + h_sec->output_section->vma
132760484Sobrien		       + h_sec->output_offset);
132860484Sobrien
132960484Sobrien              if (howto->type == ARM_26)
133060484Sobrien                {
133160484Sobrien                  if (   h->class == C_THUMBSTATFUNC
133260484Sobrien		      || h->class == C_THUMBEXTFUNC)
133360484Sobrien		    {
133489857Sobrien		      /* Arm code calling a Thumb function.  */
133560484Sobrien		      unsigned long int                 tmp;
133689857Sobrien		      bfd_vma                           my_offset;
133760484Sobrien		      asection *                        s;
133860484Sobrien		      long int                          ret_offset;
133977298Sobrien		      struct coff_link_hash_entry *     myh;
134060484Sobrien		      struct coff_arm_link_hash_table * globals;
134177298Sobrien
134260484Sobrien		      myh = find_arm_glue (info, name, input_bfd);
134360484Sobrien		      if (myh == NULL)
1344130561Sobrien			return FALSE;
134560484Sobrien
134660484Sobrien		      globals = coff_arm_hash_table (info);
134760484Sobrien
134860484Sobrien		      BFD_ASSERT (globals != NULL);
134960484Sobrien		      BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
135077298Sobrien
135160484Sobrien		      my_offset = myh->root.u.def.value;
135277298Sobrien
135377298Sobrien		      s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
135460484Sobrien						  ARM2THUMB_GLUE_SECTION_NAME);
135560484Sobrien		      BFD_ASSERT (s != NULL);
135660484Sobrien		      BFD_ASSERT (s->contents != NULL);
135760484Sobrien		      BFD_ASSERT (s->output_section != NULL);
135860484Sobrien
135960484Sobrien		      if ((my_offset & 0x01) == 0x01)
136060484Sobrien			{
136160484Sobrien			  if (h_sec->owner != NULL
136260484Sobrien			      && INTERWORK_SET (h_sec->owner)
136360484Sobrien			      && ! INTERWORK_FLAG (h_sec->owner))
1364218822Sdim			    _bfd_error_handler
1365218822Sdim			      /* xgettext:c-format */
1366218822Sdim			      (_("%B(%s): warning: interworking not enabled.\n"
1367218822Sdim				 "  first occurrence: %B: arm call to thumb"),
1368218822Sdim			       h_sec->owner, input_bfd, name);
136960484Sobrien
137060484Sobrien			  --my_offset;
137160484Sobrien			  myh->root.u.def.value = my_offset;
137260484Sobrien
137389857Sobrien			  bfd_put_32 (output_bfd, (bfd_vma) a2t1_ldr_insn,
137460484Sobrien				      s->contents + my_offset);
137577298Sobrien
137689857Sobrien			  bfd_put_32 (output_bfd, (bfd_vma) a2t2_bx_r12_insn,
137760484Sobrien				      s->contents + my_offset + 4);
137877298Sobrien
137960484Sobrien			  /* It's a thumb address.  Add the low order bit.  */
138060484Sobrien			  bfd_put_32 (output_bfd, h_val | a2t3_func_addr_insn,
138160484Sobrien				      s->contents + my_offset + 8);
138260484Sobrien
138360484Sobrien                          if (info->base_file)
138477298Sobrien                            arm_emit_base_file_entry (info, output_bfd, s,
138589857Sobrien                                                      my_offset + 8);
138660484Sobrien
138760484Sobrien			}
138860484Sobrien
138960484Sobrien		      BFD_ASSERT (my_offset <= globals->arm_glue_size);
139060484Sobrien
139160484Sobrien		      tmp = bfd_get_32 (input_bfd, contents + rel->r_vaddr
139260484Sobrien					- input_section->vma);
139377298Sobrien
139460484Sobrien		      tmp = tmp & 0xFF000000;
139560484Sobrien
139677298Sobrien		      /* Somehow these are both 4 too far, so subtract 8.  */
139760484Sobrien		      ret_offset =
139860484Sobrien			s->output_offset
139977298Sobrien			+ my_offset
140060484Sobrien			+ s->output_section->vma
140160484Sobrien			- (input_section->output_offset
140277298Sobrien			   + input_section->output_section->vma
140360484Sobrien			   + rel->r_vaddr)
140460484Sobrien			- 8;
140560484Sobrien
140660484Sobrien		      tmp = tmp | ((ret_offset >> 2) & 0x00FFFFFF);
140777298Sobrien
140889857Sobrien		      bfd_put_32 (output_bfd, (bfd_vma) tmp,
140989857Sobrien				  contents + rel->r_vaddr - input_section->vma);
141060484Sobrien		      done = 1;
141160484Sobrien		    }
141260484Sobrien                }
141377298Sobrien
141460484Sobrien#ifndef ARM_WINCE
141589857Sobrien	      /* Note: We used to check for ARM_THUMB9 and ARM_THUMB12.  */
141660484Sobrien              else if (howto->type == ARM_THUMB23)
141760484Sobrien                {
141877298Sobrien                  if (   h->class == C_EXT
141960484Sobrien		      || h->class == C_STAT
142060484Sobrien		      || h->class == C_LABEL)
142160484Sobrien		    {
1422218822Sdim		      /* Thumb code calling an ARM function.  */
142360484Sobrien		      asection *                         s = 0;
142489857Sobrien		      bfd_vma                            my_offset;
142560484Sobrien		      unsigned long int                  tmp;
142660484Sobrien		      long int                           ret_offset;
142760484Sobrien		      struct coff_link_hash_entry *      myh;
142860484Sobrien		      struct coff_arm_link_hash_table *  globals;
142960484Sobrien
143060484Sobrien		      myh = find_thumb_glue (info, name, input_bfd);
143160484Sobrien		      if (myh == NULL)
1432130561Sobrien			return FALSE;
143360484Sobrien
143460484Sobrien		      globals = coff_arm_hash_table (info);
143577298Sobrien
143660484Sobrien		      BFD_ASSERT (globals != NULL);
143760484Sobrien		      BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
143877298Sobrien
143960484Sobrien		      my_offset = myh->root.u.def.value;
144077298Sobrien
144177298Sobrien		      s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
144260484Sobrien						   THUMB2ARM_GLUE_SECTION_NAME);
144377298Sobrien
144460484Sobrien		      BFD_ASSERT (s != NULL);
144560484Sobrien		      BFD_ASSERT (s->contents != NULL);
144660484Sobrien		      BFD_ASSERT (s->output_section != NULL);
144777298Sobrien
144860484Sobrien		      if ((my_offset & 0x01) == 0x01)
144960484Sobrien			{
145060484Sobrien			  if (h_sec->owner != NULL
145160484Sobrien			      && INTERWORK_SET (h_sec->owner)
145260484Sobrien			      && ! INTERWORK_FLAG (h_sec->owner)
145360484Sobrien			      && ! globals->support_old_code)
1454218822Sdim			    _bfd_error_handler
1455218822Sdim			      /* xgettext:c-format */
1456218822Sdim			      (_("%B(%s): warning: interworking not enabled.\n"
1457218822Sdim				 "  first occurrence: %B: thumb call to arm\n"
1458218822Sdim				 "  consider relinking with --support-old-code enabled"),
1459218822Sdim			       h_sec->owner, input_bfd, name);
146077298Sobrien
146160484Sobrien			  -- my_offset;
146260484Sobrien			  myh->root.u.def.value = my_offset;
146360484Sobrien
146460484Sobrien			  if (globals->support_old_code)
146560484Sobrien			    {
146689857Sobrien			      bfd_put_16 (output_bfd, (bfd_vma) t2a1_push_insn,
146760484Sobrien					  s->contents + my_offset);
146877298Sobrien
146989857Sobrien			      bfd_put_16 (output_bfd, (bfd_vma) t2a2_ldr_insn,
147060484Sobrien					  s->contents + my_offset + 2);
147160484Sobrien
147289857Sobrien			      bfd_put_16 (output_bfd, (bfd_vma) t2a3_mov_insn,
147360484Sobrien					  s->contents + my_offset + 4);
147460484Sobrien
147589857Sobrien			      bfd_put_16 (output_bfd, (bfd_vma) t2a4_bx_insn,
147660484Sobrien					  s->contents + my_offset + 6);
147777298Sobrien
147889857Sobrien			      bfd_put_32 (output_bfd, (bfd_vma) t2a5_pop_insn,
147960484Sobrien					  s->contents + my_offset + 8);
148077298Sobrien
148189857Sobrien			      bfd_put_32 (output_bfd, (bfd_vma) t2a6_bx_insn,
148260484Sobrien					  s->contents + my_offset + 12);
148377298Sobrien
148460484Sobrien			      /* Store the address of the function in the last word of the stub.  */
148560484Sobrien			      bfd_put_32 (output_bfd, h_val,
148660484Sobrien					  s->contents + my_offset + 16);
148760484Sobrien
148860484Sobrien                              if (info->base_file)
148989857Sobrien                                arm_emit_base_file_entry (info, output_bfd, s,
149089857Sobrien							  my_offset + 16);
149160484Sobrien			    }
149260484Sobrien			  else
149360484Sobrien			    {
149489857Sobrien			      bfd_put_16 (output_bfd, (bfd_vma) t2a1_bx_pc_insn,
149560484Sobrien					  s->contents + my_offset);
149677298Sobrien
149789857Sobrien			      bfd_put_16 (output_bfd, (bfd_vma) t2a2_noop_insn,
149860484Sobrien					  s->contents + my_offset + 2);
149977298Sobrien
150060484Sobrien			      ret_offset =
1501218822Sdim		/* Address of destination of the stub.  */
1502218822Sdim				((bfd_signed_vma) h_val)
150360484Sobrien				- ((bfd_signed_vma)
1504218822Sdim		/* Offset from the start of the current section to the start of the stubs.  */
1505218822Sdim				   (s->output_offset
1506218822Sdim		/* Offset of the start of this stub from the start of the stubs.  */
1507218822Sdim				    + my_offset
1508218822Sdim		/* Address of the start of the current section.  */
1509218822Sdim				    + s->output_section->vma)
1510218822Sdim		/* The branch instruction is 4 bytes into the stub.  */
1511218822Sdim				   + 4
1512218822Sdim		/* ARM branches work from the pc of the instruction + 8.  */
1513218822Sdim				   + 8);
151477298Sobrien
151560484Sobrien			      bfd_put_32 (output_bfd,
151689857Sobrien					  (bfd_vma) t2a3_b_insn | ((ret_offset >> 2) & 0x00FFFFFF),
151760484Sobrien					  s->contents + my_offset + 4);
151860484Sobrien
151960484Sobrien			    }
152060484Sobrien			}
152160484Sobrien
152260484Sobrien		      BFD_ASSERT (my_offset <= globals->thumb_glue_size);
152360484Sobrien
152460484Sobrien		      /* Now go back and fix up the original BL insn to point
152560484Sobrien			 to here.  */
152660484Sobrien		      ret_offset =
152760484Sobrien			s->output_offset
152860484Sobrien			+ my_offset
152960484Sobrien			- (input_section->output_offset
153060484Sobrien			   + rel->r_vaddr)
153160484Sobrien			-4;
153277298Sobrien
153360484Sobrien		      tmp = bfd_get_32 (input_bfd, contents + rel->r_vaddr
153460484Sobrien					- input_section->vma);
153560484Sobrien
153660484Sobrien		      bfd_put_32 (output_bfd,
153789857Sobrien				  (bfd_vma) insert_thumb_branch (tmp,
153889857Sobrien								 ret_offset),
153989857Sobrien				  contents + rel->r_vaddr - input_section->vma);
154077298Sobrien
154160484Sobrien		      done = 1;
154260484Sobrien                    }
154360484Sobrien                }
154460484Sobrien#endif
154560484Sobrien            }
154677298Sobrien
154760484Sobrien          /* If the relocation type and destination symbol does not
154860484Sobrien             fall into one of the above categories, then we can just
154977298Sobrien             perform a direct link.  */
155060484Sobrien
155160484Sobrien	  if (done)
155260484Sobrien	    rstat = bfd_reloc_ok;
155377298Sobrien	  else
155460484Sobrien	    if (   h->root.type == bfd_link_hash_defined
155560484Sobrien		|| h->root.type == bfd_link_hash_defweak)
155660484Sobrien	    {
155760484Sobrien	      asection *sec;
155860484Sobrien
155960484Sobrien	      sec = h->root.u.def.section;
156060484Sobrien	      val = (h->root.u.def.value
156160484Sobrien		     + sec->output_section->vma
156260484Sobrien		     + sec->output_offset);
156360484Sobrien	      }
156460484Sobrien
1565130561Sobrien	  else if (! info->relocatable)
156660484Sobrien	    {
156760484Sobrien	      if (! ((*info->callbacks->undefined_symbol)
156860484Sobrien		     (info, h->root.root.string, input_bfd, input_section,
1569130561Sobrien		      rel->r_vaddr - input_section->vma, TRUE)))
1570130561Sobrien		return FALSE;
157160484Sobrien	    }
157260484Sobrien	}
157360484Sobrien
157460484Sobrien      if (info->base_file)
157560484Sobrien	{
157677298Sobrien	  /* Emit a reloc if the backend thinks it needs it.  */
157760484Sobrien	  if (sym && pe_data(output_bfd)->in_reloc_p(output_bfd, howto))
157889857Sobrien            arm_emit_base_file_entry (info, output_bfd, input_section,
157989857Sobrien				      rel->r_vaddr);
158060484Sobrien	}
158177298Sobrien
158260484Sobrien      if (done)
158360484Sobrien	rstat = bfd_reloc_ok;
158460484Sobrien#ifndef ARM_WINCE
1585218822Sdim      /* Only perform this fix during the final link, not a relocatable link.  */
1586130561Sobrien      else if (! info->relocatable
158760484Sobrien	       && howto->type == ARM_THUMB23)
158860484Sobrien        {
158960484Sobrien          /* This is pretty much a copy of what the default
159060484Sobrien             _bfd_final_link_relocate and _bfd_relocate_contents
159160484Sobrien             routines do to perform a relocation, with special
159260484Sobrien             processing for the split addressing of the Thumb BL
159360484Sobrien             instruction.  Again, it would probably be simpler adding a
159460484Sobrien             ThumbBRANCH23 specific macro expansion into the default
159560484Sobrien             code.  */
159677298Sobrien
159760484Sobrien          bfd_vma address = rel->r_vaddr - input_section->vma;
159877298Sobrien
1599218822Sdim	  if (address > high_address)
160060484Sobrien	    rstat = bfd_reloc_outofrange;
160160484Sobrien          else
160260484Sobrien            {
1603130561Sobrien              bfd_vma relocation = val + addend;
1604130561Sobrien	      int size = bfd_get_reloc_size (howto);
1605130561Sobrien	      bfd_boolean overflow = FALSE;
1606130561Sobrien	      bfd_byte *location = contents + address;
1607130561Sobrien	      bfd_vma x = bfd_get_32 (input_bfd, location);
1608130561Sobrien	      bfd_vma src_mask = 0x007FFFFE;
1609130561Sobrien	      bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1;
1610130561Sobrien	      bfd_signed_vma reloc_signed_min = ~reloc_signed_max;
1611130561Sobrien	      bfd_vma check;
1612130561Sobrien	      bfd_signed_vma signed_check;
1613130561Sobrien	      bfd_vma add;
1614130561Sobrien	      bfd_signed_vma signed_add;
161560484Sobrien
161660484Sobrien	      BFD_ASSERT (size == 4);
161777298Sobrien
161878828Sobrien              /* howto->pc_relative should be TRUE for type 14 BRANCH23.  */
161960484Sobrien              relocation -= (input_section->output_section->vma
162060484Sobrien                             + input_section->output_offset);
162177298Sobrien
162278828Sobrien              /* howto->pcrel_offset should be TRUE for type 14 BRANCH23.  */
162360484Sobrien              relocation -= address;
162477298Sobrien
162577298Sobrien	      /* No need to negate the relocation with BRANCH23.  */
162660484Sobrien	      /* howto->complain_on_overflow == complain_overflow_signed for BRANCH23.  */
162760484Sobrien	      /* howto->rightshift == 1 */
162878828Sobrien
162960484Sobrien	      /* Drop unwanted bits from the value we are relocating to.  */
163060484Sobrien	      check = relocation >> howto->rightshift;
163177298Sobrien
163260484Sobrien	      /* If this is a signed value, the rightshift just dropped
163360484Sobrien		 leading 1 bits (assuming twos complement).  */
163460484Sobrien	      if ((bfd_signed_vma) relocation >= 0)
163560484Sobrien		signed_check = check;
163660484Sobrien	      else
163760484Sobrien		signed_check = (check
163860484Sobrien				| ((bfd_vma) - 1
163960484Sobrien				   & ~((bfd_vma) - 1 >> howto->rightshift)));
164077298Sobrien
164160484Sobrien	      /* Get the value from the object file.  */
164260484Sobrien	      if (bfd_big_endian (input_bfd))
164378828Sobrien		add = (((x) & 0x07ff0000) >> 4) | (((x) & 0x7ff) << 1);
164460484Sobrien	      else
164578828Sobrien		add = ((((x) & 0x7ff) << 12) | (((x) & 0x07ff0000) >> 15));
164660484Sobrien
164760484Sobrien	      /* Get the value from the object file with an appropriate sign.
164860484Sobrien		 The expression involving howto->src_mask isolates the upper
164960484Sobrien		 bit of src_mask.  If that bit is set in the value we are
165060484Sobrien		 adding, it is negative, and we subtract out that number times
165160484Sobrien		 two.  If src_mask includes the highest possible bit, then we
165260484Sobrien		 can not get the upper bit, but that does not matter since
165360484Sobrien		 signed_add needs no adjustment to become negative in that
165460484Sobrien		 case.  */
165560484Sobrien	      signed_add = add;
165677298Sobrien
165760484Sobrien	      if ((add & (((~ src_mask) >> 1) & src_mask)) != 0)
165860484Sobrien		signed_add -= (((~ src_mask) >> 1) & src_mask) << 1;
165977298Sobrien
166078828Sobrien	      /* howto->bitpos == 0 */
166160484Sobrien	      /* Add the value from the object file, shifted so that it is a
166260484Sobrien		 straight number.  */
166360484Sobrien	      signed_check += signed_add;
166478828Sobrien	      relocation   += signed_add;
166560484Sobrien
166660484Sobrien	      BFD_ASSERT (howto->complain_on_overflow == complain_overflow_signed);
166760484Sobrien
166860484Sobrien	      /* Assumes two's complement.  */
166960484Sobrien	      if (   signed_check > reloc_signed_max
167060484Sobrien		  || signed_check < reloc_signed_min)
1671130561Sobrien		overflow = TRUE;
167277298Sobrien
1673104834Sobrien	      /* Put the relocation into the correct bits.
1674104834Sobrien		 For a BLX instruction, make sure that the relocation is rounded up
1675104834Sobrien		 to a word boundary.  This follows the semantics of the instruction
1676104834Sobrien		 which specifies that bit 1 of the target address will come from bit
1677104834Sobrien		 1 of the base address.  */
167860484Sobrien	      if (bfd_big_endian (input_bfd))
1679104834Sobrien	        {
1680104834Sobrien		  if ((x & 0x1800) == 0x0800 && (relocation & 0x02))
1681104834Sobrien		    relocation += 2;
1682104834Sobrien		  relocation = (((relocation & 0xffe) >> 1)  | ((relocation << 4) & 0x07ff0000));
1683104834Sobrien		}
168460484Sobrien	      else
1685104834Sobrien	        {
1686104834Sobrien		  if ((x & 0x18000000) == 0x08000000 && (relocation & 0x02))
1687104834Sobrien		    relocation += 2;
1688104834Sobrien		  relocation = (((relocation & 0xffe) << 15) | ((relocation >> 12) & 0x7ff));
1689104834Sobrien		}
169077298Sobrien
169178828Sobrien	      /* Add the relocation to the correct bits of X.  */
169260484Sobrien	      x = ((x & ~howto->dst_mask) | relocation);
169360484Sobrien
169478828Sobrien	      /* Put the relocated value back in the object file.  */
169560484Sobrien	      bfd_put_32 (input_bfd, x, location);
169660484Sobrien
169760484Sobrien	      rstat = overflow ? bfd_reloc_overflow : bfd_reloc_ok;
169860484Sobrien            }
169960484Sobrien        }
170060484Sobrien#endif
170160484Sobrien      else
1702130561Sobrien        if (info->relocatable && ! howto->partial_inplace)
1703130561Sobrien            rstat = bfd_reloc_ok;
1704130561Sobrien        else
1705130561Sobrien	  rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
1706130561Sobrien					    contents,
1707130561Sobrien					    rel->r_vaddr - input_section->vma,
1708130561Sobrien					    val, addend);
1709218822Sdim      /* Only perform this fix during the final link, not a relocatable link.  */
1710130561Sobrien      if (! info->relocatable
171160484Sobrien	  && (rel->r_type == ARM_32 || rel->r_type == ARM_RVA32))
171260484Sobrien	{
171360484Sobrien	  /* Determine if we need to set the bottom bit of a relocated address
171460484Sobrien	     because the address is the address of a Thumb code symbol.  */
1715130561Sobrien	  int patchit = FALSE;
171677298Sobrien
171760484Sobrien	  if (h != NULL
171860484Sobrien	      && (   h->class == C_THUMBSTATFUNC
171960484Sobrien		  || h->class == C_THUMBEXTFUNC))
172060484Sobrien	    {
1721130561Sobrien	      patchit = TRUE;
172260484Sobrien	    }
172360484Sobrien	  else if (sym != NULL
172460484Sobrien		   && sym->n_scnum > N_UNDEF)
172560484Sobrien	    {
172660484Sobrien	      /* No hash entry - use the symbol instead.  */
172760484Sobrien	      if (   sym->n_sclass == C_THUMBSTATFUNC
172860484Sobrien		  || sym->n_sclass == C_THUMBEXTFUNC)
1729130561Sobrien		patchit = TRUE;
173060484Sobrien	    }
173160484Sobrien
173260484Sobrien	  if (patchit)
173360484Sobrien	    {
173460484Sobrien	      bfd_byte * location = contents + rel->r_vaddr - input_section->vma;
173560484Sobrien	      bfd_vma    x        = bfd_get_32 (input_bfd, location);
173660484Sobrien
173760484Sobrien	      bfd_put_32 (input_bfd, x | 1, location);
173860484Sobrien	    }
173960484Sobrien	}
174077298Sobrien
174160484Sobrien      switch (rstat)
174260484Sobrien	{
174360484Sobrien	default:
174460484Sobrien	  abort ();
174560484Sobrien	case bfd_reloc_ok:
174660484Sobrien	  break;
174760484Sobrien	case bfd_reloc_outofrange:
174860484Sobrien	  (*_bfd_error_handler)
1749218822Sdim	    (_("%B: bad reloc address 0x%lx in section `%A'"),
1750218822Sdim	     input_bfd, input_section, (unsigned long) rel->r_vaddr);
1751130561Sobrien	  return FALSE;
175260484Sobrien	case bfd_reloc_overflow:
175360484Sobrien	  {
175460484Sobrien	    const char *name;
175560484Sobrien	    char buf[SYMNMLEN + 1];
175660484Sobrien
175760484Sobrien	    if (symndx == -1)
175860484Sobrien	      name = "*ABS*";
175960484Sobrien	    else if (h != NULL)
1760218822Sdim	      name = NULL;
176160484Sobrien	    else
176260484Sobrien	      {
176360484Sobrien		name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
176460484Sobrien		if (name == NULL)
1765130561Sobrien		  return FALSE;
176660484Sobrien	      }
176760484Sobrien
176860484Sobrien	    if (! ((*info->callbacks->reloc_overflow)
1769218822Sdim		   (info, (h ? &h->root : NULL), name, howto->name,
1770218822Sdim		    (bfd_vma) 0, input_bfd, input_section,
1771218822Sdim		    rel->r_vaddr - input_section->vma)))
1772130561Sobrien	      return FALSE;
177360484Sobrien	  }
177460484Sobrien	}
177560484Sobrien    }
177660484Sobrien
1777130561Sobrien  return TRUE;
177860484Sobrien}
177960484Sobrien
178060484Sobrien#ifndef COFF_IMAGE_WITH_PE
178160484Sobrien
1782130561Sobrienbfd_boolean
1783218822Sdimbfd_arm_allocate_interworking_sections (struct bfd_link_info * info)
178460484Sobrien{
178560484Sobrien  asection *                        s;
178660484Sobrien  bfd_byte *                        foo;
178760484Sobrien  struct coff_arm_link_hash_table * globals;
178860484Sobrien
178960484Sobrien  globals = coff_arm_hash_table (info);
179077298Sobrien
179160484Sobrien  BFD_ASSERT (globals != NULL);
179260484Sobrien
179360484Sobrien  if (globals->arm_glue_size != 0)
179460484Sobrien    {
179560484Sobrien      BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
179677298Sobrien
179760484Sobrien      s = bfd_get_section_by_name
179860484Sobrien	(globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME);
179960484Sobrien
180060484Sobrien      BFD_ASSERT (s != NULL);
180177298Sobrien
1802218822Sdim      foo = bfd_alloc (globals->bfd_of_glue_owner, globals->arm_glue_size);
180377298Sobrien
1804218822Sdim      s->size = globals->arm_glue_size;
180560484Sobrien      s->contents = foo;
180660484Sobrien    }
180760484Sobrien
180860484Sobrien  if (globals->thumb_glue_size != 0)
180960484Sobrien    {
181060484Sobrien      BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
181177298Sobrien
181260484Sobrien      s = bfd_get_section_by_name
181360484Sobrien	(globals->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME);
181460484Sobrien
181560484Sobrien      BFD_ASSERT (s != NULL);
181677298Sobrien
1817218822Sdim      foo = bfd_alloc (globals->bfd_of_glue_owner, globals->thumb_glue_size);
181877298Sobrien
1819218822Sdim      s->size = globals->thumb_glue_size;
182060484Sobrien      s->contents = foo;
182160484Sobrien    }
182260484Sobrien
1823130561Sobrien  return TRUE;
182460484Sobrien}
182560484Sobrien
182660484Sobrienstatic void
1827218822Sdimrecord_arm_to_thumb_glue (struct bfd_link_info *        info,
1828218822Sdim			  struct coff_link_hash_entry * h)
182960484Sobrien{
183060484Sobrien  const char *                      name = h->root.root.string;
183160484Sobrien  register asection *               s;
183260484Sobrien  char *                            tmp_name;
183360484Sobrien  struct coff_link_hash_entry *     myh;
1834107492Sobrien  struct bfd_link_hash_entry *      bh;
183560484Sobrien  struct coff_arm_link_hash_table * globals;
183689857Sobrien  bfd_vma val;
183789857Sobrien  bfd_size_type amt;
183860484Sobrien
183960484Sobrien  globals = coff_arm_hash_table (info);
184060484Sobrien
184160484Sobrien  BFD_ASSERT (globals != NULL);
184260484Sobrien  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
184360484Sobrien
184460484Sobrien  s = bfd_get_section_by_name
184560484Sobrien    (globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME);
184660484Sobrien
184760484Sobrien  BFD_ASSERT (s != NULL);
184860484Sobrien
184989857Sobrien  amt = strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1;
1850218822Sdim  tmp_name = bfd_malloc (amt);
185160484Sobrien
185260484Sobrien  BFD_ASSERT (tmp_name);
185360484Sobrien
185460484Sobrien  sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name);
185577298Sobrien
185660484Sobrien  myh = coff_link_hash_lookup
1857130561Sobrien    (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE);
185877298Sobrien
185960484Sobrien  if (myh != NULL)
186060484Sobrien    {
186160484Sobrien      free (tmp_name);
1862218822Sdim      /* We've already seen this guy.  */
1863218822Sdim      return;
186460484Sobrien    }
186560484Sobrien
186660484Sobrien  /* The only trick here is using globals->arm_glue_size as the value. Even
186760484Sobrien     though the section isn't allocated yet, this is where we will be putting
186860484Sobrien     it.  */
1869107492Sobrien  bh = NULL;
187089857Sobrien  val = globals->arm_glue_size + 1;
187160484Sobrien  bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name,
1872130561Sobrien				BSF_GLOBAL, s, val, NULL, TRUE, FALSE, &bh);
187377298Sobrien
187460484Sobrien  free (tmp_name);
187577298Sobrien
187660484Sobrien  globals->arm_glue_size += ARM2THUMB_GLUE_SIZE;
187760484Sobrien
187860484Sobrien  return;
187960484Sobrien}
188060484Sobrien
188199461Sobrien#ifndef ARM_WINCE
188260484Sobrienstatic void
1883218822Sdimrecord_thumb_to_arm_glue (struct bfd_link_info *        info,
1884218822Sdim			  struct coff_link_hash_entry * h)
188560484Sobrien{
188660484Sobrien  const char *                       name = h->root.root.string;
1887218822Sdim  asection *                         s;
188860484Sobrien  char *                             tmp_name;
188960484Sobrien  struct coff_link_hash_entry *      myh;
1890107492Sobrien  struct bfd_link_hash_entry *       bh;
189160484Sobrien  struct coff_arm_link_hash_table *  globals;
189289857Sobrien  bfd_vma val;
189389857Sobrien  bfd_size_type amt;
189460484Sobrien
189560484Sobrien  globals = coff_arm_hash_table (info);
189677298Sobrien
189760484Sobrien  BFD_ASSERT (globals != NULL);
189860484Sobrien  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
189960484Sobrien
190060484Sobrien  s = bfd_get_section_by_name
190160484Sobrien    (globals->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME);
190260484Sobrien
190360484Sobrien  BFD_ASSERT (s != NULL);
190460484Sobrien
190589857Sobrien  amt = strlen (name) + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1;
1906218822Sdim  tmp_name = bfd_malloc (amt);
190760484Sobrien
190860484Sobrien  BFD_ASSERT (tmp_name);
190960484Sobrien
191060484Sobrien  sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name);
191160484Sobrien
191260484Sobrien  myh = coff_link_hash_lookup
1913130561Sobrien    (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE);
191477298Sobrien
191560484Sobrien  if (myh != NULL)
191660484Sobrien    {
191760484Sobrien      free (tmp_name);
1918218822Sdim      /* We've already seen this guy.  */
1919218822Sdim      return;
192060484Sobrien    }
192160484Sobrien
1922107492Sobrien  bh = NULL;
192389857Sobrien  val = globals->thumb_glue_size + 1;
192460484Sobrien  bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name,
1925130561Sobrien				BSF_GLOBAL, s, val, NULL, TRUE, FALSE, &bh);
192677298Sobrien
192760484Sobrien  /* If we mark it 'thumb', the disassembler will do a better job.  */
1928107492Sobrien  myh = (struct coff_link_hash_entry *) bh;
192960484Sobrien  myh->class = C_THUMBEXTFUNC;
193060484Sobrien
193160484Sobrien  free (tmp_name);
193260484Sobrien
193360484Sobrien  /* Allocate another symbol to mark where we switch to arm mode.  */
193477298Sobrien
193560484Sobrien#define CHANGE_TO_ARM "__%s_change_to_arm"
193660484Sobrien#define BACK_FROM_ARM "__%s_back_from_arm"
193777298Sobrien
193889857Sobrien  amt = strlen (name) + strlen (CHANGE_TO_ARM) + 1;
1939218822Sdim  tmp_name = bfd_malloc (amt);
194077298Sobrien
194160484Sobrien  BFD_ASSERT (tmp_name);
194277298Sobrien
194360484Sobrien  sprintf (tmp_name, globals->support_old_code ? BACK_FROM_ARM : CHANGE_TO_ARM, name);
194460484Sobrien
1945107492Sobrien  bh = NULL;
194689857Sobrien  val = globals->thumb_glue_size + (globals->support_old_code ? 8 : 4);
194760484Sobrien  bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name,
1948130561Sobrien				BSF_LOCAL, s, val, NULL, TRUE, FALSE, &bh);
194960484Sobrien
195077298Sobrien  free (tmp_name);
195177298Sobrien
195260484Sobrien  globals->thumb_glue_size += THUMB2ARM_GLUE_SIZE;
195360484Sobrien
195460484Sobrien  return;
195560484Sobrien}
195699461Sobrien#endif /* not ARM_WINCE */
195760484Sobrien
195860484Sobrien/* Select a BFD to be used to hold the sections used by the glue code.
195960484Sobrien   This function is called from the linker scripts in ld/emultempl/
196060484Sobrien   {armcoff/pe}.em  */
196160484Sobrien
1962130561Sobrienbfd_boolean
1963218822Sdimbfd_arm_get_bfd_for_interworking (bfd * 		 abfd,
1964218822Sdim				  struct bfd_link_info * info)
196560484Sobrien{
196660484Sobrien  struct coff_arm_link_hash_table * globals;
196760484Sobrien  flagword   			    flags;
196860484Sobrien  asection * 			    sec;
196977298Sobrien
197060484Sobrien  /* If we are only performing a partial link do not bother
197160484Sobrien     getting a bfd to hold the glue.  */
1972130561Sobrien  if (info->relocatable)
1973130561Sobrien    return TRUE;
197477298Sobrien
197560484Sobrien  globals = coff_arm_hash_table (info);
197677298Sobrien
197760484Sobrien  BFD_ASSERT (globals != NULL);
197860484Sobrien
197960484Sobrien  if (globals->bfd_of_glue_owner != NULL)
1980130561Sobrien    return TRUE;
198177298Sobrien
198260484Sobrien  sec = bfd_get_section_by_name (abfd, ARM2THUMB_GLUE_SECTION_NAME);
198377298Sobrien
198477298Sobrien  if (sec == NULL)
198560484Sobrien    {
1986218822Sdim      flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
1987218822Sdim	       | SEC_CODE | SEC_READONLY);
1988218822Sdim      sec = bfd_make_section_with_flags (abfd, ARM2THUMB_GLUE_SECTION_NAME,
1989218822Sdim					 flags);
199060484Sobrien      if (sec == NULL
199160484Sobrien	  || ! bfd_set_section_alignment (abfd, sec, 2))
1992130561Sobrien	return FALSE;
199360484Sobrien    }
199460484Sobrien
199560484Sobrien  sec = bfd_get_section_by_name (abfd, THUMB2ARM_GLUE_SECTION_NAME);
199660484Sobrien
199777298Sobrien  if (sec == NULL)
199860484Sobrien    {
1999218822Sdim      flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
2000218822Sdim	       | SEC_CODE | SEC_READONLY);
2001218822Sdim      sec = bfd_make_section_with_flags (abfd, THUMB2ARM_GLUE_SECTION_NAME,
2002218822Sdim					 flags);
200377298Sobrien
200460484Sobrien      if (sec == NULL
200560484Sobrien	  || ! bfd_set_section_alignment (abfd, sec, 2))
2006130561Sobrien	return FALSE;
200760484Sobrien    }
200877298Sobrien
200960484Sobrien  /* Save the bfd for later use.  */
201060484Sobrien  globals->bfd_of_glue_owner = abfd;
201177298Sobrien
2012130561Sobrien  return TRUE;
201360484Sobrien}
201460484Sobrien
2015130561Sobrienbfd_boolean
2016218822Sdimbfd_arm_process_before_allocation (bfd *                   abfd,
2017218822Sdim				   struct bfd_link_info *  info,
2018218822Sdim				   int		           support_old_code)
201960484Sobrien{
202060484Sobrien  asection * sec;
202160484Sobrien  struct coff_arm_link_hash_table * globals;
202260484Sobrien
202360484Sobrien  /* If we are only performing a partial link do not bother
202460484Sobrien     to construct any glue.  */
2025130561Sobrien  if (info->relocatable)
2026130561Sobrien    return TRUE;
202777298Sobrien
202860484Sobrien  /* Here we have a bfd that is to be included on the link.  We have a hook
202960484Sobrien     to do reloc rummaging, before section sizes are nailed down.  */
203060484Sobrien  _bfd_coff_get_external_symbols (abfd);
203160484Sobrien
203260484Sobrien  globals = coff_arm_hash_table (info);
203377298Sobrien
203460484Sobrien  BFD_ASSERT (globals != NULL);
203560484Sobrien  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
203660484Sobrien
203760484Sobrien  globals->support_old_code = support_old_code;
203877298Sobrien
203960484Sobrien  /* Rummage around all the relocs and map the glue vectors.  */
204060484Sobrien  sec = abfd->sections;
204160484Sobrien
204260484Sobrien  if (sec == NULL)
2043130561Sobrien    return TRUE;
204460484Sobrien
204560484Sobrien  for (; sec != NULL; sec = sec->next)
204660484Sobrien    {
204760484Sobrien      struct internal_reloc * i;
204860484Sobrien      struct internal_reloc * rel;
204960484Sobrien
205077298Sobrien      if (sec->reloc_count == 0)
205160484Sobrien	continue;
205260484Sobrien
205360484Sobrien      /* Load the relocs.  */
205477298Sobrien      /* FIXME: there may be a storage leak here.  */
205560484Sobrien      i = _bfd_coff_read_internal_relocs (abfd, sec, 1, 0, 0, 0);
205677298Sobrien
205760484Sobrien      BFD_ASSERT (i != 0);
205860484Sobrien
205977298Sobrien      for (rel = i; rel < i + sec->reloc_count; ++rel)
206060484Sobrien	{
206160484Sobrien	  unsigned short                 r_type  = rel->r_type;
206260484Sobrien	  long                           symndx;
206360484Sobrien	  struct coff_link_hash_entry *  h;
206460484Sobrien
206560484Sobrien	  symndx = rel->r_symndx;
206660484Sobrien
206777298Sobrien	  /* If the relocation is not against a symbol it cannot concern us.  */
206860484Sobrien	  if (symndx == -1)
206960484Sobrien	    continue;
207060484Sobrien
207160484Sobrien	  /* If the index is outside of the range of our table, something has gone wrong.  */
207260484Sobrien	  if (symndx >= obj_conv_table_size (abfd))
207360484Sobrien	    {
2074218822Sdim	      _bfd_error_handler (_("%B: illegal symbol index in reloc: %d"),
2075218822Sdim				  abfd, symndx);
207660484Sobrien	      continue;
207760484Sobrien	    }
207877298Sobrien
207960484Sobrien	  h = obj_coff_sym_hashes (abfd)[symndx];
208060484Sobrien
208160484Sobrien	  /* If the relocation is against a static symbol it must be within
208260484Sobrien	     the current section and so cannot be a cross ARM/Thumb relocation.  */
208360484Sobrien	  if (h == NULL)
208460484Sobrien	    continue;
208560484Sobrien
208660484Sobrien	  switch (r_type)
208760484Sobrien	    {
208860484Sobrien	    case ARM_26:
208960484Sobrien	      /* This one is a call from arm code.  We need to look up
209060484Sobrien		 the target of the call. If it is a thumb target, we
209160484Sobrien		 insert glue.  */
209277298Sobrien
209360484Sobrien	      if (h->class == C_THUMBEXTFUNC)
209460484Sobrien		record_arm_to_thumb_glue (info, h);
209560484Sobrien	      break;
209677298Sobrien
209760484Sobrien#ifndef ARM_WINCE
209860484Sobrien	    case ARM_THUMB23:
209960484Sobrien	      /* This one is a call from thumb code.  We used to look
210060484Sobrien		 for ARM_THUMB9 and ARM_THUMB12 as well.  We need to look
210160484Sobrien		 up the target of the call. If it is an arm target, we
210260484Sobrien		 insert glue.  If the symbol does not exist it will be
210360484Sobrien		 given a class of C_EXT and so we will generate a stub
210460484Sobrien		 for it.  This is not really a problem, since the link
210560484Sobrien		 is doomed anyway.  */
210660484Sobrien
210760484Sobrien	      switch (h->class)
210860484Sobrien		{
210960484Sobrien		case C_EXT:
211060484Sobrien		case C_STAT:
211160484Sobrien		case C_LABEL:
211260484Sobrien		  record_thumb_to_arm_glue (info, h);
211360484Sobrien		  break;
211460484Sobrien		default:
211560484Sobrien		  ;
211660484Sobrien		}
211760484Sobrien	      break;
211860484Sobrien#endif
211977298Sobrien
212060484Sobrien	    default:
212160484Sobrien	      break;
212260484Sobrien	    }
212360484Sobrien	}
212460484Sobrien    }
212560484Sobrien
2126130561Sobrien  return TRUE;
212760484Sobrien}
212860484Sobrien
212960484Sobrien#endif /* ! defined (COFF_IMAGE_WITH_PE) */
213060484Sobrien
213160484Sobrien#define coff_bfd_reloc_type_lookup 		coff_arm_reloc_type_lookup
2132218822Sdim#define coff_bfd_reloc_name_lookup	coff_arm_reloc_name_lookup
213360484Sobrien#define coff_relocate_section 			coff_arm_relocate_section
213460484Sobrien#define coff_bfd_is_local_label_name 		coff_arm_is_local_label_name
213560484Sobrien#define coff_adjust_symndx			coff_arm_adjust_symndx
213660484Sobrien#define coff_link_output_has_begun 		coff_arm_link_output_has_begun
213760484Sobrien#define coff_final_link_postscript		coff_arm_final_link_postscript
213860484Sobrien#define coff_bfd_merge_private_bfd_data		coff_arm_merge_private_bfd_data
213960484Sobrien#define coff_bfd_print_private_bfd_data		coff_arm_print_private_bfd_data
214060484Sobrien#define coff_bfd_set_private_flags              _bfd_coff_arm_set_private_flags
214160484Sobrien#define coff_bfd_copy_private_bfd_data          coff_arm_copy_private_bfd_data
214260484Sobrien#define coff_bfd_link_hash_table_create		coff_arm_link_hash_table_create
214360484Sobrien
2144130561Sobrien/* When doing a relocatable link, we want to convert ARM_26 relocs
2145130561Sobrien   into ARM_26D relocs.  */
214660484Sobrien
2147130561Sobrienstatic bfd_boolean
2148218822Sdimcoff_arm_adjust_symndx (bfd *obfd ATTRIBUTE_UNUSED,
2149218822Sdim			struct bfd_link_info *info ATTRIBUTE_UNUSED,
2150218822Sdim			bfd *ibfd,
2151218822Sdim			asection *sec,
2152218822Sdim			struct internal_reloc *irel,
2153218822Sdim			bfd_boolean *adjustedp)
215460484Sobrien{
2155130561Sobrien  if (irel->r_type == ARM_26)
215660484Sobrien    {
215760484Sobrien      struct coff_link_hash_entry *h;
215860484Sobrien
215960484Sobrien      h = obj_coff_sym_hashes (ibfd)[irel->r_symndx];
216060484Sobrien      if (h != NULL
216160484Sobrien	  && (h->root.type == bfd_link_hash_defined
216260484Sobrien	      || h->root.type == bfd_link_hash_defweak)
216360484Sobrien	  && h->root.u.def.section->output_section == sec->output_section)
2164130561Sobrien	irel->r_type = ARM_26D;
216560484Sobrien    }
2166130561Sobrien  *adjustedp = FALSE;
2167130561Sobrien  return TRUE;
216860484Sobrien}
216960484Sobrien
217060484Sobrien/* Called when merging the private data areas of two BFDs.
217160484Sobrien   This is important as it allows us to detect if we are
217260484Sobrien   attempting to merge binaries compiled for different ARM
2173130561Sobrien   targets, eg different CPUs or different APCS's.     */
217460484Sobrien
2175130561Sobrienstatic bfd_boolean
2176218822Sdimcoff_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd)
217760484Sobrien{
217860484Sobrien  BFD_ASSERT (ibfd != NULL && obfd != NULL);
217960484Sobrien
218060484Sobrien  if (ibfd == obfd)
2181130561Sobrien    return TRUE;
218260484Sobrien
218360484Sobrien  /* If the two formats are different we cannot merge anything.
218460484Sobrien     This is not an error, since it is permissable to change the
218560484Sobrien     input and output formats.  */
218660484Sobrien  if (   ibfd->xvec->flavour != bfd_target_coff_flavour
218760484Sobrien      || obfd->xvec->flavour != bfd_target_coff_flavour)
2188130561Sobrien    return TRUE;
218960484Sobrien
2190130561Sobrien  /* Determine what should happen if the input ARM architecture
2191130561Sobrien     does not match the output ARM architecture.  */
2192130561Sobrien  if (! bfd_arm_merge_machines (ibfd, obfd))
2193130561Sobrien    return FALSE;
2194130561Sobrien
2195130561Sobrien  /* Verify that the APCS is the same for the two BFDs.  */
219660484Sobrien  if (APCS_SET (ibfd))
219760484Sobrien    {
219860484Sobrien      if (APCS_SET (obfd))
219960484Sobrien	{
220060484Sobrien	  /* If the src and dest have different APCS flag bits set, fail.  */
220160484Sobrien	  if (APCS_26_FLAG (obfd) != APCS_26_FLAG (ibfd))
220260484Sobrien	    {
220360484Sobrien	      _bfd_error_handler
220460484Sobrien		/* xgettext: c-format */
2205218822Sdim		(_("ERROR: %B is compiled for APCS-%d, whereas %B is compiled for APCS-%d"),
2206218822Sdim		 ibfd, obfd,
2207218822Sdim		 APCS_26_FLAG (ibfd) ? 26 : 32,
2208218822Sdim		 APCS_26_FLAG (obfd) ? 26 : 32
220960484Sobrien		 );
221060484Sobrien
221160484Sobrien	      bfd_set_error (bfd_error_wrong_format);
2212130561Sobrien	      return FALSE;
221360484Sobrien	    }
221477298Sobrien
221560484Sobrien	  if (APCS_FLOAT_FLAG (obfd) != APCS_FLOAT_FLAG (ibfd))
221660484Sobrien	    {
221760484Sobrien	      const char *msg;
221860484Sobrien
221960484Sobrien	      if (APCS_FLOAT_FLAG (ibfd))
222060484Sobrien		/* xgettext: c-format */
2221218822Sdim		msg = _("ERROR: %B passes floats in float registers, whereas %B passes them in integer registers");
222260484Sobrien	      else
222360484Sobrien		/* xgettext: c-format */
2224218822Sdim		msg = _("ERROR: %B passes floats in integer registers, whereas %B passes them in float registers");
222577298Sobrien
2226218822Sdim	      _bfd_error_handler (msg, ibfd, obfd);
222760484Sobrien
222860484Sobrien	      bfd_set_error (bfd_error_wrong_format);
2229130561Sobrien	      return FALSE;
223060484Sobrien	    }
223177298Sobrien
223260484Sobrien	  if (PIC_FLAG (obfd) != PIC_FLAG (ibfd))
223360484Sobrien	    {
223460484Sobrien	      const char * msg;
223560484Sobrien
223660484Sobrien	      if (PIC_FLAG (ibfd))
223760484Sobrien		/* xgettext: c-format */
2238218822Sdim		msg = _("ERROR: %B is compiled as position independent code, whereas target %B is absolute position");
223960484Sobrien	      else
224060484Sobrien		/* xgettext: c-format */
2241218822Sdim		msg = _("ERROR: %B is compiled as absolute position code, whereas target %B is position independent");
2242218822Sdim	      _bfd_error_handler (msg, ibfd, obfd);
224360484Sobrien
224460484Sobrien	      bfd_set_error (bfd_error_wrong_format);
2245130561Sobrien	      return FALSE;
224660484Sobrien	    }
224760484Sobrien	}
224860484Sobrien      else
224960484Sobrien	{
225060484Sobrien	  SET_APCS_FLAGS (obfd, APCS_26_FLAG (ibfd) | APCS_FLOAT_FLAG (ibfd) | PIC_FLAG (ibfd));
225177298Sobrien
225260484Sobrien	  /* Set up the arch and fields as well as these are probably wrong.  */
225360484Sobrien	  bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd));
225460484Sobrien	}
225560484Sobrien    }
225660484Sobrien
225760484Sobrien  /* Check the interworking support.  */
225860484Sobrien  if (INTERWORK_SET (ibfd))
225960484Sobrien    {
226060484Sobrien      if (INTERWORK_SET (obfd))
226160484Sobrien	{
226260484Sobrien	  /* If the src and dest differ in their interworking issue a warning.  */
226360484Sobrien	  if (INTERWORK_FLAG (obfd) != INTERWORK_FLAG (ibfd))
226460484Sobrien	    {
226560484Sobrien	      const char * msg;
226660484Sobrien
226760484Sobrien	      if (INTERWORK_FLAG (ibfd))
226860484Sobrien		/* xgettext: c-format */
2269218822Sdim		msg = _("Warning: %B supports interworking, whereas %B does not");
227060484Sobrien	      else
227160484Sobrien		/* xgettext: c-format */
2272218822Sdim		msg = _("Warning: %B does not support interworking, whereas %B does");
227377298Sobrien
2274218822Sdim	      _bfd_error_handler (msg, ibfd, obfd);
227560484Sobrien	    }
227660484Sobrien	}
227760484Sobrien      else
227860484Sobrien	{
227960484Sobrien	  SET_INTERWORK_FLAG (obfd, INTERWORK_FLAG (ibfd));
228060484Sobrien	}
228160484Sobrien    }
228260484Sobrien
2283130561Sobrien  return TRUE;
228460484Sobrien}
228560484Sobrien
228660484Sobrien/* Display the flags field.  */
228760484Sobrien
2288130561Sobrienstatic bfd_boolean
2289218822Sdimcoff_arm_print_private_bfd_data (bfd * abfd, void * ptr)
229060484Sobrien{
229160484Sobrien  FILE * file = (FILE *) ptr;
229277298Sobrien
229360484Sobrien  BFD_ASSERT (abfd != NULL && ptr != NULL);
229477298Sobrien
229560484Sobrien  /* xgettext:c-format */
229660484Sobrien  fprintf (file, _("private flags = %x:"), coff_data (abfd)->flags);
229777298Sobrien
229860484Sobrien  if (APCS_SET (abfd))
229960484Sobrien    {
2300130561Sobrien      /* xgettext: APCS is ARM Procedure Call Standard, it should not be translated.  */
230160484Sobrien      fprintf (file, " [APCS-%d]", APCS_26_FLAG (abfd) ? 26 : 32);
230260484Sobrien
230360484Sobrien      if (APCS_FLOAT_FLAG (abfd))
230460484Sobrien	fprintf (file, _(" [floats passed in float registers]"));
230560484Sobrien      else
230660484Sobrien	fprintf (file, _(" [floats passed in integer registers]"));
230760484Sobrien
230860484Sobrien      if (PIC_FLAG (abfd))
230960484Sobrien	fprintf (file, _(" [position independent]"));
231060484Sobrien      else
231160484Sobrien	fprintf (file, _(" [absolute position]"));
231260484Sobrien    }
231377298Sobrien
231460484Sobrien  if (! INTERWORK_SET (abfd))
231560484Sobrien    fprintf (file, _(" [interworking flag not initialised]"));
231660484Sobrien  else if (INTERWORK_FLAG (abfd))
231760484Sobrien    fprintf (file, _(" [interworking supported]"));
231860484Sobrien  else
231960484Sobrien    fprintf (file, _(" [interworking not supported]"));
232077298Sobrien
232160484Sobrien  fputc ('\n', file);
232277298Sobrien
2323130561Sobrien  return TRUE;
232460484Sobrien}
232560484Sobrien
232660484Sobrien/* Copies the given flags into the coff_tdata.flags field.
232760484Sobrien   Typically these flags come from the f_flags[] field of
232860484Sobrien   the COFF filehdr structure, which contains important,
232960484Sobrien   target specific information.
233060484Sobrien   Note: Although this function is static, it is explicitly
233160484Sobrien   called from both coffcode.h and peicode.h.  */
233260484Sobrien
2333130561Sobrienstatic bfd_boolean
2334218822Sdim_bfd_coff_arm_set_private_flags (bfd * abfd, flagword flags)
233560484Sobrien{
233660484Sobrien  flagword flag;
233760484Sobrien
233860484Sobrien  BFD_ASSERT (abfd != NULL);
233960484Sobrien
234060484Sobrien  flag = (flags & F_APCS26) ? F_APCS_26 : 0;
234177298Sobrien
234260484Sobrien  /* Make sure that the APCS field has not been initialised to the opposite
234360484Sobrien     value.  */
234460484Sobrien  if (APCS_SET (abfd)
234560484Sobrien      && (   (APCS_26_FLAG    (abfd) != flag)
234660484Sobrien	  || (APCS_FLOAT_FLAG (abfd) != (flags & F_APCS_FLOAT))
234760484Sobrien	  || (PIC_FLAG        (abfd) != (flags & F_PIC))
234860484Sobrien	  ))
2349130561Sobrien    return FALSE;
235060484Sobrien
235160484Sobrien  flag |= (flags & (F_APCS_FLOAT | F_PIC));
235277298Sobrien
235360484Sobrien  SET_APCS_FLAGS (abfd, flag);
235460484Sobrien
235560484Sobrien  flag = (flags & F_INTERWORK);
235677298Sobrien
235760484Sobrien  /* If the BFD has already had its interworking flag set, but it
235860484Sobrien     is different from the value that we have been asked to set,
235960484Sobrien     then assume that that merged code will not support interworking
236060484Sobrien     and set the flag accordingly.  */
236160484Sobrien  if (INTERWORK_SET (abfd) && (INTERWORK_FLAG (abfd) != flag))
236260484Sobrien    {
236360484Sobrien      if (flag)
236460484Sobrien	/* xgettext: c-format */
2365218822Sdim	_bfd_error_handler (_("Warning: Not setting interworking flag of %B since it has already been specified as non-interworking"),
2366218822Sdim			    abfd);
236760484Sobrien      else
236860484Sobrien	/* xgettext: c-format */
2369218822Sdim	_bfd_error_handler (_("Warning: Clearing the interworking flag of %B due to outside request"),
2370218822Sdim			    abfd);
237160484Sobrien      flag = 0;
237260484Sobrien    }
237360484Sobrien
237460484Sobrien  SET_INTERWORK_FLAG (abfd, flag);
237560484Sobrien
2376130561Sobrien  return TRUE;
237760484Sobrien}
237860484Sobrien
237960484Sobrien/* Copy the important parts of the target specific data
238060484Sobrien   from one instance of a BFD to another.  */
238160484Sobrien
2382130561Sobrienstatic bfd_boolean
2383218822Sdimcoff_arm_copy_private_bfd_data (bfd * src, bfd * dest)
238460484Sobrien{
238560484Sobrien  BFD_ASSERT (src != NULL && dest != NULL);
238677298Sobrien
238760484Sobrien  if (src == dest)
2388130561Sobrien    return TRUE;
238960484Sobrien
239060484Sobrien  /* If the destination is not in the same format as the source, do not do
239160484Sobrien     the copy.  */
239260484Sobrien  if (src->xvec != dest->xvec)
2393130561Sobrien    return TRUE;
239460484Sobrien
2395218822Sdim  /* Copy the flags field.  */
239660484Sobrien  if (APCS_SET (src))
239760484Sobrien    {
239860484Sobrien      if (APCS_SET (dest))
239960484Sobrien	{
240060484Sobrien	  /* If the src and dest have different APCS flag bits set, fail.  */
240160484Sobrien	  if (APCS_26_FLAG (dest) != APCS_26_FLAG (src))
2402130561Sobrien	    return FALSE;
240377298Sobrien
240460484Sobrien	  if (APCS_FLOAT_FLAG (dest) != APCS_FLOAT_FLAG (src))
2405130561Sobrien	    return FALSE;
240677298Sobrien
240760484Sobrien	  if (PIC_FLAG (dest) != PIC_FLAG (src))
2408130561Sobrien	    return FALSE;
240960484Sobrien	}
241060484Sobrien      else
241160484Sobrien	SET_APCS_FLAGS (dest, APCS_26_FLAG (src) | APCS_FLOAT_FLAG (src)
241260484Sobrien			| PIC_FLAG (src));
241360484Sobrien    }
241460484Sobrien
241560484Sobrien  if (INTERWORK_SET (src))
241660484Sobrien    {
241760484Sobrien      if (INTERWORK_SET (dest))
241860484Sobrien	{
241960484Sobrien	  /* If the src and dest have different interworking flags then turn
242060484Sobrien	     off the interworking bit.  */
242160484Sobrien	  if (INTERWORK_FLAG (dest) != INTERWORK_FLAG (src))
242260484Sobrien	    {
242360484Sobrien	      if (INTERWORK_FLAG (dest))
242460484Sobrien		{
242560484Sobrien		  /* xgettext:c-format */
242691041Sobrien		  _bfd_error_handler (("\
2427218822SdimWarning: Clearing the interworking flag of %B because non-interworking code in %B has been linked with it"),
2428218822Sdim				      dest, src);
242960484Sobrien		}
243077298Sobrien
243160484Sobrien	      SET_INTERWORK_FLAG (dest, 0);
243260484Sobrien	    }
243360484Sobrien	}
243460484Sobrien      else
243560484Sobrien	{
243660484Sobrien	  SET_INTERWORK_FLAG (dest, INTERWORK_FLAG (src));
243760484Sobrien	}
243860484Sobrien    }
243960484Sobrien
2440130561Sobrien  return TRUE;
244160484Sobrien}
244260484Sobrien
244360484Sobrien/* Note:  the definitions here of LOCAL_LABEL_PREFIX and USER_LABEL_PREIFX
244477298Sobrien   *must* match the definitions in gcc/config/arm/{coff|semi|aout}.h.  */
2445218822Sdim#ifndef LOCAL_LABEL_PREFIX
244677298Sobrien#define LOCAL_LABEL_PREFIX ""
2447218822Sdim#endif
244860484Sobrien#ifndef USER_LABEL_PREFIX
244960484Sobrien#define USER_LABEL_PREFIX "_"
245060484Sobrien#endif
245160484Sobrien
245260484Sobrien/* Like _bfd_coff_is_local_label_name, but
245360484Sobrien   a) test against USER_LABEL_PREFIX, to avoid stripping labels known to be
245460484Sobrien      non-local.
245560484Sobrien   b) Allow other prefixes than ".", e.g. an empty prefix would cause all
245660484Sobrien      labels of the form Lxxx to be stripped.  */
2457218822Sdim
2458130561Sobrienstatic bfd_boolean
2459218822Sdimcoff_arm_is_local_label_name (bfd *        abfd ATTRIBUTE_UNUSED,
2460218822Sdim			      const char * name)
246160484Sobrien{
246260484Sobrien#ifdef USER_LABEL_PREFIX
246360484Sobrien  if (USER_LABEL_PREFIX[0] != 0)
246460484Sobrien    {
2465218822Sdim      size_t len = strlen (USER_LABEL_PREFIX);
2466218822Sdim
2467218822Sdim      if (strncmp (name, USER_LABEL_PREFIX, len) == 0)
2468130561Sobrien	return FALSE;
246960484Sobrien    }
247060484Sobrien#endif
247160484Sobrien
247260484Sobrien#ifdef LOCAL_LABEL_PREFIX
247360484Sobrien  /* If there is a prefix for local labels then look for this.
247477298Sobrien     If the prefix exists, but it is empty, then ignore the test.  */
247577298Sobrien
247660484Sobrien  if (LOCAL_LABEL_PREFIX[0] != 0)
247760484Sobrien    {
247889857Sobrien      size_t len = strlen (LOCAL_LABEL_PREFIX);
247977298Sobrien
248060484Sobrien      if (strncmp (name, LOCAL_LABEL_PREFIX, len) != 0)
2481130561Sobrien	return FALSE;
248277298Sobrien
248360484Sobrien      /* Perform the checks below for the rest of the name.  */
248460484Sobrien      name += len;
248560484Sobrien    }
248660484Sobrien#endif
248777298Sobrien
248860484Sobrien  return name[0] == 'L';
248960484Sobrien}
249060484Sobrien
249160484Sobrien/* This piece of machinery exists only to guarantee that the bfd that holds
249277298Sobrien   the glue section is written last.
249360484Sobrien
249460484Sobrien   This does depend on bfd_make_section attaching a new section to the
2495218822Sdim   end of the section list for the bfd.  */
249660484Sobrien
2497130561Sobrienstatic bfd_boolean
2498218822Sdimcoff_arm_link_output_has_begun (bfd * sub, struct coff_final_link_info * info)
249960484Sobrien{
250060484Sobrien  return (sub->output_has_begun
250160484Sobrien	  || sub == coff_arm_hash_table (info->info)->bfd_of_glue_owner);
250260484Sobrien}
250360484Sobrien
2504130561Sobrienstatic bfd_boolean
2505218822Sdimcoff_arm_final_link_postscript (bfd * abfd ATTRIBUTE_UNUSED,
2506218822Sdim				struct coff_final_link_info * pfinfo)
250760484Sobrien{
250860484Sobrien  struct coff_arm_link_hash_table * globals;
250960484Sobrien
251060484Sobrien  globals = coff_arm_hash_table (pfinfo->info);
251177298Sobrien
251260484Sobrien  BFD_ASSERT (globals != NULL);
251377298Sobrien
251460484Sobrien  if (globals->bfd_of_glue_owner != NULL)
251560484Sobrien    {
251660484Sobrien      if (! _bfd_coff_link_input_bfd (pfinfo, globals->bfd_of_glue_owner))
2517130561Sobrien	return FALSE;
251877298Sobrien
2519130561Sobrien      globals->bfd_of_glue_owner->output_has_begun = TRUE;
252060484Sobrien    }
252177298Sobrien
2522130561Sobrien  return bfd_arm_update_notes (abfd, ARM_NOTE_SECTION);
252360484Sobrien}
252460484Sobrien
252560484Sobrien#include "coffcode.h"
252660484Sobrien
252760484Sobrien#ifndef TARGET_LITTLE_SYM
252860484Sobrien#define TARGET_LITTLE_SYM armcoff_little_vec
252960484Sobrien#endif
253060484Sobrien#ifndef TARGET_LITTLE_NAME
253160484Sobrien#define TARGET_LITTLE_NAME "coff-arm-little"
253260484Sobrien#endif
253360484Sobrien#ifndef TARGET_BIG_SYM
253460484Sobrien#define TARGET_BIG_SYM armcoff_big_vec
253560484Sobrien#endif
253660484Sobrien#ifndef TARGET_BIG_NAME
253760484Sobrien#define TARGET_BIG_NAME "coff-arm-big"
253860484Sobrien#endif
253960484Sobrien
254060484Sobrien#ifndef TARGET_UNDERSCORE
254160484Sobrien#define TARGET_UNDERSCORE 0
254260484Sobrien#endif
254360484Sobrien
254477298Sobrien#ifndef EXTRA_S_FLAGS
254560484Sobrien#ifdef COFF_WITH_PE
2546130561Sobrien#define EXTRA_S_FLAGS (SEC_CODE | SEC_LINK_ONCE | SEC_LINK_DUPLICATES)
254760484Sobrien#else
2548130561Sobrien#define EXTRA_S_FLAGS SEC_CODE
254960484Sobrien#endif
255077298Sobrien#endif
255160484Sobrien
255260484Sobrien/* Forward declaration for use initialising alternative_target field.  */
255360484Sobrienextern const bfd_target TARGET_BIG_SYM ;
255460484Sobrien
255560484Sobrien/* Target vectors.  */
2556130561SobrienCREATE_LITTLE_COFF_TARGET_VEC (TARGET_LITTLE_SYM, TARGET_LITTLE_NAME, D_PAGED, EXTRA_S_FLAGS, TARGET_UNDERSCORE, & TARGET_BIG_SYM, COFF_SWAP_TABLE)
2557130561SobrienCREATE_BIG_COFF_TARGET_VEC (TARGET_BIG_SYM, TARGET_BIG_NAME, D_PAGED, EXTRA_S_FLAGS, TARGET_UNDERSCORE, & TARGET_LITTLE_SYM, COFF_SWAP_TABLE)
2558