Back to index

cell-binutils  2.17cvs20070401
Classes | Defines | Functions | Variables
elf32-crx.c File Reference
#include "bfd.h"
#include "sysdep.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf/crx.h"
#include "elf32-target.h"

Go to the source code of this file.

Classes

struct  crx_reloc_map

Defines

#define TARGET_LITTLE_SYM   bfd_elf32_crx_vec
#define TARGET_LITTLE_NAME   "elf32-crx"
#define ELF_ARCH   bfd_arch_crx
#define ELF_MACHINE_CODE   EM_CRX
#define ELF_MAXPAGESIZE   0x1
#define elf_symbol_leading_char   '_'
#define bfd_elf32_bfd_reloc_type_lookup   elf_crx_reloc_type_lookup
#define bfd_elf32_bfd_reloc_name_lookup   elf_crx_reloc_name_lookup
#define elf_info_to_howto   elf_crx_info_to_howto
#define elf_info_to_howto_rel   0
#define elf_backend_relocate_section   elf32_crx_relocate_section
#define bfd_elf32_bfd_relax_section   elf32_crx_relax_section
#define bfd_elf32_bfd_get_relocated_section_contents   elf32_crx_get_relocated_section_contents
#define elf_backend_can_gc_sections   1
#define elf_backend_rela_normal   1

Functions

static reloc_howto_type * elf_crx_reloc_type_lookup (bfd *, bfd_reloc_code_real_type)
static void elf_crx_info_to_howto (bfd *, arelent *, Elf_Internal_Rela *)
static bfd_boolean elf32_crx_relax_delete_bytes (struct bfd_link_info *, bfd *, asection *, bfd_vma, int)
static bfd_reloc_status_type crx_elf_final_link_relocate (reloc_howto_type *, bfd *, bfd *, asection *, bfd_byte *, bfd_vma, bfd_vma, bfd_vma, struct bfd_link_info *, asection *, int)
static bfd_boolean elf32_crx_relocate_section (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)
static bfd_boolean elf32_crx_relax_section (bfd *, asection *, struct bfd_link_info *, bfd_boolean *)
static bfd_byteelf32_crx_get_relocated_section_contents (bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *, bfd_boolean, asymbol **)
static reloc_howto_type * elf_crx_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code)
static reloc_howto_type * elf_crx_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
static void elf_crx_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, Elf_Internal_Rela *dst)
static bfd_reloc_status_type crx_elf_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd, bfd *output_bfd ATTRIBUTE_UNUSED, asection *input_section, bfd_byte *contents, bfd_vma offset, bfd_vma Rvalue, bfd_vma addend, struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *sec ATTRIBUTE_UNUSED, int is_local ATTRIBUTE_UNUSED)

Variables

static struct crx_reloc_map [R_CRX_MAX]
static reloc_howto_type crx_elf_howto_table []

Class Documentation

struct crx_reloc_map

Definition at line 49 of file elf32-crx.c.

Class Members
bfd_reloc_code_real_type bfd_reloc_enum
unsigned short crx_reloc_type

Define Documentation

Definition at line 1336 of file elf32-crx.c.

Definition at line 1335 of file elf32-crx.c.

Definition at line 1330 of file elf32-crx.c.

Definition at line 1329 of file elf32-crx.c.

#define ELF_ARCH   bfd_arch_crx

Definition at line 1324 of file elf32-crx.c.

Definition at line 1338 of file elf32-crx.c.

#define elf_backend_rela_normal   1

Definition at line 1339 of file elf32-crx.c.

Definition at line 1334 of file elf32-crx.c.

Definition at line 1332 of file elf32-crx.c.

#define elf_info_to_howto_rel   0

Definition at line 1333 of file elf32-crx.c.

#define ELF_MACHINE_CODE   EM_CRX

Definition at line 1325 of file elf32-crx.c.

#define ELF_MAXPAGESIZE   0x1

Definition at line 1326 of file elf32-crx.c.

#define elf_symbol_leading_char   '_'

Definition at line 1327 of file elf32-crx.c.

#define TARGET_LITTLE_NAME   "elf32-crx"

Definition at line 1323 of file elf32-crx.c.

Definition at line 1322 of file elf32-crx.c.


Function Documentation

