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