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