static bfd_reloc_status_type crx_elf_final_link_relocate ( reloc_howto_type *  ,
bfd ,
bfd ,
asection ,
bfd_byte ,
bfd_vma  ,
bfd_vma  ,
bfd_vma  ,
struct bfd_link_info ,
asection ,
int   
) [static]

Here is the caller graph for this function:

static bfd_reloc_status_type crx_elf_final_link_relocate ( reloc_howto_type *  howto,
bfd input_bfd,
bfd *output_bfd  ATTRIBUTE_UNUSED,
asection input_section,
bfd_byte contents,
bfd_vma  offset,
bfd_vma  Rvalue,
bfd_vma  addend,
struct bfd_link_info *info  ATTRIBUTE_UNUSED,
asection *sec  ATTRIBUTE_UNUSED,
int is_local  ATTRIBUTE_UNUSED 
) [static]

Definition at line 432 of file elf32-crx.c.

{
  unsigned short r_type = howto->type;
  bfd_byte *hit_data = contents + offset;
  bfd_vma reloc_bits, check;

  switch (r_type)
    {
     case R_CRX_IMM16:
     case R_CRX_IMM32:
     case R_CRX_ABS16:
     case R_CRX_ABS32:
     case R_CRX_REL8_CMP:
     case R_CRX_REL16:
     case R_CRX_REL24:
     case R_CRX_REL32:
     case R_CRX_REGREL12:
     case R_CRX_REGREL22:
     case R_CRX_REGREL28:
     case R_CRX_REGREL32:
       /* 'hit_data' is relative to the start of the instruction, not the
         relocation offset. Advance it to account for the exact offset.  */
       hit_data += 2;
       break;

     case R_CRX_REL4:
       /* This relocation type is used only in 'Branch if Equal to 0'
         instructions and requires special handling.  */
       Rvalue -= 1;
       break;

     case R_CRX_NONE:
       return bfd_reloc_ok;
       break;

     case R_CRX_SWITCH8:
     case R_CRX_SWITCH16:
     case R_CRX_SWITCH32:
       /* We only care about the addend, where the difference between 
         expressions is kept.  */
       Rvalue = 0;
       
     default:
       break;
    }

  if (howto->pc_relative)
    {
      /* Subtract the address of the section containing the location.  */
      Rvalue -= (input_section->output_section->vma
               + input_section->output_offset);
      /* Subtract the position of the location within the section.  */
      Rvalue -= offset;
    }

  /* Add in supplied addend.  */
  Rvalue += addend;

  /* Complain if the bitfield overflows, whether it is considered
     as signed or unsigned.  */
  check = Rvalue >> howto->rightshift;

  /* Assumes two's complement.  This expression avoids
     overflow if howto->bitsize is the number of bits in
     bfd_vma.  */
  reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1;

  if (((bfd_vma) check & ~reloc_bits) != 0
      && (((bfd_vma) check & ~reloc_bits)
         != (-(bfd_vma) 1 & ~reloc_bits)))
    {
      /* The above right shift is incorrect for a signed
        value.  See if turning on the upper bits fixes the
        overflow.  */
      if (howto->rightshift && (bfd_signed_vma) Rvalue < 0)
       {
         check |= ((bfd_vma) - 1
                  & ~((bfd_vma) - 1
                     >> howto->rightshift));
         if (((bfd_vma) check & ~reloc_bits)
             != (-(bfd_vma) 1 & ~reloc_bits))
           return bfd_reloc_overflow;
       }
      else
       return bfd_reloc_overflow;
    }

  /* Drop unwanted bits from the value we are relocating to.  */
  Rvalue >>= (bfd_vma) howto->rightshift;

  /* Apply dst_mask to select only relocatable part of the insn.  */
  Rvalue &= howto->dst_mask;

  switch (howto->size)
    {
     case 0:
       if (r_type == R_CRX_REL4)
        {
          Rvalue <<= 4;
          Rvalue |= (bfd_get_8 (input_bfd, hit_data) & 0x0f);
        }

       bfd_put_8 (input_bfd, (unsigned char) Rvalue, hit_data);
       break;

     case 1:
       if (r_type == R_CRX_REGREL12)
        Rvalue |= (bfd_get_16 (input_bfd, hit_data) & 0xf000);

       bfd_put_16 (input_bfd, Rvalue, hit_data);
       break;

     case 2:
       if (r_type == R_CRX_REL24
          || r_type == R_CRX_REGREL22
          || r_type == R_CRX_REGREL28)
        Rvalue |= (((bfd_get_16 (input_bfd, hit_data) << 16) |
                    bfd_get_16 (input_bfd, hit_data + 2)) & ~howto->dst_mask);

       if (r_type == R_CRX_NUM32 || r_type == R_CRX_SWITCH32)
        /* Relocation on DATA is purely little-endian, that is, for a
           multi-byte datum, the lowest address in memory contains the
           little end of the datum, that is, the least significant byte.
           Therefore we use BFD's byte Putting functions.  */
        bfd_put_32 (input_bfd, Rvalue, hit_data);
       else
        /* Relocation on INSTRUCTIONS is different : Instructions are
           word-addressable, that is, each word itself is arranged according
           to little-endian convention, whereas the words are arranged with
           respect to one another in BIG ENDIAN fashion.
           When there is an immediate value that spans a word boundary, it is
           split in a big-endian way with respect to the words.  */
        {
          bfd_put_16 (input_bfd, (Rvalue >> 16) & 0xffff, hit_data);
          bfd_put_16 (input_bfd, Rvalue & 0xffff, hit_data + 2);
        }
     break;

     default:
       return bfd_reloc_notsupported;
    }

  return bfd_reloc_ok;
}

