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