* configure.in: i386lynx_coff_vec requires coff-i386lynx.o.
[external/binutils.git] / bfd / i386lynx.c
1 /* BFD back-end for i386 a.out binaries under Lynx.
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               NAME(aout,write_syms)(abfd);                                    \
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
90 \f
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 DEFUN(NAME(lynx,swap_std_reloc_out),(abfd, g, natptr),
101       bfd *abfd AND
102       arelent *g AND
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       natptr->r_index[0] = r_index >> 16;
165       natptr->r_index[1] = r_index >> 8;
166       natptr->r_index[2] = r_index;
167       natptr->r_type[0] =
168        (r_extern?    RELOC_STD_BITS_EXTERN_BIG: 0)
169         | (r_pcrel?     RELOC_STD_BITS_PCREL_BIG: 0)
170          | (r_baserel?   RELOC_STD_BITS_BASEREL_BIG: 0)
171           | (r_jmptable?  RELOC_STD_BITS_JMPTABLE_BIG: 0)
172            | (r_relative?  RELOC_STD_BITS_RELATIVE_BIG: 0)
173             | (r_length <<  RELOC_STD_BITS_LENGTH_SH_BIG);
174     } else {
175         natptr->r_index[2] = r_index >> 16;
176         natptr->r_index[1] = r_index >> 8;
177         natptr->r_index[0] = r_index;
178         natptr->r_type[0] =
179          (r_extern?    RELOC_STD_BITS_EXTERN_LITTLE: 0)
180           | (r_pcrel?     RELOC_STD_BITS_PCREL_LITTLE: 0)
181            | (r_baserel?   RELOC_STD_BITS_BASEREL_LITTLE: 0)
182             | (r_jmptable?  RELOC_STD_BITS_JMPTABLE_LITTLE: 0)
183              | (r_relative?  RELOC_STD_BITS_RELATIVE_LITTLE: 0)
184               | (r_length <<  RELOC_STD_BITS_LENGTH_SH_LITTLE);
185       }
186 }
187
188
189 /* Extended stuff */
190 /* Output extended relocation information to a file in target byte order. */
191
192 void
193 DEFUN(NAME(lynx,swap_ext_reloc_out),(abfd, g, natptr),
194       bfd *abfd AND
195       arelent *g AND
196       register struct reloc_ext_external *natptr)
197 {
198   int r_index;
199   int r_extern;
200   unsigned int r_type;
201   unsigned int r_addend;
202   asymbol *sym = *(g->sym_ptr_ptr);    
203   asection *output_section = sym->section->output_section;
204   
205   PUT_WORD (abfd, g->address, natptr->r_address);
206     
207   r_type = (unsigned int) g->howto->type;
208     
209   r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
210
211
212   /* If this relocation is relative to a symbol then set the 
213      r_index to the symbols index, and the r_extern bit.
214
215      Absolute symbols can come in in two ways, either as an offset
216      from the abs section, or as a symbol which has an abs value.
217      check for that here
218      */
219      
220   if (bfd_is_com_section (output_section)
221       || output_section == &bfd_abs_section
222       || output_section == &bfd_und_section)
223   {
224     if (bfd_abs_section.symbol == sym)
225     {
226       /* Whoops, looked like an abs symbol, but is really an offset
227          from the abs section */
228       r_index = 0;
229       r_extern = 0;
230      }
231     else 
232     {
233       r_extern = 1;
234       r_index =  stoi((*(g->sym_ptr_ptr))->KEEPIT);
235     }
236   }
237   else 
238   {
239     /* Just an ordinary section */
240     r_extern = 0;
241     r_index  = output_section->target_index;      
242   }
243          
244          
245   /* now the fun stuff */
246   if (abfd->xvec->header_byteorder_big_p != false) {
247     natptr->r_index[0] = r_index >> 16;
248     natptr->r_index[1] = r_index >> 8;
249     natptr->r_index[2] = r_index;
250     natptr->r_type[0] =
251      (r_extern? RELOC_EXT_BITS_EXTERN_BIG: 0)
252       | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG);
253   } else {
254     natptr->r_index[2] = r_index >> 16;
255     natptr->r_index[1] = r_index >> 8;
256     natptr->r_index[0] = r_index;
257     natptr->r_type[0] =
258      (r_extern? RELOC_EXT_BITS_EXTERN_LITTLE: 0)
259       | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
260   }
261
262   PUT_WORD (abfd, r_addend, natptr->r_addend);
263 }
264
265 /* BFD deals internally with all things based from the section they're
266    in. so, something in 10 bytes into a text section  with a base of
267    50 would have a symbol (.text+10) and know .text vma was 50. 
268
269    Aout keeps all it's symbols based from zero, so the symbol would
270    contain 60. This macro subs the base of each section from the value
271    to give the true offset from the section */
272
273
274 #define MOVE_ADDRESS(ad)                                                \
275   if (r_extern) {                                                       \
276    /* undefined symbol */                                               \
277      cache_ptr->sym_ptr_ptr = symbols + r_index;                        \
278      cache_ptr->addend = ad;                                            \
279      } else {                                                           \
280     /* defined, section relative. replace symbol with pointer to        \
281        symbol which points to section  */                               \
282     switch (r_index) {                                                  \
283     case N_TEXT:                                                        \
284     case N_TEXT | N_EXT:                                                \
285       cache_ptr->sym_ptr_ptr  = obj_textsec(abfd)->symbol_ptr_ptr;      \
286       cache_ptr->addend = ad  - su->textsec->vma;                       \
287       break;                                                            \
288     case N_DATA:                                                        \
289     case N_DATA | N_EXT:                                                \
290       cache_ptr->sym_ptr_ptr  = obj_datasec(abfd)->symbol_ptr_ptr;      \
291       cache_ptr->addend = ad - su->datasec->vma;                        \
292       break;                                                            \
293     case N_BSS:                                                         \
294     case N_BSS | N_EXT:                                                 \
295       cache_ptr->sym_ptr_ptr  = obj_bsssec(abfd)->symbol_ptr_ptr;       \
296       cache_ptr->addend = ad - su->bsssec->vma;                         \
297       break;                                                            \
298     default:                                                            \
299     case N_ABS:                                                         \
300     case N_ABS | N_EXT:                                                 \
301      cache_ptr->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;   \
302       cache_ptr->addend = ad;                                           \
303       break;                                                            \
304     }                                                                   \
305   }                                                                     \
306
307 void
308 DEFUN(NAME(lynx,swap_ext_reloc_in), (abfd, bytes, cache_ptr, symbols),
309       bfd *abfd AND
310       struct reloc_ext_external *bytes AND
311       arelent *cache_ptr AND
312       asymbol **symbols)
313 {
314   int r_index;
315   int r_extern;
316   unsigned int r_type;
317   struct aoutdata *su = &(abfd->tdata.aout_data->a);
318
319   cache_ptr->address = (GET_SWORD (abfd, bytes->r_address));
320
321   /* now the fun stuff */
322   if (1 /* abfd->xvec->header_byteorder_big_p != false */) {
323     r_index =  (bytes->r_index[0] << 16)
324              | (bytes->r_index[1] << 8)
325              |  bytes->r_index[2];
326     r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG));
327     r_type   =       (bytes->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
328                                       >> RELOC_EXT_BITS_TYPE_SH_BIG;
329   } else {
330     r_index =  (bytes->r_index[2] << 16)
331              | (bytes->r_index[1] << 8)
332              |  bytes->r_index[0];
333     r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE));
334     r_type   =       (bytes->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
335                                       >> RELOC_EXT_BITS_TYPE_SH_LITTLE;
336   }
337
338   cache_ptr->howto =  aout_32_ext_howto_table + r_type;
339   MOVE_ADDRESS(GET_SWORD(abfd, bytes->r_addend));
340 }
341
342 void
343 DEFUN(NAME(lynx,swap_std_reloc_in), (abfd, bytes, cache_ptr, symbols),
344   bfd *abfd AND
345   struct reloc_std_external *bytes AND
346   arelent *cache_ptr AND
347   asymbol **symbols)
348 {
349   char tmp;
350   int r_index;
351   int r_extern;
352   unsigned int r_length;
353   int r_pcrel;
354   int r_baserel, r_jmptable, r_relative;
355   struct aoutdata  *su = &(abfd->tdata.aout_data->a);
356
357   cache_ptr->address = bfd_h_get_32 (abfd, bytes->r_address);
358
359   r_index = (bytes->r_type[0] << 16)
360     | (bytes->r_index[2] << 8)
361       |  bytes->r_index[1];
362   r_extern  = (0 != (bytes->r_index[0] & RELOC_STD_BITS_EXTERN_BIG));
363   r_pcrel   = (0 != (bytes->r_index[0] & RELOC_STD_BITS_PCREL_BIG));
364   r_baserel = (0 != (bytes->r_index[0] & RELOC_STD_BITS_BASEREL_BIG));
365   r_jmptable= (0 != (bytes->r_index[0] & RELOC_STD_BITS_JMPTABLE_BIG));
366   r_relative= (0 != (bytes->r_index[0] & RELOC_STD_BITS_RELATIVE_BIG));
367   r_length  =       (bytes->r_index[0] & RELOC_STD_BITS_LENGTH_BIG) 
368     >> RELOC_STD_BITS_LENGTH_SH_BIG;
369
370   cache_ptr->howto =  aout_32_std_howto_table + r_length + 4 * r_pcrel;
371   /* FIXME-soon:  Roll baserel, jmptable, relative bits into howto setting */
372
373   MOVE_ADDRESS(0);
374 }
375
376 /* Reloc hackery */
377
378 boolean
379 DEFUN(NAME(lynx,slurp_reloc_table),(abfd, asect, symbols),
380       bfd *abfd AND
381       sec_ptr asect AND
382       asymbol **symbols)
383 {
384   unsigned int count;
385   bfd_size_type reloc_size;
386   PTR relocs;
387   arelent *reloc_cache;
388   size_t each_size;
389
390   if (asect->relocation) return true;
391
392   if (asect->flags & SEC_CONSTRUCTOR) return true;
393
394   if (asect == obj_datasec (abfd)) {
395     reloc_size = exec_hdr(abfd)->a_drsize;
396     goto doit;
397   }
398
399   if (asect == obj_textsec (abfd)) {
400     reloc_size = exec_hdr(abfd)->a_trsize;
401     goto doit;
402   }
403
404   bfd_error = invalid_operation;
405   return false;
406
407  doit:
408   bfd_seek (abfd, asect->rel_filepos, SEEK_SET);
409   each_size = obj_reloc_entry_size (abfd);
410
411   count = reloc_size / each_size;
412
413
414   reloc_cache = (arelent *) bfd_zalloc (abfd, (size_t)(count * sizeof
415                                                        (arelent)));
416   if (!reloc_cache) {
417 nomem:
418     bfd_error = no_memory;
419     return false;
420   }
421
422   relocs = (PTR) bfd_alloc (abfd, reloc_size);
423   if (!relocs) {
424     bfd_release (abfd, reloc_cache);
425     goto nomem;
426   }
427
428   if (bfd_read (relocs, 1, reloc_size, abfd) != reloc_size) {
429     bfd_release (abfd, relocs);
430     bfd_release (abfd, reloc_cache);
431     bfd_error = system_call_error;
432     return false;
433   }
434
435   if (each_size == RELOC_EXT_SIZE) {
436     register struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs;
437     unsigned int counter = 0;
438     arelent *cache_ptr = reloc_cache;
439
440     for (; counter < count; counter++, rptr++, cache_ptr++) {
441       NAME(lynx,swap_ext_reloc_in)(abfd, rptr, cache_ptr, symbols);
442     }
443   } else {
444     register struct reloc_std_external *rptr = (struct reloc_std_external*) relocs;
445     unsigned int counter = 0;
446     arelent *cache_ptr = reloc_cache;
447
448     for (; counter < count; counter++, rptr++, cache_ptr++) {
449         NAME(lynx,swap_std_reloc_in)(abfd, rptr, cache_ptr, symbols);
450     }
451
452   }
453
454   bfd_release (abfd,relocs);
455   asect->relocation = reloc_cache;
456   asect->reloc_count = count;
457   return true;
458 }
459
460
461
462 /* Write out a relocation section into an object file.  */
463
464 boolean
465 DEFUN(NAME(lynx,squirt_out_relocs),(abfd, section),
466       bfd *abfd AND
467       asection *section)
468 {
469   arelent **generic;
470   unsigned char *native, *natptr;
471   size_t each_size;
472
473   unsigned int count = section->reloc_count;
474   size_t natsize;
475
476   if (count == 0) return true;
477
478   each_size = obj_reloc_entry_size (abfd);
479   natsize = each_size * count;
480   native = (unsigned char *) bfd_zalloc (abfd, natsize);
481   if (!native) {
482     bfd_error = no_memory;
483     return false;
484   }
485
486   generic = section->orelocation;
487
488   if (each_size == RELOC_EXT_SIZE) 
489     {
490       for (natptr = native;
491            count != 0;
492            --count, natptr += each_size, ++generic)
493         NAME(lynx,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *)natptr);
494     }
495   else 
496     {
497       for (natptr = native;
498            count != 0;
499            --count, natptr += each_size, ++generic)
500         NAME(lynx,swap_std_reloc_out)(abfd, *generic, (struct reloc_std_external *)natptr);
501     }
502
503   if ( bfd_write ((PTR) native, 1, natsize, abfd) != natsize) {
504     bfd_release(abfd, native);
505     return false;
506   }
507   bfd_release (abfd, native);
508
509   return true;
510 }
511
512 /* This is stupid.  This function should be a boolean predicate */
513 unsigned int
514 DEFUN(NAME(lynx,canonicalize_reloc),(abfd, section, relptr, symbols),
515       bfd *abfd AND
516       sec_ptr section AND
517       arelent **relptr AND
518       asymbol **symbols)
519 {
520   arelent *tblptr = section->relocation;
521   unsigned int count;
522
523   if (!(tblptr || NAME(lynx,slurp_reloc_table)(abfd, section, symbols)))
524     return 0;
525
526   if (section->flags & SEC_CONSTRUCTOR) {
527     arelent_chain *chain = section->constructor_chain;
528     for (count = 0; count < section->reloc_count; count ++) {
529       *relptr ++ = &chain->relent;
530       chain = chain->next;
531     }
532   }
533   else {
534     tblptr = section->relocation;
535     if (!tblptr) return 0;
536
537     for (count = 0; count++ < section->reloc_count;) 
538       {
539         *relptr++ = tblptr++;
540       }
541   }
542   *relptr = 0;
543
544   return section->reloc_count;
545 }
546
547 #define MY_canonicalize_reloc NAME(lynx,canonicalize_reloc)
548
549 #include "aout-target.h"