Here is the call graph for this function:

static bfd_byte * elf32_crx_get_relocated_section_contents ( bfd output_bfd,
struct bfd_link_info link_info,
struct bfd_link_order link_order,
bfd_byte data,
bfd_boolean  relocatable,
asymbol **  symbols 
) [static]

Definition at line 723 of file elf32-crx.c.

{
  Elf_Internal_Shdr *symtab_hdr;
  asection *input_section = link_order->u.indirect.section;
  bfd *input_bfd = input_section->owner;
  asection **sections = NULL;
  Elf_Internal_Rela *internal_relocs = NULL;
  Elf_Internal_Sym *isymbuf = NULL;

  /* We only need to handle the case of relaxing, or of having a
     particular set of section contents, specially.  */
  if (relocatable
      || elf_section_data (input_section)->this_hdr.contents == NULL)
    return bfd_generic_get_relocated_section_contents (output_bfd, link_info,
                                                 link_order, data,
                                                 relocatable,
                                                 symbols);

  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;

  memcpy (data, elf_section_data (input_section)->this_hdr.contents,
         (size_t) input_section->size);

  if ((input_section->flags & SEC_RELOC) != 0
      && input_section->reloc_count > 0)
    {
      Elf_Internal_Sym *isym;
      Elf_Internal_Sym *isymend;
      asection **secpp;
      bfd_size_type amt;

      internal_relocs = (_bfd_elf_link_read_relocs
                      (input_bfd, input_section, (PTR) NULL,
                       (Elf_Internal_Rela *) NULL, FALSE));
      if (internal_relocs == NULL)
       goto error_return;

      if (symtab_hdr->sh_info != 0)
       {
         isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
         if (isymbuf == NULL)
           isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
                                       symtab_hdr->sh_info, 0,
                                       NULL, NULL, NULL);
         if (isymbuf == NULL)
           goto error_return;
       }

      amt = symtab_hdr->sh_info;
      amt *= sizeof (asection *);
      sections = bfd_malloc (amt);
      if (sections == NULL && amt != 0)
       goto error_return;

      isymend = isymbuf + symtab_hdr->sh_info;
      for (isym = isymbuf, secpp = sections; isym < isymend; ++isym, ++secpp)
       {
         asection *isec;

         if (isym->st_shndx == SHN_UNDEF)
           isec = bfd_und_section_ptr;
         else if (isym->st_shndx == SHN_ABS)
           isec = bfd_abs_section_ptr;
         else if (isym->st_shndx == SHN_COMMON)
           isec = bfd_com_section_ptr;
         else
           isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx);

         *secpp = isec;
       }

      if (! elf32_crx_relocate_section (output_bfd, link_info, input_bfd,
                                 input_section, data, internal_relocs,
                                 isymbuf, sections))
       goto error_return;

      if (sections != NULL)
       free (sections);
      if (isymbuf != NULL
         && symtab_hdr->contents != (unsigned char *) isymbuf)
       free (isymbuf);
      if (elf_section_data (input_section)->relocs != internal_relocs)
       free (internal_relocs);
    }

  return data;

 error_return:
  if (sections != NULL)
    free (sections);
  if (isymbuf != NULL
      && symtab_hdr->contents != (unsigned char *) isymbuf)
    free (isymbuf);
  if (internal_relocs != NULL
      && elf_section_data (input_section)->relocs != internal_relocs)
    free (internal_relocs);
  return NULL;
}

