1 /* BFD backend for MIPS BSD (a.out) binaries.
2    Copyright (C) 1993-2016 Free Software Foundation, Inc.
3    Written by Ralph Campbell.
4 
5    This file is part of BFD, the Binary File Descriptor library.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20    MA 02110-1301, USA.  */
21 
22 
23 /* #define ENTRY_CAN_BE_ZERO */
24 #define N_HEADER_IN_TEXT(x) 1
25 #define N_TXTADDR(x) \
26     (N_MAGIC(x) != ZMAGIC ? (x)->a_entry :	/* object file or NMAGIC */\
27 	    TEXT_START_ADDR + EXEC_BYTES_SIZE	/* no padding */\
28     )
29 #define N_DATADDR(x) (N_TXTADDR(x)+N_TXTSIZE(x))
30 #define TEXT_START_ADDR 4096
31 #define TARGET_PAGE_SIZE 4096
32 #define SEGMENT_SIZE TARGET_PAGE_SIZE
33 #define DEFAULT_ARCH bfd_arch_mips
34 #define MACHTYPE_OK(mtype) ((mtype) == M_UNKNOWN \
35 			    || (mtype) == M_MIPS1 || (mtype) == M_MIPS2)
36 #define MY_symbol_leading_char '\0'
37 
38 /* Do not "beautify" the CONCAT* macro args.  Traditional C will not
39    remove whitespace added here, and thus will fail to concatenate
40    the tokens.  */
41 #define MY(OP) CONCAT2 (mipsbsd_,OP)
42 
43 #include "sysdep.h"
44 #include "bfd.h"
45 #include "libbfd.h"
46 #include "libaout.h"
47 
48 #define SET_ARCH_MACH(ABFD, EXECP) \
49   MY(set_arch_mach) (ABFD, N_MACHTYPE (EXECP)); \
50   MY(choose_reloc_size) (ABFD);
51 static void MY(set_arch_mach) (bfd *, unsigned long);
52 static void MY(choose_reloc_size) (bfd *);
53 
54 #define MY_write_object_contents MY(write_object_contents)
55 static bfd_boolean MY(write_object_contents) (bfd *);
56 
57 /* We can't use MY(x) here because it leads to a recursive call to CONCAT2
58    when expanded inside JUMP_TABLE.  */
59 #define MY_bfd_reloc_type_lookup mipsbsd_reloc_type_lookup
60 #define MY_bfd_reloc_name_lookup mipsbsd_reloc_name_lookup
61 #define MY_canonicalize_reloc mipsbsd_canonicalize_reloc
62 
63 #define MY_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
64 #define MY_bfd_link_add_symbols _bfd_generic_link_add_symbols
65 #define MY_final_link_callback unused
66 #define MY_bfd_final_link _bfd_generic_final_link
67 
68 #define MY_backend_data &MY(backend_data)
69 #define MY_BFD_TARGET
70 
71 #include "aout-target.h"
72 
73 static bfd_reloc_status_type mips_fix_jmp_addr
74   (bfd *, arelent *, struct bfd_symbol *, void *, asection *,
75    bfd *, char **);
76 
77 long MY(canonicalize_reloc) (bfd *, sec_ptr, arelent **, asymbol **);
78 
79 static void
MY(set_arch_mach)80 MY(set_arch_mach) (bfd *abfd, unsigned long machtype)
81 {
82   enum bfd_architecture arch;
83   unsigned int machine;
84 
85   /* Determine the architecture and machine type of the object file.  */
86   switch (machtype)
87     {
88     case M_MIPS1:
89       arch = bfd_arch_mips;
90       machine = bfd_mach_mips3000;
91       break;
92 
93     case M_MIPS2:
94       arch = bfd_arch_mips;
95       machine = bfd_mach_mips4000;
96       break;
97 
98     default:
99       arch = bfd_arch_obscure;
100       machine = 0;
101       break;
102     }
103 
104   bfd_set_arch_mach (abfd, arch, machine);
105 }
106 
107 /* Determine the size of a relocation entry, based on the architecture */
108 static void
MY(choose_reloc_size)109 MY (choose_reloc_size) (bfd *abfd)
110 {
111   switch (bfd_get_arch (abfd))
112     {
113     case bfd_arch_sparc:
114     case bfd_arch_mips:
115       obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE;
116       break;
117     default:
118       obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
119       break;
120     }
121 }
122 
123 /* Write an object file in BSD a.out format.
124   Section contents have already been written.  We write the
125   file header, symbols, and relocation.  */
126 
127 static bfd_boolean
MY(write_object_contents)128 MY (write_object_contents) (bfd *abfd)
129 {
130   struct external_exec exec_bytes;
131   struct internal_exec *execp = exec_hdr (abfd);
132 
133   /* Magic number, maestro, please!  */
134   switch (bfd_get_arch (abfd))
135     {
136     case bfd_arch_m68k:
137       switch (bfd_get_mach (abfd))
138 	{
139 	case bfd_mach_m68010:
140 	  N_SET_MACHTYPE (execp, M_68010);
141 	  break;
142 	default:
143 	case bfd_mach_m68020:
144 	  N_SET_MACHTYPE (execp, M_68020);
145 	  break;
146 	}
147       break;
148     case bfd_arch_sparc:
149       N_SET_MACHTYPE (execp, M_SPARC);
150       break;
151     case bfd_arch_i386:
152       N_SET_MACHTYPE (execp, M_386);
153       break;
154     case bfd_arch_mips:
155       switch (bfd_get_mach (abfd))
156 	{
157 	case bfd_mach_mips4000:
158 	case bfd_mach_mips6000:
159 	  N_SET_MACHTYPE (execp, M_MIPS2);
160 	  break;
161 	default:
162 	  N_SET_MACHTYPE (execp, M_MIPS1);
163 	  break;
164 	}
165       break;
166     default:
167       N_SET_MACHTYPE (execp, M_UNKNOWN);
168     }
169 
170   MY (choose_reloc_size) (abfd);
171 
172   WRITE_HEADERS (abfd, execp);
173 
174   return TRUE;
175 }
176 
177 /* MIPS relocation types.  */
178 #define MIPS_RELOC_32		0
179 #define MIPS_RELOC_JMP		1
180 #define MIPS_RELOC_WDISP16	2
181 #define MIPS_RELOC_HI16		3
182 #define MIPS_RELOC_HI16_S	4
183 #define MIPS_RELOC_LO16		5
184 
185 /* This is only called when performing a BFD_RELOC_MIPS_JMP relocation.
186    The jump destination address is formed from the upper 4 bits of the
187    "current" program counter concatenated with the jump instruction's
188    26 bit field and two trailing zeros.
189    If the destination address is not in the same segment as the "current"
190    program counter, then we need to signal an error.  */
191 
192 static bfd_reloc_status_type
mips_fix_jmp_addr(bfd * abfd ATTRIBUTE_UNUSED,arelent * reloc_entry,struct bfd_symbol * symbol,void * data ATTRIBUTE_UNUSED,asection * input_section,bfd * output_bfd,char ** error_message ATTRIBUTE_UNUSED)193 mips_fix_jmp_addr (bfd *abfd ATTRIBUTE_UNUSED,
194 		   arelent *reloc_entry,
195 		   struct bfd_symbol *symbol,
196 		   void * data ATTRIBUTE_UNUSED,
197 		   asection *input_section,
198 		   bfd *output_bfd,
199 		   char **error_message ATTRIBUTE_UNUSED)
200 {
201   bfd_vma relocation, pc;
202 
203   /* If this is a partial relocation, just continue.  */
204   if (output_bfd != (bfd *) NULL)
205     return bfd_reloc_continue;
206 
207   /* If this is an undefined symbol, return error */
208   if (bfd_is_und_section (symbol->section)
209       && (symbol->flags & BSF_WEAK) == 0)
210     return bfd_reloc_undefined;
211 
212   /* Work out which section the relocation is targeted at and the
213      initial relocation command value.  */
214   if (bfd_is_com_section (symbol->section))
215     relocation = 0;
216   else
217     relocation = symbol->value;
218 
219   relocation += symbol->section->output_section->vma;
220   relocation += symbol->section->output_offset;
221   relocation += reloc_entry->addend;
222 
223   pc = input_section->output_section->vma + input_section->output_offset +
224     reloc_entry->address + 4;
225 
226   if ((relocation & 0xF0000000) != (pc & 0xF0000000))
227     return bfd_reloc_overflow;
228 
229   return bfd_reloc_continue;
230 }
231 
232 /* This is only called when performing a BFD_RELOC_HI16_S relocation.
233    We need to see if bit 15 is set in the result. If it is, we add
234    0x10000 and continue normally. This will compensate for the sign extension
235    when the low bits are added at run time.  */
236 
237 static bfd_reloc_status_type
mips_fix_hi16_s(bfd * abfd ATTRIBUTE_UNUSED,arelent * reloc_entry,asymbol * symbol,void * data ATTRIBUTE_UNUSED,asection * input_section ATTRIBUTE_UNUSED,bfd * output_bfd,char ** error_message ATTRIBUTE_UNUSED)238 mips_fix_hi16_s (bfd *abfd ATTRIBUTE_UNUSED,
239 		 arelent *reloc_entry,
240 		 asymbol *symbol,
241 		 void * data ATTRIBUTE_UNUSED,
242 		 asection *input_section ATTRIBUTE_UNUSED,
243 		 bfd *output_bfd,
244 		 char **error_message ATTRIBUTE_UNUSED)
245 {
246   bfd_vma relocation;
247 
248   /* If this is a partial relocation, just continue.  */
249   if (output_bfd != (bfd *)NULL)
250     return bfd_reloc_continue;
251 
252   /* If this is an undefined symbol, return error.  */
253   if (bfd_is_und_section (symbol->section)
254       && (symbol->flags & BSF_WEAK) == 0)
255     return bfd_reloc_undefined;
256 
257   /* Work out which section the relocation is targeted at and the
258      initial relocation command value.  */
259   if (bfd_is_com_section (symbol->section))
260     relocation = 0;
261   else
262     relocation = symbol->value;
263 
264   relocation += symbol->section->output_section->vma;
265   relocation += symbol->section->output_offset;
266   relocation += reloc_entry->addend;
267 
268   if (relocation & 0x8000)
269     reloc_entry->addend += 0x10000;
270 
271   return bfd_reloc_continue;
272 }
273 
274 static reloc_howto_type mips_howto_table_ext[] =
275 {
276   {MIPS_RELOC_32,      0, 2, 32, FALSE, 0,  complain_overflow_bitfield, 0,
277 	"32",       FALSE, 0, 0xffffffff, FALSE},
278   {MIPS_RELOC_JMP,     2, 2, 26, FALSE, 0, complain_overflow_dont,
279 	mips_fix_jmp_addr,
280 	"MIPS_JMP", FALSE, 0, 0x03ffffff, FALSE},
281   {MIPS_RELOC_WDISP16, 2, 2, 16, TRUE,  0, complain_overflow_signed, 0,
282 	"WDISP16",  FALSE, 0, 0x0000ffff, FALSE},
283   {MIPS_RELOC_HI16,   16, 2, 16, FALSE, 0, complain_overflow_bitfield, 0,
284 	"HI16",     FALSE, 0, 0x0000ffff, FALSE},
285   {MIPS_RELOC_HI16_S, 16, 2, 16, FALSE, 0, complain_overflow_bitfield,
286         mips_fix_hi16_s,
287         "HI16_S",   FALSE, 0, 0x0000ffff, FALSE},
288   {MIPS_RELOC_LO16,    0, 2, 16, FALSE, 0, complain_overflow_dont, 0,
289 	"LO16",     FALSE, 0, 0x0000ffff, FALSE},
290 };
291 
292 static reloc_howto_type *
MY(reloc_type_lookup)293 MY(reloc_type_lookup) (bfd *abfd, bfd_reloc_code_real_type code)
294 {
295   if (bfd_get_arch (abfd) != bfd_arch_mips)
296     return NULL;
297 
298   switch (code)
299     {
300     case BFD_RELOC_CTOR:
301     case BFD_RELOC_32:
302       return (&mips_howto_table_ext[MIPS_RELOC_32]);
303     case BFD_RELOC_MIPS_JMP:
304       return (&mips_howto_table_ext[MIPS_RELOC_JMP]);
305     case BFD_RELOC_16_PCREL_S2:
306       return (&mips_howto_table_ext[MIPS_RELOC_WDISP16]);
307     case BFD_RELOC_HI16:
308       return (&mips_howto_table_ext[MIPS_RELOC_HI16]);
309     case BFD_RELOC_HI16_S:
310       return (&mips_howto_table_ext[MIPS_RELOC_HI16_S]);
311     case BFD_RELOC_LO16:
312       return (&mips_howto_table_ext[MIPS_RELOC_LO16]);
313     default:
314       return NULL;
315     }
316 }
317 
318 static reloc_howto_type *
MY(reloc_name_lookup)319 MY(reloc_name_lookup) (bfd *abfd ATTRIBUTE_UNUSED,
320 		       const char *r_name)
321 {
322   unsigned int i;
323 
324   for (i = 0;
325        i < sizeof (mips_howto_table_ext) / sizeof (mips_howto_table_ext[0]);
326        i++)
327     if (mips_howto_table_ext[i].name != NULL
328 	&& strcasecmp (mips_howto_table_ext[i].name, r_name) == 0)
329       return &mips_howto_table_ext[i];
330 
331   return NULL;
332 }
333 
334 /* This is just like the standard aoutx.h version but we need to do our
335    own mapping of external reloc type values to howto entries.  */
336 long
MY(canonicalize_reloc)337 MY(canonicalize_reloc) (bfd *abfd,
338 			sec_ptr section,
339 			arelent **relptr,
340 			asymbol **symbols)
341 {
342   arelent *tblptr = section->relocation;
343   unsigned int count, c;
344   extern reloc_howto_type NAME(aout,ext_howto_table)[];
345 
346   /* If we have already read in the relocation table, return the values.  */
347   if (section->flags & SEC_CONSTRUCTOR)
348     {
349       arelent_chain *chain = section->constructor_chain;
350 
351       for (count = 0; count < section->reloc_count; count++)
352 	{
353 	  *relptr++ = &chain->relent;
354 	  chain = chain->next;
355 	}
356       *relptr = 0;
357       return section->reloc_count;
358     }
359 
360   if (tblptr && section->reloc_count)
361     {
362       for (count = 0; count++ < section->reloc_count;)
363 	*relptr++ = tblptr++;
364       *relptr = 0;
365       return section->reloc_count;
366     }
367 
368   if (!NAME(aout,slurp_reloc_table) (abfd, section, symbols))
369     return -1;
370   tblptr = section->relocation;
371 
372   /* fix up howto entries.  */
373   for (count = 0; count++ < section->reloc_count;)
374     {
375       c = tblptr->howto - NAME(aout,ext_howto_table);
376       tblptr->howto = &mips_howto_table_ext[c];
377 
378       *relptr++ = tblptr++;
379     }
380   *relptr = 0;
381   return section->reloc_count;
382 }
383 
384 static const struct aout_backend_data MY(backend_data) =
385 {
386   0,				/* zmagic contiguous */
387   1,				/* text incl header */
388   0,				/* entry is text address */
389   0,				/* exec_hdr_flags */
390   TARGET_PAGE_SIZE,			/* text vma */
391   MY_set_sizes,
392   0,				/* text size includes exec header */
393   0,				/* add_dynamic_symbols */
394   0,				/* add_one_symbol */
395   0,				/* link_dynamic_object */
396   0,				/* write_dynamic_symbol */
397   0,				/* check_dynamic_reloc */
398   0				/* finish_dynamic_link */
399 };
400 
401 extern const bfd_target mips_aout_be_vec;
402 
403 const bfd_target mips_aout_le_vec =
404 {
405     "a.out-mips-little",		/* name */
406     bfd_target_aout_flavour,
407     BFD_ENDIAN_LITTLE,		/* target byte order (little) */
408     BFD_ENDIAN_LITTLE,		/* target headers byte order (little) */
409     (HAS_RELOC | EXEC_P |		/* object flags */
410      HAS_LINENO | HAS_DEBUG |
411      HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
412     (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
413     MY_symbol_leading_char,
414     ' ',				/* ar_pad_char */
415     15,				/* ar_max_namelen */
416     0,				/* match priority.  */
417     bfd_getl64, bfd_getl_signed_64, bfd_putl64,
418     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
419     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
420     bfd_getl64, bfd_getl_signed_64, bfd_putl64,
421     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
422     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
423     {_bfd_dummy_target, MY_object_p, /* bfd_check_format */
424      bfd_generic_archive_p, MY_core_file_p},
425     {bfd_false, MY_mkobject,	/* bfd_set_format */
426      _bfd_generic_mkarchive, bfd_false},
427     {bfd_false, MY_write_object_contents, /* bfd_write_contents */
428      _bfd_write_archive_contents, bfd_false},
429 
430     BFD_JUMP_TABLE_GENERIC (MY),
431     BFD_JUMP_TABLE_COPY (MY),
432     BFD_JUMP_TABLE_CORE (MY),
433     BFD_JUMP_TABLE_ARCHIVE (MY),
434     BFD_JUMP_TABLE_SYMBOLS (MY),
435     BFD_JUMP_TABLE_RELOCS (MY),
436     BFD_JUMP_TABLE_WRITE (MY),
437     BFD_JUMP_TABLE_LINK (MY),
438     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
439 
440     & mips_aout_be_vec,
441 
442     MY_backend_data
443   };
444 
445 const bfd_target mips_aout_be_vec =
446   {
447     "a.out-mips-big",		/* name */
448     bfd_target_aout_flavour,
449     BFD_ENDIAN_BIG,		/* target byte order (big) */
450     BFD_ENDIAN_BIG,		/* target headers byte order (big) */
451     (HAS_RELOC | EXEC_P |		/* object flags */
452      HAS_LINENO | HAS_DEBUG |
453      HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
454     (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
455     MY_symbol_leading_char,
456     ' ',				/* ar_pad_char */
457     15,				/* ar_max_namelen */
458     0,				/* match priority.  */
459     bfd_getb64, bfd_getb_signed_64, bfd_putb64,
460     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
461     bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
462     bfd_getb64, bfd_getb_signed_64, bfd_putb64,
463     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
464     bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
465     {_bfd_dummy_target, MY_object_p, /* bfd_check_format */
466      bfd_generic_archive_p, MY_core_file_p},
467     {bfd_false, MY_mkobject,	/* bfd_set_format */
468      _bfd_generic_mkarchive, bfd_false},
469     {bfd_false, MY_write_object_contents, /* bfd_write_contents */
470      _bfd_write_archive_contents, bfd_false},
471 
472     BFD_JUMP_TABLE_GENERIC (MY),
473     BFD_JUMP_TABLE_COPY (MY),
474     BFD_JUMP_TABLE_CORE (MY),
475     BFD_JUMP_TABLE_ARCHIVE (MY),
476     BFD_JUMP_TABLE_SYMBOLS (MY),
477     BFD_JUMP_TABLE_RELOCS (MY),
478     BFD_JUMP_TABLE_WRITE (MY),
479     BFD_JUMP_TABLE_LINK (MY),
480     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
481 
482     & mips_aout_le_vec,
483 
484     MY_backend_data
485   };
486