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