1f7cc78ecSespie /* ARC-specific support for 32-bit ELF
2*d2201f2fSdrahn Copyright 1994, 1995, 1997, 1999, 2001, 2002
3*d2201f2fSdrahn Free Software Foundation, Inc.
4f7cc78ecSespie Contributed by Doug Evans (dje@cygnus.com).
5f7cc78ecSespie
6f7cc78ecSespie This file is part of BFD, the Binary File Descriptor library.
7f7cc78ecSespie
8f7cc78ecSespie This program is free software; you can redistribute it and/or modify
9f7cc78ecSespie it under the terms of the GNU General Public License as published by
10f7cc78ecSespie the Free Software Foundation; either version 2 of the License, or
11f7cc78ecSespie (at your option) any later version.
12f7cc78ecSespie
13f7cc78ecSespie This program is distributed in the hope that it will be useful,
14f7cc78ecSespie but WITHOUT ANY WARRANTY; without even the implied warranty of
15f7cc78ecSespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16f7cc78ecSespie GNU General Public License for more details.
17f7cc78ecSespie
18f7cc78ecSespie You should have received a copy of the GNU General Public License
19f7cc78ecSespie along with this program; if not, write to the Free Software
20f7cc78ecSespie Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21f7cc78ecSespie
22f7cc78ecSespie #include "bfd.h"
23f7cc78ecSespie #include "sysdep.h"
24f7cc78ecSespie #include "libbfd.h"
25f7cc78ecSespie #include "elf-bfd.h"
26f7cc78ecSespie #include "elf/arc.h"
27*d2201f2fSdrahn #include "libiberty.h"
28f7cc78ecSespie
29f7cc78ecSespie static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
30f7cc78ecSespie PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
31f7cc78ecSespie static void arc_info_to_howto_rel
32*d2201f2fSdrahn PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
33*d2201f2fSdrahn static bfd_boolean arc_elf_object_p
345f210c2aSfgsch PARAMS ((bfd *));
355f210c2aSfgsch static void arc_elf_final_write_processing
36*d2201f2fSdrahn PARAMS ((bfd *, bfd_boolean));
37*d2201f2fSdrahn static bfd_reloc_status_type arc_elf_b22_pcrel
38*d2201f2fSdrahn PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
39f7cc78ecSespie
40f7cc78ecSespie /* Try to minimize the amount of space occupied by relocation tables
41f7cc78ecSespie on the ROM (not that the ROM won't be swamped by other ELF overhead). */
425f210c2aSfgsch
43*d2201f2fSdrahn #define USE_REL 1
44f7cc78ecSespie
45f7cc78ecSespie static reloc_howto_type elf_arc_howto_table[] =
46f7cc78ecSespie {
47f7cc78ecSespie /* This reloc does nothing. */
48f7cc78ecSespie HOWTO (R_ARC_NONE, /* type */
49f7cc78ecSespie 0, /* rightshift */
50f7cc78ecSespie 2, /* size (0 = byte, 1 = short, 2 = long) */
51f7cc78ecSespie 32, /* bitsize */
52*d2201f2fSdrahn FALSE, /* pc_relative */
53f7cc78ecSespie 0, /* bitpos */
54f7cc78ecSespie complain_overflow_bitfield, /* complain_on_overflow */
55f7cc78ecSespie bfd_elf_generic_reloc, /* special_function */
56f7cc78ecSespie "R_ARC_NONE", /* name */
57*d2201f2fSdrahn TRUE, /* partial_inplace */
58f7cc78ecSespie 0, /* src_mask */
59f7cc78ecSespie 0, /* dst_mask */
60*d2201f2fSdrahn FALSE), /* pcrel_offset */
61f7cc78ecSespie
62f7cc78ecSespie /* A standard 32 bit relocation. */
63f7cc78ecSespie HOWTO (R_ARC_32, /* type */
64f7cc78ecSespie 0, /* rightshift */
65f7cc78ecSespie 2, /* size (0 = byte, 1 = short, 2 = long) */
66f7cc78ecSespie 32, /* bitsize */
67*d2201f2fSdrahn FALSE, /* pc_relative */
68f7cc78ecSespie 0, /* bitpos */
69f7cc78ecSespie complain_overflow_bitfield, /* complain_on_overflow */
70f7cc78ecSespie bfd_elf_generic_reloc, /* special_function */
71f7cc78ecSespie "R_ARC_32", /* name */
72*d2201f2fSdrahn TRUE, /* partial_inplace */
73f7cc78ecSespie 0xffffffff, /* src_mask */
74f7cc78ecSespie 0xffffffff, /* dst_mask */
75*d2201f2fSdrahn FALSE), /* pcrel_offset */
76f7cc78ecSespie
77f7cc78ecSespie /* A 26 bit absolute branch, right shifted by 2. */
78f7cc78ecSespie HOWTO (R_ARC_B26, /* type */
79f7cc78ecSespie 2, /* rightshift */
80f7cc78ecSespie 2, /* size (0 = byte, 1 = short, 2 = long) */
81f7cc78ecSespie 26, /* bitsize */
82*d2201f2fSdrahn FALSE, /* pc_relative */
83f7cc78ecSespie 0, /* bitpos */
84f7cc78ecSespie complain_overflow_bitfield, /* complain_on_overflow */
85f7cc78ecSespie bfd_elf_generic_reloc, /* special_function */
86f7cc78ecSespie "R_ARC_B26", /* name */
87*d2201f2fSdrahn TRUE, /* partial_inplace */
88f7cc78ecSespie 0x00ffffff, /* src_mask */
89f7cc78ecSespie 0x00ffffff, /* dst_mask */
90*d2201f2fSdrahn FALSE), /* pcrel_offset */
91f7cc78ecSespie
92f7cc78ecSespie /* A relative 22 bit branch; bits 21-2 are stored in bits 26-7. */
93f7cc78ecSespie HOWTO (R_ARC_B22_PCREL, /* type */
94f7cc78ecSespie 2, /* rightshift */
95f7cc78ecSespie 2, /* size (0 = byte, 1 = short, 2 = long) */
96f7cc78ecSespie 22, /* bitsize */
97*d2201f2fSdrahn TRUE, /* pc_relative */
98f7cc78ecSespie 7, /* bitpos */
99f7cc78ecSespie complain_overflow_signed, /* complain_on_overflow */
100*d2201f2fSdrahn arc_elf_b22_pcrel, /* special_function */
101f7cc78ecSespie "R_ARC_B22_PCREL", /* name */
102*d2201f2fSdrahn TRUE, /* partial_inplace */
103f7cc78ecSespie 0x07ffff80, /* src_mask */
104f7cc78ecSespie 0x07ffff80, /* dst_mask */
105*d2201f2fSdrahn FALSE), /* pcrel_offset */
106f7cc78ecSespie };
107f7cc78ecSespie
108f7cc78ecSespie /* Map BFD reloc types to ARC ELF reloc types. */
109f7cc78ecSespie
110f7cc78ecSespie struct arc_reloc_map
111f7cc78ecSespie {
112f7cc78ecSespie bfd_reloc_code_real_type bfd_reloc_val;
113f7cc78ecSespie unsigned char elf_reloc_val;
114f7cc78ecSespie };
115f7cc78ecSespie
116f7cc78ecSespie static const struct arc_reloc_map arc_reloc_map[] =
117f7cc78ecSespie {
118f7cc78ecSespie { BFD_RELOC_NONE, R_ARC_NONE, },
119f7cc78ecSespie { BFD_RELOC_32, R_ARC_32 },
120f7cc78ecSespie { BFD_RELOC_CTOR, R_ARC_32 },
121f7cc78ecSespie { BFD_RELOC_ARC_B26, R_ARC_B26 },
122f7cc78ecSespie { BFD_RELOC_ARC_B22_PCREL, R_ARC_B22_PCREL },
123f7cc78ecSespie };
124f7cc78ecSespie
125f7cc78ecSespie static reloc_howto_type *
bfd_elf32_bfd_reloc_type_lookup(abfd,code)126f7cc78ecSespie bfd_elf32_bfd_reloc_type_lookup (abfd, code)
127f7cc78ecSespie bfd *abfd ATTRIBUTE_UNUSED;
128f7cc78ecSespie bfd_reloc_code_real_type code;
129f7cc78ecSespie {
130f7cc78ecSespie unsigned int i;
131f7cc78ecSespie
132*d2201f2fSdrahn for (i = ARRAY_SIZE (arc_reloc_map); i--;)
133f7cc78ecSespie if (arc_reloc_map[i].bfd_reloc_val == code)
134*d2201f2fSdrahn return elf_arc_howto_table + arc_reloc_map[i].elf_reloc_val;
135*d2201f2fSdrahn
136f7cc78ecSespie return NULL;
137f7cc78ecSespie }
138f7cc78ecSespie
139f7cc78ecSespie /* Set the howto pointer for an ARC ELF reloc. */
140f7cc78ecSespie
141f7cc78ecSespie static void
arc_info_to_howto_rel(abfd,cache_ptr,dst)142f7cc78ecSespie arc_info_to_howto_rel (abfd, cache_ptr, dst)
143f7cc78ecSespie bfd *abfd ATTRIBUTE_UNUSED;
144f7cc78ecSespie arelent *cache_ptr;
145*d2201f2fSdrahn Elf_Internal_Rela *dst;
146f7cc78ecSespie {
147f7cc78ecSespie unsigned int r_type;
148f7cc78ecSespie
149f7cc78ecSespie r_type = ELF32_R_TYPE (dst->r_info);
150f7cc78ecSespie BFD_ASSERT (r_type < (unsigned int) R_ARC_max);
151f7cc78ecSespie cache_ptr->howto = &elf_arc_howto_table[r_type];
152f7cc78ecSespie }
153f7cc78ecSespie
154f7cc78ecSespie /* Set the right machine number for an ARC ELF file. */
155f7cc78ecSespie
156*d2201f2fSdrahn static bfd_boolean
arc_elf_object_p(abfd)157f7cc78ecSespie arc_elf_object_p (abfd)
158f7cc78ecSespie bfd *abfd;
159f7cc78ecSespie {
160*d2201f2fSdrahn unsigned int mach = bfd_mach_arc_6;
1615f210c2aSfgsch
1625f210c2aSfgsch if (elf_elfheader(abfd)->e_machine == EM_ARC)
1635f210c2aSfgsch {
164f7cc78ecSespie unsigned long arch = elf_elfheader (abfd)->e_flags & EF_ARC_MACH;
165f7cc78ecSespie
166f7cc78ecSespie switch (arch)
167f7cc78ecSespie {
1685f210c2aSfgsch case E_ARC_MACH_ARC5:
1695f210c2aSfgsch mach = bfd_mach_arc_5;
170f7cc78ecSespie break;
171f7cc78ecSespie default:
1725f210c2aSfgsch case E_ARC_MACH_ARC6:
1735f210c2aSfgsch mach = bfd_mach_arc_6;
1745f210c2aSfgsch break;
1755f210c2aSfgsch case E_ARC_MACH_ARC7:
1765f210c2aSfgsch mach = bfd_mach_arc_7;
1775f210c2aSfgsch break;
1785f210c2aSfgsch case E_ARC_MACH_ARC8:
1795f210c2aSfgsch mach = bfd_mach_arc_8;
1805f210c2aSfgsch break;
181f7cc78ecSespie }
1825f210c2aSfgsch }
1835f210c2aSfgsch return bfd_default_set_arch_mach (abfd, bfd_arch_arc, mach);
184f7cc78ecSespie }
185f7cc78ecSespie
186f7cc78ecSespie /* The final processing done just before writing out an ARC ELF object file.
187f7cc78ecSespie This gets the ARC architecture right based on the machine number. */
188f7cc78ecSespie
189f7cc78ecSespie static void
arc_elf_final_write_processing(abfd,linker)190f7cc78ecSespie arc_elf_final_write_processing (abfd, linker)
191f7cc78ecSespie bfd *abfd;
192*d2201f2fSdrahn bfd_boolean linker ATTRIBUTE_UNUSED;
193f7cc78ecSespie {
194f7cc78ecSespie unsigned long val;
195f7cc78ecSespie
1965f210c2aSfgsch switch (bfd_get_mach (abfd))
197f7cc78ecSespie {
1985f210c2aSfgsch case bfd_mach_arc_5:
1995f210c2aSfgsch val = E_ARC_MACH_ARC5;
200f7cc78ecSespie break;
201f7cc78ecSespie default:
2025f210c2aSfgsch case bfd_mach_arc_6:
2035f210c2aSfgsch val = E_ARC_MACH_ARC6;
2045f210c2aSfgsch break;
2055f210c2aSfgsch case bfd_mach_arc_7:
2065f210c2aSfgsch val = E_ARC_MACH_ARC7;
2075f210c2aSfgsch break;
2085f210c2aSfgsch case bfd_mach_arc_8:
2095f210c2aSfgsch val = E_ARC_MACH_ARC8;
2105f210c2aSfgsch break;
211f7cc78ecSespie }
212f7cc78ecSespie elf_elfheader (abfd)->e_flags &=~ EF_ARC_MACH;
213f7cc78ecSespie elf_elfheader (abfd)->e_flags |= val;
214f7cc78ecSespie }
215f7cc78ecSespie
216*d2201f2fSdrahn bfd_reloc_status_type
arc_elf_b22_pcrel(abfd,reloc_entry,symbol,data,input_section,output_bfd,error_message)217*d2201f2fSdrahn arc_elf_b22_pcrel (abfd, reloc_entry, symbol, data, input_section,
218*d2201f2fSdrahn output_bfd, error_message)
219*d2201f2fSdrahn bfd * abfd;
220*d2201f2fSdrahn arelent * reloc_entry;
221*d2201f2fSdrahn asymbol * symbol;
222*d2201f2fSdrahn PTR data;
223*d2201f2fSdrahn asection * input_section;
224*d2201f2fSdrahn bfd * output_bfd;
225*d2201f2fSdrahn char ** error_message;
226*d2201f2fSdrahn {
227*d2201f2fSdrahn /* If linking, back up the final symbol address by the address of the
228*d2201f2fSdrahn reloc. This cannot be accomplished by setting the pcrel_offset
229*d2201f2fSdrahn field to TRUE, as bfd_install_relocation will detect this and refuse
230*d2201f2fSdrahn to install the offset in the first place, but bfd_perform_relocation
231*d2201f2fSdrahn will still insist on removing it. */
232*d2201f2fSdrahn if (output_bfd == (bfd *) NULL)
233*d2201f2fSdrahn reloc_entry->addend -= reloc_entry->address;
234*d2201f2fSdrahn
235*d2201f2fSdrahn /* Fall through to the default elf reloc handler. */
236*d2201f2fSdrahn return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
237*d2201f2fSdrahn input_section, output_bfd, error_message);
238*d2201f2fSdrahn }
239*d2201f2fSdrahn
240f7cc78ecSespie #define TARGET_LITTLE_SYM bfd_elf32_littlearc_vec
241f7cc78ecSespie #define TARGET_LITTLE_NAME "elf32-littlearc"
242f7cc78ecSespie #define TARGET_BIG_SYM bfd_elf32_bigarc_vec
243f7cc78ecSespie #define TARGET_BIG_NAME "elf32-bigarc"
244f7cc78ecSespie #define ELF_ARCH bfd_arch_arc
2455f210c2aSfgsch #define ELF_MACHINE_CODE EM_ARC
246f7cc78ecSespie #define ELF_MAXPAGESIZE 0x1000
247f7cc78ecSespie
248f7cc78ecSespie #define elf_info_to_howto 0
249f7cc78ecSespie #define elf_info_to_howto_rel arc_info_to_howto_rel
250f7cc78ecSespie #define elf_backend_object_p arc_elf_object_p
2515f210c2aSfgsch #define elf_backend_final_write_processing arc_elf_final_write_processing
252f7cc78ecSespie
253f7cc78ecSespie #include "elf32-target.h"
254