+/* Compute the stack size and movm arguments for the function
+ referred to by HASH at address ADDR in section with
+ contents CONTENTS, store the information in the hash table. */
+
+static void
+compute_function_info (bfd *abfd,
+ struct elf32_mn10300_link_hash_entry *hash,
+ bfd_vma addr,
+ unsigned char *contents)
+{
+ unsigned char byte1, byte2;
+ /* We only care about a very small subset of the possible prologue
+ sequences here. Basically we look for:
+
+ movm [d2,d3,a2,a3],sp (optional)
+ add <size>,sp (optional, and only for sizes which fit in an unsigned
+ 8 bit number)
+
+ If we find anything else, we quit. */
+
+ /* Look for movm [regs],sp. */
+ byte1 = bfd_get_8 (abfd, contents + addr);
+ byte2 = bfd_get_8 (abfd, contents + addr + 1);
+
+ if (byte1 == 0xcf)
+ {
+ hash->movm_args = byte2;
+ addr += 2;
+ byte1 = bfd_get_8 (abfd, contents + addr);
+ byte2 = bfd_get_8 (abfd, contents + addr + 1);
+ }
+
+ /* Now figure out how much stack space will be allocated by the movm
+ instruction. We need this kept separate from the function's normal
+ stack space. */
+ if (hash->movm_args)
+ {
+ /* Space for d2. */
+ if (hash->movm_args & 0x80)
+ hash->movm_stack_size += 4;
+
+ /* Space for d3. */
+ if (hash->movm_args & 0x40)
+ hash->movm_stack_size += 4;
+
+ /* Space for a2. */
+ if (hash->movm_args & 0x20)
+ hash->movm_stack_size += 4;
+
+ /* Space for a3. */
+ if (hash->movm_args & 0x10)
+ hash->movm_stack_size += 4;
+
+ /* "other" space. d0, d1, a0, a1, mdr, lir, lar, 4 byte pad. */
+ if (hash->movm_args & 0x08)
+ hash->movm_stack_size += 8 * 4;
+
+ if (bfd_get_mach (abfd) == bfd_mach_am33
+ || bfd_get_mach (abfd) == bfd_mach_am33_2)
+ {
+ /* "exother" space. e0, e1, mdrq, mcrh, mcrl, mcvf */
+ if (hash->movm_args & 0x1)
+ hash->movm_stack_size += 6 * 4;
+
+ /* exreg1 space. e4, e5, e6, e7 */
+ if (hash->movm_args & 0x2)
+ hash->movm_stack_size += 4 * 4;
+
+ /* exreg0 space. e2, e3 */
+ if (hash->movm_args & 0x4)
+ hash->movm_stack_size += 2 * 4;
+ }
+ }
+
+ /* Now look for the two stack adjustment variants. */
+ if (byte1 == 0xf8 && byte2 == 0xfe)
+ {
+ int temp = bfd_get_8 (abfd, contents + addr + 2);
+ temp = ((temp & 0xff) ^ (~0x7f)) + 0x80;
+
+ hash->stack_size = -temp;
+ }
+ else if (byte1 == 0xfa && byte2 == 0xfe)
+ {
+ int temp = bfd_get_16 (abfd, contents + addr + 2);
+ temp = ((temp & 0xffff) ^ (~0x7fff)) + 0x8000;
+ temp = -temp;
+
+ if (temp < 255)
+ hash->stack_size = temp;
+ }
+
+ /* If the total stack to be allocated by the call instruction is more
+ than 255 bytes, then we can't remove the stack adjustment by using
+ "call" (we might still be able to remove the "movm" instruction. */
+ if (hash->stack_size + hash->movm_stack_size > 255)
+ hash->stack_size = 0;
+}
+
+/* Delete some bytes from a section while relaxing. */
+
+static bfd_boolean
+mn10300_elf_relax_delete_bytes (bfd *abfd,
+ asection *sec,
+ bfd_vma addr,
+ int count)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ unsigned int sec_shndx;
+ bfd_byte *contents;
+ Elf_Internal_Rela *irel, *irelend;
+ Elf_Internal_Rela *irelalign;
+ bfd_vma toaddr;
+ Elf_Internal_Sym *isym, *isymend;
+ struct elf_link_hash_entry **sym_hashes;
+ struct elf_link_hash_entry **end_hashes;
+ unsigned int symcount;
+
+ sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+
+ contents = elf_section_data (sec)->this_hdr.contents;
+
+ 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 alignment
+ 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));
+
+ /* 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)
+ || (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN
+ && irel->r_offset == toaddr))
+ irel->r_offset -= count;
+ }
+
+ /* 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)
+ {
+ 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. */
+ symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
+ - symtab_hdr->sh_info);
+ sym_hashes = elf_sym_hashes (abfd);
+ end_hashes = sym_hashes + symcount;
+ for (; sym_hashes < end_hashes; sym_hashes++)
+ {
+ struct elf_link_hash_entry *sym_hash = *sym_hashes;
+
+ if ((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
+ && sym_hash->root.u.def.value < toaddr)
+ {
+ 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;
+}
+
+/* Return TRUE if a symbol exists at the given address, else return
+ FALSE. */
+
+static bfd_boolean
+mn10300_elf_symbol_address_p (bfd *abfd,
+ asection *sec,
+ Elf_Internal_Sym *isym,
+ bfd_vma addr)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ unsigned int sec_shndx;
+ Elf_Internal_Sym *isymend;
+ struct elf_link_hash_entry **sym_hashes;
+ struct elf_link_hash_entry **end_hashes;
+ unsigned int symcount;
+
+ sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+
+ /* Examine all the symbols. */
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
+ if (isym->st_shndx == sec_shndx
+ && isym->st_value == addr)
+ return TRUE;
+
+ symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
+ - symtab_hdr->sh_info);
+ sym_hashes = elf_sym_hashes (abfd);
+ end_hashes = sym_hashes + symcount;
+ for (; sym_hashes < end_hashes; sym_hashes++)
+ {
+ struct elf_link_hash_entry *sym_hash = *sym_hashes;
+
+ if ((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)
+ return TRUE;
+ }
+
+ return FALSE;
+}