0xffffffff, /* src_mask */
0xffffffff, /* dst_mask */
FALSE), /* pcrel_offset */
+
+ EMPTY_HOWTO (24),
+ EMPTY_HOWTO (25),
+ EMPTY_HOWTO (26),
+ EMPTY_HOWTO (27),
+ EMPTY_HOWTO (28),
+ EMPTY_HOWTO (29),
+ EMPTY_HOWTO (30),
+ EMPTY_HOWTO (31),
+ EMPTY_HOWTO (32),
+
+ HOWTO (R_MN10300_SYM_DIFF, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ NULL, /* special handler. */
+ "R_MN10300_SYM_DIFF", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_MN10300_ALIGN, /* type */
+ 0, /* rightshift */
+ 0, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ NULL, /* special handler. */
+ "R_MN10300_ALIGN", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE) /* pcrel_offset */
};
struct mn10300_reloc_map
{ BFD_RELOC_MN10300_GLOB_DAT, R_MN10300_GLOB_DAT },
{ BFD_RELOC_MN10300_JMP_SLOT, R_MN10300_JMP_SLOT },
{ BFD_RELOC_MN10300_RELATIVE, R_MN10300_RELATIVE },
+ { BFD_RELOC_MN10300_SYM_DIFF, R_MN10300_SYM_DIFF },
+ { BFD_RELOC_MN10300_ALIGN, R_MN10300_ALIGN }
};
/* Create the GOT section. */
asection *sec,
const Elf_Internal_Rela *relocs)
{
+ bfd_boolean sym_diff_reloc_seen;
Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Sym * isymbuf = NULL;
struct elf_link_hash_entry **sym_hashes;
const Elf_Internal_Rela *rel;
const Elf_Internal_Rela *rel_end;
asection * sgot;
asection * srelgot;
asection * sreloc;
+ bfd_boolean result = FALSE;
sgot = NULL;
srelgot = NULL;
return TRUE;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
sym_hashes = elf_sym_hashes (abfd);
dynobj = elf_hash_table (info)->dynobj;
local_got_offsets = elf_local_got_offsets (abfd);
rel_end = relocs + sec->reloc_count;
+ sym_diff_reloc_seen = FALSE;
for (rel = relocs; rel < rel_end; rel++)
{
struct elf_link_hash_entry *h;
unsigned long r_symndx;
+ unsigned int r_type;
r_symndx = ELF32_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
+ r_type = ELF32_R_TYPE (rel->r_info);
+
/* Some relocs require a global offset table. */
if (dynobj == NULL)
{
- switch (ELF32_R_TYPE (rel->r_info))
+ switch (r_type)
{
case R_MN10300_GOT32:
case R_MN10300_GOT24:
case R_MN10300_GOTPC16:
elf_hash_table (info)->dynobj = dynobj = abfd;
if (! _bfd_mn10300_elf_create_got_section (dynobj, info))
- return FALSE;
+ goto fail;
break;
default:
}
}
- switch (ELF32_R_TYPE (rel->r_info))
+ switch (r_type)
{
/* This relocation describes the C++ object vtable hierarchy.
Reconstruct it for later use during GC. */
case R_MN10300_GNU_VTINHERIT:
if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
- return FALSE;
+ goto fail;
break;
/* This relocation describes which C++ vtable entries are actually
BFD_ASSERT (h != NULL);
if (h != NULL
&& !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
- return FALSE;
+ goto fail;
break;
+
case R_MN10300_GOT32:
case R_MN10300_GOT24:
case R_MN10300_GOT16:
| SEC_READONLY));
if (srelgot == NULL
|| ! bfd_set_section_alignment (dynobj, srelgot, 2))
- return FALSE;
+ goto fail;
}
}
if (h->dynindx == -1)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
+ goto fail;
}
srelgot->size += sizeof (Elf32_External_Rela);
local_got_offsets = bfd_alloc (abfd, size);
if (local_got_offsets == NULL)
- return FALSE;
+ goto fail;
+
elf_local_got_offsets (abfd) = local_got_offsets;
for (i = 0; i < symtab_hdr->sh_info; i++)
h->non_got_ref = 1;
break;
+ case R_MN10300_SYM_DIFF:
+ sym_diff_reloc_seen = TRUE;
+ break;
+
case R_MN10300_32:
if (h != NULL)
h->non_got_ref = 1;
- /* If we are creating a shared library, then we need to copy
- the reloc into the shared library. */
+ /* If we are creating a shared library, then we
+ need to copy the reloc into the shared library. */
if (info->shared
- && (sec->flags & SEC_ALLOC) != 0)
+ && (sec->flags & SEC_ALLOC) != 0
+ /* Do not generate a dynamic reloc for a
+ reloc associated with a SYM_DIFF operation. */
+ && ! sym_diff_reloc_seen)
{
- /* When creating a shared object, we must copy these
- reloc types into the output file. We create a reloc
- section in dynobj and make room for this reloc. */
- if (sreloc == NULL)
- {
- const char * name;
+ asection * sym_section = NULL;
- name = (bfd_elf_string_from_elf_section
- (abfd,
- elf_elfheader (abfd)->e_shstrndx,
- elf_section_data (sec)->rel_hdr.sh_name));
- if (name == NULL)
- return FALSE;
+ /* Find the section containing the
+ symbol involved in the relocation. */
+ if (h == NULL)
+ {
+ Elf_Internal_Sym * isym;
- BFD_ASSERT (CONST_STRNEQ (name, ".rela")
- && streq (bfd_get_section_name (abfd, sec), name + 5));
+ if (isymbuf == NULL)
+ isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ if (isymbuf)
+ {
+ isym = isymbuf + r_symndx;
+ /* All we care about is whether this local symbol is absolute. */
+ if (isym->st_shndx == SHN_ABS)
+ sym_section = bfd_abs_section_ptr;
+ }
+ }
+ else
+ {
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ sym_section = h->root.u.def.section;
+ }
- sreloc = bfd_get_section_by_name (dynobj, name);
+ /* If the symbol is absolute then the relocation can
+ be resolved during linking and there is no need for
+ a dynamic reloc. */
+ if (sym_section != bfd_abs_section_ptr)
+ {
+ /* When creating a shared object, we must copy these
+ reloc types into the output file. We create a reloc
+ section in dynobj and make room for this reloc. */
if (sreloc == NULL)
{
- flagword flags;
-
- flags = (SEC_HAS_CONTENTS | SEC_READONLY
- | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- if ((sec->flags & SEC_ALLOC) != 0)
- flags |= SEC_ALLOC | SEC_LOAD;
- sreloc = bfd_make_section_with_flags (dynobj, name, flags);
- if (sreloc == NULL
- || ! bfd_set_section_alignment (dynobj, sreloc, 2))
- return FALSE;
+ sreloc = _bfd_elf_make_dynamic_reloc_section
+ (sec, dynobj, 2, abfd, /*rela?*/ TRUE);
+ if (sreloc == NULL)
+ goto fail;
}
- }
- sreloc->size += sizeof (Elf32_External_Rela);
+ sreloc->size += sizeof (Elf32_External_Rela);
+ }
}
break;
}
+
+ if (ELF32_R_TYPE (rel->r_info) != R_MN10300_SYM_DIFF)
+ sym_diff_reloc_seen = FALSE;
}
- return TRUE;
+ result = TRUE;
+ fail:
+ if (isymbuf != NULL)
+ free (isymbuf);
+
+ return result;
}
/* Return the section that should be marked against GC for a given
asection *sym_sec ATTRIBUTE_UNUSED,
int is_local ATTRIBUTE_UNUSED)
{
+ static asection * sym_diff_section;
+ static bfd_vma sym_diff_value;
+ bfd_boolean is_sym_diff_reloc;
unsigned long r_type = howto->type;
bfd_byte * hit_data = contents + offset;
bfd * dynobj;
return bfd_reloc_dangerous;
}
+ is_sym_diff_reloc = FALSE;
+ if (sym_diff_section != NULL)
+ {
+ BFD_ASSERT (sym_diff_section == input_section);
+
+ switch (r_type)
+ {
+ case R_MN10300_32:
+ case R_MN10300_24:
+ case R_MN10300_16:
+ case R_MN10300_8:
+ value -= sym_diff_value;
+ /* If we are computing a 32-bit value for the location lists
+ and the result is 0 then we add one to the value. A zero
+ value can result because of linker relaxation deleteing
+ prologue instructions and using a value of 1 (for the begin
+ and end offsets in the location list entry) results in a
+ nul entry which does not prevent the following entries from
+ being parsed. */
+ if (r_type == R_MN10300_32
+ && value == 0
+ && strcmp (input_section->name, ".debug_loc") == 0)
+ value = 1;
+ sym_diff_section = NULL;
+ is_sym_diff_reloc = TRUE;
+ break;
+
+ default:
+ sym_diff_section = NULL;
+ break;
+ }
+ }
+
switch (r_type)
{
+ case R_MN10300_SYM_DIFF:
+ BFD_ASSERT (addend == 0);
+ /* Cache the input section and value.
+ The offset is unreliable, since relaxation may
+ have reduced the following reloc's offset. */
+ sym_diff_section = input_section;
+ sym_diff_value = value;
+ return bfd_reloc_ok;
+
+ case R_MN10300_ALIGN:
case R_MN10300_NONE:
return bfd_reloc_ok;
case R_MN10300_32:
if (info->shared
+ /* Do not generate relocs when an R_MN10300_32 has been used
+ with an R_MN10300_SYM_DIFF to compute a difference of two
+ symbols. */
+ && is_sym_diff_reloc == FALSE
+ /* Also, do not generate a reloc when the symbol associated
+ with the R_MN10300_32 reloc is absolute - there is no
+ need for a run time computation in this case. */
+ && sym_sec != bfd_abs_section_ptr
+ /* If the section is not going to be allocated at load time
+ then there is no need to generate relocs for it. */
&& (input_section->flags & SEC_ALLOC) != 0)
{
Elf_Internal_Rela outrel;
time. */
if (sreloc == NULL)
{
- const char * name;
-
- name = (bfd_elf_string_from_elf_section
- (input_bfd,
- elf_elfheader (input_bfd)->e_shstrndx,
- elf_section_data (input_section)->rel_hdr.sh_name));
- if (name == NULL)
+ sreloc = _bfd_elf_get_dynamic_reloc_section
+ (input_bfd, input_section, /*rela?*/ TRUE);
+ if (sreloc == NULL)
return FALSE;
-
- BFD_ASSERT (CONST_STRNEQ (name, ".rela")
- && streq (bfd_get_section_name (input_bfd,
- input_section),
- name + 5));
-
- sreloc = bfd_get_section_by_name (dynobj, name);
- BFD_ASSERT (sreloc != NULL);
}
skip = FALSE;
value -= offset;
value += addend;
- if ((long) value > 0xff || (long) value < -0x100)
+ if ((long) value > 0x7f || (long) value < -0x80)
return bfd_reloc_overflow;
bfd_put_8 (input_bfd, value, hit_data);
value -= offset;
value += addend;
- if ((long) value > 0xffff || (long) value < -0x10000)
+ if ((long) value > 0x7fff || (long) value < -0x8000)
return bfd_reloc_overflow;
bfd_put_16 (input_bfd, value, hit_data);
value -= offset;
value += addend;
- if ((long) value > 0xffff || (long) value < -0x10000)
+ if ((long) value > 0x7fff || (long) value < -0x8000)
return bfd_reloc_overflow;
bfd_put_16 (input_bfd, value, hit_data);
".got")->output_section->vma;
value += addend;
- if ((long) value > 0xffff || (long) value < -0x10000)
+ if ((long) value > 0x7fff || (long) value < -0x8000)
return bfd_reloc_overflow;
bfd_put_16 (input_bfd, value, hit_data);
value -= offset;
value += addend;
- if ((long) value > 0xffff || (long) value < -0x10000)
+ if ((long) value > 0x7fff || (long) value < -0x8000)
return bfd_reloc_overflow;
bfd_put_16 (input_bfd, value, hit_data);
}
else if (r_type == R_MN10300_GOT16)
{
- if ((long) value > 0xffff || (long) value < -0x10000)
+ if ((long) value > 0x7fff || (long) value < -0x8000)
return bfd_reloc_overflow;
bfd_put_16 (input_bfd, value, hit_data);
&& elf_hash_table (info)->dynamic_sections_created
&& !SYMBOL_REFERENCES_LOCAL (info, hh))
|| (r_type == R_MN10300_32
+ /* _32 relocs in executables force _COPY relocs,
+ such that the address of the symbol ends up
+ being local. */
+ && !info->executable
&& !SYMBOL_REFERENCES_LOCAL (info, hh)
&& ((input_section->flags & SEC_ALLOC) != 0
/* DWARF will emit R_MN10300_32 relocations
elf32_mn10300_count_hash_table_entries (struct bfd_hash_entry *gen_entry ATTRIBUTE_UNUSED,
void * in_args)
{
- int *count = (int *)in_args;
+ int *count = (int *) in_args;
(*count) ++;
return TRUE;
sort_by_value (const void *va, const void *vb)
{
struct elf32_mn10300_link_hash_entry *a
- = *(struct elf32_mn10300_link_hash_entry **)va;
+ = *(struct elf32_mn10300_link_hash_entry **) va;
struct elf32_mn10300_link_hash_entry *b
- = *(struct elf32_mn10300_link_hash_entry **)vb;
+ = *(struct elf32_mn10300_link_hash_entry **) vb;
return a->value - b->value;
}
contents = elf_section_data (sec)->this_hdr.contents;
- /* The deletion must stop at the next ALIGN reloc for an aligment
- power larger than the number of bytes we are deleting. */
-
irelalign = NULL;
toaddr = sec->size;
irel = elf_section_data (sec)->relocs;
irelend = irel + sec->reloc_count;
+ if (sec->reloc_count > 0)
+ {
+ /* If there is an align reloc at the end of the section ignore it.
+ GAS creates these relocs for reasons of its own, and they just
+ serve to keep the section artifically inflated. */
+ if (ELF32_R_TYPE ((irelend - 1)->r_info) == (int) R_MN10300_ALIGN)
+ --irelend;
+
+ /* The deletion must stop at the next ALIGN reloc for an aligment
+ power larger than, or not a multiple of, the number of bytes we
+ are deleting. */
+ for (; irel < irelend; irel++)
+ {
+ int alignment = 1 << irel->r_addend;
+
+ if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN
+ && irel->r_offset > addr
+ && irel->r_offset < toaddr
+ && (count < alignment
+ || alignment % count != 0))
+ {
+ irelalign = irel;
+ toaddr = irel->r_offset;
+ break;
+ }
+ }
+ }
+
/* Actually delete the bytes. */
memmove (contents + addr, contents + addr + count,
(size_t) (toaddr - addr - count));
- sec->size -= count;
+
+ /* Adjust the section's size if we are shrinking it, or else
+ pad the bytes between the end of the shrunken region and
+ the start of the next region with NOP codes. */
+ if (irelalign == NULL)
+ {
+ sec->size -= count;
+ /* Include symbols at the end of the section, but
+ not at the end of a sub-region of the section. */
+ toaddr ++;
+ }
+ else
+ {
+ int i;
+
+#define NOP_OPCODE 0xcb
+
+ for (i = 0; i < count; i ++)
+ bfd_put_8 (abfd, (bfd_vma) NOP_OPCODE, contents + toaddr - count + i);
+ }
/* Adjust all the relocs. */
for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
{
/* Get the new reloc address. */
if ((irel->r_offset > addr
- && irel->r_offset < toaddr))
+ && irel->r_offset < toaddr)
+ || (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN
+ && irel->r_offset == toaddr))
irel->r_offset -= count;
}
- /* Adjust the local symbols defined in this section. */
+ /* Adjust the local symbols in the section, reducing their value
+ by the number of bytes deleted. Note - symbols within the deleted
+ region are moved to the address of the start of the region, which
+ actually means that they will address the byte beyond the end of
+ the region once the deletion has been completed. */
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
isym = (Elf_Internal_Sym *) symtab_hdr->contents;
for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
if (isym->st_shndx == sec_shndx
&& isym->st_value > addr
&& isym->st_value < toaddr)
- isym->st_value -= count;
+ {
+ if (isym->st_value < addr + count)
+ isym->st_value = addr;
+ else
+ isym->st_value -= count;
+ }
+ /* Adjust the function symbol's size as well. */
+ else if (isym->st_shndx == sec_shndx
+ && ELF_ST_TYPE (isym->st_info) == STT_FUNC
+ && isym->st_value + isym->st_size > addr
+ && isym->st_value + isym->st_size < toaddr)
+ isym->st_size -= count;
}
/* Now adjust the global symbols defined in this section. */
&& sym_hash->root.u.def.section == sec
&& sym_hash->root.u.def.value > addr
&& sym_hash->root.u.def.value < toaddr)
- sym_hash->root.u.def.value -= count;
+ {
+ if (sym_hash->root.u.def.value < addr + count)
+ sym_hash->root.u.def.value = addr;
+ else
+ sym_hash->root.u.def.value -= count;
+ }
+ /* Adjust the function symbol's size as well. */
+ else if (sym_hash->root.type == bfd_link_hash_defined
+ && sym_hash->root.u.def.section == sec
+ && sym_hash->type == STT_FUNC
+ && sym_hash->root.u.def.value + sym_hash->size > addr
+ && sym_hash->root.u.def.value + sym_hash->size < toaddr)
+ sym_hash->size -= count;
+ }
+
+ /* See if we can move the ALIGN reloc forward.
+ We have adjusted r_offset for it already. */
+ if (irelalign != NULL)
+ {
+ bfd_vma alignto, alignaddr;
+
+ if ((int) irelalign->r_addend > 0)
+ {
+ /* This is the old address. */
+ alignto = BFD_ALIGN (toaddr, 1 << irelalign->r_addend);
+ /* This is where the align points to now. */
+ alignaddr = BFD_ALIGN (irelalign->r_offset,
+ 1 << irelalign->r_addend);
+ if (alignaddr < alignto)
+ /* Tail recursion. */
+ return mn10300_elf_relax_delete_bytes (abfd, sec, alignaddr,
+ (int) (alignto - alignaddr));
+ }
}
return TRUE;
Elf_Internal_Sym *isymbuf = NULL;
struct elf32_mn10300_link_hash_table *hash_table;
asection *section = sec;
+ bfd_vma align_gap_adjustment;
/* Assume nothing changes. */
*again = FALSE;
local symbol in the global hash table. */
amt = strlen (sym_name) + 10;
new_name = bfd_malloc (amt);
- if (new_name == 0)
+ if (new_name == NULL)
goto error_return;
sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
local symbol in the global hash table. */
amt = strlen (sym_name) + 10;
new_name = bfd_malloc (amt);
- if (new_name == 0)
+ if (new_name == NULL)
goto error_return;
sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
local symbol in the global hash table. */
amt = strlen (sym_name) + 10;
new_name = bfd_malloc (amt);
- if (new_name == 0)
+ if (new_name == NULL)
goto error_return;
sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
sym_name = new_name;
if (internal_relocs == NULL)
goto error_return;
+ /* Scan for worst case alignment gap changes. Note that this logic
+ is not ideal; what we should do is run this scan for every
+ opcode/address range and adjust accordingly, but that's
+ expensive. Worst case is that for an alignment of N bytes, we
+ move by 2*N-N-1 bytes, assuming we have aligns of 1, 2, 4, 8, etc
+ all before it. Plus, this still doesn't cover cross-section
+ jumps with section alignment. */
+ irelend = internal_relocs + sec->reloc_count;
+ align_gap_adjustment = 0;
+ for (irel = internal_relocs; irel < irelend; irel++)
+ {
+ if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN)
+ {
+ bfd_vma adj = 1 << irel->r_addend;
+ bfd_vma aend = irel->r_offset;
+
+ aend = BFD_ALIGN (aend, 1 << irel->r_addend);
+ adj = 2 * adj - adj - 1;
+
+ /* Record the biggest adjustmnet. Skip any alignment at the
+ end of our section. */
+ if (align_gap_adjustment < adj
+ && aend < sec->output_section->vma + sec->output_offset + sec->size)
+ align_gap_adjustment = adj;
+ }
+ }
+
/* Walk through them looking for relaxing opportunities. */
irelend = internal_relocs + sec->reloc_count;
for (irel = internal_relocs; irel < irelend; irel++)
{
bfd_vma symval;
+ bfd_signed_vma jump_offset;
+ asection *sym_sec = NULL;
struct elf32_mn10300_link_hash_entry *h = NULL;
/* If this isn't something that can be relaxed, then ignore
if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
{
Elf_Internal_Sym *isym;
- asection *sym_sec = NULL;
const char *sym_name;
char *new_name;
- bfd_vma saved_addend;
/* A local symbol. */
isym = isymbuf + ELF32_R_SYM (irel->r_info);
&& ELF_ST_TYPE (isym->st_info) == STT_SECTION
&& sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE)
{
- saved_addend = irel->r_addend;
- symval = _bfd_elf_rela_local_sym (abfd, isym, &sym_sec, irel);
- symval += irel->r_addend;
- irel->r_addend = saved_addend;
+ symval = isym->st_value + irel->r_addend;
+ symval = _bfd_merged_section_offset (abfd, & sym_sec,
+ elf_section_data (sym_sec)->sec_info,
+ symval);
+ symval += sym_sec->output_section->vma + sym_sec->output_offset - irel->r_addend;
}
else
- {
- symval = (isym->st_value
- + sym_sec->output_section->vma
- + sym_sec->output_offset);
- }
+ symval = (isym->st_value
+ + sym_sec->output_section->vma
+ + sym_sec->output_offset);
/* Tack on an ID so we can uniquely identify this
local symbol in the global hash table. */
new_name = bfd_malloc ((bfd_size_type) strlen (sym_name) + 10);
- if (new_name == 0)
+ if (new_name == NULL)
goto error_return;
sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
sym_name = new_name;
regular reloc processing. */
continue;
+ /* Check for a reference to a discarded symbol and ignore it. */
+ if (h->root.root.u.def.section->output_section == NULL)
+ continue;
+
+ sym_sec = h->root.root.u.def.section->output_section;
+
symval = (h->root.root.u.def.value
+ h->root.root.u.def.section->output_section->vma
+ h->root.root.u.def.section->output_offset);
/* See if the value will fit in 16 bits, note the high value is
0x7fff + 2 as the target will be two bytes closer if we are
- able to relax. */
- if ((long) value < 0x8001 && (long) value > -0x8000)
+ able to relax, if it's in the same section. */
+ if (sec->output_section == sym_sec->output_section)
+ jump_offset = 0x8001;
+ else
+ jump_offset = 0x7fff;
+
+ /* Account for jumps across alignment boundaries using
+ align_gap_adjustment. */
+ if ((bfd_signed_vma) value < jump_offset - (bfd_signed_vma) align_gap_adjustment
+ && ((bfd_signed_vma) value > -0x8000 + (bfd_signed_vma) align_gap_adjustment))
{
unsigned char code;
case 0x93:
/* sp-based offsets are zero-extended. */
if (code >= 0x90 && code <= 0x93
- && (long)value < 0)
+ && (long) value < 0)
continue;
/* Note that we've changed the relocation contents, etc. */
/* mov imm16, an zero-extends the immediate. */
if (code == 0xdc
- && (long)value < 0)
+ && (long) value < 0)
continue;
/* Note that we've changed the relocation contents, etc. */
case 0xe3:
/* cmp imm16, an zero-extends the immediate. */
if (code == 0xdc
- && (long)value < 0)
+ && (long) value < 0)
continue;
/* So do sp-based offsets. */
if (code >= 0xb0 && code <= 0xb3
- && (long)value < 0)
+ && (long) value < 0)
continue;
/* Note that we've changed the relocation contents, etc. */