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