added long jump insertion for small code model
This commit is contained in:
parent
0389bec447
commit
764e92f27f
|
@ -210,7 +210,7 @@ static void amiga_print_symbol PARAMS ((bfd *, PTR, asymbol *,
|
|||
static long amiga_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr));
|
||||
static bfd_boolean read_raw_relocs PARAMS ((bfd *, sec_ptr, unsigned long,
|
||||
unsigned long));
|
||||
static bfd_boolean amiga_slurp_relocs PARAMS ((bfd *, sec_ptr, asymbol **));
|
||||
bfd_boolean amiga_slurp_relocs PARAMS ((bfd *, sec_ptr, asymbol **));
|
||||
static long amiga_canonicalize_reloc PARAMS ((bfd *, sec_ptr, arelent **,
|
||||
asymbol **));
|
||||
static bfd_boolean amiga_set_section_contents PARAMS ((bfd *, sec_ptr, PTR,
|
||||
|
@ -232,7 +232,7 @@ static bfd *amiga_openr_next_archived_file PARAMS ((bfd *, bfd *));
|
|||
static PTR amiga_read_ar_hdr PARAMS ((bfd *));
|
||||
static int amiga_generic_stat_arch_elt PARAMS ((bfd *, struct stat *));
|
||||
|
||||
//#define DEBUG_AMIGA 1
|
||||
/*#define DEBUG_AMIGA 1*/
|
||||
#if DEBUG_AMIGA
|
||||
#include <stdarg.h>
|
||||
static void
|
||||
|
@ -249,7 +249,7 @@ error_print (const char *fmt, ...)
|
|||
#endif
|
||||
|
||||
enum {R_ABS32=0,R_ABS16,R_ABS8,R_PC32,R_PC16,R_PC8,R_SD32,R_SD16,R_SD8,R_PC26,R__MAX};
|
||||
static reloc_howto_type howto_table[R__MAX] =
|
||||
reloc_howto_type howto_table[R__MAX] =
|
||||
{
|
||||
{H_ABS32, /* type */
|
||||
0, /* rightshift */
|
||||
|
@ -450,8 +450,7 @@ static sec_ptr amiga_get_section_by_hunk_number (bfd *abfd, long hunk_number)
|
|||
last_bfd = abfd;
|
||||
return p;
|
||||
}
|
||||
BFD_FAIL ()
|
||||
;
|
||||
BFD_FAIL ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -2682,27 +2681,27 @@ amiga_get_section_contents (
|
|||
PTR location,
|
||||
file_ptr offset,
|
||||
bfd_size_type count)
|
||||
{
|
||||
unsigned long disk_size=amiga_per_section(section)->disk_size;
|
||||
{
|
||||
unsigned long disk_size=amiga_per_section(section)->disk_size;
|
||||
|
||||
if (bfd_seek (abfd, section->filepos + offset, SEEK_SET))
|
||||
return FALSE;
|
||||
if (bfd_seek (abfd, section->filepos + offset, SEEK_SET))
|
||||
return FALSE;
|
||||
|
||||
if (offset+count > disk_size)
|
||||
{
|
||||
/* the section's size on disk may be smaller than in memory
|
||||
in this case, pad the contents */
|
||||
if (bfd_bread (location, disk_size-offset, abfd) != disk_size-offset)
|
||||
return FALSE;
|
||||
memset ((char *) location + disk_size - offset, 0, count-(disk_size-offset));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bfd_bread (location, count, abfd) != count)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
if (offset+count > disk_size)
|
||||
{
|
||||
/* the section's size on disk may be smaller than in memory
|
||||
in this case, pad the contents */
|
||||
if (bfd_bread (location, disk_size-offset, abfd) != disk_size-offset)
|
||||
return FALSE;
|
||||
memset ((char *) location + disk_size - offset, 0, count-(disk_size-offset));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bfd_bread (location, count, abfd) != count)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bfd_boolean
|
||||
amiga_new_section_hook (
|
||||
|
@ -3128,7 +3127,7 @@ read_raw_relocs (
|
|||
}
|
||||
|
||||
/* slurp in relocs, amiga_digest_file left various pointers for us */
|
||||
static bfd_boolean
|
||||
bfd_boolean
|
||||
amiga_slurp_relocs (
|
||||
bfd *abfd,
|
||||
sec_ptr section,
|
||||
|
|
|
@ -70,6 +70,10 @@ the original routines from @file{linker.c} and @file{reloc.c}.
|
|||
|
||||
#define bfd_msg (*_bfd_error_handler)
|
||||
|
||||
#ifndef PARAMS
|
||||
#define PARAMS(a) a
|
||||
#endif
|
||||
|
||||
/*#define DEBUG_AMIGA 1*/
|
||||
#if DEBUG_AMIGA
|
||||
#include <stdarg.h>
|
||||
|
@ -110,6 +114,8 @@ 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));
|
||||
|
@ -121,21 +127,32 @@ 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 };
|
||||
enum { ADDEND_UNSIGNED=0x01, RELOC_SIGNED=0x02};
|
||||
|
||||
int relocation;
|
||||
|
||||
extern bfd_boolean trace_file_tries;
|
||||
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;
|
||||
|
||||
/* This one is nearly identical to bfd_generic_get_relocated_section_contents
|
||||
in reloc.c */
|
||||
bfd_byte *
|
||||
get_relocated_section_contents (abfd, link_info, link_order, data,
|
||||
relocateable, symbols)
|
||||
bfd *abfd;
|
||||
struct bfd_link_info *link_info;
|
||||
struct bfd_link_order *link_order;
|
||||
bfd_byte *data;
|
||||
bfd_boolean relocateable;
|
||||
asymbol **symbols;
|
||||
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;
|
||||
|
@ -175,6 +192,257 @@ get_relocated_section_contents (abfd, link_info, link_order, data,
|
|||
input_section->_raw_size))
|
||||
goto error_return;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* 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 (strcmp(s->name, ".text"))
|
||||
continue;
|
||||
|
||||
s->userdata = (void *)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 (strcmp(s->name, ".text"))
|
||||
continue;
|
||||
|
||||
if (s->reloc_count <= 0)
|
||||
continue;
|
||||
|
||||
DPRINT(10, ("%s: %d relocs\n", s->owner->filename, s->reloc_count));
|
||||
|
||||
// reset _raw_size
|
||||
unsigned cursize = s->_raw_size;
|
||||
s->_raw_size = (unsigned)s->userdata;
|
||||
|
||||
|
||||
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));
|
||||
|
||||
if (trace_file_tries)
|
||||
info_msg (_("using long jump from %s to %s:%s\n"), s->owner->filename,
|
||||
src->symbol->section->owner->filename, src->symbol->name);
|
||||
|
||||
// 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;
|
||||
|
||||
s->output_section->_raw_size += delta;
|
||||
s->_cooked_size = s->_raw_size;
|
||||
lo1->size += delta;
|
||||
|
||||
// 4.
|
||||
struct bfd_link_order * lo = lo1->next;
|
||||
for (; lo; lo = lo->next)
|
||||
{
|
||||
asection * s = lo->u.indirect.section;
|
||||
if (0 == strcmp(s->name, ".text"))
|
||||
{
|
||||
s->output_offset += delta;
|
||||
lo->offset += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stop if there was no size increase
|
||||
if (input_section->output_section->_raw_size == totalsize)
|
||||
break;
|
||||
}
|
||||
|
||||
// reset count
|
||||
rel_jumps_count = 0;
|
||||
|
||||
/* adjust memory for first section. */
|
||||
if ((unsigned)input_section->userdata < input_section->_raw_size)
|
||||
{
|
||||
PTR odata = data;
|
||||
data = bfd_alloc(abfd, input_section->_raw_size);
|
||||
memcpy(data, odata, (unsigned)input_section->userdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Now all sections have its final offset and size plus the old size in userdata.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
if (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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 1. append a long jump
|
||||
signed endpos = (unsigned)input_section->userdata;
|
||||
input_section->userdata = (void *)((unsigned)input_section->userdata + 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
@ -269,10 +537,10 @@ error_return:
|
|||
|
||||
/* Add a value to a location */
|
||||
static bfd_reloc_status_type
|
||||
my_add_to (r, data, add, flags)
|
||||
arelent *r;
|
||||
PTR data;
|
||||
int add, flags;
|
||||
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;
|
||||
|
@ -349,8 +617,8 @@ my_add_to (r, data, add, flags)
|
|||
|
||||
/* For base-relative linking place .bss symbols in the .data section. */
|
||||
static void
|
||||
amiga_update_target_section (target_section)
|
||||
sec_ptr target_section;
|
||||
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 */
|
||||
|
@ -377,13 +645,13 @@ amiga_update_target_section (target_section)
|
|||
|
||||
/* Perform an Amiga relocation */
|
||||
static bfd_reloc_status_type
|
||||
amiga_perform_reloc (abfd, r, data, sec, obfd, error_message)
|
||||
bfd *abfd;
|
||||
arelent *r;
|
||||
PTR data;
|
||||
sec_ptr sec;
|
||||
bfd *obfd;
|
||||
char **error_message ATTRIBUTE_UNUSED;
|
||||
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 */
|
||||
|
@ -452,8 +720,11 @@ amiga_perform_reloc (abfd, r, data, sec, obfd, error_message)
|
|||
}
|
||||
break;
|
||||
|
||||
case H_PC8: /* pcrel */
|
||||
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;
|
||||
|
@ -535,13 +806,13 @@ amiga_perform_reloc (abfd, r, data, sec, obfd, error_message)
|
|||
|
||||
/* Perform an a.out relocation */
|
||||
static bfd_reloc_status_type
|
||||
aout_perform_reloc (abfd, r, data, sec, obfd, error_message)
|
||||
bfd *abfd;
|
||||
arelent *r;
|
||||
PTR data;
|
||||
sec_ptr sec;
|
||||
bfd *obfd;
|
||||
char **error_message ATTRIBUTE_UNUSED;
|
||||
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 */
|
||||
|
@ -641,8 +912,11 @@ aout_perform_reloc (abfd, r, data, sec, obfd, error_message)
|
|||
sym->name));
|
||||
break;
|
||||
|
||||
case H_PC8: /* pcrel */
|
||||
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;
|
||||
|
@ -728,13 +1002,12 @@ aout_perform_reloc (abfd, r, data, sec, obfd, error_message)
|
|||
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 (abfd, info)
|
||||
bfd *abfd;
|
||||
struct bfd_link_info *info;
|
||||
amiga_final_link (
|
||||
bfd *abfd,
|
||||
struct bfd_link_info *info)
|
||||
{
|
||||
bfd *sub;
|
||||
asection *o;
|
||||
|
@ -744,6 +1017,8 @@ amiga_final_link (abfd, info)
|
|||
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;
|
||||
|
@ -751,8 +1026,6 @@ amiga_final_link (abfd, info)
|
|||
else
|
||||
AMIGA_DATA(abfd)->baserel = FALSE;
|
||||
|
||||
DPRINT(5,("Entering final_link\n"));
|
||||
|
||||
if (bfd_get_flavour (abfd) == bfd_target_aout_flavour)
|
||||
return aout_amiga_final_link (abfd, info);
|
||||
|
||||
|
@ -911,11 +1184,11 @@ amiga_final_link (abfd, info)
|
|||
/* Handle reloc link order.
|
||||
This is nearly a copy of linker.c/_bfd_generic_reloc_link_order */
|
||||
static bfd_boolean
|
||||
amiga_reloc_link_order (abfd, info, sec, link_order)
|
||||
bfd *abfd;
|
||||
struct bfd_link_info *info;
|
||||
asection *sec;
|
||||
struct bfd_link_order *link_order;
|
||||
amiga_reloc_link_order (
|
||||
bfd *abfd,
|
||||
struct bfd_link_info *info,
|
||||
asection *sec,
|
||||
struct bfd_link_order *link_order)
|
||||
{
|
||||
arelent *r;
|
||||
|
||||
|
|
|
@ -1175,12 +1175,11 @@ DESCRIPTION
|
|||
: bfd_get_section_size_before_reloc (sec))
|
||||
|
||||
bfd_boolean
|
||||
bfd_set_section_contents (abfd, section, location, offset, count)
|
||||
bfd *abfd;
|
||||
sec_ptr section;
|
||||
PTR location;
|
||||
file_ptr offset;
|
||||
bfd_size_type count;
|
||||
bfd_set_section_contents (bfd *abfd,
|
||||
sec_ptr section,
|
||||
PTR location,
|
||||
file_ptr offset,
|
||||
bfd_size_type count)
|
||||
{
|
||||
bfd_size_type sz;
|
||||
|
||||
|
|
Loading…
Reference in New Issue