Here is the call graph for this function:

static bfd_boolean elf32_crx_relax_delete_bytes ( struct bfd_link_info link_info,
bfd abfd,
asection sec,
bfd_vma  addr,
int  count 
) [static]

Definition at line 586 of file elf32-crx.c.

{
  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;
  Elf_Internal_Sym *isymend;
  struct elf_link_hash_entry **sym_hashes;
  struct elf_link_hash_entry **end_hashes;
  struct elf_link_hash_entry **start_hashes;
  unsigned int symcount;

  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 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;

  /* Actually delete the bytes.  */
  memmove (contents + addr, contents + addr + count,
          (size_t) (toaddr - addr - count));
  sec->size -= count;

  /* 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 -= count;
    }

  /* Adjust the local symbols defined in this section.  */
  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)
       {
         /* Adjust the addend of SWITCH relocations in this section, 
            which reference this local symbol.  */
         for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
           {
             unsigned long r_symndx;
             Elf_Internal_Sym *rsym;
             bfd_vma addsym, subsym;

             /* Skip if not a SWITCH relocation.  */
             if (ELF32_R_TYPE (irel->r_info) != (int) R_CRX_SWITCH8
                && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_SWITCH16
                && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_SWITCH32)
                continue;

             r_symndx = ELF32_R_SYM (irel->r_info);
             rsym = (Elf_Internal_Sym *) symtab_hdr->contents + r_symndx;

             /* Skip if not the local adjusted symbol.  */
             if (rsym != isym)
              continue;

             addsym = isym->st_value;
             subsym = addsym - irel->r_addend;

             /* Fix the addend only when -->> (addsym > addr >= subsym).  */
             if (subsym <= addr)
              irel->r_addend -= count;
             else
              continue;
           }

         isym->st_value -= 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 = start_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;

      /* The '--wrap SYMBOL' option is causing a pain when the object file, 
        containing the definition of __wrap_SYMBOL, includes a direct 
        call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference 
        the same symbol (which is __wrap_SYMBOL), but still exist as two 
        different symbols in 'sym_hashes', we don't want to adjust 
        the global symbol __wrap_SYMBOL twice.  
        This check is only relevant when symbols are being wrapped.  */
      if (link_info->wrap_hash != NULL)
       {
         struct elf_link_hash_entry **cur_sym_hashes;
         
         /* Loop only over the symbols whom been already checked.  */
         for (cur_sym_hashes = start_hashes; cur_sym_hashes < sym_hashes; 
              cur_sym_hashes++)
           {
             /* If the current symbol is identical to 'sym_hash', that means 
               the symbol was already adjusted (or at least checked).  */
             if (*cur_sym_hashes == sym_hash)
              break;
           }
         /* Don't adjust the symbol again.  */
         if (cur_sym_hashes < sym_hashes)
           continue;
       }

      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)
       sym_hash->root.u.def.value -= count;
    }

  return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static bfd_boolean elf32_crx_relax_section ( bfd abfd,
asection sec,
struct bfd_link_info link_info,
bfd_boolean again 
) [static]

Definition at line 972 of file elf32-crx.c.

