xref: /openbsd-src/gnu/usr.bin/binutils/bfd/elf32-msp430.c (revision cf2f2c5620d6d9a4fd01930983c4b9a1f76d7aa3)
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