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"