home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
binutils-2.7-src.tgz
/
tar.out
/
fsf
/
binutils
/
bfd
/
amigaos.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-28
|
79KB
|
2,831 lines
/* BFD back-end for Commodore-Amiga AmigaOS binaries.
Copyright (C) 1990-1994 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 "bfdlink.h"
#include "sysdep.h"
#include "libbfd.h"
#include "libamiga.h"
typedef struct aout_symbol {
asymbol symbol;
short desc;
char other;
unsigned char type;
} aout_symbol_type;
#include "aout/aout64.h"
#define GL(x) bfd_get_32 (abfd, (bfd_byte *) (x))
#define GW(x) bfd_get_16 (abfd, (bfd_byte *) (x))
#define DEBUG_AMIGA 10000
#if DEBUG_AMIGA
#include <varargs.h>
static void error_print(va_alist)
va_dcl
{
va_list args;
char *fmt;
va_start(args);
fmt=va_arg(args,char *);
(void)vfprintf(stderr,fmt,args);
va_end(args);
}
#define DPRINT(L,x) if (L>=DEBUG_AMIGA) error_print x
#else
#define DPRINT(L,x)
#endif
static boolean amiga_digest_file ();
static boolean amiga_mkobject ();
reloc_howto_type howto_hunk_reloc8 =
{
HUNK_RELOC8, /* type */
0, /* rightshift */
0, /* size */
8, /* bitsize */
true, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
0, /* special_function */
"reloc8", /* textual name */
false, /* partial_inplace? */
0x000000ff, /* src_mask */
0x000000ff, /* dst_mask */
true /* pcrel_offset */
};
reloc_howto_type howto_hunk_reloc16 =
{HUNK_RELOC16,0,1,16,true,0,complain_overflow_bitfield,0,"reloc16",false,0x0000ffff,0x0000ffff,true};
reloc_howto_type howto_hunk_reloc32 =
{HUNK_RELOC32,0,2,32,true,0,complain_overflow_bitfield,0,"reloc32",false,0xffffffff,0xffffffff,true};
reloc_howto_type howto_hunk_drel8 =
{HUNK_DREL8,0,0,8,false,0,complain_overflow_bitfield,0,"drel8",false,0x000000ff,0x000000ff,false};
reloc_howto_type howto_hunk_drel16 =
{HUNK_DREL16,0,1,16,false,0,complain_overflow_bitfield,0,"drel16",false,0x0000ffff,0x0000ffff,false};
reloc_howto_type howto_hunk_drel32 =
{HUNK_DREL32,0,2,32,false,0,complain_overflow_bitfield,0,"drel32",false,0xffffffff,0xffffffff,false};
reloc_howto_type *amiga_howto_array[2][3] =
{
{ &howto_hunk_reloc8, &howto_hunk_reloc16, &howto_hunk_reloc32 },
{ &howto_hunk_drel8, &howto_hunk_drel16, &howto_hunk_drel32 }
};
/* 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;
static const struct bfd_target *
amiga_object_p (abfd)
bfd *abfd;
{
char buf[8];
unsigned int x;
struct stat stat_buffer;
/* An Amiga object file must be at least 8 bytes long. */
if (bfd_read ((PTR) buf, 1, 8, abfd) != 8)
{
bfd_set_error(bfd_error_wrong_format);
return 0;
}
/* Does it look like an Amiga object file? */
x = GL(buf);
if ((x != HUNK_UNIT) && (x != HUNK_HEADER))
{
/* Not an Amiga file. */
bfd_set_error(bfd_error_wrong_format);
return 0;
}
/* So far it seems to be an Amiga file. Now slurp it
in and examine it closer. */
stat_buffer.st_size=0;
if ((-1 == fstat (fileno ((FILE *) abfd->iostream), &stat_buffer))||(stat_buffer.st_size%4!=0))
{ /* Error during system call or file length is not multiple of longword size */
bfd_set_error((stat_buffer.st_size%4==0)?bfd_error_system_call:bfd_error_wrong_format);
return 0;
}
/* Can't fail and return (but must be declared boolean to suit
other bfd requirements). */
(void) amiga_mkobject (abfd);
AMIGA_DATA(abfd)->IsLoadFile = (x == HUNK_HEADER);
AMIGA_DATA(abfd)->first_byte = (unsigned long *) bfd_alloc (abfd, stat_buffer.st_size);
bfd_seek (abfd, 0, SEEK_SET);
if (bfd_read (AMIGA_DATA(abfd)->first_byte, 1, stat_buffer.st_size, abfd)!=stat_buffer.st_size)
{
/* Error, reading file */
return (const struct bfd_target *)0;
}
AMIGA_DATA(abfd)->file_pointer = AMIGA_DATA(abfd)->first_byte;
AMIGA_DATA(abfd)->file_end = (unsigned long *)((unsigned char *)AMIGA_DATA(abfd)->first_byte + stat_buffer.st_size);
if (!amiga_digest_file (abfd))
{
/* Something went wrong. */
return (const struct bfd_target *) 0;
}
/* Set default architecture to m68k:68000. */
/* So we can link on 68000 AMIGAs..... */
abfd->arch_info = bfd_scan_arch ("m68k:68000");
return (abfd->xvec);
}
/* Skip over the hunk length longword + the number of longwords given there. */
#define next_hunk(abfd) \
{ AMIGA_DATA(abfd)->file_pointer += 1 + GL(AMIGA_DATA(abfd)->file_pointer); }
static asection *
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 asection *last_reference;
asection *p;
switch(hunk_number)
{
case -1:
return bfd_abs_section_ptr;
break;
case -2:
return bfd_und_section_ptr;
break;
case -3:
return bfd_com_section_ptr;
break;
default:
if (last_reference)
if (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;
return p;
}
BFD_FAIL();
return (asection *) 0;
}
return NULL;
}
static boolean
amiga_add_reloc (abfd, section, offset, symbol, howto, target_hunk)
bfd *abfd;
asection *section;
bfd_size_type offset;
amiga_symbol_type * symbol;
reloc_howto_type *howto;
long target_hunk;
{
amiga_reloc_type *reloc;
reloc = (amiga_reloc_type *) bfd_zalloc (abfd, sizeof (amiga_reloc_type));
reloc->next = 0;
if (!reloc)
{
bfd_set_error(bfd_error_no_memory);
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 = (struct reloc_cache_entry *) reloc;
amiga_per_section(section)->reloc_tail = reloc;
amiga_per_section(section)->reloc_tail->next = NULL;
reloc->relent.address = offset;
reloc->relent.addend = 0;
reloc->relent.howto = howto;
if (symbol==NULL) /* relative to section */
reloc->symbol=(amiga_symbol_type *)(amiga_get_section_by_hunk_number(abfd,target_hunk)->symbol);
else
reloc->symbol = symbol;
reloc->relent.sym_ptr_ptr=(asymbol **)(&(reloc->symbol));
reloc->target_hunk = target_hunk;
return true;
}
/* BFD doesn't currently allow multiple sections with the same
name, so we try a little harder to get a unique name. */
asection *
amiga_make_unique_section (abfd, name)
bfd *abfd;
CONST char *name;
{
asection *section;
section = bfd_make_section (abfd, name);
if (!section)
{
int i = 1;
char *new_name;
new_name = bfd_alloc (abfd, strlen(name) + 3);
/* 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);
}
if (!section)
{
/* Complain about the given name. */
bfd_set_error(bfd_error_bad_value);
return 0;
}
}
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_DEBUG ? "HUNK_DEBUG" :\
(x) == HUNK_OVERLAY ? "HUNK_OVERLAY" :\
(x) == HUNK_BREAK ? "HUNK_BREAK" :\
(x) == HUNK_HEADER ? "HUNK_HEADER" :\
(x) == HUNK_CODE ? "HUNK_CODE" :\
(x) == HUNK_DATA ? "HUNK_DATA" :\
(x) == HUNK_BSS ? "HUNK_BSS" :\
(x) == HUNK_RELOC8 ? "HUNK_RELOC8" :\
(x) == HUNK_RELOC16 ? "HUNK_RELOC16" :\
(x) == HUNK_RELOC32 ? "HUNK_RELOC32" :\
(x) == HUNK_DREL8 ? "HUNK_DREL8" :\
(x) == HUNK_DREL16 ? "HUNK_DREL16" :\
(x) == HUNK_DREL32 ? "HUNK_DREL32" :\
(x) == HUNK_SYMBOL ? "HUNK_SYMBOL" :\
(x) == HUNK_EXT ? "HUNK_EXT" :\
(x) == HUNK_END ? "HUNK_END" :\
(x) == HUNK_LIB ? "HUNK_LIB" :\
(x) == HUNK_INDEX ? "HUNK_INDEX" :\
"*unknown*",(x))
#define DPRINTHUNKEND fprintf(stderr,"...done\n")
#else
#define DPRINTHUNK(x)
#define DPRINTHUNKEND
#endif
static boolean amiga_read_unit(bfd *abfd);
static boolean amiga_read_load(bfd *abfd);
static boolean amiga_handle_cdb_hunk(bfd *abfd, int ht,int hn,int ha,int hs);
static boolean amiga_handle_rest(bfd *abfd,asection *cs,boolean isload);
static boolean
amiga_digest_file (abfd)
bfd *abfd;
{
amiga_data_type *amiga_data = AMIGA_DATA(abfd);
int hunk_type;
hunk_type = HUNK_VALUE(GL(amiga_data->file_pointer++));
switch (hunk_type)
{
case HUNK_UNIT:
/* Read in the unit */
if (!amiga_read_unit(abfd)) /* Error */
return(false);
break;
case HUNK_HEADER:
/* This is a load file, well it should not be used with linking,
but it is possible to do so, so always allow it. */
/* Read in the load file */
if (!amiga_read_load(abfd)) /* Error */
{
return(false);
}
break;
} /* of switch hunk_type */
/* If there is any trailing garbage, i.e. we are not at EOF, then
complain and reject the file... */
if (amiga_data->file_pointer!=amiga_data->file_end) /* ooops */
{
bfd_set_error(bfd_error_wrong_format);
return(false);
}
/* Success, all went well... */
return(true);
}/* of amiga_digest_file */
/* If we read over the end of file, error */
#define TOO_LARGE_P if (amiga_data->file_pointer>=amiga_data->file_end)\
{DPRINT(10,("Overflow of file pointer\n"));bfd_set_error(bfd_error_wrong_format);return false;}
/* Read in Unit file */
/* file pointer is located after the HUNK_UNIT LW */
static boolean amiga_read_unit(bfd *abfd)
{
amiga_data_type *amiga_data = AMIGA_DATA(abfd);
int hunk_type;
int hunk_number=0;
int hunk_attribute=0;
/* The unit name, if given, has no meaning to us,
since we are not in an archive.
We could set the name of abfd to the name, but that
may cause confusion...
So just ignore the unit name
ST 121194 */
amiga_data->file_pointer+=GL(amiga_data->file_pointer)+1;
TOO_LARGE_P;
while (true)
{
/* Now there may be CODE, DATA, BSS, SYMBOL, DEBUG, RELOC Hunks */
hunk_type=HUNK_VALUE(GL(amiga_data->file_pointer)); /* Type of next hunk */
hunk_attribute=HUNK_ATTRIBUTE(GL(amiga_data->file_pointer++));
hunk_attribute=(hunk_attribute==HUNK_ATTR_CHIP)?
MEMF_CHIP:(hunk_attribute==HUNK_ATTR_FAST)?MEMF_FAST:0;
switch(hunk_type)
{
case HUNK_DEBUG:
/* We ignore debug hunks in UNITS, for now, because gnu's debug hunks
are only added by the linker to LOAD files.....
And anyhow, a.out format can keep much more information for units...
*/
amiga_data->file_pointer+=1+GL(amiga_data->file_pointer);
TOO_LARGE_P;
break;
case HUNK_NAME:
case HUNK_CODE:
case HUNK_DATA:
case HUNK_BSS:
/* 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++,hunk_attribute,-1))
return(false);
break;
default:
/* Something very nasty happened:
Illegal Hunk occured....
*/
bfd_set_error(bfd_error_wrong_format);
return(false);
break;
}/* Of switch hunk_type */
/* Last HUNK ?*/
if (amiga_data->file_pointer==amiga_data->file_end)
return true;
TOO_LARGE_P; /* Sanity check */
/* Next hunk */
}/* Of while */
}/* Of amiga_read_unit */
#define MAX_HUNKS 200 /* Max # of hunks. we can read in.. */
/* Read a load file */
static boolean amiga_read_load(bfd *abfd)
{
amiga_data_type *amiga_data = AMIGA_DATA(abfd);
int hunk_sizes[MAX_HUNKS]; /* If there are more hunks than this, we are in trouble...*/
int hunk_attributes[MAX_HUNKS];
int hunk_number=0;
int hunk_type;
int max_hunk_number=0;
int i,n;
TOO_LARGE_P; /* Sanity */
/* Read hunk lengths (and memory attributes...) */
/* Read in each hunk */
/* If there are resident libs: abort (obsolete feature) */
if (GL(amiga_data->file_pointer++)!=0)
{
bfd_set_error(bfd_error_wrong_format);
return(false);
}
TOO_LARGE_P;
max_hunk_number=GL(amiga_data->file_pointer++);
if (max_hunk_number > 3)
{
bfd_set_error (bfd_error_wrong_format);
return false;
}
if (max_hunk_number>MAX_HUNKS) /* Ooops... too much hunks */
{
fprintf(stderr,"File %s has too many hunks (%d), aborting\n",abfd->filename,max_hunk_number);
bfd_set_error(bfd_error_wrong_format);
return(false);
}
/* Sanity */
if ((max_hunk_number<1)||
(amiga_data->file_pointer+max_hunk_number+2>=amiga_data->file_end))
{
bfd_set_error(bfd_error_wrong_format);
return(false);
}
/* Num of root hunk must be 0 */
if (GL(amiga_data->file_pointer++)!=0)
{
bfd_set_error(bfd_error_wrong_format);
return(false);
}
/* Num of last hunk must be mhn-1 */
if (GL(amiga_data->file_pointer++)!=max_hunk_number-1)
{
bfd_set_error(bfd_error_wrong_format);
return(false);
}
/* Now, read in sizes and memory attributes */
for (i=0;i<max_hunk_number;i++)
{
n=HUNK_VALUE(GL(amiga_data->file_pointer));
hunk_sizes[i]=n<<2;
n=HUNK_ATTRIBUTE(GL(amiga_data->file_pointer++));
if (n==HUNK_ATTR_FOLLOWS) /* Attribute is in next long */
hunk_attributes[i]=GL(amiga_data->file_pointer++);
else
hunk_attributes[i]= (n==HUNK_ATTR_CHIP)?MEMF_CHIP:
(n==HUNK_ATTR_FAST)?MEMF_FAST:0;
}
TOO_LARGE_P; /* Sanity */
/* We can now read in all the hunks */
for (hunk_number=0;hunk_number<max_hunk_number;hunk_number++)
{
hunk_type=HUNK_VALUE(GL(amiga_data->file_pointer++));
/* This may be HUNK_NAME, CODE, BSS, DEBUG, DATA */
switch(hunk_type)
{
case HUNK_NAME:
case HUNK_CODE:
case HUNK_DATA:
case HUNK_BSS:
case HUNK_DEBUG:
if (
!amiga_handle_cdb_hunk(abfd,hunk_type,hunk_number,hunk_attributes[hunk_number],
hunk_sizes[hunk_number]))
{
bfd_set_error(bfd_error_wrong_format);
return(false);
}
break;
default:
/* illegal hunk */
bfd_set_error(bfd_error_wrong_format);
return(false);
break;
}/* Of switch */
}
/* dgv -- if the end is not reached at this point, there could be a
HUNK_DEBUG here */
if (amiga_data->file_pointer!=amiga_data->file_end) {
hunk_type = HUNK_VALUE (GL(amiga_data->file_pointer++));
if (hunk_type == HUNK_DEBUG) {
if (
!amiga_handle_cdb_hunk(abfd,hunk_type,0,0,0))
{
bfd_set_error(bfd_error_wrong_format);
return(false);
}
}
}
if (amiga_data->file_pointer!=amiga_data->file_end)
{
bfd_set_error(bfd_error_wrong_format);
return(false);
}
return(true);
}/* Of amiga_read_load */
/* Handle NAME, CODE, DATA, BSS, DEBUG Hunks */
static boolean
amiga_handle_cdb_hunk(bfd *abfd,
int hunk_type,
int hunk_number,
int hunk_attribute, /* MEMF_CHIP, etc. */
int hunk_size)
/* If hunk_size==-1, then we are digesting a HUNK_UNIT */
{
amiga_data_type *amiga_data = AMIGA_DATA(abfd);
char *current_name=NULL;
int len;
asection *current_section=NULL;
int load_file = (hunk_size!=-1);
if (hunk_type==HUNK_NAME) /* get name */
{
len=HUNK_VALUE(GL(amiga_data->file_pointer))<<2; /* Length */
/* DIRTY: We move the name 4 bytes towards the beginning of the file,
overwriting the length,
and end it with a '\0' */
strncpy((char *)amiga_data->file_pointer,(char *)(amiga_data->file_pointer+1),len);
*(((char *)amiga_data->file_pointer)+len)='\0';
current_name=(char *)amiga_data->file_pointer;
amiga_data->file_pointer+=1+(len>>2); /* Advance */
TOO_LARGE_P;
hunk_type=HUNK_VALUE(GL(amiga_data->file_pointer++)); /* Next hunk */
if (hunk_size==-1) /* In a unit ==> Get attribute from file */
{
hunk_attribute=HUNK_ATTRIBUTE(GL(amiga_data->file_pointer-1));
hunk_attribute=(hunk_attribute==HUNK_ATTR_CHIP)?MEMF_CHIP:
(hunk_attribute==HUNK_ATTR_FAST)?MEMF_FAST:0;
}
}
else /* Set curent name to something appropriate */
current_name=(hunk_type==HUNK_CODE)?".text":
(hunk_type==HUNK_BSS)?".bss":".data";
/* file_pointer is now at hunk_type */
switch (hunk_type)
{
case HUNK_CODE:
/* Handle code hunk */
len=HUNK_VALUE(GL(amiga_data->file_pointer++))<<2; /* Length of section */
if (len>hunk_size) /* len may be shorter than hunk_size... */
if (hunk_size==-1)
hunk_size=len;
else
{
bfd_set_error(bfd_error_wrong_format);
return false;
}
/* Make new section */
current_section=amiga_make_unique_section(abfd,current_name);
if (!current_section)
return false;
current_section->filepos=(char *)(amiga_data->file_pointer)-(char *)amiga_data->first_byte;
current_section->_raw_size=hunk_size;
current_section->_cooked_size=hunk_size;
current_section->target_index=hunk_number;
bfd_set_section_flags(abfd,current_section,
SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS);
amiga_per_section(current_section)->real_length=len; /* real size */
amiga_per_section(current_section)->attribute=hunk_attribute;
amiga_data->file_pointer+=(len>>2); /* next hunk */
if (!amiga_handle_rest(abfd,current_section,load_file))
return false;
break;
case HUNK_DATA:
/* Handle data hunk */
len=HUNK_VALUE(GL(amiga_data->file_pointer++))<<2; /* Length of section */
if (len>hunk_size) /* len may be shorter than hunk_size... */
if (hunk_size==-1)
hunk_size=len;
else
{
bfd_set_error(bfd_error_wrong_format);
return false;
}
current_section=amiga_make_unique_section(abfd,current_name);
if (!current_section)
return false;
current_section->filepos=(char *)amiga_data->file_pointer-(char *)amiga_data->first_byte;
current_section->_raw_size=hunk_size;
current_section->_cooked_size=hunk_size;
current_section->target_index=hunk_number;
bfd_set_section_flags(abfd,current_section,
SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS);
amiga_per_section(current_section)->real_length=len; /* real size */
amiga_per_section(current_section)->attribute=hunk_attribute;
amiga_data->file_pointer+=(len>>2); /* next hunk */
if (!amiga_handle_rest(abfd,current_section,load_file))
return false;
break;
case HUNK_BSS:
/* Handle bss hunk */
len=HUNK_VALUE(GL(amiga_data->file_pointer++))<<2; /* Length of section */
if (len>hunk_size) /* len may be shorter than hunk_size... */
if (hunk_size==-1)
hunk_size=len;
else
{
bfd_set_error(bfd_error_wrong_format);
return false;
}
current_section=amiga_make_unique_section(abfd,current_name);
if (!current_section)
return false;
current_section->filepos=(file_ptr)-1;
current_section->_raw_size=hunk_size;
current_section->_cooked_size=hunk_size;
current_section->target_index=hunk_number;
bfd_set_section_flags(abfd,current_section, SEC_ALLOC );
amiga_per_section(current_section)->real_length=len; /* real size */
amiga_per_section(current_section)->attribute=hunk_attribute;
if (!amiga_handle_rest(abfd,current_section,load_file))
return false;
break;
case HUNK_DEBUG:
if (hunk_size==-1) /* We are digesting a unit ==> ignore debug hunks */
{
amiga_data->file_pointer+=1+GL(amiga_data->file_pointer);
return(true);
}
/* We are digesting a load file, so check for gnu debug hunk, else ignore it */
/* format of gnu debug hunk is:
HUNK_DEBUG
N
0413.L Magic number
symtabsize
strtabsize
symtabdata [length=symtabsize]
strtabdata [length=strtabsize]
[pad bytes]
*/
if (GL(amiga_data->file_pointer+1)==0413) /* GNU DEBUG HUNK */
{
/*FIXME: we should add the symbols in the debug hunk to symtab... */
amiga_data->symtab_size=GL(amiga_data->file_pointer+2);
amiga_data->stringtab_size=GL(amiga_data->file_pointer+3);
adata(abfd).sym_filepos=
(file_ptr)((char *)(amiga_data->file_pointer +4)-(char *)amiga_data->first_byte);
adata(abfd).str_filepos=adata(abfd).sym_filepos+amiga_data->symtab_size;
amiga_data->file_pointer+=1+GL(amiga_data->file_pointer);
}
else /* NOT GNU DEBUG HUNK... */
{
/* ignore it */
amiga_data->file_pointer+=1+GL(amiga_data->file_pointer);
}
/* there has to be an HUNK_END here... */
if (GL(amiga_data->file_pointer++)!=HUNK_END)
{
bfd_set_error(bfd_error_wrong_format);
return(false);
}
break;
default:
bfd_set_error(bfd_error_wrong_format);
return false;
break;
}/* of switch hunk_type */
return(true);
}/* Of amiga_handle_cdb_hunk */
/* Handle rest of a hunk
I.e.: Relocs, EXT, SYMBOLS... */
static boolean amiga_handle_rest(bfd *abfd, asection *current_section, boolean isload)
{
amiga_data_type *amiga_data = AMIGA_DATA(abfd);
int hunk_type;
int type;
int len;
int n;
unsigned long **p;
struct amiga_raw_symbol *sp=NULL;
while (1)/* loop */
{
hunk_type=GL(amiga_data->file_pointer++);
switch (hunk_type)
{
case HUNK_END: /* Reached end */
return(true); /* Done */
break;
case HUNK_DEBUG: /* skip debug info -- dgv */
amiga_data->file_pointer += 1+GL (amiga_data->file_pointer);
break;
/* Relocs.... */
case HUNK_RELOC8:
case HUNK_RELOC16:
case HUNK_RELOC32:
case HUNK_DREL8:
case HUNK_DREL16:
case HUNK_DREL32:
/* We leave them alone, but attach them to the section,
so we can read them in later.....*/
/* But we already set the flags HAS_RELOC, SEC_RELOC */
/* We also maintain the reloc count */
/* This is simply done by adding all addresses of relocs to an array in the section */
p=amiga_per_section(current_section)->raw_relocs;
if (amiga_per_section(current_section)->max_raw_relocs<=
amiga_per_section(current_section)->num_raw_relocs) /* allocate more space */
{
if (p==NULL)
{
p=(unsigned long **)malloc(sizeof(unsigned long *)*10); /* initial */
amiga_per_section(current_section)->max_raw_relocs=10;
amiga_per_section(current_section)->num_raw_relocs=0;
}
else /* More space */
{
p=(unsigned long **)realloc((void *)p,
sizeof(unsigned long *)*(amiga_per_section(current_section)->max_raw_relocs+30));
amiga_per_section(current_section)->max_raw_relocs+=30;
}
if (p==NULL)
{
bfd_set_error(bfd_error_no_memory);
return(false);
}
amiga_per_section(current_section)->raw_relocs=p;
}
p[amiga_per_section(current_section)->num_raw_relocs++]=amiga_data->file_pointer-1;
abfd->flags|=HAS_RELOC;
current_section->flags|=SEC_RELOC;
/* Advance file_pointer */
while ((n=GL(amiga_data->file_pointer++)))
{
amiga_data->file_pointer+=1+n;
current_section->reloc_count+=n;
TOO_LARGE_P; /* Sanity check */
}
break;
/* Symbol definition */
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)
{
int foo;
while ((foo=GL(amiga_data->file_pointer))!=0)
amiga_data->file_pointer+=foo+2;
amiga_data->file_pointer++;
break;
}
/* We add these, by falling through... */
case HUNK_EXT:
/* We leave these alone, until they are requested by the user */
sp=amiga_per_section(current_section)->last;
if (sp==NULL) /* First one added */
{
amiga_per_section(current_section)->last=amiga_per_section(current_section)->first=
(struct amiga_raw_symbol *)(amiga_data->file_pointer-1);
*(amiga_data->file_pointer-1)=0;
}
else
{
sp->next=(struct amiga_raw_symbol *)(amiga_data->file_pointer-1);
*(amiga_data->file_pointer-1)=0;
amiga_per_section(current_section)->last=sp->next;
}
/* skip these */
while ((n=GL(amiga_data->file_pointer)))
{
amiga_data->file_pointer++;
type=(n>>24)&0xff;
len=n&0xffffff;
amiga_data->file_pointer+=len; /* skip name */
switch(type)
{
case EXT_SYMB: /* Symbol hunks are relative to hunk start... */
case EXT_DEF: /* def relative to hunk */
case EXT_ABS: /* def absolute */
abfd->flags|=HAS_SYMS; /* We have symbols */
abfd->symcount++;
amiga_data->file_pointer++;
break;
case EXT_REF8: /* 8 bit ref */
case EXT_REF16: /* 16 bit ref */
case EXT_REF32: /* 32 bit ref */
case EXT_DEXT8: /* 8 bit base relative ref */
case EXT_DEXT16: /* 16 bit " "*/
case EXT_DEXT32: /* 32 bit " " */
abfd->flags|=HAS_SYMS;
n=GL(amiga_data->file_pointer);
if (n)
{
abfd->flags|=HAS_RELOC;
current_section->flags|=SEC_RELOC;
}
current_section->reloc_count+=n;
amiga_data->file_pointer+=1+n;
break;
case EXT_COMMON: /* Common ref/def */
abfd->flags|=HAS_SYMS;
abfd->symcount++;
n=GL(amiga_data->file_pointer+1);
if (n)
{
abfd->flags|=HAS_RELOC;
current_section->flags|=SEC_RELOC;
}
current_section->reloc_count+=n;
amiga_data->file_pointer+=2+n;
break;
default: /* error */
bfd_set_error(bfd_error_wrong_format);
return false;
break;
}/* of switch type */
}/* Of while */
amiga_data->file_pointer++;
break;
default: /* error */
bfd_set_error(bfd_error_wrong_format);
return(false);
break;
}/* Of switch */
}/* of while */
return(true);
}/* of amiga_handle_rest*/
static boolean
amiga_mkobject (abfd)
bfd *abfd;
{
struct amiga_data_struct *rawptr;
rawptr = (struct amiga_data_struct *) bfd_zalloc (abfd, sizeof (struct amiga_data_struct));
abfd->tdata.amiga_data = rawptr;
return true;
}
static long determine_datadata_relocs(bfd *, asection *);
static boolean amiga_write_section_contents(bfd *, asection *, asection *, long, long);
static boolean amiga_write_symbols(bfd *, asection *);
/* used with base relative linking */
extern int amiga_base_relative;
/* used with -resident linking */
extern int amiga_resident;
/* write at most 10 long words (possibly swapped out) to the output file */
static boolean
write_longs (unsigned long *in, long elt_size, long nb, bfd *abfd)
{
unsigned long out [10];
int i;
if (nb > 10)
{
fprintf(stderr, "ERROR: writing more than 10 longs using write_longs()!\n");
exit(2);
}
for (i=0; i<nb; i++)
out[i] = GL (in++);
return (bfd_write ((PTR)out, elt_size, nb, abfd) == elt_size*nb);
}
static long determine_datadata_relocs(bfd *abfd, asection *section)
{
long relocs = 1, i;
struct reloc_cache_entry *r;
asection *insection;
asymbol *sym_p;
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 section */
insection=sym_p->section;
/* Is reloc relative to a special section ? */
if ((insection==bfd_abs_section_ptr)||(insection==bfd_com_section_ptr)||
(insection==bfd_und_section_ptr)||(insection==bfd_ind_section_ptr))
continue; /* Nothing to do, since this translates to HUNK_EXT */
if (insection->output_section == section)
relocs++;
}
return relocs;
}
/* Write out the contents of a bfd */
static boolean
amiga_write_object_contents (abfd)
bfd *abfd;
{
struct amiga_data_struct *amiga_data=AMIGA_DATA(abfd);
sec_ptr p;
unsigned long n[5];
long i;
char b[3];
long datadata_relocs, bss_size = 0;
asection *data_sec;
/* 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 */
/* Distinguish Load files and Unit files */
if (amiga_data->IsLoadFile)
{
DPRINT(5,("Writing Load file\n"));
/* Write out load file header */
n[0]=HUNK_HEADER;
n[1]=0;
n[2]=abfd->section_count;
/* If amiga_base_relative is set, we write out one hunk less */
if (amiga_base_relative)
{
n[2]=abfd->section_count-1;
BFD_ASSERT(abfd->section_count==3); /* Or we are in big trouble */
}
n[3]=0;
n[4]=n[2]-1;
if (!write_longs(n,sizeof(unsigned long),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")==0)
{
datadata_relocs = determine_datadata_relocs(abfd, p);
data_sec = p;
}
else if (strcmp(p->name,".bss")==0)
{
/* Get size for header*/
if (amiga_per_section(p)->real_length != 0)
bss_size = (amiga_per_section(p)->real_length) >> 2;
else
bss_size = (p->_raw_size) >> 2;
}
}
for (p=abfd->sections;p!=NULL;p=p->next)
{
long extra = 0;
if (amiga_base_relative && (strcmp(p->name,".bss")==0)) /* skip */
continue;
if (amiga_resident && amiga_base_relative && (strcmp(p->name,".text")==0))
extra = datadata_relocs;
/* Get size for header*/
if (amiga_per_section(p)->real_length!=0)
n[0]=(amiga_per_section(p)->real_length)>>2;
else
n[0]=(p->_raw_size)>>2;
n[0] += extra;
i=amiga_per_section(p)->attribute;
switch (i)
{
case MEMF_CHIP:
n[0]|=0x40000000;
i=1;
break;
case MEMF_FAST:
n[0]|=0x80000000;
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,sizeof(unsigned long),i,abfd))
return false;
}/* Of for */
}
else
{/* Unit , no base-relative linking here.... */
/* Write out unit header */
DPRINT(5,("Writing Unit\n"));
n[0]=HUNK_UNIT;
if (!write_longs (n,sizeof(unsigned long),1,abfd))
return false;
i=(strlen(abfd->filename)+3)>>2; /* longword size of name */
if (!write_longs(&i,sizeof(unsigned long),1,abfd));
return false;
if (bfd_write((PTR)(abfd->filename),sizeof(char),strlen(abfd->filename),abfd)!=strlen(abfd->filename))
return false;
/* Pad to lw boundary */
b[0]=b[1]=b[2]='\0';
i=(i<<2)-strlen(abfd->filename);
if (i)
if (bfd_write((PTR)(b),sizeof(char),i,abfd)!=i)
return false;
/* That's all... for units :-)*/
}
/* Write out every section */
for (p=abfd->sections;p!=NULL;p=p->next)
{
if (amiga_resident && amiga_base_relative && (strcmp(p->name,".text")==0))
{
if (!amiga_write_section_contents(abfd,p,data_sec,datadata_relocs,0)) /* Write out section data + relocs */
return false;
}
else if (amiga_base_relative && (strcmp(p->name,".data")==0))
{
if (!amiga_write_section_contents(abfd,p,0,0,bss_size)) /* Write out section data + relocs */
return false;
}
else
{
if (!amiga_write_section_contents(abfd,p,0,0,0)) /* Write out section data + relocs */
return false;
}
if (!amiga_write_symbols(abfd,p)) /* Write out symbols, incl HUNK_END */
return false;
}/* of for sections */
/* Write out debug hunk, if requested */
if (amiga_data->IsLoadFile && write_debug_hunk)
{
extern boolean
translate_to_native_sym_flags(bfd *, asymbol *, struct external_nlist *);
/* We have to convert all the symbols in abfd to a.out style.... */
struct external_nlist data;
int str_size, offset = 4;
int symbols = 0;
asymbol *sym;
asection *s;
if (abfd->symcount)
{
/* 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")==0)
{
i|=1;
adata(abfd).textsec=s;
}
else if (strcmp(s->name,".data")==0)
{
i|=2;
adata(abfd).datasec=s;
}
else if (strcmp(s->name,".bss")==0)
{
i|=4;
adata(abfd).bsssec=s;
}
if (i!=7) /* One section missing... */
{
fprintf(stderr,"Missing section, hunk not written\n");
return true;
}
str_size=4; /* the first 4 bytes will be replaced with the length */
for (i = 0; i < abfd->symcount; i++) /* Translate every symbol */
{
sym = abfd->outsymbols[i];
/* NULL entries have been written already.... */
if (sym != NULL && sym->section)
{
str_size += strlen(sym->name) + 1;
symbols++;
}
}
/* Write out HUNK_DEBUG, size, 0413.... */
n[0] = HUNK_DEBUG;
n[1] = 3 + ((symbols * sizeof(struct internal_nlist) + str_size + 3) >> 2);
n[2] = 0413L; /* Magic number */
n[3] = symbols * sizeof(struct internal_nlist);
n[4] = str_size;
if (!write_longs ((PTR)(n),sizeof(unsigned long),5,abfd))
return false;
/* Write out symbols */
for (i = 0; i < abfd->symcount; i++) /* Translate every symbol */
{
sym = abfd->outsymbols[i];
/* NULL entries have been written already.... */
if (sym != NULL && sym->section)
{
if (bfd_asymbol_flavour(sym) == bfd_target_aout_flavour)
{
aout_symbol_type *t = ((aout_symbol_type *)(&(sym)->the_bfd));
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);
}
else
{
bfd_h_put_16(abfd, 0, data.e_desc);
bfd_h_put_8(abfd, 0, data.e_other);
bfd_h_put_8(abfd, 0, data.e_type);
}
if (!translate_to_native_sym_flags(abfd,sym,&data))
{
fprintf(stderr,"Cannot translate flags for %s, hunk not written\n",
sym->name);
/*return true;*/
}
PUT_WORD(abfd, offset, &(data.e_strx[0])); /* Store index */
offset += strlen(sym->name) + 1;
if (bfd_write ((unsigned long *)&data,sizeof(long),3,abfd) != sizeof(long)*3)
return false;
}
}
/* Write out strings */
if (!write_longs ((unsigned long *)&str_size, sizeof(long),1,abfd))
return false;
for (i = 0; i < abfd->symcount; i++) /* Translate every symbol */
{
sym = abfd->outsymbols[i];
/* NULL entries have been written already.... */
if (sym != NULL && sym->section)
{
int len = strlen(sym->name) + 1;
/* Write string tab */
if (bfd_write((PTR)(sym->name),sizeof(char),len,abfd)!=len)
return false;
}
}
i = ((str_size + 3) & (~3)) - str_size;
str_size = 0;
/* Write padding */
if (i && bfd_write((PTR)(&str_size),sizeof(char),i,abfd)!=i)
return false;
/* dgv -- write a HUNK_END here to finish the loadfile, or amigaos
will refuse to load it */
n[0]=HUNK_END;
if (!write_longs (n,sizeof(long),1,abfd))
return false;
}/* Of if abfd->symcount */
}/* Of write out debug hunk */
return true;
}
static int determine_size(int type)
{
if (type >= 3)
type -= 3;
return 2 - type;
}
static int determine_type(struct reloc_cache_entry *r)
{
switch (r->howto->type) /* FIXME: Is this sufficient to distinguish them ?*/
{
/* AMIGA specific */
case HUNK_RELOC8:
case HUNK_RELOC16:
case HUNK_RELOC32:
case HUNK_DREL8:
case HUNK_DREL16:
case HUNK_DREL32:
if (r->howto->type >= HUNK_DREL32)
return 3 + r->howto->type - HUNK_DREL32;
return r->howto->type - HUNK_RELOC32;
/* Now, these may occur, if a.out was used as input */
case 0: /* 8 bit ref */
return 2;
case 1: /* 16 bit relative */
return 1;
case 2: /* 32 bit relative */
return 0;
case 9: /* 16 bit base rel */
return 4;
case 10: /* 32 bit baserel */
return 3;
/* FIXME: There are other (pc relative) displacements left */
default: /* Error, can't represent this */
bfd_set_error(bfd_error_nonrepresentable_section);
return -1;
}/* Of switch */
}
#define MAX_RELOC_OUT 3
/* Write out section contents, including relocs */
static boolean
amiga_write_section_contents(bfd *abfd, asection *section, asection *data_sec,
long datadata_relocs, long bss_size)
{
unsigned long n[2];
int i, j, type, size;
unsigned int k;
char b[3];
struct reloc_cache_entry *r;
asection *osection, *sec, *insection;
asymbol *sym_p;
int reloc_count = 0;
unsigned long reloc_types[6]= { HUNK_RELOC32, HUNK_RELOC16, HUNK_RELOC8,
HUNK_DREL32, HUNK_DREL16, HUNK_DREL8 };
int max_hunk = -1;
char *c_p;
unsigned char *values;
/* 6 reloc types * 3 hunk types */
int reloc_counts[6][3] = { 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0 };
DPRINT(5, ("Entered Write-section-conts\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 && amiga_base_relative &&
(strcmp(section->name, ".bss") == 0))
return true; /* Nothing to do */
if (!AMIGA_DATA(abfd)->IsLoadFile)
{
/* WRITE out HUNK_NAME + section name */
n[0] = HUNK_NAME;
j = strlen(section->name);
i = (j + 3) >> 2; /* LW len of name */
n[1] = i;
if (!write_longs ((PTR)(n), sizeof(unsigned long), 2, abfd))
return false;
if (bfd_write((PTR)(section->name), sizeof(char), j, abfd) != j)
return false;
b[0] = b[1] = b[2] = '\0';
if ((i << 2) - j != 0) /* Pad */
if (bfd_write((PTR)(b), sizeof(char), (i<<2) - j, abfd) != ((i<<2) - j))
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) /* 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 attribute for section */
switch (amiga_per_section(section)->attribute)
{
case MEMF_CHIP:
n[0] |= HUNKF_CHIP;
break;
case MEMF_FAST:
n[0] |= HUNKF_FAST;
break;
case 0:
break;
default: /* error , can't represent this */
bfd_set_error(bfd_error_nonrepresentable_section);
return(false);
break;
}/* Of switch */
DPRINT(10,("Section attribute is %lx\n",n[0]));
/* Get real size in n[1], this may be shorter than the size in the header */
n[1] = section->_cooked_size >> 2;
if (n[1] == 0)
n[1] = section->_raw_size >> 2;
n[1] += datadata_relocs + bss_size;
if (!write_longs ((PTR)(n), sizeof(unsigned long), 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"));
/* dgv -- if the section is empty, we're done as well */
if (n[1] == 0)
return true;
/* 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 */
BFD_ASSERT((section->flags & SEC_IN_MEMORY) != 0);
DPRINT(5,("Section has %d relocs\n", section->reloc_count));
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 section */
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 ((insection == bfd_abs_section_ptr) ||
(insection == bfd_com_section_ptr) ||
(insection == bfd_und_section_ptr) ||
(insection == bfd_ind_section_ptr))
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;
osection = insection->output_section; /* target section */
/* Determine which hunk to write, and index of target */
for (j = 0, sec = abfd->sections; sec != NULL; sec = sec->next, j++)
{
if (sec == osection)
break;
}
BFD_ASSERT(sec != NULL);
if (j > max_hunk) /* Maximum number used */
max_hunk = j;
BFD_ASSERT(max_hunk < 3);
type = determine_type(r);
if (type == -1)
return false;
size = determine_size(type);
if (type < MAX_RELOC_OUT)
reloc_counts[type][j]++;
c_p = ((char *)(section->contents)) + r->address;
DPRINT(5,("reloc address=%lx,addend=%lx\n",r->address,r->addend));
/* There is no error checking with these.. */
values = (unsigned char *)c_p;
switch (size)
{
case 0: /* adjust byte */
j = (int)(*c_p) + r->addend;
*c_p = (signed char)j;
break;
case 1: /* Adjust word */
k = values[1] | (values[0] << 8);
j = (int)k + r->addend;
values[0] = (j & 0xff00) >> 8;
values[1] = j & 0xff;
break;
case 2: /* adjust long */
k = values[3] | (values[2] << 8) | (values[1] << 16) | (values[0] << 24);
j = (int)k + r->addend;
values[3] = j & 0xff;
values[2] = (j & 0xff00) >> 8;
values[1] = (j & 0xff0000) >> 16;
values[0] = ((unsigned int)j & 0xff000000) >> 24;
break;
} /* of switch */
r->addend = 0;
DPRINT(5,("Did adjusting\n"));
if (type < MAX_RELOC_OUT)
reloc_count++;
else
section->orelocation[i] = NULL;
} /* of for i */
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 (bfd_write((PTR)(section->contents), sizeof(char), section->_raw_size,
abfd) != section->_raw_size)
return false;
i = 0;
/* write bss data in the data hunk if needed */
while (bss_size--)
if (!write_longs((PTR)&i, sizeof(long), 1, abfd))
return false;
if (datadata_relocs)
{
datadata_relocs--;
if (!write_longs(&datadata_relocs, sizeof(long), 1, abfd))
return false;
for (i = 0; i < data_sec->reloc_count; i++)
{
r = data_sec->orelocation[i];
if (r == NULL)
continue;
sym_p = *(r->sym_ptr_ptr); /* The symbol for this section */
insection = sym_p->section;
/* Is reloc relative to a special section ? */
if ((insection == bfd_abs_section_ptr) ||
(insection == bfd_com_section_ptr) ||
(insection == bfd_und_section_ptr) ||
(insection == bfd_ind_section_ptr))
continue; /* Nothing to do, since this translates to HUNK_EXT */
if (insection->output_section == data_sec)
{
int offset = r->address;
if (determine_type(r) == 0)
if (!write_longs((PTR)&offset, sizeof(long), 1, abfd))
return false;
}
}
}
DPRINT(10,("Wrote contents, writing relocs now\n"));
/* We gathered all the relocs, now compactify them */
if (!reloc_count) /* No reloc found ==> We are done */
return true;
/* There are some relocs.... */
/* Sample every reloc type */
while (reloc_count) {
for (i = 0; i < 3; i++)
/* are there relocs of this type? */
if (reloc_counts[i][0] || reloc_counts[i][1] || reloc_counts[i][2]) {
if (!write_longs(&reloc_types[i], sizeof(long), 1, abfd))
return false;
for (j = 0; j <= max_hunk; j++) {
while (reloc_counts[i][j] > 0) {
int relocs = reloc_counts[i][j];
if (relocs > 0xffff)
relocs = 0xffff;
reloc_counts[i][j] -= relocs;
n[0] = relocs;
n[1] = j;
if (!write_longs(n, sizeof(long), 2, abfd))
return false;
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 section */
insection = sym_p->section;
/* Is reloc relative to a special section ? */
if ((insection == bfd_abs_section_ptr) ||
(insection == bfd_com_section_ptr) ||
(insection == bfd_und_section_ptr) ||
(insection == bfd_ind_section_ptr))
continue; /* Nothing to do, since this translates to HUNK_EXT */
osection = insection->output_section; /* target section */
/* Determine which hunk to write, and index of target */
for (jj = 0, sec = abfd->sections; sec != NULL; sec = sec->next, jj++) {
if (sec == osection)
break;
}
if (jj == j && i == determine_type(r)) {
section->orelocation[k] = NULL;
if (!write_longs((PTR)&r->address, sizeof(long), 1, abfd))
return false;
if (--relocs == 0)
break;
}
}
}
}
}
}
if (!write_longs((PTR)&reloc_count, sizeof(long), 1, abfd))
return false;
DPRINT(5,("Leaving write_section...\n"));
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 boolean amiga_write_symbols(bfd *abfd, asection *section)
{
int i,j;
struct reloc_cache_entry *r;
asection *osection;
asymbol *sym_p;
char b[3]="\0\0\0";
unsigned long n[3];
int symbol_count;
unsigned long symbol_header;
unsigned long type, tmp;
int len;
/* If base rel linking and section is .bss ==> exit */
if (amiga_base_relative && (strcmp(section->name,".bss")==0))
return true;
if (section->reloc_count==0 && abfd->symcount==0)
{/* Write HUNK_END */
alldone:
DPRINT(5,("Leaving write_symbols\n"));
n[0]=HUNK_END;
return write_longs ((PTR)n,sizeof(unsigned long),1,abfd);
}
symbol_count=0;
symbol_header=HUNK_EXT;
/* If this is Loadfile, then do not write HUNK_EXT, but rather HUNK_SYMB*/
/* 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 */
/* Determine the type of HUNK_EXT to issue and build a single HUNK_EXT subtype */
/*FIXME: We write out many HUNK_EXT's entries for references to the same symbol.. */
for (i=0;i<section->reloc_count;i++)
{
r=section->orelocation[i];
if (r==NULL) /* Empty entry */
continue;
sym_p=*(r->sym_ptr_ptr); /* The symbol for this section */
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));
if (osection!=bfd_com_section_ptr) /* Not common symbol */
{
DPRINT(5,("Non common ref\n"));
/* Add a reference to this HUNK */
if ((symbol_count++)==0) /* First write out the HUNK_EXT */
{
tmp=HUNK_EXT;
if (!write_longs(&tmp,sizeof(long),1,abfd))
return false;
}
/* Determine type of ref */
switch(r->howto->type) /* FIXME: Is this sufficient to distinguish them ?*/
{
/* AMIGA specific */
case 0:
case HUNK_RELOC8:
type=EXT_REF8;
break;
case 1:
case HUNK_RELOC16:
type=EXT_REF16;
break;
case 2:
case HUNK_RELOC32:
type=EXT_REF32;
break;
case HUNK_DREL8:
type=EXT_DEXT8;
break;
case 9:
case HUNK_DREL16:
type=EXT_DEXT16;
break;
case 10:
case HUNK_DREL32:
type=EXT_DEXT32;
break;
/* FIXME: There are other (pc relative) displacements left */
default: /* Error, can't represent this */
bfd_set_error(bfd_error_nonrepresentable_section);
return false;
break;
}/* Of switch */
DPRINT(5,("Type is %x\n",type));
type<<=24;
type&=0xff000000;
j=strlen(sym_p->name);
len=(j+3)>>2; /* LW Len of name */
type|=(len & 0xffffff);
if (!write_longs (&type,sizeof(unsigned long),1,abfd))
return false;
if (bfd_write((PTR)(sym_p->name),sizeof(char),j,abfd)!=j)
return false;
if ((len<<2)-j!=0) /* Pad name */
if (bfd_write((PTR)(b),sizeof(char),(len<<2)-j,abfd)!=((len<<2)-j))
return false;
n[0]=1; /* 1 ref at address... */
n[1]=r->address;
if (!write_longs (n,sizeof(unsigned long),2,abfd))
return false;
continue; /* Next relocation */
}/* Of is ref to undefined or abs symbol */
if (osection==bfd_com_section_ptr) /* ref to common symbol */
{
DPRINT(5,("Common ref\n"));
/* If the reference is NOT 32 bit wide absolute , then issue warning */
if ((r->howto->type!=2)&&(r->howto->type!=HUNK_RELOC32))
fprintf(stderr,"Warning: Non 32 bit wide reference to common symbol %s\n",
sym_p->name);
if ((symbol_count++)==0) /* First write out the HUNK_EXT */
{
tmp=HUNK_EXT;
if (!write_longs (&tmp,sizeof(long),1,abfd))
return false;
}
type=(EXT_COMMON<<24)&0xff000000;
j=strlen(sym_p->name);
len=(j+3)>>2;
type|=(len&0xffffff);
if (!write_longs (&type,sizeof(unsigned long),1,abfd))
return false;
if (bfd_write((PTR)(sym_p->name),sizeof(char),j,abfd)!=j)
return false;
if ((len<<2)-j!=0) /* Pad name */
if (bfd_write((PTR)(b),sizeof(char),(len<<2)-j,abfd)!=((len<<2)-j))
return false;
n[0]=sym_p->value; /* Size of common block */
n[1]=1;
n[2]=r->address;
if (!write_longs ((PTR)(n),sizeof(unsigned long),3,abfd))
return false;
continue;
}/* Of is common section */
DPRINT(10,("Failing...\n"));
BFD_FAIL();
}/* 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 COMMON symbols
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"));
symbol_header=(AMIGA_DATA(abfd)->IsLoadFile)?HUNK_SYMBOL:HUNK_EXT;
for (i=0;i<abfd->symcount;i++)
{
sym_p=abfd->outsymbols[i];
osection=sym_p->section;
DPRINT(5,("%d. symbol(%s), osec=%x(%s)\n",i,sym_p->name,osection,osection->name));
if ((osection==bfd_und_section_ptr)||(osection==bfd_com_section_ptr)||
(osection==bfd_ind_section_ptr))
continue; /* Don't write these */
/* Only write abs defs, if not writing A Loadfile */
if ((osection==bfd_abs_section_ptr)&&(section->index==0)&&!AMIGA_DATA(abfd)->IsLoadFile) /* Write out abs defs */
{
DPRINT(5,("Abs symbol\n"));
if ((symbol_count++)==0) /* First write out the HUNK_EXT */
{
if (!write_longs (&symbol_header,sizeof(long),1,abfd))
return false;
}
type=(EXT_ABS<<24)&0xff000000;
j=strlen(sym_p->name);
len=(j+3)>>2;
type|=(len & 0xffffff);
if (!write_longs (&type,sizeof(unsigned long),1,abfd))
return false;
if (bfd_write((PTR)(sym_p->name),sizeof(char),j,abfd)!=j)
return false;
if ((len<<2)-j!=0) /* Pad name */
if (bfd_write((PTR)(b),sizeof(char),(len<<2)-j,abfd)!=((len<<2)-j))
return false;
n[0]=sym_p->value;
if (!write_longs (n,sizeof(unsigned long),1,abfd))
return false;
continue;
}/* Of abs def */
if (osection == NULL) /* Happens with constructor functions. FIXME */
continue;
if (osection==bfd_abs_section_ptr) /* Not first hunk. Already written */
continue;
/* 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;
/* 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,sizeof(long),1,abfd))
return false;
}
type=((symbol_header==HUNK_EXT?EXT_DEF:0)<<24)&0xff000000;
j=strlen(sym_p->name);
/* workaround for an amigaos bug: symbol names longer than 124
characters are not supported */
if (j > 124)
j = 124;
len=(j+3)>>2;
type|=(len & 0xffffff);
if (!write_longs ((PTR)(&type),sizeof(unsigned long),1,abfd))
return false;
if (bfd_write((PTR)(sym_p->name),sizeof(char),j,abfd)!=j)
return false;
if ((len<<2)-j!=0) /* Pad name */
if (bfd_write((PTR)(b),sizeof(char),(len<<2)-j,abfd)!=((len<<2)-j))
return false;
n[0]=sym_p->value+sym_p->section->output_offset;
if (!write_longs (n,sizeof(unsigned long),1,abfd))
return false;
}/* Of this section */
}/* Of for */
DPRINT(10,("Did traversing\n"));
if (symbol_count) /* terminate HUNK_EXT, HUNK_SYMBOL */
{
n[0]=0;
if (!write_longs (n,sizeof(unsigned long),1,abfd))
return false;
}
DPRINT(5,("Leaving\n"));
goto alldone; /* Write HUNK_END, return */
}
static boolean
amiga_get_section_contents (abfd, section, location, offset, count)
bfd *abfd;
sec_ptr section;
PTR location;
file_ptr offset;
bfd_size_type count;
{
long disk_size = amiga_per_section (section)->real_length;
if (offset+count > disk_size) {
/* the section's size on disk may be smaller than in memory
in this case, pad the contents */
memmove ((void *) location,
(void *) (((int) AMIGA_DATA(abfd)->first_byte)
+ (int) section->filepos
+ (int) offset),
disk_size - offset);
memset (location + disk_size - offset, 0, count-(disk_size-offset));
}
else {
memmove ((void *) location,
(void *) (((int) AMIGA_DATA(abfd)->first_byte)
+ (int) section->filepos
+ (int) offset),
count);
}
return true;
}
boolean
amiga_new_section_hook (abfd, newsect)
bfd *abfd;
asection *newsect;
{
newsect->used_by_bfd = (PTR) bfd_zalloc (abfd, sizeof (amiga_per_section_type));
newsect->alignment_power = 2;
amiga_per_section(newsect)->reloc_tail = NULL;
return true;
}
/* This reads the symbol table, by following various pointers,
set up by amiga_digest_file */
static boolean
amiga_slurp_symbol_table (abfd)
bfd *abfd;
{
/* slurp in symbols, associated with this bfd */
amiga_data_type *amiga_data=AMIGA_DATA(abfd);
asection *section;
struct amiga_raw_symbol *sp;
amiga_symbol_type *asp=NULL;
unsigned long *lp, l;
int len;
int type;
if (amiga_data->symbols)
return true; /* already read */
/* Symbols are associated with every section */
for (section=abfd->sections;section!=NULL;section=section->next)
{
for (sp=amiga_per_section(section)->first;sp!=NULL;sp=sp->next)
{
lp=&(sp->data[0]);
while ((l = GL(lp++)))
{
type = l>>24; /* type of entry */
len = l & 0xffffff; /* namelength */
switch(type)
{
case EXT_COMMON: /* Common reference/definition*/
case EXT_ABS: /* Absolute */
case EXT_DEF: /* Relative Definition */
case EXT_SYMB: /* Same as EXT_DEF for load files */
/* Add symbol to section.... */
/* We don't have to increase symcount, this has already been done */
asp=(amiga_symbol_type *)bfd_zalloc(abfd,sizeof(amiga_symbol_type));
if (!asp) /* No mem */
{
bfd_set_error(bfd_error_no_memory);
return(false);
}
/* Add symbol to list of all symbols */
asp->next=NULL;
if (!amiga_data->symbols) /* first one */
{
amiga_data->symbols=amiga_data->symbol_tail=asp;
}
else
{
amiga_data->symbol_tail->next=asp;
amiga_data->symbol_tail=asp;
}
asp->symbol.section=((type==EXT_DEF)||(type==EXT_SYMB))?section:(type==EXT_COMMON)?
bfd_com_section_ptr:bfd_abs_section_ptr;
asp->symbol.flags=BSF_GLOBAL;
asp->symbol.value= GL(lp+len);
asp->symbol.the_bfd=abfd;
asp->type=type;
asp->hunk_number=((type==EXT_DEF)||(type==EXT_SYMB))?section->target_index:
(type==EXT_ABS)?-1:-3;
if ((asp->symbol.name=bfd_alloc(abfd,(len<<2)+1))==NULL)
{
bfd_set_error(bfd_error_no_memory);
return(false);
}
strncpy((char *)(asp->symbol.name),(char *)lp,len<<2);
((char*)(asp->symbol.name))[(len<<2)]='\0';
/* Now store the symbol in the first name longword */
*lp=(unsigned long)asp;
lp+=len+1;
if (type==EXT_COMMON) /* skip refs */
lp+= GL(lp)+1;
break;
default: /* References to an undefined symbol */
/* Problem is that this symbol may be defined in another hunk WITHIN this bfd */
/* To avoid conflicts with bfd, we simply scan through the list of already defined symbols
and add a symbol only, if we did not find it */
for (asp=amiga_data->symbols;asp!=NULL;asp=asp->next)
{
if (strncmp((char *)lp,asp->symbol.name,len<<2)==0)
break; /* Found symbol */
}
if (asp==NULL) /* Symbol not defined */
{
asp=(amiga_symbol_type *)bfd_zalloc(abfd,sizeof(amiga_symbol_type));
if (!asp) /* No mem */
{
bfd_set_error(bfd_error_no_memory);
return(false);
}
/* Add symbol to list of all symbols */
asp->next=NULL;
if (!amiga_data->symbols) /* first one */
{
amiga_data->symbols=amiga_data->symbol_tail=asp;
}
else
{
amiga_data->symbol_tail->next=asp;
amiga_data->symbol_tail=asp;
}
if ((asp->symbol.name=bfd_alloc(abfd,(len<<2)+1))==NULL)
{
bfd_set_error(bfd_error_no_memory);
return(false);
}
strncpy((char *)(asp->symbol.name),(const char *)lp,len<<2);
((char *)(asp->symbol.name))[(len<<2)]='\0';
asp->symbol.section=bfd_und_section_ptr;
asp->symbol.flags=0;
asp->symbol.the_bfd=abfd;
asp->hunk_number=-2;
asp->type=type;
abfd->symcount++;
}
/* Store symbol in 1st LW of name */
*lp=(unsigned long)asp;
lp+=len;
lp+= 1+ GL(lp); /* skip refs */
break;
}/* Of switch type */
}/* Of while *lp */
}/* of for sp */
}/* Of for section */
return true;
}
/* Get size of symtab */
long
amiga_get_symtab_upper_bound (abfd)
bfd *abfd;
{
/* We read in the symbol table first */
if (!amiga_slurp_symbol_table (abfd))
return -1;
return (abfd->symcount != 0) ?
(abfd->symcount+1) * (sizeof (amiga_symbol_type *)) : 0;
}
long
amiga_get_symtab (abfd, location)
bfd *abfd;
asymbol **location;
{
amiga_symbol_type *symp;
if(!amiga_slurp_symbol_table(abfd))
return -1;
if (abfd->symcount)
{
int i = 0;
for (symp = AMIGA_DATA(abfd)->symbols;
symp != (amiga_symbol_type *) NULL;
symp = symp->next)
{
location[i++] = &symp->symbol;
}
}
return abfd->symcount;
}
asymbol *
amiga_make_empty_symbol (abfd)
bfd *abfd;
{
amiga_symbol_type *new =
(amiga_symbol_type *) bfd_zalloc (abfd, sizeof (amiga_symbol_type));
new->symbol.the_bfd = abfd;
return &new->symbol;
}
void
amiga_get_symbol_info (ignore_abfd, symbol, ret)
bfd *ignore_abfd;
asymbol *symbol;
symbol_info *ret;
{
bfd_symbol_info (symbol, ret);
if (symbol->name[0] == ' ')
ret->name = "* empty table entry ";
if (symbol->section==bfd_abs_section_ptr)
ret->type = (symbol->flags & BSF_LOCAL) ? 'a' : 'A';
}
void
amiga_print_symbol (ignore_abfd, afile, symbol, how)
bfd *ignore_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(stderr,"%4x %2x %2x",
(unsigned int)((amiga_symbol(symbol)->hunk_number)&0xffff),0,amiga_symbol(symbol)->type);
break;
case bfd_print_symbol_all:
{
CONST char *section_name = symbol->section->name;
if (symbol->name[0] == ' ')
{
fprintf(file, "* empty table entry ");
}
else
{
bfd_print_symbol_vandf ((PTR)file, symbol);
fprintf(file," %-5s %04x %02x %s",
section_name,
(unsigned int)((amiga_symbol(symbol)->hunk_number)&0xffff), /* ->desc */
(unsigned) 0, /* ->other */
/* type */
symbol->name); /* ->name */
}
}
break;
}
}
long
amiga_get_reloc_upper_bound (abfd, asect)
bfd *abfd;
sec_ptr asect;
{
if (bfd_get_format (abfd) != bfd_object)
{
bfd_set_error(bfd_error_invalid_operation);
return 0;
}
return sizeof (arelent *) * (asect->reloc_count + 1);
}
/* slurp in relocs , amiga_digest_file left various pointers for us*/
static boolean
amiga_slurp_relocs(bfd *abfd, sec_ptr section, asymbol **symbols)
{
struct amiga_raw_symbol *sp;
amiga_symbol_type *asp;
long *lp;
int i,n,br,j;
int index;
long hunk_number;
int type;
/* First browse through raw_relocs */
for (i=0;i<amiga_per_section(section)->num_raw_relocs;i++)
{
lp=amiga_per_section(section)->raw_relocs[i];
/* lp points to RELOC ID */
/* first determine type of reloc */
n = GL(lp);
switch (n)
{
case HUNK_RELOC32: /* 32 bit ref */
case HUNK_RELOC16: /* 16 bit ref */
case HUNK_RELOC8: /* 8 bit ref */
case HUNK_DREL32: /* 32 bit ref baserel */
case HUNK_DREL16: /* 16 bit baserel */
case HUNK_DREL8: /* 8 bit baserel */
if (n < HUNK_DREL32)
{ /*0:8bit, 1: 16bit, 2:32bit */
index=2-(n-HUNK_RELOC32);
br=0; /* not base relative */
}
else
{
index=2-(n-HUNK_DREL32);
br=1; /* base relative */
}
lp++;
while ((n=GL(lp++))) /* read offsets and hunk number */
{
hunk_number=(long)GL(lp++);
for (j=0;j<n;j++)
{ /* add relocs */
if (!amiga_add_reloc(abfd,section,GL(lp+j),NULL,
amiga_howto_array[br][index],hunk_number))
return false;
}/* of for */
lp+=n;
}/* of while */
break;
default: /* error */
bfd_set_error(bfd_error_wrong_format);
return (false);
break;
}/* of switch */
}/* of for i */
/* Now step through the raw_symbols and add all relocs in them */
for (sp=amiga_per_section(section)->first;sp!=NULL;sp=sp->next)
{
lp=&(sp->data[0]);
/* points to id */
while ((n=GL(lp++))) /* until end is reached */
{
type = (n>>24) & 0xff;
n &= 0xffffff;
/* lp points to symbol pointer (former 1st LW of name )*/
asp=(amiga_symbol_type *) *lp;
switch (type)
{
case EXT_SYMB:
case EXT_DEF:
case EXT_ABS: /* no relocs here, just advance the pointer */
lp+=1+n;
break;
case EXT_COMMON: /* same as below, but advance lp by one to skip common size */
lp++;
/* Fall through */
default: /* reference to something */
/* skip name first */
lp+=n;
/* points to num of refs to hunk */
n=GL(lp++);
/* Add relocs to this section, relative to asp, offset is lp[i] */
/* determine howto first */
if (type==EXT_COMMON) /* 32 bit ref */
{
index=2;
br=0;
}
else
{
if (type>EXT_REF32)
type--; /* skip EXT_COMMON gap */
type-=EXT_REF32;
br=0;
if (type>2) /* base relative */
{
type-=3;
br=1;
}
index=2-type;
}/* of else */
for (i=0;i<n;i++) /* refs follow */
{
if (!amiga_add_reloc(abfd,section,GL(lp+i),asp,amiga_howto_array[br][index],-4))
return false;
}
lp+=n;
break;
}/* of switch */
}/* of while *lp */
}/* Of for sp*/
return true;
}/* Of slurp_relocs */
long
amiga_canonicalize_reloc (abfd, section, relptr, symbols)
bfd *abfd;
sec_ptr section;
arelent **relptr;
asymbol **symbols;
{
amiga_reloc_type *src = NULL;
if (!section->relocation && !amiga_slurp_relocs(abfd,section,symbols))
return -1;
src=(amiga_reloc_type *)section->relocation;
while (src != (amiga_reloc_type *) 0)
{
*relptr++ = &src->relent;
src = src->next;
}
*relptr = (arelent *) 0;
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 boolean
amiga_set_section_contents (abfd, section, location, offset, count)
bfd *abfd;
sec_ptr section;
unsigned char *location;
file_ptr offset;
int count;
{
unsigned char *contents;
if ((section->flags&SEC_HAS_CONTENTS)==0) /* BSS */
{
bfd_set_error(bfd_error_invalid_operation);
return false;
}
if ((section->flags&SEC_IN_MEMORY)==0) /* Not in memory, so alloc space */
{
contents=bfd_zalloc(abfd,section->_raw_size);
if (!contents)
{
bfd_set_error(bfd_error_no_memory);
return false;
}
DPRINT(5,("Allocated %lx bytes at %lx\n",section->_raw_size,contents));
section->contents=contents;
section->flags|=SEC_IN_MEMORY;
}
else /* In memory */
contents=section->contents;
/* Copy mem */
memmove(contents+offset,location,count);
return(true);
}/* Of section_set_contents */
/* FIXME: Is this everything ? */
static boolean
amiga_set_arch_mach (abfd, arch, machine)
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 68000:
case 68008:
case 68010:
case 68020:
case 68030:
case 68040:
case 68070:
case 0:
return true;
default:
return false;
}
}
else if (arch == bfd_arch_powerpc)
{
return true;
}
return false;
}
static int
DEFUN(amiga_sizeof_headers,(ignore_abfd, ignore),
bfd *ignore_abfd AND
boolean ignore)
{
/* The amiga hunk format doesn't have headers.*/
return 0;
}
/* 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. */
boolean
amiga_find_nearest_line(abfd, section, symbols, offset, filename_ptr,
functionname_ptr, line_ptr)
bfd *abfd;
asection *section;
asymbol **symbols;
bfd_vma offset;
char **filename_ptr;
char **functionname_ptr;
int *line_ptr;
{
/* FIXME (see aoutx.h, for example) */
return false;
}
static const struct reloc_howto_struct *
amiga_bfd_reloc_type_lookup (abfd, code)
bfd *abfd;
bfd_reloc_code_real_type code;
{
switch (code)
{
case BFD_RELOC_8_PCREL: return &howto_hunk_reloc8;
case BFD_RELOC_16_PCREL: return &howto_hunk_reloc16;
case BFD_RELOC_CTOR: /* FIXME - assumes 32 bits */
case BFD_RELOC_32_PCREL: return &howto_hunk_reloc32;
case BFD_RELOC_8: return &howto_hunk_drel8;
case BFD_RELOC_16: return &howto_hunk_drel16;
case BFD_RELOC_32: return &howto_hunk_drel32;
/* FIXME: Add more cases here for base relative relocs*/
default: return 0;
}
}
static boolean
amiga_bfd_copy_private_bfd_data(bfd *ibfd, bfd *obfd)
{
AMIGA_DATA(obfd)->IsLoadFile = AMIGA_DATA(ibfd)->IsLoadFile;
return true;
}
/* We don't have core files. */
#define amiga_core_file_failing_command _bfd_dummy_core_file_failing_command
#define amiga_core_file_failing_signal _bfd_dummy_core_file_failing_signal
#define amiga_core_file_matches_executable_p _bfd_dummy_core_file_matches_executable_p
/* Entry points through BFD_JUMP_TABLE_ARCHIVE */
/* 101194: We do not use archive files, AMIGA Hunk load libs will be supported someday... ST */
#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_bsd_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 */
#undef amiga_get_symtab_upper_bound /* defined above */
#undef amiga_get_symtab /* defined above */
#undef amiga_make_empty_symbol /* defined above */
#undef amiga_print_symbol /* defined above */
#undef amiga_get_symbol_info /* defined above */
#define amiga_bfd_is_local_label bfd_generic_is_local_label
#define amiga_get_lineno (struct lineno_cache_entry *(*)())bfd_nullvoidptr
#undef amiga_find_nearest_line /* defined above */
#define amiga_bfd_make_debug_symbol (asymbol * (*)(bfd *, void *, unsigned long)) bfd_nullvoidptr
#define amiga_read_minisymbols _bfd_generic_read_minisymbols
#define amiga_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
#define amiga_bfd_debug_info_start bfd_void
#define amiga_bfd_debug_info_end bfd_void
#define amiga_bfd_debug_info_accumulate (PROTO(void,(*),(bfd*, struct sec *))) bfd_void
/* 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 */
extern bfd_byte *get_relocated_section_contents(bfd*, struct bfd_link_info *,
struct bfd_link_order *, bfd_byte *,
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_add_symbols _bfd_generic_link_add_symbols
extern boolean amiga_final_link(bfd *, struct bfd_link_info *);
#define amiga_bfd_final_link amiga_final_link
/* 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_hook 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_flags _bfd_generic_bfd_print_private_flags
#define amiga_bfd_print_private_bfd_data _bfd_generic_bfd_print_private_bfd_data
#define amiga_bfd_link_split_section _bfd_generic_link_split_section
#if defined (amiga)
/* So that the JUMP_TABLE() macro below can work. */
#undef amiga
#endif
const bfd_target amiga_vec =
{
"amiga", /* name */
bfd_target_amiga_flavour,
true, /* data byte order is big */
true, /* header byte order is big */
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, /* 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,
bfd_generic_archive_p, /* AMIGA archives not supported yet */
_bfd_dummy_target
},
{
/* bfd_set_format */
bfd_false,
amiga_mkobject,
_bfd_generic_mkarchive, /* AMIGA archives not supported yet */
bfd_false
},
{
/* bfd_write_contents */
bfd_false,
amiga_write_object_contents,
_bfd_write_archive_contents, /* AMIGA archives not supported yet */
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),
(PTR) 0
#if 0
/* fixme: no longer in use? */
/* How applications can find out about amiga relocation types (see
documentation on reloc types). */
amiga_reloc_type_lookup
#endif
};