2009-12-04 Rafael Avila de Espindola <espindola@google.com>
[binutils.git] / bfd / i386lynx.c
blob45909bf603c997d2a1a0533af25f3740a723c666
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 Free Software Foundation, Inc.
5 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
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
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"
33 #include "sysdep.h"
34 #include "bfd.h"
35 #include "libbfd.h"
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); \
45 execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE; \
46 execp->a_entry = bfd_get_start_address (abfd); \
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); \
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 */ \
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; \
66 if (! NAME(aout,write_syms) (abfd)) return FALSE; \
68 if (bfd_seek (abfd, (file_ptr) (N_TRELOFF(*execp)), SEEK_SET) \
69 != 0) \
70 return FALSE; \
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; \
78 if (!NAME(lynx,squirt_out_relocs) (abfd, obj_datasec (abfd))) \
79 return FALSE; \
80 } \
82 #endif
84 #include "libaout.h"
85 #include "aout/aout64.h"
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 **));
104 #ifdef LYNX_CORE
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 ();
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
116 #endif /* LYNX_CORE */
119 #define KEEPIT udata.i
121 extern reloc_howto_type aout_32_ext_howto_table[];
122 extern reloc_howto_type aout_32_std_howto_table[];
124 /* Standard reloc stuff */
125 /* Output standard relocation information to a file in target byte order. */
127 void
128 NAME(lynx,swap_std_reloc_out) (abfd, g, natptr)
129 bfd *abfd;
130 arelent *g;
131 struct reloc_std_external *natptr;
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 unsigned int r_addend;
140 asection *output_section = sym->section->output_section;
142 PUT_WORD (abfd, g->address, natptr->r_address);
144 r_length = g->howto->size; /* Size as a power of two */
145 r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */
146 /* r_baserel, r_jmptable, r_relative??? FIXME-soon */
147 r_baserel = 0;
148 r_jmptable = 0;
149 r_relative = 0;
151 r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
153 /* name was clobbered by aout_write_syms to be symbol index */
155 /* If this relocation is relative to a symbol then set the
156 r_index to the symbols index, and the r_extern bit.
158 Absolute symbols can come in in two ways, either as an offset
159 from the abs section, or as a symbol which has an abs value.
160 check for that here
164 if (bfd_is_com_section (output_section)
165 || bfd_is_abs_section (output_section)
166 || bfd_is_und_section (output_section))
168 if (bfd_abs_section_ptr->symbol == sym)
170 /* Whoops, looked like an abs symbol, but is really an offset
171 from the abs section */
172 r_index = 0;
173 r_extern = 0;
175 else
177 /* Fill in symbol */
178 r_extern = 1;
179 r_index = (*g->sym_ptr_ptr)->KEEPIT;
182 else
184 /* Just an ordinary section */
185 r_extern = 0;
186 r_index = output_section->target_index;
189 /* now the fun stuff */
190 if (bfd_header_big_endian (abfd))
192 natptr->r_index[0] = r_index >> 16;
193 natptr->r_index[1] = r_index >> 8;
194 natptr->r_index[2] = r_index;
195 natptr->r_type[0] =
196 (r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0)
197 | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0)
198 | (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0)
199 | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0)
200 | (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0)
201 | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG);
203 else
205 natptr->r_index[2] = r_index >> 16;
206 natptr->r_index[1] = r_index >> 8;
207 natptr->r_index[0] = r_index;
208 natptr->r_type[0] =
209 (r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0)
210 | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0)
211 | (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0)
212 | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0)
213 | (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0)
214 | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE);
219 /* Extended stuff */
220 /* Output extended relocation information to a file in target byte order. */
222 void
223 NAME(lynx,swap_ext_reloc_out) (abfd, g, natptr)
224 bfd *abfd;
225 arelent *g;
226 register struct reloc_ext_external *natptr;
228 int r_index;
229 int r_extern;
230 unsigned int r_type;
231 unsigned int r_addend;
232 asymbol *sym = *(g->sym_ptr_ptr);
233 asection *output_section = sym->section->output_section;
235 PUT_WORD (abfd, g->address, natptr->r_address);
237 r_type = (unsigned int) g->howto->type;
239 r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
242 /* If this relocation is relative to a symbol then set the
243 r_index to the symbols index, and the r_extern bit.
245 Absolute symbols can come in in two ways, either as an offset
246 from the abs section, or as a symbol which has an abs value.
247 check for that here
250 if (bfd_is_com_section (output_section)
251 || bfd_is_abs_section (output_section)
252 || bfd_is_und_section (output_section))
254 if (bfd_abs_section_ptr->symbol == sym)
256 /* Whoops, looked like an abs symbol, but is really an offset
257 from the abs section */
258 r_index = 0;
259 r_extern = 0;
261 else
263 r_extern = 1;
264 r_index = (*g->sym_ptr_ptr)->KEEPIT;
267 else
269 /* Just an ordinary section */
270 r_extern = 0;
271 r_index = output_section->target_index;
275 /* now the fun stuff */
276 if (bfd_header_big_endian (abfd))
278 natptr->r_index[0] = r_index >> 16;
279 natptr->r_index[1] = r_index >> 8;
280 natptr->r_index[2] = r_index;
281 natptr->r_type[0] =
282 (r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0)
283 | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG);
285 else
287 natptr->r_index[2] = r_index >> 16;
288 natptr->r_index[1] = r_index >> 8;
289 natptr->r_index[0] = r_index;
290 natptr->r_type[0] =
291 (r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0)
292 | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
295 PUT_WORD (abfd, r_addend, natptr->r_addend);
298 /* BFD deals internally with all things based from the section they're
299 in. so, something in 10 bytes into a text section with a base of
300 50 would have a symbol (.text+10) and know .text vma was 50.
302 Aout keeps all it's symbols based from zero, so the symbol would
303 contain 60. This macro subs the base of each section from the value
304 to give the true offset from the section */
307 #define MOVE_ADDRESS(ad) \
308 if (r_extern) { \
309 /* undefined symbol */ \
310 cache_ptr->sym_ptr_ptr = symbols + r_index; \
311 cache_ptr->addend = ad; \
312 } else { \
313 /* defined, section relative. replace symbol with pointer to \
314 symbol which points to section */ \
315 switch (r_index) { \
316 case N_TEXT: \
317 case N_TEXT | N_EXT: \
318 cache_ptr->sym_ptr_ptr = obj_textsec(abfd)->symbol_ptr_ptr; \
319 cache_ptr->addend = ad - su->textsec->vma; \
320 break; \
321 case N_DATA: \
322 case N_DATA | N_EXT: \
323 cache_ptr->sym_ptr_ptr = obj_datasec(abfd)->symbol_ptr_ptr; \
324 cache_ptr->addend = ad - su->datasec->vma; \
325 break; \
326 case N_BSS: \
327 case N_BSS | N_EXT: \
328 cache_ptr->sym_ptr_ptr = obj_bsssec(abfd)->symbol_ptr_ptr; \
329 cache_ptr->addend = ad - su->bsssec->vma; \
330 break; \
331 default: \
332 case N_ABS: \
333 case N_ABS | N_EXT: \
334 cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; \
335 cache_ptr->addend = ad; \
336 break; \
340 void
341 NAME(lynx,swap_ext_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount)
342 bfd *abfd;
343 struct reloc_ext_external *bytes;
344 arelent *cache_ptr;
345 asymbol **symbols;
346 bfd_size_type symcount ATTRIBUTE_UNUSED;
348 int r_index;
349 int r_extern;
350 unsigned int r_type;
351 struct aoutdata *su = &(abfd->tdata.aout_data->a);
353 cache_ptr->address = (GET_SWORD (abfd, bytes->r_address));
355 r_index = bytes->r_index[1];
356 r_extern = (0 != (bytes->r_index[0] & RELOC_EXT_BITS_EXTERN_BIG));
357 r_type = (bytes->r_index[0] & RELOC_EXT_BITS_TYPE_BIG)
358 >> RELOC_EXT_BITS_TYPE_SH_BIG;
360 cache_ptr->howto = aout_32_ext_howto_table + r_type;
361 MOVE_ADDRESS (GET_SWORD (abfd, bytes->r_addend));
364 void
365 NAME(lynx,swap_std_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount)
366 bfd *abfd;
367 struct reloc_std_external *bytes;
368 arelent *cache_ptr;
369 asymbol **symbols;
370 bfd_size_type symcount ATTRIBUTE_UNUSED;
372 int r_index;
373 int r_extern;
374 unsigned int r_length;
375 int r_pcrel;
376 int r_baserel, r_jmptable, r_relative;
377 struct aoutdata *su = &(abfd->tdata.aout_data->a);
379 cache_ptr->address = H_GET_32 (abfd, bytes->r_address);
381 r_index = bytes->r_index[1];
382 r_extern = (0 != (bytes->r_index[0] & RELOC_STD_BITS_EXTERN_BIG));
383 r_pcrel = (0 != (bytes->r_index[0] & RELOC_STD_BITS_PCREL_BIG));
384 r_baserel = (0 != (bytes->r_index[0] & RELOC_STD_BITS_BASEREL_BIG));
385 r_jmptable = (0 != (bytes->r_index[0] & RELOC_STD_BITS_JMPTABLE_BIG));
386 r_relative = (0 != (bytes->r_index[0] & RELOC_STD_BITS_RELATIVE_BIG));
387 r_length = (bytes->r_index[0] & RELOC_STD_BITS_LENGTH_BIG)
388 >> RELOC_STD_BITS_LENGTH_SH_BIG;
390 cache_ptr->howto = aout_32_std_howto_table + r_length + 4 * r_pcrel;
391 /* FIXME-soon: Roll baserel, jmptable, relative bits into howto setting */
393 MOVE_ADDRESS (0);
396 /* Reloc hackery */
398 bfd_boolean
399 NAME(lynx,slurp_reloc_table) (abfd, asect, symbols)
400 bfd *abfd;
401 sec_ptr asect;
402 asymbol **symbols;
404 bfd_size_type count;
405 bfd_size_type reloc_size;
406 PTR relocs;
407 arelent *reloc_cache;
408 size_t each_size;
410 if (asect->relocation)
411 return TRUE;
413 if (asect->flags & SEC_CONSTRUCTOR)
414 return TRUE;
416 if (asect == obj_datasec (abfd))
418 reloc_size = exec_hdr (abfd)->a_drsize;
419 goto doit;
422 if (asect == obj_textsec (abfd))
424 reloc_size = exec_hdr (abfd)->a_trsize;
425 goto doit;
428 bfd_set_error (bfd_error_invalid_operation);
429 return FALSE;
431 doit:
432 if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
433 return FALSE;
434 each_size = obj_reloc_entry_size (abfd);
436 count = reloc_size / each_size;
439 reloc_cache = (arelent *) bfd_zmalloc (count * sizeof (arelent));
440 if (!reloc_cache && count != 0)
441 return FALSE;
443 relocs = (PTR) bfd_alloc (abfd, reloc_size);
444 if (!relocs && reloc_size != 0)
446 free (reloc_cache);
447 return FALSE;
450 if (bfd_bread (relocs, reloc_size, abfd) != reloc_size)
452 bfd_release (abfd, relocs);
453 free (reloc_cache);
454 return FALSE;
457 if (each_size == RELOC_EXT_SIZE)
459 register struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs;
460 unsigned int counter = 0;
461 arelent *cache_ptr = reloc_cache;
463 for (; counter < count; counter++, rptr++, cache_ptr++)
465 NAME(lynx,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols,
466 (bfd_size_type) bfd_get_symcount (abfd));
469 else
471 register struct reloc_std_external *rptr = (struct reloc_std_external *) relocs;
472 unsigned int counter = 0;
473 arelent *cache_ptr = reloc_cache;
475 for (; counter < count; counter++, rptr++, cache_ptr++)
477 NAME(lynx,swap_std_reloc_in) (abfd, rptr, cache_ptr, symbols,
478 (bfd_size_type) bfd_get_symcount (abfd));
483 bfd_release (abfd, relocs);
484 asect->relocation = reloc_cache;
485 asect->reloc_count = count;
486 return TRUE;
491 /* Write out a relocation section into an object file. */
493 bfd_boolean
494 NAME(lynx,squirt_out_relocs) (abfd, section)
495 bfd *abfd;
496 asection *section;
498 arelent **generic;
499 unsigned char *native, *natptr;
500 size_t each_size;
502 unsigned int count = section->reloc_count;
503 bfd_size_type natsize;
505 if (count == 0)
506 return TRUE;
508 each_size = obj_reloc_entry_size (abfd);
509 natsize = count;
510 natsize *= each_size;
511 native = (unsigned char *) bfd_zalloc (abfd, natsize);
512 if (!native)
513 return FALSE;
515 generic = section->orelocation;
517 if (each_size == RELOC_EXT_SIZE)
519 for (natptr = native;
520 count != 0;
521 --count, natptr += each_size, ++generic)
522 NAME(lynx,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *) natptr);
524 else
526 for (natptr = native;
527 count != 0;
528 --count, natptr += each_size, ++generic)
529 NAME(lynx,swap_std_reloc_out) (abfd, *generic, (struct reloc_std_external *) natptr);
532 if (bfd_bwrite ((PTR) native, natsize, abfd) != natsize)
534 bfd_release (abfd, native);
535 return FALSE;
537 bfd_release (abfd, native);
539 return TRUE;
542 /* This is stupid. This function should be a boolean predicate */
543 long
544 NAME(lynx,canonicalize_reloc) (abfd, section, relptr, symbols)
545 bfd *abfd;
546 sec_ptr section;
547 arelent **relptr;
548 asymbol **symbols;
550 arelent *tblptr = section->relocation;
551 unsigned int count;
553 if (!(tblptr || NAME(lynx,slurp_reloc_table) (abfd, section, symbols)))
554 return -1;
556 if (section->flags & SEC_CONSTRUCTOR)
558 arelent_chain *chain = section->constructor_chain;
559 for (count = 0; count < section->reloc_count; count++)
561 *relptr++ = &chain->relent;
562 chain = chain->next;
565 else
567 tblptr = section->relocation;
569 for (count = 0; count++ < section->reloc_count;)
571 *relptr++ = tblptr++;
574 *relptr = 0;
576 return section->reloc_count;
579 #define MY_canonicalize_reloc NAME(lynx,canonicalize_reloc)
581 #include "aout-target.h"