elf32-pru.c revision 1.1.1.2 1 1.1 christos /* 32-bit ELF support for TI PRU.
2 1.1.1.2 christos Copyright (C) 2014-2019 Free Software Foundation, Inc.
3 1.1 christos Contributed by Dimitar Dimitrov <dimitar (at) dinux.eu>
4 1.1 christos Based on elf32-nios2.c
5 1.1 christos
6 1.1 christos This file is part of BFD, the Binary File Descriptor library.
7 1.1 christos
8 1.1 christos This program is free software; you can redistribute it and/or modify
9 1.1 christos it under the terms of the GNU General Public License as published by
10 1.1 christos the Free Software Foundation; either version 3 of the License, or
11 1.1 christos (at your option) any later version.
12 1.1 christos
13 1.1 christos This program is distributed in the hope that it will be useful,
14 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
15 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 1.1 christos GNU General Public License for more details.
17 1.1 christos
18 1.1 christos You should have received a copy of the GNU General Public License
19 1.1 christos along with this program; if not, write to the Free Software
20 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 1.1 christos MA 02110-1301, USA. */
22 1.1 christos
23 1.1 christos /* This file handles TI PRU ELF targets. */
24 1.1 christos
25 1.1 christos #include "sysdep.h"
26 1.1 christos #include "bfd.h"
27 1.1 christos #include "libbfd.h"
28 1.1 christos #include "bfdlink.h"
29 1.1 christos #include "genlink.h"
30 1.1 christos #include "elf-bfd.h"
31 1.1 christos #include "elf/pru.h"
32 1.1 christos #include "opcode/pru.h"
33 1.1.1.2 christos #include "libiberty.h"
34 1.1 christos
35 1.1 christos #define SWAP_VALS(A,B) \
36 1.1 christos do { \
37 1.1 christos (A) ^= (B); \
38 1.1 christos (B) ^= (A); \
39 1.1 christos (A) ^= (B); \
40 1.1 christos } while (0)
41 1.1 christos
42 1.1 christos /* Enable debugging printout at stdout with this variable. */
43 1.1 christos static bfd_boolean debug_relax = FALSE;
44 1.1 christos
45 1.1 christos /* Forward declarations. */
46 1.1 christos static bfd_reloc_status_type pru_elf32_pmem_relocate
47 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
48 1.1 christos static bfd_reloc_status_type pru_elf32_s10_pcrel_relocate
49 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
50 1.1 christos static bfd_reloc_status_type pru_elf32_u8_pcrel_relocate
51 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
52 1.1 christos static bfd_reloc_status_type pru_elf32_ldi32_relocate
53 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
54 1.1 christos static bfd_reloc_status_type bfd_elf_pru_diff_relocate
55 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
56 1.1 christos
57 1.1 christos /* Target vector. */
58 1.1 christos extern const bfd_target pru_elf32_vec;
59 1.1 christos
60 1.1 christos /* The relocation table used for SHT_REL sections. */
61 1.1 christos static reloc_howto_type elf_pru_howto_table_rel[] = {
62 1.1 christos /* No relocation. */
63 1.1 christos HOWTO (R_PRU_NONE, /* type */
64 1.1 christos 0, /* rightshift */
65 1.1 christos 0, /* size (0 = byte, 1 = short, 2 = long) */
66 1.1 christos 3, /* bitsize */
67 1.1 christos FALSE, /* pc_relative */
68 1.1 christos 0, /* bitpos */
69 1.1 christos complain_overflow_dont,/* complain_on_overflow */
70 1.1 christos bfd_elf_generic_reloc, /* special_function */
71 1.1 christos "R_PRU_NONE", /* name */
72 1.1 christos FALSE, /* partial_inplace */
73 1.1 christos 0, /* src_mask */
74 1.1 christos 0, /* dst_mask */
75 1.1 christos FALSE), /* pcrel_offset */
76 1.1 christos
77 1.1 christos HOWTO (R_PRU_16_PMEM,
78 1.1 christos 2,
79 1.1 christos 1, /* short */
80 1.1 christos 32,
81 1.1 christos FALSE,
82 1.1 christos 0,
83 1.1 christos complain_overflow_dont,
84 1.1 christos bfd_elf_generic_reloc,
85 1.1 christos "R_PRU_16_PMEM",
86 1.1 christos FALSE,
87 1.1 christos 0, /* src_mask */
88 1.1 christos 0xffff,
89 1.1 christos FALSE),
90 1.1 christos
91 1.1 christos HOWTO (R_PRU_U16_PMEMIMM,
92 1.1 christos 2,
93 1.1 christos 2,
94 1.1 christos 32,
95 1.1 christos FALSE,
96 1.1 christos 8,
97 1.1 christos complain_overflow_unsigned,
98 1.1 christos pru_elf32_pmem_relocate,
99 1.1 christos "R_PRU_U16_PMEMIMM",
100 1.1 christos FALSE,
101 1.1 christos 0, /* src_mask */
102 1.1 christos 0x00ffff00,
103 1.1 christos FALSE),
104 1.1 christos
105 1.1 christos HOWTO (R_PRU_BFD_RELOC_16,
106 1.1 christos 0,
107 1.1 christos 1, /* short */
108 1.1 christos 16,
109 1.1 christos FALSE,
110 1.1 christos 0,
111 1.1 christos complain_overflow_bitfield,
112 1.1 christos bfd_elf_generic_reloc,
113 1.1 christos "R_PRU_BFD_RELOC16",
114 1.1 christos FALSE,
115 1.1 christos 0, /* src_mask */
116 1.1 christos 0x0000ffff,
117 1.1 christos FALSE),
118 1.1 christos
119 1.1 christos /* 16-bit unsigned immediate relocation. */
120 1.1 christos HOWTO (R_PRU_U16, /* type */
121 1.1 christos 0, /* rightshift */
122 1.1 christos 2, /* size (0 = byte, 1 = short, 2 = long) */
123 1.1 christos 16, /* bitsize */
124 1.1 christos FALSE, /* pc_relative */
125 1.1 christos 8, /* bitpos */
126 1.1 christos complain_overflow_unsigned, /* complain on overflow */
127 1.1 christos bfd_elf_generic_reloc, /* special function */
128 1.1 christos "R_PRU_U16", /* name */
129 1.1 christos FALSE, /* partial_inplace */
130 1.1 christos 0, /* src_mask */
131 1.1 christos 0x00ffff00, /* dest_mask */
132 1.1 christos FALSE), /* pcrel_offset */
133 1.1 christos
134 1.1 christos HOWTO (R_PRU_32_PMEM,
135 1.1 christos 2,
136 1.1 christos 2, /* long */
137 1.1 christos 32,
138 1.1 christos FALSE,
139 1.1 christos 0,
140 1.1 christos complain_overflow_dont,
141 1.1 christos pru_elf32_pmem_relocate,
142 1.1 christos "R_PRU_32_PMEM",
143 1.1 christos FALSE,
144 1.1 christos 0, /* src_mask */
145 1.1 christos 0xffffffff,
146 1.1 christos FALSE),
147 1.1 christos
148 1.1 christos HOWTO (R_PRU_BFD_RELOC_32,
149 1.1 christos 0,
150 1.1 christos 2, /* long */
151 1.1 christos 32,
152 1.1 christos FALSE,
153 1.1 christos 0,
154 1.1 christos complain_overflow_dont,
155 1.1 christos bfd_elf_generic_reloc,
156 1.1 christos "R_PRU_BFD_RELOC32",
157 1.1 christos FALSE,
158 1.1 christos 0, /* src_mask */
159 1.1 christos 0xffffffff,
160 1.1 christos FALSE),
161 1.1 christos
162 1.1 christos HOWTO (R_PRU_S10_PCREL,
163 1.1 christos 2,
164 1.1 christos 2,
165 1.1 christos 10,
166 1.1 christos TRUE,
167 1.1 christos 0,
168 1.1 christos complain_overflow_bitfield,
169 1.1 christos pru_elf32_s10_pcrel_relocate,
170 1.1 christos "R_PRU_S10_PCREL",
171 1.1 christos FALSE,
172 1.1 christos 0, /* src_mask */
173 1.1 christos 0x060000ff,
174 1.1 christos TRUE),
175 1.1 christos
176 1.1 christos HOWTO (R_PRU_U8_PCREL,
177 1.1 christos 2,
178 1.1 christos 2,
179 1.1 christos 8,
180 1.1 christos TRUE,
181 1.1 christos 0,
182 1.1 christos complain_overflow_unsigned,
183 1.1 christos pru_elf32_u8_pcrel_relocate,
184 1.1 christos "R_PRU_U8_PCREL",
185 1.1 christos FALSE,
186 1.1 christos 0, /* src_mask */
187 1.1 christos 0x000000ff,
188 1.1 christos TRUE),
189 1.1 christos
190 1.1 christos HOWTO (R_PRU_LDI32,
191 1.1 christos 0, /* rightshift */
192 1.1 christos 4, /* size (4 = 8bytes) */
193 1.1 christos 32, /* bitsize */
194 1.1 christos FALSE, /* pc_relative */
195 1.1 christos 0, /* bitpos */
196 1.1 christos complain_overflow_unsigned, /* complain on overflow */
197 1.1 christos pru_elf32_ldi32_relocate, /* special function */
198 1.1 christos "R_PRU_LDI32", /* name */
199 1.1 christos FALSE, /* partial_inplace */
200 1.1 christos 0, /* src_mask */
201 1.1 christos 0xffffffff, /* dest_mask */
202 1.1 christos FALSE), /* pcrel_offset */
203 1.1 christos
204 1.1 christos /* GNU-specific relocations. */
205 1.1 christos HOWTO (R_PRU_GNU_BFD_RELOC_8,
206 1.1 christos 0,
207 1.1 christos 0, /* byte */
208 1.1 christos 8,
209 1.1 christos FALSE,
210 1.1 christos 0,
211 1.1 christos complain_overflow_bitfield,
212 1.1 christos bfd_elf_generic_reloc,
213 1.1 christos "R_PRU_BFD_RELOC8",
214 1.1 christos FALSE,
215 1.1 christos 0, /* src_mask */
216 1.1 christos 0x000000ff,
217 1.1 christos FALSE),
218 1.1 christos
219 1.1 christos HOWTO (R_PRU_GNU_DIFF8, /* type */
220 1.1 christos 0, /* rightshift */
221 1.1.1.2 christos 0, /* size (0 = byte, 1 = short, 2 = long) */
222 1.1.1.2 christos 8, /* bitsize */
223 1.1 christos FALSE, /* pc_relative */
224 1.1 christos 0, /* bitpos */
225 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */
226 1.1 christos bfd_elf_pru_diff_relocate, /* special_function */
227 1.1.1.2 christos "R_PRU_DIFF8", /* name */
228 1.1 christos FALSE, /* partial_inplace */
229 1.1 christos 0, /* src_mask */
230 1.1 christos 0xff, /* dst_mask */
231 1.1 christos FALSE), /* pcrel_offset */
232 1.1 christos
233 1.1.1.2 christos HOWTO (R_PRU_GNU_DIFF16, /* type */
234 1.1 christos 0, /* rightshift */
235 1.1 christos 1, /* size (0 = byte, 1 = short, 2 = long) */
236 1.1 christos 16, /* bitsize */
237 1.1 christos FALSE, /* pc_relative */
238 1.1 christos 0, /* bitpos */
239 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */
240 1.1 christos bfd_elf_pru_diff_relocate,/* special_function */
241 1.1.1.2 christos "R_PRU_DIFF16", /* name */
242 1.1 christos FALSE, /* partial_inplace */
243 1.1 christos 0, /* src_mask */
244 1.1 christos 0xffff, /* dst_mask */
245 1.1 christos FALSE), /* pcrel_offset */
246 1.1 christos
247 1.1.1.2 christos HOWTO (R_PRU_GNU_DIFF32, /* type */
248 1.1 christos 0, /* rightshift */
249 1.1 christos 2, /* size (0 = byte, 1 = short, 2 = long) */
250 1.1 christos 32, /* bitsize */
251 1.1 christos FALSE, /* pc_relative */
252 1.1 christos 0, /* bitpos */
253 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */
254 1.1 christos bfd_elf_pru_diff_relocate,/* special_function */
255 1.1.1.2 christos "R_PRU_DIFF32", /* name */
256 1.1 christos FALSE, /* partial_inplace */
257 1.1 christos 0, /* src_mask */
258 1.1.1.2 christos 0xffffffff, /* dst_mask */
259 1.1 christos FALSE), /* pcrel_offset */
260 1.1 christos
261 1.1 christos HOWTO (R_PRU_GNU_DIFF16_PMEM, /* type */
262 1.1 christos 0, /* rightshift */
263 1.1 christos 1, /* size (0 = byte, 1 = short, 2 = long) */
264 1.1 christos 16, /* bitsize */
265 1.1 christos FALSE, /* pc_relative */
266 1.1 christos 0, /* bitpos */
267 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */
268 1.1 christos bfd_elf_pru_diff_relocate,/* special_function */
269 1.1.1.2 christos "R_PRU_DIFF16_PMEM", /* name */
270 1.1 christos FALSE, /* partial_inplace */
271 1.1 christos 0, /* src_mask */
272 1.1 christos 0xffff, /* dst_mask */
273 1.1 christos FALSE), /* pcrel_offset */
274 1.1 christos
275 1.1 christos HOWTO (R_PRU_GNU_DIFF32_PMEM, /* type */
276 1.1 christos 0, /* rightshift */
277 1.1 christos 2, /* size (0 = byte, 1 = short, 2 = long) */
278 1.1 christos 32, /* bitsize */
279 1.1 christos FALSE, /* pc_relative */
280 1.1 christos 0, /* bitpos */
281 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */
282 1.1 christos bfd_elf_pru_diff_relocate,/* special_function */
283 1.1.1.2 christos "R_PRU_DIFF32_PMEM", /* name */
284 1.1 christos FALSE, /* partial_inplace */
285 1.1 christos 0, /* src_mask */
286 1.1 christos 0xffffffff, /* dst_mask */
287 1.1 christos FALSE), /* pcrel_offset */
288 1.1 christos
289 1.1 christos /* Add other relocations here. */
290 1.1 christos };
291 1.1 christos
292 1.1 christos static unsigned char elf_code_to_howto_index[R_PRU_ILLEGAL + 1];
293 1.1 christos
294 1.1 christos /* Return the howto for relocation RTYPE. */
295 1.1.1.2 christos
296 1.1 christos static reloc_howto_type *
297 1.1 christos lookup_howto (unsigned int rtype)
298 1.1 christos {
299 1.1.1.2 christos static bfd_boolean initialized = FALSE;
300 1.1 christos int i;
301 1.1 christos int howto_tbl_size = (int) (sizeof (elf_pru_howto_table_rel)
302 1.1 christos / sizeof (elf_pru_howto_table_rel[0]));
303 1.1 christos
304 1.1.1.2 christos if (! initialized)
305 1.1 christos {
306 1.1.1.2 christos initialized = TRUE;
307 1.1 christos memset (elf_code_to_howto_index, 0xff,
308 1.1 christos sizeof (elf_code_to_howto_index));
309 1.1 christos for (i = 0; i < howto_tbl_size; i++)
310 1.1 christos elf_code_to_howto_index[elf_pru_howto_table_rel[i].type] = i;
311 1.1 christos }
312 1.1 christos
313 1.1.1.2 christos if (rtype > R_PRU_ILLEGAL)
314 1.1.1.2 christos return NULL;
315 1.1 christos i = elf_code_to_howto_index[rtype];
316 1.1 christos if (i >= howto_tbl_size)
317 1.1.1.2 christos return NULL;
318 1.1 christos return elf_pru_howto_table_rel + i;
319 1.1 christos }
320 1.1 christos
321 1.1 christos /* Map for converting BFD reloc types to PRU reloc types. */
322 1.1.1.2 christos
323 1.1 christos struct elf_reloc_map
324 1.1 christos {
325 1.1 christos bfd_reloc_code_real_type bfd_val;
326 1.1 christos enum elf_pru_reloc_type elf_val;
327 1.1 christos };
328 1.1 christos
329 1.1.1.2 christos static const struct elf_reloc_map pru_reloc_map[] =
330 1.1.1.2 christos {
331 1.1 christos {BFD_RELOC_NONE, R_PRU_NONE},
332 1.1 christos {BFD_RELOC_PRU_16_PMEM, R_PRU_16_PMEM},
333 1.1 christos {BFD_RELOC_PRU_U16_PMEMIMM, R_PRU_U16_PMEMIMM},
334 1.1 christos {BFD_RELOC_16, R_PRU_BFD_RELOC_16},
335 1.1 christos {BFD_RELOC_PRU_U16, R_PRU_U16},
336 1.1 christos {BFD_RELOC_PRU_32_PMEM, R_PRU_32_PMEM},
337 1.1 christos {BFD_RELOC_32, R_PRU_BFD_RELOC_32},
338 1.1 christos {BFD_RELOC_PRU_S10_PCREL, R_PRU_S10_PCREL},
339 1.1 christos {BFD_RELOC_PRU_U8_PCREL, R_PRU_U8_PCREL},
340 1.1 christos {BFD_RELOC_PRU_LDI32, R_PRU_LDI32},
341 1.1 christos
342 1.1 christos {BFD_RELOC_8, R_PRU_GNU_BFD_RELOC_8},
343 1.1 christos {BFD_RELOC_PRU_GNU_DIFF8, R_PRU_GNU_DIFF8},
344 1.1 christos {BFD_RELOC_PRU_GNU_DIFF16, R_PRU_GNU_DIFF16},
345 1.1 christos {BFD_RELOC_PRU_GNU_DIFF32, R_PRU_GNU_DIFF32},
346 1.1 christos {BFD_RELOC_PRU_GNU_DIFF16_PMEM, R_PRU_GNU_DIFF16_PMEM},
347 1.1 christos {BFD_RELOC_PRU_GNU_DIFF32_PMEM, R_PRU_GNU_DIFF32_PMEM},
348 1.1 christos };
349 1.1 christos
350 1.1 christos
351 1.1 christos /* Assorted hash table functions. */
352 1.1 christos
353 1.1 christos /* Create an entry in a PRU ELF linker hash table. */
354 1.1.1.2 christos
355 1.1 christos static struct bfd_hash_entry *
356 1.1 christos link_hash_newfunc (struct bfd_hash_entry *entry,
357 1.1 christos struct bfd_hash_table *table, const char *string)
358 1.1 christos {
359 1.1 christos /* Allocate the structure if it has not already been allocated by a
360 1.1 christos subclass. */
361 1.1 christos if (entry == NULL)
362 1.1 christos {
363 1.1 christos entry = bfd_hash_allocate (table,
364 1.1 christos sizeof (struct elf_link_hash_entry));
365 1.1 christos if (entry == NULL)
366 1.1 christos return entry;
367 1.1 christos }
368 1.1 christos
369 1.1 christos /* Call the allocation method of the superclass. */
370 1.1 christos entry = _bfd_elf_link_hash_newfunc (entry, table, string);
371 1.1 christos
372 1.1 christos return entry;
373 1.1 christos }
374 1.1 christos
375 1.1 christos /* Implement bfd_elf32_bfd_reloc_type_lookup:
376 1.1 christos Given a BFD reloc type, return a howto structure. */
377 1.1.1.2 christos
378 1.1 christos static reloc_howto_type *
379 1.1 christos pru_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
380 1.1 christos bfd_reloc_code_real_type code)
381 1.1 christos {
382 1.1.1.2 christos unsigned int i;
383 1.1.1.2 christos
384 1.1.1.2 christos for (i = 0; i < ARRAY_SIZE (pru_reloc_map); ++i)
385 1.1 christos if (pru_reloc_map[i].bfd_val == code)
386 1.1 christos return lookup_howto ((unsigned int) pru_reloc_map[i].elf_val);
387 1.1 christos return NULL;
388 1.1 christos }
389 1.1 christos
390 1.1 christos /* Implement bfd_elf32_bfd_reloc_name_lookup:
391 1.1 christos Given a reloc name, return a howto structure. */
392 1.1.1.2 christos
393 1.1 christos static reloc_howto_type *
394 1.1 christos pru_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
395 1.1 christos const char *r_name)
396 1.1 christos {
397 1.1 christos unsigned int i;
398 1.1.1.2 christos
399 1.1.1.2 christos for (i = 0; i < ARRAY_SIZE (elf_pru_howto_table_rel); i++)
400 1.1 christos if (elf_pru_howto_table_rel[i].name
401 1.1 christos && strcasecmp (elf_pru_howto_table_rel[i].name, r_name) == 0)
402 1.1 christos return &elf_pru_howto_table_rel[i];
403 1.1 christos
404 1.1 christos return NULL;
405 1.1 christos }
406 1.1 christos
407 1.1 christos /* Implement elf_info_to_howto:
408 1.1 christos Given a ELF32 relocation, fill in a arelent structure. */
409 1.1.1.2 christos
410 1.1.1.2 christos static bfd_boolean
411 1.1.1.2 christos pru_elf32_info_to_howto (bfd *abfd, arelent *cache_ptr,
412 1.1 christos Elf_Internal_Rela *dst)
413 1.1 christos {
414 1.1 christos unsigned int r_type;
415 1.1 christos
416 1.1 christos r_type = ELF32_R_TYPE (dst->r_info);
417 1.1.1.2 christos if (r_type >= R_PRU_ILLEGAL)
418 1.1.1.2 christos {
419 1.1.1.2 christos /* xgettext:c-format */
420 1.1.1.2 christos _bfd_error_handler (_("%pB: unsupported relocation type %#x"), abfd, r_type);
421 1.1.1.2 christos bfd_set_error (bfd_error_bad_value);
422 1.1.1.2 christos return FALSE;
423 1.1.1.2 christos }
424 1.1.1.2 christos
425 1.1 christos cache_ptr->howto = lookup_howto (r_type);
426 1.1.1.2 christos return cache_ptr->howto != NULL;
427 1.1 christos }
428 1.1 christos
429 1.1 christos /* Do the relocations that require special handling. */
430 1.1 christos /* Produce a word address for program memory. Linker scripts will put .text
431 1.1 christos at a high offset in order to differentiate it from .data. So here we also
432 1.1 christos mask the high bits of PMEM address.
433 1.1 christos
434 1.1 christos But why 1MB when internal Program Memory much smaller? We want to catch
435 1.1 christos unintended overflows.
436 1.1 christos
437 1.1 christos Why not use (1<<31) as an offset and a mask? Sitara DDRAM usually resides
438 1.1 christos there, and users might want to put some shared carveout memory region in
439 1.1 christos their linker scripts. So 0x80000000 might be a valid .data address.
440 1.1 christos
441 1.1 christos Note that we still keep and pass down the original howto. This way we
442 1.1 christos can reuse this function for several different relocations. */
443 1.1 christos static bfd_reloc_status_type
444 1.1 christos pru_elf32_do_pmem_relocate (bfd *abfd, reloc_howto_type *howto,
445 1.1 christos asection *input_section,
446 1.1 christos bfd_byte *data, bfd_vma offset,
447 1.1 christos bfd_vma symbol_value, bfd_vma addend)
448 1.1 christos {
449 1.1 christos symbol_value = symbol_value + addend;
450 1.1 christos addend = 0;
451 1.1 christos symbol_value &= 0x3fffff;
452 1.1 christos return _bfd_final_link_relocate (howto, abfd, input_section,
453 1.1 christos data, offset, symbol_value, addend);
454 1.1 christos }
455 1.1 christos
456 1.1 christos /* Direct copy of _bfd_final_link_relocate, but with special
457 1.1 christos "fill-in". This copy-paste mumbo jumbo is only needed because BFD
458 1.1 christos cannot deal correctly with non-contiguous bit fields. */
459 1.1 christos static bfd_reloc_status_type
460 1.1 christos pru_elf32_do_s10_pcrel_relocate (bfd *input_bfd, reloc_howto_type *howto,
461 1.1 christos asection *input_section,
462 1.1 christos bfd_byte *contents, bfd_vma address,
463 1.1 christos bfd_vma relocation, bfd_vma addend)
464 1.1 christos {
465 1.1 christos bfd_byte *location;
466 1.1 christos bfd_vma x = 0;
467 1.1 christos bfd_vma qboff;
468 1.1 christos bfd_reloc_status_type flag = bfd_reloc_ok;
469 1.1 christos
470 1.1 christos /* Sanity check the address. */
471 1.1 christos if (address > bfd_get_section_limit (input_bfd, input_section))
472 1.1 christos return bfd_reloc_outofrange;
473 1.1 christos
474 1.1 christos BFD_ASSERT (howto->pc_relative);
475 1.1 christos BFD_ASSERT (howto->pcrel_offset);
476 1.1 christos
477 1.1 christos relocation = relocation + addend - (input_section->output_section->vma
478 1.1 christos + input_section->output_offset) - address;
479 1.1 christos
480 1.1 christos location = contents + address;
481 1.1 christos
482 1.1 christos /* Get the value we are going to relocate. */
483 1.1 christos BFD_ASSERT (bfd_get_reloc_size (howto) == 4);
484 1.1 christos x = bfd_get_32 (input_bfd, location);
485 1.1 christos
486 1.1 christos qboff = GET_BROFF_SIGNED (x) << howto->rightshift;
487 1.1 christos relocation += qboff;
488 1.1 christos
489 1.1 christos BFD_ASSERT (howto->complain_on_overflow == complain_overflow_bitfield);
490 1.1 christos
491 1.1 christos if (relocation > 2047 && relocation < (bfd_vma)-2048l)
492 1.1 christos flag = bfd_reloc_overflow;
493 1.1 christos
494 1.1 christos /* Check that target address is word-aligned. */
495 1.1 christos if (relocation & ((1 << howto->rightshift) - 1))
496 1.1 christos flag = bfd_reloc_outofrange;
497 1.1 christos
498 1.1 christos relocation >>= (bfd_vma) howto->rightshift;
499 1.1 christos
500 1.1 christos /* Fill-in the RELOCATION to the right bits of X. */
501 1.1 christos SET_BROFF_URAW (x, relocation);
502 1.1 christos
503 1.1 christos bfd_put_32 (input_bfd, x, location);
504 1.1 christos
505 1.1 christos return flag;
506 1.1 christos }
507 1.1 christos
508 1.1 christos static bfd_reloc_status_type
509 1.1 christos pru_elf32_do_u8_pcrel_relocate (bfd *abfd, reloc_howto_type *howto,
510 1.1 christos asection *input_section,
511 1.1 christos bfd_byte *data, bfd_vma offset,
512 1.1 christos bfd_vma symbol_value, bfd_vma addend)
513 1.1 christos {
514 1.1 christos bfd_vma relocation;
515 1.1 christos
516 1.1 christos BFD_ASSERT (howto->pc_relative);
517 1.1 christos BFD_ASSERT (howto->pcrel_offset);
518 1.1 christos
519 1.1 christos relocation = symbol_value + addend - (input_section->output_section->vma
520 1.1 christos + input_section->output_offset) - offset;
521 1.1 christos relocation >>= howto->rightshift;
522 1.1 christos
523 1.1 christos /* 0 and 1 are invalid target labels for LOOP. We cannot
524 1.1 christos encode this info in HOWTO, so catch such cases here. */
525 1.1 christos if (relocation < 2)
526 1.1 christos return bfd_reloc_outofrange;
527 1.1 christos
528 1.1 christos return _bfd_final_link_relocate (howto, abfd, input_section,
529 1.1 christos data, offset, symbol_value, addend);
530 1.1 christos }
531 1.1 christos
532 1.1 christos /* Idea and code taken from elf32-d30v. */
533 1.1 christos static bfd_reloc_status_type
534 1.1 christos pru_elf32_do_ldi32_relocate (bfd *abfd, reloc_howto_type *howto,
535 1.1 christos asection *input_section,
536 1.1 christos bfd_byte *data, bfd_vma offset,
537 1.1 christos bfd_vma symbol_value, bfd_vma addend)
538 1.1 christos {
539 1.1 christos bfd_signed_vma relocation;
540 1.1 christos bfd_size_type octets = offset * bfd_octets_per_byte (abfd);
541 1.1 christos bfd_byte *location;
542 1.1.1.2 christos unsigned long in1, in2;
543 1.1 christos
544 1.1 christos /* A hacked-up version of _bfd_final_link_relocate() follows. */
545 1.1 christos
546 1.1 christos /* Sanity check the address. */
547 1.1 christos if (octets + bfd_get_reloc_size (howto)
548 1.1 christos > bfd_get_section_limit_octets (abfd, input_section))
549 1.1 christos return bfd_reloc_outofrange;
550 1.1 christos
551 1.1 christos /* This function assumes that we are dealing with a basic relocation
552 1.1 christos against a symbol. We want to compute the value of the symbol to
553 1.1 christos relocate to. This is just VALUE, the value of the symbol, plus
554 1.1 christos ADDEND, any addend associated with the reloc. */
555 1.1 christos relocation = symbol_value + addend;
556 1.1 christos
557 1.1 christos BFD_ASSERT (!howto->pc_relative);
558 1.1 christos
559 1.1 christos /* A hacked-up version of _bfd_relocate_contents() follows. */
560 1.1 christos location = data + offset * bfd_octets_per_byte (abfd);
561 1.1 christos
562 1.1 christos BFD_ASSERT (!howto->pc_relative);
563 1.1 christos
564 1.1 christos in1 = bfd_get_32 (abfd, location);
565 1.1 christos in2 = bfd_get_32 (abfd, location + 4);
566 1.1 christos
567 1.1.1.2 christos SET_INSN_FIELD (IMM16, in1, relocation >> 16);
568 1.1.1.2 christos SET_INSN_FIELD (IMM16, in2, relocation & 0xffff);
569 1.1 christos
570 1.1 christos bfd_put_32 (abfd, in1, location);
571 1.1 christos bfd_put_32 (abfd, in2, location + 4);
572 1.1 christos
573 1.1.1.2 christos /* Old GAS and LD versions have a bug, where the two
574 1.1.1.2 christos LDI instructions are swapped. Detect such object
575 1.1.1.2 christos files and bail. */
576 1.1.1.2 christos if (GET_INSN_FIELD (RDSEL, in1) != RSEL_31_16)
577 1.1.1.2 christos {
578 1.1.1.2 christos /* xgettext:c-format */
579 1.1.1.2 christos _bfd_error_handler (_("error: %pB: old incompatible object file detected"),
580 1.1.1.2 christos abfd);
581 1.1.1.2 christos return bfd_reloc_notsupported;
582 1.1.1.2 christos }
583 1.1.1.2 christos
584 1.1 christos return bfd_reloc_ok;
585 1.1 christos }
586 1.1 christos
587 1.1 christos /* HOWTO handlers for relocations that require special handling. */
588 1.1 christos
589 1.1 christos static bfd_reloc_status_type
590 1.1 christos pru_elf32_pmem_relocate (bfd *abfd, arelent *reloc_entry,
591 1.1 christos asymbol *symbol, void *data,
592 1.1 christos asection *input_section, bfd *output_bfd,
593 1.1 christos char **error_message)
594 1.1 christos {
595 1.1 christos /* If this is a relocatable link (output_bfd test tells us), just
596 1.1 christos call the generic function. Any adjustment will be done at final
597 1.1 christos link time. */
598 1.1 christos if (output_bfd != NULL)
599 1.1 christos return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
600 1.1 christos input_section, output_bfd, error_message);
601 1.1 christos
602 1.1.1.2 christos BFD_ASSERT (0);
603 1.1 christos return pru_elf32_do_pmem_relocate (abfd, reloc_entry->howto,
604 1.1 christos input_section,
605 1.1 christos data, reloc_entry->address,
606 1.1 christos (symbol->value
607 1.1 christos + symbol->section->output_section->vma
608 1.1 christos + symbol->section->output_offset),
609 1.1 christos reloc_entry->addend);
610 1.1 christos }
611 1.1 christos
612 1.1 christos static bfd_reloc_status_type
613 1.1 christos pru_elf32_s10_pcrel_relocate (bfd *abfd, arelent *reloc_entry,
614 1.1 christos asymbol *symbol, void *data,
615 1.1 christos asection *input_section, bfd *output_bfd,
616 1.1 christos char **error_message)
617 1.1 christos {
618 1.1 christos /* If this is a relocatable link (output_bfd test tells us), just
619 1.1 christos call the generic function. Any adjustment will be done at final
620 1.1 christos link time. */
621 1.1 christos if (output_bfd != NULL)
622 1.1 christos return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
623 1.1 christos input_section, output_bfd, error_message);
624 1.1 christos
625 1.1 christos return pru_elf32_do_s10_pcrel_relocate (abfd, reloc_entry->howto,
626 1.1 christos input_section, data,
627 1.1 christos reloc_entry->address,
628 1.1 christos (symbol->value
629 1.1 christos + symbol->section->output_section->vma
630 1.1 christos + symbol->section->output_offset),
631 1.1 christos reloc_entry->addend);
632 1.1 christos }
633 1.1 christos
634 1.1 christos static bfd_reloc_status_type
635 1.1 christos pru_elf32_u8_pcrel_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
636 1.1 christos void *data, asection *input_section,
637 1.1 christos bfd *output_bfd,
638 1.1 christos char **error_message)
639 1.1 christos {
640 1.1 christos /* If this is a relocatable link (output_bfd test tells us), just
641 1.1 christos call the generic function. Any adjustment will be done at final
642 1.1 christos link time. */
643 1.1 christos if (output_bfd != NULL)
644 1.1 christos return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
645 1.1 christos input_section, output_bfd, error_message);
646 1.1 christos
647 1.1 christos return pru_elf32_do_u8_pcrel_relocate (abfd, reloc_entry->howto,
648 1.1 christos input_section,
649 1.1 christos data, reloc_entry->address,
650 1.1 christos (symbol->value
651 1.1 christos + symbol->section->output_section->vma
652 1.1 christos + symbol->section->output_offset),
653 1.1 christos reloc_entry->addend);
654 1.1 christos }
655 1.1 christos
656 1.1 christos static bfd_reloc_status_type
657 1.1 christos pru_elf32_ldi32_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
658 1.1 christos void *data, asection *input_section,
659 1.1 christos bfd *output_bfd,
660 1.1 christos char **error_message)
661 1.1 christos {
662 1.1 christos /* If this is a relocatable link (output_bfd test tells us), just
663 1.1 christos call the generic function. Any adjustment will be done at final
664 1.1 christos link time. */
665 1.1 christos if (output_bfd != NULL)
666 1.1 christos return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
667 1.1 christos input_section, output_bfd, error_message);
668 1.1 christos
669 1.1 christos return pru_elf32_do_ldi32_relocate (abfd, reloc_entry->howto,
670 1.1 christos input_section,
671 1.1 christos data, reloc_entry->address,
672 1.1 christos (symbol->value
673 1.1 christos + symbol->section->output_section->vma
674 1.1 christos + symbol->section->output_offset),
675 1.1 christos reloc_entry->addend);
676 1.1 christos }
677 1.1 christos
678 1.1 christos
679 1.1 christos /* Implement elf_backend_relocate_section. */
680 1.1 christos static bfd_boolean
681 1.1 christos pru_elf32_relocate_section (bfd *output_bfd,
682 1.1 christos struct bfd_link_info *info,
683 1.1 christos bfd *input_bfd,
684 1.1 christos asection *input_section,
685 1.1 christos bfd_byte *contents,
686 1.1 christos Elf_Internal_Rela *relocs,
687 1.1 christos Elf_Internal_Sym *local_syms,
688 1.1 christos asection **local_sections)
689 1.1 christos {
690 1.1.1.2 christos struct bfd_elf_section_data * esd = elf_section_data (input_section);
691 1.1 christos Elf_Internal_Shdr *symtab_hdr;
692 1.1 christos struct elf_link_hash_entry **sym_hashes;
693 1.1 christos Elf_Internal_Rela *rel;
694 1.1 christos Elf_Internal_Rela *relend;
695 1.1.1.2 christos bfd_boolean is_rel_reloc;
696 1.1 christos
697 1.1 christos symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
698 1.1 christos sym_hashes = elf_sym_hashes (input_bfd);
699 1.1 christos relend = relocs + input_section->reloc_count;
700 1.1 christos
701 1.1.1.2 christos /* See if we have a REL type relocation. */
702 1.1.1.2 christos is_rel_reloc = (esd->rel.hdr != NULL);
703 1.1.1.2 christos /* Sanity check - only one type of relocation per section.
704 1.1.1.2 christos FIXME: Theoretically it is possible to have both types,
705 1.1.1.2 christos but if that happens how can we distinguish between the two ? */
706 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc || ! esd->rela.hdr);
707 1.1.1.2 christos
708 1.1 christos for (rel = relocs; rel < relend; rel++)
709 1.1 christos {
710 1.1 christos reloc_howto_type *howto;
711 1.1 christos unsigned long r_symndx;
712 1.1 christos Elf_Internal_Sym *sym;
713 1.1 christos asection *sec;
714 1.1 christos struct elf_link_hash_entry *h;
715 1.1 christos bfd_vma relocation;
716 1.1 christos bfd_reloc_status_type r = bfd_reloc_ok;
717 1.1 christos const char *name = NULL;
718 1.1 christos const char* msg = (const char*) NULL;
719 1.1 christos bfd_boolean unresolved_reloc;
720 1.1.1.2 christos bfd_vma addend;
721 1.1.1.2 christos
722 1.1.1.2 christos /* If we are using a REL relocation then the addend should be empty. */
723 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc || rel->r_addend == 0);
724 1.1 christos
725 1.1 christos r_symndx = ELF32_R_SYM (rel->r_info);
726 1.1 christos
727 1.1 christos howto = lookup_howto ((unsigned) ELF32_R_TYPE (rel->r_info));
728 1.1 christos h = NULL;
729 1.1 christos sym = NULL;
730 1.1 christos sec = NULL;
731 1.1 christos
732 1.1 christos if (r_symndx < symtab_hdr->sh_info)
733 1.1 christos {
734 1.1 christos sym = local_syms + r_symndx;
735 1.1 christos sec = local_sections[r_symndx];
736 1.1 christos relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
737 1.1 christos }
738 1.1 christos else
739 1.1 christos {
740 1.1 christos bfd_boolean warned, ignored;
741 1.1 christos
742 1.1 christos RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
743 1.1 christos r_symndx, symtab_hdr, sym_hashes,
744 1.1 christos h, sec, relocation,
745 1.1 christos unresolved_reloc, warned, ignored);
746 1.1 christos }
747 1.1 christos
748 1.1 christos if (sec && discarded_section (sec))
749 1.1 christos RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
750 1.1 christos rel, 1, relend, howto, 0, contents);
751 1.1 christos
752 1.1 christos /* Nothing more to do unless this is a final link. */
753 1.1 christos if (bfd_link_relocatable (info))
754 1.1 christos continue;
755 1.1 christos
756 1.1 christos if (howto)
757 1.1 christos {
758 1.1 christos switch (howto->type)
759 1.1 christos {
760 1.1 christos case R_PRU_NONE:
761 1.1 christos /* We don't need to find a value for this symbol. It's just a
762 1.1 christos marker. */
763 1.1 christos r = bfd_reloc_ok;
764 1.1 christos break;
765 1.1 christos
766 1.1.1.2 christos case R_PRU_U16:
767 1.1.1.2 christos if (is_rel_reloc)
768 1.1.1.2 christos {
769 1.1.1.2 christos unsigned long insn;
770 1.1.1.2 christos insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
771 1.1.1.2 christos addend = GET_INSN_FIELD (IMM16, insn);
772 1.1.1.2 christos }
773 1.1.1.2 christos else
774 1.1.1.2 christos addend = rel->r_addend;
775 1.1.1.2 christos r = _bfd_final_link_relocate (howto, input_bfd,
776 1.1.1.2 christos input_section, contents,
777 1.1.1.2 christos rel->r_offset, relocation,
778 1.1.1.2 christos addend);
779 1.1.1.2 christos break;
780 1.1.1.2 christos
781 1.1 christos case R_PRU_U16_PMEMIMM:
782 1.1 christos case R_PRU_32_PMEM:
783 1.1 christos case R_PRU_16_PMEM:
784 1.1.1.2 christos if (is_rel_reloc && howto->type == R_PRU_U16_PMEMIMM)
785 1.1.1.2 christos {
786 1.1.1.2 christos unsigned long insn;
787 1.1.1.2 christos insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
788 1.1.1.2 christos addend = GET_INSN_FIELD (IMM16, insn) << 2;
789 1.1.1.2 christos }
790 1.1.1.2 christos else if (is_rel_reloc && howto->type == R_PRU_32_PMEM)
791 1.1.1.2 christos {
792 1.1.1.2 christos addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
793 1.1.1.2 christos addend <<= 2;
794 1.1.1.2 christos }
795 1.1.1.2 christos else if (is_rel_reloc && howto->type == R_PRU_16_PMEM)
796 1.1.1.2 christos {
797 1.1.1.2 christos addend = bfd_get_16 (input_bfd, contents + rel->r_offset);
798 1.1.1.2 christos addend <<= 2;
799 1.1.1.2 christos }
800 1.1.1.2 christos else
801 1.1.1.2 christos {
802 1.1.1.2 christos BFD_ASSERT (!is_rel_reloc);
803 1.1.1.2 christos addend = rel->r_addend;
804 1.1.1.2 christos }
805 1.1 christos r = pru_elf32_do_pmem_relocate (input_bfd, howto,
806 1.1 christos input_section,
807 1.1 christos contents, rel->r_offset,
808 1.1.1.2 christos relocation, addend);
809 1.1 christos break;
810 1.1 christos case R_PRU_S10_PCREL:
811 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc);
812 1.1 christos r = pru_elf32_do_s10_pcrel_relocate (input_bfd, howto,
813 1.1 christos input_section,
814 1.1 christos contents,
815 1.1 christos rel->r_offset,
816 1.1 christos relocation,
817 1.1 christos rel->r_addend);
818 1.1 christos break;
819 1.1 christos case R_PRU_U8_PCREL:
820 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc);
821 1.1 christos r = pru_elf32_do_u8_pcrel_relocate (input_bfd, howto,
822 1.1 christos input_section,
823 1.1 christos contents,
824 1.1 christos rel->r_offset,
825 1.1 christos relocation,
826 1.1 christos rel->r_addend);
827 1.1 christos break;
828 1.1 christos case R_PRU_LDI32:
829 1.1.1.2 christos if (is_rel_reloc)
830 1.1.1.2 christos {
831 1.1.1.2 christos unsigned long in1, in2;
832 1.1.1.2 christos in1 = bfd_get_32 (input_bfd, contents + rel->r_offset);
833 1.1.1.2 christos in2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
834 1.1.1.2 christos addend = (GET_INSN_FIELD (IMM16, in1) << 16)
835 1.1.1.2 christos | GET_INSN_FIELD (IMM16, in2);
836 1.1.1.2 christos }
837 1.1.1.2 christos else
838 1.1.1.2 christos {
839 1.1.1.2 christos addend = rel->r_addend;
840 1.1.1.2 christos }
841 1.1 christos r = pru_elf32_do_ldi32_relocate (input_bfd, howto,
842 1.1 christos input_section,
843 1.1 christos contents,
844 1.1 christos rel->r_offset,
845 1.1 christos relocation,
846 1.1.1.2 christos addend);
847 1.1 christos break;
848 1.1 christos case R_PRU_GNU_DIFF8:
849 1.1 christos case R_PRU_GNU_DIFF16:
850 1.1 christos case R_PRU_GNU_DIFF32:
851 1.1 christos case R_PRU_GNU_DIFF16_PMEM:
852 1.1 christos case R_PRU_GNU_DIFF32_PMEM:
853 1.1.1.2 christos /* GNU extensions support only rela. */
854 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc);
855 1.1 christos /* Nothing to do here, as contents already contain the
856 1.1 christos diff value. */
857 1.1 christos r = bfd_reloc_ok;
858 1.1 christos break;
859 1.1 christos
860 1.1.1.2 christos case R_PRU_BFD_RELOC_16:
861 1.1.1.2 christos if (is_rel_reloc)
862 1.1.1.2 christos addend = bfd_get_16 (input_bfd, contents + rel->r_offset);
863 1.1.1.2 christos else
864 1.1.1.2 christos addend = rel->r_addend;
865 1.1.1.2 christos r = _bfd_final_link_relocate (howto, input_bfd,
866 1.1.1.2 christos input_section, contents,
867 1.1.1.2 christos rel->r_offset, relocation,
868 1.1.1.2 christos addend);
869 1.1.1.2 christos break;
870 1.1.1.2 christos
871 1.1.1.2 christos case R_PRU_BFD_RELOC_32:
872 1.1.1.2 christos if (is_rel_reloc)
873 1.1.1.2 christos addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
874 1.1.1.2 christos else
875 1.1.1.2 christos addend = rel->r_addend;
876 1.1.1.2 christos r = _bfd_final_link_relocate (howto, input_bfd,
877 1.1.1.2 christos input_section, contents,
878 1.1.1.2 christos rel->r_offset, relocation,
879 1.1.1.2 christos addend);
880 1.1.1.2 christos break;
881 1.1.1.2 christos
882 1.1.1.2 christos case R_PRU_GNU_BFD_RELOC_8:
883 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc);
884 1.1 christos r = _bfd_final_link_relocate (howto, input_bfd,
885 1.1 christos input_section, contents,
886 1.1 christos rel->r_offset, relocation,
887 1.1 christos rel->r_addend);
888 1.1 christos break;
889 1.1.1.2 christos
890 1.1.1.2 christos default:
891 1.1.1.2 christos BFD_ASSERT (0);
892 1.1.1.2 christos break;
893 1.1 christos }
894 1.1 christos }
895 1.1 christos else
896 1.1 christos r = bfd_reloc_notsupported;
897 1.1 christos
898 1.1 christos if (r != bfd_reloc_ok)
899 1.1 christos {
900 1.1 christos if (h != NULL)
901 1.1 christos name = h->root.root.string;
902 1.1 christos else
903 1.1 christos {
904 1.1 christos name = bfd_elf_string_from_elf_section (input_bfd,
905 1.1 christos symtab_hdr->sh_link,
906 1.1 christos sym->st_name);
907 1.1 christos if (name == NULL || *name == '\0')
908 1.1 christos name = bfd_section_name (input_bfd, sec);
909 1.1 christos }
910 1.1 christos
911 1.1 christos switch (r)
912 1.1 christos {
913 1.1 christos case bfd_reloc_overflow:
914 1.1 christos (*info->callbacks->reloc_overflow) (info, NULL, name,
915 1.1 christos howto->name, (bfd_vma) 0,
916 1.1 christos input_bfd, input_section,
917 1.1 christos rel->r_offset);
918 1.1 christos break;
919 1.1 christos
920 1.1 christos case bfd_reloc_undefined:
921 1.1 christos (*info->callbacks->undefined_symbol) (info, name, input_bfd,
922 1.1 christos input_section,
923 1.1 christos rel->r_offset, TRUE);
924 1.1 christos break;
925 1.1 christos
926 1.1 christos case bfd_reloc_outofrange:
927 1.1 christos if (msg == NULL)
928 1.1 christos msg = _("relocation out of range");
929 1.1 christos break;
930 1.1 christos
931 1.1 christos case bfd_reloc_notsupported:
932 1.1 christos if (msg == NULL)
933 1.1 christos msg = _("unsupported relocation");
934 1.1 christos break;
935 1.1 christos
936 1.1 christos case bfd_reloc_dangerous:
937 1.1 christos if (msg == NULL)
938 1.1 christos msg = _("dangerous relocation");
939 1.1 christos break;
940 1.1 christos
941 1.1 christos default:
942 1.1 christos if (msg == NULL)
943 1.1 christos msg = _("unknown error");
944 1.1 christos break;
945 1.1 christos }
946 1.1 christos
947 1.1 christos if (msg)
948 1.1 christos {
949 1.1 christos (*info->callbacks->warning) (info, msg, name, input_bfd,
950 1.1 christos input_section, rel->r_offset);
951 1.1 christos return FALSE;
952 1.1 christos }
953 1.1 christos }
954 1.1 christos }
955 1.1 christos return TRUE;
956 1.1 christos }
957 1.1 christos
958 1.1 christos
959 1.1 christos /* Perform a diff relocation. Nothing to do, as the difference value is
961 1.1 christos already written into the section's contents. */
962 1.1 christos
963 1.1 christos static bfd_reloc_status_type
964 1.1 christos bfd_elf_pru_diff_relocate (bfd *abfd ATTRIBUTE_UNUSED,
965 1.1 christos arelent *reloc_entry ATTRIBUTE_UNUSED,
966 1.1 christos asymbol *symbol ATTRIBUTE_UNUSED,
967 1.1 christos void *data ATTRIBUTE_UNUSED,
968 1.1 christos asection *input_section ATTRIBUTE_UNUSED,
969 1.1 christos bfd *output_bfd ATTRIBUTE_UNUSED,
970 1.1 christos char **error_message ATTRIBUTE_UNUSED)
971 1.1 christos {
972 1.1 christos return bfd_reloc_ok;
973 1.1 christos }
974 1.1 christos
975 1.1 christos
976 1.1 christos /* Returns whether the relocation type passed is a diff reloc. */
977 1.1 christos
978 1.1 christos static bfd_boolean
979 1.1 christos elf32_pru_is_diff_reloc (Elf_Internal_Rela *irel)
980 1.1 christos {
981 1.1 christos return (ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF8
982 1.1 christos || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16
983 1.1 christos || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32
984 1.1 christos || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16_PMEM
985 1.1 christos || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32_PMEM);
986 1.1 christos }
987 1.1 christos
988 1.1 christos /* Reduce the diff value written in the section by count if the shrinked
989 1.1 christos insn address happens to fall between the two symbols for which this
990 1.1 christos diff reloc was emitted. */
991 1.1 christos
992 1.1 christos static void
993 1.1 christos elf32_pru_adjust_diff_reloc_value (bfd *abfd,
994 1.1 christos struct bfd_section *isec,
995 1.1 christos Elf_Internal_Rela *irel,
996 1.1 christos bfd_vma symval,
997 1.1 christos bfd_vma shrinked_insn_address,
998 1.1 christos int count)
999 1.1 christos {
1000 1.1 christos unsigned char *reloc_contents = NULL;
1001 1.1 christos unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents;
1002 1.1 christos if (isec_contents == NULL)
1003 1.1 christos {
1004 1.1 christos if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents))
1005 1.1 christos return;
1006 1.1 christos
1007 1.1 christos elf_section_data (isec)->this_hdr.contents = isec_contents;
1008 1.1 christos }
1009 1.1 christos
1010 1.1 christos reloc_contents = isec_contents + irel->r_offset;
1011 1.1 christos
1012 1.1 christos /* Read value written in object file. */
1013 1.1 christos bfd_signed_vma x = 0;
1014 1.1 christos switch (ELF32_R_TYPE (irel->r_info))
1015 1.1 christos {
1016 1.1 christos case R_PRU_GNU_DIFF8:
1017 1.1 christos {
1018 1.1 christos x = bfd_get_signed_8 (abfd, reloc_contents);
1019 1.1 christos break;
1020 1.1 christos }
1021 1.1 christos case R_PRU_GNU_DIFF16:
1022 1.1 christos {
1023 1.1 christos x = bfd_get_signed_16 (abfd, reloc_contents);
1024 1.1 christos break;
1025 1.1 christos }
1026 1.1 christos case R_PRU_GNU_DIFF32:
1027 1.1 christos {
1028 1.1 christos x = bfd_get_signed_32 (abfd, reloc_contents);
1029 1.1 christos break;
1030 1.1 christos }
1031 1.1 christos case R_PRU_GNU_DIFF16_PMEM:
1032 1.1 christos {
1033 1.1 christos x = bfd_get_signed_16 (abfd, reloc_contents) * 4;
1034 1.1 christos break;
1035 1.1 christos }
1036 1.1 christos case R_PRU_GNU_DIFF32_PMEM:
1037 1.1 christos {
1038 1.1 christos x = bfd_get_signed_32 (abfd, reloc_contents) * 4;
1039 1.1 christos break;
1040 1.1 christos }
1041 1.1 christos default:
1042 1.1 christos {
1043 1.1 christos BFD_FAIL ();
1044 1.1 christos }
1045 1.1 christos }
1046 1.1 christos
1047 1.1 christos /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written
1048 1.1 christos into the object file at the reloc offset. sym2's logical value is
1049 1.1 christos symval (<start_of_section>) + reloc addend. Compute the start and end
1050 1.1 christos addresses and check if the shrinked insn falls between sym1 and sym2. */
1051 1.1 christos
1052 1.1 christos bfd_vma end_address = symval + irel->r_addend;
1053 1.1 christos bfd_vma start_address = end_address - x;
1054 1.1 christos
1055 1.1 christos /* Shrink the absolute DIFF value (get the to labels "closer"
1056 1.1 christos together), because we have removed data between labels. */
1057 1.1 christos if (x < 0)
1058 1.1 christos {
1059 1.1 christos x += count;
1060 1.1 christos /* In case the signed x is negative, restore order. */
1061 1.1 christos SWAP_VALS (end_address, start_address);
1062 1.1 christos }
1063 1.1 christos else
1064 1.1 christos {
1065 1.1 christos x -= count;
1066 1.1 christos }
1067 1.1 christos
1068 1.1 christos /* Reduce the diff value by count bytes and write it back into section
1069 1.1 christos contents. */
1070 1.1 christos
1071 1.1 christos if (shrinked_insn_address >= start_address
1072 1.1 christos && shrinked_insn_address <= end_address)
1073 1.1 christos {
1074 1.1 christos switch (ELF32_R_TYPE (irel->r_info))
1075 1.1 christos {
1076 1.1 christos case R_PRU_GNU_DIFF8:
1077 1.1 christos {
1078 1.1 christos bfd_put_signed_8 (abfd, x & 0xFF, reloc_contents);
1079 1.1 christos break;
1080 1.1 christos }
1081 1.1 christos case R_PRU_GNU_DIFF16:
1082 1.1 christos {
1083 1.1 christos bfd_put_signed_16 (abfd, x & 0xFFFF, reloc_contents);
1084 1.1 christos break;
1085 1.1 christos }
1086 1.1 christos case R_PRU_GNU_DIFF32:
1087 1.1 christos {
1088 1.1 christos bfd_put_signed_32 (abfd, x & 0xFFFFFFFF, reloc_contents);
1089 1.1 christos break;
1090 1.1 christos }
1091 1.1 christos case R_PRU_GNU_DIFF16_PMEM:
1092 1.1 christos {
1093 1.1 christos bfd_put_signed_16 (abfd, (x / 4) & 0xFFFF, reloc_contents);
1094 1.1 christos break;
1095 1.1 christos }
1096 1.1 christos case R_PRU_GNU_DIFF32_PMEM:
1097 1.1 christos {
1098 1.1 christos bfd_put_signed_32 (abfd, (x / 4) & 0xFFFFFFFF, reloc_contents);
1099 1.1 christos break;
1100 1.1 christos }
1101 1.1 christos default:
1102 1.1 christos {
1103 1.1 christos BFD_FAIL ();
1104 1.1 christos }
1105 1.1 christos }
1106 1.1 christos
1107 1.1 christos }
1108 1.1 christos }
1109 1.1 christos
1110 1.1 christos /* Delete some bytes from a section while changing the size of an instruction.
1111 1.1 christos The parameter "addr" denotes the section-relative offset pointing just
1112 1.1 christos behind the shrinked instruction. "addr+count" point at the first
1113 1.1 christos byte just behind the original unshrinked instruction.
1114 1.1 christos
1115 1.1 christos Idea copied from the AVR port. */
1116 1.1 christos
1117 1.1 christos static bfd_boolean
1118 1.1 christos pru_elf_relax_delete_bytes (bfd *abfd,
1119 1.1 christos asection *sec,
1120 1.1 christos bfd_vma addr,
1121 1.1 christos int count)
1122 1.1 christos {
1123 1.1 christos Elf_Internal_Shdr *symtab_hdr;
1124 1.1 christos unsigned int sec_shndx;
1125 1.1 christos bfd_byte *contents;
1126 1.1 christos Elf_Internal_Rela *irel, *irelend;
1127 1.1 christos Elf_Internal_Sym *isym;
1128 1.1 christos Elf_Internal_Sym *isymbuf = NULL;
1129 1.1 christos bfd_vma toaddr;
1130 1.1 christos struct elf_link_hash_entry **sym_hashes;
1131 1.1 christos struct elf_link_hash_entry **end_hashes;
1132 1.1 christos unsigned int symcount;
1133 1.1 christos
1134 1.1 christos symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
1135 1.1 christos sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
1136 1.1 christos contents = elf_section_data (sec)->this_hdr.contents;
1137 1.1 christos
1138 1.1 christos toaddr = sec->size;
1139 1.1 christos
1140 1.1 christos irel = elf_section_data (sec)->relocs;
1141 1.1 christos irelend = irel + sec->reloc_count;
1142 1.1 christos
1143 1.1 christos /* Actually delete the bytes. */
1144 1.1 christos if (toaddr - addr - count > 0)
1145 1.1 christos memmove (contents + addr, contents + addr + count,
1146 1.1 christos (size_t) (toaddr - addr - count));
1147 1.1 christos sec->size -= count;
1148 1.1 christos
1149 1.1 christos /* Adjust all the reloc addresses. */
1150 1.1 christos for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
1151 1.1 christos {
1152 1.1 christos bfd_vma old_reloc_address;
1153 1.1 christos
1154 1.1 christos old_reloc_address = (sec->output_section->vma
1155 1.1 christos + sec->output_offset + irel->r_offset);
1156 1.1 christos
1157 1.1 christos /* Get the new reloc address. */
1158 1.1 christos if ((irel->r_offset > addr
1159 1.1 christos && irel->r_offset < toaddr))
1160 1.1 christos {
1161 1.1 christos if (debug_relax)
1162 1.1 christos printf ("Relocation at address 0x%x needs to be moved.\n"
1163 1.1 christos "Old section offset: 0x%x, New section offset: 0x%x \n",
1164 1.1 christos (unsigned int) old_reloc_address,
1165 1.1 christos (unsigned int) irel->r_offset,
1166 1.1 christos (unsigned int) ((irel->r_offset) - count));
1167 1.1 christos
1168 1.1 christos irel->r_offset -= count;
1169 1.1 christos }
1170 1.1 christos
1171 1.1 christos }
1172 1.1 christos
1173 1.1 christos /* The reloc's own addresses are now ok. However, we need to readjust
1174 1.1 christos the reloc's addend, i.e. the reloc's value if two conditions are met:
1175 1.1 christos 1.) the reloc is relative to a symbol in this section that
1176 1.1 christos is located in front of the shrinked instruction
1177 1.1 christos 2.) symbol plus addend end up behind the shrinked instruction.
1178 1.1 christos
1179 1.1 christos The most common case where this happens are relocs relative to
1180 1.1 christos the section-start symbol.
1181 1.1 christos
1182 1.1 christos This step needs to be done for all of the sections of the bfd. */
1183 1.1 christos
1184 1.1 christos {
1185 1.1 christos struct bfd_section *isec;
1186 1.1 christos
1187 1.1 christos for (isec = abfd->sections; isec; isec = isec->next)
1188 1.1 christos {
1189 1.1 christos bfd_vma symval;
1190 1.1 christos bfd_vma shrinked_insn_address;
1191 1.1 christos
1192 1.1 christos if (isec->reloc_count == 0)
1193 1.1 christos continue;
1194 1.1 christos
1195 1.1.1.2 christos shrinked_insn_address = (sec->output_section->vma
1196 1.1 christos + sec->output_offset + addr);
1197 1.1 christos
1198 1.1 christos irel = elf_section_data (isec)->relocs;
1199 1.1 christos /* PR 12161: Read in the relocs for this section if necessary. */
1200 1.1 christos if (irel == NULL)
1201 1.1 christos irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE);
1202 1.1 christos
1203 1.1 christos for (irelend = irel + isec->reloc_count;
1204 1.1 christos irel < irelend;
1205 1.1 christos irel++)
1206 1.1 christos {
1207 1.1 christos /* Read this BFD's local symbols if we haven't done
1208 1.1 christos so already. */
1209 1.1 christos if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1210 1.1 christos {
1211 1.1 christos isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1212 1.1 christos if (isymbuf == NULL)
1213 1.1 christos isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1214 1.1 christos symtab_hdr->sh_info, 0,
1215 1.1 christos NULL, NULL, NULL);
1216 1.1 christos if (isymbuf == NULL)
1217 1.1 christos return FALSE;
1218 1.1 christos }
1219 1.1 christos
1220 1.1 christos /* Get the value of the symbol referred to by the reloc. */
1221 1.1 christos if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
1222 1.1 christos {
1223 1.1 christos /* A local symbol. */
1224 1.1 christos asection *sym_sec;
1225 1.1 christos
1226 1.1 christos isym = isymbuf + ELF32_R_SYM (irel->r_info);
1227 1.1 christos sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1228 1.1 christos symval = isym->st_value;
1229 1.1 christos /* If the reloc is absolute, it will not have
1230 1.1 christos a symbol or section associated with it. */
1231 1.1 christos if (sym_sec == sec)
1232 1.1 christos {
1233 1.1 christos symval += sym_sec->output_section->vma
1234 1.1 christos + sym_sec->output_offset;
1235 1.1 christos
1236 1.1 christos if (debug_relax)
1237 1.1 christos printf ("Checking if the relocation's "
1238 1.1 christos "addend needs corrections.\n"
1239 1.1 christos "Address of anchor symbol: 0x%x \n"
1240 1.1 christos "Address of relocation target: 0x%x \n"
1241 1.1 christos "Address of relaxed insn: 0x%x \n",
1242 1.1 christos (unsigned int) symval,
1243 1.1 christos (unsigned int) (symval + irel->r_addend),
1244 1.1 christos (unsigned int) shrinked_insn_address);
1245 1.1 christos
1246 1.1 christos /* Shrink the special DIFF relocations. */
1247 1.1 christos if (elf32_pru_is_diff_reloc (irel))
1248 1.1 christos {
1249 1.1 christos elf32_pru_adjust_diff_reloc_value (abfd, isec, irel,
1250 1.1 christos symval,
1251 1.1 christos shrinked_insn_address,
1252 1.1 christos count);
1253 1.1 christos }
1254 1.1 christos
1255 1.1 christos /* Fix the addend, if it is affected. */
1256 1.1 christos if (symval <= shrinked_insn_address
1257 1.1 christos && (symval + irel->r_addend) > shrinked_insn_address)
1258 1.1 christos {
1259 1.1 christos
1260 1.1 christos irel->r_addend -= count;
1261 1.1 christos
1262 1.1 christos if (debug_relax)
1263 1.1 christos printf ("Relocation's addend needed to be fixed \n");
1264 1.1 christos }
1265 1.1 christos }
1266 1.1 christos /* else...Reference symbol is absolute.
1267 1.1 christos No adjustment needed. */
1268 1.1 christos }
1269 1.1 christos /* else...Reference symbol is extern. No need for adjusting
1270 1.1 christos the addend. */
1271 1.1 christos }
1272 1.1 christos }
1273 1.1 christos }
1274 1.1 christos
1275 1.1 christos /* Adjust the local symbols defined in this section. */
1276 1.1 christos isym = (Elf_Internal_Sym *) symtab_hdr->contents;
1277 1.1 christos /* Fix PR 9841, there may be no local symbols. */
1278 1.1 christos if (isym != NULL)
1279 1.1 christos {
1280 1.1 christos Elf_Internal_Sym *isymend;
1281 1.1 christos
1282 1.1 christos isymend = isym + symtab_hdr->sh_info;
1283 1.1 christos for (; isym < isymend; isym++)
1284 1.1 christos {
1285 1.1 christos if (isym->st_shndx == sec_shndx)
1286 1.1 christos {
1287 1.1 christos if (isym->st_value > addr
1288 1.1 christos && isym->st_value <= toaddr)
1289 1.1 christos isym->st_value -= count;
1290 1.1 christos
1291 1.1 christos if (isym->st_value <= addr
1292 1.1 christos && isym->st_value + isym->st_size > addr)
1293 1.1 christos {
1294 1.1 christos /* If this assert fires then we have a symbol that ends
1295 1.1 christos part way through an instruction. Does that make
1296 1.1 christos sense? */
1297 1.1 christos BFD_ASSERT (isym->st_value + isym->st_size >= addr + count);
1298 1.1 christos isym->st_size -= count;
1299 1.1 christos }
1300 1.1 christos }
1301 1.1 christos }
1302 1.1 christos }
1303 1.1 christos
1304 1.1 christos /* Now adjust the global symbols defined in this section. */
1305 1.1 christos symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
1306 1.1 christos - symtab_hdr->sh_info);
1307 1.1 christos sym_hashes = elf_sym_hashes (abfd);
1308 1.1 christos end_hashes = sym_hashes + symcount;
1309 1.1 christos for (; sym_hashes < end_hashes; sym_hashes++)
1310 1.1 christos {
1311 1.1 christos struct elf_link_hash_entry *sym_hash = *sym_hashes;
1312 1.1 christos if ((sym_hash->root.type == bfd_link_hash_defined
1313 1.1 christos || sym_hash->root.type == bfd_link_hash_defweak)
1314 1.1 christos && sym_hash->root.u.def.section == sec)
1315 1.1 christos {
1316 1.1 christos if (sym_hash->root.u.def.value > addr
1317 1.1 christos && sym_hash->root.u.def.value <= toaddr)
1318 1.1 christos sym_hash->root.u.def.value -= count;
1319 1.1 christos
1320 1.1 christos if (sym_hash->root.u.def.value <= addr
1321 1.1 christos && (sym_hash->root.u.def.value + sym_hash->size > addr))
1322 1.1 christos {
1323 1.1 christos /* If this assert fires then we have a symbol that ends
1324 1.1 christos part way through an instruction. Does that make
1325 1.1 christos sense? */
1326 1.1 christos BFD_ASSERT (sym_hash->root.u.def.value + sym_hash->size
1327 1.1 christos >= addr + count);
1328 1.1 christos sym_hash->size -= count;
1329 1.1 christos }
1330 1.1 christos }
1331 1.1 christos }
1332 1.1 christos
1333 1.1 christos return TRUE;
1334 1.1 christos }
1335 1.1 christos
1336 1.1 christos static bfd_boolean
1337 1.1 christos pru_elf32_relax_section (bfd * abfd, asection * sec,
1338 1.1 christos struct bfd_link_info * link_info,
1339 1.1 christos bfd_boolean * again)
1340 1.1 christos {
1341 1.1 christos Elf_Internal_Shdr * symtab_hdr;
1342 1.1 christos Elf_Internal_Rela * internal_relocs;
1343 1.1 christos Elf_Internal_Rela * irel;
1344 1.1 christos Elf_Internal_Rela * irelend;
1345 1.1 christos bfd_byte * contents = NULL;
1346 1.1 christos Elf_Internal_Sym * isymbuf = NULL;
1347 1.1 christos
1348 1.1 christos /* Assume nothing changes. */
1349 1.1 christos *again = FALSE;
1350 1.1 christos
1351 1.1 christos /* We don't have to do anything for a relocatable link, if
1352 1.1 christos this section does not have relocs, or if this is not a
1353 1.1 christos code section. */
1354 1.1 christos if (bfd_link_relocatable (link_info)
1355 1.1 christos || (sec->flags & SEC_RELOC) == 0
1356 1.1 christos || sec->reloc_count == 0 || (sec->flags & SEC_CODE) == 0)
1357 1.1 christos return TRUE;
1358 1.1 christos
1359 1.1 christos symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
1360 1.1 christos
1361 1.1 christos /* Get a copy of the native relocations. */
1362 1.1 christos internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
1363 1.1 christos link_info->keep_memory);
1364 1.1 christos if (internal_relocs == NULL)
1365 1.1 christos goto error_return;
1366 1.1 christos
1367 1.1 christos /* Walk through them looking for relaxing opportunities. */
1368 1.1 christos irelend = internal_relocs + sec->reloc_count;
1369 1.1 christos
1370 1.1 christos for (irel = internal_relocs; irel < irelend; irel++)
1371 1.1 christos {
1372 1.1 christos bfd_vma symval;
1373 1.1 christos
1374 1.1 christos /* Get the section contents if we haven't done so already. */
1375 1.1 christos if (contents == NULL)
1376 1.1 christos {
1377 1.1 christos /* Get cached copy if it exists. */
1378 1.1 christos if (elf_section_data (sec)->this_hdr.contents != NULL)
1379 1.1 christos contents = elf_section_data (sec)->this_hdr.contents;
1380 1.1 christos else if (! bfd_malloc_and_get_section (abfd, sec, &contents))
1381 1.1 christos goto error_return;
1382 1.1 christos }
1383 1.1 christos
1384 1.1 christos /* Read this BFD's local symbols if we haven't done so already. */
1385 1.1 christos if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1386 1.1 christos {
1387 1.1 christos isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1388 1.1 christos if (isymbuf == NULL)
1389 1.1 christos isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1390 1.1 christos symtab_hdr->sh_info, 0,
1391 1.1 christos NULL, NULL, NULL);
1392 1.1 christos if (isymbuf == NULL)
1393 1.1 christos goto error_return;
1394 1.1 christos }
1395 1.1 christos
1396 1.1 christos /* Get the value of the symbol referred to by the reloc. */
1397 1.1 christos if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
1398 1.1 christos {
1399 1.1 christos /* A local symbol. */
1400 1.1 christos Elf_Internal_Sym *isym;
1401 1.1 christos asection *sym_sec;
1402 1.1 christos
1403 1.1 christos isym = isymbuf + ELF32_R_SYM (irel->r_info);
1404 1.1 christos if (isym->st_shndx == SHN_UNDEF)
1405 1.1 christos sym_sec = bfd_und_section_ptr;
1406 1.1 christos else if (isym->st_shndx == SHN_ABS)
1407 1.1 christos sym_sec = bfd_abs_section_ptr;
1408 1.1 christos else if (isym->st_shndx == SHN_COMMON)
1409 1.1 christos sym_sec = bfd_com_section_ptr;
1410 1.1 christos else
1411 1.1 christos sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1412 1.1 christos symval = (isym->st_value
1413 1.1 christos + sym_sec->output_section->vma + sym_sec->output_offset);
1414 1.1 christos }
1415 1.1 christos else
1416 1.1 christos {
1417 1.1 christos unsigned long indx;
1418 1.1 christos struct elf_link_hash_entry *h;
1419 1.1 christos
1420 1.1 christos /* An external symbol. */
1421 1.1 christos indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
1422 1.1 christos h = elf_sym_hashes (abfd)[indx];
1423 1.1 christos BFD_ASSERT (h != NULL);
1424 1.1 christos
1425 1.1 christos if (h->root.type != bfd_link_hash_defined
1426 1.1 christos && h->root.type != bfd_link_hash_defweak)
1427 1.1 christos /* This appears to be a reference to an undefined
1428 1.1 christos symbol. Just ignore it--it will be caught by the
1429 1.1 christos regular reloc processing. */
1430 1.1 christos continue;
1431 1.1 christos
1432 1.1 christos symval = (h->root.u.def.value
1433 1.1 christos + h->root.u.def.section->output_section->vma
1434 1.1 christos + h->root.u.def.section->output_offset);
1435 1.1 christos }
1436 1.1 christos
1437 1.1 christos /* For simplicity of coding, we are going to modify the section
1438 1.1 christos contents, the section relocs, and the BFD symbol table. We
1439 1.1 christos must tell the rest of the code not to free up this
1440 1.1 christos information. It would be possible to instead create a table
1441 1.1 christos of changes which have to be made, as is done in coff-mips.c;
1442 1.1 christos that would be more work, but would require less memory when
1443 1.1 christos the linker is run. */
1444 1.1 christos
1445 1.1 christos /* Check if we can remove an LDI instruction from the LDI32
1446 1.1 christos pseudo instruction if the upper 16 operand bits are zero. */
1447 1.1 christos if (ELF32_R_TYPE (irel->r_info) == (int) R_PRU_LDI32)
1448 1.1 christos {
1449 1.1 christos bfd_vma value = symval + irel->r_addend;
1450 1.1 christos
1451 1.1 christos if (debug_relax)
1452 1.1 christos printf ("R_PRU_LDI32 with value=0x%lx\n", (long) value);
1453 1.1 christos
1454 1.1 christos if ((long) value >> 16 == 0)
1455 1.1.1.2 christos {
1456 1.1.1.2 christos unsigned long insn;
1457 1.1 christos
1458 1.1 christos /* Note that we've changed the relocs, section contents. */
1459 1.1 christos elf_section_data (sec)->relocs = internal_relocs;
1460 1.1 christos elf_section_data (sec)->this_hdr.contents = contents;
1461 1.1 christos symtab_hdr->contents = (unsigned char *) isymbuf;
1462 1.1.1.2 christos
1463 1.1.1.2 christos /* Make the second instruction load the 16-bit constant
1464 1.1.1.2 christos into the full 32-bit register. */
1465 1.1.1.2 christos insn = bfd_get_32 (abfd, contents + irel->r_offset + 4);
1466 1.1.1.2 christos
1467 1.1.1.2 christos /* Old GAS and LD versions have a bug, where the two
1468 1.1.1.2 christos LDI instructions are swapped. Detect such object
1469 1.1.1.2 christos files and bail. */
1470 1.1.1.2 christos if (GET_INSN_FIELD (RDSEL, insn) != RSEL_15_0)
1471 1.1.1.2 christos {
1472 1.1.1.2 christos /* xgettext:c-format */
1473 1.1.1.2 christos _bfd_error_handler (_("error: %pB: old incompatible object file detected"),
1474 1.1.1.2 christos abfd);
1475 1.1.1.2 christos goto error_return;
1476 1.1.1.2 christos }
1477 1.1.1.2 christos
1478 1.1.1.2 christos SET_INSN_FIELD (RDSEL, insn, RSEL_31_0);
1479 1.1.1.2 christos bfd_put_32 (abfd, insn, contents + irel->r_offset + 4);
1480 1.1.1.2 christos
1481 1.1.1.2 christos /* Delete the first LDI instruction. Note that there should
1482 1.1.1.2 christos be no relocations or symbols pointing to the second LDI
1483 1.1.1.2 christos instruction. */
1484 1.1 christos if (!pru_elf_relax_delete_bytes (abfd, sec, irel->r_offset, 4))
1485 1.1 christos goto error_return;
1486 1.1.1.2 christos
1487 1.1.1.2 christos /* We're done with deletion of the first instruction.
1488 1.1 christos Set a regular LDI relocation for the second instruction
1489 1.1 christos we left to load the 16-bit value into the 32-bit
1490 1.1 christos register. */
1491 1.1 christos irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1492 1.1 christos R_PRU_U16);
1493 1.1 christos
1494 1.1 christos /* That will change things, so, we should relax again.
1495 1.1 christos Note that this is not required, and it may be slow. */
1496 1.1 christos *again = TRUE;
1497 1.1 christos }
1498 1.1 christos }
1499 1.1 christos }
1500 1.1 christos
1501 1.1 christos if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
1502 1.1 christos {
1503 1.1 christos if (!link_info->keep_memory)
1504 1.1 christos free (isymbuf);
1505 1.1 christos else
1506 1.1 christos {
1507 1.1 christos /* Cache the symbols for elf_link_input_bfd. */
1508 1.1 christos symtab_hdr->contents = (unsigned char *) isymbuf;
1509 1.1 christos }
1510 1.1 christos }
1511 1.1 christos
1512 1.1 christos if (contents != NULL
1513 1.1 christos && elf_section_data (sec)->this_hdr.contents != contents)
1514 1.1 christos {
1515 1.1 christos if (!link_info->keep_memory)
1516 1.1 christos free (contents);
1517 1.1 christos else
1518 1.1 christos {
1519 1.1 christos /* Cache the section contents for elf_link_input_bfd. */
1520 1.1 christos elf_section_data (sec)->this_hdr.contents = contents;
1521 1.1 christos }
1522 1.1 christos }
1523 1.1 christos
1524 1.1 christos if (internal_relocs != NULL
1525 1.1 christos && elf_section_data (sec)->relocs != internal_relocs)
1526 1.1 christos free (internal_relocs);
1527 1.1 christos
1528 1.1 christos return TRUE;
1529 1.1 christos
1530 1.1 christos error_return:
1531 1.1 christos if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
1532 1.1 christos free (isymbuf);
1533 1.1 christos if (contents != NULL
1534 1.1 christos && elf_section_data (sec)->this_hdr.contents != contents)
1535 1.1 christos free (contents);
1536 1.1 christos if (internal_relocs != NULL
1537 1.1 christos && elf_section_data (sec)->relocs != internal_relocs)
1538 1.1 christos free (internal_relocs);
1539 1.1 christos
1540 1.1 christos return FALSE;
1541 1.1 christos }
1542 1.1 christos
1543 1.1 christos /* Free the derived linker hash table. */
1544 1.1 christos static void
1545 1.1 christos pru_elf32_link_hash_table_free (bfd *obfd)
1546 1.1 christos {
1547 1.1 christos _bfd_elf_link_hash_table_free (obfd);
1548 1.1 christos }
1549 1.1 christos
1550 1.1 christos /* Implement bfd_elf32_bfd_link_hash_table_create. */
1551 1.1 christos static struct bfd_link_hash_table *
1552 1.1 christos pru_elf32_link_hash_table_create (bfd *abfd)
1553 1.1 christos {
1554 1.1 christos struct elf_link_hash_table *ret;
1555 1.1 christos bfd_size_type amt = sizeof (struct elf_link_hash_table);
1556 1.1 christos
1557 1.1 christos ret = bfd_zmalloc (amt);
1558 1.1 christos if (ret == NULL)
1559 1.1 christos return NULL;
1560 1.1 christos
1561 1.1 christos if (!_bfd_elf_link_hash_table_init (ret, abfd,
1562 1.1 christos link_hash_newfunc,
1563 1.1 christos sizeof (struct
1564 1.1 christos elf_link_hash_entry),
1565 1.1 christos PRU_ELF_DATA))
1566 1.1 christos {
1567 1.1 christos free (ret);
1568 1.1 christos return NULL;
1569 1.1 christos }
1570 1.1 christos
1571 1.1 christos ret->root.hash_table_free = pru_elf32_link_hash_table_free;
1572 1.1 christos
1573 1.1 christos return &ret->root;
1574 1.1 christos }
1575 1.1 christos
1576 1.1 christos #define ELF_ARCH bfd_arch_pru
1577 1.1 christos #define ELF_TARGET_ID PRU_ELF_DATA
1578 1.1 christos #define ELF_MACHINE_CODE EM_TI_PRU
1579 1.1 christos
1580 1.1 christos #define ELF_MAXPAGESIZE 1
1581 1.1 christos
1582 1.1 christos #define bfd_elf32_bfd_link_hash_table_create \
1583 1.1 christos pru_elf32_link_hash_table_create
1584 1.1 christos
1585 1.1 christos /* Relocation table lookup macros. */
1586 1.1 christos
1587 1.1 christos #define bfd_elf32_bfd_reloc_type_lookup pru_elf32_bfd_reloc_type_lookup
1588 1.1 christos #define bfd_elf32_bfd_reloc_name_lookup pru_elf32_bfd_reloc_name_lookup
1589 1.1 christos
1590 1.1.1.2 christos #define elf_info_to_howto pru_elf32_info_to_howto
1591 1.1 christos #define elf_info_to_howto_rel NULL
1592 1.1 christos
1593 1.1 christos /* elf backend functions. */
1594 1.1.1.2 christos
1595 1.1.1.2 christos /* TI folks like to use a mix of REL and RELA relocations. See also
1596 1.1.1.2 christos the MSP430 and TI C6X backends. */
1597 1.1.1.2 christos #define elf_backend_may_use_rel_p 1
1598 1.1.1.2 christos #define elf_backend_may_use_rela_p 1
1599 1.1.1.2 christos #define elf_backend_default_use_rela_p 1
1600 1.1 christos
1601 1.1 christos #define elf_backend_rela_normal 1
1602 1.1 christos
1603 1.1 christos #define elf_backend_relocate_section pru_elf32_relocate_section
1604 1.1 christos #define bfd_elf32_bfd_relax_section pru_elf32_relax_section
1605 1.1 christos
1606 1.1 christos #define TARGET_LITTLE_SYM pru_elf32_vec
1607 1.1 christos #define TARGET_LITTLE_NAME "elf32-pru"
1608 1.1 christos
1609 #include "elf32-target.h"
1610