daily update
[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, 2012  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 (&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
88 #ifdef LYNX_CORE
89
90 char *lynx_core_file_failing_command ();
91 int lynx_core_file_failing_signal ();
92 bfd_boolean lynx_core_file_matches_executable_p ();
93 const bfd_target *lynx_core_file_p ();
94
95 #define MY_core_file_failing_command lynx_core_file_failing_command
96 #define MY_core_file_failing_signal lynx_core_file_failing_signal
97 #define MY_core_file_matches_executable_p lynx_core_file_matches_executable_p
98 #define MY_core_file_p lynx_core_file_p
99
100 #endif /* LYNX_CORE */
101 \f
102
103 #define KEEPIT udata.i
104
105 extern reloc_howto_type aout_32_ext_howto_table[];
106 extern reloc_howto_type aout_32_std_howto_table[];
107
108 /* Standard reloc stuff */
109 /* Output standard relocation information to a file in target byte order. */
110
111 static void
112 NAME(lynx,swap_std_reloc_out) (bfd *abfd,
113                                arelent *g,
114                                struct reloc_std_external *natptr)
115 {
116   int r_index;
117   asymbol *sym = *(g->sym_ptr_ptr);
118   int r_extern;
119   unsigned int r_length;
120   int r_pcrel;
121   int r_baserel, r_jmptable, r_relative;
122   asection *output_section = sym->section->output_section;
123
124   PUT_WORD (abfd, g->address, natptr->r_address);
125
126   r_length = g->howto->size;    /* Size as a power of two */
127   r_pcrel = (int) g->howto->pc_relative;        /* Relative to PC? */
128   /* r_baserel, r_jmptable, r_relative???  FIXME-soon */
129   r_baserel = 0;
130   r_jmptable = 0;
131   r_relative = 0;
132
133   /* name was clobbered by aout_write_syms to be symbol index */
134
135   /* If this relocation is relative to a symbol then set the
136      r_index to the symbols index, and the r_extern bit.
137
138      Absolute symbols can come in in two ways, either as an offset
139      from the abs section, or as a symbol which has an abs value.
140      check for that here
141   */
142
143   if (bfd_is_com_section (output_section)
144       || bfd_is_abs_section (output_section)
145       || bfd_is_und_section (output_section))
146     {
147       if (bfd_abs_section_ptr->symbol == sym)
148         {
149           /* Whoops, looked like an abs symbol, but is really an offset
150              from the abs section */
151           r_index = 0;
152           r_extern = 0;
153         }
154       else
155         {
156           /* Fill in symbol */
157           r_extern = 1;
158           r_index = (*g->sym_ptr_ptr)->KEEPIT;
159         }
160     }
161   else
162     {
163       /* Just an ordinary section */
164       r_extern = 0;
165       r_index = output_section->target_index;
166     }
167
168   /* now the fun stuff */
169   if (bfd_header_big_endian (abfd))
170     {
171       natptr->r_index[0] = r_index >> 16;
172       natptr->r_index[1] = r_index >> 8;
173       natptr->r_index[2] = r_index;
174       natptr->r_type[0] =
175         (r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0)
176         | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0)
177         | (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0)
178         | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0)
179         | (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0)
180         | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG);
181     }
182   else
183     {
184       natptr->r_index[2] = r_index >> 16;
185       natptr->r_index[1] = r_index >> 8;
186       natptr->r_index[0] = r_index;
187       natptr->r_type[0] =
188         (r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0)
189         | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0)
190         | (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0)
191         | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0)
192         | (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0)
193         | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE);
194     }
195 }
196
197
198 /* Extended stuff */
199 /* Output extended relocation information to a file in target byte order. */
200
201 static void
202 NAME(lynx,swap_ext_reloc_out) (bfd *abfd,
203                                arelent *g,
204                                struct reloc_ext_external *natptr)
205 {
206   int r_index;
207   int r_extern;
208   unsigned int r_type;
209   unsigned int r_addend;
210   asymbol *sym = *(g->sym_ptr_ptr);
211   asection *output_section = sym->section->output_section;
212
213   PUT_WORD (abfd, g->address, natptr->r_address);
214
215   r_type = (unsigned int) g->howto->type;
216
217   r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
218
219
220   /* If this relocation is relative to a symbol then set the
221      r_index to the symbols index, and the r_extern bit.
222
223      Absolute symbols can come in in two ways, either as an offset
224      from the abs section, or as a symbol which has an abs value.
225      check for that here
226      */
227
228   if (bfd_is_com_section (output_section)
229       || bfd_is_abs_section (output_section)
230       || bfd_is_und_section (output_section))
231     {
232       if (bfd_abs_section_ptr->symbol == sym)
233         {
234           /* Whoops, looked like an abs symbol, but is really an offset
235          from the abs section */
236           r_index = 0;
237           r_extern = 0;
238         }
239       else
240         {
241           r_extern = 1;
242           r_index = (*g->sym_ptr_ptr)->KEEPIT;
243         }
244     }
245   else
246     {
247       /* Just an ordinary section */
248       r_extern = 0;
249       r_index = output_section->target_index;
250     }
251
252
253   /* now the fun stuff */
254   if (bfd_header_big_endian (abfd))
255     {
256       natptr->r_index[0] = r_index >> 16;
257       natptr->r_index[1] = r_index >> 8;
258       natptr->r_index[2] = r_index;
259       natptr->r_type[0] =
260         (r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0)
261         | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG);
262     }
263   else
264     {
265       natptr->r_index[2] = r_index >> 16;
266       natptr->r_index[1] = r_index >> 8;
267       natptr->r_index[0] = r_index;
268       natptr->r_type[0] =
269         (r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0)
270         | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
271     }
272
273   PUT_WORD (abfd, r_addend, natptr->r_addend);
274 }
275
276 /* BFD deals internally with all things based from the section they're
277    in. so, something in 10 bytes into a text section  with a base of
278    50 would have a symbol (.text+10) and know .text vma was 50.
279
280    Aout keeps all it's symbols based from zero, so the symbol would
281    contain 60. This macro subs the base of each section from the value
282    to give the true offset from the section */
283
284
285 #define MOVE_ADDRESS(ad)                                                \
286   if (r_extern)                                                         \
287     {                                                                   \
288    /* undefined symbol */                                               \
289      cache_ptr->sym_ptr_ptr = symbols + r_index;                        \
290      cache_ptr->addend = ad;                                            \
291     }                                                                   \
292   else                                                                  \
293     {                                                                   \
294     /* defined, section relative. replace symbol with pointer to        \
295        symbol which points to section  */                               \
296     switch (r_index) {                                                  \
297     case N_TEXT:                                                        \
298     case N_TEXT | N_EXT:                                                \
299       cache_ptr->sym_ptr_ptr  = obj_textsec(abfd)->symbol_ptr_ptr;      \
300       cache_ptr->addend = ad  - su->textsec->vma;                       \
301       break;                                                            \
302     case N_DATA:                                                        \
303     case N_DATA | N_EXT:                                                \
304       cache_ptr->sym_ptr_ptr  = obj_datasec(abfd)->symbol_ptr_ptr;      \
305       cache_ptr->addend = ad - su->datasec->vma;                        \
306       break;                                                            \
307     case N_BSS:                                                         \
308     case N_BSS | N_EXT:                                                 \
309       cache_ptr->sym_ptr_ptr  = obj_bsssec(abfd)->symbol_ptr_ptr;       \
310       cache_ptr->addend = ad - su->bsssec->vma;                         \
311       break;                                                            \
312     default:                                                            \
313     case N_ABS:                                                         \
314     case N_ABS | N_EXT:                                                 \
315      cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;      \
316       cache_ptr->addend = ad;                                           \
317       break;                                                            \
318     }                                                                   \
319   }                                                                     \
320
321 static void
322 NAME(lynx,swap_ext_reloc_in) (bfd *abfd,
323                               struct reloc_ext_external *bytes,
324                               arelent *cache_ptr,
325                               asymbol **symbols,
326                               bfd_size_type symcount ATTRIBUTE_UNUSED)
327 {
328   int r_index;
329   int r_extern;
330   unsigned int r_type;
331   struct aoutdata *su = &(abfd->tdata.aout_data->a);
332
333   cache_ptr->address = (GET_SWORD (abfd, bytes->r_address));
334
335   r_index = bytes->r_index[1];
336   r_extern = (0 != (bytes->r_index[0] & RELOC_EXT_BITS_EXTERN_BIG));
337   r_type = (bytes->r_index[0] & RELOC_EXT_BITS_TYPE_BIG)
338     >> RELOC_EXT_BITS_TYPE_SH_BIG;
339
340   cache_ptr->howto = aout_32_ext_howto_table + r_type;
341   MOVE_ADDRESS (GET_SWORD (abfd, bytes->r_addend));
342 }
343
344 static void
345 NAME(lynx,swap_std_reloc_in) (bfd *abfd,
346                               struct reloc_std_external *bytes,
347                               arelent *cache_ptr,
348                               asymbol **symbols,
349                               bfd_size_type symcount ATTRIBUTE_UNUSED)
350 {
351   int r_index;
352   int r_extern;
353   unsigned int r_length;
354   int r_pcrel;
355   struct aoutdata *su = &(abfd->tdata.aout_data->a);
356
357   cache_ptr->address = H_GET_32 (abfd, bytes->r_address);
358
359   r_index = bytes->r_index[1];
360   r_extern = (0 != (bytes->r_index[0] & RELOC_STD_BITS_EXTERN_BIG));
361   r_pcrel = (0 != (bytes->r_index[0] & RELOC_STD_BITS_PCREL_BIG));
362   r_length = (bytes->r_index[0] & RELOC_STD_BITS_LENGTH_BIG)
363     >> RELOC_STD_BITS_LENGTH_SH_BIG;
364
365   cache_ptr->howto = aout_32_std_howto_table + r_length + 4 * r_pcrel;
366   /* FIXME-soon:  Roll baserel, jmptable, relative bits into howto setting */
367
368   MOVE_ADDRESS (0);
369 }
370
371 /* Reloc hackery */
372
373 static bfd_boolean
374 NAME(lynx,slurp_reloc_table) (bfd *abfd,
375                               sec_ptr asect,
376                               asymbol **symbols)
377 {
378   bfd_size_type count;
379   bfd_size_type reloc_size;
380   void * relocs;
381   arelent *reloc_cache;
382   size_t each_size;
383
384   if (asect->relocation)
385     return TRUE;
386
387   if (asect->flags & SEC_CONSTRUCTOR)
388     return TRUE;
389
390   if (asect == obj_datasec (abfd))
391     {
392       reloc_size = exec_hdr (abfd)->a_drsize;
393       goto doit;
394     }
395
396   if (asect == obj_textsec (abfd))
397     {
398       reloc_size = exec_hdr (abfd)->a_trsize;
399       goto doit;
400     }
401
402   bfd_set_error (bfd_error_invalid_operation);
403   return FALSE;
404
405 doit:
406   if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
407     return FALSE;
408   each_size = obj_reloc_entry_size (abfd);
409
410   count = reloc_size / each_size;
411
412
413   reloc_cache = (arelent *) bfd_zmalloc (count * sizeof (arelent));
414   if (!reloc_cache && count != 0)
415     return FALSE;
416
417   relocs = bfd_alloc (abfd, reloc_size);
418   if (!relocs && reloc_size != 0)
419     {
420       free (reloc_cache);
421       return FALSE;
422     }
423
424   if (bfd_bread (relocs, reloc_size, abfd) != reloc_size)
425     {
426       bfd_release (abfd, relocs);
427       free (reloc_cache);
428       return FALSE;
429     }
430
431   if (each_size == RELOC_EXT_SIZE)
432     {
433       struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs;
434       unsigned int counter = 0;
435       arelent *cache_ptr = reloc_cache;
436
437       for (; counter < count; counter++, rptr++, cache_ptr++)
438         {
439           NAME(lynx,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols,
440                                         (bfd_size_type) bfd_get_symcount (abfd));
441         }
442     }
443   else
444     {
445       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                                         (bfd_size_type) bfd_get_symcount (abfd));
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 static bfd_boolean
468 NAME(lynx,squirt_out_relocs) (bfd *abfd, asection *section)
469 {
470   arelent **generic;
471   unsigned char *native, *natptr;
472   size_t each_size;
473   unsigned int count = section->reloc_count;
474   bfd_size_type natsize;
475
476   if (count == 0)
477     return TRUE;
478
479   each_size = obj_reloc_entry_size (abfd);
480   natsize = count;
481   natsize *= each_size;
482   native = (unsigned char *) bfd_zalloc (abfd, natsize);
483   if (!native)
484     return FALSE;
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_bwrite (native, natsize, abfd) != natsize)
504     {
505       bfd_release (abfd, native);
506       return FALSE;
507     }
508   bfd_release (abfd, native);
509
510   return TRUE;
511 }
512
513 /* This is stupid.  This function should be a boolean predicate */
514 static long
515 NAME(lynx,canonicalize_reloc) (bfd *abfd,
516                                sec_ptr section,
517                                arelent **relptr,
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 -1;
525
526   if (section->flags & SEC_CONSTRUCTOR)
527     {
528       arelent_chain *chain = section->constructor_chain;
529       for (count = 0; count < section->reloc_count; count++)
530         {
531           *relptr++ = &chain->relent;
532           chain = chain->next;
533         }
534     }
535   else
536     {
537       tblptr = section->relocation;
538
539       for (count = 0; count++ < section->reloc_count;)
540         {
541           *relptr++ = tblptr++;
542         }
543     }
544   *relptr = 0;
545
546   return section->reloc_count;
547 }
548
549 #define MY_canonicalize_reloc NAME(lynx,canonicalize_reloc)
550
551 #include "aout-target.h"