Use fprintf_vma to print vma values.
[external/binutils.git] / bfd / mipsbsd.c
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
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 2 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., 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);
51 static void MY(set_arch_mach) PARAMS ((bfd *abfd, unsigned long machtype));
52 static void MY(choose_reloc_size) PARAMS ((bfd *abfd));
53
54 #define MY_write_object_contents MY(write_object_contents)
55 static 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
72 static bfd_reloc_status_type mips_fix_jmp_addr
73   PARAMS ((bfd *, arelent *, struct bfd_symbol *, PTR, asection *,
74            bfd *, char **));
75 static reloc_howto_type *MY(reloc_howto_type_lookup)
76   PARAMS ((bfd *, bfd_reloc_code_real_type));
77
78 long MY(canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **, asymbol **));
79
80 static void
81 MY(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 */
111 static void
112 MY (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
132 static bfd_boolean
133 MY (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
201 static bfd_reloc_status_type
202 mips_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
248 static bfd_reloc_status_type
249 mips_fix_hi16_s PARAMS ((bfd *, arelent *, asymbol *, PTR,
250                          asection *, bfd *, char **));
251
252 static bfd_reloc_status_type
253 mips_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
291 static 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
308 static reloc_howto_type *
309 MY(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.  */
339 long
340 MY(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
388 static 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
404 extern const bfd_target aout_mips_big_vec;
405
406 const 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
447 const 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   };