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