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