2
0
mirror of https://github.com/bebbo/amigaos-binutils-2.14.git synced 2025-12-08 22:28:25 +00:00
Files
amigaos-binutils/bfd/amigaos.c
Gunther Nikl fc73468ff9 Prefer BFD data where available.
* bfd/amigaos.c (amiga_write_section_contents): Consult relocation howto
  for the size of the relocation object.
2015-04-29 17:18:00 +00:00

3248 lines
86 KiB
C
Raw 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 "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
#include "libamiga.h"
#define BYTES_IN_WORD 4
#include "aout/aout64.h" /* struct external_nlist */
#ifndef alloca
extern PTR alloca PARAMS ((size_t));
#endif
#define bfd_is_bfd_section(sec) \
(bfd_is_abs_section(sec)||bfd_is_com_section(sec)||bfd_is_und_section(sec)||bfd_is_ind_section(sec))
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 */
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
static reloc_howto_type *howto_for_raw_reloc PARAMS ((unsigned long type));
static reloc_howto_type *howto_for_reloc PARAMS ((unsigned long type));
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 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));
static 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_PC16,R_PC8,R_SD32,R_SD16,R_SD8,R_ABS32SHORT,R_PC26,R_PC32,R__MAX};
static 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_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_ABS32SHORT, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0, "RELOC32SHORT", FALSE, 0x0000ffff, 0x0000ffff, FALSE},
{H_PC26, 0, 2, 26, TRUE, 0, complain_overflow_signed, 0, "RELRELOC26", FALSE, 0x03fffffc, 0x03fffffc, TRUE},
{H_PC32, 0, 2, 32, TRUE, 0, complain_overflow_signed, 0, "RELRELOC32", FALSE, 0xffffffff, 0xffffffff, TRUE}
};
static reloc_howto_type *
howto_for_raw_reloc (type)
unsigned long type;
{
switch (type)
{
case HUNK_ABSRELOC32:
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[R_SD32];
case HUNK_DREL16:
return &howto_table[R_SD16];
case HUNK_DREL8:
return &howto_table[R_SD8];
case HUNK_RELOC32SHORT:
return &howto_table[R_ABS32SHORT];
case HUNK_RELRELOC32:
return &howto_table[R_PC32];
case HUNK_RELRELOC26:
return &howto_table[R_PC26];
default:
return NULL;
}
}
static reloc_howto_type *
howto_for_reloc (type)
unsigned long type;
{
switch (type)
{
case EXT_ABSREF32:
case EXT_ABSCOMMON:
return &howto_table[R_ABS32];
case EXT_RELREF32:
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 (abfd, n)
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 (abfd, n)
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 (abfd)
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 (abfd, 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 (abfd, section, offset, symbol, howto, target_hunk)
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 (abfd, name)
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 (abfd, n_units, filesize, one, syms, symcount)
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;
*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;
}
/* Fall through */
case HUNK_NAME:
case HUNK_CODE:
case HUNK_DATA:
case HUNK_DEBUG:
case HUNK_PPC_CODE:
if (!get_long (abfd, &len)
|| 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:
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_EXT:
defsym_pos = 0;
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 */
if (defsym_pos==0)
defsym_pos = bfd_tell (abfd) - 4;
/* skip name & value */
if (bfd_seek (abfd, (len+1)<<2, SEEK_CUR))
return FALSE;
defsymcount++;
break;
case EXT_ABSREF32:
case EXT_RELREF16:
case EXT_RELREF8:
case EXT_DEXT32:
case EXT_DEXT16:
case EXT_DEXT8:
case EXT_RELREF32:
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:
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 (!get_long (abfd, &n))
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;
}
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 (abfd)
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 (abfd, size)
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 (abfd)
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 */
}
return TRUE;
}/* Of amiga_read_load */
/* Handle NAME, CODE, DATA, BSS, DEBUG Hunks */
static bfd_boolean
amiga_handle_cdb_hunk (abfd, hunk_type, hunk_number, hunk_attribute,
hunk_size)
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;
/* 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:
/* 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 (abfd, current_section, isload)
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_DREL32:
if (isload)
hunk_value = HUNK_RELOC32SHORT;
case HUNK_ABSRELOC32:
case HUNK_RELRELOC16:
case HUNK_RELRELOC8:
case HUNK_DREL16:
case HUNK_DREL8:
case HUNK_RELOC32SHORT:
/* 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 (hunk_value != HUNK_RELOC32SHORT) {
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_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_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 (abfd)
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 (abfd)
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 (in, nb, abfd)
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 long
determine_datadata_relocs (abfd, section)
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_bfd_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, index_map)
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 (abfd)
bfd *abfd;
{
long datadata_relocs=0,bss_size=0,idx;
int *index_map,max_hunk=-1;
sec_ptr data_sec,p;
unsigned long i,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 */
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"));
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")))
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, i;
if (index_map[p->index] < 0)
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);
i = amiga_per_section(p)->attribute;
switch (i)
{
case MEMF_CHIP:
n[0]|=HUNKF_CHIP;
i=1;
break;
case MEMF_FAST:
n[0]|=HUNKF_FAST;
i=1;
break;
case 0: /* nothing */
i=1;
break;
default: /* special one */
n[0]|=0xc0000000;
n[1]=i;
i=2;
break;
}/* Of switch */
if (!write_longs (n, i, 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;
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)
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, i;
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 (i = 0; i < bfd_get_symcount (abfd); i++)
{
sym = abfd->outsymbols[i];
/* 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 (i=0,s=abfd->sections;s!=NULL;s=s->next)
if (!strcmp(s->name,".text"))
{
i|=1;
adata(abfd).textsec=s;
}
else if (!strcmp(s->name,".data"))
{
i|=2;
adata(abfd).datasec=s;
}
else if (!strcmp(s->name,".bss"))
{
i|=4;
adata(abfd).bsssec=s;
}
if (i!=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 (i = 0; i < bfd_get_symcount (abfd); i++) /* Translate every symbol */
{
sym = abfd->outsymbols[i];
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 (i = 0; i < bfd_get_symcount (abfd); i++)
{
sym = abfd->outsymbols[i];
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;
i = (4 - (str_size & 3)) & 3;
if (i && bfd_bwrite ((PTR)n, i, abfd) != i)
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 (abfd, name, value)
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 (arch)
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 (arch, elength, map, orl_count, stridx)
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 (r)
arelent *r;
{
switch (r->howto->type)
{
case H_ABS8: /* 8 bit absolute */
case H_PC8: /* 8 bit pcrel */
return 2;
case H_ABS16: /* 16 bit absolute */
case H_PC16: /* 16 bit pcrel */
return 1;
case H_ABS32: /* 32 bit absolute */
/*case H_PC32:*//* 32 bit pcrel */
return 0;
case H_SD8: /* 8 bit base rel */
return 5;
case H_SD16: /* 16 bit base rel */
return 4;
case H_SD32: /* 32 bit baserel */
return 3;
default: /* Error, can't represent this */
bfd_set_error (bfd_error_nonrepresentable_section);
return -1;
}/* Of switch */
}
#define NB_RELOC_TYPES 6
static const unsigned long reloc_types[NB_RELOC_TYPES] = {
HUNK_ABSRELOC32, HUNK_RELRELOC16, HUNK_RELRELOC8,
HUNK_DREL32, HUNK_DREL16, HUNK_DREL8
};
/* Write out section contents, including relocs */
static bfd_boolean
amiga_write_section_contents (abfd, section, data_sec, datadata_relocs,
index_map, max_hunk)
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,