merge from gcc
[platform/upstream/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, 1999, 2001, 2002,
3    2003, 2005, 2007, 2009, 2010 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 3 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., 51 Franklin Street - Fifth Floor, Boston,
20    MA 02110-1301, USA.  */
21
22 #define TEXT_START_ADDR 0
23 #define TARGET_PAGE_SIZE 4096
24 #define SEGMENT_SIZE TARGET_PAGE_SIZE
25 #define DEFAULT_ARCH bfd_arch_i386
26
27 /* Do not "beautify" the CONCAT* macro args.  Traditional C will not
28    remove whitespace added here, and thus will fail to concatenate
29    the tokens.  */
30 #define MY(OP) CONCAT2 (i386lynx_aout_,OP)
31 #define TARGETNAME "a.out-i386-lynx"
32
33 #include "sysdep.h"
34 #include "bfd.h"
35 #include "libbfd.h"
36
37 #ifndef WRITE_HEADERS
38 #define WRITE_HEADERS(abfd, execp)                                            \
39       {                                                                       \
40         bfd_size_type text_size; /* dummy vars */                             \
41         file_ptr text_end;                                                    \
42         if (adata(abfd).magic == undecided_magic)                             \
43           NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end);     \
44                                                                               \
45         execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE;        \
46         execp->a_entry = bfd_get_start_address (abfd);                        \
47                                                                               \
48         execp->a_trsize = ((obj_textsec (abfd)->reloc_count) *                \
49                            obj_reloc_entry_size (abfd));                      \
50         execp->a_drsize = ((obj_datasec (abfd)->reloc_count) *                \
51                            obj_reloc_entry_size (abfd));                      \
52         NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes);           \
53                                                                               \
54         if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0                      \
55             || bfd_bwrite ((PTR) &exec_bytes, (bfd_size_type) EXEC_BYTES_SIZE, \
56                           abfd) != EXEC_BYTES_SIZE)                           \
57           return FALSE;                                                       \
58         /* Now write out reloc info, followed by syms and strings */          \
59                                                                               \
60         if (bfd_get_symcount (abfd) != 0)                                     \
61             {                                                                 \
62               if (bfd_seek (abfd, (file_ptr) (N_SYMOFF(*execp)), SEEK_SET)    \
63                   != 0)                                                       \
64                 return FALSE;                                                 \
65                                                                               \
66               if (! NAME(aout,write_syms) (abfd)) return FALSE;               \
67                                                                               \
68               if (bfd_seek (abfd, (file_ptr) (N_TRELOFF(*execp)), SEEK_SET)   \
69                   != 0)                                                       \
70                 return FALSE;                                                 \
71                                                                               \
72               if (!NAME(lynx,squirt_out_relocs) (abfd, obj_textsec (abfd)))   \
73                 return FALSE;                                                 \
74               if (bfd_seek (abfd, (file_ptr) (N_DRELOFF(*execp)), SEEK_SET)   \
75                   != 0)                                                       \
76                 return 0;                                                     \
77                                                                               \
78               if (!NAME(lynx,squirt_out_relocs) (abfd, obj_datasec (abfd)))   \
79                 return FALSE;                                                 \
80             }                                                                 \
81       }
82 #endif
83
84 #include "libaout.h"
85 #include "aout/aout64.h"
86
87 void NAME (lynx,swap_std_reloc_out)
88   PARAMS ((bfd *, arelent *, struct reloc_std_external *));
89 void NAME (lynx,swap_ext_reloc_out)
90   PARAMS ((bfd *, arelent *, struct reloc_ext_external *));
91 void NAME (lynx,swap_ext_reloc_in)
92   PARAMS ((bfd *, struct reloc_ext_external *, arelent *, asymbol **,
93            bfd_size_type));
94 void NAME (lynx,swap_std_reloc_in)
95   PARAMS ((bfd *, struct reloc_std_external *, arelent *, asymbol **,
96            bfd_size_type));
97 bfd_boolean NAME (lynx,slurp_reloc_table)
98   PARAMS ((bfd *, sec_ptr, asymbol **));
99 bfd_boolean NAME (lynx,squirt_out_relocs)
100   PARAMS ((bfd *, asection *));
101 long NAME (lynx,canonicalize_reloc)
102   PARAMS ((bfd *, sec_ptr, arelent **, asymbol **));
103
104 #ifdef LYNX_CORE
105
106 char *lynx_core_file_failing_command ();
107 int lynx_core_file_failing_signal ();
108 bfd_boolean lynx_core_file_matches_executable_p ();
109 const bfd_target *lynx_core_file_p ();
110
111 #define MY_core_file_failing_command lynx_core_file_failing_command
112 #define MY_core_file_failing_signal lynx_core_file_failing_signal
113 #define MY_core_file_matches_executable_p lynx_core_file_matches_executable_p
114 #define MY_core_file_p lynx_core_file_p
115
116 #endif /* LYNX_CORE */
117 \f
118
119 #define KEEPIT udata.i
120
121 extern reloc_howto_type aout_32_ext_howto_table[];
122 extern reloc_howto_type aout_32_std_howto_table[];
123
124 /* Standard reloc stuff */
125 /* Output standard relocation information to a file in target byte order. */
126
127 void
128 NAME(lynx,swap_std_reloc_out) (abfd, g, natptr)
129      bfd *abfd;
130      arelent *g;
131      struct reloc_std_external *natptr;
132 {
133   int r_index;
134   asymbol *sym = *(g->sym_ptr_ptr);
135   int r_extern;
136   unsigned int r_length;
137   int r_pcrel;
138   int r_baserel, r_jmptable, r_relative;
139   asection *output_section = sym->section->output_section;
140
141   PUT_WORD (abfd, g->address, natptr->r_address);
142
143   r_length = g->howto->size;    /* Size as a power of two */
144   r_pcrel = (int) g->howto->pc_relative;        /* Relative to PC? */
145   /* r_baserel, r_jmptable, r_relative???  FIXME-soon */
146   r_baserel = 0;
147   r_jmptable = 0;
148   r_relative = 0;
149
150   /* name was clobbered by aout_write_syms to be symbol index */
151
152   /* If this relocation is relative to a symbol then set the
153      r_index to the symbols index, and the r_extern bit.
154
155      Absolute symbols can come in in two ways, either as an offset
156      from the abs section, or as a symbol which has an abs value.
157      check for that here
158   */
159
160
161   if (bfd_is_com_section (output_section)
162       || bfd_is_abs_section (output_section)
163       || bfd_is_und_section (output_section))
164     {
165       if (bfd_abs_section_ptr->symbol == sym)
166         {
167           /* Whoops, looked like an abs symbol, but is really an offset
168              from the abs section */
169           r_index = 0;
170           r_extern = 0;
171         }
172       else
173         {
174           /* Fill in symbol */
175           r_extern = 1;
176           r_index = (*g->sym_ptr_ptr)->KEEPIT;
177         }
178     }
179   else
180     {
181       /* Just an ordinary section */
182       r_extern = 0;
183       r_index = output_section->target_index;
184     }
185
186   /* now the fun stuff */
187   if (bfd_header_big_endian (abfd))
188     {
189       natptr->r_index[0] = r_index >> 16;
190       natptr->r_index[1] = r_index >> 8;
191       natptr->r_index[2] = r_index;
192       natptr->r_type[0] =
193         (r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0)
194         | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0)
195         | (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0)
196         | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0)
197         | (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0)
198         | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG);
199     }
200   else
201     {
202       natptr->r_index[2] = r_index >> 16;
203       natptr->r_index[1] = r_index >> 8;
204       natptr->r_index[0] = r_index;
205       natptr->r_type[0] =
206         (r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0)
207         | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0)
208         | (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0)
209         | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0)
210         | (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0)
211         | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE);
212     }
213 }
214
215
216 /* Extended stuff */
217 /* Output extended relocation information to a file in target byte order. */
218
219 void
220 NAME(lynx,swap_ext_reloc_out) (abfd, g, natptr)
221      bfd *abfd;
222      arelent *g;
223      register struct reloc_ext_external *natptr;
224 {
225   int r_index;
226   int r_extern;
227   unsigned int r_type;
228   unsigned int r_addend;
229   asymbol *sym = *(g->sym_ptr_ptr);
230   asection *output_section = sym->section->output_section;
231
232   PUT_WORD (abfd, g->address, natptr->r_address);
233
234   r_type = (unsigned int) g->howto->type;
235
236   r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
237
238
239   /* If this relocation is relative to a symbol then set the
240      r_index to the symbols index, and the r_extern bit.
241
242      Absolute symbols can come in in two ways, either as an offset
243      from the abs section, or as a symbol which has an abs value.
244      check for that here
245      */
246
247   if (bfd_is_com_section (output_section)
248       || bfd_is_abs_section (output_section)
249       || bfd_is_und_section (output_section))
250     {
251       if (bfd_abs_section_ptr->symbol == sym)
252         {
253           /* Whoops, looked like an abs symbol, but is really an offset
254          from the abs section */
255           r_index = 0;
256           r_extern = 0;
257         }
258       else
259         {
260           r_extern = 1;
261           r_index = (*g->sym_ptr_ptr)->KEEPIT;
262         }
263     }
264   else
265     {
266       /* Just an ordinary section */
267       r_extern = 0;
268       r_index = output_section->target_index;
269     }
270
271
272   /* now the fun stuff */
273   if (bfd_header_big_endian (abfd))
274     {
275       natptr->r_index[0] = r_index >> 16;
276       natptr->r_index[1] = r_index >> 8;
277       natptr->r_index[2] = r_index;
278       natptr->r_type[0] =
279         (r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0)
280         | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG);
281     }
282   else
283     {
284       natptr->r_index[2] = r_index >> 16;
285       natptr->r_index[1] = r_index >> 8;
286       natptr->r_index[0] = r_index;
287       natptr->r_type[0] =
288         (r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0)
289         | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
290     }
291
292   PUT_WORD (abfd, r_addend, natptr->r_addend);
293 }
294
295 /* BFD deals internally with all things based from the section they're
296    in. so, something in 10 bytes into a text section  with a base of
297    50 would have a symbol (.text+10) and know .text vma was 50.
298
299    Aout keeps all it's symbols based from zero, so the symbol would
300    contain 60. This macro subs the base of each section from the value
301    to give the true offset from the section */
302
303
304 #define MOVE_ADDRESS(ad)                                                \
305   if (r_extern) {                                                       \
306    /* undefined symbol */                                               \
307      cache_ptr->sym_ptr_ptr = symbols + r_index;                        \
308      cache_ptr->addend = ad;                                            \
309      } else {                                                           \
310     /* defined, section relative. replace symbol with pointer to        \
311        symbol which points to section  */                               \
312     switch (r_index) {                                                  \
313     case N_TEXT:                                                        \
314     case N_TEXT | N_EXT:                                                \
315       cache_ptr->sym_ptr_ptr  = obj_textsec(abfd)->symbol_ptr_ptr;      \
316       cache_ptr->addend = ad  - su->textsec->vma;                       \
317       break;                                                            \
318     case N_DATA:                                                        \
319     case N_DATA | N_EXT:                                                \
320       cache_ptr->sym_ptr_ptr  = obj_datasec(abfd)->symbol_ptr_ptr;      \
321       cache_ptr->addend = ad - su->datasec->vma;                        \
322       break;                                                            \
323     case N_BSS:                                                         \
324     case N_BSS | N_EXT:                                                 \
325       cache_ptr->sym_ptr_ptr  = obj_bsssec(abfd)->symbol_ptr_ptr;       \
326       cache_ptr->addend = ad - su->bsssec->vma;                         \
327       break;                                                            \
328     default:                                                            \
329     case N_ABS:                                                         \
330     case N_ABS | N_EXT:                                                 \
331      cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;      \
332       cache_ptr->addend = ad;                                           \
333       break;                                                            \
334     }                                                                   \
335   }                                                                     \
336
337 void
338 NAME(lynx,swap_ext_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount)
339      bfd *abfd;
340      struct reloc_ext_external *bytes;
341      arelent *cache_ptr;
342      asymbol **symbols;
343      bfd_size_type symcount ATTRIBUTE_UNUSED;
344 {
345   int r_index;
346   int r_extern;
347   unsigned int r_type;
348   struct aoutdata *su = &(abfd->tdata.aout_data->a);
349
350   cache_ptr->address = (GET_SWORD (abfd, bytes->r_address));
351
352   r_index = bytes->r_index[1];
353   r_extern = (0 != (bytes->r_index[0] & RELOC_EXT_BITS_EXTERN_BIG));
354   r_type = (bytes->r_index[0] & RELOC_EXT_BITS_TYPE_BIG)
355     >> RELOC_EXT_BITS_TYPE_SH_BIG;
356
357   cache_ptr->howto = aout_32_ext_howto_table + r_type;
358   MOVE_ADDRESS (GET_SWORD (abfd, bytes->r_addend));
359 }
360
361 void
362 NAME(lynx,swap_std_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount)
363      bfd *abfd;
364      struct reloc_std_external *bytes;
365      arelent *cache_ptr;
366      asymbol **symbols;
367      bfd_size_type symcount ATTRIBUTE_UNUSED;
368 {
369   int r_index;
370   int r_extern;
371   unsigned int r_length;
372   int r_pcrel;
373   struct aoutdata *su = &(abfd->tdata.aout_data->a);
374
375   cache_ptr->address = H_GET_32 (abfd, bytes->r_address);
376
377   r_index = bytes->r_index[1];
378   r_extern = (0 != (bytes->r_index[0] & RELOC_STD_BITS_EXTERN_BIG));
379   r_pcrel = (0 != (bytes->r_index[0] & RELOC_STD_BITS_PCREL_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 bfd_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 bfd_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"