121288Sdavidn/* BFD back-end for AMD 29000 COFF binaries.
221288Sdavidn   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1999, 2000, 2001,
321288Sdavidn   2002, 2003
421288Sdavidn   Free Software Foundation, Inc.
521288Sdavidn   Contributed by David Wood at New York University 7/8/91.
621288Sdavidn
721288SdavidnThis file is part of BFD, the Binary File Descriptor library.
821288Sdavidn
921288SdavidnThis program is free software; you can redistribute it and/or modify
1021288Sdavidnit under the terms of the GNU General Public License as published by
1121288Sdavidnthe Free Software Foundation; either version 2 of the License, or
1221288Sdavidn(at your option) any later version.
1321288Sdavidn
1421288SdavidnThis program is distributed in the hope that it will be useful,
1521288Sdavidnbut WITHOUT ANY WARRANTY; without even the implied warranty of
1621288SdavidnMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1721288SdavidnGNU General Public License for more details.
1821288Sdavidn
1921288SdavidnYou should have received a copy of the GNU General Public License
2021288Sdavidnalong with this program; if not, write to the Free Software
2121288SdavidnFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2221288Sdavidn
2321288Sdavidn#define A29K 1
2436607Sjb
2521288Sdavidn#include "bfd.h"
2621288Sdavidn#include "sysdep.h"
2721288Sdavidn#include "libbfd.h"
2821288Sdavidn#include "coff/a29k.h"
2921288Sdavidn#include "coff/internal.h"
3021288Sdavidn#include "libcoff.h"
3121288Sdavidn
3221288Sdavidnstatic long get_symbol_value PARAMS ((asymbol *));
3322084Sdavidnstatic bfd_reloc_status_type a29k_reloc
3421288Sdavidn  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
3521288Sdavidnstatic bfd_boolean coff_a29k_relocate_section
3621288Sdavidn  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
3721288Sdavidn	   struct internal_reloc *, struct internal_syment *, asection **));
3821288Sdavidnstatic bfd_boolean coff_a29k_adjust_symndx
3921288Sdavidn  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *,
4021288Sdavidn	   struct internal_reloc *, bfd_boolean *));
4136351Sstevestatic void reloc_processing
4221288Sdavidn  PARAMS ((arelent *, struct internal_reloc *, asymbol **, bfd *, asection *));
4321288Sdavidn
4421288Sdavidn#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
4521288Sdavidn
4621288Sdavidn#define INSERT_HWORD(WORD,HWORD)	\
4721288Sdavidn    (((WORD) & 0xff00ff00) | (((HWORD) & 0xff00) << 8) | ((HWORD)& 0xff))
4821288Sdavidn#define EXTRACT_HWORD(WORD) \
4925670Sdavidn    ((((WORD) & 0x00ff0000) >> 8) | ((WORD) & 0xff))
5025670Sdavidn#define SIGN_EXTEND_HWORD(HWORD) \
5125670Sdavidn    (((HWORD) ^ 0x8000) - 0x8000)
5221288Sdavidn
5325670Sdavidn/* Provided the symbol, returns the value reffed.  */
5425670Sdavidn
5525670Sdavidnstatic long
5625670Sdavidnget_symbol_value (symbol)
5725670Sdavidn     asymbol *symbol;
5825670Sdavidn{
5925670Sdavidn  long relocation = 0;
6025670Sdavidn
6125670Sdavidn  if (bfd_is_com_section (symbol->section))
6225670Sdavidn    relocation = 0;
6321288Sdavidn  else
6421288Sdavidn    relocation = symbol->value +
6521288Sdavidn      symbol->section->output_section->vma +
6621288Sdavidn      symbol->section->output_offset;
6721288Sdavidn
6821288Sdavidn  return relocation;
6925670Sdavidn}
7021288Sdavidn
7125670Sdavidn/* This function is in charge of performing all the 29k relocations.  */
7225670Sdavidn
7321402Sdavidnstatic bfd_reloc_status_type
7425670Sdavidna29k_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
7525670Sdavidn	    error_message)
7621288Sdavidn     bfd *abfd;
7725670Sdavidn     arelent *reloc_entry;
7825670Sdavidn     asymbol *symbol_in;
7925670Sdavidn     PTR data;
8025670Sdavidn     asection *input_section;
8125670Sdavidn     bfd *output_bfd;
8225670Sdavidn     char **error_message;
8325670Sdavidn{
8425670Sdavidn  /* The consth relocation comes in two parts, we have to remember
8525670Sdavidn     the state between calls, in these variables.  */
8625670Sdavidn  static bfd_boolean part1_consth_active = FALSE;
8725670Sdavidn  static unsigned long part1_consth_value;
8821288Sdavidn  unsigned long insn;
8925670Sdavidn  unsigned long sym_value;
9025670Sdavidn  unsigned long unsigned_value;
9125670Sdavidn  unsigned short r_type;
9225670Sdavidn  long signed_value;
9325670Sdavidn  unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/
9425670Sdavidn  bfd_byte  *hit_data =addr + (bfd_byte *) (data);
9525670Sdavidn
9621288Sdavidn  r_type = reloc_entry->howto->type;
9725670Sdavidn
9825670Sdavidn  if (output_bfd)
9921288Sdavidn    {
10025670Sdavidn      /* Partial linking - do nothing.  */
10125670Sdavidn      reloc_entry->address += input_section->output_offset;
10225670Sdavidn      return bfd_reloc_ok;
10325670Sdavidn    }
10421288Sdavidn
10525670Sdavidn  if (symbol_in != NULL
10625670Sdavidn      && bfd_is_und_section (symbol_in->section))
10725670Sdavidn    {
10825670Sdavidn      /* Keep the state machine happy in case we're called again.  */
10921288Sdavidn      if (r_type == R_IHIHALF)
11021288Sdavidn	{
11125670Sdavidn	  part1_consth_active = TRUE;
11225670Sdavidn	  part1_consth_value  = 0;
11321288Sdavidn	}
11425670Sdavidn      return bfd_reloc_undefined;
11525670Sdavidn    }
11625670Sdavidn
11721288Sdavidn  if ((part1_consth_active) && (r_type != R_IHCONST))
11825670Sdavidn    {
11925670Sdavidn      part1_consth_active = FALSE;
12025670Sdavidn      *error_message = (char *) _("Missing IHCONST");
12125670Sdavidn
12221288Sdavidn      return bfd_reloc_dangerous;
12325670Sdavidn    }
12425670Sdavidn
12525670Sdavidn  sym_value = get_symbol_value(symbol_in);
12625670Sdavidn
12725670Sdavidn  switch (r_type)
12821288Sdavidn    {
12921288Sdavidn    case R_IREL:
13021288Sdavidn      insn = bfd_get_32 (abfd, hit_data);
13121288Sdavidn      /* Take the value in the field and sign extend it.  */
13221288Sdavidn      signed_value = EXTRACT_HWORD(insn);
13325670Sdavidn      signed_value = SIGN_EXTEND_HWORD(signed_value);
13421288Sdavidn      signed_value <<= 2;
13525670Sdavidn
13625670Sdavidn      /* See the note on the R_IREL reloc in coff_a29k_relocate_section.  */
13725670Sdavidn      if (signed_value == - (long) reloc_entry->address)
13825670Sdavidn	signed_value = 0;
13921288Sdavidn
14025670Sdavidn      signed_value += sym_value + reloc_entry->addend;
14125670Sdavidn      if ((signed_value & ~0x3ffff) == 0)
14225670Sdavidn	{				/* Absolute jmp/call */
14325670Sdavidn	  insn |= (1 << 24);		/* Make it absolute */
14425670Sdavidn	  /* FIXME: Should we change r_type to R_IABS.  */
14525670Sdavidn	}
14625670Sdavidn      else
14725670Sdavidn	{
14825670Sdavidn	  /* Relative jmp/call, so subtract from the value the
14925670Sdavidn	     address of the place we're coming from.  */
15021288Sdavidn	  signed_value -= (reloc_entry->address
15125670Sdavidn			   + input_section->output_section->vma
15225670Sdavidn			   + input_section->output_offset);
15325670Sdavidn	  if (signed_value > 0x1ffff || signed_value < -0x20000)
15421288Sdavidn	    return bfd_reloc_overflow;
15525670Sdavidn	}
15625670Sdavidn      signed_value >>= 2;
15721288Sdavidn      insn = INSERT_HWORD (insn, signed_value);
15825670Sdavidn      bfd_put_32 (abfd, (bfd_vma) insn ,hit_data);
15925670Sdavidn      break;
16025670Sdavidn    case R_ILOHALF:
16125670Sdavidn      insn = bfd_get_32 (abfd, hit_data);
16225670Sdavidn      unsigned_value = EXTRACT_HWORD(insn);
16325670Sdavidn      unsigned_value +=  sym_value + reloc_entry->addend;
16425670Sdavidn      insn = INSERT_HWORD(insn, unsigned_value);
16521288Sdavidn      bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
16625670Sdavidn      break;
16725670Sdavidn    case R_IHIHALF:
16825670Sdavidn      insn = bfd_get_32 (abfd, hit_data);
16925670Sdavidn      /* consth, part 1
17025670Sdavidn	 Just get the symbol value that is referenced.  */
17125670Sdavidn      part1_consth_active = TRUE;
17225670Sdavidn      part1_consth_value = sym_value + reloc_entry->addend;
17325670Sdavidn      /* Don't modify insn until R_IHCONST.  */
17425670Sdavidn      break;
17525670Sdavidn    case R_IHCONST:
17625670Sdavidn      insn = bfd_get_32 (abfd, hit_data);
17725670Sdavidn      /* consth, part 2
17825670Sdavidn	 Now relocate the reference.  */
17925670Sdavidn      if (! part1_consth_active)
18025670Sdavidn	{
18125670Sdavidn	  *error_message = (char *) _("Missing IHIHALF");
18225670Sdavidn	  return bfd_reloc_dangerous;
18321288Sdavidn	}
18421288Sdavidn      /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */
18525670Sdavidn      unsigned_value = 0;		/*EXTRACT_HWORD(insn) << 16;*/
18625670Sdavidn      unsigned_value += reloc_entry->addend; /* r_symndx */
18721288Sdavidn      unsigned_value += part1_consth_value;
18821288Sdavidn      unsigned_value = unsigned_value >> 16;
18921288Sdavidn      insn = INSERT_HWORD(insn, unsigned_value);
19021288Sdavidn      part1_consth_active = FALSE;
19121288Sdavidn      bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
19221288Sdavidn      break;
19325670Sdavidn    case R_BYTE:
19425670Sdavidn      insn = bfd_get_8 (abfd, hit_data);
19525670Sdavidn      unsigned_value = insn + sym_value + reloc_entry->addend;
19625670Sdavidn      if (unsigned_value & 0xffffff00)
19721288Sdavidn	return bfd_reloc_overflow;
19825670Sdavidn      bfd_put_8 (abfd, unsigned_value, hit_data);
19925670Sdavidn      break;
20021288Sdavidn    case R_HWORD:
20125670Sdavidn      insn = bfd_get_16 (abfd, hit_data);
20225670Sdavidn      unsigned_value = insn + sym_value + reloc_entry->addend;
20325670Sdavidn      if (unsigned_value & 0xffff0000)
20421288Sdavidn	return bfd_reloc_overflow;
20525670Sdavidn      bfd_put_16 (abfd, (bfd_vma) insn, hit_data);
20621288Sdavidn      break;
20725670Sdavidn    case R_WORD:
20825670Sdavidn      insn = bfd_get_32 (abfd, hit_data);
20925670Sdavidn      insn += sym_value + reloc_entry->addend;
21025670Sdavidn      bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
21125670Sdavidn      break;
21225670Sdavidn    default:
21325670Sdavidn      *error_message = _("Unrecognized reloc");
21421288Sdavidn      return bfd_reloc_dangerous;
21521288Sdavidn    }
21625670Sdavidn
21725670Sdavidn  return(bfd_reloc_ok);
21825670Sdavidn}
21925670Sdavidn
22025670Sdavidn/*FIXME: I'm not real sure about this table.  */
22125670Sdavidnstatic reloc_howto_type howto_table[] =
22221402Sdavidn  {
22325670Sdavidn    {R_ABS,     0, 3, 32, FALSE, 0, complain_overflow_bitfield,a29k_reloc,"ABS",     TRUE, 0xffffffff,0xffffffff, FALSE},
22425670Sdavidn    EMPTY_HOWTO (1),
22525670Sdavidn    EMPTY_HOWTO (2),
22621402Sdavidn    EMPTY_HOWTO (3),
22725670Sdavidn    EMPTY_HOWTO (4),
22825670Sdavidn    EMPTY_HOWTO (5),
22925670Sdavidn    EMPTY_HOWTO (6),
23025670Sdavidn    EMPTY_HOWTO (7),
23125670Sdavidn    EMPTY_HOWTO (8),
23225670Sdavidn    EMPTY_HOWTO (9),
23325670Sdavidn    EMPTY_HOWTO (10),
23425670Sdavidn    EMPTY_HOWTO (11),
23525670Sdavidn    EMPTY_HOWTO (12),
23625670Sdavidn    EMPTY_HOWTO (13),
23725670Sdavidn    EMPTY_HOWTO (14),
23821288Sdavidn    EMPTY_HOWTO (15),
23921288Sdavidn    EMPTY_HOWTO (16),
24021288Sdavidn    EMPTY_HOWTO (17),
24121288Sdavidn    EMPTY_HOWTO (18),
24221288Sdavidn    EMPTY_HOWTO (19),
24321288Sdavidn    EMPTY_HOWTO (20),
24421288Sdavidn    EMPTY_HOWTO (21),
24521288Sdavidn    EMPTY_HOWTO (22),
24621288Sdavidn    EMPTY_HOWTO (23),
24721288Sdavidn    {R_IREL,    0, 3, 32, TRUE,  0, complain_overflow_signed,a29k_reloc,"IREL",    TRUE, 0xffffffff,0xffffffff, FALSE},
24821288Sdavidn    {R_IABS,    0, 3, 32, FALSE, 0, complain_overflow_bitfield, a29k_reloc,"IABS",    TRUE, 0xffffffff,0xffffffff, FALSE},
24921288Sdavidn    {R_ILOHALF, 0, 3, 16, TRUE,  0, complain_overflow_signed, a29k_reloc,"ILOHALF", TRUE, 0x0000ffff,0x0000ffff, FALSE},
25021288Sdavidn    {R_IHIHALF, 0, 3, 16, TRUE,  16, complain_overflow_signed, a29k_reloc,"IHIHALF", TRUE, 0xffff0000,0xffff0000, FALSE},
25121288Sdavidn    {R_IHCONST, 0, 3, 16, TRUE,  0, complain_overflow_signed, a29k_reloc,"IHCONST", TRUE, 0xffff0000,0xffff0000, FALSE},
25221288Sdavidn    {R_BYTE,    0, 0, 8, FALSE, 0, complain_overflow_bitfield, a29k_reloc,"BYTE",    TRUE, 0x000000ff,0x000000ff, FALSE},
25321288Sdavidn    {R_HWORD,   0, 1, 16, FALSE, 0, complain_overflow_bitfield, a29k_reloc,"HWORD",   TRUE, 0x0000ffff,0x0000ffff, FALSE},
25421288Sdavidn    {R_WORD,    0, 2, 32, FALSE, 0, complain_overflow_bitfield, a29k_reloc,"WORD",    TRUE, 0xffffffff,0xffffffff, FALSE},
25521288Sdavidn  };
25621288Sdavidn
25725670Sdavidn#define BADMAG(x) A29KBADMAG(x)
25825670Sdavidn
25925670Sdavidn#define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
26025670Sdavidn reloc_processing(relent, reloc, symbols, abfd, section)
26125670Sdavidn
26225670Sdavidnstatic void
26325670Sdavidnreloc_processing (relent,reloc, symbols, abfd, section)
26425670Sdavidn     arelent *relent;
26525670Sdavidn     struct internal_reloc *reloc;
26625670Sdavidn     asymbol **symbols;
26725670Sdavidn     bfd *abfd;
26821288Sdavidn     asection *section;
26921288Sdavidn{
27021288Sdavidn  static bfd_vma ihihalf_vaddr = (bfd_vma) -1;
27125670Sdavidn
27221288Sdavidn  relent->address = reloc->r_vaddr;
27325670Sdavidn  relent->howto = howto_table + reloc->r_type;
27425670Sdavidn  if (reloc->r_type == R_IHCONST)
27525670Sdavidn    {
27625670Sdavidn      /* The address of an R_IHCONST should always be the address of
27725670Sdavidn	 the immediately preceding R_IHIHALF.  relocs generated by gas
27825670Sdavidn	 are correct, but relocs generated by High C are different (I
27925670Sdavidn	 can't figure out what the address means for High C).  We can
28025670Sdavidn	 handle both gas and High C by ignoring the address here, and
28125670Sdavidn	 simply reusing the address saved for R_IHIHALF.  */
28225670Sdavidn      if (ihihalf_vaddr == (bfd_vma) -1)
28325670Sdavidn	abort ();
28425670Sdavidn      relent->address = ihihalf_vaddr;
28525670Sdavidn      ihihalf_vaddr = (bfd_vma) -1;
28625670Sdavidn      relent->addend = reloc->r_symndx;
28725670Sdavidn      relent->sym_ptr_ptr= bfd_abs_section_ptr->symbol_ptr_ptr;
28825670Sdavidn    }
28925670Sdavidn  else
29025670Sdavidn    {
29125670Sdavidn      asymbol *ptr;
29225670Sdavidn
29325670Sdavidn      relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
29425670Sdavidn
29525670Sdavidn      ptr = *(relent->sym_ptr_ptr);
29625670Sdavidn
29725670Sdavidn      if (ptr
29825670Sdavidn	  && bfd_asymbol_bfd(ptr) == abfd
29925670Sdavidn	  && ((ptr->flags & BSF_OLD_COMMON) == 0))
30021288Sdavidn	relent->addend = 0;
30121288Sdavidn      else
30221288Sdavidn	relent->addend = 0;
30321288Sdavidn
30421288Sdavidn      relent->address-= section->vma;
30521288Sdavidn      if (reloc->r_type == R_IHIHALF)
30621288Sdavidn	ihihalf_vaddr = relent->address;
30721288Sdavidn      else if (ihihalf_vaddr != (bfd_vma) -1)
30821288Sdavidn	abort ();
30921288Sdavidn    }
31021288Sdavidn}
31121288Sdavidn
31221288Sdavidn/* The reloc processing routine for the optimized COFF linker.  */
31321288Sdavidn
31421288Sdavidnstatic bfd_boolean
31521288Sdavidncoff_a29k_relocate_section (output_bfd, info, input_bfd, input_section,
31625670Sdavidn			    contents, relocs, syms, sections)
31725670Sdavidn     bfd *output_bfd ATTRIBUTE_UNUSED;
31825670Sdavidn     struct bfd_link_info *info;
31936607Sjb     bfd *input_bfd;
32036351Ssteve     asection *input_section;
32136607Sjb     bfd_byte *contents;
32221288Sdavidn     struct internal_reloc *relocs;
32325670Sdavidn     struct internal_syment *syms;
32425670Sdavidn     asection **sections;
32525670Sdavidn{
32625670Sdavidn  struct internal_reloc *rel;
32721288Sdavidn  struct internal_reloc *relend;
32825670Sdavidn  bfd_boolean hihalf;
32925670Sdavidn  bfd_vma hihalf_val;
33021288Sdavidn
33125670Sdavidn  /* If we are performing a relocatable link, we don't need to do a
33225670Sdavidn     thing.  The caller will take care of adjusting the reloc
33325670Sdavidn     addresses and symbol indices.  */
33421288Sdavidn  if (info->relocatable)
33525670Sdavidn    return TRUE;
33625670Sdavidn
33725670Sdavidn  hihalf = FALSE;
33821288Sdavidn  hihalf_val = 0;
33936351Ssteve
34036607Sjb  rel = relocs;
34136351Ssteve  relend = rel + input_section->reloc_count;
34236351Ssteve  for (; rel < relend; rel++)
34336351Ssteve    {
34436351Ssteve      long symndx;
34536351Ssteve      bfd_byte *loc;
34636351Ssteve      struct coff_link_hash_entry *h;
34736607Sjb      struct internal_syment *sym;
34836351Ssteve      asection *sec;
34936607Sjb      bfd_vma val;
35036351Ssteve      bfd_boolean overflow;
35136351Ssteve      unsigned long insn;
35236351Ssteve      long signed_value;
35336351Ssteve      unsigned long unsigned_value;
35436351Ssteve      bfd_reloc_status_type rstat;
35536351Ssteve
35636607Sjb      symndx = rel->r_symndx;
35736351Ssteve      loc = contents + rel->r_vaddr - input_section->vma;
35836351Ssteve
35936351Ssteve      if (symndx == -1 || rel->r_type == R_IHCONST)
36036351Ssteve	h = NULL;
36136351Ssteve      else
36225670Sdavidn	h = obj_coff_sym_hashes (input_bfd)[symndx];
36321288Sdavidn
36425670Sdavidn      sym = NULL;
36525670Sdavidn      sec = NULL;
36625670Sdavidn      val = 0;
36725670Sdavidn
36825670Sdavidn      /* An R_IHCONST reloc does not have a symbol.  Instead, the
36925670Sdavidn         symbol index is an addend.  R_IHCONST is always used in
37025670Sdavidn         conjunction with R_IHHALF.  */
37125670Sdavidn      if (rel->r_type != R_IHCONST)
37225670Sdavidn	{
37325670Sdavidn	  if (h == NULL)
37425670Sdavidn	    {
37525670Sdavidn	      if (symndx == -1)
37625670Sdavidn		sec = bfd_abs_section_ptr;
37725670Sdavidn	      else
37821288Sdavidn		{
37925670Sdavidn		  sym = syms + symndx;
38025670Sdavidn		  sec = sections[symndx];
38125670Sdavidn		  val = (sec->output_section->vma
38225670Sdavidn			 + sec->output_offset
38325670Sdavidn			 + sym->n_value
38425670Sdavidn			 - sec->vma);
38521288Sdavidn		}
38625670Sdavidn	    }
38725670Sdavidn	  else
38825670Sdavidn	    {
38921288Sdavidn	      if (   h->root.type == bfd_link_hash_defined
39025670Sdavidn		  || h->root.type == bfd_link_hash_defweak)
39125670Sdavidn		{
39225670Sdavidn		  sec = h->root.u.def.section;
39325670Sdavidn		  val = (h->root.u.def.value
39421288Sdavidn			 + sec->output_section->vma
39521288Sdavidn			 + sec->output_offset);
39625670Sdavidn		}
39725670Sdavidn	      else
39825670Sdavidn		{
39925670Sdavidn		  if (! ((*info->callbacks->undefined_symbol)
40025670Sdavidn			 (info, h->root.root.string, input_bfd, input_section,
40125670Sdavidn			  rel->r_vaddr - input_section->vma, TRUE)))
40225670Sdavidn		    return FALSE;
40321288Sdavidn		}
40425670Sdavidn	    }
40525670Sdavidn
40625670Sdavidn	  if (hihalf)
40721288Sdavidn	    {
40825670Sdavidn	      if (! ((*info->callbacks->reloc_dangerous)
40921288Sdavidn		     (info, _("missing IHCONST reloc"), input_bfd,
41021288Sdavidn		      input_section, rel->r_vaddr - input_section->vma)))
411		return FALSE;
412	      hihalf = FALSE;
413	    }
414	}
415
416      overflow = FALSE;
417
418      switch (rel->r_type)
419	{
420	default:
421	  bfd_set_error (bfd_error_bad_value);
422	  return FALSE;
423
424	case R_IREL:
425	  insn = bfd_get_32 (input_bfd, loc);
426
427	  /* Extract the addend.  */
428	  signed_value = EXTRACT_HWORD (insn);
429	  signed_value = SIGN_EXTEND_HWORD (signed_value);
430	  signed_value <<= 2;
431
432	  /* Unfortunately, there are two different versions of COFF
433	     a29k.  In the original AMD version, the value stored in
434	     the field for the R_IREL reloc is a simple addend.  In
435	     the GNU version, the value is the negative of the address
436	     of the reloc within section.  We try to cope here by
437	     assuming the AMD version, unless the addend is exactly
438	     the negative of the address; in the latter case we assume
439	     the GNU version.  This means that something like
440	         .text
441		 nop
442		 jmp i-4
443	     will fail, because the addend of -4 will happen to equal
444	     the negative of the address within the section.  The
445	     compiler will never generate code like this.
446
447	     At some point in the future we may want to take out this
448	     check.  */
449
450	  if (signed_value == - (long) (rel->r_vaddr - input_section->vma))
451	    signed_value = 0;
452
453	  /* Determine the destination of the jump.  */
454	  signed_value += val;
455
456	  if ((signed_value & ~0x3ffff) == 0)
457	    {
458	      /* We can use an absolute jump.  */
459	      insn |= (1 << 24);
460	    }
461	  else
462	    {
463	      /* Make the destination PC relative.  */
464	      signed_value -= (input_section->output_section->vma
465			       + input_section->output_offset
466			       + (rel->r_vaddr - input_section->vma));
467	      if (signed_value > 0x1ffff || signed_value < - 0x20000)
468		{
469		  overflow = TRUE;
470		  signed_value = 0;
471		}
472	    }
473
474	  /* Put the adjusted value back into the instruction.  */
475	  signed_value >>= 2;
476	  insn = INSERT_HWORD (insn, signed_value);
477
478	  bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
479	  break;
480
481	case R_ILOHALF:
482	  insn = bfd_get_32 (input_bfd, loc);
483	  unsigned_value = EXTRACT_HWORD (insn);
484	  unsigned_value += val;
485	  insn = INSERT_HWORD (insn, unsigned_value);
486	  bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
487	  break;
488
489	case R_IHIHALF:
490	  /* Save the value for the R_IHCONST reloc.  */
491	  hihalf = TRUE;
492	  hihalf_val = val;
493	  break;
494
495	case R_IHCONST:
496	  if (! hihalf)
497	    {
498	      if (! ((*info->callbacks->reloc_dangerous)
499		     (info, _("missing IHIHALF reloc"), input_bfd,
500		      input_section, rel->r_vaddr - input_section->vma)))
501		return FALSE;
502	      hihalf_val = 0;
503	    }
504
505	  insn = bfd_get_32 (input_bfd, loc);
506	  unsigned_value = rel->r_symndx + hihalf_val;
507	  unsigned_value >>= 16;
508	  insn = INSERT_HWORD (insn, unsigned_value);
509	  bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
510
511	  hihalf = FALSE;
512
513	  break;
514
515	case R_BYTE:
516	case R_HWORD:
517	case R_WORD:
518	  rstat = _bfd_relocate_contents (howto_table + rel->r_type,
519					  input_bfd, val, loc);
520	  if (rstat == bfd_reloc_overflow)
521	    overflow = TRUE;
522	  else if (rstat != bfd_reloc_ok)
523	    abort ();
524	  break;
525	}
526
527      if (overflow)
528	{
529	  const char *name;
530	  char buf[SYMNMLEN + 1];
531
532	  if (symndx == -1)
533	    name = "*ABS*";
534	  else if (h != NULL)
535	    name = h->root.root.string;
536	  else if (sym == NULL)
537	    name = "*unknown*";
538	  else if (sym->_n._n_n._n_zeroes == 0
539		   && sym->_n._n_n._n_offset != 0)
540	    name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
541	  else
542	    {
543	      strncpy (buf, sym->_n._n_name, SYMNMLEN);
544	      buf[SYMNMLEN] = '\0';
545	      name = buf;
546	    }
547
548	  if (! ((*info->callbacks->reloc_overflow)
549		 (info, name, howto_table[rel->r_type].name, (bfd_vma) 0,
550		  input_bfd, input_section,
551		  rel->r_vaddr - input_section->vma)))
552	    return FALSE;
553	}
554    }
555
556  return TRUE;
557}
558
559#define coff_relocate_section coff_a29k_relocate_section
560
561/* We don't want to change the symndx of a R_IHCONST reloc, since it
562   is actually an addend, not a symbol index at all.  */
563
564static bfd_boolean
565coff_a29k_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
566     bfd *obfd ATTRIBUTE_UNUSED;
567     struct bfd_link_info *info ATTRIBUTE_UNUSED;
568     bfd *ibfd ATTRIBUTE_UNUSED;
569     asection *sec ATTRIBUTE_UNUSED;
570     struct internal_reloc *irel;
571     bfd_boolean *adjustedp;
572{
573  if (irel->r_type == R_IHCONST)
574    *adjustedp = TRUE;
575  else
576    *adjustedp = FALSE;
577  return TRUE;
578}
579
580#define coff_adjust_symndx coff_a29k_adjust_symndx
581
582#include "coffcode.h"
583
584CREATE_BIG_COFF_TARGET_VEC (a29kcoff_big_vec, "coff-a29k-big", 0, SEC_READONLY, '_', NULL, COFF_SWAP_TABLE)
585