{
  Elf_Internal_Shdr *symtab_hdr;
  Elf_Internal_Rela *internal_relocs;
  Elf_Internal_Rela *irel, *irelend;
  bfd_byte *contents = NULL;
  Elf_Internal_Sym *isymbuf = NULL;

  /* Assume nothing changes.  */
  *again = FALSE;

  /* We don't have to do anything for a relocatable link, if
     this section does not have relocs, or if this is not a
     code section.  */
  if (link_info->relocatable
      || (sec->flags & SEC_RELOC) == 0
      || sec->reloc_count == 0
      || (sec->flags & SEC_CODE) == 0)
    return TRUE;

  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;

  /* Get a copy of the native relocations.  */
  internal_relocs = (_bfd_elf_link_read_relocs
                   (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
                    link_info->keep_memory));
  if (internal_relocs == NULL)
    goto error_return;

  /* Walk through them looking for relaxing opportunities.  */
  irelend = internal_relocs + sec->reloc_count;
  for (irel = internal_relocs; irel < irelend; irel++)
    {
      bfd_vma symval;

      /* If this isn't something that can be relaxed, then ignore
        this reloc.  */
      if (ELF32_R_TYPE (irel->r_info) != (int) R_CRX_REL32
         && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_REL16
         && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_REL24
         && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_IMM32)
       continue;

      /* Get the section contents if we haven't done so already.  */
      if (contents == NULL)
       {
         /* Get cached copy if it exists.  */
         if (elf_section_data (sec)->this_hdr.contents != NULL)
           contents = elf_section_data (sec)->this_hdr.contents;
         /* Go get them off disk.  */
         else if (!bfd_malloc_and_get_section (abfd, sec, &contents))
           goto error_return;
       }

      /* Read this BFD's local symbols if we haven't done so already.  */
      if (isymbuf == NULL && symtab_hdr->sh_info != 0)
       {
         isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
         if (isymbuf == NULL)
           isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
                                       symtab_hdr->sh_info, 0,
                                       NULL, NULL, NULL);
         if (isymbuf == NULL)
           goto error_return;
       }

      /* Get the value of the symbol referred to by the reloc.  */
      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
       {
         /* A local symbol.  */
         Elf_Internal_Sym *isym;
         asection *sym_sec;

         isym = isymbuf + ELF32_R_SYM (irel->r_info);
         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);
       }

      /* 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.  */

      /* Try to turn a 32bit pc-relative branch/call into
        a 16bit pc-relative branch/call.  */
      if (ELF32_R_TYPE (irel->r_info) == (int) R_CRX_REL32)
       {
         bfd_vma value = symval;

         /* Deal with pc-relative gunk.  */
         value -= (sec->output_section->vma + sec->output_offset);
         value -= irel->r_offset;
         value += irel->r_addend;

         /* See if the value will fit in 16 bits, note the high value is
            0xfffe + 2 as the target will be two bytes closer if we are
            able to relax.  */
         if ((long) value < 0x10000 && (long) value > -0x10002)
           {
             unsigned short code;

             /* Get the opcode.  */
             code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset);

             /* Verify it's a 'bal'/'bcond' and fix the opcode.  */
             if ((code & 0xfff0) == 0x3170)
              bfd_put_8 (abfd, 0x30, contents + irel->r_offset + 1);
             else if ((code & 0xf0ff) == 0x707f)
              bfd_put_8 (abfd, 0x7e, contents + irel->r_offset);
             else
              continue;

             /* Note that we've changed the relocs, section contents, etc.  */
             elf_section_data (sec)->relocs = internal_relocs;
             elf_section_data (sec)->this_hdr.contents = contents;
             symtab_hdr->contents = (unsigned char *) isymbuf;

             /* Fix the relocation's type.  */
             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
                                      R_CRX_REL16);

             /* Delete two bytes of data.  */
             if (!elf32_crx_relax_delete_bytes (link_info, abfd, sec,
                                             irel->r_offset + 2, 2))
              goto error_return;

             /* That will change things, so, we should relax again.
               Note that this is not required, and it may be slow.  */
             *again = TRUE;
           }
       }

      /* Try to turn a 16bit pc-relative branch into an
        8bit pc-relative branch.  */
      if (ELF32_R_TYPE (irel->r_info) == (int) R_CRX_REL16)
       {
         bfd_vma value = symval;

         /* Deal with pc-relative gunk.  */
         value -= (sec->output_section->vma + sec->output_offset);
         value -= irel->r_offset;
         value += irel->r_addend;

         /* See if the value will fit in 8 bits, note the high value is
            0xfc + 2 as the target will be two bytes closer if we are
            able to relax.  */
         if ((long) value < 0xfe && (long) value > -0x100)
           {
             unsigned short code;

             /* Get the opcode.  */
             code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset);

             /* Verify it's a 'bcond' opcode.  */
             if ((code & 0xf0ff) != 0x707e)
              continue;

             /* Note that we've changed the relocs, section contents, etc.  */
             elf_section_data (sec)->relocs = internal_relocs;
             elf_section_data (sec)->this_hdr.contents = contents;
             symtab_hdr->contents = (unsigned char *) isymbuf;

             /* Fix the relocation's type.  */
             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
                                      R_CRX_REL8);

             /* Delete two bytes of data.  */
             if (!elf32_crx_relax_delete_bytes (link_info, abfd, sec,
                                             irel->r_offset + 2, 2))
              goto error_return;

             /* That will change things, so, we should relax again.
               Note that this is not required, and it may be slow.  */
             *again = TRUE;
           }
       }

      /* Try to turn a 24bit pc-relative cmp&branch into
        an 8bit pc-relative cmp&branch.  */
      if (ELF32_R_TYPE (irel->r_info) == (int) R_CRX_REL24)
       {
         bfd_vma value = symval;

         /* Deal with pc-relative gunk.  */
         value -= (sec->output_section->vma + sec->output_offset);
         value -= irel->r_offset;
         value += irel->r_addend;

         /* See if the value will fit in 8 bits, note the high value is
            0x7e + 2 as the target will be two bytes closer if we are
            able to relax.  */
         if ((long) value < 0x100 && (long) value > -0x100)
           {
             unsigned short code;

             /* Get the opcode.  */
             code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset);

             /* Verify it's a 'cmp&branch' opcode.  */
             if ((code & 0xfff0) != 0x3180 && (code & 0xfff0) != 0x3190
              && (code & 0xfff0) != 0x31a0 && (code & 0xfff0) != 0x31c0
              && (code & 0xfff0) != 0x31d0 && (code & 0xfff0) != 0x31e0
              /* Or a Co-processor branch ('bcop').  */
              && (code & 0xfff0) != 0x3010 && (code & 0xfff0) != 0x3110)
              continue;

             /* Note that we've changed the relocs, section contents, etc.  */
             elf_section_data (sec)->relocs = internal_relocs;
             elf_section_data (sec)->this_hdr.contents = contents;
             symtab_hdr->contents = (unsigned char *) isymbuf;

             /* Fix the opcode.  */
             bfd_put_8 (abfd, 0x30, contents + irel->r_offset + 1);

             /* Fix the relocation's type.  */
             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
                                      R_CRX_REL8_CMP);

             /* Delete two bytes of data.  */
             if (!elf32_crx_relax_delete_bytes (link_info, abfd, sec,
                                             irel->r_offset + 4, 2))
              goto error_return;

             /* That will change things, so, we should relax again.
               Note that this is not required, and it may be slow.  */
             *again = TRUE;
           }
       }

      /* Try to turn a 32bit immediate address into
        a 16bit immediate address.  */
      if (ELF32_R_TYPE (irel->r_info) == (int) R_CRX_IMM32)
       {
         bfd_vma value = symval;

         /* See if the value will fit in 16 bits.  */
         if ((long) value < 0x7fff && (long) value > -0x8000)
           {
             unsigned short code;

             /* Get the opcode.  */
             code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset);

             /* Verify it's a 'arithmetic double'.  */
             if ((code & 0xf0f0) != 0x20f0)
              continue;

             /* Note that we've changed the relocs, section contents, etc.  */
             elf_section_data (sec)->relocs = internal_relocs;
             elf_section_data (sec)->this_hdr.contents = contents;
             symtab_hdr->contents = (unsigned char *) isymbuf;

             /* Fix the opcode.  */
             bfd_put_8 (abfd, (code & 0xff) - 0x10, contents + irel->r_offset);

             /* Fix the relocation's type.  */
             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
                                      R_CRX_IMM16);

             /* Delete two bytes of data.  */
             if (!elf32_crx_relax_delete_bytes (link_info, abfd, sec,
                                             irel->r_offset + 2, 2))
              goto error_return;

             /* That will change things, so, we should relax again.
               Note that this is not required, and it may be slow.  */
             *again = TRUE;
           }
       }
    }

  if (isymbuf != NULL
      && symtab_hdr->contents != (unsigned char *) isymbuf)
    {
      if (! link_info->keep_memory)
       free (isymbuf);
      else
       {
         /* Cache the symbols for elf_link_input_bfd.  */
         symtab_hdr->contents = (unsigned char *) isymbuf;
       }
    }

  if (contents != NULL
      && elf_section_data (sec)->this_hdr.contents != contents)
    {
      if (! link_info->keep_memory)
       free (contents);
      else
       {
         /* Cache the section contents for elf_link_input_bfd.  */
         elf_section_data (sec)->this_hdr.contents = contents;
       }
    }

  if (internal_relocs != NULL
      && elf_section_data (sec)->relocs != internal_relocs)
    free (internal_relocs);

  return TRUE;

 error_return:
  if (isymbuf != NULL
      && symtab_hdr->contents != (unsigned char *) isymbuf)
    free (isymbuf);
  if (contents != NULL
      && elf_section_data (sec)->this_hdr.contents != contents)
    free (contents);
  if (internal_relocs != NULL
      && elf_section_data (sec)->relocs != internal_relocs)
    free (internal_relocs);

  return FALSE;
}

