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