This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Add v850 linker relaxation
- From: Nick Clifton <nickc at redhat dot com>
- To: binutils at sources dot redhat dot com
- Date: 29 Aug 2002 07:50:00 +0100
- Subject: Add v850 linker relaxation
Hi Guys,
I am applying the attached patch which adds linker relaxation to the
v850 toolchain. It also removes the redundant references to the
v850ea architecture. The patch was developed a while ago and we now
have permission to release it to the free software community.
Cheers
Nick
bfd/ChangeLog
2002-08-28 Catherine Moore <clm@redhat.com>
* elf32-v850.c (v850_elf_reloc_map): Add new relocs.
(v850-elf-reloc): Don't resolve pc relative relocs.
(v850_elf_ignore_reloc): New routine.
(v850_elf_final_link_relocate): Handle new relocs.
(v850_elf_relax_delete_bytes ): New routine.
(v850_elf_relax_section): New routine.
(bfd_elf32_bfd_relax_section): Define.
(HOWTO): New entries for new relocs.
* reloc.c (BFD_RELOC_V850_LONGCALL): New reloc.
(BFD_RELOC_V850_LONGJUMP): New reloc.
(BFD_RELOC_V850_ALIGN): New reloc.
* archures.c: Remove redundant v850ea architecture.
* cpu-v850.c: Remove redundant v850ea support.
* libbfd.h: Regenerate.
* bfd-in2.h: Regenerated.
gas/ChangeLog
2000-08-28 Catherine Moore <clm@redhat.com>
* tc-v850.c (v850_relax): Declare.
(v850_longcode): New routine.
(v850_handle_align): New routine.
(md_pseudo_table): Add longcall and longjump.
(md_parse_option): Check for relax option.
(tc_gen_reloc): Handle BFD_RELOC_V850_LONGCALL,
BFD_RELOC_V850_LONGJUMP, and BFD_RELOC_V850_ALIGN.
(md_apply_fix3): Likewise.
(v850_force_relocation): Likewise.
(v850_comm): Change the current section.
(md_assemble): Ensure that the correct value is put in the
fixup.
(v850_sdata, v850_tdata, v850_zdata, v850_sbss, v850_tbss,
v850_zbss, v850_rosdata, v850_rozdata): Fix section book keeping.
Remove redundant v850ea support.
* tc-v850.h (HANDLE_ALIGN): Define.
(v850_handle_align): Declare.
* doc/c-v850.c: Document -mrelax, .longcall and .longjump.
include/elf/ChangeLog
2002-08-28 Catherine Moore <clm@redhat.com>
* elf/v850.h (R_V850_LONGCALL, R_V850_ALIGN,
R_V850_LONGJUMP): New relocations.
Index: bfd/archures.c
===================================================================
RCS file: /cvs/src/src/bfd/archures.c,v
retrieving revision 1.54
diff -c -3 -p -w -r1.54 archures.c
*** bfd/archures.c 28 Aug 2002 10:38:44 -0000 1.54
--- bfd/archures.c 29 Aug 2002 06:43:10 -0000
*************** DESCRIPTION
*** 236,242 ****
. bfd_arch_v850, {* NEC V850 *}
.#define bfd_mach_v850 0
.#define bfd_mach_v850e 'E'
- .#define bfd_mach_v850ea 'A'
. bfd_arch_arc, {* ARC Cores *}
.#define bfd_mach_arc_5 0
.#define bfd_mach_arc_6 1
--- 236,241 ----
Index: bfd/cpu-v850.c
===================================================================
RCS file: /cvs/src/src/bfd/cpu-v850.c,v
retrieving revision 1.5
diff -c -3 -p -w -r1.5 cpu-v850.c
*** bfd/cpu-v850.c 19 Sep 2001 05:33:12 -0000 1.5
--- bfd/cpu-v850.c 29 Aug 2002 06:43:12 -0000
***************
*** 1,5 ****
/* BFD support for the NEC V850 processor
! Copyright 1996, 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
--- 1,5 ----
/* BFD support for the NEC V850 processor
! Copyright 1996, 1997, 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
*************** scan (info, string)
*** 67,73 ****
switch (number)
{
case bfd_mach_v850e: arch = bfd_arch_v850; break;
- case bfd_mach_v850ea: arch = bfd_arch_v850; break;
default:
return false;
}
--- 67,72 ----
*************** scan (info, string)
*** 89,96 ****
static const bfd_arch_info_type arch_info_struct[] =
{
! N (bfd_mach_v850e, "v850e", false, & arch_info_struct[1]),
! N (bfd_mach_v850ea, "v850ea", false, NULL)
};
#undef NEXT
--- 88,94 ----
static const bfd_arch_info_type arch_info_struct[] =
{
! N (bfd_mach_v850e, "v850e", false, NULL)
};
#undef NEXT
Index: bfd/elf32-v850.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-v850.c,v
retrieving revision 1.24
diff -c -3 -p -w -r1.24 elf32-v850.c
*** bfd/elf32-v850.c 23 Jul 2002 12:29:32 -0000 1.24
--- bfd/elf32-v850.c 29 Aug 2002 06:43:12 -0000
*************** along with this program; if not, write t
*** 19,25 ****
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* XXX FIXME: This code is littered with 32bit int, 16bit short, 8bit char
! dependencies. As is the gas & simulator code or the v850. */
#include "bfd.h"
#include "sysdep.h"
--- 19,25 ----
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* XXX FIXME: This code is littered with 32bit int, 16bit short, 8bit char
! dependencies. As is the gas & simulator code for the v850. */
#include "bfd.h"
#include "sysdep.h"
*************** static asection * v850_elf_gc_mark_hook
*** 87,92 ****
--- 87,98 ----
PARAMS ((asection *, struct bfd_link_info *,
Elf_Internal_Rela *, struct elf_link_hash_entry *,
Elf_Internal_Sym *));
+ static bfd_reloc_status_type v850_elf_ignore_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+ static boolean v850_elf_relax_delete_bytes
+ PARAMS ((bfd *, asection *, bfd_vma, bfd_vma, int));
+ static boolean v850_elf_relax_section
+ PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *));
/* Note: It is REQUIRED that the 'type' value of each entry
in this array match the index of the entry in the array. */
*************** static reloc_howto_type v850_elf_howto_t
*** 467,472 ****
--- 473,523 ----
0, /* dst_mask */
false), /* pcrel_offset */
+ /* Indicates a .longcall pseudo-op. The compiler will generate a .longcall
+ pseudo-op when it finds a function call which can be relaxed. */
+ HOWTO (R_V850_LONGCALL, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ v850_elf_ignore_reloc, /* special_function */
+ "R_V850_LONGCALL", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* Indicates a .longjump pseudo-op. The compiler will generate a
+ .longjump pseudo-op when it finds a branch which can be relaxed. */
+ HOWTO (R_V850_LONGJUMP, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ v850_elf_ignore_reloc, /* special_function */
+ "R_V850_LONGJUMP", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ true), /* pcrel_offset */
+
+ HOWTO (R_V850_ALIGN, /* type */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ v850_elf_ignore_reloc, /* special_function */
+ "R_V850_ALIGN", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ true), /* pcrel_offset */
};
/* Map BFD reloc types to V850 ELF reloc types. */
*************** static const struct v850_elf_reloc_map v
*** 506,511 ****
--- 557,565 ----
{ BFD_RELOC_V850_CALLT_16_16_OFFSET, R_V850_CALLT_16_16_OFFSET },
{ BFD_RELOC_VTABLE_INHERIT, R_V850_GNU_VTINHERIT },
{ BFD_RELOC_VTABLE_ENTRY, R_V850_GNU_VTENTRY },
+ { BFD_RELOC_V850_LONGCALL, R_V850_LONGCALL },
+ { BFD_RELOC_V850_LONGJUMP, R_V850_LONGJUMP },
+ { BFD_RELOC_V850_ALIGN, R_V850_ALIGN },
};
*************** v850_elf_reloc (abfd, reloc, symbol, dat
*** 1297,1302 ****
--- 1351,1359 ----
/* Work out which section the relocation is targetted at and the
initial relocation command value. */
+ if (reloc->howto->pc_relative == true)
+ return bfd_reloc_ok;
+
/* Get symbol value. (Common symbols are special.) */
if (bfd_is_com_section (symbol->section))
relocation = 0;
*************** v850_elf_reloc (abfd, reloc, symbol, dat
*** 1336,1341 ****
--- 1393,1418 ----
return bfd_reloc_ok;
}
+ /* This function is used for relocs which are only used
+ for relaxing, which the linker should otherwise ignore. */
+
+ static bfd_reloc_status_type
+ v850_elf_ignore_reloc (abfd, reloc_entry, symbol, data, input_section,
+ output_bfd, error_message)
+ bfd * abfd ATTRIBUTE_UNUSED;
+ arelent * reloc_entry;
+ asymbol * symbol ATTRIBUTE_UNUSED;
+ PTR data ATTRIBUTE_UNUSED;
+ asection * input_section;
+ bfd * output_bfd;
+ char ** error_message ATTRIBUTE_UNUSED;
+ {
+ if (output_bfd != NULL)
+ reloc_entry->address += input_section->output_offset;
+
+ return bfd_reloc_ok;
+ }
+
static boolean
v850_elf_is_local_label_name (abfd, name)
bfd * abfd ATTRIBUTE_UNUSED;
*************** v850_elf_final_link_relocate (howto, inp
*** 1500,1505 ****
--- 1577,1585 ----
case R_V850_NONE:
case R_V850_GNU_VTINHERIT:
case R_V850_GNU_VTENTRY:
+ case R_V850_LONGCALL:
+ case R_V850_LONGJUMP:
+ case R_V850_ALIGN:
return bfd_reloc_ok;
default:
*************** v850_elf_object_p (abfd)
*** 1770,1776 ****
default:
case E_V850_ARCH: (void) bfd_default_set_arch_mach (abfd, bfd_arch_v850, 0); break;
case E_V850E_ARCH: (void) bfd_default_set_arch_mach (abfd, bfd_arch_v850, bfd_mach_v850e); break;
- case E_V850EA_ARCH: (void) bfd_default_set_arch_mach (abfd, bfd_arch_v850, bfd_mach_v850ea); break;
}
return true;
}
--- 1850,1855 ----
*************** v850_elf_final_write_processing (abfd, l
*** 1789,1795 ****
default:
case 0: val = E_V850_ARCH; break;
case bfd_mach_v850e: val = E_V850E_ARCH; break;
- case bfd_mach_v850ea: val = E_V850EA_ARCH; break;
}
elf_elfheader (abfd)->e_flags &=~ EF_V850_ARCH;
--- 1868,1873 ----
*************** v850_elf_print_private_bfd_data (abfd, p
*** 1882,1888 ****
default:
case E_V850_ARCH: fprintf (file, _("v850 architecture")); break;
case E_V850E_ARCH: fprintf (file, _("v850e architecture")); break;
- case E_V850EA_ARCH: fprintf (file, _("v850ea architecture")); break;
}
fputc ('\n', file);
--- 1960,1965 ----
*************** v850_elf_fake_sections (abfd, hdr, sec)
*** 2167,2172 ****
--- 2244,3182 ----
return true;
}
+ /* Delete some bytes from a section while relaxing. */
+
+ static boolean
+ v850_elf_relax_delete_bytes (abfd, sec, addr, toaddr, count)
+ bfd * abfd;
+ asection * sec;
+ bfd_vma addr;
+ bfd_vma toaddr;
+ int count;
+ {
+ Elf_Internal_Shdr * symtab_hdr;
+ Elf32_External_Sym * extsyms;
+ Elf32_External_Sym * esym;
+ Elf32_External_Sym * esymend;
+ int index;
+ unsigned int sec_shndx;
+ bfd_byte * contents;
+ Elf_Internal_Rela * irel;
+ Elf_Internal_Rela * irelend;
+ struct elf_link_hash_entry * sym_hash;
+ Elf_Internal_Shdr * shndx_hdr;
+ Elf_External_Sym_Shndx * shndx;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
+
+ sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+
+ contents = elf_section_data (sec)->this_hdr.contents;
+
+ /* The deletion must stop at the next ALIGN reloc for an alignment
+ power larger than the number of bytes we are deleting. */
+
+ /* Actually delete the bytes. */
+ #if (DEBUG_RELAX & 2)
+ fprintf (stderr, "relax_delete: contents: sec: %s %p .. %p %x\n",
+ sec->name, addr, toaddr, count );
+ #endif
+ memmove (contents + addr, contents + addr + count,
+ toaddr - addr - count);
+ memset (contents + toaddr-count, 0, count);
+
+ /* Adjust all the relocs. */
+ irel = elf_section_data (sec)->relocs;
+ irelend = irel + sec->reloc_count;
+ shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+ shndx = (Elf_External_Sym_Shndx *) shndx_hdr->contents;
+
+ for (; irel < irelend; irel++)
+ {
+ bfd_vma raddr, paddr, symval;
+ Elf_Internal_Sym isym;
+
+ /* Get the new reloc address. */
+ raddr = irel->r_offset;
+ if ((raddr >= (addr + count) && raddr < toaddr))
+ irel->r_offset -= count;
+
+ if (raddr >= addr && raddr < addr + count)
+ {
+ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+ (int) R_V850_NONE);
+ continue;
+ }
+
+ if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_ALIGN)
+ continue;
+
+ bfd_elf32_swap_symbol_in (abfd,
+ extsyms + ELF32_R_SYM (irel->r_info),
+ shndx ? shndx + ELF32_R_SYM (irel->r_info) : NULL,
+ & isym);
+
+ if (isym.st_shndx != sec_shndx)
+ continue;
+
+ /* Get the value of the symbol referred to by the reloc. */
+ if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
+ {
+ symval = isym.st_value;
+ #if (DEBUG_RELAX & 2)
+ {
+ char * name = bfd_elf_string_from_elf_section
+ (abfd, symtab_hdr->sh_link, isym.st_name);
+ fprintf (stderr,
+ "relax_delete: local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
+ sec->name, name, isym.st_name,
+ sec->output_section->vma, sec->output_offset,
+ isym.st_value, irel->r_addend);
+ }
+ #endif
+ }
+ else
+ {
+ unsigned long indx;
+ struct elf_link_hash_entry * h;
+
+ /* An external symbol. */
+ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+
+ h = elf_sym_hashes (abfd) [indx];
+ BFD_ASSERT (h != NULL);
+
+ symval = h->root.u.def.value;
+ #if (DEBUG_RELAX & 2)
+ fprintf (stderr,
+ "relax_delete: defined: sec: %s, name: %s, value: %x + %x + %x addend %x\n",
+ sec->name, h->root.root.string, h->root.u.def.value,
+ sec->output_section->vma, sec->output_offset, irel->r_addend);
+ #endif
+ }
+
+ paddr = symval + irel->r_addend;
+
+ if ( (symval >= addr + count && symval < toaddr)
+ && (paddr < addr + count || paddr >= toaddr))
+ irel->r_addend += count;
+ else if ( (symval < addr + count || symval >= toaddr)
+ && (paddr >= addr + count && paddr < toaddr))
+ irel->r_addend -= count;
+ }
+
+ /* Adjust the local symbols defined in this section. */
+ esym = extsyms;
+ esymend = esym + symtab_hdr->sh_info;
+
+ for (; esym < esymend; esym++, shndx = (shndx ? shndx + 1 : NULL))
+ {
+ Elf_Internal_Sym isym;
+
+ bfd_elf32_swap_symbol_in (abfd, esym, shndx, & isym);
+
+ if (isym.st_shndx == sec_shndx
+ && isym.st_value >= addr + count
+ && isym.st_value < toaddr)
+ {
+ isym.st_value -= count;
+
+ if (isym.st_value + isym.st_size >= toaddr)
+ isym.st_size += count;
+
+ bfd_elf32_swap_symbol_out (abfd, & isym, shndx, esym);
+ }
+ else if (isym.st_shndx == sec_shndx
+ && isym.st_value < addr + count)
+ {
+ if (isym.st_value+isym.st_size >= addr + count
+ && isym.st_value+isym.st_size < toaddr)
+ isym.st_size -= count;
+
+ if (isym.st_value >= addr
+ && isym.st_value < addr + count)
+ isym.st_value = addr;
+
+ bfd_elf32_swap_symbol_out (abfd, & isym, shndx, esym);
+ }
+ }
+
+ /* Now adjust the global symbols defined in this section. */
+ esym = extsyms + symtab_hdr->sh_info;
+ esymend = extsyms + (symtab_hdr->sh_size / sizeof (Elf32_External_Sym));
+
+ for (index = 0; esym < esymend; esym ++, index ++)
+ {
+ Elf_Internal_Sym isym;
+
+ bfd_elf32_swap_symbol_in (abfd, esym, shndx, & isym);
+ sym_hash = elf_sym_hashes (abfd) [index];
+
+ if (isym.st_shndx == sec_shndx
+ && ((sym_hash)->root.type == bfd_link_hash_defined
+ || (sym_hash)->root.type == bfd_link_hash_defweak)
+ && (sym_hash)->root.u.def.section == sec
+ && (sym_hash)->root.u.def.value >= addr + count
+ && (sym_hash)->root.u.def.value < toaddr)
+ {
+ if ((sym_hash)->root.u.def.value + isym.st_size >= toaddr)
+ {
+ isym.st_size += count;
+ bfd_elf32_swap_symbol_out (abfd, & isym, shndx, esym);
+ }
+
+ (sym_hash)->root.u.def.value -= count;
+ }
+ else if (isym.st_shndx == sec_shndx
+ && ((sym_hash)->root.type == bfd_link_hash_defined
+ || (sym_hash)->root.type == bfd_link_hash_defweak)
+ && (sym_hash)->root.u.def.section == sec
+ && (sym_hash)->root.u.def.value < addr + count)
+ {
+ if ((sym_hash)->root.u.def.value+isym.st_size >= addr + count
+ && (sym_hash)->root.u.def.value+isym.st_size < toaddr)
+ isym.st_size -= count;
+
+ if ((sym_hash)->root.u.def.value >= addr
+ && (sym_hash)->root.u.def.value < addr + count)
+ (sym_hash)->root.u.def.value = addr;
+
+ bfd_elf32_swap_symbol_out (abfd, & isym, shndx, esym);
+ }
+
+ if (shndx)
+ ++ shndx;
+ }
+
+ return true;
+ }
+
+ #define NOP_OPCODE (0x0000)
+ #define MOVHI 0x0640 /* 4byte */
+ #define MOVHI_MASK 0x07e0
+ #define MOVHI_R1(insn) ((insn) & 0x1f) /* 4byte */
+ #define MOVHI_R2(insn) ((insn) >> 11)
+ #define MOVEA 0x0620 /* 2byte */
+ #define MOVEA_MASK 0x07e0
+ #define MOVEA_R1(insn) ((insn) & 0x1f)
+ #define MOVEA_R2(insn) ((insn) >> 11)
+ #define JARL_4 0x00040780 /* 4byte */
+ #define JARL_4_MASK 0xFFFF07FF
+ #define JARL_R2(insn) (int)(((insn) & (~JARL_4_MASK)) >> 11)
+ #define ADD_I 0x0240 /* 2byte */
+ #define ADD_I_MASK 0x07e0
+ #define ADD_I5(insn) ((((insn) & 0x001f) << 11) >> 11) /* 2byte */
+ #define ADD_R2(insn) ((insn) >> 11)
+ #define JMP_R 0x0060 /* 2byte */
+ #define JMP_R_MASK 0xFFE0
+ #define JMP_R1(insn) ((insn) & 0x1f)
+
+ static boolean
+ v850_elf_relax_section (abfd, sec, link_info, again)
+ bfd * abfd;
+ asection * sec;
+ struct bfd_link_info * link_info;
+ boolean * again;
+ {
+ Elf_Internal_Shdr * symtab_hdr;
+ Elf_Internal_Rela * internal_relocs;
+ Elf_Internal_Rela * free_relocs = NULL;
+ Elf_Internal_Rela * irel;
+ Elf_Internal_Rela * irelend;
+ Elf_Internal_Rela * irelalign = NULL;
+ bfd_byte * contents = NULL;
+ bfd_byte * free_contents = NULL;
+ Elf32_External_Sym * extsyms = NULL;
+ Elf32_External_Sym * free_extsyms = NULL;
+ bfd_vma addr = 0;
+ bfd_vma toaddr;
+ int align_pad_size = 0;
+ Elf_Internal_Shdr * shndx_hdr = NULL;
+ Elf_External_Sym_Shndx * shndx_buf = NULL;
+
+ * again = false;
+
+ if (link_info->relocateable
+ || (sec->flags & SEC_RELOC) == 0
+ || sec->reloc_count == 0)
+ return true;
+
+ /* If this is the first time we have been called
+ for this section, initialize the cooked size. */
+ if (sec->_cooked_size == 0)
+ sec->_cooked_size = sec->_raw_size;
+
+ symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
+
+ internal_relocs = (_bfd_elf32_link_read_relocs
+ (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
+ link_info->keep_memory));
+ if (internal_relocs == NULL)
+ goto error_return;
+ if (! link_info->keep_memory)
+ free_relocs = internal_relocs;
+
+ irelend = internal_relocs + sec->reloc_count;
+
+ while (addr < sec->_cooked_size)
+ {
+ toaddr = sec->_cooked_size;
+
+ for (irel = internal_relocs; irel < irelend; irel ++)
+ if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_ALIGN
+ && irel->r_offset > addr
+ && irel->r_offset < toaddr)
+ toaddr = irel->r_offset;
+
+ #ifdef DEBUG_RELAX
+ fprintf (stderr, "relax region 0x%x to 0x%x align pad %d\n",
+ addr, toaddr, align_pad_size);
+ #endif
+ if (irelalign)
+ {
+ bfd_vma alignto;
+ bfd_vma alignmoveto;
+
+ alignmoveto = BFD_ALIGN (addr - align_pad_size, 1 << irelalign->r_addend);
+ alignto = BFD_ALIGN (addr, 1 << irelalign->r_addend);
+
+ if (alignmoveto < alignto)
+ {
+ unsigned int i;
+
+ align_pad_size = alignto - alignmoveto;
+ #ifdef DEBUG_RELAX
+ fprintf (stderr, "relax move region 0x%x to 0x%x delete size 0x%x\n",
+ alignmoveto, toaddr, align_pad_size);
+ #endif
+ if (!v850_elf_relax_delete_bytes (abfd, sec, alignmoveto,
+ toaddr, align_pad_size))
+ goto error_return;
+
+ for (i = BFD_ALIGN (toaddr - align_pad_size, 1);
+ (i + 1) < toaddr; i += 2)
+ bfd_put_16 (abfd, NOP_OPCODE, contents + i);
+
+ addr = alignmoveto;
+ }
+ else
+ align_pad_size = 0;
+ }
+
+ for (irel = internal_relocs; irel < irelend; irel++)
+ {
+ bfd_vma laddr;
+ bfd_vma addend;
+ bfd_vma symval;
+ int insn[5];
+ int no_match = -1;
+ Elf_Internal_Rela * hi_irelfn;
+ Elf_Internal_Rela * lo_irelfn;
+ Elf_Internal_Rela * irelcall;
+ bfd_signed_vma foff;
+
+ if (! (irel->r_offset >= addr && irel->r_offset < toaddr
+ && (ELF32_R_TYPE (irel->r_info) == (int) R_V850_LONGCALL
+ || ELF32_R_TYPE (irel->r_info) == (int) R_V850_LONGJUMP)))
+ continue;
+
+ #ifdef DEBUG_RELAX
+ fprintf (stderr, "relax check r_info 0x%x r_offset 0x%x r_addend 0x%x\n",
+ irel->r_info,
+ irel->r_offset,
+ irel->r_addend );
+ #endif
+
+ /* Get the section contents. */
+ if (contents == NULL)
+ {
+ if (elf_section_data (sec)->this_hdr.contents != NULL)
+ contents = elf_section_data (sec)->this_hdr.contents;
+ else
+ {
+ contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
+ if (contents == NULL)
+ goto error_return;
+
+ free_contents = contents;
+
+ if (! bfd_get_section_contents (abfd, sec, contents,
+ (file_ptr) 0, sec->_raw_size))
+ goto error_return;
+ }
+ }
+
+ /* Read this BFD's symbols if we haven't done so already. */
+ if (extsyms == NULL)
+ {
+ /* Get cached copy if it exists. */
+ if (symtab_hdr->contents != NULL)
+ extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
+ else
+ {
+ /* Go get them off disk. */
+ bfd_size_type amt;
+
+ amt = symtab_hdr->sh_info;
+ amt *= sizeof (Elf32_External_Sym);
+ extsyms = (Elf32_External_Sym *) bfd_malloc (amt);
+ if (extsyms == NULL)
+ goto error_return;
+ free_extsyms = extsyms;
+ if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
+ || bfd_bread ((PTR) extsyms, amt, abfd) != amt)
+ goto error_return;
+ }
+
+ if (shndx_hdr->sh_size != 0)
+ {
+ bfd_size_type amt;
+
+ amt = symtab_hdr->sh_info;
+ amt *= sizeof (Elf_External_Sym_Shndx);
+ shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+ if (shndx_buf == NULL)
+ goto error_return;
+ if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
+ || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt)
+ goto error_return;
+ }
+ }
+
+ laddr = irel->r_offset;
+
+ if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_LONGCALL)
+ {
+ /* Check code for -mlong-calls output. */
+ if (laddr + 16 <= (bfd_vma) sec->_raw_size)
+ {
+ insn[0] = bfd_get_16 (abfd, contents + laddr);
+ insn[1] = bfd_get_16 (abfd, contents + laddr + 4);
+ insn[2] = bfd_get_32 (abfd, contents + laddr + 8);
+ insn[3] = bfd_get_16 (abfd, contents + laddr + 12);
+ insn[4] = bfd_get_16 (abfd, contents + laddr + 14);
+
+ if ((insn[0] & MOVHI_MASK) != MOVHI
+ || MOVHI_R1 (insn[0]) != 0)
+ no_match = 0;
+
+ if (no_match < 0
+ && ((insn[1] & MOVEA_MASK) != MOVEA
+ || MOVHI_R2 (insn[0]) != MOVEA_R1 (insn[1])))
+ no_match = 1;
+
+ if (no_match < 0
+ && (insn[2] & JARL_4_MASK) != JARL_4)
+ no_match = 2;
+
+ if (no_match < 0
+ && ((insn[3] & ADD_I_MASK) != ADD_I
+ || ADD_I5 (insn[3]) != 4
+ || JARL_R2 (insn[2]) != ADD_R2 (insn[3])))
+ no_match = 3;
+
+ if (no_match < 0
+ && ((insn[4] & JMP_R_MASK) != JMP_R
+ || MOVEA_R2 (insn[1]) != JMP_R1 (insn[4])))
+ no_match = 4;
+ }
+ else
+ {
+ ((*_bfd_error_handler)
+ ("%s: 0x%lx: warning: R_V850_LONGCALL points to unrecognized insns",
+ bfd_get_filename (abfd), (unsigned long) irel->r_offset));
+
+ continue;
+ }
+
+ if (no_match >= 0)
+ {
+ ((*_bfd_error_handler)
+ ("%s: 0x%lx: warning: R_V850_LONGCALL points to unrecognized insn 0x%x",
+ bfd_get_filename (abfd), (unsigned long) irel->r_offset+no_match, insn[no_match]));
+
+ continue;
+ }
+
+ /* Get the reloc for the address from which the register is
+ being loaded. This reloc will tell us which function is
+ actually being called. */
+ for (hi_irelfn = internal_relocs; hi_irelfn < irelend; hi_irelfn ++)
+ if (hi_irelfn->r_offset == laddr + 2
+ && ELF32_R_TYPE (hi_irelfn->r_info)
+ == (int) R_V850_HI16_S)
+ break;
+
+ for (lo_irelfn = internal_relocs; lo_irelfn < irelend; lo_irelfn ++)
+ if (lo_irelfn->r_offset == laddr + 6
+ && ELF32_R_TYPE (lo_irelfn->r_info)
+ == (int) R_V850_LO16)
+ break;
+
+ for (irelcall = internal_relocs; irelcall < irelend; irelcall ++)
+ if (irelcall->r_offset == laddr + 8
+ && ELF32_R_TYPE (irelcall->r_info)
+ == (int) R_V850_22_PCREL)
+ break;
+
+ if ( hi_irelfn == irelend
+ || lo_irelfn == irelend
+ || irelcall == irelend)
+ {
+ ((*_bfd_error_handler)
+ ("%s: 0x%lx: warning: R_V850_LONGCALL points to unrecognized reloc",
+ bfd_get_filename (abfd), (unsigned long) irel->r_offset ));
+
+ continue;
+ }
+
+ if (ELF32_R_SYM (irelcall->r_info) < symtab_hdr->sh_info)
+ {
+ unsigned int r_index;
+ Elf_Internal_Sym isym;
+ asection * sym_sec;
+ Elf32_External_Sym * esym;
+ Elf_External_Sym_Shndx * shndx;
+
+ /* A local symbol. */
+ r_index = ELF32_R_SYM (irelcall->r_info);
+ esym = extsyms + r_index;
+ shndx = shndx_buf + (shndx_buf ? r_index : 0);
+ bfd_elf32_swap_symbol_in (abfd, esym, shndx, & isym);
+
+ if (isym.st_shndx == SHN_UNDEF)
+ sym_sec = bfd_und_section_ptr;
+ else if (isym.st_shndx == SHN_ABS)
+ sym_sec = bfd_abs_section_ptr;
+ else if (isym.st_shndx == SHN_COMMON)
+ sym_sec = bfd_com_section_ptr;
+ else
+ sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx);
+ symval = isym.st_value;
+ }
+ else
+ {
+ unsigned long indx;
+ struct elf_link_hash_entry * h;
+
+ /* An external symbol. */
+ indx = ELF32_R_SYM (irelcall->r_info) - symtab_hdr->sh_info;
+ h = elf_sym_hashes (abfd)[indx];
+ BFD_ASSERT (h != NULL);
+
+ if ( h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+ /* This appears to be a reference to an undefined
+ symbol. Just ignore it--it will be caught by the
+ regular reloc processing. */
+ continue;
+
+ symval = h->root.u.def.value;
+ }
+
+ if (symval + irelcall->r_addend != irelcall->r_offset + 4)
+ {
+ ((*_bfd_error_handler)
+ ("%s: 0x%lx: warning: R_V850_LONGCALL points to unrecognized reloc 0x%lx",
+ bfd_get_filename (abfd), (unsigned long) irel->r_offset, irelcall->r_offset ));
+
+ continue;
+ }
+
+ /* Get the value of the symbol referred to by the reloc. */
+ if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info)
+ {
+ unsigned int r_index;
+ Elf_Internal_Sym isym;
+ asection * sym_sec;
+ Elf32_External_Sym * esym;
+ Elf_External_Sym_Shndx * shndx;
+
+ /* A local symbol. */
+ r_index = ELF32_R_SYM (irel->r_info);
+ esym = extsyms + r_index;
+ shndx = shndx_buf + (shndx_buf ? r_index : 0);
+ bfd_elf32_swap_symbol_in (abfd, esym, shndx, & isym);
+
+ if (isym.st_shndx == SHN_UNDEF)
+ sym_sec = bfd_und_section_ptr;
+ else if (isym.st_shndx == SHN_ABS)
+ sym_sec = bfd_abs_section_ptr;
+ else if (isym.st_shndx == SHN_COMMON)
+ sym_sec = bfd_com_section_ptr;
+ else
+ sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx);
+ symval = (isym.st_value
+ + sym_sec->output_section->vma
+ + sym_sec->output_offset);
+ }
+ else
+ {
+ unsigned long indx;
+ struct elf_link_hash_entry * h;
+
+ /* An external symbol. */
+ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+ h = elf_sym_hashes (abfd)[indx];
+ BFD_ASSERT (h != NULL);
+
+ if ( h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+ /* This appears to be a reference to an undefined
+ symbol. Just ignore it--it will be caught by the
+ regular reloc processing. */
+ continue;
+
+ symval = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ }
+
+ addend = irel->r_addend;
+
+ foff = (symval + addend
+ - (irel->r_offset
+ + sec->output_section->vma
+ + sec->output_offset
+ + 4));
+ #ifdef DEBUG_RELAX
+ fprintf (stderr, "relax longcall r_offset 0x%x ptr 0x%x symbol 0x%x addend 0x%x distance 0x%x\n",
+ irel->r_offset,
+ (irel->r_offset
+ + sec->output_section->vma
+ + sec->output_offset),
+ symval, addend, foff);
+ #endif
+
+ if (foff < -0x100000 || foff >= 0x100000)
+ /* After all that work, we can't shorten this function call. */
+ continue;
+
+ /* For simplicity of coding, we are going to modify the section
+ contents, the section relocs, and the BFD symbol table. We
+ must tell the rest of the code not to free up this
+ information. It would be possible to instead create a table
+ of changes which have to be made, as is done in coff-mips.c;
+ that would be more work, but would require less memory when
+ the linker is run. */
+ elf_section_data (sec)->relocs = internal_relocs;
+ free_relocs = NULL;
+
+ elf_section_data (sec)->this_hdr.contents = contents;
+ free_contents = NULL;
+
+ symtab_hdr->contents = (bfd_byte *) extsyms;
+ free_extsyms = NULL;
+
+ /* Replace the long call with a jarl. */
+ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_V850_22_PCREL);
+
+ addend = 0;
+
+ if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info)
+ /* If this needs to be changed because of future relaxing,
+ it will be handled here like other internal IND12W
+ relocs. */
+ bfd_put_32 (abfd,
+ 0x00000780 | (JARL_R2 (insn[2])<<11) | ((addend << 16) & 0xffff) | ((addend >> 16) & 0xf),
+ contents + irel->r_offset);
+ else
+ /* We can't fully resolve this yet, because the external
+ symbol value may be changed by future relaxing.
+ We let the final link phase handle it. */
+ bfd_put_32 (abfd, 0x00000780 | (JARL_R2 (insn[2])<<11),
+ contents + irel->r_offset);
+
+ hi_irelfn->r_info =
+ ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_V850_NONE);
+ lo_irelfn->r_info =
+ ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_V850_NONE);
+ irelcall->r_info =
+ ELF32_R_INFO (ELF32_R_SYM (irelcall->r_info), R_V850_NONE);
+
+ if (! v850_elf_relax_delete_bytes (abfd, sec,
+ irel->r_offset + 4, toaddr, 12))
+ goto error_return;
+
+ align_pad_size += 12;
+ }
+ else if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_LONGJUMP)
+ {
+ /* Check code for -mlong-jumps output. */
+ if (laddr + 10 <= (bfd_vma) sec->_raw_size)
+ {
+ insn[0] = bfd_get_16 (abfd, contents + laddr);
+ insn[1] = bfd_get_16 (abfd, contents + laddr + 4);
+ insn[2] = bfd_get_16 (abfd, contents + laddr + 8);
+
+ if ((insn[0] & MOVHI_MASK) != MOVHI
+ || MOVHI_R1 (insn[0]) != 0)
+ no_match = 0;
+
+ if (no_match < 0
+ && ((insn[1] & MOVEA_MASK) != MOVEA
+ || MOVHI_R2 (insn[0]) != MOVEA_R1 (insn[1])))
+ no_match = 1;
+
+ if (no_match < 0
+ && ((insn[2] & JMP_R_MASK) != JMP_R
+ || MOVEA_R2 (insn[1]) != JMP_R1 (insn[2])))
+ no_match = 4;
+ }
+ else
+ {
+ ((*_bfd_error_handler)
+ ("%s: 0x%lx: warning: R_V850_LONGJUMP points to unrecognized insns",
+ bfd_get_filename (abfd), (unsigned long) irel->r_offset));
+
+ continue;
+ }
+
+ if (no_match >= 0)
+ {
+ ((*_bfd_error_handler)
+ ("%s: 0x%lx: warning: R_V850_LONGJUMP points to unrecognized insn 0x%x",
+ bfd_get_filename (abfd), (unsigned long) irel->r_offset+no_match, insn[no_match]));
+
+ continue;
+ }
+
+ /* Get the reloc for the address from which the register is
+ being loaded. This reloc will tell us which function is
+ actually being called. */
+ for (hi_irelfn = internal_relocs; hi_irelfn < irelend; hi_irelfn ++)
+ if (hi_irelfn->r_offset == laddr + 2
+ && ELF32_R_TYPE (hi_irelfn->r_info) == (int) R_V850_HI16_S)
+ break;
+
+ for (lo_irelfn = internal_relocs; lo_irelfn < irelend; lo_irelfn ++)
+ if (lo_irelfn->r_offset == laddr + 6
+ && ELF32_R_TYPE (lo_irelfn->r_info) == (int) R_V850_LO16)
+ break;
+
+ if ( hi_irelfn == irelend
+ || lo_irelfn == irelend)
+ {
+ ((*_bfd_error_handler)
+ ("%s: 0x%lx: warning: R_V850_LONGJUMP points to unrecognized reloc",
+ bfd_get_filename (abfd), (unsigned long) irel->r_offset ));
+
+ continue;
+ }
+
+ /* Get the value of the symbol referred to by the reloc. */
+ if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info)
+ {
+ unsigned int r_index;
+ Elf_Internal_Sym isym;
+ asection * sym_sec;
+ Elf32_External_Sym * esym;
+ Elf_External_Sym_Shndx * shndx;
+
+ /* A local symbol. */
+ r_index = ELF32_R_SYM (irel->r_info);
+ esym = extsyms + r_index;
+ shndx = shndx_buf + (shndx_buf ? r_index : 0);
+ bfd_elf32_swap_symbol_in (abfd, esym, shndx, & isym);
+
+ if (isym.st_shndx == SHN_UNDEF)
+ sym_sec = bfd_und_section_ptr;
+ else if (isym.st_shndx == SHN_ABS)
+ sym_sec = bfd_abs_section_ptr;
+ else if (isym.st_shndx == SHN_COMMON)
+ sym_sec = bfd_com_section_ptr;
+ else
+ sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx);
+ symval = (isym.st_value
+ + sym_sec->output_section->vma
+ + sym_sec->output_offset);
+ #ifdef DEBUG_RELAX
+ {
+ char * name = bfd_elf_string_from_elf_section
+ (abfd, symtab_hdr->sh_link, isym.st_name);
+
+ fprintf (stderr, "relax long jump local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
+ sym_sec->name, name, isym.st_name,
+ sym_sec->output_section->vma, sym_sec->output_offset,
+ isym.st_value, irel->r_addend);
+ }
+ #endif
+ }
+ else
+ {
+ unsigned long indx;
+ struct elf_link_hash_entry * h;
+
+ /* An external symbol. */
+ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+ h = elf_sym_hashes (abfd)[indx];
+ BFD_ASSERT (h != NULL);
+
+ if ( h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+ /* This appears to be a reference to an undefined
+ symbol. Just ignore it--it will be caught by the
+ regular reloc processing. */
+ continue;
+
+ symval = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ #ifdef DEBUG_RELAX
+ fprintf (stderr,
+ "relax longjump defined: sec: %s, name: %s, value: %x + %x + %x addend %x\n",
+ sec->name, h->root.root.string, h->root.u.def.value,
+ sec->output_section->vma, sec->output_offset, irel->r_addend);
+ #endif
+ }
+
+ addend = irel->r_addend;
+
+ foff = (symval + addend
+ - (irel->r_offset
+ + sec->output_section->vma
+ + sec->output_offset
+ + 4));
+ #ifdef DEBUG_RELAX
+ fprintf (stderr, "relax longjump r_offset 0x%x ptr 0x%x symbol 0x%x addend 0x%x distance 0x%x\n",
+ irel->r_offset,
+ (irel->r_offset
+ + sec->output_section->vma
+ + sec->output_offset),
+ symval, addend, foff);
+ #endif
+ if (foff < -0x100000 || foff >= 0x100000)
+ /* After all that work, we can't shorten this function call. */
+ continue;
+
+ /* For simplicity of coding, we are going to modify the section
+ contents, the section relocs, and the BFD symbol table. We
+ must tell the rest of the code not to free up this
+ information. It would be possible to instead create a table
+ of changes which have to be made, as is done in coff-mips.c;
+ that would be more work, but would require less memory when
+ the linker is run. */
+ elf_section_data (sec)->relocs = internal_relocs;
+ free_relocs = NULL;
+
+ elf_section_data (sec)->this_hdr.contents = contents;
+ free_contents = NULL;
+
+ symtab_hdr->contents = (bfd_byte *) extsyms;
+ free_extsyms = NULL;
+
+ if (foff < -0x100 || foff >= 0x100)
+ {
+ /* Replace the long jump with a jr. */
+
+ irel->r_info =
+ ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_V850_22_PCREL);
+
+ irel->r_addend = addend;
+ addend = 0;
+
+ if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info)
+ /* If this needs to be changed because of future relaxing,
+ it will be handled here like other internal IND12W
+ relocs. */
+ bfd_put_32 (abfd,
+ 0x00000780 | ((addend << 15) & 0xffff0000) | ((addend >> 17) & 0xf),
+ contents + irel->r_offset);
+ else
+ /* We can't fully resolve this yet, because the external
+ symbol value may be changed by future relaxing.
+ We let the final link phase handle it. */
+ bfd_put_32 (abfd, 0x00000780, contents + irel->r_offset);
+
+ hi_irelfn->r_info =
+ ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_V850_NONE);
+ lo_irelfn->r_info =
+ ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_V850_NONE);
+ if (!v850_elf_relax_delete_bytes (abfd, sec,
+ irel->r_offset + 4, toaddr, 6))
+ goto error_return;
+
+ align_pad_size += 6;
+ }
+ else
+ {
+ /* Replace the long jump with a br. */
+
+ irel->r_info =
+ ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_V850_9_PCREL);
+
+ irel->r_addend = addend;
+ addend = 0;
+
+ if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info)
+ /* If this needs to be changed because of future relaxing,
+ it will be handled here like other internal IND12W
+ relocs. */
+ bfd_put_16 (abfd,
+ 0x0585 | ((addend << 10) & 0xf800) | ((addend << 3) & 0x0070),
+ contents + irel->r_offset);
+ else
+ /* We can't fully resolve this yet, because the external
+ symbol value may be changed by future relaxing.
+ We let the final link phase handle it. */
+ bfd_put_16 (abfd, 0x0585, contents + irel->r_offset);
+
+ hi_irelfn->r_info =
+ ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_V850_NONE);
+ lo_irelfn->r_info =
+ ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_V850_NONE);
+ if (!v850_elf_relax_delete_bytes (abfd, sec,
+ irel->r_offset + 2, toaddr, 8))
+ goto error_return;
+
+ align_pad_size += 8;
+ }
+ }
+ }
+
+ irelalign = NULL;
+ for (irel = internal_relocs; irel < irelend; irel++)
+ {
+ if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_ALIGN
+ && irel->r_offset == toaddr)
+ {
+ irel->r_offset -= align_pad_size;
+
+ if (irelalign == NULL || irelalign->r_addend > irel->r_addend)
+ irelalign = irel;
+ }
+ }
+
+ addr = toaddr;
+ }
+
+ if (!irelalign)
+ {
+ #ifdef DEBUG_RELAX
+ fprintf (stderr, "relax pad %d shorten %d -> %d\n",
+ align_pad_size,
+ sec->_cooked_size,
+ sec->_cooked_size - align_pad_size);
+ #endif
+ sec->_cooked_size -= align_pad_size;
+ }
+
+ return true;
+
+ error_return:
+ if (free_relocs != NULL)
+ free (free_relocs);
+
+ if (free_contents != NULL)
+ free (free_contents);
+
+ if (free_extsyms != NULL)
+ free (free_extsyms);
+
+ return false;
+ }
+
#define TARGET_LITTLE_SYM bfd_elf32_v850_vec
#define TARGET_LITTLE_NAME "elf32-v850"
#define ELF_ARCH bfd_arch_v850
*************** v850_elf_fake_sections (abfd, hdr, sec)
*** 2198,2203 ****
--- 3208,3214 ----
#define bfd_elf32_bfd_merge_private_bfd_data v850_elf_merge_private_bfd_data
#define bfd_elf32_bfd_set_private_flags v850_elf_set_private_flags
#define bfd_elf32_bfd_print_private_bfd_data v850_elf_print_private_bfd_data
+ #define bfd_elf32_bfd_relax_section v850_elf_relax_section
#define elf_symbol_leading_char '_'
Index: bfd/reloc.c
===================================================================
RCS file: /cvs/src/src/bfd/reloc.c,v
retrieving revision 1.64
diff -c -3 -p -w -r1.64 reloc.c
*** bfd/reloc.c 13 Aug 2002 20:08:49 -0000 1.64
--- bfd/reloc.c 29 Aug 2002 06:43:13 -0000
*************** ENUM
*** 2788,2795 ****
BFD_RELOC_V850_CALLT_16_16_OFFSET
ENUMDOC
This is a 16 bit offset from the call table base pointer.
! COMMENT
!
ENUM
BFD_RELOC_MN10300_32_PCREL
ENUMDOC
--- 2788,2806 ----
BFD_RELOC_V850_CALLT_16_16_OFFSET
ENUMDOC
This is a 16 bit offset from the call table base pointer.
! ENUM
! BFD_RELOC_V850_LONGCALL
! ENUMDOC
! Used for relaxing indirect function calls.
! ENUM
! BFD_RELOC_V850_LONGJUMP
! ENUMDOC
! Used for relaxing indirect jumps.
! ENUM
! BFD_RELOC_V850_ALIGN
! ENUMDOC
! Used to maintain alignment whilst relaxing.
ENUM
BFD_RELOC_MN10300_32_PCREL
ENUMDOC
Index: gas/config/tc-v850.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-v850.c,v
retrieving revision 1.24
diff -c -3 -p -w -r1.24 tc-v850.c
*** gas/config/tc-v850.c 20 Aug 2002 23:49:27 -0000 1.24
--- gas/config/tc-v850.c 29 Aug 2002 06:43:17 -0000
*************** const relax_typeS md_relax_table[] = {
*** 78,83 ****
--- 78,85 ----
{0x1fffff, -0x200000, 4, 0},
};
+ static int v850_relax = 0;
+
/* Fixups. */
#define MAX_INSN_FIXUPS (5)
struct v850_fixup {
*************** v850_comm (area)
*** 394,400 ****
--- 396,408 ----
}
else
{
+ segT old_sec;
+ int old_subsec;
+
allocate_common:
+ old_sec = now_seg;
+ old_subsec = now_subseg;
+
S_SET_VALUE (symbolP, (valueT) size);
S_SET_ALIGN (symbolP, temp);
S_SET_EXTERNAL (symbolP);
*************** v850_comm (area)
*** 411,416 ****
--- 419,427 ----
default:
abort ();
}
+
+ obj_elf_section_change_hook ();
+ subseg_set (old_sec, old_subsec);
}
}
else
*************** set_machine (number)
*** 468,477 ****
{
case 0: processor_mask = PROCESSOR_V850; break;
case bfd_mach_v850e: processor_mask = PROCESSOR_V850E; break;
- case bfd_mach_v850ea: processor_mask = PROCESSOR_V850EA; break;
}
}
/* The target specific pseudo-ops which we support. */
const pseudo_typeS md_pseudo_table[] = {
{ "sdata", v850_seg, SDATA_SECTION },
--- 479,523 ----
{
case 0: processor_mask = PROCESSOR_V850; break;
case bfd_mach_v850e: processor_mask = PROCESSOR_V850E; break;
}
}
+ static void v850_longcode PARAMS ((int));
+
+ static void
+ v850_longcode (type)
+ int type;
+ {
+ expressionS ex;
+
+ if (! v850_relax)
+ {
+ if (type == 1)
+ as_warn (".longcall pseudo-op seen when not relaxing");
+ else
+ as_warn (".longjump pseudo-op seen when not relaxing");
+ }
+
+ expression (&ex);
+
+ if (ex.X_op != O_symbol || ex.X_add_number != 0)
+ {
+ as_bad ("bad .longcall format");
+ ignore_rest_of_line ();
+
+ return;
+ }
+
+ if (type == 1)
+ fix_new_exp (frag_now, frag_now_fix (), 4, & ex, 1,
+ BFD_RELOC_V850_LONGCALL);
+ else
+ fix_new_exp (frag_now, frag_now_fix (), 4, & ex, 1,
+ BFD_RELOC_V850_LONGJUMP);
+
+ demand_empty_rest_of_line ();
+ }
+
/* The target specific pseudo-ops which we support. */
const pseudo_typeS md_pseudo_table[] = {
{ "sdata", v850_seg, SDATA_SECTION },
*************** const pseudo_typeS md_pseudo_table[] = {
*** 492,500 ****
{ "call_table_data", v850_seg, CALL_TABLE_DATA_SECTION },
{ "call_table_text", v850_seg, CALL_TABLE_TEXT_SECTION },
{ "v850e", set_machine, bfd_mach_v850e },
- { "v850ea", set_machine, bfd_mach_v850ea },
{ "file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0 },
{ "loc", dwarf2_directive_loc, 0 },
{ NULL, NULL, 0 }
};
--- 538,547 ----
{ "call_table_data", v850_seg, CALL_TABLE_DATA_SECTION },
{ "call_table_text", v850_seg, CALL_TABLE_TEXT_SECTION },
{ "v850e", set_machine, bfd_mach_v850e },
{ "file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0 },
{ "loc", dwarf2_directive_loc, 0 },
+ { "longcall", v850_longcode, 1 },
+ { "longjump", v850_longcode, 2 },
{ NULL, NULL, 0 }
};
*************** md_show_usage (stream)
*** 1103,1110 ****
fprintf (stream, _(" -mwarn-unsigned-overflow Warn if unsigned immediate values overflow\n"));
fprintf (stream, _(" -mv850 The code is targeted at the v850\n"));
fprintf (stream, _(" -mv850e The code is targeted at the v850e\n"));
- fprintf (stream, _(" -mv850ea The code is targeted at the v850ea\n"));
fprintf (stream, _(" -mv850any The code is generic, despite any processor specific instructions\n"));
}
int
--- 1150,1158 ----
fprintf (stream, _(" -mwarn-unsigned-overflow Warn if unsigned immediate values overflow\n"));
fprintf (stream, _(" -mv850 The code is targeted at the v850\n"));
fprintf (stream, _(" -mv850e The code is targeted at the v850e\n"));
fprintf (stream, _(" -mv850any The code is generic, despite any processor specific instructions\n"));
+ fprintf (stream, _(" -mrelax Enable relaxation\n"));
+
}
int
*************** md_parse_option (c, arg)
*** 1138,1156 ****
machine = bfd_mach_v850e;
processor_mask = PROCESSOR_V850E;
}
- else if (strcmp (arg, "v850ea") == 0)
- {
- machine = bfd_mach_v850ea;
- processor_mask = PROCESSOR_V850EA;
- }
else if (strcmp (arg, "v850any") == 0)
{
/* Tell the world that this is for any v850 chip. */
machine = 0;
/* But support instructions for the extended versions. */
! processor_mask = PROCESSOR_V850EA;
}
else
{
/* xgettext:c-format */
--- 1186,1201 ----
machine = bfd_mach_v850e;
processor_mask = PROCESSOR_V850E;
}
else if (strcmp (arg, "v850any") == 0)
{
/* Tell the world that this is for any v850 chip. */
machine = 0;
/* But support instructions for the extended versions. */
! processor_mask = PROCESSOR_V850E;
}
+ else if (strcmp (arg, "relax") == 0)
+ v850_relax = 1;
else
{
/* xgettext:c-format */
*************** void
*** 1275,1291 ****
md_begin ()
{
char *prev_name = "";
! register const struct v850_opcode *op;
! if (strncmp (TARGET_CPU, "v850ea", 6) == 0)
! {
! if (machine == -1)
! machine = bfd_mach_v850ea;
!
! if (processor_mask == -1)
! processor_mask = PROCESSOR_V850EA;
! }
! else if (strncmp (TARGET_CPU, "v850e", 5) == 0)
{
if (machine == -1)
machine = bfd_mach_v850e;
--- 1320,1328 ----
md_begin ()
{
char *prev_name = "";
! const struct v850_opcode *op;
! if (strncmp (TARGET_CPU, "v850e", 5) == 0)
{
if (machine == -1)
machine = bfd_mach_v850e;
*************** md_assemble (str)
*** 1750,1757 ****
extra_data_after_insn = true;
extra_data_len = 4;
! extra_data = ex.X_add_number;
! ex.X_add_number = 0;
break;
default:
--- 1787,1793 ----
extra_data_after_insn = true;
extra_data_len = 4;
! extra_data = 0;
break;
default:
*************** tc_gen_reloc (seg, fixp)
*** 2215,2226 ****
--- 2251,2282 ----
if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
|| fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT)
reloc->addend = fixp->fx_offset;
+ else if ( fixp->fx_r_type == BFD_RELOC_V850_LONGCALL
+ || fixp->fx_r_type == BFD_RELOC_V850_LONGJUMP
+ || fixp->fx_r_type == BFD_RELOC_V850_ALIGN)
+ reloc->addend = fixp->fx_offset;
else
reloc->addend = fixp->fx_addnumber;
return reloc;
}
+ void
+ v850_handle_align (frag)
+ fragS * frag;
+ {
+ if (v850_relax
+ && frag->fr_type == rs_align
+ && frag->fr_address + frag->fr_fix > 0
+ && frag->fr_offset > 1
+ && now_seg != bss_section
+ && now_seg != v850_seg_table[SBSS_SECTION].s
+ && now_seg != v850_seg_table[TBSS_SECTION].s
+ && now_seg != v850_seg_table[ZBSS_SECTION].s)
+ fix_new (frag, frag->fr_fix, 2, & abs_symbol, frag->fr_offset, 0,
+ BFD_RELOC_V850_ALIGN);
+ }
+
/* Return current size of variable part of frag. */
int
*************** md_apply_fix3 (fixP, valueP, seg)
*** 2261,2266 ****
--- 2317,2324 ----
char *where;
if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixP->fx_r_type == BFD_RELOC_V850_LONGCALL
+ || fixP->fx_r_type == BFD_RELOC_V850_LONGJUMP
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
{
fixP->fx_done = 0;
*************** md_apply_fix3 (fixP, valueP, seg)
*** 2268,2277 ****
}
if (fixP->fx_addsy == (symbolS *) NULL)
fixP->fx_done = 1;
else if (fixP->fx_pcrel)
! ;
else
{
--- 2326,2336 ----
}
if (fixP->fx_addsy == (symbolS *) NULL)
+ fixP->fx_addnumber = value,
fixP->fx_done = 1;
else if (fixP->fx_pcrel)
! fixP->fx_addnumber = fixP->fx_offset;
else
{
*************** md_apply_fix3 (fixP, valueP, seg)
*** 2287,2292 ****
--- 2346,2352 ----
_("expression too complex"));
}
}
+ fixP->fx_addnumber = value;
}
if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
*************** md_apply_fix3 (fixP, valueP, seg)
*** 2345,2352 ****
else if (fixP->fx_size == 4)
bfd_putl32 (value, (unsigned char *) where);
}
-
- fixP->fx_addnumber = value;
}
/* Parse a cons expression. We have to handle hi(), lo(), etc
--- 2405,2410 ----
*************** v850_force_relocation (fixP)
*** 2428,2433 ****
--- 2486,2503 ----
if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ return 1;
+
+ if ( fixP->fx_r_type == BFD_RELOC_V850_LONGCALL
+ || fixP->fx_r_type == BFD_RELOC_V850_LONGJUMP)
+ return 1;
+
+ if (v850_relax
+ && (fixP->fx_pcrel
+ || fixP->fx_r_type == BFD_RELOC_V850_ALIGN
+ || fixP->fx_r_type == BFD_RELOC_V850_22_PCREL
+ || fixP->fx_r_type == BFD_RELOC_V850_9_PCREL
+ || fixP->fx_r_type >= BFD_RELOC_UNUSED))
return 1;
return 0;
Index: gas/config/tc-v850.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-v850.h,v
retrieving revision 1.11
diff -c -3 -p -w -r1.11 tc-v850.h
*** gas/config/tc-v850.h 25 May 2002 12:53:29 -0000 1.11
--- gas/config/tc-v850.h 29 Aug 2002 06:43:17 -0000
*************** extern void cons_fix_new_v850 PARAMS ((f
*** 70,75 ****
--- 70,80 ----
#define TC_GENERIC_RELAX_TABLE md_relax_table
extern const struct relax_type md_relax_table[];
+ /* When relaxing, we need to generate
+ relocations for alignment directives. */
+ #define HANDLE_ALIGN(frag) v850_handle_align (frag)
+ extern void v850_handle_align PARAMS ((fragS *));
+
/* This section must be in the small data area (pointed to by GP). */
#define SHF_V850_GPREL 0x10000000
/* This section must be in the tiny data area (pointed to by EP). */
Index: gas/doc/c-v850.texi
===================================================================
RCS file: /cvs/src/src/gas/doc/c-v850.texi,v
retrieving revision 1.2
diff -c -3 -p -w -r1.2 c-v850.texi
*** gas/doc/c-v850.texi 8 Mar 2001 23:24:26 -0000 1.2
--- gas/doc/c-v850.texi 29 Aug 2002 06:43:17 -0000
*************** routines used by the code produced by GC
*** 62,67 ****
--- 62,75 ----
architecture, together with support routines only used by the V850E
architecture.
+ @cindex @code{-mrelax} command line option, V850
+ @item -mrelax
+ Enables relaxation. This allows the .longcall and .longjump pseudo
+ ops to be used in the assembler source code. These ops label sections
+ of code which are either a long function call or a long branch. The
+ assembler will then flag these sections of code and the linker will
+ attempt to relax them.
+
@end table
*************** example:
*** 354,363 ****
will put the call the function whoes address is held in the call table
at the location labeled 'table_func1'.
@end table
For information on the V850 instruction set, see @cite{V850
Family 32-/16-Bit single-Chip Microcontroller Architecture Manual} from NEC.
Ltd.
-
--- 362,384 ----
will put the call the function whoes address is held in the call table
at the location labeled 'table_func1'.
+ @cindex @code{longcall} pseudo-op, V850
+ @item .longcall @code{name}
+ Indicates that the following sequence of instructions is a long call
+ to function @code{name}. The linker will attempt to shorten this call
+ sequence if @code{name} is within a 22bit offset of the call. Only
+ valid if the @code{-mrelax} command line switch has been enabled.
+
+ @cindex @code{longjump} pseudo-op, V850
+ @item .longjump @code{name}
+ Indicates that the following sequence of instructions is a long jump
+ to label @code{name}. The linker will attempt to shorten this code
+ sequence if @code{name} is within a 22bit offset of the jump. Only
+ valid if the @code{-mrelax} command line switch has been enabled.
+
@end table
For information on the V850 instruction set, see @cite{V850
Family 32-/16-Bit single-Chip Microcontroller Architecture Manual} from NEC.
Ltd.
Index: include/elf/v850.h
===================================================================
RCS file: /cvs/src/src/include/elf/v850.h,v
retrieving revision 1.5
diff -c -3 -p -w -r1.5 v850.h
*** include/elf/v850.h 14 Mar 2001 02:27:44 -0000 1.5
--- include/elf/v850.h 29 Aug 2002 06:43:18 -0000
***************
*** 1,5 ****
/* V850 ELF support for BFD.
! Copyright 1997, 1998, 2000 Free Software Foundation, Inc.
Created by Michael Meissner, Cygnus Support <meissner@cygnus.com>
This file is part of BFD, the Binary File Descriptor library.
--- 1,5 ----
/* V850 ELF support for BFD.
! Copyright 1997, 1998, 2000, 2002 Free Software Foundation, Inc.
Created by Michael Meissner, Cygnus Support <meissner@cygnus.com>
This file is part of BFD, the Binary File Descriptor library.
*************** Foundation, Inc., 59 Temple Place - Suit
*** 35,52 ****
/* v850e code. */
#define E_V850E_ARCH 0x10000000
- /* v850ea code. */
- #define E_V850EA_ARCH 0x20000000
! /* Flags for the st_other field */
! #define V850_OTHER_SDA 0x01 /* symbol had SDA relocations */
! #define V850_OTHER_ZDA 0x02 /* symbol had ZDA relocations */
! #define V850_OTHER_TDA 0x04 /* symbol had TDA relocations */
! #define V850_OTHER_TDA_BYTE 0x08 /* symbol had TDA byte relocations */
! #define V850_OTHER_ERROR 0x80 /* symbol had an error reported */
!
! /* V850 relocations */
#include "elf/reloc-macros.h"
START_RELOC_NUMBERS (v850_reloc_type)
--- 35,49 ----
/* v850e code. */
#define E_V850E_ARCH 0x10000000
+ /* Flags for the st_other field. */
+ #define V850_OTHER_SDA 0x01 /* Symbol had SDA relocations. */
+ #define V850_OTHER_ZDA 0x02 /* Symbol had ZDA relocations. */
+ #define V850_OTHER_TDA 0x04 /* Symbol had TDA relocations. */
+ #define V850_OTHER_TDA_BYTE 0x08 /* Symbol had TDA byte relocations. */
+ #define V850_OTHER_ERROR 0x80 /* Symbol had an error reported. */
! /* V850 relocations. */
#include "elf/reloc-macros.h"
START_RELOC_NUMBERS (v850_reloc_type)
*************** START_RELOC_NUMBERS (v850_reloc_type)
*** 75,80 ****
--- 72,80 ----
RELOC_NUMBER( R_V850_CALLT_16_16_OFFSET, 22) /* For callt */
RELOC_NUMBER (R_V850_GNU_VTINHERIT, 23)
RELOC_NUMBER (R_V850_GNU_VTENTRY, 24)
+ RELOC_NUMBER (R_V850_LONGCALL, 25)
+ RELOC_NUMBER (R_V850_LONGJUMP, 26)
+ RELOC_NUMBER (R_V850_ALIGN, 27)
END_RELOC_NUMBERS (R_V850_max)
*************** END_RELOC_NUMBERS (R_V850_max)
*** 102,107 ****
/* Section contains the .scommon data. */
#define SHT_V850_ZCOMMON 0x70000002
-
#endif /* _ELF_V850_H */
--- 102,106 ----