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