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