1333 lines
38 KiB
C
1333 lines
38 KiB
C
/* BFD back-end for Commodore-Amiga AmigaOS binaries. Linker routines.
|
|
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
|
|
Free Software Foundation, Inc.
|
|
Contributed 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. */
|
|
|
|
/*
|
|
INODE
|
|
amigalink, , implementation, amiga
|
|
SECTION
|
|
amigalink
|
|
|
|
This is the description of the linker routines for the amiga.
|
|
In fact, this includes a description of the changes made to the
|
|
a.out code, in order to build a working linker for the Amiga.
|
|
@menu
|
|
@* alterations::
|
|
@end menu
|
|
|
|
INODE
|
|
alterations, , , amigalink
|
|
SUBSECTION
|
|
alterations
|
|
|
|
The file @file{aout-amiga.c} defines the amiga a.out backend. It differs from
|
|
the sun3 backend only in these details:
|
|
o The @code{final_link} routine is @code{amiga_final_link}.
|
|
o The routine to get the relocated section contents is
|
|
@code{get_relocated_section_contents}.
|
|
|
|
This ensures that the link is performed properly, but has the side effect of
|
|
loosing performance.
|
|
|
|
The amiga bfd code uses the same functions since they check for the used flavour.
|
|
@@*
|
|
|
|
The usage of a special linker code has one reason:
|
|
The bfd library assumes that a program is always loaded at a known memory
|
|
address. This is not a case on an Amiga. So the Amiga format has to take over
|
|
some relocs to an executable output file.
|
|
This is not the case with a.out formats, so there relocations can be applied at link time,
|
|
not at run time, like on the Amiga.
|
|
The special routines compensate this: instead of applying the relocations, they are
|
|
copied to the output file, if neccessary.
|
|
As as consequence, @code{final_link} and @code{get_relocated_section_contents} are nearly identical to
|
|
the original routines from @file{linker.c} and @file{reloc.c}.
|
|
*/
|
|
|
|
#include "bfd.h"
|
|
#include "sysdep.h"
|
|
#include "libbfd.h"
|
|
#include "bfdlink.h"
|
|
#include "genlink.h"
|
|
#include "libamiga.h"
|
|
|
|
#define bfd_msg (*_bfd_error_handler)
|
|
|
|
#ifndef PARAMS
|
|
#define PARAMS(a) a
|
|
#endif
|
|
|
|
/*#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
|
|
|
|
/* This one is used by the linker and tells us, if a debug hunk should be
|
|
written out */
|
|
int write_debug_hunk = 1;
|
|
|
|
/* This is also used by the linker to set the attribute of sections */
|
|
int amiga_attribute = 0;
|
|
|
|
/* This one is used to indicate base-relative linking */
|
|
int amiga_base_relative = 0;
|
|
|
|
/* This one is used to indicate -resident linking */
|
|
int amiga_resident = 0;
|
|
|
|
bfd_boolean
|
|
default_indirect_link_order PARAMS ((bfd *, struct bfd_link_info *,
|
|
asection *, struct bfd_link_order *, bfd_boolean));
|
|
bfd_byte *
|
|
get_relocated_section_contents PARAMS ((bfd *, struct bfd_link_info *,
|
|
struct bfd_link_order *, bfd_byte *, bfd_boolean, asymbol **));
|
|
bfd_boolean
|
|
amiga_final_link PARAMS ((bfd *, struct bfd_link_info *));
|
|
bfd_boolean
|
|
aout_amiga_final_link PARAMS ((bfd *, struct bfd_link_info *));
|
|
|
|
bfd_boolean amiga_slurp_relocs PARAMS ((bfd *, sec_ptr, asymbol **));
|
|
|
|
static bfd_reloc_status_type
|
|
my_add_to PARAMS ((arelent *, PTR, int, int));
|
|
static void amiga_update_target_section PARAMS ((sec_ptr));
|
|
static bfd_reloc_status_type
|
|
amiga_perform_reloc PARAMS ((bfd *, arelent *, PTR, sec_ptr, bfd *, char **));
|
|
static bfd_reloc_status_type
|
|
aout_perform_reloc PARAMS ((bfd *, arelent *, PTR, sec_ptr, bfd *, char **));
|
|
static bfd_boolean
|
|
amiga_reloc_link_order PARAMS ((bfd *, struct bfd_link_info *, asection *,
|
|
struct bfd_link_order *));
|
|
|
|
enum { ADDEND_UNSIGNED=0x01, RELOC_SIGNED=0x02};
|
|
|
|
int relocation;
|
|
|
|
extern reloc_howto_type howto_table[10];
|
|
|
|
struct rel_chain {
|
|
asymbol * symbol;
|
|
signed offset;
|
|
};
|
|
|
|
static struct rel_chain * rel_jumps;
|
|
static unsigned rel_jumps_count;
|
|
static unsigned rel_jumps_max;
|
|
|
|
static void insert_long_jumps(bfd * abfd, bfd * input_bfd, asection *input_section, struct bfd_link_order *link_order, bfd_byte *data)
|
|
{
|
|
/**
|
|
* Check here for to large pcrel relocs which are to large.
|
|
* hack the current input_section:
|
|
* 1. append a jmp <symbol> 4ef9 0000 0000
|
|
* 2. perform relocation to the new jmp
|
|
* 3. patch the relent: address and howto
|
|
* 4. patch output_offsets of all input_sections starting behind current input_section
|
|
* 5. patch bfd_section_reloc_link_order entries since the linker already put an offset into these.
|
|
*
|
|
* Since the output offsets may change, a dry run is needed to precompute the new section sizes and offsets.
|
|
*
|
|
*/
|
|
if (0 == strcmp(input_section->name, ".text"))
|
|
{
|
|
// dry run? on first invocation there is no content yet in the output_section
|
|
if (!input_section->output_section->contents)
|
|
{
|
|
// record the current sizes;
|
|
struct bfd_link_order * lo1 = link_order;
|
|
for (; lo1; lo1 = lo1->next)
|
|
{
|
|
asection * s = lo1->u.indirect.section;
|
|
if (s->owner->xvec->flavour != bfd_target_amiga_flavour)
|
|
continue;
|
|
|
|
if (strcmp(s->name, ".text"))
|
|
continue;
|
|
|
|
s->compressed_size = s->_raw_size;
|
|
}
|
|
|
|
/**
|
|
* determine new section sizes, loop until output_section no longer changes.
|
|
*/
|
|
for(;;)
|
|
{
|
|
unsigned totalsize = input_section->output_section->_raw_size;
|
|
rel_jumps_count = 0;
|
|
|
|
lo1 = link_order;
|
|
for (; lo1; lo1 = lo1->next)
|
|
{
|
|
asection * s = lo1->u.indirect.section;
|
|
if (s->owner->xvec->flavour != bfd_target_amiga_flavour)
|
|
continue;
|
|
|
|
if (strcmp(s->name, ".text"))
|
|
continue;
|
|
|
|
if (s->reloc_count <= 0)
|
|
continue;
|
|
|
|
DPRINT(10, ("%s: %d relocs\n", s->owner->filename, s->reloc_count));
|
|
|
|
// reset rawsize
|
|
unsigned cursize = s->_raw_size;
|
|
s->_raw_size = s->compressed_size;
|
|
|
|
|
|
amiga_reloc_type *src;
|
|
for (src = (amiga_reloc_type *) s->relocation; src; src = src->next)
|
|
{
|
|
signed from;
|
|
signed to;
|
|
signed dist;
|
|
if (src->relent.howto->type != H_PC16 || strcmp(src->symbol->section->name, ".text"))
|
|
continue;
|
|
|
|
// check if relative jump is in 16 bit range
|
|
to = src->symbol->section->output_offset + src->symbol->value;
|
|
from = s->output_offset + src->relent.address;
|
|
dist = to - from;
|
|
|
|
if (-32766 <= dist && dist <= 32766)
|
|
continue;
|
|
|
|
DPRINT(10, ("%s %d, ", src->symbol->name, dist));
|
|
|
|
// check last generated jumps
|
|
if (rel_jumps)
|
|
{
|
|
unsigned i = 0;
|
|
for (; i < rel_jumps_count; ++i)
|
|
{
|
|
if (rel_jumps[i].symbol == src->symbol)
|
|
{
|
|
to = rel_jumps[i].offset;
|
|
dist = to - from;
|
|
break;
|
|
}
|
|
}
|
|
// use an existing jump entry
|
|
if (-32766 <= dist && dist <= 32766)
|
|
{
|
|
DPRINT(10, ("reuse %d, ", dist));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// 2.
|
|
// update rel_jumps
|
|
unsigned slot = 0;
|
|
for (;slot < rel_jumps_count; ++ slot)
|
|
{
|
|
if (rel_jumps[slot].offset - from < -32766)
|
|
break;
|
|
}
|
|
if (slot == rel_jumps_max)
|
|
{
|
|
rel_jumps_max += 16;
|
|
rel_jumps = (struct rel_chain *)realloc(rel_jumps, sizeof(struct rel_chain) * rel_jumps_max);
|
|
}
|
|
rel_jumps[slot].symbol = src->symbol;
|
|
rel_jumps[slot].offset = s->_raw_size + s->output_offset;
|
|
if (slot == rel_jumps_count)
|
|
++rel_jumps_count;
|
|
|
|
s->_raw_size += 6;
|
|
}
|
|
|
|
DPRINT(10, ("\n"));
|
|
|
|
// update sizes and offsets
|
|
unsigned delta = s->_raw_size - cursize;
|
|
if (delta == 0)
|
|
continue;
|
|
|
|
struct bfd_link_order * lo;
|
|
|
|
// 5. also patch data's link statements with bfd_section_reloc_link_order, needed for CTs
|
|
asection * xs = s->output_section;
|
|
for(;xs;xs = xs->next)
|
|
{
|
|
for (lo = xs->link_order_head; lo; lo = lo->next)
|
|
{
|
|
if (lo->type == bfd_section_reloc_link_order && lo->u.reloc.p->u.section == s->output_section
|
|
&& lo->u.reloc.p->addend >= s->_cooked_size + s->output_offset)
|
|
lo->u.reloc.p->addend += delta;
|
|
}
|
|
}
|
|
|
|
|
|
s->output_section->_raw_size += delta;
|
|
s->_cooked_size = s->_raw_size;
|
|
lo1->size += delta;
|
|
|
|
// 4. update output_offsets
|
|
for (lo = lo1->next; lo; lo = lo->next)
|
|
{
|
|
asection * ss = lo->u.indirect.section;
|
|
if (0 == strcmp(ss->name, ".text"))
|
|
{
|
|
ss->output_offset += delta;
|
|
lo->offset += delta;
|
|
}
|
|
}
|
|
}
|
|
|
|
// stop if there was no size increase
|
|
if (input_section->output_section->_raw_size == totalsize)
|
|
break;
|
|
}
|
|
|
|
input_section->output_section->_cooked_size = input_section->output_section->_raw_size;
|
|
|
|
// reset count
|
|
rel_jumps_count = 0;
|
|
|
|
/* adjust memory for first section. */
|
|
if (input_section->compressed_size < input_section->_raw_size)
|
|
{
|
|
PTR odata = data;
|
|
data = bfd_alloc(abfd, input_section->_raw_size);
|
|
memcpy(data, odata, input_section->compressed_size);
|
|
}
|
|
|
|
/**
|
|
* Now all sections have its final offset and size plus the old size in compressed_size.
|
|
*/
|
|
}
|
|
|
|
/**
|
|
* Create the jump tables.
|
|
*/
|
|
if (input_section->owner->xvec->flavour == bfd_target_amiga_flavour && input_section->reloc_count > 0)
|
|
{
|
|
amiga_reloc_type *src;
|
|
for (src = (amiga_reloc_type *) input_section->relocation; src; src = src->next)
|
|
{
|
|
signed from;
|
|
signed to;
|
|
signed dist;
|
|
if (src->relent.howto->type != H_PC16 || strcmp(src->symbol->section->name, ".text"))
|
|
continue;
|
|
|
|
// check if relative jump is in 16 bit range
|
|
to = src->symbol->section->output_offset + src->symbol->value;
|
|
from = input_section->output_offset + src->relent.address;
|
|
dist = to - from;
|
|
|
|
if (-32766 <= dist && dist <= 32766)
|
|
continue;
|
|
|
|
// check last generated jumps
|
|
if (rel_jumps)
|
|
{
|
|
unsigned i = 0;
|
|
for (; i < rel_jumps_count; ++i)
|
|
{
|
|
if (rel_jumps[i].symbol == src->symbol)
|
|
{
|
|
to = rel_jumps[i].offset;
|
|
dist = to - from;
|
|
break;
|
|
}
|
|
}
|
|
// use an existing jump entry
|
|
if (-32766 <= dist && dist <= 32766)
|
|
{
|
|
// 3.
|
|
signed relpos = src->relent.address;
|
|
signed offset = rel_jumps[i].offset - input_section->output_offset - relpos;
|
|
data[relpos] = offset >> 8;
|
|
data[relpos + 1] = offset;
|
|
|
|
src->relent.address = 0x80000000;
|
|
|
|
DPRINT(10, ("reuse %s %d\n", src->symbol->name, dist));
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
printf("INFO: using long jump from %s to %s:%s\n", input_section->owner->filename,
|
|
src->symbol->section->owner->filename, src->symbol->name);
|
|
fflush(stdout);
|
|
|
|
// 1. append a long jump
|
|
signed endpos = input_section->compressed_size;
|
|
input_section->compressed_size += 6;
|
|
data[endpos] = 0x4e;
|
|
data[endpos + 1] = 0xf9;
|
|
data[endpos + 2] = 0;
|
|
data[endpos + 3] = 0;
|
|
data[endpos + 4] = 0;
|
|
data[endpos + 5] = 0;
|
|
|
|
// update rel_jumps
|
|
unsigned slot = 0;
|
|
for (;slot < rel_jumps_count; ++ slot)
|
|
{
|
|
if (rel_jumps[slot].offset - from < -32766)
|
|
break;
|
|
}
|
|
rel_jumps[slot].symbol = src->symbol;
|
|
rel_jumps[slot].offset = endpos + input_section->output_offset;
|
|
if (slot == rel_jumps_count)
|
|
++rel_jumps_count;
|
|
|
|
// 2. apply relocation
|
|
signed relpos = src->relent.address;
|
|
signed offset = endpos - relpos;
|
|
data[relpos] = offset >> 8;
|
|
data[relpos + 1] = offset;
|
|
|
|
// 3. convert to ABS32 reloc
|
|
src->relent.howto = &howto_table[0];
|
|
src->relent.addend = 0;
|
|
src->relent.address = endpos + 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* update the associated .stab if .stabstr
|
|
*/
|
|
if (input_section->output_offset && 0 == strcmp(input_section->name, ".stabstr"))
|
|
{
|
|
sec_ptr s = input_bfd->sections;
|
|
while (s && s->next != input_section)
|
|
s = s->next;
|
|
|
|
if (s) {
|
|
unsigned char * start = s->output_section->contents + s->output_offset;
|
|
unsigned char * end = start + s->_raw_size;
|
|
while (start < end)
|
|
{
|
|
// update the name offset
|
|
unsigned offset = bfd_getb32(start);
|
|
if (offset)
|
|
bfd_putb32(offset + input_section->output_offset, start);
|
|
|
|
start += 12;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* This one is nearly identical to bfd_generic_get_relocated_section_contents
|
|
in reloc.c */
|
|
bfd_byte *
|
|
get_relocated_section_contents (
|
|
bfd *abfd,
|
|
struct bfd_link_info *link_info,
|
|
struct bfd_link_order *link_order,
|
|
bfd_byte *data,
|
|
bfd_boolean relocateable,
|
|
asymbol **symbols)
|
|
{
|
|
/* Get enough memory to hold the stuff. */
|
|
bfd *input_bfd = link_order->u.indirect.section->owner;
|
|
asection *input_section = link_order->u.indirect.section;
|
|
|
|
long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
|
|
arelent **reloc_vector = NULL;
|
|
long reloc_count;
|
|
bfd_reloc_status_type (*reloc_func)(bfd *, arelent *, PTR, sec_ptr,
|
|
bfd *, char **);
|
|
|
|
DPRINT(5,("Entering get_rel_sec_cont\n"));
|
|
|
|
if (reloc_size < 0)
|
|
goto error_return;
|
|
|
|
if (bfd_get_flavour (input_bfd) == bfd_target_amiga_flavour)
|
|
reloc_func = amiga_perform_reloc;
|
|
else if (bfd_get_flavour (input_bfd) == bfd_target_aout_flavour)
|
|
reloc_func = aout_perform_reloc;
|
|
else
|
|
{
|
|
bfd_set_error (bfd_error_bad_value);
|
|
goto error_return;
|
|
}
|
|
|
|
reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
|
|
if (reloc_vector == NULL && reloc_size != 0)
|
|
goto error_return;
|
|
|
|
DPRINT(5,("GRSC: GetSecCont()\n"));
|
|
/* Read in the section. */
|
|
if (!bfd_get_section_contents (input_bfd,
|
|
input_section,
|
|
(PTR) data,
|
|
(bfd_vma) 0,
|
|
input_section->_raw_size))
|
|
goto error_return;
|
|
|
|
insert_long_jumps(abfd, input_bfd, input_section, link_order, data);
|
|
|
|
/* We're not relaxing the section, so just copy the size info. */
|
|
input_section->_cooked_size = input_section->_raw_size;
|
|
input_section->reloc_done = TRUE;
|
|
|
|
DPRINT(5,("GRSC: CanReloc\n"));
|
|
reloc_count = bfd_canonicalize_reloc (input_bfd,
|
|
input_section,
|
|
reloc_vector,
|
|
symbols);
|
|
if (reloc_count < 0)
|
|
goto error_return;
|
|
|
|
if (reloc_count > 0)
|
|
{
|
|
arelent **parent;
|
|
|
|
DPRINT(5,("reloc_count=%ld\n",reloc_count));
|
|
|
|
for (parent = reloc_vector; *parent != (arelent *) NULL;
|
|
parent++)
|
|
{
|
|
char *error_message = (char *) NULL;
|
|
bfd_reloc_status_type r;
|
|
|
|
DPRINT(5,("Applying a reloc\nparent=%lx, reloc_vector=%lx, "
|
|
"*parent=%lx\n",parent,reloc_vector,*parent));
|
|
r=(*reloc_func) (input_bfd,
|
|
*parent,
|
|
(PTR) data,
|
|
input_section,
|
|
relocateable ? abfd : (bfd *) NULL,
|
|
&error_message);
|
|
if (relocateable)
|
|
{
|
|
asection *os = input_section->output_section;
|
|
|
|
DPRINT(5,("Keeping reloc\n"));
|
|
/* A partial link, so keep the relocs. */
|
|
os->orelocation[os->reloc_count] = *parent;
|
|
os->reloc_count++;
|
|
}
|
|
|
|
if (r != bfd_reloc_ok)
|
|
{
|
|
switch (r)
|
|
{
|
|
case bfd_reloc_undefined:
|
|
if (!((*link_info->callbacks->undefined_symbol)
|
|
(link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
|
|
input_bfd, input_section, (*parent)->address,
|
|
TRUE)))
|
|
goto error_return;
|
|
break;
|
|
case bfd_reloc_dangerous:
|
|
BFD_ASSERT (error_message != (char *) NULL);
|
|
if (!((*link_info->callbacks->reloc_dangerous)
|
|
(link_info, error_message, input_bfd, input_section,
|
|
(*parent)->address)))
|
|
goto error_return;
|
|
break;
|
|
case bfd_reloc_overflow:
|
|
if (!((*link_info->callbacks->reloc_overflow)
|
|
(link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
|
|
(*parent)->howto->name, (*parent)->addend,
|
|
input_bfd, input_section, (*parent)->address)))
|
|
goto error_return;
|
|
break;
|
|
case bfd_reloc_outofrange:
|
|
default:
|
|
DPRINT(10,("get_rel_sec_cont fails, perform reloc "
|
|
"returned $%x\n",r));
|
|
fprintf(stderr, "%s: %s reloc for %s is out of range: %08x\n", abfd->filename, (*(*parent)->sym_ptr_ptr)->section->name, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), relocation);
|
|
abort ();
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
if (reloc_vector != NULL)
|
|
free (reloc_vector);
|
|
DPRINT(5,("GRSC: Returning ok\n"));
|
|
return data;
|
|
|
|
error_return:
|
|
DPRINT(5,("GRSC: Error_return\n"));
|
|
if (reloc_vector != NULL)
|
|
free (reloc_vector);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* Add a value to a location */
|
|
static bfd_reloc_status_type
|
|
my_add_to (
|
|
arelent *r,
|
|
PTR data,
|
|
int add, int flags)
|
|
{
|
|
bfd_reloc_status_type ret=bfd_reloc_ok;
|
|
bfd_byte *p=((bfd_byte *)data)+r->address;
|
|
int val;
|
|
|
|
DPRINT(5,("Entering add_value\n"));
|
|
|
|
switch (r->howto->size)
|
|
{
|
|
case 0: /* byte size */
|
|
if ((flags & ADDEND_UNSIGNED) == 0)
|
|
val = ((*p & 0xff) ^ 0x80) - 0x80 + add;
|
|
else
|
|
val = (*p & 0xff) + add;
|
|
/* check for overflow */
|
|
if ((flags & RELOC_SIGNED) != 0) {
|
|
if (val<-0x80 || val>0x7f)
|
|
ret = bfd_reloc_overflow;
|
|
}
|
|
else {
|
|
if ((val&0xffffff00)!=0 && (val&0xffffff00)!=0xffffff00)
|
|
ret=bfd_reloc_overflow;
|
|
}
|
|
/* set the value */
|
|
*p = val & 0xff;
|
|
break;
|
|
|
|
case 1: /* word size */
|
|
if ((flags & ADDEND_UNSIGNED) == 0)
|
|
val = bfd_getb_signed_16 (p) + add;
|
|
else
|
|
val = bfd_getb16 (p) + add;
|
|
/* check for overflow */
|
|
if ((flags & RELOC_SIGNED) != 0) {
|
|
if (val<-0x8000 || val>0x7fff)
|
|
ret = bfd_reloc_overflow;
|
|
}
|
|
else {
|
|
if ((val&0xffff0000)!=0 && (val&0xffff0000)!=0xffff0000)
|
|
ret=bfd_reloc_overflow;
|
|
}
|
|
/* set the value */
|
|
bfd_putb16 (val, p);
|
|
break;
|
|
|
|
case 2: /* long word */
|
|
val = bfd_getb_signed_32 (p) + add;
|
|
/* If we are linking a resident program, then we limit the reloc size
|
|
to about +/- 1 GB.
|
|
|
|
When linking a shared library all variables defined in other
|
|
libraries are placed in memory >0x80000000, so if the library
|
|
tries to use one of those variables an error is output.
|
|
|
|
Without this it would be much more difficult to check for
|
|
incorrect references. */
|
|
if (amiga_resident &&
|
|
(val & 0xc0000000)!=0 && (val&0xc0000000)!=0xc0000000) /* Overflow */
|
|
{
|
|
ret=bfd_reloc_overflow;
|
|
}
|
|
bfd_putb32 (val, p);
|
|
break;
|
|
|
|
default: /* Error */
|
|
ret=bfd_reloc_notsupported;
|
|
break;
|
|
}/* Of switch */
|
|
|
|
DPRINT(5,("Leaving add_value\n"));
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* For base-relative linking place .bss symbols in the .data section. */
|
|
static void
|
|
amiga_update_target_section (
|
|
sec_ptr target_section)
|
|
{
|
|
/* If target->out is .bss, add the value of the .data section to
|
|
sym->value and set new output_section */
|
|
/* If we access a symbol in the .bss section, we have to convert
|
|
this to an access to .data section */
|
|
/* This is done through a change to the output section of
|
|
the symbol.. */
|
|
if (!strcmp(target_section->output_section->name,".bss"))
|
|
{
|
|
/* get value for .data section */
|
|
bfd *ibfd;
|
|
sec_ptr s;
|
|
|
|
ibfd=target_section->output_section->owner;
|
|
for (s=ibfd->sections;s!=NULL;s=s->next)
|
|
if (!strcmp(s->name,".data"))
|
|
{
|
|
target_section->output_offset+=s->_raw_size;
|
|
target_section->output_section=s;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Perform an Amiga relocation */
|
|
static bfd_reloc_status_type
|
|
amiga_perform_reloc (
|
|
bfd *abfd,
|
|
arelent *r,
|
|
PTR data,
|
|
sec_ptr sec,
|
|
bfd *obfd,
|
|
char **error_message ATTRIBUTE_UNUSED)
|
|
{
|
|
asymbol *sym; /* Reloc is relative to sym */
|
|
sec_ptr target_section; /* reloc is relative to this section */
|
|
bfd_reloc_status_type ret;
|
|
bfd_boolean copy;
|
|
int flags;
|
|
|
|
DPRINT(5,("Entering APR\nflavour is %d (amiga_flavour=%d, aout_flavour=%d)\n",
|
|
bfd_get_flavour (sec->owner), bfd_target_amiga_flavour,
|
|
bfd_target_aout_flavour));
|
|
|
|
/* If obfd==NULL: Apply the reloc, if possible. */
|
|
/* Else: Modify it and return */
|
|
|
|
if (obfd!=NULL) /* Only modify the reloc */
|
|
{
|
|
r->address+=sec->output_offset;
|
|
sec->output_section->flags|=SEC_RELOC;
|
|
DPRINT(5,("Leaving amiga_perf_reloc, modified\n"));
|
|
return bfd_reloc_ok;
|
|
}
|
|
|
|
/* Try to apply the reloc */
|
|
|
|
sym=*(r->sym_ptr_ptr);
|
|
|
|
// SBF: no idea what to fix here...?? /* FIXME: XXX */
|
|
// if (0 && sym->udata.p)
|
|
// sym = ((struct generic_link_hash_entry *) sym->udata.p)->sym;
|
|
|
|
target_section=sym->section;
|
|
|
|
if (bfd_is_und_section(target_section)) /* Error */
|
|
{
|
|
DPRINT(10,("amiga_perf_reloc: target_sec==UND\n"));
|
|
return bfd_reloc_undefined;
|
|
}
|
|
|
|
relocation=0; flags=RELOC_SIGNED; copy=FALSE; ret=bfd_reloc_ok;
|
|
|
|
DPRINT(5,("%s: size=%u\n",r->howto->name,bfd_get_reloc_size(r->howto)));
|
|
switch (r->howto->type)
|
|
{
|
|
case H_ABS16:
|
|
case H_ABS32:
|
|
if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */
|
|
relocation=sym->value;
|
|
else if (bfd_is_com_section(target_section)) /* ref to common */
|
|
{
|
|
relocation=0;
|
|
copy=TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (0 == strcmp(sec->name, ".stab") || 0 == strcmp(sec->name, ".stabstr"))
|
|
{
|
|
relocation=sym->value + target_section->output_offset;
|
|
}
|
|
else
|
|
{
|
|
if (amiga_base_relative)
|
|
amiga_update_target_section (target_section);
|
|
relocation=0;
|
|
copy=TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case H_PC16:
|
|
if (r->address == 0x80000000)
|
|
return bfd_reloc_ok;
|
|
/* no break */
|
|
case H_PC8: /* pcrel */
|
|
case H_PC32:
|
|
if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */
|
|
relocation=sym->value;
|
|
else if (bfd_is_com_section(target_section)) /* Error.. */
|
|
{
|
|
ret=bfd_reloc_undefined;
|
|
}
|
|
else if (sec->output_section!=target_section->output_section) /* Error */
|
|
{
|
|
DPRINT(5,("pc relative, but out-of-range\n"));
|
|
ret=bfd_reloc_outofrange;
|
|
}
|
|
else /* Same section */
|
|
{
|
|
DPRINT(5,("PC relative\n"));
|
|
relocation = sym->value + target_section->output_offset
|
|
- sec->output_offset;
|
|
}
|
|
break;
|
|
|
|
case H_SD8: /* baserel */
|
|
case H_SD16:
|
|
case H_SD32:
|
|
/* Relocs are always relative to the symbol ___a4_init */
|
|
/* Relocs to .bss section are converted to a reloc to .data section,
|
|
since .bss section contains only COMMON sections...... and should
|
|
be following .data section.. */
|
|
if (bfd_is_abs_section(target_section))
|
|
relocation=sym->value;
|
|
else if (!AMIGA_DATA(target_section->output_section->owner)->baserel)
|
|
{
|
|
bfd_msg ("Base symbol for base relative reloc not defined: "
|
|
"section %s, reloc to symbol %s",sec->name,sym->name);
|
|
ret=bfd_reloc_notsupported;
|
|
}
|
|
else if ((target_section->flags&SEC_CODE)!=0)
|
|
{
|
|
bfd_msg ("%s: baserelative text relocation to \"%s\"",
|
|
abfd->filename, sym->name);
|
|
ret=bfd_reloc_notsupported;
|
|
}
|
|
else
|
|
{
|
|
amiga_update_target_section (target_section);
|
|
relocation = sym->value + target_section->output_offset + r->addend;
|
|
|
|
DPRINT(20,("symbol=%s (0x%lx)\nsection %s (0x%lx; %s; output=0x%lx)"
|
|
"\nrelocation @0x%lx\n", sym->name, sym->value,
|
|
target_section->name, target_section,
|
|
target_section->owner->filename, target_section->output_offset,
|
|
r->address));
|
|
|
|
relocation -= (AMIGA_DATA(target_section->output_section->owner))->a4init;
|
|
flags|=ADDEND_UNSIGNED;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
bfd_msg ("Error: unsupported reloc: %s(%d)",r->howto->name,r->howto->size);
|
|
ret=bfd_reloc_notsupported;
|
|
break;
|
|
}/* Of switch */
|
|
|
|
/* Add in relocation */
|
|
if (relocation!=0)
|
|
ret = my_add_to (r, data, relocation, flags);
|
|
|
|
if (copy) /* Copy reloc to output section */
|
|
{
|
|
DPRINT(5,("Copying reloc\n"));
|
|
target_section=sec->output_section;
|
|
r->address+=sec->output_offset;
|
|
target_section->orelocation[target_section->reloc_count++]=r;
|
|
target_section->flags|=SEC_RELOC;
|
|
}
|
|
DPRINT(5,("Leaving amiga_perf_reloc with %d (OK=%d)\n",ret,bfd_reloc_ok));
|
|
return ret;
|
|
}
|
|
|
|
/* Perform an a.out relocation */
|
|
static bfd_reloc_status_type
|
|
aout_perform_reloc (
|
|
bfd *abfd,
|
|
arelent *r,
|
|
PTR data,
|
|
sec_ptr sec,
|
|
bfd *obfd,
|
|
char **error_message ATTRIBUTE_UNUSED)
|
|
{
|
|
asymbol *sym; /* Reloc is relative to sym */
|
|
sec_ptr target_section; /* reloc is relative to this section */
|
|
bfd_reloc_status_type ret;
|
|
bfd_boolean copy;
|
|
int relocation,flags;
|
|
|
|
DPRINT(5,("Entering aout_perf_reloc\n"));
|
|
|
|
/* If obfd==NULL: Apply the reloc, if possible. */
|
|
/* Else: Modify it and return */
|
|
|
|
if (obfd!=NULL) /* Only modify the reloc */
|
|
{
|
|
r->address+=sec->output_offset;
|
|
DPRINT(5,("Leaving aout_perf_reloc, modified\n"));
|
|
return bfd_reloc_ok;
|
|
}
|
|
|
|
/* Try to apply the reloc */
|
|
|
|
sym=*(r->sym_ptr_ptr);
|
|
target_section=sym->section;
|
|
|
|
if (bfd_is_und_section(target_section)) /* Error */
|
|
{
|
|
if ((sym->flags & BSF_WEAK) == 0)
|
|
{
|
|
DPRINT(10,("aout_perf_reloc: target_sec==UND\n"));
|
|
return bfd_reloc_undefined;
|
|
}
|
|
target_section=bfd_abs_section_ptr;
|
|
}
|
|
|
|
relocation=0; flags=RELOC_SIGNED; copy=FALSE; ret=bfd_reloc_ok;
|
|
|
|
DPRINT(10,("RELOC: %s: size=%u\n",r->howto->name,bfd_get_reloc_size(r->howto)));
|
|
switch (r->howto->type)
|
|
{
|
|
case H_ABS8: /* 8/16 bit reloc, pc relative or absolute */
|
|
case H_ABS16:
|
|
if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */
|
|
relocation=sym->value;
|
|
else if (bfd_is_com_section(target_section)) /* Error.. */
|
|
{
|
|
bfd_msg ("pc relative relocation to common symbol \"%s\" in "
|
|
"section %s",sym->name,sec->name);
|
|
DPRINT(10,("Ref to common symbol...aout_perf_reloc\n"));
|
|
ret=bfd_reloc_undefined;
|
|
}
|
|
else if (sec->output_section!=target_section->output_section)
|
|
{
|
|
// SBF: the if statement has been fixed, but the linker does no longer work.
|
|
// if ((target_section->output_section->flags&SEC_DATA)!=0)
|
|
// I replaced it with the old (obvious bogus) statement
|
|
// TODO: a better fix?
|
|
//if (target_section->output_section->flags & (SEC_DATA != 0))
|
|
if (amiga_base_relative)
|
|
goto baserel; /* Dirty, but no code duplication.. */
|
|
bfd_msg ("pc relative relocation out-of-range in section %s. "
|
|
"Relocation was to symbol %s",sec->name,sym->name);
|
|
DPRINT(10,("Section %s, target %s: Reloc out-of-range...not same "
|
|
"section, aout_perf\nsec->out=%s, target->out=%s, "
|
|
"offset=%lx\n",sec->name,target_section->name,
|
|
sec->output_section->name,
|
|
target_section->output_section->name,r->address));
|
|
ret=bfd_reloc_outofrange;
|
|
}
|
|
else
|
|
{
|
|
/* Same section, this is a pc relative hunk... */
|
|
DPRINT(5,("Reloc to same section...\n"));
|
|
relocation=-(long)(r->address+sec->output_offset);
|
|
}
|
|
break;
|
|
|
|
case H_ABS32: /* 32 bit reloc, pc relative or absolute */
|
|
if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */
|
|
relocation=sym->value;
|
|
else if (bfd_is_com_section(target_section)) /* ref to common */
|
|
{
|
|
relocation=0;
|
|
copy=TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (amiga_base_relative)
|
|
amiga_update_target_section (target_section);
|
|
relocation=0;
|
|
copy=TRUE;
|
|
}
|
|
DPRINT(10,("target->out=%s(%lx), sec->out=%s(%lx), symbol=%s\n",
|
|
target_section->output_section->name,
|
|
target_section->output_section,
|
|
sec->output_section->name,
|
|
sec->output_section,
|
|
sym->name));
|
|
break;
|
|
|
|
case H_PC16:
|
|
if (r->address == 0x80000000)
|
|
return bfd_reloc_ok;
|
|
/* no break */
|
|
case H_PC8: /* pcrel */
|
|
case H_PC32:
|
|
if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */
|
|
relocation=sym->value;
|
|
else if (sec->output_section!=target_section->output_section) /* Error */
|
|
{
|
|
DPRINT(5,("pc relative, but out-of-range\n"));
|
|
ret=bfd_reloc_outofrange;
|
|
}
|
|
else /* Same section */
|
|
{
|
|
relocation = sym->value + target_section->output_offset
|
|
- sec->output_offset;
|
|
}
|
|
break;
|
|
|
|
case H_SD16: /* baserel */
|
|
case H_SD32:
|
|
baserel:
|
|
/* We use the symbol ___a4_init as base */
|
|
if (bfd_is_abs_section(target_section))
|
|
relocation=sym->value;
|
|
else if (bfd_is_com_section(target_section)) /* Error.. */
|
|
{
|
|
bfd_msg ("baserelative relocation to common \"%s\"",sym->name);
|
|
DPRINT(10,("Ref to common symbol...aout_perf_reloc\n"));
|
|
ret=bfd_reloc_undefined;
|
|
}
|
|
else if (!AMIGA_DATA(target_section->output_section->owner)->baserel)
|
|
{
|
|
bfd_msg ("Base symbol for base relative reloc not defined: "
|
|
"section %s, reloc to symbol %s",sec->name,sym->name);
|
|
ret=bfd_reloc_notsupported;
|
|
}
|
|
else if ((target_section->flags&SEC_CODE)!=0)
|
|
{
|
|
bfd_msg ("%s: baserelative text relocation to \"%s\"",
|
|
abfd->filename, sym->name);
|
|
ret=bfd_reloc_notsupported;
|
|
}
|
|
else /* Target section and sec need not be the same.. */
|
|
{
|
|
amiga_update_target_section (target_section);
|
|
relocation = sym->value + target_section->output_offset;
|
|
/* if the symbol is in .bss, subtract the offset that gas has put
|
|
into the opcode */
|
|
if (target_section->index == 2 && !(sym->flags & BSF_GLOBAL))
|
|
relocation -= adata(abfd).datasec->_raw_size;
|
|
DPRINT(20,("symbol=%s (0x%lx)\nsection %s (0x%lx; %s; output=0x%lx)"
|
|
"\nrelocation @0x%lx\n", sym->name, sym->value,
|
|
target_section->name, target_section,
|
|
target_section->owner->filename, target_section->output_offset,
|
|
r->address));
|
|
|
|
relocation -= (AMIGA_DATA(target_section->output_section->owner))->a4init;
|
|
flags|=ADDEND_UNSIGNED;
|
|
}
|
|
DPRINT(10,("target->out=%s(%lx), sec->out=%s(%lx), symbol=%s\n",
|
|
target_section->output_section->name,
|
|
target_section->output_section,
|
|
sec->output_section->name,
|
|
sec->output_section,
|
|
sym->name));
|
|
break;
|
|
|
|
default:
|
|
bfd_msg ("Error: unsupported reloc: %s(%d)",r->howto->name,r->howto->size);
|
|
ret=bfd_reloc_notsupported;
|
|
break;
|
|
}/* Of switch */
|
|
|
|
/* Add in relocation */
|
|
if (relocation!=0)
|
|
ret = my_add_to (r, data, relocation, flags);
|
|
|
|
if (copy) /* Copy reloc to output section */
|
|
{
|
|
DPRINT(5,("Copying reloc\n"));
|
|
target_section=sec->output_section;
|
|
r->address+=sec->output_offset;
|
|
target_section->orelocation[target_section->reloc_count++]=r;
|
|
}
|
|
DPRINT(5,("Leaving aout_perf_reloc with %d (OK=%d)\n",ret,bfd_reloc_ok));
|
|
return ret;
|
|
}
|
|
|
|
/* The final link routine, used both by Amiga and a.out backend */
|
|
/* This is nearly a copy of linker.c/_bfd_generic_final_link */
|
|
bfd_boolean
|
|
amiga_final_link (
|
|
bfd *abfd,
|
|
struct bfd_link_info *info)
|
|
{
|
|
bfd *sub;
|
|
asection *o;
|
|
struct bfd_link_order *p;
|
|
size_t outsymalloc;
|
|
struct generic_write_global_symbol_info wginfo;
|
|
struct bfd_link_hash_entry *h =
|
|
bfd_link_hash_lookup (info->hash, "___a4_init", FALSE, FALSE, TRUE);
|
|
|
|
DPRINT(5,("Entering final_link\n"));
|
|
|
|
if (amiga_base_relative && h && h->type == bfd_link_hash_defined) {
|
|
AMIGA_DATA(abfd)->baserel = TRUE;
|
|
AMIGA_DATA(abfd)->a4init = h->u.def.value;
|
|
}
|
|
else
|
|
AMIGA_DATA(abfd)->baserel = FALSE;
|
|
|
|
if (bfd_get_flavour (abfd) == bfd_target_aout_flavour)
|
|
return aout_amiga_final_link (abfd, info);
|
|
|
|
bfd_get_outsymbols (abfd) = (asymbol **) NULL;
|
|
bfd_get_symcount (abfd) = 0;
|
|
outsymalloc = 0;
|
|
|
|
/* Mark all sections which will be included in the output file. */
|
|
for (o = abfd->sections; o != NULL; o = o->next)
|
|
for (p = o->link_order_head; p != NULL; p = p->next)
|
|
if (p->type == bfd_indirect_link_order)
|
|
p->u.indirect.section->linker_mark = TRUE;
|
|
|
|
/* Build the output symbol table. */
|
|
for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next)
|
|
if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc))
|
|
return FALSE;
|
|
|
|
DPRINT(10,("Did build output symbol table\n"));
|
|
|
|
/* Accumulate the global symbols. */
|
|
wginfo.info = info;
|
|
wginfo.output_bfd = abfd;
|
|
wginfo.psymalloc = &outsymalloc;
|
|
_bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info),
|
|
_bfd_generic_link_write_global_symbol,
|
|
(PTR) &wginfo);
|
|
|
|
DPRINT(10,("Accumulated global symbols\n"));
|
|
|
|
DPRINT(10,("Output bfd is %s(%lx)\n",abfd->filename,abfd));
|
|
|
|
if (1)
|
|
{
|
|
/* Allocate space for the output relocs for each section. */
|
|
/* We also handle base-relative linking special, by setting the .data
|
|
sections real length to it's length + .bss length */
|
|
/* This is different to bfd_generic_final_link: We ALWAYS alloc space
|
|
for the relocs, because we may need it anyway */
|
|
for (o = abfd->sections;
|
|
o != (asection *) NULL;
|
|
o = o->next)
|
|
{
|
|
DPRINT(10,("Section in output bfd is %s (%lx)\n",o->name,o));
|
|
|
|
o->reloc_count = 0;
|
|
for (p = o->link_order_head;
|
|
p != (struct bfd_link_order *) NULL;
|
|
p = p->next)
|
|
{
|
|
if (p->type == bfd_section_reloc_link_order
|
|
|| p->type == bfd_symbol_reloc_link_order)
|
|
++o->reloc_count;
|
|
else if (p->type == bfd_indirect_link_order)
|
|
{
|
|
asection *input_section;
|
|
bfd *input_bfd;
|
|
long relsize;
|
|
arelent **relocs;
|
|
asymbol **symbols;
|
|
long reloc_count;
|
|
|
|
input_section = p->u.indirect.section;
|
|
input_bfd = input_section->owner;
|
|
|
|
DPRINT(10,("\tIndirect section from bfd %s, section is %s(%lx) "
|
|
"(COM=%lx)\n",
|
|
input_bfd->filename,input_section->name,input_section,
|
|
bfd_com_section_ptr));
|
|
|
|
relsize = bfd_get_reloc_upper_bound (input_bfd,
|
|
input_section);
|
|
if (relsize < 0)
|
|
{
|
|
DPRINT(10,("Relsize<0.I..in bfd %s, sec %s\n",
|
|
input_bfd->filename, input_section->name));
|
|
return FALSE;
|
|
}
|
|
relocs = (arelent **) bfd_malloc ((bfd_size_type) relsize);
|
|
if (!relocs && relsize != 0)
|
|
return FALSE;
|
|
symbols = _bfd_generic_link_get_symbols (input_bfd);
|
|
reloc_count = bfd_canonicalize_reloc (input_bfd,
|
|
input_section,
|
|
relocs,
|
|
symbols);
|
|
free (relocs);
|
|
if (reloc_count < 0)
|
|
{
|
|
DPRINT(10,("Relsize<0.II..in bfd %s, sec %s\n",
|
|
input_bfd->filename, input_section->name));
|
|
return FALSE;
|
|
}
|
|
BFD_ASSERT ((unsigned long) reloc_count
|
|
== input_section->reloc_count);
|
|
o->reloc_count += reloc_count;
|
|
}
|
|
}
|
|
if (o->reloc_count > 0)
|
|
{
|
|
bfd_size_type amt;
|
|
|
|
amt = o->reloc_count;
|
|
amt *= sizeof (arelent *);
|
|
o->orelocation = (arelent **) bfd_alloc (abfd, amt);
|
|
if (!o->orelocation)
|
|
return FALSE;
|
|
/* o->flags |= SEC_RELOC; There may be no relocs. This can
|
|
be determined later only */
|
|
/* Reset the count so that it can be used as an index
|
|
when putting in the output relocs. */
|
|
o->reloc_count = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
DPRINT(10,("Got all relocs\n"));
|
|
|
|
/* Handle all the link order information for the sections. */
|
|
for (o = abfd->sections;
|
|
o != (asection *) NULL;
|
|
o = o->next)
|
|
{
|
|
for (p = o->link_order_head;
|
|
p != (struct bfd_link_order *) NULL;
|
|
p = p->next)
|
|
{
|
|
switch (p->type)
|
|
{
|
|
case bfd_section_reloc_link_order:
|
|
case bfd_symbol_reloc_link_order:
|
|
if (! amiga_reloc_link_order (abfd, info, o, p)) /* We use an own routine */
|
|
return FALSE;
|
|
break;
|
|
case bfd_indirect_link_order:
|
|
if (! default_indirect_link_order (abfd, info, o, p, FALSE))
|
|
/* Calls our get_relocated_section_contents */
|
|
return FALSE;
|
|
break;
|
|
default:
|
|
if (! _bfd_default_link_order (abfd, info, o, p))
|
|
return FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bfd_get_flavour(abfd)==bfd_target_amiga_flavour&&!info->relocateable)
|
|
AMIGA_DATA(abfd)->IsLoadFile = TRUE;
|
|
|
|
DPRINT(10,("Leaving final_link\n"));
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* Handle reloc link order.
|
|
This is nearly a copy of linker.c/_bfd_generic_reloc_link_order */
|
|
static bfd_boolean
|
|
amiga_reloc_link_order (
|
|
bfd *abfd,
|
|
struct bfd_link_info *info,
|
|
asection *sec,
|
|
struct bfd_link_order *link_order)
|
|
{
|
|
arelent *r;
|
|
|
|
DPRINT(5,("Entering amiga_reloc_link_order\n"));
|
|
|
|
if (sec->orelocation == (arelent **) NULL)
|
|
{
|
|
DPRINT(10,("aborting, since orelocation==NULL\n"));
|
|
abort ();
|
|
}
|
|
|
|
/* We generate a new ***AMIGA*** style reloc */
|
|
r = (arelent *) bfd_zalloc (abfd, (bfd_size_type) sizeof (amiga_reloc_type));
|
|
if (r == (arelent *) NULL)
|
|
{
|
|
DPRINT(5,("Leaving amiga_reloc_link, no mem\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
r->address = link_order->offset;
|
|
r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc);
|
|
if (r->howto == 0)
|
|
{
|
|
bfd_set_error (bfd_error_bad_value);
|
|
DPRINT(5,("Leaving amiga_reloc_link, bad value\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
/* Get the symbol to use for the relocation. */
|
|
if (link_order->type == bfd_section_reloc_link_order)
|
|
r->sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr;
|
|
else
|
|
{
|
|
struct generic_link_hash_entry *h;
|
|
|
|
h = ((struct generic_link_hash_entry *)
|
|
bfd_wrapped_link_hash_lookup (abfd, info,
|
|
link_order->u.reloc.p->u.name,
|
|
FALSE, FALSE, TRUE));
|
|
if (h == (struct generic_link_hash_entry *) NULL
|
|
|| ! h->written)
|
|
{
|
|
if (! ((*info->callbacks->unattached_reloc)
|
|
(info, link_order->u.reloc.p->u.name,
|
|
(bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
|
|
return FALSE;
|
|
bfd_set_error (bfd_error_bad_value);
|
|
DPRINT(5,("Leaving amiga_reloc_link, bad value in hash lookup\n"));
|
|
return FALSE;
|
|
}
|
|
r->sym_ptr_ptr = &h->sym;
|
|
}
|
|
DPRINT(5,("Got symbol for relocation\n"));
|
|
/* Store the addend */
|
|
r->addend = link_order->u.reloc.p->addend;
|
|
|
|
/* If we are generating relocateable output, just add the reloc */
|
|
if (info->relocateable)
|
|
{
|
|
DPRINT(5,("Adding reloc\n"));
|
|
sec->orelocation[sec->reloc_count] = r;
|
|
++sec->reloc_count;
|
|
sec->flags|=SEC_RELOC;
|
|
}
|
|
else /* Try to apply the reloc */
|
|
{
|
|
PTR data=(PTR)sec->contents;
|
|
bfd_reloc_status_type ret;
|
|
char *em=NULL;
|
|
|
|
DPRINT(5,("Apply link_order_reloc\n"));
|
|
|
|
/* FIXME: Maybe, we have to get the section contents, before we
|
|
use them, if they have not been set by now.. */
|
|
BFD_ASSERT (data!=NULL);
|
|
|
|
if (bfd_get_flavour(abfd)==bfd_target_amiga_flavour)
|
|
ret=amiga_perform_reloc(abfd,r,data,sec,NULL,&em);
|
|
else
|
|
ret=aout_perform_reloc(abfd,r,data,sec,NULL,&em);
|
|
|
|
if (ret!=bfd_reloc_ok)
|
|
{
|
|
DPRINT(5,("Leaving amiga_reloc_link, value FALSE\n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
DPRINT(5,("Leaving amiga_reloc_link\n"));
|
|
return TRUE;
|
|
}
|