138889Sjdp/* ARC-specific support for 32-bit ELF
2218822Sdim   Copyright 1994, 1995, 1997, 1999, 2001, 2002, 2005, 2007
3130561Sobrien   Free Software Foundation, Inc.
438889Sjdp   Contributed by Doug Evans (dje@cygnus.com).
538889Sjdp
685815Sobrien   This file is part of BFD, the Binary File Descriptor library.
738889Sjdp
885815Sobrien   This program is free software; you can redistribute it and/or modify
985815Sobrien   it under the terms of the GNU General Public License as published by
1085815Sobrien   the Free Software Foundation; either version 2 of the License, or
1185815Sobrien   (at your option) any later version.
1238889Sjdp
1385815Sobrien   This program is distributed in the hope that it will be useful,
1485815Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1585815Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1685815Sobrien   GNU General Public License for more details.
1738889Sjdp
1885815Sobrien   You should have received a copy of the GNU General Public License
1985815Sobrien   along with this program; if not, write to the Free Software
20218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21218822Sdim   MA 02110-1301, USA.  */
2238889Sjdp
23218822Sdim#include "sysdep.h"
2438889Sjdp#include "bfd.h"
2538889Sjdp#include "libbfd.h"
2638889Sjdp#include "elf-bfd.h"
2738889Sjdp#include "elf/arc.h"
2889857Sobrien#include "libiberty.h"
2938889Sjdp
3038889Sjdp/* Try to minimize the amount of space occupied by relocation tables
3138889Sjdp   on the ROM (not that the ROM won't be swamped by other ELF overhead).  */
3285815Sobrien
33130561Sobrien#define USE_REL	1
3438889Sjdp
35218822Sdimstatic bfd_reloc_status_type
36218822Sdimarc_elf_b22_pcrel (bfd * abfd,
37218822Sdim		   arelent * reloc_entry,
38218822Sdim		   asymbol * symbol,
39218822Sdim		   void * data,
40218822Sdim		   asection * input_section,
41218822Sdim		   bfd * output_bfd,
42218822Sdim		   char ** error_message)
43218822Sdim{
44218822Sdim  /* If linking, back up the final symbol address by the address of the
45218822Sdim     reloc.  This cannot be accomplished by setting the pcrel_offset
46218822Sdim     field to TRUE, as bfd_install_relocation will detect this and refuse
47218822Sdim     to install the offset in the first place, but bfd_perform_relocation
48218822Sdim     will still insist on removing it.  */
49218822Sdim  if (output_bfd == NULL)
50218822Sdim    reloc_entry->addend -= reloc_entry->address;
51218822Sdim
52218822Sdim  /* Fall through to the default elf reloc handler.  */
53218822Sdim  return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
54218822Sdim				input_section, output_bfd, error_message);
55218822Sdim}
56218822Sdim
5738889Sjdpstatic reloc_howto_type elf_arc_howto_table[] =
5838889Sjdp{
5938889Sjdp  /* This reloc does nothing.  */
60218822Sdim  HOWTO (R_ARC_NONE,		/* Type.  */
61218822Sdim	 0,			/* Rightshift.  */
62218822Sdim	 2,			/* Size (0 = byte, 1 = short, 2 = long).  */
63218822Sdim	 32,			/* Bitsize.  */
64218822Sdim	 FALSE,			/* PC_relative.  */
65218822Sdim	 0,			/* Bitpos.  */
66218822Sdim	 complain_overflow_bitfield, /* Complain_on_overflow.  */
67218822Sdim	 bfd_elf_generic_reloc,	/* Special_function.  */
68218822Sdim	 "R_ARC_NONE",		/* Name.  */
69218822Sdim	 TRUE,			/* Partial_inplace.  */
70218822Sdim	 0,			/* Src_mask.  */
71218822Sdim	 0,			/* Dst_mask.  */
72218822Sdim	 FALSE),		/* PCrel_offset.  */
7338889Sjdp
7438889Sjdp  /* A standard 32 bit relocation.  */
75218822Sdim  HOWTO (R_ARC_32,		/* Type.  */
76218822Sdim	 0,			/* Rightshift.  */
77218822Sdim	 2,			/* Size (0 = byte, 1 = short, 2 = long).  */
78218822Sdim	 32,			/* Bitsize.  */
79218822Sdim	 FALSE,			/* PC_relative.  */
80218822Sdim	 0,			/* Bitpos.  */
81218822Sdim	 complain_overflow_bitfield, /* Complain_on_overflow.  */
82218822Sdim	 bfd_elf_generic_reloc,	/* Special_function.  */
83218822Sdim	 "R_ARC_32",		/* Name.  */
84218822Sdim	 TRUE,			/* Partial_inplace.  */
85218822Sdim	 0xffffffff,		/* Src_mask.  */
86218822Sdim	 0xffffffff,		/* Dst_mask.  */
87218822Sdim	 FALSE),		/* PCrel_offset.  */
8838889Sjdp
8938889Sjdp  /* A 26 bit absolute branch, right shifted by 2.  */
90218822Sdim  HOWTO (R_ARC_B26,		/* Type.  */
91218822Sdim	 2,			/* Rightshift.  */
92218822Sdim	 2,			/* Size (0 = byte, 1 = short, 2 = long).  */
93218822Sdim	 26,			/* Bitsize.  */
94218822Sdim	 FALSE,			/* PC_relative.  */
95218822Sdim	 0,			/* Bitpos.  */
96218822Sdim	 complain_overflow_bitfield, /* Complain_on_overflow.  */
97218822Sdim	 bfd_elf_generic_reloc,	/* Special_function.  */
98218822Sdim	 "R_ARC_B26",		/* Name.  */
99218822Sdim	 TRUE,			/* Partial_inplace.  */
100218822Sdim	 0x00ffffff,		/* Src_mask.  */
101218822Sdim	 0x00ffffff,		/* Dst_mask.  */
102218822Sdim	 FALSE),		/* PCrel_offset.  */
10338889Sjdp
10438889Sjdp  /* A relative 22 bit branch; bits 21-2 are stored in bits 26-7.  */
105218822Sdim  HOWTO (R_ARC_B22_PCREL,	/* Type.  */
106218822Sdim	 2,			/* Rightshift.  */
107218822Sdim	 2,			/* Size (0 = byte, 1 = short, 2 = long).  */
108218822Sdim	 22,			/* Bitsize.  */
109218822Sdim	 TRUE,			/* PC_relative.  */
110218822Sdim	 7,			/* Bitpos.  */
111218822Sdim	 complain_overflow_signed, /* Complain_on_overflow.  */
112218822Sdim	 arc_elf_b22_pcrel,	/* Special_function.  */
113218822Sdim	 "R_ARC_B22_PCREL",	/* Name.  */
114218822Sdim	 TRUE,			/* Partial_inplace.  */
115218822Sdim	 0x07ffff80,		/* Src_mask.  */
116218822Sdim	 0x07ffff80,		/* Dst_mask.  */
117218822Sdim	 FALSE),		/* PCrel_offset.  */
11838889Sjdp};
11938889Sjdp
12038889Sjdp/* Map BFD reloc types to ARC ELF reloc types.  */
12138889Sjdp
12238889Sjdpstruct arc_reloc_map
12338889Sjdp{
12460484Sobrien  bfd_reloc_code_real_type bfd_reloc_val;
12538889Sjdp  unsigned char elf_reloc_val;
12638889Sjdp};
12738889Sjdp
12838889Sjdpstatic const struct arc_reloc_map arc_reloc_map[] =
12938889Sjdp{
13038889Sjdp  { BFD_RELOC_NONE, R_ARC_NONE, },
13138889Sjdp  { BFD_RELOC_32, R_ARC_32 },
13238889Sjdp  { BFD_RELOC_CTOR, R_ARC_32 },
13338889Sjdp  { BFD_RELOC_ARC_B26, R_ARC_B26 },
13438889Sjdp  { BFD_RELOC_ARC_B22_PCREL, R_ARC_B22_PCREL },
13538889Sjdp};
13638889Sjdp
13738889Sjdpstatic reloc_howto_type *
138218822Sdimbfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
139218822Sdim				 bfd_reloc_code_real_type code)
14038889Sjdp{
14138889Sjdp  unsigned int i;
14238889Sjdp
14389857Sobrien  for (i = ARRAY_SIZE (arc_reloc_map); i--;)
14489857Sobrien    if (arc_reloc_map[i].bfd_reloc_val == code)
14589857Sobrien      return elf_arc_howto_table + arc_reloc_map[i].elf_reloc_val;
14689857Sobrien
14738889Sjdp  return NULL;
14838889Sjdp}
14938889Sjdp
150218822Sdimstatic reloc_howto_type *
151218822Sdimbfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
152218822Sdim				 const char *r_name)
153218822Sdim{
154218822Sdim  unsigned int i;
155218822Sdim
156218822Sdim  for (i = 0;
157218822Sdim       i < sizeof (elf_arc_howto_table) / sizeof (elf_arc_howto_table[0]);
158218822Sdim       i++)
159218822Sdim    if (elf_arc_howto_table[i].name != NULL
160218822Sdim	&& strcasecmp (elf_arc_howto_table[i].name, r_name) == 0)
161218822Sdim      return &elf_arc_howto_table[i];
162218822Sdim
163218822Sdim  return NULL;
164218822Sdim}
165218822Sdim
16638889Sjdp/* Set the howto pointer for an ARC ELF reloc.  */
16738889Sjdp
16838889Sjdpstatic void
169218822Sdimarc_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
170218822Sdim		       arelent *cache_ptr,
171218822Sdim		       Elf_Internal_Rela *dst)
17238889Sjdp{
17338889Sjdp  unsigned int r_type;
17438889Sjdp
17538889Sjdp  r_type = ELF32_R_TYPE (dst->r_info);
17638889Sjdp  BFD_ASSERT (r_type < (unsigned int) R_ARC_max);
17738889Sjdp  cache_ptr->howto = &elf_arc_howto_table[r_type];
17838889Sjdp}
17938889Sjdp
18038889Sjdp/* Set the right machine number for an ARC ELF file.  */
18138889Sjdp
182130561Sobrienstatic bfd_boolean
183218822Sdimarc_elf_object_p (bfd *abfd)
18438889Sjdp{
18589857Sobrien  unsigned int mach = bfd_mach_arc_6;
18638889Sjdp
18785815Sobrien  if (elf_elfheader(abfd)->e_machine == EM_ARC)
18838889Sjdp    {
18985815Sobrien      unsigned long arch = elf_elfheader (abfd)->e_flags & EF_ARC_MACH;
19085815Sobrien
19185815Sobrien      switch (arch)
19285815Sobrien	{
19385815Sobrien	case E_ARC_MACH_ARC5:
19485815Sobrien	  mach = bfd_mach_arc_5;
19585815Sobrien	  break;
19685815Sobrien	default:
19785815Sobrien	case E_ARC_MACH_ARC6:
19885815Sobrien	  mach = bfd_mach_arc_6;
19985815Sobrien	  break;
20085815Sobrien	case E_ARC_MACH_ARC7:
20185815Sobrien	  mach = bfd_mach_arc_7;
20285815Sobrien	  break;
20385815Sobrien	case E_ARC_MACH_ARC8:
20485815Sobrien	  mach = bfd_mach_arc_8;
20585815Sobrien	  break;
20685815Sobrien	}
20738889Sjdp    }
20885815Sobrien  return bfd_default_set_arch_mach (abfd, bfd_arch_arc, mach);
20938889Sjdp}
21038889Sjdp
21138889Sjdp/* The final processing done just before writing out an ARC ELF object file.
21238889Sjdp   This gets the ARC architecture right based on the machine number.  */
21338889Sjdp
21438889Sjdpstatic void
215218822Sdimarc_elf_final_write_processing (bfd *abfd,
216218822Sdim				bfd_boolean linker ATTRIBUTE_UNUSED)
21738889Sjdp{
21838889Sjdp  unsigned long val;
21938889Sjdp
22085815Sobrien  switch (bfd_get_mach (abfd))
22138889Sjdp    {
22285815Sobrien    case bfd_mach_arc_5:
22385815Sobrien      val = E_ARC_MACH_ARC5;
22438889Sjdp      break;
22538889Sjdp    default:
22685815Sobrien    case bfd_mach_arc_6:
22785815Sobrien      val = E_ARC_MACH_ARC6;
22885815Sobrien      break;
22985815Sobrien    case bfd_mach_arc_7:
23085815Sobrien      val = E_ARC_MACH_ARC7;
23185815Sobrien      break;
23285815Sobrien    case bfd_mach_arc_8:
23385815Sobrien      val = E_ARC_MACH_ARC8;
23485815Sobrien      break;
23538889Sjdp    }
23638889Sjdp  elf_elfheader (abfd)->e_flags &=~ EF_ARC_MACH;
23738889Sjdp  elf_elfheader (abfd)->e_flags |= val;
23838889Sjdp}
23938889Sjdp
240218822Sdim#define TARGET_LITTLE_SYM   bfd_elf32_littlearc_vec
241218822Sdim#define TARGET_LITTLE_NAME  "elf32-littlearc"
242218822Sdim#define TARGET_BIG_SYM      bfd_elf32_bigarc_vec
243218822Sdim#define TARGET_BIG_NAME	    "elf32-bigarc"
244218822Sdim#define ELF_ARCH            bfd_arch_arc
245218822Sdim#define ELF_MACHINE_CODE    EM_ARC
246218822Sdim#define ELF_MAXPAGESIZE     0x1000
24789857Sobrien
248218822Sdim#define elf_info_to_howto                   0
249218822Sdim#define elf_info_to_howto_rel               arc_info_to_howto_rel
250218822Sdim#define elf_backend_object_p                arc_elf_object_p
251218822Sdim#define elf_backend_final_write_processing  arc_elf_final_write_processing
252104834Sobrien
25338889Sjdp#include "elf32-target.h"
254