1 /* BFD back-end for RISC iX (Acorn, arm) binaries.
2 Copyright 1994, 1995, 1996, 1997, 1998, 2000, 2001
3 Free Software Foundation, Inc.
4 Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
6 This file is part of BFD, the Binary File Descriptor library.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22 /* RISC iX overloads the MAGIC field to indicate more than just the usual
23 [ZNO]MAGIC values. Also included are squeezing information and
24 shared library usage. */
26 /* The following come from the man page. */
29 #define MF_IMPURE 00200
30 #define MF_SQUEEZED 01000
31 #define MF_USES_SL 02000
32 #define MF_IS_SL 04000
34 /* Common combinations. */
35 #define IMAGIC (MF_IMPURE|ZMAGIC) /* Demand load (impure text) */
36 #define SPOMAGIC (MF_USES_SL|OMAGIC) /* OMAGIC with large header */
37 /* -- may contain a ref to a */
38 /* shared lib required by the */
40 #define SLOMAGIC (MF_IS_SL|OMAGIC) /* A reference to a shared library */
41 /* The text portion of the object */
42 /* contains "overflow text" from */
43 /* the shared library to be linked */
44 /* in with an object */
45 #define QMAGIC (MF_SQUEEZED|ZMAGIC) /* Sqeezed demand paged. */
46 /* NOTE: This interpretation of */
47 /* QMAGIC seems to be at variance */
48 /* With that used on other */
50 #define SPZMAGIC (MF_USES_SL|ZMAGIC) /* program which uses sl */
51 #define SPQMAGIC (MF_USES_SL|QMAGIC) /* sqeezed ditto */
52 #define SLZMAGIC (MF_IS_SL|ZMAGIC) /* shared lib part of prog */
53 #define SLPZMAGIC (MF_USES_SL|SLZMAGIC) /* sl which uses another */
55 #define N_SHARED_LIB(x) ((x).a_info & MF_USES_SL)
57 /* Only a pure OMAGIC file has the minimal header */
59 ((x).a_info == OMAGIC \
61 : (N_MAGIC(x) == ZMAGIC \
65 #define N_TXTADDR(x) \
66 (N_MAGIC(x) != ZMAGIC \
67 ? (bfd_vma) 0 /* object file or NMAGIC */ \
68 /* Programs with shared libs are loaded at the first page after all the \
69 text segments of the shared library programs. Without looking this \
70 up we can't know exactly what the address will be. A reasonable guess \
71 is that a_entry will be in the first page of the executable. */ \
73 ? ((x).a_entry & ~(bfd_vma) (TARGET_PAGE_SIZE - 1)) \
74 : (bfd_vma) TEXT_START_ADDR))
77 (N_TXTOFF (x) + (x).a_text + (x).a_data + (x).a_trsize + (x).a_drsize)
79 #define N_STROFF(x) (N_SYMOFF (x) + (x).a_syms)
81 #define TEXT_START_ADDR 32768
82 #define TARGET_PAGE_SIZE 32768
83 #define SEGMENT_SIZE TARGET_PAGE_SIZE
84 #define DEFAULT_ARCH bfd_arch_arm
86 /* Do not "beautify" the CONCAT* macro args. Traditional C will not
87 remove whitespace added here, and thus will fail to concatenate
89 #define MY(OP) CONCAT2 (riscix_,OP)
90 #define TARGETNAME "a.out-riscix"
91 #define N_BADMAG(x) ((((x).a_info & ~007200) != ZMAGIC) && \
92 (((x).a_info & ~006000) != OMAGIC) && \
93 ((x).a_info != NMAGIC))
94 #define N_MAGIC(x) ((x).a_info & ~07200)
100 #define WRITE_HEADERS(abfd, execp) \
102 bfd_size_type text_size; /* dummy vars */ \
104 if (adata(abfd).magic == undecided_magic) \
105 NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end); \
107 execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE; \
108 execp->a_entry = bfd_get_start_address (abfd); \
110 execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * \
111 obj_reloc_entry_size (abfd)); \
112 execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * \
113 obj_reloc_entry_size (abfd)); \
114 NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes); \
116 if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 \
117 || bfd_bwrite ((PTR) &exec_bytes, (bfd_size_type) EXEC_BYTES_SIZE, \
118 abfd) != EXEC_BYTES_SIZE) \
120 /* Now write out reloc info, followed by syms and strings */ \
122 if (bfd_get_outsymbols (abfd) != (asymbol **) NULL \
123 && bfd_get_symcount (abfd) != 0) \
125 if (bfd_seek (abfd, (file_ptr) (N_SYMOFF(*execp)), SEEK_SET) != 0) \
128 if (! NAME(aout,write_syms) (abfd)) return false; \
130 if (bfd_seek (abfd, (file_ptr) (N_TRELOFF(*execp)), SEEK_SET) != 0) \
133 if (! riscix_squirt_out_relocs (abfd, obj_textsec (abfd))) \
135 if (bfd_seek (abfd, (file_ptr) (N_DRELOFF(*execp)), SEEK_SET) != 0) \
138 if (!NAME(aout,squirt_out_relocs) (abfd, obj_datasec (abfd))) \
144 #include "aout/aout64.h"
146 static bfd_reloc_status_type
147 riscix_fix_pcrel_26_done PARAMS ((bfd *, arelent *, asymbol *, PTR,
148 asection *, bfd *, char **));
150 static bfd_reloc_status_type
151 riscix_fix_pcrel_26 PARAMS ((bfd *, arelent *, asymbol *, PTR,
152 asection *, bfd *, char **));
153 static const bfd_target *
154 MY (object_p) PARAMS ((bfd *));
157 riscix_reloc_type_lookup PARAMS ((bfd *, bfd_reloc_code_real_type));
160 riscix_swap_std_reloc_out PARAMS ((bfd *, arelent *, struct reloc_std_external *));
163 riscix_squirt_out_relocs PARAMS ((bfd *, asection *));
166 MY (canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **, asymbol **));
169 riscix_some_aout_object_p PARAMS ((bfd *, struct internal_exec *, const bfd_target *(*) (bfd *)));
172 static reloc_howto_type riscix_std_reloc_howto[] = {
173 /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */
174 HOWTO( 0, 0, 0, 8, false, 0, complain_overflow_bitfield,0,"8", true, 0x000000ff,0x000000ff, false),
175 HOWTO( 1, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"16", true, 0x0000ffff,0x0000ffff, false),
176 HOWTO( 2, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"32", true, 0xffffffff,0xffffffff, false),
177 HOWTO( 3, 2, 3, 26, true, 0, complain_overflow_signed, riscix_fix_pcrel_26 , "ARM26", true, 0x00ffffff,0x00ffffff, false),
178 HOWTO( 4, 0, 0, 8, true, 0, complain_overflow_signed, 0,"DISP8", true, 0x000000ff,0x000000ff, true),
179 HOWTO( 5, 0, 1, 16, true, 0, complain_overflow_signed, 0,"DISP16", true, 0x0000ffff,0x0000ffff, true),
180 HOWTO( 6, 0, 2, 32, true, 0, complain_overflow_signed, 0,"DISP32", true, 0xffffffff,0xffffffff, true),
181 HOWTO( 7, 2, 3, 26, false, 0, complain_overflow_signed, riscix_fix_pcrel_26_done, "ARM26D",true,0x00ffffff,0x00ffffff, false),
183 HOWTO( 9, 0, -1, 16, false, 0, complain_overflow_bitfield,0,"NEG16", true, 0x0000ffff,0x0000ffff, false),
184 HOWTO( 10, 0, -2, 32, false, 0, complain_overflow_bitfield,0,"NEG32", true, 0xffffffff,0xffffffff, false)
187 #define RISCIX_TABLE_SIZE \
188 (sizeof (riscix_std_reloc_howto) / sizeof (reloc_howto_type))
190 static bfd_reloc_status_type
191 riscix_fix_pcrel_26_done (abfd, reloc_entry, symbol, data, input_section,
192 output_bfd, error_message)
193 bfd *abfd ATTRIBUTE_UNUSED;
194 arelent *reloc_entry ATTRIBUTE_UNUSED;
195 asymbol *symbol ATTRIBUTE_UNUSED;
196 PTR data ATTRIBUTE_UNUSED;
197 asection *input_section ATTRIBUTE_UNUSED;
198 bfd *output_bfd ATTRIBUTE_UNUSED;
199 char **error_message ATTRIBUTE_UNUSED;
201 /* This is dead simple at present. */
205 static bfd_reloc_status_type
206 riscix_fix_pcrel_26 (abfd, reloc_entry, symbol, data, input_section,
207 output_bfd, error_message)
209 arelent *reloc_entry;
212 asection *input_section;
214 char **error_message ATTRIBUTE_UNUSED;
217 bfd_size_type addr = reloc_entry->address;
218 long target = bfd_get_32 (abfd, (bfd_byte *) data + addr);
219 bfd_reloc_status_type flag = bfd_reloc_ok;
221 /* If this is an undefined symbol, return error */
222 if (symbol->section == &bfd_und_section
223 && (symbol->flags & BSF_WEAK) == 0)
224 return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined;
226 /* If the sections are different, and we are doing a partial relocation,
227 just ignore it for now. */
228 if (symbol->section->name != input_section->name
229 && output_bfd != (bfd *)NULL)
230 return bfd_reloc_continue;
232 relocation = (target & 0x00ffffff) << 2;
233 relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend */
234 relocation += symbol->value;
235 relocation += symbol->section->output_section->vma;
236 relocation += symbol->section->output_offset;
237 relocation += reloc_entry->addend;
238 relocation -= input_section->output_section->vma;
239 relocation -= input_section->output_offset;
242 return bfd_reloc_overflow;
244 /* Check for overflow */
245 if (relocation & 0x02000000)
247 if ((relocation & ~ (bfd_vma) 0x03ffffff) != ~ (bfd_vma) 0x03ffffff)
248 flag = bfd_reloc_overflow;
250 else if (relocation & ~ (bfd_vma) 0x03ffffff)
251 flag = bfd_reloc_overflow;
253 target &= ~0x00ffffff;
254 target |= (relocation >> 2) & 0x00ffffff;
255 bfd_put_32 (abfd, (bfd_vma) target, (bfd_byte *) data + addr);
257 /* Now the ARM magic... Change the reloc type so that it is marked as done.
258 Strictly this is only necessary if we are doing a partial relocation. */
259 reloc_entry->howto = &riscix_std_reloc_howto[7];
265 riscix_reloc_type_lookup (abfd, code)
267 bfd_reloc_code_real_type code;
269 #define ASTD(i,j) case i: return &riscix_std_reloc_howto[j]
270 if (code == BFD_RELOC_CTOR)
271 switch (bfd_get_arch_info (abfd)->bits_per_address)
276 default: return (reloc_howto_type *) NULL;
281 ASTD (BFD_RELOC_16, 1);
282 ASTD (BFD_RELOC_32, 2);
283 ASTD (BFD_RELOC_ARM_PCREL_BRANCH, 3);
284 ASTD (BFD_RELOC_8_PCREL, 4);
285 ASTD (BFD_RELOC_16_PCREL, 5);
286 ASTD (BFD_RELOC_32_PCREL, 6);
287 default: return (reloc_howto_type *) NULL;
291 #define MY_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
292 #define MY_bfd_link_add_symbols _bfd_generic_link_add_symbols
293 #define MY_final_link_callback should_not_be_used
294 #define MY_bfd_final_link _bfd_generic_final_link
296 #define MY_bfd_reloc_type_lookup riscix_reloc_type_lookup
297 #define MY_canonicalize_reloc riscix_canonicalize_reloc
298 #define MY_object_p riscix_object_p
300 static const bfd_target *riscix_callback PARAMS ((bfd *));
303 riscix_swap_std_reloc_out (abfd, g, natptr)
306 struct reloc_std_external *natptr;
309 asymbol *sym = *(g->sym_ptr_ptr);
313 int r_neg = 0; /* Negative relocs use the BASEREL bit. */
314 asection *output_section = sym->section->output_section;
316 PUT_WORD(abfd, g->address, natptr->r_address);
318 r_length = g->howto->size ; /* Size as a power of two */
321 r_length = -r_length;
325 r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */
327 /* For RISC iX, in pc-relative relocs the r_pcrel bit means that the
328 relocation has been done already (Only for the 26-bit one I think)???!!!
332 r_pcrel = r_pcrel ? 0 : 1;
335 /* For a standard reloc, the addend is in the object file. */
336 r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
339 /* name was clobbered by aout_write_syms to be symbol index */
341 /* If this relocation is relative to a symbol then set the
342 r_index to the symbols index, and the r_extern bit.
344 Absolute symbols can come in in two ways, either as an offset
345 from the abs section, or as a symbol which has an abs value.
349 if (bfd_is_com_section (output_section)
350 || output_section == &bfd_abs_section
351 || output_section == &bfd_und_section)
353 if (bfd_abs_section.symbol == sym)
355 /* Whoops, looked like an abs symbol, but is really an offset
356 from the abs section */
364 r_index = (*g->sym_ptr_ptr)->udata.i;
369 /* Just an ordinary section */
371 r_index = output_section->target_index;
374 /* now the fun stuff */
375 if (bfd_header_big_endian (abfd))
377 natptr->r_index[0] = r_index >> 16;
378 natptr->r_index[1] = r_index >> 8;
379 natptr->r_index[2] = r_index;
381 ( (r_extern ? RELOC_STD_BITS_EXTERN_BIG: 0)
382 | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG: 0)
383 | (r_neg ? RELOC_STD_BITS_BASEREL_BIG: 0)
384 | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG));
388 natptr->r_index[2] = r_index >> 16;
389 natptr->r_index[1] = r_index >> 8;
390 natptr->r_index[0] = r_index;
392 ( (r_extern ? RELOC_STD_BITS_EXTERN_LITTLE: 0)
393 | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE: 0)
394 | (r_neg ? RELOC_STD_BITS_BASEREL_LITTLE: 0)
395 | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE));
400 riscix_squirt_out_relocs (abfd, section)
405 unsigned char *native, *natptr;
408 unsigned int count = section->reloc_count;
409 bfd_size_type natsize;
411 if (count == 0) return true;
413 each_size = obj_reloc_entry_size (abfd);
416 native = (unsigned char *) bfd_zalloc (abfd, natsize);
420 generic = section->orelocation;
422 for (natptr = native;
424 --count, natptr += each_size, ++generic)
425 riscix_swap_std_reloc_out (abfd, *generic,
426 (struct reloc_std_external *) natptr);
428 if (bfd_bwrite ((PTR) native, natsize, abfd) != natsize)
430 bfd_release (abfd, native);
434 bfd_release (abfd, native);
439 * This is just like the standard aoutx.h version but we need to do our
440 * own mapping of external reloc type values to howto entries.
443 MY(canonicalize_reloc) (abfd, section, relptr, symbols)
449 arelent *tblptr = section->relocation;
450 unsigned int count, c;
451 extern reloc_howto_type NAME(aout,std_howto_table)[];
453 /* If we have already read in the relocation table, return the values. */
454 if (section->flags & SEC_CONSTRUCTOR) {
455 arelent_chain *chain = section->constructor_chain;
457 for (count = 0; count < section->reloc_count; count++) {
458 *relptr++ = &chain->relent;
462 return section->reloc_count;
464 if (tblptr && section->reloc_count) {
465 for (count = 0; count++ < section->reloc_count;)
466 *relptr++ = tblptr++;
468 return section->reloc_count;
471 if (!NAME(aout,slurp_reloc_table) (abfd, section, symbols))
473 tblptr = section->relocation;
475 /* fix up howto entries */
476 for (count = 0; count++ < section->reloc_count;)
478 c = tblptr->howto - NAME(aout,std_howto_table);
479 BFD_ASSERT (c < RISCIX_TABLE_SIZE);
480 tblptr->howto = &riscix_std_reloc_howto[c];
482 *relptr++ = tblptr++;
485 return section->reloc_count;
488 /* This is the same as NAME(aout,some_aout_object_p), but has different
489 expansions of the macro definitions. */
492 riscix_some_aout_object_p (abfd, execp, callback_to_real_object_p)
494 struct internal_exec *execp;
495 const bfd_target *(*callback_to_real_object_p) PARAMS ((bfd *));
497 struct aout_data_struct *rawptr, *oldrawptr;
498 const bfd_target *result;
499 bfd_size_type amt = sizeof (struct aout_data_struct);
501 rawptr = (struct aout_data_struct *) bfd_zalloc (abfd, amt);
506 oldrawptr = abfd->tdata.aout_data;
507 abfd->tdata.aout_data = rawptr;
509 /* Copy the contents of the old tdata struct.
510 In particular, we want the subformat, since for hpux it was set in
511 hp300hpux.c:swap_exec_header_in and will be used in
512 hp300hpux.c:callback. */
513 if (oldrawptr != NULL)
514 *abfd->tdata.aout_data = *oldrawptr;
516 abfd->tdata.aout_data->a.hdr = &rawptr->e;
517 *(abfd->tdata.aout_data->a.hdr) = *execp; /* Copy in the internal_exec
519 execp = abfd->tdata.aout_data->a.hdr;
521 /* Set the file flags */
522 abfd->flags = BFD_NO_FLAGS;
523 if (execp->a_drsize || execp->a_trsize)
524 abfd->flags |= HAS_RELOC;
525 /* Setting of EXEC_P has been deferred to the bottom of this function */
527 abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS;
528 if (N_DYNAMIC(*execp))
529 abfd->flags |= DYNAMIC;
531 if ((execp->a_info & MF_SQUEEZED) != 0) /* Squeezed files aren't supported
534 bfd_set_error (bfd_error_wrong_format);
537 else if ((execp->a_info & MF_IS_SL) != 0) /* Nor are shared libraries */
539 bfd_set_error (bfd_error_wrong_format);
542 else if (N_MAGIC (*execp) == ZMAGIC)
544 abfd->flags |= D_PAGED | WP_TEXT;
545 adata (abfd).magic = z_magic;
547 else if (N_MAGIC (*execp) == NMAGIC)
549 abfd->flags |= WP_TEXT;
550 adata (abfd).magic = n_magic;
552 else if (N_MAGIC (*execp) == OMAGIC)
553 adata (abfd).magic = o_magic;
556 /* Should have been checked with N_BADMAG before this routine
561 bfd_get_start_address (abfd) = execp->a_entry;
563 obj_aout_symbols (abfd) = (aout_symbol_type *)NULL;
564 bfd_get_symcount (abfd) = execp->a_syms / sizeof (struct external_nlist);
566 /* The default relocation entry size is that of traditional V7 Unix. */
567 obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
569 /* The default symbol entry size is that of traditional Unix. */
570 obj_symbol_entry_size (abfd) = EXTERNAL_NLIST_SIZE;
572 obj_aout_external_syms (abfd) = NULL;
573 obj_aout_external_strings (abfd) = NULL;
574 obj_aout_sym_hashes (abfd) = NULL;
576 if (! NAME(aout,make_sections) (abfd))
579 obj_datasec (abfd)->_raw_size = execp->a_data;
580 obj_bsssec (abfd)->_raw_size = execp->a_bss;
582 obj_textsec (abfd)->flags =
583 (execp->a_trsize != 0
584 ? (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_RELOC)
585 : (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS));
586 obj_datasec (abfd)->flags =
587 (execp->a_drsize != 0
588 ? (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS | SEC_RELOC)
589 : (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS));
590 obj_bsssec (abfd)->flags = SEC_ALLOC;
592 result = (*callback_to_real_object_p) (abfd);
594 #if defined(MACH) || defined(STAT_FOR_EXEC)
595 /* The original heuristic doesn't work in some important cases. The
596 * a.out file has no information about the text start address. For
597 * files (like kernels) linked to non-standard addresses (ld -Ttext
598 * nnn) the entry point may not be between the default text start
599 * (obj_textsec(abfd)->vma) and (obj_textsec(abfd)->vma) + text size
600 * This is not just a mach issue. Many kernels are loaded at non
601 * standard addresses.
604 struct stat stat_buf;
605 if (abfd->iostream != NULL
606 && (abfd->flags & BFD_IN_MEMORY) == 0
607 && (fstat(fileno((FILE *) (abfd->iostream)), &stat_buf) == 0)
608 && ((stat_buf.st_mode & 0111) != 0))
609 abfd->flags |= EXEC_P;
612 /* Now that the segment addresses have been worked out, take a better
613 guess at whether the file is executable. If the entry point
614 is within the text segment, assume it is. (This makes files
615 executable even if their entry point address is 0, as long as
616 their text starts at zero.)
618 At some point we should probably break down and stat the file and
619 declare it executable if (one of) its 'x' bits are on... */
620 if ((execp->a_entry >= obj_textsec(abfd)->vma) &&
621 (execp->a_entry < obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size))
622 abfd->flags |= EXEC_P;
630 abfd->tdata.aout_data = oldrawptr;
635 static const bfd_target *
639 struct external_exec exec_bytes; /* Raw exec header from file */
640 struct internal_exec exec; /* Cleaned-up exec header */
641 const bfd_target *target;
643 if (bfd_bread ((PTR) &exec_bytes, (bfd_size_type) EXEC_BYTES_SIZE, abfd)
646 if (bfd_get_error () != bfd_error_system_call)
647 bfd_set_error (bfd_error_wrong_format);
651 exec.a_info = H_GET_32 (abfd, exec_bytes.e_info);
653 if (N_BADMAG (exec)) return 0;
655 if (!(MACHTYPE_OK (N_MACHTYPE (exec)))) return 0;
658 NAME(aout,swap_exec_header_in) (abfd, &exec_bytes, &exec);
660 target = riscix_some_aout_object_p (abfd, &exec, MY(callback));
665 #include "aout-target.h"