Add bfd_free_cached_info support to a.out backends.
[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   if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
404     return false;
405   each_size = obj_reloc_entry_size (abfd);
406
407   count = reloc_size / each_size;
408
409
410   reloc_cache = (arelent *) malloc (count * sizeof (arelent));
411   if (!reloc_cache && count != 0)
412     {
413     nomem:
414       bfd_set_error (bfd_error_no_memory);
415       return false;
416     }
417   memset (reloc_cache, 0, count * sizeof (arelent));
418
419   relocs = (PTR) bfd_alloc (abfd, reloc_size);
420   if (!relocs)
421     {
422       free (reloc_cache);
423       goto nomem;
424     }
425
426   if (bfd_read (relocs, 1, reloc_size, abfd) != reloc_size)
427     {
428       bfd_release (abfd, relocs);
429       free (reloc_cache);
430       return false;
431     }
432
433   if (each_size == RELOC_EXT_SIZE)
434     {
435       register struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs;
436       unsigned int counter = 0;
437       arelent *cache_ptr = reloc_cache;
438
439       for (; counter < count; counter++, rptr++, cache_ptr++)
440         {
441           NAME (lynx, swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols);
442         }
443     }
444   else
445     {
446       register struct reloc_std_external *rptr = (struct reloc_std_external *) relocs;
447       unsigned int counter = 0;
448       arelent *cache_ptr = reloc_cache;
449
450       for (; counter < count; counter++, rptr++, cache_ptr++)
451         {
452           NAME (lynx, swap_std_reloc_in) (abfd, rptr, cache_ptr, symbols);
453         }
454
455     }
456
457   bfd_release (abfd, relocs);
458   asect->relocation = reloc_cache;
459   asect->reloc_count = count;
460   return true;
461 }
462
463
464
465 /* Write out a relocation section into an object file.  */
466
467 boolean
468 NAME (lynx, squirt_out_relocs) (abfd, section)
469      bfd *abfd;
470      asection *section;
471 {
472   arelent **generic;
473   unsigned char *native, *natptr;
474   size_t each_size;
475
476   unsigned int count = section->reloc_count;
477   size_t natsize;
478
479   if (count == 0)
480     return true;
481
482   each_size = obj_reloc_entry_size (abfd);
483   natsize = each_size * count;
484   native = (unsigned char *) bfd_zalloc (abfd, natsize);
485   if (!native)
486     {
487       bfd_set_error (bfd_error_no_memory);
488       return false;
489     }
490
491   generic = section->orelocation;
492
493   if (each_size == RELOC_EXT_SIZE)
494     {
495       for (natptr = native;
496            count != 0;
497            --count, natptr += each_size, ++generic)
498         NAME (lynx, swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *) natptr);
499     }
500   else
501     {
502       for (natptr = native;
503            count != 0;
504            --count, natptr += each_size, ++generic)
505         NAME (lynx, swap_std_reloc_out) (abfd, *generic, (struct reloc_std_external *) natptr);
506     }
507
508   if (bfd_write ((PTR) native, 1, natsize, abfd) != natsize)
509     {
510       bfd_release (abfd, native);
511       return false;
512     }
513   bfd_release (abfd, native);
514
515   return true;
516 }
517
518 /* This is stupid.  This function should be a boolean predicate */
519 long
520 NAME(lynx,canonicalize_reloc) (abfd, section, relptr, symbols)
521      bfd *abfd;
522      sec_ptr section;
523      arelent **relptr;
524      asymbol **symbols;
525 {
526   arelent *tblptr = section->relocation;
527   unsigned int count;
528
529   if (!(tblptr || NAME (lynx, slurp_reloc_table) (abfd, section, symbols)))
530     return -1;
531
532   if (section->flags & SEC_CONSTRUCTOR)
533     {
534       arelent_chain *chain = section->constructor_chain;
535       for (count = 0; count < section->reloc_count; count++)
536         {
537           *relptr++ = &chain->relent;
538           chain = chain->next;
539         }
540     }
541   else
542     {
543       tblptr = section->relocation;
544       if (!tblptr)
545         return -1;
546
547       for (count = 0; count++ < section->reloc_count;)
548         {
549           *relptr++ = tblptr++;
550         }
551     }
552   *relptr = 0;
553
554   return section->reloc_count;
555 }
556
557 #define MY_canonicalize_reloc NAME(lynx,canonicalize_reloc)
558
559 #include "aout-target.h"