#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
#include "bfdlink.h"
#include "genlink.h"
#include "coff/internal.h"
#include "libcoff.h"
bfd_vma
bfd_coff_reloc16_get_value (reloc, link_info, input_section)
arelent *reloc;
struct bfd_link_info *link_info;
asection *input_section;
{
bfd_vma value;
asymbol *symbol = *(reloc->sym_ptr_ptr);
if (bfd_is_und_section (symbol->section)
|| bfd_is_com_section (symbol->section))
{
struct bfd_link_hash_entry *h;
h = bfd_wrapped_link_hash_lookup (input_section->owner, link_info,
bfd_asymbol_name (symbol),
FALSE, FALSE, TRUE);
if (h != (struct bfd_link_hash_entry *) NULL
&& (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak))
value = (h->u.def.value
+ h->u.def.section->output_section->vma
+ h->u.def.section->output_offset);
else if (h != (struct bfd_link_hash_entry *) NULL
&& h->type == bfd_link_hash_common)
value = h->u.c.size;
else
{
if (!((*link_info->callbacks->undefined_symbol)
(link_info, bfd_asymbol_name (symbol),
input_section->owner, input_section, reloc->address,
TRUE)))
abort ();
value = 0;
}
}
else
{
value = symbol->value
+ symbol->section->output_offset
+ symbol->section->output_section->vma;
}
value += reloc->addend;
return value;
}
void
bfd_perform_slip (abfd, slip, input_section, value)
bfd *abfd;
unsigned int slip;
asection *input_section;
bfd_vma value;
{
asymbol **s;
s = _bfd_generic_link_get_symbols (abfd);
BFD_ASSERT (s != (asymbol **) NULL);
while (*s)
{
asymbol *p = *s;
if (p->section == input_section)
{
if (p->value > value)
{
p->value -= slip;
if (p->udata.p != NULL)
{
struct generic_link_hash_entry *h;
h = (struct generic_link_hash_entry *) p->udata.p;
BFD_ASSERT (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak);
h->root.u.def.value -= slip;
BFD_ASSERT (h->root.u.def.value == p->value);
}
}
}
s++;
}
}
bfd_boolean
bfd_coff_reloc16_relax_section (abfd, input_section, link_info, again)
bfd *abfd;
asection *input_section;
struct bfd_link_info *link_info;
bfd_boolean *again;
{
bfd *input_bfd = input_section->owner;
unsigned *shrinks;
unsigned shrink = 0;
long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
arelent **reloc_vector = NULL;
long reloc_count;
*again = FALSE;
if (reloc_size < 0)
return FALSE;
reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
if (!reloc_vector && reloc_size > 0)
return FALSE;
reloc_count =
bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector,
_bfd_generic_link_get_symbols (input_bfd));
if (reloc_count < 0)
{
free (reloc_vector);
return FALSE;
}
if (reloc_count > 0)
{
int another_pass = 0;
bfd_size_type amt;
amt = reloc_count + 1;
amt *= sizeof (unsigned);
shrinks = (unsigned *) bfd_zmalloc (amt);
do
{
arelent **parent;
unsigned int i;
long j;
another_pass = 0;
for (i = 0, parent = reloc_vector; *parent; parent++, i++)
{
shrink = bfd_coff_reloc16_estimate (abfd, input_section, *parent,
shrinks[i], link_info);
if (shrink != shrinks[i])
{
another_pass = 1;
for (j = i + 1; j <= reloc_count; j++)
shrinks[j] += shrink - shrinks[i];
}
}
}
while (another_pass);
shrink = shrinks[reloc_count];
free ((char *) shrinks);
}
input_section->_cooked_size -= shrink;
free ((char *) reloc_vector);
return TRUE;
}
bfd_byte *
bfd_coff_reloc16_get_relocated_section_contents (in_abfd,
link_info,
link_order,
data,
relocateable,
symbols)
bfd *in_abfd;
struct bfd_link_info *link_info;
struct bfd_link_order *link_order;
bfd_byte *data;
bfd_boolean relocateable;
asymbol **symbols;
{
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;
long reloc_count;
if (reloc_size < 0)
return NULL;
if (relocateable)
return bfd_generic_get_relocated_section_contents (in_abfd, link_info,
link_order,
data, relocateable,
symbols);
if (!bfd_get_section_contents (input_bfd,
input_section,
data,
(bfd_vma) 0,
input_section->_raw_size))
return NULL;
reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
if (!reloc_vector && reloc_size != 0)
return NULL;
reloc_count = bfd_canonicalize_reloc (input_bfd,
input_section,
reloc_vector,
symbols);
if (reloc_count < 0)
{
free (reloc_vector);
return NULL;
}
if (reloc_count > 0)
{
arelent **parent = reloc_vector;
arelent *reloc;
unsigned int dst_address = 0;
unsigned int src_address = 0;
unsigned int run;
unsigned int idx;
while (dst_address < link_order->size)
{
reloc = *parent;
if (reloc)
{
run = reloc->address - src_address;
parent++;
}
else
{
run = link_order->size - dst_address;
}
for (idx = 0; idx < run; idx++)
data[dst_address++] = data[src_address++];
if (reloc)
{
bfd_coff_reloc16_extra_cases (input_bfd, link_info, link_order,
reloc, data, &src_address,
&dst_address);
}
}
}
free ((char *) reloc_vector);
return data;
}