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