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