Here is the call graph for this function:

static bfd_boolean elf32_crx_relocate_section ( bfd output_bfd,
struct bfd_link_info info,
bfd input_bfd,
asection input_section,
bfd_byte contents,
Elf_Internal_Rela relocs,
Elf_Internal_Sym *  local_syms,
asection **  local_sections 
) [static]

Definition at line 830 of file elf32-crx.c.

{
  Elf_Internal_Shdr *symtab_hdr;
  struct elf_link_hash_entry **sym_hashes;
  Elf_Internal_Rela *rel, *relend;

  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
  sym_hashes = elf_sym_hashes (input_bfd);

  rel = relocs;
  relend = relocs + input_section->reloc_count;
  for (; rel < relend; rel++)
    {
      int r_type;
      reloc_howto_type *howto;
      unsigned long r_symndx;
      Elf_Internal_Sym *sym;
      asection *sec;
      struct elf_link_hash_entry *h;
      bfd_vma relocation;
      bfd_reloc_status_type r;

      r_symndx = ELF32_R_SYM (rel->r_info);
      r_type = ELF32_R_TYPE (rel->r_info);
      howto = crx_elf_howto_table + (r_type);

      h = NULL;
      sym = NULL;
      sec = NULL;
      if (r_symndx < symtab_hdr->sh_info)
       {
         sym = local_syms + r_symndx;
         sec = local_sections[r_symndx];
         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
       }
      else
       {
         bfd_boolean unresolved_reloc, warned;

         RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
                               r_symndx, symtab_hdr, sym_hashes,
                               h, sec, relocation,
                               unresolved_reloc, warned);
       }

      if (sec != NULL && elf_discarded_section (sec))
       {
         /* For relocs against symbols from removed linkonce sections,
            or sections discarded by a linker script, we just want the
            section contents zeroed.  Avoid any special processing.  */
         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
         rel->r_info = 0;
         rel->r_addend = 0;
         continue;
       }

      if (info->relocatable)
       continue;

      r = crx_elf_final_link_relocate (howto, input_bfd, output_bfd,
                                   input_section,
                                   contents, rel->r_offset,
                                   relocation, rel->r_addend,
                                   info, sec, h == NULL);

      if (r != bfd_reloc_ok)
       {
         const char *name;
         const char *msg = (const char *) 0;

         if (h != NULL)
           name = h->root.root.string;
         else
           {
             name = (bfd_elf_string_from_elf_section
                    (input_bfd, symtab_hdr->sh_link, sym->st_name));
             if (name == NULL || *name == '\0')
              name = bfd_section_name (input_bfd, sec);
           }

         switch (r)
           {
            case bfd_reloc_overflow:
              if (!((*info->callbacks->reloc_overflow)
                   (info, (h ? &h->root : NULL), name, howto->name,
                    (bfd_vma) 0, input_bfd, input_section,
                    rel->r_offset)))
               return FALSE;
              break;

            case bfd_reloc_undefined:
              if (!((*info->callbacks->undefined_symbol)
                   (info, name, input_bfd, input_section,
                    rel->r_offset, TRUE)))
               return FALSE;
              break;

            case bfd_reloc_outofrange:
              msg = _("internal error: out of range error");
              goto common_error;

            case bfd_reloc_notsupported:
              msg = _("internal error: unsupported relocation error");
              goto common_error;

            case bfd_reloc_dangerous:
              msg = _("internal error: dangerous error");
              goto common_error;

            default:
              msg = _("internal error: unknown error");
              /* Fall through.  */

            common_error:
              if (!((*info->callbacks->warning)
                   (info, msg, name, input_bfd, input_section,
                    rel->r_offset)))
               return FALSE;
              break;
           }
       }
    }

  return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void elf_crx_info_to_howto ( bfd ,
arelent ,
Elf_Internal_Rela  
) [static]
static void elf_crx_info_to_howto ( bfd *abfd  ATTRIBUTE_UNUSED,
arelent cache_ptr,
Elf_Internal_Rela dst 
) [static]

