1d2201f2fSdrahn /* MSP430-specific support for 32-bit ELF
2*cf2f2c56Smiod Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
3d2201f2fSdrahn Contributed by Dmitry Diky <diwil@mail.ru>
4d2201f2fSdrahn
5d2201f2fSdrahn This file is part of BFD, the Binary File Descriptor library.
6d2201f2fSdrahn
7d2201f2fSdrahn This program is free software; you can redistribute it and/or modify
8d2201f2fSdrahn it under the terms of the GNU General Public License as published by
9d2201f2fSdrahn the Free Software Foundation; either version 2 of the License, or
10d2201f2fSdrahn (at your option) any later version.
11d2201f2fSdrahn
12d2201f2fSdrahn This program is distributed in the hope that it will be useful,
13d2201f2fSdrahn but WITHOUT ANY WARRANTY; without even the implied warranty of
14d2201f2fSdrahn MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15d2201f2fSdrahn GNU General Public License for more details.
16d2201f2fSdrahn
17d2201f2fSdrahn You should have received a copy of the GNU General Public License
18d2201f2fSdrahn along with this program; if not, write to the Free Software
19d2201f2fSdrahn Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20d2201f2fSdrahn
21d2201f2fSdrahn #include "bfd.h"
22d2201f2fSdrahn #include "sysdep.h"
23d2201f2fSdrahn #include "libiberty.h"
24d2201f2fSdrahn #include "libbfd.h"
25d2201f2fSdrahn #include "elf-bfd.h"
26d2201f2fSdrahn #include "elf/msp430.h"
27d2201f2fSdrahn
28d2201f2fSdrahn static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
29d2201f2fSdrahn PARAMS ((bfd *, bfd_reloc_code_real_type));
30d2201f2fSdrahn
31d2201f2fSdrahn static void msp430_info_to_howto_rela
32d2201f2fSdrahn PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
33d2201f2fSdrahn
34d2201f2fSdrahn static asection *elf32_msp430_gc_mark_hook
35d2201f2fSdrahn PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
36d2201f2fSdrahn struct elf_link_hash_entry *, Elf_Internal_Sym *));
37d2201f2fSdrahn
38d2201f2fSdrahn static bfd_boolean elf32_msp430_gc_sweep_hook
39d2201f2fSdrahn PARAMS ((bfd *, struct bfd_link_info *, asection *,
40d2201f2fSdrahn const Elf_Internal_Rela *));
41d2201f2fSdrahn
42d2201f2fSdrahn static bfd_boolean elf32_msp430_check_relocs
43d2201f2fSdrahn PARAMS ((bfd *, struct bfd_link_info *, asection *,
44d2201f2fSdrahn const Elf_Internal_Rela *));
45d2201f2fSdrahn
46d2201f2fSdrahn static bfd_reloc_status_type msp430_final_link_relocate
47d2201f2fSdrahn PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *,
48d2201f2fSdrahn Elf_Internal_Rela *, bfd_vma));
49d2201f2fSdrahn
50d2201f2fSdrahn static bfd_boolean elf32_msp430_relocate_section
51d2201f2fSdrahn PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
52d2201f2fSdrahn Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
53d2201f2fSdrahn
54d2201f2fSdrahn static void bfd_elf_msp430_final_write_processing
55d2201f2fSdrahn PARAMS ((bfd *, bfd_boolean));
56d2201f2fSdrahn
57d2201f2fSdrahn static bfd_boolean elf32_msp430_object_p
58d2201f2fSdrahn PARAMS ((bfd *));
59d2201f2fSdrahn
60d2201f2fSdrahn static void elf32_msp430_post_process_headers
61d2201f2fSdrahn PARAMS ((bfd *, struct bfd_link_info *));
62d2201f2fSdrahn
63d2201f2fSdrahn /* Use RELA instead of REL. */
64d2201f2fSdrahn #undef USE_REL
65d2201f2fSdrahn
66d2201f2fSdrahn static reloc_howto_type elf_msp430_howto_table[] =
67d2201f2fSdrahn {
68d2201f2fSdrahn HOWTO (R_MSP430_NONE, /* type */
69d2201f2fSdrahn 0, /* rightshift */
70d2201f2fSdrahn 2, /* size (0 = byte, 1 = short, 2 = long) */
71d2201f2fSdrahn 32, /* bitsize */
72d2201f2fSdrahn FALSE, /* pc_relative */
73d2201f2fSdrahn 0, /* bitpos */
74d2201f2fSdrahn complain_overflow_bitfield, /* complain_on_overflow */
75d2201f2fSdrahn bfd_elf_generic_reloc, /* special_function */
76d2201f2fSdrahn "R_MSP430_NONE", /* name */
77d2201f2fSdrahn FALSE, /* partial_inplace */
78d2201f2fSdrahn 0, /* src_mask */
79d2201f2fSdrahn 0, /* dst_mask */
80d2201f2fSdrahn FALSE), /* pcrel_offset */
81d2201f2fSdrahn
82d2201f2fSdrahn HOWTO (R_MSP430_32, /* type */
83d2201f2fSdrahn 0, /* rightshift */
84d2201f2fSdrahn 2, /* size (0 = byte, 1 = short, 2 = long) */
85d2201f2fSdrahn 32, /* bitsize */
86d2201f2fSdrahn FALSE, /* pc_relative */
87d2201f2fSdrahn 0, /* bitpos */
88d2201f2fSdrahn complain_overflow_bitfield, /* complain_on_overflow */
89d2201f2fSdrahn bfd_elf_generic_reloc, /* special_function */
90d2201f2fSdrahn "R_MSP430_32", /* name */
91d2201f2fSdrahn FALSE, /* partial_inplace */
92d2201f2fSdrahn 0xffffffff, /* src_mask */
93d2201f2fSdrahn 0xffffffff, /* dst_mask */
94d2201f2fSdrahn FALSE), /* pcrel_offset */
95d2201f2fSdrahn
96d2201f2fSdrahn /* A 13 bit PC relative relocation. */
97d2201f2fSdrahn HOWTO (R_MSP430_10_PCREL, /* type */
98d2201f2fSdrahn 1, /* rightshift */
99d2201f2fSdrahn 1, /* size (0 = byte, 1 = short, 2 = long) */
100d2201f2fSdrahn 10, /* bitsize */
101d2201f2fSdrahn TRUE, /* pc_relative */
102d2201f2fSdrahn 0, /* bitpos */
103d2201f2fSdrahn complain_overflow_bitfield, /* complain_on_overflow */
104d2201f2fSdrahn bfd_elf_generic_reloc, /* special_function */
105d2201f2fSdrahn "R_MSP430_13_PCREL", /* name */
106d2201f2fSdrahn FALSE, /* partial_inplace */
107d2201f2fSdrahn 0xfff, /* src_mask */
108d2201f2fSdrahn 0xfff, /* dst_mask */
109d2201f2fSdrahn TRUE), /* pcrel_offset */
110d2201f2fSdrahn
111d2201f2fSdrahn /* A 16 bit absolute relocation. */
112d2201f2fSdrahn HOWTO (R_MSP430_16, /* type */
113d2201f2fSdrahn 0, /* rightshift */
114d2201f2fSdrahn 1, /* size (0 = byte, 1 = short, 2 = long) */
115d2201f2fSdrahn 16, /* bitsize */
116d2201f2fSdrahn FALSE, /* pc_relative */
117d2201f2fSdrahn 0, /* bitpos */
118d2201f2fSdrahn complain_overflow_dont,/* complain_on_overflow */
119d2201f2fSdrahn bfd_elf_generic_reloc, /* special_function */
120d2201f2fSdrahn "R_MSP430_16", /* name */
121d2201f2fSdrahn FALSE, /* partial_inplace */
122d2201f2fSdrahn 0xffff, /* src_mask */
123d2201f2fSdrahn 0xffff, /* dst_mask */
124d2201f2fSdrahn FALSE), /* pcrel_offset */
125d2201f2fSdrahn
126d2201f2fSdrahn /* A 16 bit absolute relocation for command address. */
127d2201f2fSdrahn HOWTO (R_MSP430_16_PCREL, /* type */
128d2201f2fSdrahn 1, /* rightshift */
129d2201f2fSdrahn 1, /* size (0 = byte, 1 = short, 2 = long) */
130d2201f2fSdrahn 16, /* bitsize */
131d2201f2fSdrahn TRUE, /* pc_relative */
132d2201f2fSdrahn 0, /* bitpos */
133d2201f2fSdrahn complain_overflow_dont,/* complain_on_overflow */
134d2201f2fSdrahn bfd_elf_generic_reloc, /* special_function */
135d2201f2fSdrahn "R_MSP430_16_PCREL", /* name */
136d2201f2fSdrahn FALSE, /* partial_inplace */
137d2201f2fSdrahn 0xffff, /* src_mask */
138d2201f2fSdrahn 0xffff, /* dst_mask */
139d2201f2fSdrahn TRUE), /* pcrel_offset */
140d2201f2fSdrahn
141d2201f2fSdrahn /* A 16 bit absolute relocation, byte operations. */
142d2201f2fSdrahn HOWTO (R_MSP430_16_BYTE, /* type */
143d2201f2fSdrahn 0, /* rightshift */
144d2201f2fSdrahn 1, /* size (0 = byte, 1 = short, 2 = long) */
145d2201f2fSdrahn 16, /* bitsize */
146d2201f2fSdrahn FALSE, /* pc_relative */
147d2201f2fSdrahn 0, /* bitpos */
148d2201f2fSdrahn complain_overflow_dont,/* complain_on_overflow */
149d2201f2fSdrahn bfd_elf_generic_reloc, /* special_function */
150d2201f2fSdrahn "R_MSP430_16_BYTE", /* name */
151d2201f2fSdrahn FALSE, /* partial_inplace */
152d2201f2fSdrahn 0xffff, /* src_mask */
153d2201f2fSdrahn 0xffff, /* dst_mask */
154d2201f2fSdrahn FALSE), /* pcrel_offset */
155d2201f2fSdrahn
156d2201f2fSdrahn /* A 16 bit absolute relocation for command address. */
157d2201f2fSdrahn HOWTO (R_MSP430_16_PCREL_BYTE,/* type */
158d2201f2fSdrahn 1, /* rightshift */
159d2201f2fSdrahn 1, /* size (0 = byte, 1 = short, 2 = long) */
160d2201f2fSdrahn 16, /* bitsize */
161d2201f2fSdrahn TRUE, /* pc_relative */
162d2201f2fSdrahn 0, /* bitpos */
163d2201f2fSdrahn complain_overflow_dont,/* complain_on_overflow */
164d2201f2fSdrahn bfd_elf_generic_reloc, /* special_function */
165d2201f2fSdrahn "R_MSP430_16_PCREL_BYTE", /* name */
166d2201f2fSdrahn FALSE, /* partial_inplace */
167d2201f2fSdrahn 0xffff, /* src_mask */
168d2201f2fSdrahn 0xffff, /* dst_mask */
169d2201f2fSdrahn TRUE) /* pcrel_offset */
170d2201f2fSdrahn };
171d2201f2fSdrahn
172d2201f2fSdrahn /* Map BFD reloc types to MSP430 ELF reloc types. */
173d2201f2fSdrahn
174d2201f2fSdrahn struct msp430_reloc_map
175d2201f2fSdrahn {
176d2201f2fSdrahn bfd_reloc_code_real_type bfd_reloc_val;
177d2201f2fSdrahn unsigned int elf_reloc_val;
178d2201f2fSdrahn };
179d2201f2fSdrahn
180d2201f2fSdrahn static const struct msp430_reloc_map msp430_reloc_map[] =
181d2201f2fSdrahn {
182d2201f2fSdrahn {BFD_RELOC_NONE, R_MSP430_NONE},
183d2201f2fSdrahn {BFD_RELOC_32, R_MSP430_32},
184d2201f2fSdrahn {BFD_RELOC_MSP430_10_PCREL, R_MSP430_10_PCREL},
185d2201f2fSdrahn {BFD_RELOC_16, R_MSP430_16_BYTE},
186d2201f2fSdrahn {BFD_RELOC_MSP430_16_PCREL, R_MSP430_16_PCREL},
187d2201f2fSdrahn {BFD_RELOC_MSP430_16, R_MSP430_16},
188d2201f2fSdrahn {BFD_RELOC_MSP430_16_PCREL_BYTE, R_MSP430_16_PCREL_BYTE},
189d2201f2fSdrahn {BFD_RELOC_MSP430_16_BYTE, R_MSP430_16_BYTE}
190d2201f2fSdrahn };
191d2201f2fSdrahn
192d2201f2fSdrahn static reloc_howto_type *
bfd_elf32_bfd_reloc_type_lookup(abfd,code)193d2201f2fSdrahn bfd_elf32_bfd_reloc_type_lookup (abfd, code)
194d2201f2fSdrahn bfd *abfd ATTRIBUTE_UNUSED;
195d2201f2fSdrahn bfd_reloc_code_real_type code;
196d2201f2fSdrahn {
197d2201f2fSdrahn unsigned int i;
198d2201f2fSdrahn
199d2201f2fSdrahn for (i = 0; i < ARRAY_SIZE (msp430_reloc_map); i++)
200d2201f2fSdrahn if (msp430_reloc_map[i].bfd_reloc_val == code)
201d2201f2fSdrahn return &elf_msp430_howto_table[msp430_reloc_map[i].elf_reloc_val];
202d2201f2fSdrahn
203d2201f2fSdrahn return NULL;
204d2201f2fSdrahn }
205d2201f2fSdrahn
206d2201f2fSdrahn /* Set the howto pointer for an MSP430 ELF reloc. */
207d2201f2fSdrahn
208d2201f2fSdrahn static void
msp430_info_to_howto_rela(abfd,cache_ptr,dst)209d2201f2fSdrahn msp430_info_to_howto_rela (abfd, cache_ptr, dst)
210d2201f2fSdrahn bfd *abfd ATTRIBUTE_UNUSED;
211d2201f2fSdrahn arelent *cache_ptr;
212d2201f2fSdrahn Elf_Internal_Rela *dst;
213d2201f2fSdrahn {
214d2201f2fSdrahn unsigned int r_type;
215d2201f2fSdrahn
216d2201f2fSdrahn r_type = ELF32_R_TYPE (dst->r_info);
217d2201f2fSdrahn BFD_ASSERT (r_type < (unsigned int) R_MSP430_max);
218d2201f2fSdrahn cache_ptr->howto = &elf_msp430_howto_table[r_type];
219d2201f2fSdrahn }
220d2201f2fSdrahn
221d2201f2fSdrahn static asection *
elf32_msp430_gc_mark_hook(sec,info,rel,h,sym)222d2201f2fSdrahn elf32_msp430_gc_mark_hook (sec, info, rel, h, sym)
223d2201f2fSdrahn asection *sec;
224d2201f2fSdrahn struct bfd_link_info *info ATTRIBUTE_UNUSED;
225d2201f2fSdrahn Elf_Internal_Rela *rel;
226d2201f2fSdrahn struct elf_link_hash_entry *h;
227d2201f2fSdrahn Elf_Internal_Sym *sym;
228d2201f2fSdrahn {
229d2201f2fSdrahn if (h != NULL)
230d2201f2fSdrahn {
231d2201f2fSdrahn switch (ELF32_R_TYPE (rel->r_info))
232d2201f2fSdrahn {
233d2201f2fSdrahn default:
234d2201f2fSdrahn switch (h->root.type)
235d2201f2fSdrahn {
236d2201f2fSdrahn case bfd_link_hash_defined:
237d2201f2fSdrahn case bfd_link_hash_defweak:
238d2201f2fSdrahn return h->root.u.def.section;
239d2201f2fSdrahn
240d2201f2fSdrahn case bfd_link_hash_common:
241d2201f2fSdrahn return h->root.u.c.p->section;
242d2201f2fSdrahn
243d2201f2fSdrahn default:
244d2201f2fSdrahn break;
245d2201f2fSdrahn }
246d2201f2fSdrahn }
247d2201f2fSdrahn }
248d2201f2fSdrahn else
249d2201f2fSdrahn return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
250d2201f2fSdrahn
251d2201f2fSdrahn return NULL;
252d2201f2fSdrahn }
253d2201f2fSdrahn
254d2201f2fSdrahn static bfd_boolean
elf32_msp430_gc_sweep_hook(abfd,info,sec,relocs)255d2201f2fSdrahn elf32_msp430_gc_sweep_hook (abfd, info, sec, relocs)
256d2201f2fSdrahn bfd *abfd ATTRIBUTE_UNUSED;
257d2201f2fSdrahn struct bfd_link_info *info ATTRIBUTE_UNUSED;
258d2201f2fSdrahn asection *sec ATTRIBUTE_UNUSED;
259d2201f2fSdrahn const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
260d2201f2fSdrahn {
261d2201f2fSdrahn /* We don't use got and plt entries for msp430. */
262d2201f2fSdrahn return TRUE;
263d2201f2fSdrahn }
264d2201f2fSdrahn
265d2201f2fSdrahn /* Look through the relocs for a section during the first phase.
266d2201f2fSdrahn Since we don't do .gots or .plts, we just need to consider the
267d2201f2fSdrahn virtual table relocs for gc. */
268d2201f2fSdrahn
269d2201f2fSdrahn static bfd_boolean
elf32_msp430_check_relocs(abfd,info,sec,relocs)270d2201f2fSdrahn elf32_msp430_check_relocs (abfd, info, sec, relocs)
271d2201f2fSdrahn bfd *abfd;
272d2201f2fSdrahn struct bfd_link_info *info;
273d2201f2fSdrahn asection *sec;
274d2201f2fSdrahn const Elf_Internal_Rela *relocs;
275d2201f2fSdrahn {
276d2201f2fSdrahn Elf_Internal_Shdr *symtab_hdr;
277d2201f2fSdrahn struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
278d2201f2fSdrahn const Elf_Internal_Rela *rel;
279d2201f2fSdrahn const Elf_Internal_Rela *rel_end;
280d2201f2fSdrahn
281*cf2f2c56Smiod if (info->relocatable)
282d2201f2fSdrahn return TRUE;
283d2201f2fSdrahn
284d2201f2fSdrahn symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
285d2201f2fSdrahn sym_hashes = elf_sym_hashes (abfd);
286d2201f2fSdrahn sym_hashes_end =
287d2201f2fSdrahn sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
288d2201f2fSdrahn if (!elf_bad_symtab (abfd))
289d2201f2fSdrahn sym_hashes_end -= symtab_hdr->sh_info;
290d2201f2fSdrahn
291d2201f2fSdrahn rel_end = relocs + sec->reloc_count;
292d2201f2fSdrahn for (rel = relocs; rel < rel_end; rel++)
293d2201f2fSdrahn {
294d2201f2fSdrahn struct elf_link_hash_entry *h;
295d2201f2fSdrahn unsigned long r_symndx;
296d2201f2fSdrahn
297d2201f2fSdrahn r_symndx = ELF32_R_SYM (rel->r_info);
298d2201f2fSdrahn if (r_symndx < symtab_hdr->sh_info)
299d2201f2fSdrahn h = NULL;
300d2201f2fSdrahn else
301d2201f2fSdrahn h = sym_hashes[r_symndx - symtab_hdr->sh_info];
302d2201f2fSdrahn }
303d2201f2fSdrahn
304d2201f2fSdrahn return TRUE;
305d2201f2fSdrahn }
306d2201f2fSdrahn
307d2201f2fSdrahn /* Perform a single relocation. By default we use the standard BFD
308d2201f2fSdrahn routines, but a few relocs, we have to do them ourselves. */
309d2201f2fSdrahn
310d2201f2fSdrahn static bfd_reloc_status_type
msp430_final_link_relocate(howto,input_bfd,input_section,contents,rel,relocation)311d2201f2fSdrahn msp430_final_link_relocate (howto, input_bfd, input_section,
312d2201f2fSdrahn contents, rel, relocation)
313d2201f2fSdrahn reloc_howto_type *howto;
314d2201f2fSdrahn bfd *input_bfd;
315d2201f2fSdrahn asection *input_section;
316d2201f2fSdrahn bfd_byte *contents;
317d2201f2fSdrahn Elf_Internal_Rela *rel;
318d2201f2fSdrahn bfd_vma relocation;
319d2201f2fSdrahn {
320d2201f2fSdrahn bfd_reloc_status_type r = bfd_reloc_ok;
321d2201f2fSdrahn bfd_vma x;
322d2201f2fSdrahn bfd_signed_vma srel;
323d2201f2fSdrahn
324d2201f2fSdrahn switch (howto->type)
325d2201f2fSdrahn {
326d2201f2fSdrahn case R_MSP430_10_PCREL:
327d2201f2fSdrahn contents += rel->r_offset;
328d2201f2fSdrahn srel = (bfd_signed_vma) relocation;
329d2201f2fSdrahn srel += rel->r_addend;
330d2201f2fSdrahn srel -= rel->r_offset;
331d2201f2fSdrahn srel -= 2; /* Branch instructions add 2 to the PC... */
332d2201f2fSdrahn srel -= (input_section->output_section->vma +
333d2201f2fSdrahn input_section->output_offset);
334d2201f2fSdrahn
335d2201f2fSdrahn if (srel & 1)
336d2201f2fSdrahn return bfd_reloc_outofrange;
337d2201f2fSdrahn
338d2201f2fSdrahn /* MSP430 addresses commands as words. */
339d2201f2fSdrahn srel >>= 1;
340d2201f2fSdrahn
341d2201f2fSdrahn /* Check for an overflow. */
342d2201f2fSdrahn if (srel < -512 || srel > 511)
343d2201f2fSdrahn return bfd_reloc_overflow;
344d2201f2fSdrahn
345d2201f2fSdrahn x = bfd_get_16 (input_bfd, contents);
346d2201f2fSdrahn x = (x & 0xfc00) | (srel & 0x3ff);
347d2201f2fSdrahn bfd_put_16 (input_bfd, x, contents);
348d2201f2fSdrahn break;
349d2201f2fSdrahn
350d2201f2fSdrahn case R_MSP430_16_PCREL:
351d2201f2fSdrahn contents += rel->r_offset;
352d2201f2fSdrahn srel = (bfd_signed_vma) relocation;
353d2201f2fSdrahn srel += rel->r_addend;
354d2201f2fSdrahn srel -= rel->r_offset;
355d2201f2fSdrahn /* Only branch instructions add 2 to the PC... */
356d2201f2fSdrahn srel -= (input_section->output_section->vma +
357d2201f2fSdrahn input_section->output_offset);
358d2201f2fSdrahn
359d2201f2fSdrahn if (srel & 1)
360d2201f2fSdrahn return bfd_reloc_outofrange;
361d2201f2fSdrahn
362d2201f2fSdrahn bfd_put_16 (input_bfd, srel & 0xffff, contents);
363d2201f2fSdrahn break;
364d2201f2fSdrahn
365d2201f2fSdrahn case R_MSP430_16_PCREL_BYTE:
366d2201f2fSdrahn contents += rel->r_offset;
367d2201f2fSdrahn srel = (bfd_signed_vma) relocation;
368d2201f2fSdrahn srel += rel->r_addend;
369d2201f2fSdrahn srel -= rel->r_offset;
370d2201f2fSdrahn /* Only branch instructions add 2 to the PC... */
371d2201f2fSdrahn srel -= (input_section->output_section->vma +
372d2201f2fSdrahn input_section->output_offset);
373d2201f2fSdrahn
374d2201f2fSdrahn bfd_put_16 (input_bfd, srel & 0xffff, contents);
375d2201f2fSdrahn break;
376d2201f2fSdrahn
377d2201f2fSdrahn case R_MSP430_16_BYTE:
378d2201f2fSdrahn contents += rel->r_offset;
379d2201f2fSdrahn srel = (bfd_signed_vma) relocation;
380d2201f2fSdrahn srel += rel->r_addend;
381d2201f2fSdrahn bfd_put_16 (input_bfd, srel & 0xffff, contents);
382d2201f2fSdrahn break;
383d2201f2fSdrahn
384d2201f2fSdrahn case R_MSP430_16:
385d2201f2fSdrahn contents += rel->r_offset;
386d2201f2fSdrahn srel = (bfd_signed_vma) relocation;
387d2201f2fSdrahn srel += rel->r_addend;
388d2201f2fSdrahn
389d2201f2fSdrahn if (srel & 1)
390d2201f2fSdrahn return bfd_reloc_notsupported;
391d2201f2fSdrahn
392d2201f2fSdrahn bfd_put_16 (input_bfd, srel & 0xffff, contents);
393d2201f2fSdrahn break;
394d2201f2fSdrahn
395d2201f2fSdrahn default:
396d2201f2fSdrahn r = _bfd_final_link_relocate (howto, input_bfd, input_section,
397d2201f2fSdrahn contents, rel->r_offset,
398d2201f2fSdrahn relocation, rel->r_addend);
399d2201f2fSdrahn }
400d2201f2fSdrahn
401d2201f2fSdrahn return r;
402d2201f2fSdrahn }
403d2201f2fSdrahn
404d2201f2fSdrahn /* Relocate an MSP430 ELF section. */
405d2201f2fSdrahn
406d2201f2fSdrahn static bfd_boolean
elf32_msp430_relocate_section(output_bfd,info,input_bfd,input_section,contents,relocs,local_syms,local_sections)407d2201f2fSdrahn elf32_msp430_relocate_section (output_bfd, info, input_bfd, input_section,
408d2201f2fSdrahn contents, relocs, local_syms, local_sections)
409d2201f2fSdrahn bfd *output_bfd ATTRIBUTE_UNUSED;
410d2201f2fSdrahn struct bfd_link_info *info;
411d2201f2fSdrahn bfd *input_bfd;
412d2201f2fSdrahn asection *input_section;
413d2201f2fSdrahn bfd_byte *contents;
414d2201f2fSdrahn Elf_Internal_Rela *relocs;
415d2201f2fSdrahn Elf_Internal_Sym *local_syms;
416d2201f2fSdrahn asection **local_sections;
417d2201f2fSdrahn {
418d2201f2fSdrahn Elf_Internal_Shdr *symtab_hdr;
419d2201f2fSdrahn struct elf_link_hash_entry **sym_hashes;
420d2201f2fSdrahn Elf_Internal_Rela *rel;
421d2201f2fSdrahn Elf_Internal_Rela *relend;
422d2201f2fSdrahn
423d2201f2fSdrahn symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
424d2201f2fSdrahn sym_hashes = elf_sym_hashes (input_bfd);
425d2201f2fSdrahn relend = relocs + input_section->reloc_count;
426d2201f2fSdrahn
427d2201f2fSdrahn for (rel = relocs; rel < relend; rel++)
428d2201f2fSdrahn {
429d2201f2fSdrahn reloc_howto_type *howto;
430d2201f2fSdrahn unsigned long r_symndx;
431d2201f2fSdrahn Elf_Internal_Sym *sym;
432d2201f2fSdrahn asection *sec;
433d2201f2fSdrahn struct elf_link_hash_entry *h;
434d2201f2fSdrahn bfd_vma relocation;
435d2201f2fSdrahn bfd_reloc_status_type r;
436d2201f2fSdrahn const char *name = NULL;
437d2201f2fSdrahn int r_type;
438d2201f2fSdrahn
439d2201f2fSdrahn /* This is a final link. */
440d2201f2fSdrahn
441d2201f2fSdrahn r_type = ELF32_R_TYPE (rel->r_info);
442d2201f2fSdrahn r_symndx = ELF32_R_SYM (rel->r_info);
443d2201f2fSdrahn howto = elf_msp430_howto_table + ELF32_R_TYPE (rel->r_info);
444d2201f2fSdrahn h = NULL;
445d2201f2fSdrahn sym = NULL;
446d2201f2fSdrahn sec = NULL;
447d2201f2fSdrahn
448d2201f2fSdrahn if (r_symndx < symtab_hdr->sh_info)
449d2201f2fSdrahn {
450d2201f2fSdrahn sym = local_syms + r_symndx;
451d2201f2fSdrahn sec = local_sections[r_symndx];
452*cf2f2c56Smiod relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
453d2201f2fSdrahn
454d2201f2fSdrahn name = bfd_elf_string_from_elf_section
455d2201f2fSdrahn (input_bfd, symtab_hdr->sh_link, sym->st_name);
456d2201f2fSdrahn name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
457d2201f2fSdrahn }
458d2201f2fSdrahn else
459d2201f2fSdrahn {
460*cf2f2c56Smiod bfd_boolean unresolved_reloc, warned;
461d2201f2fSdrahn
462*cf2f2c56Smiod RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
463*cf2f2c56Smiod r_symndx, symtab_hdr, sym_hashes,
464*cf2f2c56Smiod h, sec, relocation,
465*cf2f2c56Smiod unresolved_reloc, warned);
466d2201f2fSdrahn }
467d2201f2fSdrahn
468d2201f2fSdrahn r = msp430_final_link_relocate (howto, input_bfd, input_section,
469d2201f2fSdrahn contents, rel, relocation);
470d2201f2fSdrahn
471d2201f2fSdrahn if (r != bfd_reloc_ok)
472d2201f2fSdrahn {
473d2201f2fSdrahn const char *msg = (const char *) NULL;
474d2201f2fSdrahn
475d2201f2fSdrahn switch (r)
476d2201f2fSdrahn {
477d2201f2fSdrahn case bfd_reloc_overflow:
478d2201f2fSdrahn r = info->callbacks->reloc_overflow
479d2201f2fSdrahn (info, name, howto->name, (bfd_vma) 0,
480d2201f2fSdrahn input_bfd, input_section, rel->r_offset);
481d2201f2fSdrahn break;
482d2201f2fSdrahn
483d2201f2fSdrahn case bfd_reloc_undefined:
484d2201f2fSdrahn r = info->callbacks->undefined_symbol
485d2201f2fSdrahn (info, name, input_bfd, input_section, rel->r_offset, TRUE);
486d2201f2fSdrahn break;
487d2201f2fSdrahn
488d2201f2fSdrahn case bfd_reloc_outofrange:
489d2201f2fSdrahn msg = _("internal error: out of range error");
490d2201f2fSdrahn break;
491d2201f2fSdrahn
492d2201f2fSdrahn case bfd_reloc_notsupported:
493d2201f2fSdrahn msg = _("internal error: unsupported relocation error");
494d2201f2fSdrahn break;
495d2201f2fSdrahn
496d2201f2fSdrahn case bfd_reloc_dangerous:
497d2201f2fSdrahn msg = _("internal error: dangerous relocation");
498d2201f2fSdrahn break;
499d2201f2fSdrahn
500d2201f2fSdrahn default:
501d2201f2fSdrahn msg = _("internal error: unknown error");
502d2201f2fSdrahn break;
503d2201f2fSdrahn }
504d2201f2fSdrahn
505d2201f2fSdrahn if (msg)
506d2201f2fSdrahn r = info->callbacks->warning
507d2201f2fSdrahn (info, msg, name, input_bfd, input_section, rel->r_offset);
508d2201f2fSdrahn
509d2201f2fSdrahn if (!r)
510d2201f2fSdrahn return FALSE;
511d2201f2fSdrahn }
512d2201f2fSdrahn
513d2201f2fSdrahn }
514d2201f2fSdrahn
515d2201f2fSdrahn return TRUE;
516d2201f2fSdrahn }
517d2201f2fSdrahn
518d2201f2fSdrahn /* The final processing done just before writing out a MSP430 ELF object
519d2201f2fSdrahn file. This gets the MSP430 architecture right based on the machine
520d2201f2fSdrahn number. */
521d2201f2fSdrahn
522d2201f2fSdrahn static void
bfd_elf_msp430_final_write_processing(abfd,linker)523d2201f2fSdrahn bfd_elf_msp430_final_write_processing (abfd, linker)
524d2201f2fSdrahn bfd *abfd;
525d2201f2fSdrahn bfd_boolean linker ATTRIBUTE_UNUSED;
526d2201f2fSdrahn {
527d2201f2fSdrahn unsigned long val;
528d2201f2fSdrahn
529d2201f2fSdrahn switch (bfd_get_mach (abfd))
530d2201f2fSdrahn {
531d2201f2fSdrahn default:
532d2201f2fSdrahn case bfd_mach_msp110:
533d2201f2fSdrahn val = E_MSP430_MACH_MSP430x11x1;
534d2201f2fSdrahn break;
535d2201f2fSdrahn
536d2201f2fSdrahn case bfd_mach_msp11:
537d2201f2fSdrahn val = E_MSP430_MACH_MSP430x11;
538d2201f2fSdrahn break;
539d2201f2fSdrahn
540*cf2f2c56Smiod case bfd_mach_msp12:
541*cf2f2c56Smiod val = E_MSP430_MACH_MSP430x12;
542*cf2f2c56Smiod break;
543*cf2f2c56Smiod
544d2201f2fSdrahn case bfd_mach_msp13:
545d2201f2fSdrahn val = E_MSP430_MACH_MSP430x13;
546d2201f2fSdrahn break;
547d2201f2fSdrahn
548d2201f2fSdrahn case bfd_mach_msp14:
549d2201f2fSdrahn val = E_MSP430_MACH_MSP430x14;
550d2201f2fSdrahn break;
551d2201f2fSdrahn
552*cf2f2c56Smiod case bfd_mach_msp15:
553*cf2f2c56Smiod val = E_MSP430_MACH_MSP430x15;
554d2201f2fSdrahn break;
555d2201f2fSdrahn
556*cf2f2c56Smiod case bfd_mach_msp16:
557*cf2f2c56Smiod val = E_MSP430_MACH_MSP430x16;
558d2201f2fSdrahn break;
559d2201f2fSdrahn
560d2201f2fSdrahn case bfd_mach_msp31:
561d2201f2fSdrahn val = E_MSP430_MACH_MSP430x31;
562d2201f2fSdrahn break;
563d2201f2fSdrahn
564d2201f2fSdrahn case bfd_mach_msp32:
565d2201f2fSdrahn val = E_MSP430_MACH_MSP430x32;
566d2201f2fSdrahn break;
567d2201f2fSdrahn
568d2201f2fSdrahn case bfd_mach_msp33:
569d2201f2fSdrahn val = E_MSP430_MACH_MSP430x33;
570d2201f2fSdrahn break;
571d2201f2fSdrahn
572*cf2f2c56Smiod case bfd_mach_msp41:
573*cf2f2c56Smiod val = E_MSP430_MACH_MSP430x41;
574d2201f2fSdrahn break;
575d2201f2fSdrahn
576*cf2f2c56Smiod case bfd_mach_msp42:
577*cf2f2c56Smiod val = E_MSP430_MACH_MSP430x42;
578*cf2f2c56Smiod break;
579*cf2f2c56Smiod
580*cf2f2c56Smiod case bfd_mach_msp43:
581*cf2f2c56Smiod val = E_MSP430_MACH_MSP430x43;
582*cf2f2c56Smiod break;
583*cf2f2c56Smiod
584*cf2f2c56Smiod case bfd_mach_msp44:
585*cf2f2c56Smiod val = E_MSP430_MACH_MSP430x44;
586d2201f2fSdrahn break;
587d2201f2fSdrahn }
588d2201f2fSdrahn
589d2201f2fSdrahn elf_elfheader (abfd)->e_machine = EM_MSP430;
590d2201f2fSdrahn elf_elfheader (abfd)->e_flags &= ~EF_MSP430_MACH;
591d2201f2fSdrahn elf_elfheader (abfd)->e_flags |= val;
592d2201f2fSdrahn }
593d2201f2fSdrahn
594d2201f2fSdrahn /* Set the right machine number. */
595d2201f2fSdrahn
596d2201f2fSdrahn static bfd_boolean
elf32_msp430_object_p(abfd)597d2201f2fSdrahn elf32_msp430_object_p (abfd)
598d2201f2fSdrahn bfd *abfd;
599d2201f2fSdrahn {
600d2201f2fSdrahn int e_set = bfd_mach_msp14;
601d2201f2fSdrahn
602d2201f2fSdrahn if (elf_elfheader (abfd)->e_machine == EM_MSP430
603d2201f2fSdrahn || elf_elfheader (abfd)->e_machine == EM_MSP430_OLD)
604d2201f2fSdrahn {
605d2201f2fSdrahn int e_mach = elf_elfheader (abfd)->e_flags & EF_MSP430_MACH;
606d2201f2fSdrahn
607d2201f2fSdrahn switch (e_mach)
608d2201f2fSdrahn {
609d2201f2fSdrahn default:
610d2201f2fSdrahn case E_MSP430_MACH_MSP430x11:
611d2201f2fSdrahn e_set = bfd_mach_msp11;
612d2201f2fSdrahn break;
613d2201f2fSdrahn
614d2201f2fSdrahn case E_MSP430_MACH_MSP430x11x1:
615d2201f2fSdrahn e_set = bfd_mach_msp110;
616d2201f2fSdrahn break;
617d2201f2fSdrahn
618*cf2f2c56Smiod case E_MSP430_MACH_MSP430x12:
619*cf2f2c56Smiod e_set = bfd_mach_msp12;
620*cf2f2c56Smiod break;
621*cf2f2c56Smiod
622d2201f2fSdrahn case E_MSP430_MACH_MSP430x13:
623d2201f2fSdrahn e_set = bfd_mach_msp13;
624d2201f2fSdrahn break;
625d2201f2fSdrahn
626d2201f2fSdrahn case E_MSP430_MACH_MSP430x14:
627d2201f2fSdrahn e_set = bfd_mach_msp14;
628d2201f2fSdrahn break;
629d2201f2fSdrahn
630*cf2f2c56Smiod case E_MSP430_MACH_MSP430x15:
631*cf2f2c56Smiod e_set = bfd_mach_msp15;
632*cf2f2c56Smiod break;
633*cf2f2c56Smiod
634*cf2f2c56Smiod case E_MSP430_MACH_MSP430x16:
635*cf2f2c56Smiod e_set = bfd_mach_msp16;
636d2201f2fSdrahn break;
637d2201f2fSdrahn
638d2201f2fSdrahn case E_MSP430_MACH_MSP430x31:
639d2201f2fSdrahn e_set = bfd_mach_msp31;
640d2201f2fSdrahn break;
641d2201f2fSdrahn
642d2201f2fSdrahn case E_MSP430_MACH_MSP430x32:
643d2201f2fSdrahn e_set = bfd_mach_msp32;
644d2201f2fSdrahn break;
645d2201f2fSdrahn
646d2201f2fSdrahn case E_MSP430_MACH_MSP430x33:
647d2201f2fSdrahn e_set = bfd_mach_msp33;
648d2201f2fSdrahn break;
649d2201f2fSdrahn
650*cf2f2c56Smiod case E_MSP430_MACH_MSP430x41:
651*cf2f2c56Smiod e_set = bfd_mach_msp41;
652*cf2f2c56Smiod break;
653*cf2f2c56Smiod
654*cf2f2c56Smiod case E_MSP430_MACH_MSP430x42:
655*cf2f2c56Smiod e_set = bfd_mach_msp42;
656*cf2f2c56Smiod break;
657*cf2f2c56Smiod
658d2201f2fSdrahn case E_MSP430_MACH_MSP430x43:
659d2201f2fSdrahn e_set = bfd_mach_msp43;
660d2201f2fSdrahn break;
661d2201f2fSdrahn
662d2201f2fSdrahn case E_MSP430_MACH_MSP430x44:
663d2201f2fSdrahn e_set = bfd_mach_msp44;
664d2201f2fSdrahn break;
665d2201f2fSdrahn }
666d2201f2fSdrahn }
667d2201f2fSdrahn
668d2201f2fSdrahn return bfd_default_set_arch_mach (abfd, bfd_arch_msp430, e_set);
669d2201f2fSdrahn }
670d2201f2fSdrahn
671d2201f2fSdrahn static void
elf32_msp430_post_process_headers(abfd,link_info)672d2201f2fSdrahn elf32_msp430_post_process_headers (abfd, link_info)
673d2201f2fSdrahn bfd *abfd;
674d2201f2fSdrahn struct bfd_link_info *link_info ATTRIBUTE_UNUSED;
675d2201f2fSdrahn {
676d2201f2fSdrahn Elf_Internal_Ehdr *i_ehdrp; /* ELF file header, internal form. */
677d2201f2fSdrahn
678d2201f2fSdrahn i_ehdrp = elf_elfheader (abfd);
679d2201f2fSdrahn
680d2201f2fSdrahn #ifndef ELFOSABI_STANDALONE
681d2201f2fSdrahn #define ELFOSABI_STANDALONE 255
682d2201f2fSdrahn #endif
683d2201f2fSdrahn
684d2201f2fSdrahn i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_STANDALONE;
685d2201f2fSdrahn }
686d2201f2fSdrahn
687d2201f2fSdrahn
688d2201f2fSdrahn #define ELF_ARCH bfd_arch_msp430
689d2201f2fSdrahn #define ELF_MACHINE_CODE EM_MSP430
690d2201f2fSdrahn #define ELF_MACHINE_ALT1 EM_MSP430_OLD
691d2201f2fSdrahn #define ELF_MAXPAGESIZE 1
692d2201f2fSdrahn
693d2201f2fSdrahn #define TARGET_LITTLE_SYM bfd_elf32_msp430_vec
694d2201f2fSdrahn #define TARGET_LITTLE_NAME "elf32-msp430"
695d2201f2fSdrahn
696d2201f2fSdrahn #define elf_info_to_howto msp430_info_to_howto_rela
697d2201f2fSdrahn #define elf_info_to_howto_rel NULL
698d2201f2fSdrahn #define elf_backend_relocate_section elf32_msp430_relocate_section
699d2201f2fSdrahn #define elf_backend_gc_mark_hook elf32_msp430_gc_mark_hook
700d2201f2fSdrahn #define elf_backend_gc_sweep_hook elf32_msp430_gc_sweep_hook
701d2201f2fSdrahn #define elf_backend_check_relocs elf32_msp430_check_relocs
702d2201f2fSdrahn #define elf_backend_can_gc_sections 1
703d2201f2fSdrahn #define elf_backend_final_write_processing bfd_elf_msp430_final_write_processing
704d2201f2fSdrahn #define elf_backend_object_p elf32_msp430_object_p
705d2201f2fSdrahn #define elf_backend_post_process_headers elf32_msp430_post_process_headers
706d2201f2fSdrahn
707d2201f2fSdrahn #include "elf32-target.h"
708