1/* BFD back-end for TMS320C4X coff binaries.
2   Copyright 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2005, 2007,
3   2008  Free Software Foundation, Inc.
4
5   Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz)
6
7   This file is part of BFD, the Binary File Descriptor library.
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 3 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22   02110-1301, USA.  */
23
24#include "sysdep.h"
25#include "bfd.h"
26#include "libbfd.h"
27#include "bfdlink.h"
28#include "coff/tic4x.h"
29#include "coff/internal.h"
30#include "libcoff.h"
31
32#undef  F_LSYMS
33#define	F_LSYMS		F_LSYMS_TICOFF
34
35static bfd_boolean ticoff_bfd_is_local_label_name
36    PARAMS ((bfd *, const char *));
37static bfd_reloc_status_type tic4x_relocation
38    PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char ** ));
39static reloc_howto_type *tic4x_coff_reloc_type_lookup
40    PARAMS ((bfd *, bfd_reloc_code_real_type ));
41static void tic4x_lookup_howto
42    PARAMS ((arelent *, struct internal_reloc * ));
43static reloc_howto_type *coff_tic4x_rtype_to_howto
44    PARAMS ((bfd *, asection *, struct internal_reloc *, struct coff_link_hash_entry *, struct internal_syment *, bfd_vma * ));
45static void tic4x_reloc_processing
46    PARAMS ((arelent *, struct internal_reloc *, asymbol **, bfd *, asection * ));
47
48
49/* Replace the stock _bfd_coff_is_local_label_name to recognize TI COFF local
50   labels.  */
51static bfd_boolean
52ticoff_bfd_is_local_label_name (abfd, name)
53  bfd *abfd ATTRIBUTE_UNUSED;
54  const char *name;
55{
56  if (TICOFF_LOCAL_LABEL_P(name))
57    return TRUE;
58  return FALSE;
59}
60
61#define coff_bfd_is_local_label_name ticoff_bfd_is_local_label_name
62
63#define RELOC_PROCESSING(RELENT,RELOC,SYMS,ABFD,SECT)\
64 tic4x_reloc_processing (RELENT,RELOC,SYMS,ABFD,SECT)
65
66/* Customize coffcode.h; the default coff_ functions are set up to use
67   COFF2; coff_bad_format_hook uses BADMAG, so set that for COFF2.
68   The COFF1 and COFF0 vectors use custom _bad_format_hook procs
69   instead of setting BADMAG.  */
70#define BADMAG(x) COFF2_BADMAG(x)
71
72#undef  coff_rtype_to_howto
73#define coff_rtype_to_howto	coff_tic4x_rtype_to_howto
74
75#ifndef bfd_pe_print_pdata
76#define bfd_pe_print_pdata	NULL
77#endif
78
79#include "coffcode.h"
80
81static bfd_reloc_status_type
82tic4x_relocation (abfd, reloc_entry, symbol, data, input_section,
83		  output_bfd, error_message)
84  bfd *abfd ATTRIBUTE_UNUSED;
85  arelent *reloc_entry;
86  asymbol *symbol ATTRIBUTE_UNUSED;
87  PTR data ATTRIBUTE_UNUSED;
88  asection *input_section;
89  bfd *output_bfd;
90  char **error_message ATTRIBUTE_UNUSED;
91{
92  if (output_bfd != (bfd *) NULL)
93    {
94      /* This is a partial relocation, and we want to apply the
95 	 relocation to the reloc entry rather than the raw data.
96 	 Modify the reloc inplace to reflect what we now know.  */
97      reloc_entry->address += input_section->output_offset;
98      return bfd_reloc_ok;
99    }
100  return bfd_reloc_continue;
101}
102
103reloc_howto_type tic4x_howto_table[] =
104{
105    HOWTO(R_RELWORD,	 0,  2, 16, FALSE, 0, complain_overflow_signed,   tic4x_relocation, "RELWORD",   TRUE, 0x0000ffff, 0x0000ffff, FALSE),
106    HOWTO(R_REL24,	 0,  2, 24, FALSE, 0, complain_overflow_bitfield, tic4x_relocation, "REL24",     TRUE, 0x00ffffff, 0x00ffffff, FALSE),
107    HOWTO(R_RELLONG,	 0,  2, 32, FALSE, 0, complain_overflow_dont,     tic4x_relocation, "RELLONG",   TRUE, 0xffffffff, 0xffffffff, FALSE),
108    HOWTO(R_PCRWORD,	 0,  2, 16, TRUE,  0, complain_overflow_signed,   tic4x_relocation, "PCRWORD",   TRUE, 0x0000ffff, 0x0000ffff, FALSE),
109    HOWTO(R_PCR24,	 0,  2, 24, TRUE,  0, complain_overflow_signed,   tic4x_relocation, "PCR24",     TRUE, 0x00ffffff, 0x00ffffff, FALSE),
110    HOWTO(R_PARTLS16,	 0,  2, 16, FALSE, 0, complain_overflow_dont,     tic4x_relocation, "PARTLS16",  TRUE, 0x0000ffff, 0x0000ffff, FALSE),
111    HOWTO(R_PARTMS8,	16,  2, 16, FALSE, 0, complain_overflow_dont,     tic4x_relocation, "PARTMS8",   TRUE, 0x0000ffff, 0x0000ffff, FALSE),
112    HOWTO(R_RELWORD,	 0,  2, 16, FALSE, 0, complain_overflow_signed,   tic4x_relocation, "ARELWORD",  TRUE, 0x0000ffff, 0x0000ffff, FALSE),
113    HOWTO(R_REL24,	 0,  2, 24, FALSE, 0, complain_overflow_signed,   tic4x_relocation, "AREL24",    TRUE, 0x00ffffff, 0x00ffffff, FALSE),
114    HOWTO(R_RELLONG,	 0,  2, 32, FALSE, 0, complain_overflow_signed,   tic4x_relocation, "ARELLONG",  TRUE, 0xffffffff, 0xffffffff, FALSE),
115    HOWTO(R_PCRWORD,	 0,  2, 16, TRUE,  0, complain_overflow_signed,   tic4x_relocation, "APCRWORD",  TRUE, 0x0000ffff, 0x0000ffff, FALSE),
116    HOWTO(R_PCR24,	 0,  2, 24, TRUE,  0, complain_overflow_signed,   tic4x_relocation, "APCR24",    TRUE, 0x00ffffff, 0x00ffffff, FALSE),
117    HOWTO(R_PARTLS16,	 0,  2, 16, FALSE, 0, complain_overflow_dont,     tic4x_relocation, "APARTLS16", TRUE, 0x0000ffff, 0x0000ffff, FALSE),
118    HOWTO(R_PARTMS8,	16,  2, 16, FALSE, 0, complain_overflow_dont,     tic4x_relocation, "APARTMS8",  TRUE, 0x0000ffff, 0x0000ffff, FALSE),
119};
120#define HOWTO_SIZE (sizeof(tic4x_howto_table) / sizeof(tic4x_howto_table[0]))
121
122#undef coff_bfd_reloc_type_lookup
123#define coff_bfd_reloc_type_lookup tic4x_coff_reloc_type_lookup
124#undef coff_bfd_reloc_name_lookup
125#define coff_bfd_reloc_name_lookup tic4x_coff_reloc_name_lookup
126
127/* For the case statement use the code values used tc_gen_reloc (defined in
128   bfd/reloc.c) to map to the howto table entries.  */
129
130static reloc_howto_type *
131tic4x_coff_reloc_type_lookup (abfd, code)
132    bfd *abfd ATTRIBUTE_UNUSED;
133    bfd_reloc_code_real_type code;
134{
135  unsigned int type;
136  unsigned int i;
137
138  switch (code)
139    {
140    case BFD_RELOC_32:		type = R_RELLONG; break;
141    case BFD_RELOC_24:		type = R_REL24; break;
142    case BFD_RELOC_16:		type = R_RELWORD; break;
143    case BFD_RELOC_24_PCREL:	type = R_PCR24; break;
144    case BFD_RELOC_16_PCREL:	type = R_PCRWORD; break;
145    case BFD_RELOC_HI16:	type = R_PARTMS8; break;
146    case BFD_RELOC_LO16:	type = R_PARTLS16; break;
147    default:
148      return NULL;
149    }
150
151  for (i = 0; i < HOWTO_SIZE; i++)
152    {
153      if (tic4x_howto_table[i].type == type)
154	return tic4x_howto_table + i;
155    }
156  return NULL;
157}
158
159static reloc_howto_type *
160tic4x_coff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
161			      const char *r_name)
162{
163  unsigned int i;
164
165  for (i = 0;
166       i < sizeof (tic4x_howto_table) / sizeof (tic4x_howto_table[0]);
167       i++)
168    if (tic4x_howto_table[i].name != NULL
169	&& strcasecmp (tic4x_howto_table[i].name, r_name) == 0)
170      return &tic4x_howto_table[i];
171
172  return NULL;
173}
174
175/* Code to turn a r_type into a howto ptr, uses the above howto table.
176   Called after some initial checking by the tic4x_rtype_to_howto fn
177   below.  */
178static void
179tic4x_lookup_howto (internal, dst)
180     arelent *internal;
181     struct internal_reloc *dst;
182{
183  unsigned int i;
184  int bank = (dst->r_symndx == -1) ? HOWTO_BANK : 0;
185
186  for (i = 0; i < HOWTO_SIZE; i++)
187    {
188      if (tic4x_howto_table[i].type == dst->r_type)
189	{
190	  internal->howto = tic4x_howto_table + i + bank;
191	  return;
192	}
193    }
194
195  (*_bfd_error_handler) (_("Unrecognized reloc type 0x%x"),
196			 (unsigned int) dst->r_type);
197  abort();
198}
199
200static reloc_howto_type *
201coff_tic4x_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
202     bfd *abfd ATTRIBUTE_UNUSED;
203     asection *sec;
204     struct internal_reloc *rel;
205     struct coff_link_hash_entry *h ATTRIBUTE_UNUSED;
206     struct internal_syment *sym ATTRIBUTE_UNUSED;
207     bfd_vma *addendp;
208{
209  arelent genrel;
210
211  if (rel->r_symndx == -1 && addendp != NULL)
212    /* This is a TI "internal relocation", which means that the relocation
213       amount is the amount by which the current section is being relocated
214       in the output section.  */
215    *addendp = (sec->output_section->vma + sec->output_offset) - sec->vma;
216
217  tic4x_lookup_howto (&genrel, rel);
218
219  return genrel.howto;
220}
221
222
223static void
224tic4x_reloc_processing (relent, reloc, symbols, abfd, section)
225     arelent *relent;
226     struct internal_reloc *reloc;
227     asymbol **symbols;
228     bfd *abfd;
229     asection *section;
230{
231  asymbol *ptr;
232
233  relent->address = reloc->r_vaddr;
234
235  if (reloc->r_symndx != -1)
236    {
237      if (reloc->r_symndx < 0 || reloc->r_symndx >= obj_conv_table_size (abfd))
238        {
239          (*_bfd_error_handler)
240            (_("%s: warning: illegal symbol index %ld in relocs"),
241             bfd_get_filename (abfd), reloc->r_symndx);
242          relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
243          ptr = NULL;
244        }
245      else
246        {
247          relent->sym_ptr_ptr = (symbols
248                                 + obj_convert (abfd)[reloc->r_symndx]);
249          ptr = *(relent->sym_ptr_ptr);
250        }
251    }
252  else
253    {
254      relent->sym_ptr_ptr = section->symbol_ptr_ptr;
255      ptr = *(relent->sym_ptr_ptr);
256    }
257
258  /* The symbols definitions that we have read in have been relocated
259     as if their sections started at 0.  But the offsets refering to
260     the symbols in the raw data have not been modified, so we have to
261     have a negative addend to compensate.
262
263     Note that symbols which used to be common must be left alone.  */
264
265  /* Calculate any reloc addend by looking at the symbol.  */
266  CALC_ADDEND (abfd, ptr, *reloc, relent);
267
268  relent->address -= section->vma;
269  /* !!     relent->section = (asection *) NULL;  */
270
271  /* Fill in the relent->howto field from reloc->r_type.  */
272  tic4x_lookup_howto (relent, reloc);
273}
274
275
276/* TI COFF v0, DOS tools (little-endian headers).  */
277CREATE_LITTLE_COFF_TARGET_VEC(tic4x_coff0_vec, "coff0-tic4x", HAS_LOAD_PAGE, 0, '_', NULL, (PTR)&ticoff0_swap_table);
278
279/* TI COFF v0, SPARC tools (big-endian headers).  */
280CREATE_BIGHDR_COFF_TARGET_VEC(tic4x_coff0_beh_vec, "coff0-beh-tic4x", HAS_LOAD_PAGE, 0, '_', &tic4x_coff0_vec, (PTR)&ticoff0_swap_table);
281
282/* TI COFF v1, DOS tools (little-endian headers).  */
283CREATE_LITTLE_COFF_TARGET_VEC(tic4x_coff1_vec, "coff1-tic4x", HAS_LOAD_PAGE, 0, '_', &tic4x_coff0_beh_vec, (PTR)&ticoff1_swap_table);
284
285/* TI COFF v1, SPARC tools (big-endian headers).  */
286CREATE_BIGHDR_COFF_TARGET_VEC(tic4x_coff1_beh_vec, "coff1-beh-tic4x", HAS_LOAD_PAGE, 0, '_', &tic4x_coff1_vec, (PTR)&ticoff1_swap_table);
287
288/* TI COFF v2, TI DOS tools output (little-endian headers).  */
289CREATE_LITTLE_COFF_TARGET_VEC(tic4x_coff2_vec, "coff2-tic4x", HAS_LOAD_PAGE, 0, '_', &tic4x_coff1_beh_vec, COFF_SWAP_TABLE);
290
291/* TI COFF v2, TI SPARC tools output (big-endian headers).  */
292CREATE_BIGHDR_COFF_TARGET_VEC(tic4x_coff2_beh_vec, "coff2-beh-tic4x", HAS_LOAD_PAGE, 0, '_', &tic4x_coff2_vec, COFF_SWAP_TABLE);
293