amigaos-binutils/bfd/amigaos.c

3841 lines
102 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* BFD back-end for Commodore-Amiga AmigaOS binaries.
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
Free Software Foundation, Inc.
Contributed by Leonard Norrgard. Partially based on the bout
and ieee BFD backends and Markus Wild's tool hunk2gcc.
Revised and updated by Stephan Thesing.
This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
SECTION
amiga back end
This section describes the overall structure of the Amiga BFD back end.
The linker stuff can be found in @xref{amigalink}.
@menu
@* implementation::
@* amigalink::
@end menu
INODE
implementation, amigalink, amiga, amiga
SECTION
implementation
The need for a port of the bfd library for Amiga style object (hunk) files
arose by the desire to port the GNU debugger gdb to the Amiga.
Also, the linker ld should be updated to the current version (2.5.2).
@@*
This port bases on the work done by Leonard Norrgard, who started porting
gdb. Raphael Luebbert, who supports the ixemul.library, has also worked on
implementing the needed @code{ptrace()} system call and gas2.5.
@menu
@* not supported::
@* Does it work?::
@* TODO::
@end menu
INODE
not supported, Does it work?, implementation, implementation
SUBSECTION
not supported
Currently, the implementation does not support Amiga link library files, like
e.g. amiga.lib. This may be added in a later version, if anyone starts work
on it, or I find some time for it.
The handling of the symbols in hunk files is a little bit broken:
o The symbols in a load file are totally ignored at the moment, so gdb and gprof
do not work.
o The symbols of a object module (Hunk file, starting with HUNK_UNIT) are read in
correctly, but HUNK_SYMBOL hunks are also ignored.
The reason for this is the following:
Amiga symbol hunks do not allow for much information. Only a name and a value are allowed.
On the other hand, a.out format carries along much more information (see, e.g. the
entry on set symbols in the ld manual). The old linker copied this information into
a HUNK_DEBUG hunk. Now there is the choice:
o ignoring the debug hunk, read in only HUNK_SYMBOL definitions => extra info is lost.
o read in the debug hunk and use the information therein => How can clashs between the
information in the debug hunk and HUNK_SYMBOL or HUNK_EXT hunks be avoided?
I haven't decided yet, what to do about this.
Although bfd allows to link together object modules of different flavours,
producing a.out style executables does not work on Amiga :-)
It should, however, be possible to create a.out files with the -r option of ld
(incremental link).
INODE
Does it work?, TODO, not supported, implementation
SUBSECTION
Does it work?
Currently, the following utilities work:
o objdump
o objcopy
o strip
o nm
o ar
o gas
INODE
TODO, , Does it work?, implementation
SUBSECTION
TODO
o fix FIXME:s
@*
BFD:
o add flag to say if the format allows multiple sections with the
same name. Fix bfd_get_section_by_name() and bfd_make_section()
accordingly.
o dumpobj.c: the disassembler: use relocation record data to find symbolic
names of addresses, when available. Needs new routine where one can
specify the source section of the symbol to be printed as well as some
rewrite of the disassemble functions.
*/
#include "config.h"
#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
#include "libamiga.h"
#define BYTES_IN_WORD 4
#include "aout/aout64.h" /* struct external_nlist */
#ifndef PARAMS
#define PARAMS(x) x
#endif
#ifndef alloca
extern PTR alloca PARAMS ((size_t));
#endif
#define bfd_is_special_section(sec) \
(bfd_is_abs_section(sec)||bfd_is_com_section(sec)||bfd_is_und_section(sec)||bfd_is_ind_section(sec))
typedef struct aout_symbol {
asymbol symbol;
short desc;
char other;
unsigned char type;
} aout_symbol_type;
struct arch_syms {
unsigned long offset; /* disk offset in the archive */
unsigned long size; /* size of the block of symbols */
unsigned long unit_offset; /* start of unit on disk */
char * name; /* pre read name from .stabstr */
struct arch_syms *next; /* linked list */
};
typedef struct amiga_ardata_struct {
/* generic stuff */
struct artdata generic;
/* amiga-specific stuff */
unsigned long filesize;
struct arch_syms *defsyms;
unsigned long defsym_count;
unsigned long outnum;
} amiga_ardata_type;
#define amiga_ardata(bfd) ((bfd)->tdata.amiga_ar_data)
#define bfd_msg (*_bfd_error_handler)
#define GL(x) bfd_get_32 (abfd, (bfd_byte *) (x))
#define GW(x) bfd_get_16 (abfd, (bfd_byte *) (x))
#define LONGSIZE(l) (((l)+3) >> 2)
/* AmigaOS doesn't like HUNK_SYMBOL with symbol names longer than 124 characters */
#define MAX_NAME_SIZE 124
aout_symbol_type **
amiga_load_stab_symbols (bfd *abfd);
bfd_boolean
aout_32_find_nearest_line (bfd *abfd, sec_ptr section, struct aout_symbol **symbols,
bfd_vma offset, const char **filename_ptr, const char **functionname_ptr,
unsigned int *line_ptr);
bfd_boolean
aout_32_translate_symbol_table (bfd *abfd, aout_symbol_type *in, struct external_nlist *ext,
bfd_size_type count, char *str, bfd_size_type strsize, bfd_boolean dynamic);
static bfd_boolean amiga_reloc_long_p PARAMS ((unsigned long, bfd_boolean));
static reloc_howto_type *howto_for_raw_reloc PARAMS ((unsigned long, bfd_boolean));
static reloc_howto_type *howto_for_reloc PARAMS ((unsigned long));
static bfd_boolean get_long PARAMS ((bfd *, unsigned long *));
static bfd_boolean get_word PARAMS ((bfd *, unsigned long *));
static const struct bfd_target *amiga_object_p PARAMS ((bfd *));
static sec_ptr amiga_get_section_by_hunk_number PARAMS ((bfd *, long));
static bfd_boolean amiga_add_reloc PARAMS ((bfd *, sec_ptr, bfd_size_type,
amiga_symbol_type *, reloc_howto_type *, long));
static sec_ptr amiga_make_unique_section PARAMS ((bfd *, const char *));
static bfd_boolean parse_archive_units PARAMS ((bfd *, int *, unsigned long,
bfd_boolean, struct arch_syms **, symindex *));
static bfd_boolean amiga_digest_file PARAMS ((bfd *));
static bfd_boolean amiga_read_unit PARAMS ((bfd *, unsigned long));
static bfd_boolean amiga_read_load PARAMS ((bfd *));
static bfd_boolean amiga_handle_cdb_hunk PARAMS ((bfd *, unsigned long,
unsigned long, unsigned long, unsigned long));
static bfd_boolean amiga_handle_rest PARAMS ((bfd *, sec_ptr, bfd_boolean));
static bfd_boolean amiga_mkobject PARAMS ((bfd *));
static bfd_boolean amiga_mkarchive PARAMS ((bfd *));
static bfd_boolean write_longs PARAMS ((const unsigned long *, unsigned long,
bfd *));
static bfd_boolean write_words PARAMS ((const unsigned long *, unsigned long,
bfd *));
static long determine_datadata_relocs PARAMS ((bfd *, sec_ptr));
static void remove_section_index PARAMS ((sec_ptr, int *));
static bfd_boolean amiga_write_object_contents PARAMS ((bfd *));
static bfd_boolean write_name PARAMS ((bfd *, const char *, unsigned long));
static bfd_boolean amiga_write_archive_contents PARAMS ((bfd *));
static bfd_boolean amiga_write_armap PARAMS ((bfd *, unsigned int,
struct orl *, unsigned int, int));
static int determine_type PARAMS ((arelent *));
static bfd_boolean amiga_write_section_contents PARAMS ((bfd *, sec_ptr,
sec_ptr, unsigned long, int *, int));
static bfd_boolean amiga_write_symbols PARAMS ((bfd *, sec_ptr));
static bfd_boolean amiga_get_section_contents PARAMS ((bfd *, sec_ptr, PTR,
file_ptr, bfd_size_type));
static bfd_boolean amiga_new_section_hook PARAMS ((bfd *, sec_ptr));
static bfd_boolean amiga_slurp_symbol_table PARAMS ((bfd *));
static long amiga_get_symtab_upper_bound PARAMS ((bfd *));
static long amiga_get_symtab PARAMS ((bfd *, asymbol **));
static asymbol *amiga_make_empty_symbol PARAMS ((bfd *));
static void amiga_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *));
static void amiga_print_symbol PARAMS ((bfd *, PTR, asymbol *,
bfd_print_symbol_type));
static long amiga_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr));
static bfd_boolean read_raw_relocs PARAMS ((bfd *, sec_ptr, unsigned long,
unsigned long));
bfd_boolean amiga_slurp_relocs PARAMS ((bfd *, sec_ptr, asymbol **));
static long amiga_canonicalize_reloc PARAMS ((bfd *, sec_ptr, arelent **,
asymbol **));
static bfd_boolean amiga_set_section_contents PARAMS ((bfd *, sec_ptr, PTR,
file_ptr, bfd_size_type));
static bfd_boolean amiga_set_arch_mach PARAMS ((bfd *, enum bfd_architecture,
unsigned long));
static int amiga_sizeof_headers PARAMS ((bfd *, bfd_boolean));
static bfd_boolean amiga_find_nearest_line PARAMS ((bfd *, sec_ptr,
asymbol **, bfd_vma, const char **, const char **, unsigned int *));
static reloc_howto_type *amiga_bfd_reloc_type_lookup PARAMS ((bfd *,
bfd_reloc_code_real_type));
static bfd_boolean amiga_bfd_copy_private_bfd_data PARAMS ((bfd *, bfd *));
static bfd_boolean amiga_bfd_copy_private_section_data PARAMS ((bfd *,
sec_ptr, bfd *, sec_ptr));
static bfd_boolean amiga_slurp_armap PARAMS ((bfd *));
static void amiga_truncate_arname PARAMS ((bfd *, const char *, char *));
static const struct bfd_target *amiga_archive_p PARAMS ((bfd *));
static bfd *amiga_openr_next_archived_file PARAMS ((bfd *, bfd *));
static PTR amiga_read_ar_hdr PARAMS ((bfd *));
static int amiga_generic_stat_arch_elt PARAMS ((bfd *, struct stat *));
/*#define DEBUG_AMIGA 1*/
#if DEBUG_AMIGA
#include <stdarg.h>
static void
error_print (const char *fmt, ...)
{
va_list args;
va_start (args, fmt);
vfprintf (stderr, fmt, args);
va_end (args);
}
#define DPRINT(L,x) if (L>=DEBUG_AMIGA) error_print x
#else
#define DPRINT(L,x)
#endif
enum {R_ABS32=0,R_ABS16,R_ABS8,R_PC32,R_PC16,R_PC8,R_SD32,R_SD16,R_SD8,R_PC26,R__MAX};
reloc_howto_type howto_table[R__MAX] =
{
{H_ABS32, /* type */
0, /* rightshift */
2, /* size */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield,/* complain_on_overflow */
0, /* special_function */
"RELOC32", /* textual name */
FALSE, /* partial_inplace */
0xffffffff, /* src_mask */
0xffffffff, /* dst_mask */
FALSE}, /* pcrel_offset */
{H_ABS16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0, "RELOC16", FALSE, 0x0000ffff, 0x0000ffff, FALSE},
{H_ABS8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "RELOC8", FALSE, 0x000000ff, 0x000000ff, FALSE},
{H_PC32, 0, 2, 32, TRUE, 0, complain_overflow_signed, 0, "RELRELOC32", FALSE, 0xffffffff, 0xffffffff, TRUE},
{H_PC16, 0, 1, 16, TRUE, 0, complain_overflow_signed, 0, "RELRELOC16", FALSE, 0x0000ffff, 0x0000ffff, TRUE},
{H_PC8, 0, 0, 8, TRUE, 0, complain_overflow_signed, 0, "RELRELOC8", FALSE, 0x000000ff, 0x000000ff, TRUE},
{H_SD32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "DREL32", FALSE, 0xffffffff, 0xffffffff, FALSE},
{H_SD16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0, "DREL16", FALSE, 0x0000ffff, 0x0000ffff, FALSE},
{H_SD8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "DREL8", FALSE, 0x000000ff, 0x000000ff, FALSE},
{H_PC26, 0, 2, 26, TRUE, 0, complain_overflow_signed, 0, "RELRELOC26", FALSE, 0x03fffffc, 0x03fffffc, TRUE},
};
/* Determine the on-disk relocation size.
AmigaOS upto 3.9 goofed parsing HUNK_RELRELOC32 within an executable
and reads the hunk data as 16bit words. */
static bfd_boolean
amiga_reloc_long_p (unsigned long type, bfd_boolean isload)
{
if (type == HUNK_RELOC32SHORT
|| (isload && (type == HUNK_DREL32 || type == HUNK_RELRELOC32)))
return FALSE;
return TRUE;
}
static reloc_howto_type *
howto_for_raw_reloc (unsigned long type, bfd_boolean isload)
{
switch (type)
{
case HUNK_ABSRELOC32:
case HUNK_RELOC32SHORT:
return &howto_table[R_ABS32];
case HUNK_RELRELOC16:
return &howto_table[R_PC16];
case HUNK_RELRELOC8:
return &howto_table[R_PC8];
case HUNK_DREL32:
return &howto_table[isload ? R_ABS32 : R_SD32];
case HUNK_DREL16:
return &howto_table[R_SD16];
case HUNK_DREL8:
return &howto_table[R_SD8];
case HUNK_RELRELOC32:
return &howto_table[R_PC32];
case HUNK_ABSRELOC16:
return &howto_table[R_ABS16];
case HUNK_RELRELOC26:
return &howto_table[R_PC26];
default:
return NULL;
}
}
static reloc_howto_type *
howto_for_reloc (unsigned long type)
{
switch (type)
{
case EXT_ABSREF32:
case EXT_ABSCOMMON:
return &howto_table[R_ABS32];
case EXT_ABSREF16:
return &howto_table[R_ABS16];
case EXT_ABSREF8:
return &howto_table[R_ABS8];
case EXT_RELREF32:
case EXT_RELCOMMON:
return &howto_table[R_PC32];
case EXT_RELREF16:
return &howto_table[R_PC16];
case EXT_RELREF8:
return &howto_table[R_PC8];
case EXT_DEXT32:
case EXT_DEXT32COMMON:
return &howto_table[R_SD32];
case EXT_DEXT16:
case EXT_DEXT16COMMON:
return &howto_table[R_SD16];
case EXT_DEXT8:
case EXT_DEXT8COMMON:
return &howto_table[R_SD8];
case EXT_RELREF26:
return &howto_table[R_PC26];
default:
return NULL;
}
}
/* The following are gross hacks that need to be fixed. The problem is
that the linker unconditionally references these values without
going through any of bfd's standard interface. Thus they need to
be defined in a bfd module that is included in *all* configurations,
and are currently in bfd.c, otherwise linking the linker will fail
on non-Amiga target configurations. */
/* This one is used by the linker and tells us, if a debug hunk should
be written out. */
extern int write_debug_hunk;
/* This is also used by the linker to set the attribute of sections. */
extern int amiga_attribute;
/* used with base-relative linking */
extern int amiga_base_relative;
/* used with -resident linking */
extern int amiga_resident;
static bfd_boolean
get_long (bfd * abfd, unsigned long *n)
{
if (bfd_bread ((PTR) n, 4, abfd) != 4)
return FALSE;
*n = GL(n);
return TRUE;
}
static bfd_boolean
get_word (bfd * abfd, unsigned long *n)
{
if (bfd_bread ((PTR) n, 2, abfd) != 2)
return FALSE;
*n = GW(n);
return TRUE;
}
static const struct bfd_target *
amiga_object_p (bfd * abfd)
{
unsigned long x;
char buf[8];
/* An Amiga object file must be at least 8 bytes long. */
if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf))
{
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
bfd_seek (abfd, 0, SEEK_SET);
/* Does it look like an Amiga object file? */
x = GL(&buf[0]);
if ((x != HUNK_UNIT) && (x != HUNK_HEADER))
{
/* Not an Amiga file. */
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
/* Can't fail and return (but must be declared bfd_boolean to suit
other bfd requirements). */
(void) amiga_mkobject (abfd);
AMIGA_DATA(abfd)->IsLoadFile = (x == HUNK_HEADER);
if (!amiga_digest_file (abfd))
{
/* Something went wrong. */
DPRINT(20,("bfd parser stopped at offset 0x%lx\n",bfd_tell(abfd)));
return NULL;
}
/* Set default architecture to m68k:68000. */
/* So we can link on 68000 AMIGAs... */
abfd->arch_info = bfd_scan_arch ("m68k:68000");
return abfd->xvec;
}
static sec_ptr amiga_get_section_by_hunk_number (bfd *abfd, long hunk_number)
{
/* A cache, so we don't have to search the entire list every time. */
static sec_ptr last_reference;
static bfd *last_bfd;
sec_ptr p;
if (last_reference)
if (last_bfd == abfd && last_reference->target_index == hunk_number)
return last_reference;
for (p = abfd->sections; p != NULL; p = p->next)
if (p->target_index == hunk_number)
{
last_reference = p;
last_bfd = abfd;
return p;
}
BFD_FAIL ();
return NULL;
}
static bfd_boolean
amiga_add_reloc (
bfd *abfd,
sec_ptr section,
bfd_size_type offset,
amiga_symbol_type *symbol,
reloc_howto_type *howto,
long target_hunk)
{
amiga_reloc_type *reloc;
sec_ptr target_sec;
reloc = (amiga_reloc_type *) bfd_alloc (abfd, sizeof(amiga_reloc_type));
if (reloc == NULL)
return FALSE;
abfd->flags |= HAS_RELOC;
section->flags |= SEC_RELOC;
if (amiga_per_section(section)->reloc_tail)
amiga_per_section(section)->reloc_tail->next = reloc;
else
section->relocation = &reloc->relent;
amiga_per_section(section)->reloc_tail = reloc;
reloc->relent.sym_ptr_ptr = &reloc->symbol;
reloc->relent.address = offset;
reloc->relent.addend = 0;
reloc->relent.howto = howto;
reloc->next = NULL;
if (symbol == NULL)
{ /* relative to section */
target_sec = amiga_get_section_by_hunk_number (abfd, target_hunk);
if (target_sec)
reloc->symbol = target_sec->symbol;
else
return FALSE;
}
else
reloc->symbol = &symbol->symbol;
return TRUE;
}
/* BFD doesn't currently allow multiple sections with the same
name, so we try a little harder to get a unique name. */
static sec_ptr
amiga_make_unique_section (
bfd *abfd,
const char *name)
{
sec_ptr section;
bfd_set_error (bfd_error_no_error);
section = bfd_make_section (abfd, name);
if ((section == NULL) && (bfd_get_error () == bfd_error_no_error))
{
#if 0
char *new_name = bfd_alloc (abfd, strlen(name) + 4);
int i = 1;
/* We try to come up with an original name (since BFD currently
requires all sections to have different names). */
while (!section && (i<=99))
{
sprintf (new_name, "%s_%u", name, i++);
section = bfd_make_section (abfd, new_name);
}
#else
section = bfd_make_section_anyway (abfd, name);
#endif
}
return section;
}
#if DEBUG_AMIGA
#define DPRINTHUNK(x) fprintf(stderr,"Processing %s hunk (0x%x)...",\
(x) == HUNK_UNIT ? "HUNK_UNIT" :\
(x) == HUNK_NAME ? "HUNK_NAME" :\
(x) == HUNK_CODE ? "HUNK_CODE" :\
(x) == HUNK_DATA ? "HUNK_DATA" :\
(x) == HUNK_BSS ? "HUNK_BSS" :\
(x) == HUNK_ABSRELOC32 ? "HUNK_RELOC32" :\
(x) == HUNK_RELRELOC16 ? "HUNK_RELRELOC16" :\
(x) == HUNK_RELRELOC8 ? "HUNK_RELRELOC8" :\
(x) == HUNK_EXT ? "HUNK_EXT" :\
(x) == HUNK_SYMBOL ? "HUNK_SYMBOL" :\
(x) == HUNK_DEBUG ? "HUNK_DEBUG" :\
(x) == HUNK_END ? "HUNK_END" :\
(x) == HUNK_HEADER ? "HUNK_HEADER" :\
(x) == HUNK_OVERLAY ? "HUNK_OVERLAY" :\
(x) == HUNK_BREAK ? "HUNK_BREAK" :\
(x) == HUNK_DREL32 ? "HUNK_DREL32" :\
(x) == HUNK_DREL16 ? "HUNK_DREL16" :\
(x) == HUNK_DREL8 ? "HUNK_DREL8" :\
(x) == HUNK_LIB ? "HUNK_LIB" :\
(x) == HUNK_INDEX ? "HUNK_INDEX" :\
(x) == HUNK_RELOC32SHORT ? "HUNK_RELOC32SHORT" :\
(x) == HUNK_RELRELOC32 ? "HUNK_RELRELOC32" :\
(x) == HUNK_PPC_CODE ? "HUNK_PPC_CODE" :\
(x) == HUNK_RELRELOC26 ? "HUNK_RELRELOC26" :\
"*unknown*",(x))
#define DPRINTHUNKEND fprintf(stderr,"done\n")
#else
#define DPRINTHUNK(x)
#define DPRINTHUNKEND
#endif
static bfd_boolean
parse_archive_units (
bfd *abfd,
int *n_units,
unsigned long filesize,
bfd_boolean one, /* parse only the first unit? */
struct arch_syms **syms,
symindex *symcount)
{
struct arch_syms *nsyms, *syms_tail = NULL;
unsigned long unit_offset, defsym_pos = 0;
unsigned long hunk_type, type, len, no, n;
symindex defsymcount = 0;
char * last_name = 0;
bfd_vma stab_pos = 0;
bfd_vma stabstr_pos = 0;
unsigned stab_size, stabstr_size;
*n_units = 0;
while (get_long (abfd, &hunk_type))
{
switch (HUNK_VALUE(hunk_type))
{
case HUNK_END:
break;
case HUNK_UNIT:
unit_offset = bfd_tell (abfd) - 4;
(*n_units)++;
if (one && *n_units > 1)
{
bfd_seek (abfd, -4, SEEK_CUR);
return TRUE;
}
stab_pos = stabstr_pos = 0;
/* no break */
case HUNK_NAME:
if (!get_long (abfd, &len))
return FALSE;
/* check for .stab and .stabstr. */
if (len <= 16)
{
static char name[16*4 + 1];
if (bfd_bread (name, len<<2, abfd) != len<<2)
return FALSE;
name[len<<2] = 0;
last_name = name;
#ifdef DEBUG_AMIGA
if (HUNK_VALUE(hunk_type) == HUNK_UNIT)
DPRINT(10, ("unit: %s\n", last_name));
#endif
}
else if (bfd_seek (abfd, HUNK_VALUE (len) << 2, SEEK_CUR))
return FALSE;
break;
case HUNK_CODE:
case HUNK_DATA:
case HUNK_PPC_CODE:
last_name = 0;
if (!get_long (abfd, &len) || bfd_seek (abfd, HUNK_VALUE (len) << 2, SEEK_CUR))
return FALSE;
break;
case HUNK_DEBUG:
if (!get_long (abfd, &len))
return FALSE;
if (last_name)
{
if (0 == strcmp (".stab", last_name))
{
stab_size = HUNK_VALUE (len) << 2;
stab_pos = bfd_tell (abfd);
}
else if (0 == strcmp (".stabstr", last_name))
{
stabstr_size = HUNK_VALUE (len) << 2;
stabstr_pos = bfd_tell (abfd);
}
last_name = 0;
/*
* Create arch_syms for the stab entries.
*/
if (stab_pos && stabstr_pos)
{
bfd_vma last_pos = bfd_tell (abfd);
unsigned char * stabstrdata = (unsigned char *) bfd_alloc (abfd, stabstr_size);
if (!stabstrdata)
return FALSE;
if (bfd_seek (abfd, stabstr_pos, SEEK_SET))
return FALSE;
if (bfd_bread (stabstrdata, stabstr_size, abfd) != stabstr_size)
return FALSE;
unsigned char * stabdata = (unsigned char *) bfd_alloc (abfd, stab_size);
if (!stabdata)
return FALSE;
if (bfd_seek (abfd, stab_pos, SEEK_SET))
return FALSE;
if (bfd_bread (stabdata, stab_size, abfd) != stab_size)
return FALSE;
{unsigned i; for (i = 0; i < stab_size; i += 12)
{
unsigned str_offset = bfd_getb32 (stabdata + i);
char ctype = stabdata[i + 4];
switch (ctype)
{
default:
continue;
case N_WARNING:
case N_INDR | N_EXT:
i += 12; // skip next
break;
}
if (str_offset > stabstr_size)
return FALSE;
nsyms = (struct arch_syms *) bfd_alloc (abfd, sizeof(struct arch_syms));
nsyms->next = NULL;
if (syms_tail)
syms_tail->next = nsyms;
else
*syms = nsyms;
syms_tail = nsyms;
nsyms->offset = stab_pos + 1;
nsyms->size = 12;
nsyms->unit_offset = unit_offset;
nsyms->name = (char *) stabstrdata + str_offset;
DPRINT(20,("sym: %s\n", nsyms->name));
++defsymcount;
}}
bfd_seek (abfd, last_pos, SEEK_SET);
stab_pos = stabstr_pos = 0;
}
}
if (bfd_seek (abfd, HUNK_VALUE (len) << 2, SEEK_CUR))
return FALSE;
break;
case HUNK_BSS:
if (!get_long (abfd, &len))
return FALSE;
break;
case HUNK_ABSRELOC32:
case HUNK_RELRELOC16:
case HUNK_RELRELOC8:
case HUNK_SYMBOL:
case HUNK_DREL32:
case HUNK_DREL16:
case HUNK_DREL8:
case HUNK_RELRELOC32: /* 32bit data in an object file! */
case HUNK_ABSRELOC16:
case HUNK_RELRELOC26:
for (;;)
{
/* read offsets count */
if (!get_long (abfd, &no))
return FALSE;
if (!no)
break;
/* skip hunk+offsets */
if (bfd_seek (abfd, (no + 1) << 2, SEEK_CUR))
return FALSE;
}
break;
case HUNK_RELOC32SHORT:
for (;;)
{
/* read offsets count */
if (!get_word (abfd, &no))
return FALSE;
if (!no)
break;
/* skip hunk+offsets */
if (bfd_seek (abfd, (no + 1) << 1, SEEK_CUR))
return FALSE;
}
if ((bfd_tell (abfd) & 2) && bfd_seek (abfd, 2, SEEK_CUR))
return FALSE;
break;
case HUNK_EXT:
if (!get_long (abfd, &n))
return FALSE;
while (n)
{
len = n & 0xffffff;
type = (n >> 24) & 0xff;
switch (type)
{
case EXT_SYMB:
case EXT_DEF:
case EXT_ABS:
/* retain the positions of defined symbols for each object
in the archive. They'll be used later to build a
pseudo-armap, which _bfd_generic_link_add_archive_symbols
needs */
defsym_pos = bfd_tell (abfd) - 4;
/* skip name & value */
if (bfd_seek (abfd, (len + 1) << 2, SEEK_CUR))
return FALSE;
break;
case EXT_ABSREF32:
case EXT_RELREF16:
case EXT_RELREF8:
case EXT_DEXT32:
case EXT_DEXT16:
case EXT_DEXT8:
case EXT_RELREF32:
case EXT_ABSREF16:
case EXT_ABSREF8:
case EXT_RELREF26:
/* skip name */
if (bfd_seek (abfd, len << 2, SEEK_CUR))
return FALSE;
/* skip references */
if (!get_long (abfd, &no))
return FALSE;
if (no && bfd_seek (abfd, no << 2, SEEK_CUR))
return FALSE;
break;
case EXT_ABSCOMMON:
defsym_pos = bfd_tell (abfd) - 4;
case EXT_RELCOMMON:
case EXT_DEXT32COMMON:
case EXT_DEXT16COMMON:
case EXT_DEXT8COMMON:
/* skip name & value */
if (bfd_seek (abfd, (len + 1) << 2, SEEK_CUR))
return FALSE;
/* skip references */
if (!get_long (abfd, &no))
return FALSE;
if (no && bfd_seek (abfd, no << 2, SEEK_CUR))
return FALSE;
break;
default: /* error */
bfd_msg ("unexpected type %ld(0x%lx) in hunk_ext1 at offset 0x%lx", type, type, bfd_tell (abfd));
return FALSE;
}
if (defsym_pos != 0 && syms)
{
/* there are some defined symbols, keep enough information on
them to simulate an armap later on */
nsyms = (struct arch_syms *) bfd_alloc (abfd, sizeof(struct arch_syms));
nsyms->next = NULL;
if (syms_tail)
syms_tail->next = nsyms;
else
*syms = nsyms;
syms_tail = nsyms;
nsyms->offset = defsym_pos;
nsyms->size = bfd_tell (abfd) - defsym_pos;
nsyms->unit_offset = unit_offset;
nsyms->name = 0;
++defsymcount;
defsym_pos = 0;
}
if (!get_long (abfd, &n))
return FALSE;
}
break; /* of HUNK_EXT */
default:
#if 0
bfd_msg ("unexpected hunk 0x%lx at offset 0x%lx",
hunk_type, bfd_tell (abfd));
#endif
return FALSE;
}
}
if (syms && symcount)
*symcount = defsymcount;
return (bfd_tell (abfd) == filesize);
}
static bfd_boolean amiga_digest_file (
bfd *abfd)
{
struct stat stat_buffer;
unsigned long tmp;
if (!get_long (abfd, &tmp))
{
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
switch (HUNK_VALUE(tmp))
{
case HUNK_UNIT:
/* Read the unit(s) */
if (bfd_stat (abfd, &stat_buffer) < 0)
return FALSE;
/*
while ((pos=bfd_tell (abfd)) < stat_buffer.st_size)
{*/
if (!amiga_read_unit (abfd, stat_buffer.st_size - abfd->origin))
return FALSE;
if (abfd->arelt_data)
arelt_size (abfd) = bfd_tell (abfd);
/* }*/
break;
case HUNK_HEADER:
/* This is a load file */
if (!amiga_read_load (abfd))
return FALSE;
break;
}
return TRUE;
}/* of amiga_digest_file */
/* Read in Unit file */
/* file pointer is located after the HUNK_UNIT LW */
static bfd_boolean
amiga_read_unit (
bfd *abfd,
unsigned long size)
{
unsigned long hunk_number = 0, hunk_type, tmp;
/* read LW length of unit's name */
if (!get_long (abfd, &tmp))
return FALSE;
/* and skip it (FIXME maybe) */
if (bfd_seek (abfd, tmp << 2, SEEK_CUR))
return FALSE;
while (bfd_tell (abfd) < size)
{
if (!get_long (abfd, &hunk_type))
return FALSE;
/* Now there may be CODE, DATA, BSS, SYMBOL, DEBUG, RELOC Hunks */
switch (HUNK_VALUE(hunk_type))
{
case HUNK_UNIT:
/* next unit, seek back and return */
return (bfd_seek (abfd, -4, SEEK_CUR) == 0);
case HUNK_DEBUG:
/* we don't parse hunk_debug at the moment */
if (!get_long (abfd, &tmp) || bfd_seek (abfd, tmp << 2, SEEK_CUR))
return FALSE;
break;
case HUNK_NAME:
case HUNK_CODE:
case HUNK_DATA:
case HUNK_BSS:
case HUNK_PPC_CODE:
/* Handle this hunk, including relocs, etc.
The finishing HUNK_END is consumed by the routine */
if (!amiga_handle_cdb_hunk (abfd, hunk_type, hunk_number++, 0, -1))
return FALSE;
break;
default:
/* Something very nasty happened: invalid hunk occured... */
bfd_set_error (bfd_error_wrong_format);
return FALSE;
break;
}/* Of switch hunk_type */
/* Next hunk */
}
return TRUE;
}
/* Read a load file */
static bfd_boolean
amiga_read_load (
bfd *abfd)
{
unsigned long *hunk_attributes, *hunk_sizes;
unsigned long max_hunk_number, hunk_type, i;
char buf[16];
/* Read hunk lengths (and memory attributes...) */
/* Read in each hunk */
if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf))
return FALSE;
/* If there are resident libs: abort (obsolete feature) */
if (GL (&buf[0]) != 0)
return FALSE;
max_hunk_number = GL(&buf[4]);
/* Sanity */
if (max_hunk_number < 1)
{
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
AMIGA_DATA(abfd)->nb_hunks = max_hunk_number;
/* Num of root hunk must be 0 */
if (GL (&buf[8]) != 0)
{
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
/* Num of last hunk must be mhn-1 */
if (GL (&buf[12]) != max_hunk_number - 1)
{
bfd_msg ("Overlay loadfiles are not supported");
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
hunk_sizes = alloca(max_hunk_number * sizeof(unsigned long));
hunk_attributes = alloca(max_hunk_number * sizeof(unsigned long));
if (hunk_sizes == NULL || hunk_attributes == NULL)
{
bfd_set_error (bfd_error_no_memory);
return FALSE;
}
/* Now, read in sizes and memory attributes */
for (i = 0; i < max_hunk_number; i++)
{
if (!get_long (abfd, &hunk_sizes[i]))
return FALSE;
switch (HUNK_ATTRIBUTE(hunk_sizes[i]))
{
case HUNK_ATTR_CHIP:
hunk_attributes[i] = MEMF_CHIP;
break;
case HUNK_ATTR_FAST:
hunk_attributes[i] = MEMF_FAST;
break;
case HUNK_ATTR_FOLLOWS:
if (!get_long (abfd, &hunk_attributes[i]))
return FALSE;
break;
default:
hunk_attributes[i] = 0;
break;
}
hunk_sizes[i] = HUNK_VALUE (hunk_sizes[i]) << 2;
}
for (i = 0; i < max_hunk_number; i++)
{
if (!get_long (abfd, &hunk_type))
return FALSE;
/* This may be HUNK_NAME, CODE, DATA, BSS, DEBUG */
switch (HUNK_VALUE(hunk_type))
{
case HUNK_NAME:
case HUNK_CODE:
case HUNK_DATA:
case HUNK_BSS:
case HUNK_PPC_CODE:
if (!amiga_handle_cdb_hunk (abfd, hunk_type, i,
hunk_attributes[i], hunk_sizes[i]))
{
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
break;
case HUNK_DEBUG:
if (--i, !amiga_handle_cdb_hunk (abfd, hunk_type, -1, 0, 0))
{
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
break;
default:
/* invalid hunk */
bfd_set_error (bfd_error_wrong_format);
return FALSE;
break;
}/* Of switch */
}
/* read stab */
if (get_long (abfd, &hunk_type) && hunk_type == HUNK_DEBUG)
{
unsigned long sz;
if (get_long (abfd, &sz))
if (bfd_seek(abfd, -4, SEEK_CUR) >= 0)
amiga_handle_cdb_hunk (abfd, hunk_type, -1, 0, sz);
}
return TRUE;
}/* Of amiga_read_load */
/* Handle NAME, CODE, DATA, BSS, DEBUG Hunks */
static bfd_boolean
amiga_handle_cdb_hunk (
bfd *abfd,
unsigned long hunk_type,
unsigned long hunk_number,
unsigned long hunk_attribute,
unsigned long hunk_size)
/* If hunk_size==-1, then we are digesting a HUNK_UNIT */
{
sec_ptr current_section;
char *sec_name, *current_name = NULL;
unsigned long len, tmp;
int secflags, is_load = (hunk_size != (unsigned long) -1);
if (HUNK_NAME == HUNK_VALUE(hunk_type)) /* get name */
{
if (!get_long (abfd, &tmp))
return FALSE;
len = HUNK_VALUE (tmp) << 2;
if (len != 0)
{
current_name = bfd_alloc (abfd, len + 1);
if (!current_name)
return FALSE;
if (bfd_bread (current_name, len, abfd) != len)
return FALSE;
current_name[len] = '\0';
if (current_name[0] == '\0')
{
bfd_release (abfd, current_name);
current_name = NULL;
}
}
if (!get_long (abfd, &hunk_type))
return FALSE;
}
/* file_pointer is now after hunk_type */
secflags = 0;
switch (HUNK_VALUE(hunk_type))
{
case HUNK_CODE:
case HUNK_PPC_CODE:
secflags = SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS;
sec_name = ".text";
goto do_section;
case HUNK_DATA:
secflags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS;
sec_name = ".data";
goto do_section;
case HUNK_BSS:
secflags = SEC_ALLOC;
sec_name = ".bss";
do_section:
if (!current_name)
current_name = sec_name;
if (!get_long (abfd, &tmp))
return FALSE;
len = HUNK_VALUE (tmp) << 2; /* Length of section */
if (!is_load)
{
hunk_attribute = HUNK_ATTRIBUTE(len);
hunk_attribute = (hunk_attribute == HUNK_ATTR_CHIP) ? MEMF_CHIP :
(hunk_attribute == HUNK_ATTR_FAST) ? MEMF_FAST : 0;
}
/* Make new section */
current_section = amiga_make_unique_section (abfd, current_name);
if (!current_section)
return FALSE;
current_section->filepos = bfd_tell (abfd);
/* For a loadfile, the section size in memory comes from the
hunk header. The size on disk may be smaller. */
current_section->_cooked_size = current_section->_raw_size =
((hunk_size == (unsigned long) -1) ? len : hunk_size);
current_section->target_index = hunk_number;
bfd_set_section_flags (abfd, current_section, secflags);
amiga_per_section(current_section)->disk_size = len; /* size on disk */
amiga_per_section(current_section)->attribute = hunk_attribute;
/* SBF: reserve symbol space for parsed stabs. */
if (HUNK_VALUE (hunk_type) == HUNK_DEBUG && current_name && (0 == strcmp (current_name, ".stab")))
{
/* read the content and scan for stabs to create BSF_CONSTRUCTORS. */
char buf[12];
while (len > 0)
{
len -= sizeof(buf);
if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf))
return FALSE;
switch (buf[4])
{
case N_INDR | N_EXT:
case N_WARNING:
// /* always take the next symbol. */
// len -= sizeof(buf);
// if (len > amiga_per_section(current_section)->disk_size || bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf))
// return FALSE;
// abfd->symcount++;
//
// /* fallthrough */
case N_UNDF | N_EXT:
case N_ABS | N_EXT:
case N_TEXT | N_EXT:
case N_DATA | N_EXT:
case N_SETV | N_EXT:
case N_BSS | N_EXT:
case N_COMM | N_EXT:
case N_SETA:
case N_SETA | N_EXT:
case N_SETT:
case N_SETT | N_EXT:
case N_SETD:
case N_SETD | N_EXT:
case N_SETB:
case N_SETB | N_EXT:
case N_WEAKU:
case N_WEAKA:
case N_WEAKT:
case N_WEAKD:
case N_WEAKB:
abfd->symcount++;
break;
}
}
/* We have symbols */
if (abfd->symcount)
abfd->flags |= HAS_SYMS;
}
else
/* skip the contents */
if ((secflags & SEC_HAS_CONTENTS) && bfd_seek (abfd, len, SEEK_CUR))
return FALSE;
if (!amiga_handle_rest (abfd, current_section, is_load))
return FALSE;
break;
/* Currently, there is one debug hunk per executable, instead of one
per unit as it would with a "standard" AmigaOS implementation. So
the debug hunk is at the same level as code/data/bss.
This will change in the future */
case HUNK_DEBUG:
/* handle .stab and .stabs as real sections. */
if (current_name && (0 == strcmp (current_name, ".stab") || 0 == strcmp (current_name, ".stabstr")))
{
secflags = SEC_HAS_CONTENTS;
goto do_section;
}
/* format of gnu debug hunk is:
HUNK_DEBUG
N
ZMAGIC
symtabsize
strtabsize
symtabdata [length=symtabsize]
strtabdata [length=strtabsize]
[pad bytes]
*/
/* read LW length */
if (!get_long (abfd, &tmp))
return FALSE;
len = tmp << 2;
if (len > 12)
{
char buf[12];
if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf))
return FALSE;
if (GL (&buf[0]) == ZMAGIC) /* GNU DEBUG HUNK */
{
amiga_data_type *amiga_data = AMIGA_DATA(abfd);
/* FIXME: we should add the symbols in the debug hunk to symtab... */
amiga_data->symtab_size = GL(&buf[4]);
amiga_data->stringtab_size = GL(&buf[8]);
adata(abfd).sym_filepos = bfd_tell (abfd);
adata(abfd).str_filepos = adata(abfd).sym_filepos + amiga_data->symtab_size;
}
len -= sizeof(buf);
}
if (bfd_seek (abfd, len, SEEK_CUR))
return FALSE;
break;
default:
bfd_set_error (bfd_error_wrong_format);
return FALSE;
break;
}/* switch (hunk_type) */
return TRUE;
}/* Of amiga_handle_cdb_hunk */
/* Handle rest of a hunk
I.e.: Relocs, EXT, SYMBOLS... */
static bfd_boolean
amiga_handle_rest (
bfd *abfd,
sec_ptr current_section,
bfd_boolean isload)
{
amiga_per_section_type *asect = amiga_per_section(current_section);
unsigned long hunk_type, hunk_value, relno, type, len, no;
raw_reloc_type *relp;
for (relno = 0;;)
{
if (!get_long (abfd, &hunk_type))
return FALSE;
hunk_value = HUNK_VALUE(hunk_type);
switch (hunk_value)
{
case HUNK_END:
if (relno)
{
abfd->flags |= HAS_RELOC;
current_section->flags |= SEC_RELOC;
current_section->reloc_count = relno;
}
return TRUE;
break;
case HUNK_ABSRELOC32:
case HUNK_RELRELOC16:
case HUNK_RELRELOC8:
case HUNK_DREL32:
case HUNK_DREL16:
case HUNK_DREL8:
case HUNK_RELOC32SHORT:
case HUNK_RELRELOC32:
case HUNK_ABSRELOC16:
case HUNK_RELRELOC26:
/* count and skip relocs */
relp = (raw_reloc_type *) bfd_alloc (abfd, sizeof(*relp));
relp->next = asect->relocs;
asect->relocs = relp;
relp->pos = bfd_tell (abfd) - 4;
relp->num = 0;
if (amiga_reloc_long_p (hunk_value, isload))
{
for (;;)
{
if (!get_long (abfd, &no))
return FALSE;
if (!no)
break;
relp->num += no;
if (bfd_seek (abfd, (no + 1) << 2, SEEK_CUR))
return FALSE;
}
}
else
{
for (;;)
{
if (!get_word (abfd, &no))
return FALSE;
if (!no)
break;
relp->num += no;
if (bfd_seek (abfd, (no + 1) << 1, SEEK_CUR))
return FALSE;
}
if ((bfd_tell (abfd) & 2) && bfd_seek (abfd, 2, SEEK_CUR))
return FALSE;
}
relno += relp->num;
break;
case HUNK_SYMBOL:
/* In a unit, we ignore these, since all symbol information
comes with HUNK_EXT, in a load file, these are added */
if (!isload)
{
asect->hunk_symbol_pos = bfd_tell (abfd);
for (;;)
{
/* size of symbol */
if (!get_long (abfd, &no))
return FALSE;
if (!no)
break;
/* skip the name */
if (bfd_seek (abfd, (no + 1) << 2, SEEK_CUR))
return FALSE;
}
break;
}
/* We add these, by falling through... */
case HUNK_EXT:
/* We leave these alone, until they are requested by the user */
asect->hunk_ext_pos = bfd_tell (abfd);
for (;;)
{
if (!get_long (abfd, &no))
return FALSE;
if (!no)
break;
/* symbol type and length */
type = (no >> 24) & 0xff;
len = no & 0xffffff;
/* skip symbol name */
if (bfd_seek (abfd, len << 2, SEEK_CUR))
return FALSE;
/* We have symbols */
abfd->flags |= HAS_SYMS;
abfd->symcount++;
switch (type)
{
case EXT_SYMB: /* Symbol hunks are relative to hunk start... */
case EXT_DEF: /* def relative to hunk */
case EXT_ABS: /* def absolute */
/* skip the value */
if (!get_long (abfd, &no))
return FALSE;
break;
case EXT_ABSCOMMON: /* Common ref/def */
case EXT_RELCOMMON:
case EXT_DEXT32COMMON:
case EXT_DEXT16COMMON:
case EXT_DEXT8COMMON:
/* FIXME: skip the size of common block */
if (!get_long (abfd, &no))
return FALSE;
/* Fall through */
case EXT_ABSREF32: /* 32 bit ref */
case EXT_RELREF16: /* 16 bit ref */
case EXT_RELREF8: /* 8 bit ref */
case EXT_DEXT32: /* 32 bit baserel */
case EXT_DEXT16: /* 16 bit baserel */
case EXT_DEXT8: /* 8 bit baserel */
case EXT_RELREF32:
case EXT_ABSREF16:
case EXT_ABSREF8:
case EXT_RELREF26:
if (!get_long (abfd, &no))
return FALSE;
if (no)
{
relno += no;
/* skip references */
if (bfd_seek (abfd, no << 2, SEEK_CUR))
return FALSE;
}
break;
default: /* error */
bfd_msg ("unexpected type %ld(0x%lx) in hunk_ext2 at offset 0x%lx", type, type, bfd_tell (abfd));
bfd_set_error (bfd_error_wrong_format);
return FALSE;
break;
}/* of switch type */
}
break;
case HUNK_DEBUG:
/* If a debug hunk is found at this position, the file has
been generated by a third party tool and the debug info
here are useless to us. Just skip the hunk, then. */
if (!get_long (abfd, &no) || bfd_seek (abfd, no << 2, SEEK_CUR))
return FALSE;
break;
default: /* error */
bfd_seek (abfd, -4, SEEK_CUR);
bfd_msg ("HUNK_END missing: unexpected hunktype %ld(0x%lx) at offset 0x%lx", hunk_type, hunk_type,
bfd_tell (abfd));
switch (hunk_value)
{
default:
bfd_set_error (bfd_error_wrong_format);
return FALSE;
case HUNK_CODE:
case HUNK_DATA:
case HUNK_BSS:
return TRUE;
}
break;
}/* Of switch */
}/* Of for */
return TRUE;
}/* of amiga_handle_rest */
static bfd_boolean
amiga_mkobject (
bfd *abfd)
{
amiga_data_type *rawptr;
rawptr = (amiga_data_type *) bfd_zalloc (abfd, sizeof(*rawptr));
abfd->tdata.amiga_data = rawptr;
return (rawptr != NULL);
}
static bfd_boolean
amiga_mkarchive (
bfd *abfd)
{
amiga_ardata_type *ar;
ar = (amiga_ardata_type *) bfd_zalloc (abfd, sizeof(*ar));
amiga_ardata (abfd) = ar;
return (ar != NULL);
}
/* write nb long words (possibly swapped out) to the output file */
static bfd_boolean
write_longs (
const unsigned long *in,
unsigned long nb,
bfd *abfd)
{
unsigned char out[10 * 4];
unsigned long i;
while (nb)
{
for (i = 0; i < nb && i < 10; in++, i++)
bfd_putb32 (in[0], &out[i * 4]);
if (bfd_bwrite ((PTR) out, 4 * i, abfd) != 4 * i)
return FALSE;
nb -= i;
}
return TRUE;
}
static bfd_boolean
write_words (
const unsigned long *in,
unsigned long nb,
bfd *abfd)
{
unsigned char out[10 * 2];
unsigned long i;
while (nb)
{
for (i = 0; i < nb && i < 10; in++, i++)
bfd_putb16 (in[0], &out[i * 2]);
if (bfd_bwrite ((PTR) out, 2 * i, abfd) != 2 * i)
return FALSE;
nb -= i;
}
return TRUE;
}
static long
determine_datadata_relocs (
bfd *abfd ATTRIBUTE_UNUSED,
sec_ptr section)
{
sec_ptr insection;
asymbol *sym_p;
unsigned int i;
long relocs = 1;
for (i = 0; i < section->reloc_count; i++)
{
arelent *r = section->orelocation[i];
if (r == NULL)
continue;
sym_p = *(r->sym_ptr_ptr); /* The symbol for this relocation */
insection = sym_p->section;
/* Is reloc relative to a special section? */
if (bfd_is_special_section(insection))
continue; /* Nothing to do, since this translates to HUNK_EXT */
if (insection->output_section == section)
relocs++;
}
return relocs;
}
/* Adjust the indices map when we decide not to output the section <sec> */
static void
remove_section_index (
sec_ptr sec,
int *index_map)
{
int i = sec->index;
for (sec = sec->next, index_map[i++] = -1; sec; sec = sec->next)
(index_map[i++])--;
}
/* Write out the contents of a bfd */
static bfd_boolean
amiga_write_object_contents (
bfd *abfd)
{
long datadata_relocs = 0, bss_size = 0, idx;
int *index_map, max_hunk = -1;
sec_ptr data_sec, p, q, stab = 0, stabstr = 0;
unsigned long n[5];
/* Distinguish UNITS, LOAD Files
Write out hunks+relocs+HUNK_EXT+HUNK_DEBUG (GNU format) */
DPRINT(5,("Entering write_object_conts\n"));
abfd->output_has_begun = TRUE; /* Output has begun */
if (AMIGA_DATA(abfd)->IsLoadFile)
{
// remove .stab and .stabstr
for (q = abfd->sections, p = q->next; p; p = p->next)
{
if (0 == strcmp (p->name, ".stab"))
{
stab = p;
q->next = p->next;
if (!p->next)
break;
continue;
}
if (0 == strcmp (p->name, ".stabstr"))
{
stabstr = p;
q->next = p->next;
if (!p->next)
break;
continue;
}
q = p;
}
// q points to last section - patch stab section and append
if (write_debug_hunk && stab && stabstr)
{
unsigned total = 12 + stab->_raw_size + stabstr->_raw_size;
unsigned char * data = (unsigned char *)bfd_alloc(abfd, total);
bfd_putb32(ZMAGIC, data);
bfd_putb32(stab->_raw_size, data + 4);
bfd_putb32(stabstr->_raw_size, data + 8);
memcpy(data + 12, stab->contents, stab->_raw_size);
memcpy(data + 12 + stab->_raw_size, stabstr->contents, stabstr->_raw_size);
stab->_raw_size = stab->_cooked_size = total;
stab->contents = data;
q->next = stab;
stab->next = 0;
}
int nn = 0;
for (p = abfd->sections; p != NULL; p = p->next)
p->index = nn++;
}
index_map = bfd_alloc (abfd, abfd->section_count * sizeof(int));
if (!index_map)
return FALSE;
for (idx = 0, p = abfd->sections; p != NULL; p = p->next)
index_map[idx++] = p->index;
/* Distinguish Load files and Unit files */
if (AMIGA_DATA(abfd)->IsLoadFile)
{
DPRINT(5,("Writing load file\n"));
/* no longer true - a base relative executable may have a chip,far and stab/stabstr sections */
// if (amiga_base_relative)
// BFD_ASSERT (abfd->section_count==3);
/* Write out load file header */
n[0] = HUNK_HEADER;
n[1] = n[2] = 0;
for (p = abfd->sections; p != NULL; p = p->next)
{
/* For baserel linking, don't remove empty sections, since they
may get some contents later on */
if ((amiga_base_relative || p->_raw_size != 0 || p->_cooked_size != 0)
&& !(amiga_base_relative && !strcmp (p->name, ".bss")))
{
/* don't count debug sections. */
if (strcmp (p->name, ".stab"))
n[2]++;
}
else
remove_section_index (p, index_map);
}
n[3] = 0;
n[4] = n[2] - 1;
if (!write_longs (n, 5, abfd))
return FALSE;
/* Write out sizes and memory specifiers... */
/* We have to traverse the section list again, bad but no other way... */
if (amiga_base_relative)
{
for (p = abfd->sections; p != NULL; p = p->next)
{
if (amiga_resident && !strcmp (p->name, ".data"))
{
datadata_relocs = determine_datadata_relocs (abfd, p);
data_sec = p;
}
else if (!strcmp (p->name, ".bss"))
{
/* Get size for header */
bss_size = p->_raw_size;
}
}
}
for (p = abfd->sections; p != NULL; p = p->next)
{
long extra = 0, ii;
if (index_map[p->index] < 0)
continue;
/* don't add debug sections. */
if (!strcmp (p->name, ".stab") || !strcmp (p->name, ".stabstr"))
continue;
if (datadata_relocs && !strcmp (p->name, ".text"))
extra = datadata_relocs * 4;
else if (bss_size && !strcmp (p->name, ".data"))
extra = bss_size;
/* convert to a size in long words */
n[0] = LONGSIZE(p->_raw_size + extra);
ii = amiga_per_section(p)->attribute;
switch (ii)
{
case MEMF_CHIP:
n[0] |= HUNKF_CHIP;
ii = 1;
break;
case MEMF_FAST:
n[0] |= HUNKF_FAST;
ii = 1;
break;
case 0: /* nothing */
ii = 1;
break;
default: /* special one */
n[0] |= 0xc0000000;
n[1] = ii;
ii = 2;
break;
}/* Of switch */
if (!write_longs (n, ii, abfd))
return FALSE;
}/* Of for */
}
else
{ /* Unit, no base-relative linking here.. */
DPRINT(5,("Writing unit\n"));
/* Write out unit header */
n[0] = HUNK_UNIT;
if (!write_longs (n, 1, abfd) || !write_name (abfd, abfd->filename, 0))
return FALSE;
unsigned i;
for (i = 0; i < bfd_get_symcount(abfd); i++)
{
asymbol *sym_p = abfd->outsymbols[i];
sec_ptr osection = sym_p->section;
if (!osection || !bfd_is_com_section(osection->output_section))
continue;
for (p = abfd->sections; p != NULL; p = p->next)
{
if (!strcmp (p->name, ".bss"))
{
if (!p->_raw_size && !p->_cooked_size)
p->_cooked_size = sym_p->value;
break;
}
}
break;
}
for (p = abfd->sections; p != NULL; p = p->next)
{
if (p->_raw_size == 0 && p->_cooked_size == 0 && strcmp (".text", p->name))
remove_section_index (p, index_map);
}
}
/* Compute the maximum hunk number of the ouput file */
for (p = abfd->sections; p != NULL; p = p->next)
max_hunk++;
/* Write out every section */
for (p = abfd->sections; p != NULL; p = p->next)
{
if (index_map[p->index] < 0)
continue;
#define ddrels (datadata_relocs&&!strcmp(p->name,".text")?datadata_relocs:0)
if (!amiga_write_section_contents (abfd, p, data_sec, ddrels, index_map, max_hunk))
return FALSE;
if (!amiga_write_symbols (abfd, p)) /* Write out symbols + HUNK_END */
return FALSE;
}/* of for sections */
/* Write out debug hunk, if requested */
if (AMIGA_DATA(abfd)->IsLoadFile && write_debug_hunk)
{
extern bfd_boolean
translate_to_native_sym_flags (bfd*, asymbol*, struct external_nlist*);
unsigned int offset = 4, symbols = 0, ii;
unsigned long str_size = 4; /* the first 4 bytes will be replaced with the length */
asymbol *sym;
sec_ptr s;
/* We have to convert all the symbols in abfd to a.out style... */
if (bfd_get_symcount(abfd))
{
#define CAN_WRITE_OUTSYM(sym) (sym!=NULL && sym->section && \
((sym->section->owner && \
bfd_get_flavour (sym->section->owner) == \
bfd_target_aout_flavour) || \
bfd_asymbol_flavour (sym) == \
bfd_target_aout_flavour))
for (ii = 0; ii < bfd_get_symcount(abfd); ii++)
{
sym = abfd->outsymbols[ii];
/* NULL entries have been written already... */
if (CAN_WRITE_OUTSYM(sym))
{
str_size += strlen (sym->name) + 1;
symbols++;
}
}
if (!symbols)
return TRUE;
/* Now, set the .text, .data and .bss fields in the tdata struct
because translate_to_native_sym_flags needs them... */
for (ii = 0, s = abfd->sections; s != NULL; s = s->next)
if (!strcmp (s->name, ".text"))
{
ii |= 1;
adata(abfd).textsec = s;
}
else if (!strcmp (s->name, ".data"))
{
ii |= 2;
adata(abfd).datasec = s;
}
else if (!strcmp (s->name, ".bss"))
{
ii |= 4;
adata(abfd).bsssec = s;
}
if (ii != 7) /* section(s) missing... */
{
bfd_msg ("Missing section, debughunk not written");
return TRUE;
}
/* Write out HUNK_DEBUG, size, ZMAGIC, ... */
n[0] = HUNK_DEBUG;
n[1] = 3 + ((symbols * sizeof(struct external_nlist) + str_size + 3) >> 2);
n[2] = ZMAGIC; /* Magic number */
n[3] = symbols * sizeof(struct external_nlist);
n[4] = str_size;
if (!write_longs (n, 5, abfd))
return FALSE;
/* Write out symbols */
for (ii = 0; ii < bfd_get_symcount(abfd); ii++) /* Translate every symbol */
{
sym = abfd->outsymbols[ii];
if (CAN_WRITE_OUTSYM(sym))
{
amiga_symbol_type *t = amiga_symbol(sym);
struct external_nlist data;
bfd_h_put_16(abfd, t->desc, data.e_desc);
bfd_h_put_8(abfd, t->other, data.e_other);
bfd_h_put_8(abfd, t->type, data.e_type);
if (!translate_to_native_sym_flags (abfd, sym, &data))
{
bfd_msg ("Cannot translate flags for %s", sym->name);
}
bfd_h_put_32(abfd, offset, &data.e_strx[0]); /* Store index */
offset += strlen (sym->name) + 1;
if (bfd_bwrite ((PTR) &data, sizeof(data), abfd) != sizeof(data))
return FALSE;
}
}
/* Write out strings */
if (!write_longs (&str_size, 1, abfd))
return FALSE;
for (ii = 0; ii < bfd_get_symcount(abfd); ii++)
{
sym = abfd->outsymbols[ii];
if (CAN_WRITE_OUTSYM(sym))
{
size_t len = strlen (sym->name) + 1;
/* Write string tab */
if (bfd_bwrite (sym->name, len, abfd) != len)
return FALSE;
}
}
/* Write padding */
n[0] = 0;
ii = (4 - (str_size & 3)) & 3;
if (ii && bfd_bwrite ((PTR) n, ii, abfd) != ii)
return FALSE;
/* write a HUNK_END here to finish the loadfile, or AmigaOS
will refuse to load it */
n[0] = HUNK_END;
if (!write_longs (n, 1, abfd))
return FALSE;
}/* Of if bfd_get_symcount (abfd) */
}/* Of write out debug hunk */
bfd_release (abfd, index_map);
return TRUE;
}
/* Write a string padded to 4 bytes and preceded by it's length in
long words ORed with <value> */
static bfd_boolean
write_name (
bfd *abfd,
const char *name,
unsigned long value)
{
unsigned long n[1];
size_t l;
l = strlen (name);
if (AMIGA_DATA(abfd)->IsLoadFile && l > MAX_NAME_SIZE)
l = MAX_NAME_SIZE;
n[0] = (LONGSIZE (l) | value);
if (!write_longs (n, 1, abfd))
return FALSE;
if (bfd_bwrite (name, l, abfd) != l)
return FALSE;
n[0] = 0;
l = (4 - (l & 3)) & 3;
return (l && bfd_bwrite ((PTR) n, l, abfd) != l ? FALSE : TRUE);
}
static bfd_boolean
amiga_write_archive_contents (
bfd *arch)
{
struct stat status;
bfd *object;
for (object = arch->archive_head; object; object = object->next)
{
unsigned long remaining;
if (bfd_write_p(object))
{
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
}
if (object->arelt_data != NULL)
{
remaining = arelt_size(object);
}
else
{
if (stat (object->filename, &status) != 0)
{
bfd_set_error (bfd_error_system_call);
return FALSE;
}
remaining = status.st_size;
}
if (bfd_seek (object, 0, SEEK_SET))
return FALSE;
while (remaining)
{
char buf[DEFAULT_BUFFERSIZE];
unsigned long amt = sizeof(buf);
if (amt > remaining)
amt = remaining;
errno = 0;
if (bfd_bread (buf, amt, object) != amt)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_malformed_archive);
return FALSE;
}
if (bfd_bwrite (buf, amt, arch) != amt)
return FALSE;
remaining -= amt;
}
}
return TRUE;
}
static bfd_boolean
amiga_write_armap (
bfd *arch ATTRIBUTE_UNUSED,
unsigned int elength ATTRIBUTE_UNUSED,
struct orl *map ATTRIBUTE_UNUSED,
unsigned int orl_count ATTRIBUTE_UNUSED,
int stridx ATTRIBUTE_UNUSED)
{
return TRUE;
}
static int
determine_type (
arelent *r)
{
switch (r->howto->type)
{
case H_ABS32: /* 32 bit absolute */
return 0;
case H_ABS16: /* 16 bit absolute */
return 0; // not working properly?
case H_PC32: /* 32 bit pcrel */
return 2;
case H_PC16: /* 16 bit pcrel */
return 3;
case H_ABS8: /* 8 bit absolute */
case H_PC8: /* 8 bit pcrel */
return 4;
case H_SD32: /* 32 bit baserel */
return 5;
case H_SD16: /* 16 bit baserel */
return 6;
case H_SD8: /* 8 bit baserel */
return 7;
default: /* Error, can't represent this */
bfd_set_error (bfd_error_nonrepresentable_section);
return -1;
}/* Of switch */
}
#define NB_RELOC_TYPES 8
static const unsigned long reloc_types[NB_RELOC_TYPES] = {
HUNK_ABSRELOC32, HUNK_ABSRELOC16,
HUNK_RELRELOC32, HUNK_RELRELOC16, HUNK_RELRELOC8,
HUNK_DREL32, HUNK_DREL16, HUNK_DREL8
};
/* Write out section contents, including relocs */
static bfd_boolean
amiga_write_section_contents (
bfd *abfd,
sec_ptr section,
sec_ptr data_sec,
unsigned long datadata_relocs,
int *index_map,
int max_hunk)
{
sec_ptr insection;
asymbol *sym_p;
arelent *r;
unsigned long zero = 0, disksize, pad, n[2], k, l, s;
long *reloc_counts, reloc_count = 0;
unsigned char *values;
int i, j, x, type;
DPRINT(5,("Entering write_section_contents\n"));
/* If we are base-relative linking and the section is .bss and abfd
is a load file, then return */
if (AMIGA_DATA(abfd)->IsLoadFile)
{
if (amiga_base_relative && !strcmp (section->name, ".bss"))
return TRUE; /* Nothing to do */
}
else
{
/* WRITE out HUNK_NAME + section name */
n[0] = HUNK_NAME;
if (!write_longs (n, 1, abfd) || !write_name (abfd, section->name, 0))
return FALSE;
}
/* Depending on the type of the section, write out HUNK_{CODE|DATA|BSS} */
if (section->flags & SEC_CODE) /* Code section */
n[0] = HUNK_CODE;
else if (section->flags & (SEC_DATA | SEC_LOAD)) /* data section */
n[0] = HUNK_DATA;
else if (section->flags & SEC_ALLOC) /* BSS */
n[0] = HUNK_BSS;
else if (section->flags & SEC_DEBUGGING) /* debug section */
n[0] = HUNK_DEBUG;
else /* Error */
{
#if 0
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
#else
/* FIXME: Just dump everything we don't currently recognize into
a DEBUG hunk. */
n[0] = HUNK_DEBUG;
#endif
}
DPRINT(10,("Section type is %lx\n",n[0]));
/* Get real size in n[1], this may be shorter than the size in the header */
if (amiga_per_section(section)->disk_size == 0)
amiga_per_section(section)->disk_size = section->_raw_size;
disksize = LONGSIZE (amiga_per_section(section)->disk_size) + datadata_relocs;
n[1] = disksize;
/* in a load file, we put section attributes only in the header */
if (!AMIGA_DATA(abfd)->IsLoadFile)
{
/* Get attribute for section */
switch (amiga_per_section(section)->attribute)
{
case MEMF_CHIP:
n[1] |= HUNKF_CHIP;
break;
case MEMF_FAST:
n[1] |= HUNKF_FAST;
break;
case 0:
break;
default: /* error, can't represent this */
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
break;
}
}/* Of switch */
if (!write_longs (n, 2, abfd))
return FALSE;
DPRINT(5,("Wrote code and size=%lx\n",n[1]));
/* If a BSS hunk, we're done, else write out section contents */
if (HUNK_VALUE (n[0]) == HUNK_BSS)
return TRUE;
DPRINT(5,("Non bss hunk...\n"));
/* Traverse through the relocs, sample them in reloc_data, adjust section
data to get 0 addend
Then compactify reloc_data
Set the entry in the section for the reloc to NULL */
if (disksize != 0)
BFD_ASSERT((section->flags & SEC_IN_MEMORY) != 0);
reloc_counts = (long *) bfd_zalloc (abfd, NB_RELOC_TYPES * (max_hunk + 1) * sizeof(long));
if (!reloc_counts)
return FALSE;
DPRINT(5,("Section has %d relocs\n",section->reloc_count));
for (l = 0; l < section->reloc_count; l++)
{
r = section->orelocation[l];
if (r == NULL)
continue;
sym_p = *(r->sym_ptr_ptr); /* The symbol for this relocation */
insection = sym_p->section;
DPRINT(5,("Sec for reloc is %lx(%s)\n",insection,insection->name));
DPRINT(5,("Symbol for this reloc is %lx(%s)\n",sym_p,sym_p->name));
/* Is reloc relative to a special section? */
if (bfd_is_special_section(insection))
continue; /* Nothing to do, since this translates to HUNK_EXT */
r->addend += sym_p->value; /* Add offset of symbol from section start */
/* Address of reloc has been unchanged since original reloc, or has
been adjusted by get_relocated_section_contents. */
/* For relocs, the vma of the target section is in the data, the
addend is -vma of that section =>No need to add vma */
/* Add in offset */
r->addend += insection->output_offset;
/* Determine which hunk to write, and index of target */
x = index_map[insection->output_section->index];
if (x < 0 || x > max_hunk)
{
bfd_msg ("erroneous relocation to hunk %d/%s from %s", x, insection->output_section->name, insection->name);
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
}
type = determine_type (r);
if (type == -1)
return FALSE;
if (type >= NB_RELOC_TYPES)
{
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
}
reloc_counts[type + (x * NB_RELOC_TYPES)]++;
reloc_count++;
/* There is no error checking with these... */
DPRINT(5,("reloc address=%lx,addend=%lx\n",r->address,r->addend));
values = &section->contents[r->address];
switch (r->howto->size)
{
case 0: /* adjust byte */
x = ((char *) values)[0] + r->addend;
values[0] = x & 0xff;
break;
case 1: /* adjust word */
k = values[1] | (values[0] << 8);
x = (int) k + r->addend;
values[0] = (x & 0xff00) >> 8;
values[1] = x & 0xff;
break;
case 2: /* adjust long */
k = values[3] | (values[2] << 8) | (values[1] << 16) | (values[0] << 24);
x = (int) k + r->addend;
values[3] = x & 0xff;
values[2] = (x & 0xff00) >> 8;
values[1] = (x & 0xff0000) >> 16;
values[0] = ((unsigned int) x & 0xff000000) >> 24;
break;
}/* of switch */
r->addend = 0;
DPRINT(5,("Did adjusting\n"));
}/* of for l */
DPRINT(5,("Did all relocs\n"));
/* We applied all the relocs, as far as possible to obtain 0 addend fields */
/* Write the section contents */
if (amiga_per_section(section)->disk_size != 0)
{
if (bfd_bwrite ((PTR) section->contents,
amiga_per_section(section)->disk_size,
abfd) !=
amiga_per_section(section)->disk_size)
return FALSE;
/* pad the section on disk if necessary (to a long boundary) */
pad = (4 - (amiga_per_section(section)->disk_size & 3)) & 3;
if (pad && (bfd_bwrite ((PTR) &zero, pad, abfd) != pad))
return FALSE;
}
#if 0
/* write bss data in the data hunk if needed */
for (; bss_size--;)
if (!write_longs (&zero, 1, abfd))
return FALSE;
#endif
if (datadata_relocs)
{
datadata_relocs--;
if (!write_longs (&datadata_relocs, 1, abfd))
return FALSE;
for (s = 0; s < data_sec->reloc_count; s++)
{
r = data_sec->orelocation[s];
if (r == NULL)
continue;
sym_p = *(r->sym_ptr_ptr); /* The symbol for this relocation */
insection = sym_p->section;
/* Is reloc relative to a special section? */
if (bfd_is_special_section(insection))
continue; /* Nothing to do, since this translates to HUNK_EXT */
if (insection->output_section == data_sec)
{
if (determine_type (r) == 0)
if (!write_longs (&r->address, 1, abfd))
return FALSE;
}
}
}
DPRINT(10,("Wrote contents, writing relocs now\n"));
if (reloc_count > 0)
{
/* do not use H_ABS32 and H_ABS16 simultaneous. */
if (reloc_counts[0] && reloc_counts[1])
{
}
/* Sample every reloc type */
for (i = 0; i < NB_RELOC_TYPES; i++)
{
bfd_boolean rel32 = amiga_reloc_long_p (reloc_types[i], AMIGA_DATA(abfd)->IsLoadFile);
int written = FALSE;
for (j = 0; j <= max_hunk; j++)
{
long relocs;
while ((relocs = reloc_counts[i + (j * NB_RELOC_TYPES)]) > 0)
{
if (!written)
{
if (!write_longs (&reloc_types[i], 1, abfd))
return FALSE;
written = TRUE;
}
if (relocs > 0xffff)
relocs = 0xffff;
n[0] = relocs;
n[1] = j;
if (rel32)
{
if (!write_longs (n, 2, abfd))
return FALSE;
}
else
{
if (!write_words (n, 2, abfd))
return FALSE;
}
reloc_counts[i + (j * NB_RELOC_TYPES)] -= relocs;
reloc_count -= relocs;
for (k = 0; k < section->reloc_count; k++)
{
int jj;
r = section->orelocation[k];
if (r == NULL) /* already written */
continue;
sym_p = *(r->sym_ptr_ptr); /* The symbol for this relocation */
insection = sym_p->section;
/* Is reloc relative to a special section? */
if (bfd_is_special_section(insection))
continue; /* Nothing to do, since this translates to HUNK_EXT */
#if 0
/* Determine which hunk to write, and index of target */
for (jj = 0, sec = abfd->sections; sec; sec = sec->next, jj++)
{
if (sec == insection->output_section)
break;
}
BFD_ASSERT (jj==index_map[insection->output_section->index]);
#else
jj = index_map[insection->output_section->index];
#endif
if (jj == j && i == determine_type (r))
{
section->orelocation[k] = NULL;
if (rel32)
{
if (!write_longs (&r->address, 1, abfd))
return FALSE;
}
else
{
if (!write_words (&r->address, 1, abfd))
return FALSE;
}
if (--relocs == 0)
break;
}
}
}
}
/* write a zero to finish the relocs */
if (written)
{
if (rel32 || (bfd_tell (abfd) & 2) == 0)
{
if (!write_longs (&zero, 1, abfd))
return FALSE;
}
else
{
if (!write_words (&zero, 1, abfd))
return FALSE;
}
}
}
}
bfd_release (abfd, reloc_counts);
DPRINT(5,("Leaving write_section...\n"));
if (reloc_count > 0)
{
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
}
return TRUE;
}
/* Write out symbol information, including HUNK_EXT, DEFS, ABS.
In the case, we were linking base relative, the symbols of the .bss
hunk have been converted already to belong to the .data hunk */
static bfd_boolean amiga_write_symbols (
bfd *abfd, sec_ptr section)
{
sec_ptr osection;
asymbol *sym_p;
arelent *r;
unsigned long n[3], symbol_header, type;
unsigned int i, j, idx, ncnt, symbol_count;
/* If base rel linking and section is .bss ==> exit */
if (amiga_base_relative && !strcmp (section->name, ".bss"))
return TRUE;
if (section->reloc_count == 0 && bfd_get_symcount (abfd) == 0)
{/* Write HUNK_END */
alldone:
DPRINT(5,("Leaving write_symbols\n"));
n[0] = HUNK_END;
return write_longs (n, 1, abfd);
}
/* If this is Loadfile, then do not write HUNK_EXT, but rather HUNK_SYMBOL */
symbol_header = AMIGA_DATA(abfd)->IsLoadFile ? HUNK_SYMBOL : HUNK_EXT;
/* Write out all the symbol definitions, then HUNK_END
Now, first traverse the relocs, all entries that are non NULL
have to be taken into account */
symbol_count = 0;
DPRINT(10,("Traversing relocation table\n"));
for (i = 0; i < section->reloc_count; i++)
{
r = section->orelocation[i];
if (r == NULL)
continue;
sym_p = *(r->sym_ptr_ptr); /* The symbol for this relocation */
osection = sym_p->section; /* The section the symbol belongs to */
/* this section MUST be a special section */
DPRINT(5,("Symbol is %s, section is %lx(%s)\n",sym_p->name,osection,osection->name));
/* group together relocations referring to the same symbol and howto */
for (idx = i, j = i + 1; j < section->reloc_count; j++)
{
arelent *rj = section->orelocation[j];
if (rj == NULL || sym_p != *(rj->sym_ptr_ptr) || r->howto != rj->howto)
continue; /* no match */
if (++i == j)
continue; /* adjacent */
section->orelocation[j] = section->orelocation[i];
section->orelocation[i] = rj;
}
if ((symbol_count++) == 0) /* First write out the HUNK_EXT */
{
if (!write_longs (&symbol_header, 1, abfd))
return FALSE;
}
if (!bfd_is_com_section(osection)) /* Not common symbol */
{
DPRINT(5,("Non common ref\n"));
/* Determine type of ref */
switch (r->howto->type)
{
case H_ABS8:
type = EXT_ABSREF8;
break;
case H_ABS16:
type = EXT_ABSREF16;
break;
case H_ABS32:
type = EXT_ABSREF32;
break;
case H_PC8:
type = EXT_RELREF8;
break;
case H_PC16:
type = EXT_RELREF16;
break;
case H_PC32:
type = EXT_RELREF32;
break;
case H_SD8:
type = EXT_DEXT8;
break;
case H_SD16:
type = EXT_DEXT16;
break;
case H_SD32:
type = EXT_DEXT32;
break;
case H_PC26:
type = EXT_RELREF26;
break;
default: /* Error, can't represent this */
bfd_msg ("unexpected reloc %d(%s) at offset 0x%lx", r->howto->type, r->howto->name, bfd_tell (abfd));
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
break;
}/* Of switch */
ncnt = 0;
}/* Of is ref to undefined or abs symbol */
else /* ref to common symbol */
{
DPRINT(5,("Common ref\n"));
switch (r->howto->type)
{
default:
bfd_msg ("Warning: bad reloc %s for common symbol %s", r->howto->name, sym_p->name);
case H_ABS32:
type = EXT_ABSCOMMON;
break;
case H_PC32:
type = EXT_RELCOMMON;
break;
case H_SD8:
type = EXT_DEXT8COMMON;
break;
case H_SD16:
type = EXT_DEXT16COMMON;
break;
case H_SD32:
type = EXT_DEXT32COMMON;
break;
}/* Of switch */
n[0] = sym_p->value; /* Size of common block */
ncnt = 1;
}/* Of is common section */
DPRINT(5,("Type is %lx\n",type));
if (!write_name (abfd, sym_p->name, type << 24))
return FALSE;
n[ncnt] = i - idx + 1; /* refs for symbol... */
if (!write_longs (n, ncnt + 1, abfd))
return FALSE;
for (; idx <= i; ++idx)
{
n[0] = section->orelocation[idx]->address;
if (!write_longs (n, 1, abfd))
return FALSE;
}
}/* Of traverse relocs */
/* Now traverse the symbol table and write out all definitions, that are relative
to this hunk.
Absolute defs are always only written out with the first hunk.
Don't write out:
local symbols
undefined symbols
indirect symbols
warning symbols
debugging symbols
warning symbols
constructor symbols
since they are unrepresentable in HUNK format.. */
DPRINT(10,("Traversing symbol table\n"));
for (i = 0; i < bfd_get_symcount(abfd); i++)
{
sym_p = abfd->outsymbols[i];
osection = sym_p->section;
DPRINT(5,("%d: symbol(%s), osec=%lx(%s)\n",
i,sym_p->name,osection,osection?osection->name:"null"));
if (osection == NULL) /* FIXME: Happens with constructor functions. */
continue;
if (bfd_is_und_section(osection)
/*||bfd_is_com_section(osection)*/
|| bfd_is_ind_section(osection))
continue; /* Don't write these */
/* Only write abs defs, if not writing a Loadfile */
if (bfd_is_abs_section(osection) && (section->index == 0) && !AMIGA_DATA(abfd)->IsLoadFile)
{
DPRINT(5,("Abs symbol\n"));
/* don't write debug symbols, they will be written in a
HUNK_DEBUG later on */
if (sym_p->flags & BSF_DEBUGGING)
continue;
if ((symbol_count++) == 0) /* First write out the HUNK_EXT */
{
if (!write_longs (&symbol_header, 1, abfd))
return FALSE;
}
if (!write_name (abfd, sym_p->name, EXT_ABS << 24))
return FALSE;
n[0] = sym_p->value;
if (!write_longs (n, 1, abfd))
return FALSE;
continue;
}/* Of abs def */
if (bfd_is_abs_section(osection))
continue; /* Not first hunk, already written */
/* If it is a warning symbol, or a constructor symbol or a
debugging or a local symbol, don't write it */
if (sym_p->flags & (BSF_WARNING | BSF_CONSTRUCTOR | BSF_DEBUGGING | BSF_LOCAL))
continue;
if ((sym_p->flags & BSF_GLOBAL) == 0)
continue;
/* Now, if osection==section, write it out */
if (osection->output_section == section)
{
DPRINT(5,("Writing it out\n"));
if ((symbol_count++) == 0) /* First write out the header */
{
if (!write_longs (&symbol_header, 1, abfd))
return FALSE;
}
type = symbol_header == HUNK_EXT ? EXT_DEF << 24 : 0;
if (!write_name (abfd, sym_p->name, type))
return FALSE;
n[0] = sym_p->value + sym_p->section->output_offset;
if (!write_longs (n, 1, abfd))
return FALSE;
}
else
{
/* write common definitions as bss common references */
if (bfd_is_com_section(osection->output_section) && section->index == 2)
{
if ((symbol_count++) == 0) /* First write out the header */
{
if (!write_longs (&symbol_header, 1, abfd))
return FALSE;
}
if (!write_name (abfd, sym_p->name, EXT_ABSCOMMON << 24))
return FALSE;
n[0] = sym_p->value;
n[1] = 0;
if (!write_longs (n, 2, abfd))
return FALSE;
}
}
}/* Of for */
DPRINT(10,("Did traversing\n"));
if (symbol_count) /* terminate HUNK_EXT, HUNK_SYMBOL */
{
n[0] = 0;
if (!write_longs (n, 1, abfd))
return FALSE;
}
DPRINT(5,("Leaving\n"));
goto alldone;
/* Write HUNK_END, return */
}
static bfd_boolean
amiga_get_section_contents (bfd *abfd, sec_ptr section,
PTR location,
file_ptr offset,
bfd_size_type count)
{
unsigned long disk_size=amiga_per_section(section)->disk_size;
if (bfd_seek (abfd, section->filepos + offset, SEEK_SET))
return FALSE;
if (offset+count > disk_size)
{
/* the section's size on disk may be smaller than in memory
in this case, pad the contents */
if (bfd_bread (location, disk_size-offset, abfd) != disk_size-offset)
return FALSE;
memset ((char *) location + disk_size - offset, 0, count-(disk_size-offset));
}
else
{
if (bfd_bread (location, count, abfd) != count)
return FALSE;
}
return TRUE;
}
static bfd_boolean
amiga_new_section_hook (
bfd *abfd,
sec_ptr newsect)
{
newsect->used_by_bfd = (PTR) bfd_zalloc (abfd, sizeof(amiga_per_section_type));
newsect->alignment_power = 2;
if (!strcmp (newsect->name, ".data_chip") || !strcmp (newsect->name, ".bss_chip"))
amiga_per_section(newsect)->attribute |= MEMF_CHIP;
if (!strcmp (newsect->name, ".data_fast") || !strcmp (newsect->name, ".bss_fast"))
amiga_per_section(newsect)->attribute |= MEMF_FAST;
return TRUE;
}
static bfd_boolean
amiga_slurp_symbol_table (
bfd *abfd)
{
amiga_data_type *amiga_data = AMIGA_DATA(abfd);
amiga_symbol_type *asp;
unsigned long l, len, type;
sec_ptr section;
sec_ptr stab = 0;
sec_ptr stabstr = 0;
sec_ptr sbss = 0;
sec_ptr sdata = 0;
sec_ptr stext = 0;
if (amiga_data->symbols)
return TRUE; /* already read */
if (!bfd_get_symcount(abfd))
return TRUE;
asp = (amiga_symbol_type *) bfd_zalloc (abfd, sizeof(amiga_symbol_type) * bfd_get_symcount(abfd));
if ((amiga_data->symbols = asp) == NULL)
return FALSE;
/* Symbols are associated with every section */
for (section = abfd->sections; section != NULL; section = section->next)
{
amiga_per_section_type *asect = amiga_per_section(section);
/* remember the stabstr section. */
if (0 == strcmp (section->name, ".stabstr"))
stabstr = section;
else if (0 == strcmp (section->name, ".stab"))
stab = section;
else if (0 == strcmp (section->name, ".data"))
sdata = section;
else if (0 == strcmp (section->name, ".text"))
stext = section;
else if (0 == strcmp (section->name, ".bss"))
sbss = section;
if (asect->hunk_ext_pos == 0)
continue;
if (bfd_seek (abfd, asect->hunk_ext_pos, SEEK_SET))
return FALSE;
for (asect->amiga_symbols = asp; get_long (abfd, &l) && l; asp++)
{
type = l >> 24; /* type of entry */
len = (l & 0xffffff) << 2; /* namelength */
/* read the name */
if ((asp->symbol.name = bfd_alloc (abfd, len + 1)) == NULL)
return FALSE;
if (bfd_bread ((PTR) asp->symbol.name, len, abfd) != len)
return FALSE;
((char *) asp->symbol.name)[len] = '\0';
asp->symbol.the_bfd = abfd;
asp->symbol.flags = BSF_GLOBAL;
/*asp->desc = 0;
asp->other = 0;*/
asp->type = type;
asp->index = asp - amiga_data->symbols;
switch (type)
{
case EXT_ABSCOMMON: /* Common reference/definition */
case EXT_RELCOMMON:
case EXT_DEXT32COMMON:
case EXT_DEXT16COMMON:
case EXT_DEXT8COMMON:
asp->symbol.section = bfd_com_section_ptr;
/* size of common block -> symbol's value */
if (!get_long (abfd, &l))
return FALSE;
asp->symbol.value = l;
/* skip refs */
if (!get_long (abfd, &l) || bfd_seek (abfd, l << 2, SEEK_CUR))
return FALSE;
asp->refnum = l;
break;
case EXT_ABS: /* Absolute */
asp->symbol.section = bfd_abs_section_ptr;
goto rval;
break;
case EXT_DEF: /* Relative Definition */
case EXT_SYMB: /* Same as EXT_DEF for load files */
asp->symbol.section = section;
rval:
/* read the value */
if (!get_long (abfd, &l))
return FALSE;
asp->symbol.value = l;
break;
default: /* References to an undefined symbol */
asp->symbol.section = bfd_und_section_ptr;
asp->symbol.flags = 0;
/* skip refs */
if (!get_long (abfd, &l) || bfd_seek (abfd, l << 2, SEEK_CUR))
return FALSE;
asp->refnum = l;
break;
}
}
}
/* add the constructor symbols defined by stab. */
if (stab && stabstr)
{
amiga_per_section_type *astab = amiga_per_section(stab);
amiga_per_section_type *astabstr = amiga_per_section(stabstr);
if (sbss == 0)
sbss = amiga_make_unique_section (abfd, ".bss");
if (sdata == 0)
sdata = amiga_make_unique_section (abfd, ".data");
unsigned char * stabstrdata = (unsigned char *) bfd_alloc (abfd, astabstr->disk_size);
if (!stabstrdata)
return FALSE;
if (bfd_seek (abfd, stabstr->filepos, SEEK_SET))
return FALSE;
if (bfd_bread (stabstrdata, astabstr->disk_size, abfd) != astabstr->disk_size)
return FALSE;
stabstr->contents = stabstrdata;
unsigned char * stabdata = (unsigned char *) bfd_alloc (abfd, astab->disk_size);
if (!stabdata)
return FALSE;
if (bfd_seek (abfd, stab->filepos, SEEK_SET))
return FALSE;
if (bfd_bread (stabdata, astab->disk_size, abfd) != astab->disk_size)
return FALSE;
stab->contents = stabdata;
{unsigned i; for (i = 0; i < astab->disk_size; i += 12)
{
unsigned str_offset = bfd_getb32 (stabdata + i);
char ctype = stabdata[i + 4];
unsigned value = bfd_getb32 (stabdata + i + 8);
unsigned flags = BSF_GLOBAL;
switch (ctype)
{
default:
continue;
case N_WARNING:
section = bfd_und_section_ptr;
flags |= BSF_WARNING;
break;
case N_INDR | N_EXT:
asp->symbol.section = bfd_ind_section_ptr;
flags |= BSF_INDIRECT;
break;
case N_UNDF | N_EXT:
if (value == 0)
{
asp->symbol.section = bfd_und_section_ptr;
flags = 0;
}
else
asp->symbol.section = bfd_com_section_ptr;
break;
case N_ABS | N_EXT:
asp->symbol.section = bfd_abs_section_ptr;
break;
case N_TEXT | N_EXT:
asp->symbol.section = stext;
break;
case N_DATA | N_EXT:
case N_SETV | N_EXT:
asp->symbol.section = sdata;
break;
case N_BSS | N_EXT:
asp->symbol.section = sbss;
break;
case N_COMM | N_EXT:
asp->symbol.section = bfd_com_section_ptr;
break;
case N_SETA:
case N_SETA | N_EXT:
flags |= BSF_CONSTRUCTOR;
asp->symbol.section = bfd_abs_section_ptr;
break;
case N_SETT:
case N_SETT | N_EXT:
flags |= BSF_CONSTRUCTOR;
asp->symbol.section = stext;
break;
case N_SETD:
case N_SETD | N_EXT:
flags |= BSF_CONSTRUCTOR;
asp->symbol.section = sdata;
break;
case N_SETB:
case N_SETB | N_EXT:
flags |= BSF_CONSTRUCTOR;
asp->symbol.section = sbss;
break;
case N_WEAKU:
asp->symbol.section = bfd_und_section_ptr;
flags |= BSF_WEAK;
break;
case N_WEAKA:
asp->symbol.section = bfd_abs_section_ptr;
flags |= BSF_WEAK;
break;
case N_WEAKT:
asp->symbol.section = stext;
flags |= BSF_WEAK;
break;
case N_WEAKD:
asp->symbol.section = sdata;
flags |= BSF_WEAK;
break;
case N_WEAKB:
asp->symbol.section = sbss;
flags |= BSF_WEAK;
break;
}
asp->symbol.flags = flags;
asp->symbol.the_bfd = abfd;
asp->type = 0x81; //??
asp->index = asp - amiga_data->symbols;
if (str_offset > astabstr->disk_size)
return FALSE;
asp->symbol.name = (char *) stabstrdata + str_offset;
asp->symbol.value = value;
++asp;
}}
}
return TRUE;
}
/* Get size of symtab */
static long amiga_get_symtab_upper_bound (
bfd *abfd)
{
if (!amiga_slurp_symbol_table (abfd))
return -1;
return (bfd_get_symcount (abfd) + 1) * (sizeof(amiga_symbol_type *));
}
static long amiga_get_symtab (
bfd *abfd,asymbol **location)
{
if (!amiga_slurp_symbol_table (abfd))
return -1;
if (bfd_get_symcount(abfd))
{
amiga_symbol_type *symp = AMIGA_DATA(abfd)->symbols;
unsigned int i;
for (i = 0; i < bfd_get_symcount(abfd); i++, symp++)
*location++ = &symp->symbol;
*location = 0;
}
return bfd_get_symcount(abfd);
}
static asymbol *
amiga_make_empty_symbol (
bfd *abfd)
{
amiga_symbol_type *new = (amiga_symbol_type *) bfd_zalloc (abfd, sizeof(amiga_symbol_type));
new->symbol.the_bfd = abfd;
return &new->symbol;
}
static void
amiga_get_symbol_info (
bfd *ignore_abfd ATTRIBUTE_UNUSED,
asymbol *symbol,
symbol_info *ret)
{
bfd_symbol_info (symbol, ret);
if (symbol->name[0] == ' ')
ret->name = "* empty table entry ";
if (bfd_is_abs_section(symbol->section))
ret->type = (symbol->flags & BSF_LOCAL) ? 'a' : 'A';
}
static void
amiga_print_symbol (
bfd *abfd,
PTR afile,
asymbol *symbol,
bfd_print_symbol_type how)
{
FILE *file = (FILE *)afile;
switch (how)
{
case bfd_print_symbol_name:
fprintf (file, "%s", symbol->name);
break;
case bfd_print_symbol_more:
fprintf (file, "%4lx %2x",
amiga_symbol(symbol)->refnum,
(unsigned int)amiga_symbol(symbol)->type);
break;
case bfd_print_symbol_all:
if (symbol->name[0] == ' ')
{
fprintf (file, "* empty table entry ");
}
else
{
bfd_print_symbol_vandf (abfd, (PTR)file, symbol);
fprintf (file, " %-10s %04lx %02x %s",
symbol->section->name,
amiga_symbol(symbol)->refnum,
(unsigned int)amiga_symbol(symbol)->type,
symbol->name);
}
break;
}
}
static long
amiga_get_reloc_upper_bound (
bfd *abfd ATTRIBUTE_UNUSED,
sec_ptr asect)
{
return (asect->reloc_count + 1) * sizeof(arelent *);
}
static bfd_boolean
read_raw_relocs (
bfd *abfd,
sec_ptr section,
unsigned long d_offset, /* offset in the bfd */
unsigned long count) /* number of relocs */
{
unsigned long hunk_number, offset, type, no, j;
reloc_howto_type *howto;
if (bfd_seek (abfd, d_offset, SEEK_SET))
return FALSE;
while ((long) count > 0)
{
/* first determine type of reloc */
if (!get_long (abfd, &type))
return FALSE;
howto = howto_for_raw_reloc (type, AMIGA_DATA(abfd)->IsLoadFile);
if (howto == NULL)
{
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
/* read reloc count, hunk number and offsets */
if (amiga_reloc_long_p (type, AMIGA_DATA(abfd)->IsLoadFile))
{
for (;;)
{
/* read offsets and hunk number */
if (!get_long (abfd, &no))
return FALSE;
if (!no)
break;
count -= no;
if (!get_long (abfd, &hunk_number))
return FALSE;
/* add relocs */
for (j = 0; j < no; j++)
{
if (!get_long (abfd, &offset) || !amiga_add_reloc (abfd, section, offset, NULL, howto, hunk_number))
return FALSE;
}
}
}
else
{
for (;;)
{
/* read offsets and hunk number */
if (!get_word (abfd, &no))
return FALSE;
if (!no)
break;
count -= no;
if (!get_word (abfd, &hunk_number))
return FALSE;
/* add relocs */
for (j = 0; j < no; j++)
{
if (!get_word (abfd, &offset) || !amiga_add_reloc (abfd, section, offset, NULL, howto, hunk_number))
return FALSE;
}
}
}
}
return TRUE;
}
/* slurp in relocs, amiga_digest_file left various pointers for us */
bfd_boolean
amiga_slurp_relocs (
bfd *abfd,
sec_ptr section,
asymbol **symbols ATTRIBUTE_UNUSED)
{
amiga_per_section_type *asect = amiga_per_section(section);
reloc_howto_type *howto;
amiga_symbol_type *asp;
raw_reloc_type *relp;
unsigned long offset, type, n, i;
if (section->relocation)
return TRUE;
for (relp = asect->relocs; relp != NULL; relp = relp->next)
if (relp->num && !read_raw_relocs (abfd, section, relp->pos, relp->num))
return FALSE;
/* Now step through the raw_symbols and add all relocs in them */
if (!AMIGA_DATA(abfd)->symbols && !amiga_slurp_symbol_table (abfd))
return FALSE;
if (asect->hunk_ext_pos == 0)
return TRUE;
if (bfd_seek (abfd, asect->hunk_ext_pos, SEEK_SET))
return FALSE;
for (asp = asect->amiga_symbols; get_long (abfd, &n) && n; asp++)
{
type = (n >> 24) & 0xff;
n &= 0xffffff;
/* skip the name */
if (bfd_seek (abfd, n << 2, SEEK_CUR))
return FALSE;
switch (type)
{
case EXT_SYMB:
case EXT_DEF:
case EXT_ABS: /* no relocs here */
if (bfd_seek (abfd, 4, SEEK_CUR))
return FALSE;
break;
/* same as below, but advance lp by one to skip common size */
case EXT_DEXT32COMMON:
case EXT_DEXT16COMMON:
case EXT_DEXT8COMMON:
case EXT_RELCOMMON:
case EXT_ABSCOMMON:
if (bfd_seek (abfd, 4, SEEK_CUR))
return FALSE;
/* Fall through */
default: /* reference to something */
/* points to num of refs to hunk */
if (!get_long (abfd, &n))
return FALSE;
/* determine howto */
howto = howto_for_reloc (type);
if (howto == NULL)
return FALSE;
/* Add relocs to this section, relative to asp */
for (i = 0; i < n; i++) /* refs follow */
{
if (!get_long (abfd, &offset))
return FALSE;
if (!amiga_add_reloc (abfd, section, offset,
abfd->outsymbols ? amiga_symbol(abfd->outsymbols[asp->index]) : asp, howto, -4))
return FALSE;
}
break;
}/* of switch */
}
return TRUE;
}/* Of slurp_relocs */
static long
amiga_canonicalize_reloc (
bfd *abfd,
sec_ptr section,
arelent **relptr,
asymbol **symbols)
{
amiga_reloc_type *src;
if (!section->relocation && !amiga_slurp_relocs (abfd, section, symbols))
return -1;
for (src = (amiga_reloc_type *) section->relocation; src; src = src->next)
*relptr++ = &src->relent;
*relptr = NULL;
return section->reloc_count;
}
/* Set section contents */
/* We do it the following way:
If this is a bss section ==> error
Otherwise, we try to allocate space for this section,
if this has not already been done
Then we set the memory area to the contents */
static bfd_boolean
amiga_set_section_contents (
bfd *abfd,
sec_ptr section,
PTR location,
file_ptr offset,
bfd_size_type count)
{
if ((section->flags&SEC_HAS_CONTENTS)==0) /* BSS */
{
bfd_set_error (bfd_error_no_contents);
return FALSE;
}
if ((section->flags&SEC_IN_MEMORY)==0) /* Not in memory, so alloc space */
{
section->contents = (bfd_byte *) bfd_zalloc (abfd, section->_raw_size);
if (section->contents == NULL)
return FALSE;
section->flags |= SEC_IN_MEMORY;
DPRINT(5,("Allocated %lx bytes at %lx\n",section->_raw_size,section->contents));
}
/* Copy mem */
memmove(&section->contents[offset],location,count);
return TRUE;
}/* Of set_section_contents */
/* FIXME: Is this everything? */
static bfd_boolean
amiga_set_arch_mach (
bfd *abfd,
enum bfd_architecture arch,
unsigned long machine)
{
bfd_default_set_arch_mach (abfd, arch, machine);
if (arch == bfd_arch_m68k)
{
switch (machine)
{
case bfd_mach_m68000:
case bfd_mach_m68008:
case bfd_mach_m68010:
case bfd_mach_m68020:
case bfd_mach_m68030:
case bfd_mach_m68040:
case bfd_mach_m68060:
case 0:
return TRUE;
default:
break;
}
}
return FALSE;
}
static int
amiga_sizeof_headers (
bfd *ignore_abfd ATTRIBUTE_UNUSED,
bfd_boolean ignore ATTRIBUTE_UNUSED)
{
/* The amiga hunk format doesn't have headers. */
return 0;
}
/*
* Load the stab symbols if both sections .stab and .stabstr exist.
* For Loadables use the stabs DEBUG section, if present
*/
aout_symbol_type **
amiga_load_stab_symbols (bfd *abfd)
{
amiga_data_type *amiga_data = AMIGA_DATA(abfd);
if (amiga_data->stab_symbols)
return amiga_data->stab_symbols;
/* search the stab sections. */
unsigned char * stab = 0;
unsigned char * stabstr = 0;
sec_ptr s;
for (s = abfd->sections; s; s = s->next)
{
if (0 == strcmp(".text", s->name))
amiga_data->a.textsec = s;
else
if (0 == strcmp(".data", s->name))
amiga_data->a.datasec = s;
else
if (0 == strcmp(".bss", s->name))
amiga_data->a.bsssec = s;
else
if (0 == strcmp(".stab", s->name))
{
amiga_data->symtab_size = s->_raw_size;
stab = s->contents;
}
else
if (0 == strcmp(".stabstr", s->name))
{
amiga_data->stringtab_size = s->_raw_size;
stabstr = s->contents;
}
}
if (!stab || !stabstr)
{
if (!adata(abfd).sym_filepos || !adata(abfd).str_filepos)
return 0;
// executable - load the data now.
stab = (unsigned char *)bfd_alloc(abfd, amiga_data->symtab_size);
bfd_seek(abfd, adata(abfd).sym_filepos, SEEK_SET);
if (bfd_bread (stab, amiga_data->symtab_size, abfd) != amiga_data->symtab_size)
return 0;
stabstr = (unsigned char *)bfd_alloc(abfd, amiga_data->stringtab_size);
bfd_seek(abfd, adata(abfd).str_filepos, SEEK_SET);
if (bfd_bread (stabstr, amiga_data->stringtab_size, abfd) != amiga_data->stringtab_size)
return 0;
}
unsigned num = amiga_data->symtab_size / sizeof(struct external_nlist);
struct aout_symbol * asyms = (struct aout_symbol *)bfd_zalloc(abfd, num * sizeof(struct aout_symbol));
if (!aout_32_translate_symbol_table(abfd, asyms, (struct external_nlist *) stab, num, (char *)stabstr, amiga_data->stringtab_size, 0))
return 0;
struct aout_symbol ** ss = (struct aout_symbol **)bfd_alloc(abfd, (1 + num) * sizeof(struct aout_symbol *));
unsigned i;
for (i = 0; i < num; ++i)
ss[i] = &asyms[i];
ss[num] = 0;
amiga_data->stab_symbols = ss;
return ss;
}
/* Provided a BFD, a section and an offset into the section, calculate
and return the name of the source file and the line nearest to the
wanted location. */
bfd_boolean
amiga_find_nearest_line (
bfd *abfd ATTRIBUTE_UNUSED,
sec_ptr section ATTRIBUTE_UNUSED,
asymbol **symbols ATTRIBUTE_UNUSED,
bfd_vma offset ATTRIBUTE_UNUSED,
const char **filename_ptr ATTRIBUTE_UNUSED,
const char **functionname_ptr ATTRIBUTE_UNUSED,
unsigned int *line_ptr ATTRIBUTE_UNUSED)
{
aout_symbol_type **stab_symbols = amiga_load_stab_symbols(abfd);
if (stab_symbols)
return aout_32_find_nearest_line(abfd, section, stab_symbols, offset, filename_ptr, functionname_ptr, line_ptr);
return FALSE;
}
static reloc_howto_type *
amiga_bfd_reloc_type_lookup (
bfd *abfd ATTRIBUTE_UNUSED,
bfd_reloc_code_real_type code)
{
DPRINT(5,("reloc: %s (%d)\n",bfd_get_reloc_code_name(code),code));
switch (code)
{
case BFD_RELOC_8_PCREL: return &howto_table[R_PC8];
case BFD_RELOC_16_PCREL: return &howto_table[R_PC16];
case BFD_RELOC_32_PCREL: return &howto_table[R_PC32];
case BFD_RELOC_8: return &howto_table[R_ABS8];
case BFD_RELOC_16: return &howto_table[R_ABS16];
case BFD_RELOC_32: return &howto_table[R_ABS32];
case BFD_RELOC_8_BASEREL: return &howto_table[R_SD8];
case BFD_RELOC_16_BASEREL: return &howto_table[R_SD16];
case BFD_RELOC_32_BASEREL: return &howto_table[R_SD32];
case BFD_RELOC_CTOR: return &howto_table[R_ABS32];
/* FIXME: everything handled? */
default: return NULL;
}
}
static bfd_boolean
amiga_bfd_copy_private_bfd_data (
bfd *ibfd,
bfd *obfd)
{
if (bfd_get_flavour (ibfd) == bfd_target_amiga_flavour
&& bfd_get_flavour (obfd) == bfd_target_amiga_flavour) {
AMIGA_DATA(obfd)->IsLoadFile = AMIGA_DATA(ibfd)->IsLoadFile;
}
return TRUE;
}
static bfd_boolean
amiga_bfd_copy_private_section_data (
bfd *ibfd ATTRIBUTE_UNUSED,
sec_ptr isec,
bfd *obfd ATTRIBUTE_UNUSED,
sec_ptr osec)
{
if (bfd_get_flavour (osec->owner) == bfd_target_amiga_flavour
&& bfd_get_flavour (isec->owner) == bfd_target_amiga_flavour)
{
amiga_per_section(osec)->disk_size = amiga_per_section(isec)->disk_size;
amiga_per_section(osec)->attribute = amiga_per_section(isec)->attribute;
}
return TRUE;
}
/* There is no armap in the amiga libraries, so we fill carsym entries
one by one after having parsed the whole archive. */
static bfd_boolean
amiga_slurp_armap (
bfd *abfd)
{
struct arch_syms *syms;
carsym *defsyms, *csym;
unsigned long symcount;
/* allocate the carsyms */
syms = amiga_ardata(abfd)->defsyms;
symcount = amiga_ardata(abfd)->defsym_count;
defsyms = (carsym *) bfd_alloc (abfd, sizeof(carsym) * symcount);
if (!defsyms)
return FALSE;
bfd_ardata(abfd)->symdefs = defsyms;
bfd_ardata(abfd)->symdef_count = symcount;
for (csym = defsyms; syms; syms = syms->next)
{
unsigned long len, n;
char *symblock;
if(csym >= defsyms + symcount)
{
fprintf(stderr, "slurp_armap: read to many symbols\n");
exit(1);
}
if (syms->name)
{
csym->file_offset = syms->unit_offset;
csym->name = syms->name;
++csym;
continue;
}
if (bfd_seek (abfd, syms->offset, SEEK_SET))
return FALSE;
symblock = (char *) bfd_alloc (abfd, syms->size);
if (!symblock)
return FALSE;
if (bfd_bread (symblock, syms->size, abfd) != syms->size)
return FALSE;
n = GL(symblock);
symblock += 4;
len = n & 0xffffff;
//type = (n >> 24) & 0xff;
len <<= 2;
csym->name = symblock;
csym->name[len] = '\0';
csym->file_offset = syms->unit_offset;
++csym;
}
if(csym != defsyms + symcount)
{
fprintf(stderr, "slurp_armap: read not enough symbols\n");
exit(1);
}
bfd_has_map (abfd) = TRUE;
return TRUE;
}
static void
amiga_truncate_arname (
bfd *abfd ATTRIBUTE_UNUSED,
const char *pathname ATTRIBUTE_UNUSED,
char *arhdr ATTRIBUTE_UNUSED)
{
}
static const struct bfd_target *
amiga_archive_p (
bfd *abfd)
{
struct arch_syms *symbols = NULL;
struct stat stat_buffer;
symindex symcount = 0;
int units;
if (bfd_stat (abfd, &stat_buffer) < 0)
{
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
if (stat_buffer.st_size != 0)
{
/* scan the units */
if (!parse_archive_units (abfd, &units, stat_buffer.st_size, FALSE,
&symbols, &symcount))
{
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
/* if there is only one unit, file suffix is not .a and .lib, we
consider it an object, not an archive. Obviously it's not
always true but taking objects for archives makes ld fail,
so we don't have much of a choice */
if (units == 1)
{
char *p = strrchr (abfd->filename, '.');
if (p == NULL || (strcmp (p, ".a") && strcmp (p, ".lib")))
{
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
}
}
if (abfd->arelt_data)
arelt_size (abfd) = bfd_tell (abfd);
bfd_seek (abfd, 0, SEEK_SET);
abfd->arch_info = bfd_scan_arch ("m68k:68000");
if (amiga_mkarchive (abfd))
{
bfd_ardata(abfd)->first_file_filepos = 0;
amiga_ardata(abfd)->filesize = stat_buffer.st_size;
amiga_ardata(abfd)->defsyms = symbols;
amiga_ardata(abfd)->defsym_count = symcount;
if (amiga_slurp_armap (abfd))
{
bfd_set_error (bfd_error_no_more_archived_files);
return abfd->xvec;
}
}
return NULL;
}
static bfd *
amiga_openr_next_archived_file (
bfd *archive,
bfd *last_file)
{
file_ptr filestart;
if (!last_file)
filestart = bfd_ardata (archive)->first_file_filepos;
else
{
unsigned int size = arelt_size(last_file);
/* Pad to an even boundary... */
filestart = last_file->origin + size;
filestart += filestart % 2;
}
return _bfd_get_elt_at_filepos (archive, filestart);
}
static PTR
amiga_read_ar_hdr (
bfd *abfd)
{
struct areltdata *ared;
unsigned long start_pos,len;
char buf[8],*base,*name;
start_pos = bfd_tell (abfd);
if (start_pos >= amiga_ardata(abfd)->filesize)
{
bfd_set_error (bfd_error_no_more_archived_files);
return NULL;
}
/* get unit type and name length in long words */
if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf))
return NULL;
if (GL (&buf[0]) != HUNK_UNIT)
{
bfd_set_error (bfd_error_malformed_archive);
return NULL;
}
ared = bfd_zalloc (abfd, sizeof (struct areltdata));
if (ared == NULL)
return NULL;
len = GL (&buf[4]) << 2;
ared->filename = bfd_alloc (abfd, len+1 > 16 ? len+1+16 : 32);
if (ared->filename == NULL)
return NULL;
switch (len)
{
default:
if (bfd_bread (ared->filename, len, abfd) != len)
return NULL;
ared->filename[len] = '\0';
/* strip path part */
base = strchr (name = ared->filename, ':');
if (base != NULL)
name = base + 1;
for (base = name; *name; ++name)
{
if (*name == '/')
base = name + 1;
}
if (*base != '\0')
{
char *const p = strrchr (ared->filename = base, '.');
if (!p || (strcmp (p, ".o") && strcmp (p, ".obj")))
sprintf (name, "-%08lu.o", ++amiga_ardata(abfd)->outnum);
break;
}
/* Fall through */
case 0: /* fake a name */
sprintf (ared->filename, "obj-%08lu.o", ++amiga_ardata(abfd)->outnum);
break;
}
if (bfd_seek (abfd, start_pos+4, SEEK_SET))
return NULL;
if (!amiga_read_unit (abfd, amiga_ardata(abfd)->filesize))
return NULL;
ared->parsed_size = bfd_tell (abfd) - start_pos;
if (bfd_seek (abfd, start_pos, SEEK_SET))
return NULL;
return (PTR) ared;
}
static int
amiga_generic_stat_arch_elt (
bfd *abfd,
struct stat *buf)
{
if (abfd->arelt_data == NULL)
{
bfd_set_error (bfd_error_invalid_operation);
return -1;
}
/* No header in amiga archives. Let's set reasonable default values */
buf->st_mode = 0644;
buf->st_uid = 0;
buf->st_gid = 0;
buf->st_mtime = 2922 * 24 * 60 * 60;
buf->st_size = arelt_size(abfd);
return 0;
}
/* Entry points through BFD_JUMP_TABLE_GENERIC */
#define amiga_close_and_cleanup _bfd_generic_close_and_cleanup
#define amiga_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
/* amiga_new_section_hook defined above */
/* amiga_get_section_contents defined above */
#define amiga_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
/* Entry points through BFD_JUMP_TABLE_COPY */
#define amiga_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
/*#define amiga_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data*/
#define amiga_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data
#define amiga_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
#define amiga_bfd_print_private_bfd_data _bfd_generic_bfd_print_private_bfd_data
/* Entry points through BFD_JUMP_TABLE_ARCHIVE */
/*#define amiga_slurp_armap bfd_slurp_armap*/
#define amiga_slurp_extended_name_table _bfd_slurp_extended_name_table
#define amiga_construct_extended_name_table _bfd_archive_bsd_construct_extended_name_table
/*#define amiga_truncate_arname bfd_gnu_truncate_arname*/
/*#define amiga_write_armap bsd_write_armap*/
/*#define amiga_read_ar_hdr _bfd_generic_read_ar_hdr*/
/*#define amiga_openr_next_archived_file bfd_generic_openr_next_archived_file*/
#define amiga_get_elt_at_index _bfd_generic_get_elt_at_index
/*#define amiga_generic_stat_arch_elt bfd_generic_stat_arch_elt*/
#define amiga_update_armap_timestamp _bfd_archive_bsd_update_armap_timestamp
/* Entry points through BFD_JUMP_TABLE_SYMBOLS */
/* amiga_get_symtab_upper_bound defined above */
/* amiga_get_symtab defined above */
/* amiga_make_empty_symbol defined above */
/* amiga_print_symbol defined above */
/* amiga_get_symbol_info defined above */
#define amiga_bfd_is_local_label_name bfd_generic_is_local_label_name
#define amiga_get_lineno (alent * (*)(bfd *, asymbol *)) bfd_nullvoidptr
/* amiga_find_nearest_line defined above */
#define amiga_bfd_make_debug_symbol (asymbol * (*)(bfd *, PTR, unsigned long)) bfd_nullvoidptr
#define amiga_read_minisymbols _bfd_generic_read_minisymbols
#define amiga_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
/* Entry points through BFD_JUMP_TABLE_LINK
NOTE: We use a special get_relocated_section_contents both in amiga AND in a.out files.
In addition, we use an own final_link routine, which is nearly identical to _bfd_generic_final_link */
bfd_byte *
get_relocated_section_contents PARAMS ((bfd *, struct bfd_link_info *,
struct bfd_link_order *, bfd_byte *, bfd_boolean, asymbol **));
#define amiga_bfd_get_relocated_section_contents get_relocated_section_contents
#define amiga_bfd_relax_section bfd_generic_relax_section
#define amiga_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
#define amiga_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
#define amiga_bfd_link_add_symbols _bfd_generic_link_add_symbols
#define amiga_bfd_link_just_syms _bfd_generic_link_just_syms
bfd_boolean amiga_final_link PARAMS ((bfd *, struct bfd_link_info *));
#define amiga_bfd_final_link amiga_final_link
#define amiga_bfd_link_split_section _bfd_generic_link_split_section
#define amiga_bfd_gc_sections bfd_generic_gc_sections
#define amiga_bfd_merge_sections bfd_generic_merge_sections
#define amiga_bfd_discard_group bfd_generic_discard_group
#if defined (amiga)
#undef amiga /* So that the JUMP_TABLE() macros below can work. */
#endif
const bfd_target amiga_vec =
{
"amiga", /* name */
bfd_target_amiga_flavour,
BFD_ENDIAN_BIG, /* data byte order */
BFD_ENDIAN_BIG, /* header byte order */
HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS | WP_TEXT, /* object flags */
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA, /* section flags */
'_', /* symbol leading char */
' ', /* ar_pad_char */
15, /* ar_max_namelen (15 for UNIX compatibility) */
bfd_getb64, bfd_getb_signed_64, bfd_putb64,
bfd_getb32, bfd_getb_signed_32, bfd_putb32,
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
bfd_getb64, bfd_getb_signed_64, bfd_putb64,
bfd_getb32, bfd_getb_signed_32, bfd_putb32,
bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
{
/* bfd_check_format */
_bfd_dummy_target,
amiga_object_p,
amiga_archive_p,
_bfd_dummy_target
},
{
/* bfd_set_format */
bfd_false,
amiga_mkobject,
amiga_mkarchive,
bfd_false
},
{
/* bfd_write_contents */
bfd_false,
amiga_write_object_contents,
amiga_write_archive_contents,
bfd_false
},
BFD_JUMP_TABLE_GENERIC(amiga),
BFD_JUMP_TABLE_COPY(amiga),
BFD_JUMP_TABLE_CORE(_bfd_nocore),
BFD_JUMP_TABLE_ARCHIVE(amiga),
BFD_JUMP_TABLE_SYMBOLS (amiga),
BFD_JUMP_TABLE_RELOCS(amiga),
BFD_JUMP_TABLE_WRITE(amiga),
BFD_JUMP_TABLE_LINK(amiga),
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
NULL,
NULL
};