Definition at line 421 of file elf32-crx.c.

{
  unsigned int r_type = ELF32_R_TYPE (dst->r_info);
  BFD_ASSERT (r_type < (unsigned int) R_CRX_MAX);
  cache_ptr->howto = &crx_elf_howto_table[r_type];
}
static reloc_howto_type* elf_crx_reloc_name_lookup ( bfd *abfd  ATTRIBUTE_UNUSED,
const char *  r_name 
) [static]

Definition at line 403 of file elf32-crx.c.

{
  unsigned int i;

  for (i = 0;
       i < sizeof (crx_elf_howto_table) / sizeof (crx_elf_howto_table[0]);
       i++)
    if (crx_elf_howto_table[i].name != NULL
       && strcasecmp (crx_elf_howto_table[i].name, r_name) == 0)
      return &crx_elf_howto_table[i];

  return NULL;
}

Here is the call graph for this function:

static reloc_howto_type* elf_crx_reloc_type_lookup ( bfd ,
bfd_reloc_code_real_type   
) [static]
static reloc_howto_type* elf_crx_reloc_type_lookup ( bfd *abfd  ATTRIBUTE_UNUSED,
bfd_reloc_code_real_type  code 
) [static]

Definition at line 389 of file elf32-crx.c.

{
  unsigned int i;

  for (i = 0; i < R_CRX_MAX; i++)
    if (code == crx_reloc_map[i].bfd_reloc_enum)
      return &crx_elf_howto_table[crx_reloc_map[i].crx_reloc_type];

  printf ("This relocation Type is not supported -0x%x\n", code);
  return 0;
}

