1 /* BFD back-end for RISC iX (Acorn, arm) binaries.
2 Copyright (C) 1994 Free Software Foundation, Inc.
3 Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
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 2 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., 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 ? 32 \
60 : (N_MAGIC(x) == ZMAGIC) ? TARGET_PAGE_SIZE \
63 #define N_TXTADDR(x) \
64 (N_MAGIC(x) != ZMAGIC ? 0 /* object file or NMAGIC */ \
65 /* Programs with shared libs are loaded at the first page after all the \
66 text segments of the shared library programs. Without looking this \
67 up we can't know exactly what the address will be. A reasonable guess \
68 is that a_entry will be in the first page of the executable. */ \
69 : N_SHARED_LIB(x) ? ((x).a_entry & ~(TARGET_PAGE_SIZE - 1)) \
73 (N_TXTOFF (x) + (x).a_text + (x).a_data + (x).a_trsize + (x).a_drsize)
75 #define N_STROFF(x) (N_SYMOFF (x) + (x).a_syms)
77 #define TEXT_START_ADDR 32768
78 #define TARGET_PAGE_SIZE 32768
79 #define SEGMENT_SIZE TARGET_PAGE_SIZE
80 #define DEFAULT_ARCH bfd_arch_arm
82 #define MY(OP) CAT(riscix_,OP)
83 #define TARGETNAME "a.out-riscix"
84 #define N_BADMAG(x) ((((x).a_info & ~007200) != ZMAGIC) && \
85 (((x).a_info & ~006000) != OMAGIC) && \
86 ((x).a_info != NMAGIC))
87 #define N_MAGIC(x) ((x).a_info & ~07200)
94 #define WRITE_HEADERS(abfd, execp) \
96 bfd_size_type text_size; /* dummy vars */ \
98 if (adata(abfd).magic == undecided_magic) \
99 NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end); \
101 execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE; \
102 execp->a_entry = bfd_get_start_address (abfd); \
104 execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * \
105 obj_reloc_entry_size (abfd)); \
106 execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * \
107 obj_reloc_entry_size (abfd)); \
108 NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes); \
110 if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) return false; \
111 if (bfd_write ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd) \
112 != EXEC_BYTES_SIZE) \
114 /* Now write out reloc info, followed by syms and strings */ \
116 if (bfd_get_outsymbols (abfd) != (asymbol **) NULL \
117 && bfd_get_symcount (abfd) != 0) \
119 if (bfd_seek (abfd, (file_ptr)(N_SYMOFF(*execp)), SEEK_SET) != 0) \
122 if (! NAME(aout,write_syms)(abfd)) return false; \
124 if (bfd_seek (abfd, (file_ptr)(N_TRELOFF(*execp)), SEEK_SET) != 0) \
127 if (! riscix_squirt_out_relocs (abfd, obj_textsec (abfd))) \
129 if (bfd_seek (abfd, (file_ptr)(N_DRELOFF(*execp)), SEEK_SET) != 0) \
132 if (!NAME(aout,squirt_out_relocs)(abfd, obj_datasec (abfd))) \
138 #include "aout/aout64.h"
140 static bfd_reloc_status_type
141 riscix_fix_pcrel_26_done
PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
,
142 asection
*, bfd
*, char **));
144 static bfd_reloc_status_type
145 riscix_fix_pcrel_26
PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
,
146 asection
*, bfd
*, char **));
148 static reloc_howto_type riscix_std_reloc_howto
[] = {
149 /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */
150 HOWTO( 0, 0, 0, 8, false, 0, complain_overflow_bitfield
,0,"8", true, 0x000000ff,0x000000ff, false),
151 HOWTO( 1, 0, 1, 16, false, 0, complain_overflow_bitfield
,0,"16", true, 0x0000ffff,0x0000ffff, false),
152 HOWTO( 2, 0, 2, 32, false, 0, complain_overflow_bitfield
,0,"32", true, 0xffffffff,0xffffffff, false),
153 HOWTO( 3, 2, 3, 26, true, 0, complain_overflow_signed
, riscix_fix_pcrel_26
, "ARM26", true, 0x00ffffff,0x00ffffff, false),
154 HOWTO( 4, 0, 0, 8, true, 0, complain_overflow_signed
, 0,"DISP8", true, 0x000000ff,0x000000ff, true),
155 HOWTO( 5, 0, 1, 16, true, 0, complain_overflow_signed
, 0,"DISP16", true, 0x0000ffff,0x0000ffff, true),
156 HOWTO( 6, 0, 2, 32, true, 0, complain_overflow_signed
, 0,"DISP32", true, 0xffffffff,0xffffffff, true),
157 HOWTO( 7, 2, 3, 26, false, 0, complain_overflow_signed
, riscix_fix_pcrel_26_done
, "ARM26D",true,0x00ffffff,0x00ffffff, false),
159 HOWTO( 9, 0, -1, 16, false, 0, complain_overflow_bitfield
,0,"NEG16", true, 0x0000ffff,0x0000ffff, false),
160 HOWTO( 10, 0, -2, 32, false, 0, complain_overflow_bitfield
,0,"NEG32", true, 0xffffffff,0xffffffff, false)
163 #define RISCIX_TABLE_SIZE \
164 (sizeof (riscix_std_reloc_howto) / sizeof (reloc_howto_type))
167 static bfd_reloc_status_type
168 riscix_fix_pcrel_26_done (abfd
, reloc_entry
, symbol
, data
, input_section
,
169 output_bfd
, error_message
)
171 arelent
*reloc_entry
;
174 asection
*input_section
;
176 char **error_message
;
178 /* This is dead simple at present. */
182 static bfd_reloc_status_type
183 riscix_fix_pcrel_26 (abfd
, reloc_entry
, symbol
, data
, input_section
,
184 output_bfd
, error_message
)
186 arelent
*reloc_entry
;
189 asection
*input_section
;
191 char **error_message
;
194 bfd_size_type addr
= reloc_entry
->address
;
195 long target
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ addr
);
196 bfd_reloc_status_type flag
= bfd_reloc_ok
;
198 /* If this is an undefined symbol, return error */
199 if (symbol
->section
== &bfd_und_section
200 && (symbol
->flags
& BSF_WEAK
) == 0)
201 return output_bfd
? bfd_reloc_continue
: bfd_reloc_undefined
;
203 /* If the sections are different, and we are doing a partial relocation,
204 just ignore it for now. */
205 if (symbol
->section
->name
!= input_section
->name
206 && output_bfd
!= (bfd
*)NULL
)
207 return bfd_reloc_continue
;
209 relocation
= (target
& 0x00ffffff) << 2;
210 relocation
= (relocation
^ 0x02000000) - 0x02000000; /* Sign extend */
211 relocation
+= symbol
->value
;
212 relocation
+= symbol
->section
->output_section
->vma
;
213 relocation
+= symbol
->section
->output_offset
;
214 relocation
+= reloc_entry
->addend
;
215 relocation
-= input_section
->output_section
->vma
;
216 relocation
-= input_section
->output_offset
;
219 return bfd_reloc_overflow
;
221 /* Check for overflow */
222 if (relocation
& 0x02000000)
224 if ((relocation
& ~0x03ffffff) != ~0x03ffffff)
225 flag
= bfd_reloc_overflow
;
227 else if (relocation
& ~0x03ffffff)
228 flag
= bfd_reloc_overflow
;
230 target
&= ~0x00ffffff;
231 target
|= (relocation
>> 2) & 0x00ffffff;
232 bfd_put_32 (abfd
, target
, (bfd_byte
*) data
+ addr
);
234 /* Now the ARM magic... Change the reloc type so that it is marked as done.
235 Strictly this is only necessary if we are doing a partial relocation. */
236 reloc_entry
->howto
= &riscix_std_reloc_howto
[7];
242 DEFUN(riscix_reloc_type_lookup
,(abfd
,code
),
244 bfd_reloc_code_real_type code
)
246 #define ASTD(i,j) case i: return &riscix_std_reloc_howto[j]
247 if (code
== BFD_RELOC_CTOR
)
248 switch (bfd_get_arch_info (abfd
)->bits_per_address
)
253 default: return (reloc_howto_type
*) NULL
;
258 ASTD (BFD_RELOC_16
, 1);
259 ASTD (BFD_RELOC_32
, 2);
260 ASTD (BFD_RELOC_ARM_PCREL_BRANCH
, 3);
261 ASTD (BFD_RELOC_8_PCREL
, 4);
262 ASTD (BFD_RELOC_16_PCREL
, 5);
263 ASTD (BFD_RELOC_32_PCREL
, 6);
264 default: return (reloc_howto_type
*) NULL
;
268 #define MY_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
269 #define MY_bfd_link_add_symbols _bfd_generic_link_add_symbols
270 #define MY_bfd_final_link _bfd_generic_final_link
272 #define MY_bfd_reloc_type_lookup riscix_reloc_type_lookup
273 #define MY_canonicalize_reloc riscix_canonicalize_reloc
274 #define MY_object_p riscix_object_p
276 static const bfd_target
*riscix_callback
PARAMS ((bfd
*));
279 riscix_swap_std_reloc_out (abfd
, g
, natptr
)
282 struct reloc_std_external
*natptr
;
285 asymbol
*sym
= *(g
->sym_ptr_ptr
);
289 int r_neg
= 0; /* Negative relocs use the BASEREL bit. */
290 asection
*output_section
= sym
->section
->output_section
;
292 PUT_WORD(abfd
, g
->address
, natptr
->r_address
);
294 r_length
= g
->howto
->size
; /* Size as a power of two */
297 r_length
= -r_length
;
301 r_pcrel
= (int) g
->howto
->pc_relative
; /* Relative to PC? */
303 /* For RISC iX, in pc-relative relocs the r_pcrel bit means that the
304 relocation has been done already (Only for the 26-bit one I think)???!!!
308 r_pcrel
= r_pcrel
? 0 : 1;
312 /* For a standard reloc, the addend is in the object file. */
313 r_addend
= g
->addend
+ (*(g
->sym_ptr_ptr
))->section
->output_section
->vma
;
316 /* name was clobbered by aout_write_syms to be symbol index */
318 /* If this relocation is relative to a symbol then set the
319 r_index to the symbols index, and the r_extern bit.
321 Absolute symbols can come in in two ways, either as an offset
322 from the abs section, or as a symbol which has an abs value.
326 if (bfd_is_com_section (output_section
)
327 || output_section
== &bfd_abs_section
328 || output_section
== &bfd_und_section
)
330 if (bfd_abs_section
.symbol
== sym
)
332 /* Whoops, looked like an abs symbol, but is really an offset
333 from the abs section */
341 r_index
= stoi((*(g
->sym_ptr_ptr
))->flags
);
346 /* Just an ordinary section */
348 r_index
= output_section
->target_index
;
351 /* now the fun stuff */
352 if (bfd_header_big_endian (abfd
))
354 natptr
->r_index
[0] = r_index
>> 16;
355 natptr
->r_index
[1] = r_index
>> 8;
356 natptr
->r_index
[2] = r_index
;
358 ( (r_extern
? RELOC_STD_BITS_EXTERN_BIG
: 0)
359 | (r_pcrel
? RELOC_STD_BITS_PCREL_BIG
: 0)
360 | (r_neg
? RELOC_STD_BITS_BASEREL_BIG
: 0)
361 | (r_length
<< RELOC_STD_BITS_LENGTH_SH_BIG
));
365 natptr
->r_index
[2] = r_index
>> 16;
366 natptr
->r_index
[1] = r_index
>> 8;
367 natptr
->r_index
[0] = r_index
;
369 ( (r_extern
? RELOC_STD_BITS_EXTERN_LITTLE
: 0)
370 | (r_pcrel
? RELOC_STD_BITS_PCREL_LITTLE
: 0)
371 | (r_neg
? RELOC_STD_BITS_BASEREL_LITTLE
: 0)
372 | (r_length
<< RELOC_STD_BITS_LENGTH_SH_LITTLE
));
377 riscix_squirt_out_relocs (abfd
, section
)
382 unsigned char *native
, *natptr
;
385 unsigned int count
= section
->reloc_count
;
388 if (count
== 0) return true;
390 each_size
= obj_reloc_entry_size (abfd
);
391 natsize
= each_size
* count
;
392 native
= (unsigned char *) bfd_zalloc (abfd
, natsize
);
396 generic
= section
->orelocation
;
398 for (natptr
= native
;
400 --count
, natptr
+= each_size
, ++generic
)
401 riscix_swap_std_reloc_out (abfd
, *generic
,
402 (struct reloc_std_external
*) natptr
);
404 if ( bfd_write ((PTR
) native
, 1, natsize
, abfd
) != natsize
)
406 bfd_release(abfd
, native
);
410 bfd_release (abfd
, native
);
416 * This is just like the standard aoutx.h version but we need to do our
417 * own mapping of external reloc type values to howto entries.
420 MY(canonicalize_reloc
)(abfd
, section
, relptr
, symbols
)
426 arelent
*tblptr
= section
->relocation
;
427 unsigned int count
, c
;
428 extern reloc_howto_type
NAME(aout
,std_howto_table
)[];
430 /* If we have already read in the relocation table, return the values. */
431 if (section
->flags
& SEC_CONSTRUCTOR
) {
432 arelent_chain
*chain
= section
->constructor_chain
;
434 for (count
= 0; count
< section
->reloc_count
; count
++) {
435 *relptr
++ = &chain
->relent
;
439 return section
->reloc_count
;
441 if (tblptr
&& section
->reloc_count
) {
442 for (count
= 0; count
++ < section
->reloc_count
;)
443 *relptr
++ = tblptr
++;
445 return section
->reloc_count
;
448 if (!NAME(aout
,slurp_reloc_table
)(abfd
, section
, symbols
))
450 tblptr
= section
->relocation
;
452 /* fix up howto entries */
453 for (count
= 0; count
++ < section
->reloc_count
;)
455 c
= tblptr
->howto
- NAME(aout
,std_howto_table
);
456 assert (c
< RISCIX_TABLE_SIZE
);
457 tblptr
->howto
= &riscix_std_reloc_howto
[c
];
459 *relptr
++ = tblptr
++;
462 return section
->reloc_count
;
465 /* This is the same as NAME(aout,some_aout_object_p), but has different
466 expansions of the macro definitions. */
469 riscix_some_aout_object_p (abfd
, execp
, callback_to_real_object_p
)
471 struct internal_exec
*execp
;
472 const bfd_target
*(*callback_to_real_object_p
) PARAMS ((bfd
*));
474 struct aout_data_struct
*rawptr
, *oldrawptr
;
475 const bfd_target
*result
;
477 rawptr
= ((struct aout_data_struct
*)
478 bfd_zalloc (abfd
, sizeof (struct aout_data_struct
)));
483 oldrawptr
= abfd
->tdata
.aout_data
;
484 abfd
->tdata
.aout_data
= rawptr
;
486 /* Copy the contents of the old tdata struct.
487 In particular, we want the subformat, since for hpux it was set in
488 hp300hpux.c:swap_exec_header_in and will be used in
489 hp300hpux.c:callback. */
490 if (oldrawptr
!= NULL
)
491 *abfd
->tdata
.aout_data
= *oldrawptr
;
493 abfd
->tdata
.aout_data
->a
.hdr
= &rawptr
->e
;
494 *(abfd
->tdata
.aout_data
->a
.hdr
) = *execp
; /* Copy in the internal_exec
496 execp
= abfd
->tdata
.aout_data
->a
.hdr
;
498 /* Set the file flags */
499 abfd
->flags
= NO_FLAGS
;
500 if (execp
->a_drsize
|| execp
->a_trsize
)
501 abfd
->flags
|= HAS_RELOC
;
502 /* Setting of EXEC_P has been deferred to the bottom of this function */
504 abfd
->flags
|= HAS_LINENO
| HAS_DEBUG
| HAS_SYMS
| HAS_LOCALS
;
505 if (N_DYNAMIC(*execp
))
506 abfd
->flags
|= DYNAMIC
;
509 if ((execp
->a_info
& MF_SQUEEZED
) != 0) /* Squeezed files aren't supported
512 bfd_set_error (bfd_error_wrong_format
);
515 else if ((execp
->a_info
& MF_IS_SL
) != 0) /* Nor are shared libraries */
517 bfd_set_error (bfd_error_wrong_format
);
520 else if (N_MAGIC (*execp
) == ZMAGIC
)
522 abfd
->flags
|= D_PAGED
| WP_TEXT
;
523 adata (abfd
).magic
= z_magic
;
525 else if (N_MAGIC (*execp
) == NMAGIC
)
527 abfd
->flags
|= WP_TEXT
;
528 adata (abfd
).magic
= n_magic
;
530 else if (N_MAGIC (*execp
) == OMAGIC
)
531 adata (abfd
).magic
= o_magic
;
534 /* Should have been checked with N_BADMAG before this routine
539 bfd_get_start_address (abfd
) = execp
->a_entry
;
541 obj_aout_symbols (abfd
) = (aout_symbol_type
*)NULL
;
542 bfd_get_symcount (abfd
) = execp
->a_syms
/ sizeof (struct external_nlist
);
544 /* The default relocation entry size is that of traditional V7 Unix. */
545 obj_reloc_entry_size (abfd
) = RELOC_STD_SIZE
;
547 /* The default symbol entry size is that of traditional Unix. */
548 obj_symbol_entry_size (abfd
) = EXTERNAL_NLIST_SIZE
;
550 obj_aout_external_syms (abfd
) = NULL
;
551 obj_aout_external_strings (abfd
) = NULL
;
552 obj_aout_sym_hashes (abfd
) = NULL
;
554 if (! NAME(aout
,make_sections
) (abfd
))
557 obj_datasec (abfd
)->_raw_size
= execp
->a_data
;
558 obj_bsssec (abfd
)->_raw_size
= execp
->a_bss
;
560 obj_textsec (abfd
)->flags
=
561 (execp
->a_trsize
!= 0
562 ? (SEC_ALLOC
| SEC_LOAD
| SEC_CODE
| SEC_HAS_CONTENTS
| SEC_RELOC
)
563 : (SEC_ALLOC
| SEC_LOAD
| SEC_CODE
| SEC_HAS_CONTENTS
));
564 obj_datasec (abfd
)->flags
=
565 (execp
->a_drsize
!= 0
566 ? (SEC_ALLOC
| SEC_LOAD
| SEC_DATA
| SEC_HAS_CONTENTS
| SEC_RELOC
)
567 : (SEC_ALLOC
| SEC_LOAD
| SEC_DATA
| SEC_HAS_CONTENTS
));
568 obj_bsssec (abfd
)->flags
= SEC_ALLOC
;
570 result
= (*callback_to_real_object_p
)(abfd
);
572 #if defined(MACH) || defined(STAT_FOR_EXEC)
573 /* The original heuristic doesn't work in some important cases. The
574 * a.out file has no information about the text start address. For
575 * files (like kernels) linked to non-standard addresses (ld -Ttext
576 * nnn) the entry point may not be between the default text start
577 * (obj_textsec(abfd)->vma) and (obj_textsec(abfd)->vma) + text size
578 * This is not just a mach issue. Many kernels are loaded at non
579 * standard addresses.
582 struct stat stat_buf
;
583 if (abfd
->iostream
!= NULL
584 && (abfd
->flags
& BFD_IN_MEMORY
) == 0
585 && (fstat(fileno((FILE *) (abfd
->iostream
)), &stat_buf
) == 0)
586 && ((stat_buf
.st_mode
& 0111) != 0))
587 abfd
->flags
|= EXEC_P
;
590 /* Now that the segment addresses have been worked out, take a better
591 guess at whether the file is executable. If the entry point
592 is within the text segment, assume it is. (This makes files
593 executable even if their entry point address is 0, as long as
594 their text starts at zero.)
596 At some point we should probably break down and stat the file and
597 declare it executable if (one of) its 'x' bits are on... */
598 if ((execp
->a_entry
>= obj_textsec(abfd
)->vma
) &&
599 (execp
->a_entry
< obj_textsec(abfd
)->vma
+ obj_textsec(abfd
)->_raw_size
))
600 abfd
->flags
|= EXEC_P
;
608 abfd
->tdata
.aout_data
= oldrawptr
;
614 static const bfd_target
*
618 struct external_exec exec_bytes
; /* Raw exec header from file */
619 struct internal_exec exec
; /* Cleaned-up exec header */
620 const bfd_target
*target
;
622 if (bfd_read ((PTR
) &exec_bytes
, 1, EXEC_BYTES_SIZE
, abfd
)
623 != EXEC_BYTES_SIZE
) {
624 if (bfd_get_error () != bfd_error_system_call
)
625 bfd_set_error (bfd_error_wrong_format
);
629 exec
.a_info
= bfd_h_get_32 (abfd
, exec_bytes
.e_info
);
631 if (N_BADMAG (exec
)) return 0;
633 if (!(MACHTYPE_OK (N_MACHTYPE (exec
)))) return 0;
636 NAME(aout
,swap_exec_header_in
)(abfd
, &exec_bytes
, &exec
);
638 target
= riscix_some_aout_object_p (abfd
, &exec
, MY(callback
));
644 #include "aout-target.h"