daily update
[external/binutils.git] / bfd / i386lynx.c
1 /* BFD back-end for i386 a.out binaries under LynxOS.
2    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1999, 2001, 2002,
3    2003, 2007 Free Software Foundation, Inc.
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 #define N_SHARED_LIB(x) 0
23
24 #define TEXT_START_ADDR 0
25 #define TARGET_PAGE_SIZE 4096
26 #define SEGMENT_SIZE TARGET_PAGE_SIZE
27 #define DEFAULT_ARCH bfd_arch_i386
28
29 /* Do not "beautify" the CONCAT* macro args.  Traditional C will not
30    remove whitespace added here, and thus will fail to concatenate
31    the tokens.  */
32 #define MY(OP) CONCAT2 (i386lynx_aout_,OP)
33 #define TARGETNAME "a.out-i386-lynx"
34
35 #include "sysdep.h"
36 #include "bfd.h"
37 #include "libbfd.h"
38
39 #ifndef WRITE_HEADERS
40 #define WRITE_HEADERS(abfd, execp)                                            \
41       {                                                                       \
42         bfd_size_type text_size; /* dummy vars */                             \
43         file_ptr text_end;                                                    \
44         if (adata(abfd).magic == undecided_magic)                             \
45           NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end);     \
46                                                                               \
47         execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE;        \
48         execp->a_entry = bfd_get_start_address (abfd);                        \
49                                                                               \
50         execp->a_trsize = ((obj_textsec (abfd)->reloc_count) *                \
51                            obj_reloc_entry_size (abfd));                      \
52         execp->a_drsize = ((obj_datasec (abfd)->reloc_count) *                \
53                            obj_reloc_entry_size (abfd));                      \
54         NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes);           \
55                                                                               \
56         if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0                      \
57             || bfd_bwrite ((PTR) &exec_bytes, (bfd_size_type) EXEC_BYTES_SIZE, \
58                           abfd) != EXEC_BYTES_SIZE)                           \
59           return FALSE;                                                       \
60         /* Now write out reloc info, followed by syms and strings */          \
61                                                                               \
62         if (bfd_get_symcount (abfd) != 0)                                     \
63             {                                                                 \
64               if (bfd_seek (abfd, (file_ptr) (N_SYMOFF(*execp)), SEEK_SET)    \
65                   != 0)                                                       \
66                 return FALSE;                                                 \
67                                                                               \
68               if (! NAME(aout,write_syms) (abfd)) return FALSE;               \
69                                                                               \
70               if (bfd_seek (abfd, (file_ptr) (N_TRELOFF(*execp)), SEEK_SET)   \
71                   != 0)                                                       \
72                 return FALSE;                                                 \
73                                                                               \
74               if (!NAME(lynx,squirt_out_relocs) (abfd, obj_textsec (abfd)))   \
75                 return FALSE;                                                 \
76               if (bfd_seek (abfd, (file_ptr) (N_DRELOFF(*execp)), SEEK_SET)   \
77                   != 0)                                                       \
78                 return 0;                                                     \
79                                                                               \
80               if (!NAME(lynx,squirt_out_relocs) (abfd, obj_datasec (abfd)))   \
81                 return FALSE;                                                 \
82             }                                                                 \
83       }
84 #endif
85
86 #include "libaout.h"
87 #include "aout/aout64.h"
88
89 void NAME (lynx,swap_std_reloc_out)
90   PARAMS ((bfd *, arelent *, struct reloc_std_external *));
91 void NAME (lynx,swap_ext_reloc_out)
92   PARAMS ((bfd *, arelent *, struct reloc_ext_external *));
93 void NAME (lynx,swap_ext_reloc_in)
94   PARAMS ((bfd *, struct reloc_ext_external *, arelent *, asymbol **,
95            bfd_size_type));
96 void NAME (lynx,swap_std_reloc_in)
97   PARAMS ((bfd *, struct reloc_std_external *, arelent *, asymbol **,
98            bfd_size_type));
99 bfd_boolean NAME (lynx,slurp_reloc_table)
100   PARAMS ((bfd *, sec_ptr, asymbol **));
101 bfd_boolean NAME (lynx,squirt_out_relocs)
102   PARAMS ((bfd *, asection *));
103 long NAME (lynx,canonicalize_reloc)
104   PARAMS ((bfd *, sec_ptr, arelent **, asymbol **));
105
106 #ifdef LYNX_CORE
107
108 char *lynx_core_file_failing_command ();
109 int lynx_core_file_failing_signal ();
110 bfd_boolean lynx_core_file_matches_executable_p ();
111 const bfd_target *lynx_core_file_p ();
112
113 #define MY_core_file_failing_command lynx_core_file_failing_command
114 #define MY_core_file_failing_signal lynx_core_file_failing_signal
115 #define MY_core_file_matches_executable_p lynx_core_file_matches_executable_p
116 #define MY_core_file_p lynx_core_file_p
117
118 #endif /* LYNX_CORE */
119 \f
120
121 #define KEEPIT udata.i
122
123 extern reloc_howto_type aout_32_ext_howto_table[];
124 extern reloc_howto_type aout_32_std_howto_table[];
125
126 /* Standard reloc stuff */
127 /* Output standard relocation information to a file in target byte order. */
128
129 void
130 NAME(lynx,swap_std_reloc_out) (abfd, g, natptr)
131      bfd *abfd;
132      arelent *g;
133      struct reloc_std_external *natptr;
134 {
135   int r_index;
136   asymbol *sym = *(g->sym_ptr_ptr);
137   int r_extern;
138   unsigned int r_length;
139   int r_pcrel;
140   int r_baserel, r_jmptable, r_relative;
141   unsigned int r_addend;
142   asection *output_section = sym->section->output_section;
143
144   PUT_WORD (abfd, g->address, natptr->r_address);
145
146   r_length = g->howto->size;    /* Size as a power of two */
147   r_pcrel = (int) g->howto->pc_relative;        /* Relative to PC? */
148   /* r_baserel, r_jmptable, r_relative???  FIXME-soon */
149   r_baserel = 0;
150   r_jmptable = 0;
151   r_relative = 0;
152
153   r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
154
155   /* name was clobbered by aout_write_syms to be symbol index */
156
157   /* If this relocation is relative to a symbol then set the
158      r_index to the symbols index, and the r_extern bit.
159
160      Absolute symbols can come in in two ways, either as an offset
161      from the abs section, or as a symbol which has an abs value.
162      check for that here
163   */
164
165
166   if (bfd_is_com_section (output_section)
167       || bfd_is_abs_section (output_section)
168       || bfd_is_und_section (output_section))
169     {
170       if (bfd_abs_section_ptr->symbol == sym)
171         {
172           /* Whoops, looked like an abs symbol, but is really an offset
173              from the abs section */
174           r_index = 0;
175           r_extern = 0;
176         }
177       else
178         {
179           /* Fill in symbol */
180           r_extern = 1;
181           r_index = (*g->sym_ptr_ptr)->KEEPIT;
182         }
183     }
184   else
185     {
186       /* Just an ordinary section */
187       r_extern = 0;
188       r_index = output_section->target_index;
189     }
190
191   /* now the fun stuff */
192   if (bfd_header_big_endian (abfd))
193     {
194       natptr->r_index[0] = r_index >> 16;
195       natptr->r_index[1] = r_index >> 8;
196       natptr->r_index[2] = r_index;
197       natptr->r_type[0] =
198         (r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0)
199         | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0)
200         | (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0)
201         | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0)
202         | (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0)
203         | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG);
204     }
205   else
206     {
207       natptr->r_index[2] = r_index >> 16;
208       natptr->r_index[1] = r_index >> 8;
209       natptr->r_index[0] = r_index;
210       natptr->r_type[0] =
211         (r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0)
212         | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0)
213         | (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0)
214         | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0)
215         | (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0)
216         | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE);
217     }
218 }
219
220
221 /* Extended stuff */
222 /* Output extended relocation information to a file in target byte order. */
223
224 void
225 NAME(lynx,swap_ext_reloc_out) (abfd, g, natptr)
226      bfd *abfd;
227      arelent *g;
228      register struct reloc_ext_external *natptr;
229 {
230   int r_index;
231   int r_extern;
232   unsigned int r_type;
233   unsigned int r_addend;
234   asymbol *sym = *(g->sym_ptr_ptr);
235   asection *output_section = sym->section->output_section;
236
237   PUT_WORD (abfd, g->address, natptr->r_address);
238
239   r_type = (unsigned int) g->howto->type;
240
241   r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
242
243
244   /* If this relocation is relative to a symbol then set the
245      r_index to the symbols index, and the r_extern bit.
246
247      Absolute symbols can come in in two ways, either as an offset
248      from the abs section, or as a symbol which has an abs value.
249      check for that here
250      */
251
252   if (bfd_is_com_section (output_section)
253       || bfd_is_abs_section (output_section)
254       || bfd_is_und_section (output_section))
255     {
256       if (bfd_abs_section_ptr->symbol == sym)
257         {
258           /* Whoops, looked like an abs symbol, but is really an offset
259          from the abs section */
260           r_index = 0;
261           r_extern = 0;
262         }
263       else
264         {
265           r_extern = 1;
266           r_index = (*g->sym_ptr_ptr)->KEEPIT;
267         }
268     }
269   else
270     {
271       /* Just an ordinary section */
272       r_extern = 0;
273       r_index = output_section->target_index;
274     }
275
276
277   /* now the fun stuff */
278   if (bfd_header_big_endian (abfd))
279     {
280       natptr->r_index[0] = r_index >> 16;
281       natptr->r_index[1] = r_index >> 8;
282       natptr->r_index[2] = r_index;
283       natptr->r_type[0] =
284         (r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0)
285         | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG);
286     }
287   else
288     {
289       natptr->r_index[2] = r_index >> 16;
290       natptr->r_index[1] = r_index >> 8;
291       natptr->r_index[0] = r_index;
292       natptr->r_type[0] =
293         (r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0)
294         | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
295     }
296
297   PUT_WORD (abfd, r_addend, natptr->r_addend);
298 }
299
300 /* BFD deals internally with all things based from the section they're
301    in. so, something in 10 bytes into a text section  with a base of
302    50 would have a symbol (.text+10) and know .text vma was 50.
303
304    Aout keeps all it's symbols based from zero, so the symbol would
305    contain 60. This macro subs the base of each section from the value
306    to give the true offset from the section */
307
308
309 #define MOVE_ADDRESS(ad)                                                \
310   if (r_extern) {                                                       \
311    /* undefined symbol */                                               \
312      cache_ptr->sym_ptr_ptr = symbols + r_index;                        \
313      cache_ptr->addend = ad;                                            \
314      } else {                                                           \
315     /* defined, section relative. replace symbol with pointer to        \
316        symbol which points to section  */                               \
317     switch (r_index) {                                                  \
318     case N_TEXT:                                                        \
319     case N_TEXT | N_EXT:                                                \
320       cache_ptr->sym_ptr_ptr  = obj_textsec(abfd)->symbol_ptr_ptr;      \
321       cache_ptr->addend = ad  - su->textsec->vma;                       \
322       break;                                                            \
323     case N_DATA:                                                        \
324     case N_DATA | N_EXT:                                                \
325       cache_ptr->sym_ptr_ptr  = obj_datasec(abfd)->symbol_ptr_ptr;      \
326       cache_ptr->addend = ad - su->datasec->vma;                        \
327       break;                                                            \
328     case N_BSS:                                                         \
329     case N_BSS | N_EXT:                                                 \
330       cache_ptr->sym_ptr_ptr  = obj_bsssec(abfd)->symbol_ptr_ptr;       \
331       cache_ptr->addend = ad - su->bsssec->vma;                         \
332       break;                                                            \
333     default:                                                            \
334     case N_ABS:                                                         \
335     case N_ABS | N_EXT:                                                 \
336      cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;      \
337       cache_ptr->addend = ad;                                           \
338       break;                                                            \
339     }                                                                   \
340   }                                                                     \
341
342 void
343 NAME(lynx,swap_ext_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount)
344      bfd *abfd;
345      struct reloc_ext_external *bytes;
346      arelent *cache_ptr;
347      asymbol **symbols;
348      bfd_size_type symcount ATTRIBUTE_UNUSED;
349 {
350   int r_index;
351   int r_extern;
352   unsigned int r_type;
353   struct aoutdata *su = &(abfd->tdata.aout_data->a);
354
355   cache_ptr->address = (GET_SWORD (abfd, bytes->r_address));
356
357   r_index = bytes->r_index[1];
358   r_extern = (0 != (bytes->r_index[0] & RELOC_EXT_BITS_EXTERN_BIG));
359   r_type = (bytes->r_index[0] & RELOC_EXT_BITS_TYPE_BIG)
360     >> RELOC_EXT_BITS_TYPE_SH_BIG;
361
362   cache_ptr->howto = aout_32_ext_howto_table + r_type;
363   MOVE_ADDRESS (GET_SWORD (abfd, bytes->r_addend));
364 }
365
366 void
367 NAME(lynx,swap_std_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount)
368      bfd *abfd;
369      struct reloc_std_external *bytes;
370      arelent *cache_ptr;
371      asymbol **symbols;
372      bfd_size_type symcount ATTRIBUTE_UNUSED;
373 {
374   int r_index;
375   int r_extern;
376   unsigned int r_length;
377   int r_pcrel;
378   int r_baserel, r_jmptable, r_relative;
379   struct aoutdata *su = &(abfd->tdata.aout_data->a);
380
381   cache_ptr->address = H_GET_32 (abfd, bytes->r_address);
382
383   r_index = bytes->r_index[1];
384   r_extern = (0 != (bytes->r_index[0] & RELOC_STD_BITS_EXTERN_BIG));
385   r_pcrel = (0 != (bytes->r_index[0] & RELOC_STD_BITS_PCREL_BIG));
386   r_baserel = (0 != (bytes->r_index[0] & RELOC_STD_BITS_BASEREL_BIG));
387   r_jmptable = (0 != (bytes->r_index[0] & RELOC_STD_BITS_JMPTABLE_BIG));
388   r_relative = (0 != (bytes->r_index[0] & RELOC_STD_BITS_RELATIVE_BIG));
389   r_length = (bytes->r_index[0] & RELOC_STD_BITS_LENGTH_BIG)
390     >> RELOC_STD_BITS_LENGTH_SH_BIG;
391
392   cache_ptr->howto = aout_32_std_howto_table + r_length + 4 * r_pcrel;
393   /* FIXME-soon:  Roll baserel, jmptable, relative bits into howto setting */
394
395   MOVE_ADDRESS (0);
396 }
397
398 /* Reloc hackery */
399
400 bfd_boolean
401 NAME(lynx,slurp_reloc_table) (abfd, asect, symbols)
402      bfd *abfd;
403      sec_ptr asect;
404      asymbol **symbols;
405 {
406   bfd_size_type count;
407   bfd_size_type reloc_size;
408   PTR relocs;
409   arelent *reloc_cache;
410   size_t each_size;
411
412   if (asect->relocation)
413     return TRUE;
414
415   if (asect->flags & SEC_CONSTRUCTOR)
416     return TRUE;
417
418   if (asect == obj_datasec (abfd))
419     {
420       reloc_size = exec_hdr (abfd)->a_drsize;
421       goto doit;
422     }
423
424   if (asect == obj_textsec (abfd))
425     {
426       reloc_size = exec_hdr (abfd)->a_trsize;
427       goto doit;
428     }
429
430   bfd_set_error (bfd_error_invalid_operation);
431   return FALSE;
432
433 doit:
434   if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
435     return FALSE;
436   each_size = obj_reloc_entry_size (abfd);
437
438   count = reloc_size / each_size;
439
440
441   reloc_cache = (arelent *) bfd_zmalloc (count * sizeof (arelent));
442   if (!reloc_cache && count != 0)
443     return FALSE;
444
445   relocs = (PTR) bfd_alloc (abfd, reloc_size);
446   if (!relocs && reloc_size != 0)
447     {
448       free (reloc_cache);
449       return FALSE;
450     }
451
452   if (bfd_bread (relocs, reloc_size, abfd) != reloc_size)
453     {
454       bfd_release (abfd, relocs);
455       free (reloc_cache);
456       return FALSE;
457     }
458
459   if (each_size == RELOC_EXT_SIZE)
460     {
461       register struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs;
462       unsigned int counter = 0;
463       arelent *cache_ptr = reloc_cache;
464
465       for (; counter < count; counter++, rptr++, cache_ptr++)
466         {
467           NAME(lynx,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols,
468                                         (bfd_size_type) bfd_get_symcount (abfd));
469         }
470     }
471   else
472     {
473       register struct reloc_std_external *rptr = (struct reloc_std_external *) relocs;
474       unsigned int counter = 0;
475       arelent *cache_ptr = reloc_cache;
476
477       for (; counter < count; counter++, rptr++, cache_ptr++)
478         {
479           NAME(lynx,swap_std_reloc_in) (abfd, rptr, cache_ptr, symbols,
480                                         (bfd_size_type) bfd_get_symcount (abfd));
481         }
482
483     }
484
485   bfd_release (abfd, relocs);
486   asect->relocation = reloc_cache;
487   asect->reloc_count = count;
488   return TRUE;
489 }
490
491
492
493 /* Write out a relocation section into an object file.  */
494
495 bfd_boolean
496 NAME(lynx,squirt_out_relocs) (abfd, section)
497      bfd *abfd;
498      asection *section;
499 {
500   arelent **generic;
501   unsigned char *native, *natptr;
502   size_t each_size;
503
504   unsigned int count = section->reloc_count;
505   bfd_size_type natsize;
506
507   if (count == 0)
508     return TRUE;
509
510   each_size = obj_reloc_entry_size (abfd);
511   natsize = count;
512   natsize *= each_size;
513   native = (unsigned char *) bfd_zalloc (abfd, natsize);
514   if (!native)
515     return FALSE;
516
517   generic = section->orelocation;
518
519   if (each_size == RELOC_EXT_SIZE)
520     {
521       for (natptr = native;
522            count != 0;
523            --count, natptr += each_size, ++generic)
524         NAME(lynx,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *) natptr);
525     }
526   else
527     {
528       for (natptr = native;
529            count != 0;
530            --count, natptr += each_size, ++generic)
531         NAME(lynx,swap_std_reloc_out) (abfd, *generic, (struct reloc_std_external *) natptr);
532     }
533
534   if (bfd_bwrite ((PTR) native, natsize, abfd) != natsize)
535     {
536       bfd_release (abfd, native);
537       return FALSE;
538     }
539   bfd_release (abfd, native);
540
541   return TRUE;
542 }
543
544 /* This is stupid.  This function should be a boolean predicate */
545 long
546 NAME(lynx,canonicalize_reloc) (abfd, section, relptr, symbols)
547      bfd *abfd;
548      sec_ptr section;
549      arelent **relptr;
550      asymbol **symbols;
551 {
552   arelent *tblptr = section->relocation;
553   unsigned int count;
554
555   if (!(tblptr || NAME(lynx,slurp_reloc_table) (abfd, section, symbols)))
556     return -1;
557
558   if (section->flags & SEC_CONSTRUCTOR)
559     {
560       arelent_chain *chain = section->constructor_chain;
561       for (count = 0; count < section->reloc_count; count++)
562         {
563           *relptr++ = &chain->relent;
564           chain = chain->next;
565         }
566     }
567   else
568     {
569       tblptr = section->relocation;
570
571       for (count = 0; count++ < section->reloc_count;)
572         {
573           *relptr++ = tblptr++;
574         }
575     }
576   *relptr = 0;
577
578   return section->reloc_count;
579 }
580
581 #define MY_canonicalize_reloc NAME(lynx,canonicalize_reloc)
582
583 #include "aout-target.h"