Here is the call graph for this function:


Variable Documentation

reloc_howto_type crx_elf_howto_table[] [static]

Definition at line 80 of file elf32-crx.c.

struct crx_reloc_map[R_CRX_MAX] [static]
Initial value:
{
  {BFD_RELOC_NONE,       R_CRX_NONE},
  {BFD_RELOC_CRX_REL4,          R_CRX_REL4},
  {BFD_RELOC_CRX_REL8,          R_CRX_REL8},
  {BFD_RELOC_CRX_REL8_CMP,  R_CRX_REL8_CMP},
  {BFD_RELOC_CRX_REL16,         R_CRX_REL16},
  {BFD_RELOC_CRX_REL24,         R_CRX_REL24},
  {BFD_RELOC_CRX_REL32,         R_CRX_REL32},
  {BFD_RELOC_CRX_REGREL12,  R_CRX_REGREL12},
  {BFD_RELOC_CRX_REGREL22,  R_CRX_REGREL22},
  {BFD_RELOC_CRX_REGREL28,  R_CRX_REGREL28},
  {BFD_RELOC_CRX_REGREL32,  R_CRX_REGREL32},
  {BFD_RELOC_CRX_ABS16,         R_CRX_ABS16},
  {BFD_RELOC_CRX_ABS32,         R_CRX_ABS32},
  {BFD_RELOC_CRX_NUM8,          R_CRX_NUM8},
  {BFD_RELOC_CRX_NUM16,         R_CRX_NUM16},
  {BFD_RELOC_CRX_NUM32,         R_CRX_NUM32},
  {BFD_RELOC_CRX_IMM16,         R_CRX_IMM16},
  {BFD_RELOC_CRX_IMM32,         R_CRX_IMM32},
  {BFD_RELOC_CRX_SWITCH8,   R_CRX_SWITCH8},
  {BFD_RELOC_CRX_SWITCH16,  R_CRX_SWITCH16},
  {BFD_RELOC_CRX_SWITCH32,  R_CRX_SWITCH32}
}

Definition at line 55 of file elf32-crx.c.