xref: /openbsd-src/gnu/usr.bin/binutils/bfd/coff-a29k.c (revision 007c2a4539b8b8aaa95c5e73e77620090abe113b)
12159047fSniklas /* BFD back-end for AMD 29000 COFF binaries.
2*007c2a45Smiod    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1999, 2000, 2001,
3*007c2a45Smiod    2002, 2003
4b305b0f1Sespie    Free Software Foundation, Inc.
52159047fSniklas    Contributed by David Wood at New York University 7/8/91.
62159047fSniklas 
72159047fSniklas This file is part of BFD, the Binary File Descriptor library.
82159047fSniklas 
92159047fSniklas This program is free software; you can redistribute it and/or modify
102159047fSniklas it under the terms of the GNU General Public License as published by
112159047fSniklas the Free Software Foundation; either version 2 of the License, or
122159047fSniklas (at your option) any later version.
132159047fSniklas 
142159047fSniklas This program is distributed in the hope that it will be useful,
152159047fSniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
162159047fSniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
172159047fSniklas GNU General Public License for more details.
182159047fSniklas 
192159047fSniklas You should have received a copy of the GNU General Public License
202159047fSniklas along with this program; if not, write to the Free Software
212159047fSniklas Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
222159047fSniklas 
232159047fSniklas #define A29K 1
242159047fSniklas 
252159047fSniklas #include "bfd.h"
262159047fSniklas #include "sysdep.h"
272159047fSniklas #include "libbfd.h"
282159047fSniklas #include "coff/a29k.h"
292159047fSniklas #include "coff/internal.h"
302159047fSniklas #include "libcoff.h"
312159047fSniklas 
322159047fSniklas static long get_symbol_value PARAMS ((asymbol *));
332159047fSniklas static bfd_reloc_status_type a29k_reloc
342159047fSniklas   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
35c074d1c9Sdrahn static bfd_boolean coff_a29k_relocate_section
362159047fSniklas   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
372159047fSniklas 	   struct internal_reloc *, struct internal_syment *, asection **));
38c074d1c9Sdrahn static bfd_boolean coff_a29k_adjust_symndx
392159047fSniklas   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *,
40c074d1c9Sdrahn 	   struct internal_reloc *, bfd_boolean *));
41c074d1c9Sdrahn static void reloc_processing
42c074d1c9Sdrahn   PARAMS ((arelent *, struct internal_reloc *, asymbol **, bfd *, asection *));
432159047fSniklas 
442159047fSniklas #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
452159047fSniklas 
462159047fSniklas #define INSERT_HWORD(WORD,HWORD)	\
472159047fSniklas     (((WORD) & 0xff00ff00) | (((HWORD) & 0xff00) << 8) | ((HWORD)& 0xff))
482159047fSniklas #define EXTRACT_HWORD(WORD) \
492159047fSniklas     ((((WORD) & 0x00ff0000) >> 8) | ((WORD) & 0xff))
502159047fSniklas #define SIGN_EXTEND_HWORD(HWORD) \
51b55d4692Sfgsch     (((HWORD) ^ 0x8000) - 0x8000)
522159047fSniklas 
53c074d1c9Sdrahn /* Provided the symbol, returns the value reffed.  */
54c074d1c9Sdrahn 
552159047fSniklas static long
get_symbol_value(symbol)562159047fSniklas get_symbol_value (symbol)
572159047fSniklas      asymbol *symbol;
582159047fSniklas {
592159047fSniklas   long relocation = 0;
602159047fSniklas 
612159047fSniklas   if (bfd_is_com_section (symbol->section))
622159047fSniklas     relocation = 0;
632159047fSniklas   else
642159047fSniklas     relocation = symbol->value +
652159047fSniklas       symbol->section->output_section->vma +
662159047fSniklas       symbol->section->output_offset;
67c074d1c9Sdrahn 
68c074d1c9Sdrahn   return relocation;
692159047fSniklas }
702159047fSniklas 
71c074d1c9Sdrahn /* This function is in charge of performing all the 29k relocations.  */
722159047fSniklas 
732159047fSniklas static bfd_reloc_status_type
a29k_reloc(abfd,reloc_entry,symbol_in,data,input_section,output_bfd,error_message)742159047fSniklas a29k_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
752159047fSniklas 	    error_message)
762159047fSniklas      bfd *abfd;
772159047fSniklas      arelent *reloc_entry;
782159047fSniklas      asymbol *symbol_in;
792159047fSniklas      PTR data;
802159047fSniklas      asection *input_section;
812159047fSniklas      bfd *output_bfd;
822159047fSniklas      char **error_message;
832159047fSniklas {
84c074d1c9Sdrahn   /* The consth relocation comes in two parts, we have to remember
85c074d1c9Sdrahn      the state between calls, in these variables.  */
86c074d1c9Sdrahn   static bfd_boolean part1_consth_active = FALSE;
872159047fSniklas   static unsigned long part1_consth_value;
882159047fSniklas   unsigned long insn;
892159047fSniklas   unsigned long sym_value;
902159047fSniklas   unsigned long unsigned_value;
912159047fSniklas   unsigned short r_type;
922159047fSniklas   long signed_value;
932159047fSniklas   unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/
942159047fSniklas   bfd_byte  *hit_data =addr + (bfd_byte *) (data);
952159047fSniklas 
962159047fSniklas   r_type = reloc_entry->howto->type;
972159047fSniklas 
98b55d4692Sfgsch   if (output_bfd)
99b55d4692Sfgsch     {
100c074d1c9Sdrahn       /* Partial linking - do nothing.  */
1012159047fSniklas       reloc_entry->address += input_section->output_offset;
1022159047fSniklas       return bfd_reloc_ok;
1032159047fSniklas     }
1042159047fSniklas 
1052159047fSniklas   if (symbol_in != NULL
1062159047fSniklas       && bfd_is_und_section (symbol_in->section))
1072159047fSniklas     {
108c074d1c9Sdrahn       /* Keep the state machine happy in case we're called again.  */
1092159047fSniklas       if (r_type == R_IHIHALF)
1102159047fSniklas 	{
111c074d1c9Sdrahn 	  part1_consth_active = TRUE;
1122159047fSniklas 	  part1_consth_value  = 0;
1132159047fSniklas 	}
114c074d1c9Sdrahn       return bfd_reloc_undefined;
1152159047fSniklas     }
1162159047fSniklas 
1172159047fSniklas   if ((part1_consth_active) && (r_type != R_IHCONST))
1182159047fSniklas     {
119c074d1c9Sdrahn       part1_consth_active = FALSE;
120b305b0f1Sespie       *error_message = (char *) _("Missing IHCONST");
121c074d1c9Sdrahn 
122c074d1c9Sdrahn       return bfd_reloc_dangerous;
1232159047fSniklas     }
1242159047fSniklas 
1252159047fSniklas   sym_value = get_symbol_value(symbol_in);
1262159047fSniklas 
1272159047fSniklas   switch (r_type)
1282159047fSniklas     {
1292159047fSniklas     case R_IREL:
1302159047fSniklas       insn = bfd_get_32 (abfd, hit_data);
131c074d1c9Sdrahn       /* Take the value in the field and sign extend it.  */
1322159047fSniklas       signed_value = EXTRACT_HWORD(insn);
1332159047fSniklas       signed_value = SIGN_EXTEND_HWORD(signed_value);
1342159047fSniklas       signed_value <<= 2;
1352159047fSniklas 
1362159047fSniklas       /* See the note on the R_IREL reloc in coff_a29k_relocate_section.  */
1372159047fSniklas       if (signed_value == - (long) reloc_entry->address)
1382159047fSniklas 	signed_value = 0;
1392159047fSniklas 
1402159047fSniklas       signed_value += sym_value + reloc_entry->addend;
1412159047fSniklas       if ((signed_value & ~0x3ffff) == 0)
1422159047fSniklas 	{				/* Absolute jmp/call */
1432159047fSniklas 	  insn |= (1 << 24);		/* Make it absolute */
144c074d1c9Sdrahn 	  /* FIXME: Should we change r_type to R_IABS.  */
1452159047fSniklas 	}
1462159047fSniklas       else
1472159047fSniklas 	{
1482159047fSniklas 	  /* Relative jmp/call, so subtract from the value the
149c074d1c9Sdrahn 	     address of the place we're coming from.  */
1502159047fSniklas 	  signed_value -= (reloc_entry->address
1512159047fSniklas 			   + input_section->output_section->vma
1522159047fSniklas 			   + input_section->output_offset);
1532159047fSniklas 	  if (signed_value > 0x1ffff || signed_value < -0x20000)
154c074d1c9Sdrahn 	    return bfd_reloc_overflow;
1552159047fSniklas 	}
1562159047fSniklas       signed_value >>= 2;
1572159047fSniklas       insn = INSERT_HWORD (insn, signed_value);
158c074d1c9Sdrahn       bfd_put_32 (abfd, (bfd_vma) insn ,hit_data);
1592159047fSniklas       break;
1602159047fSniklas     case R_ILOHALF:
1612159047fSniklas       insn = bfd_get_32 (abfd, hit_data);
1622159047fSniklas       unsigned_value = EXTRACT_HWORD(insn);
1632159047fSniklas       unsigned_value +=  sym_value + reloc_entry->addend;
1642159047fSniklas       insn = INSERT_HWORD(insn, unsigned_value);
165c074d1c9Sdrahn       bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
1662159047fSniklas       break;
1672159047fSniklas     case R_IHIHALF:
1682159047fSniklas       insn = bfd_get_32 (abfd, hit_data);
1692159047fSniklas       /* consth, part 1
170c074d1c9Sdrahn 	 Just get the symbol value that is referenced.  */
171c074d1c9Sdrahn       part1_consth_active = TRUE;
1722159047fSniklas       part1_consth_value = sym_value + reloc_entry->addend;
173c074d1c9Sdrahn       /* Don't modify insn until R_IHCONST.  */
1742159047fSniklas       break;
1752159047fSniklas     case R_IHCONST:
1762159047fSniklas       insn = bfd_get_32 (abfd, hit_data);
1772159047fSniklas       /* consth, part 2
178c074d1c9Sdrahn 	 Now relocate the reference.  */
179c074d1c9Sdrahn       if (! part1_consth_active)
180b55d4692Sfgsch 	{
181b305b0f1Sespie 	  *error_message = (char *) _("Missing IHIHALF");
182c074d1c9Sdrahn 	  return bfd_reloc_dangerous;
1832159047fSniklas 	}
1842159047fSniklas       /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */
1852159047fSniklas       unsigned_value = 0;		/*EXTRACT_HWORD(insn) << 16;*/
1862159047fSniklas       unsigned_value += reloc_entry->addend; /* r_symndx */
1872159047fSniklas       unsigned_value += part1_consth_value;
1882159047fSniklas       unsigned_value = unsigned_value >> 16;
1892159047fSniklas       insn = INSERT_HWORD(insn, unsigned_value);
190c074d1c9Sdrahn       part1_consth_active = FALSE;
191c074d1c9Sdrahn       bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
1922159047fSniklas       break;
1932159047fSniklas     case R_BYTE:
1942159047fSniklas       insn = bfd_get_8 (abfd, hit_data);
1952159047fSniklas       unsigned_value = insn + sym_value + reloc_entry->addend;
1962159047fSniklas       if (unsigned_value & 0xffffff00)
197c074d1c9Sdrahn 	return bfd_reloc_overflow;
1982159047fSniklas       bfd_put_8 (abfd, unsigned_value, hit_data);
1992159047fSniklas       break;
2002159047fSniklas     case R_HWORD:
2012159047fSniklas       insn = bfd_get_16 (abfd, hit_data);
2022159047fSniklas       unsigned_value = insn + sym_value + reloc_entry->addend;
2032159047fSniklas       if (unsigned_value & 0xffff0000)
204c074d1c9Sdrahn 	return bfd_reloc_overflow;
205c074d1c9Sdrahn       bfd_put_16 (abfd, (bfd_vma) insn, hit_data);
2062159047fSniklas       break;
2072159047fSniklas     case R_WORD:
2082159047fSniklas       insn = bfd_get_32 (abfd, hit_data);
2092159047fSniklas       insn += sym_value + reloc_entry->addend;
210c074d1c9Sdrahn       bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
2112159047fSniklas       break;
2122159047fSniklas     default:
213b305b0f1Sespie       *error_message = _("Unrecognized reloc");
214c074d1c9Sdrahn       return bfd_reloc_dangerous;
2152159047fSniklas     }
2162159047fSniklas 
2172159047fSniklas   return(bfd_reloc_ok);
2182159047fSniklas }
2192159047fSniklas 
220c074d1c9Sdrahn /*FIXME: I'm not real sure about this table.  */
2212159047fSniklas static reloc_howto_type howto_table[] =
2222159047fSniklas   {
223c074d1c9Sdrahn     {R_ABS,     0, 3, 32, FALSE, 0, complain_overflow_bitfield,a29k_reloc,"ABS",     TRUE, 0xffffffff,0xffffffff, FALSE},
224b305b0f1Sespie     EMPTY_HOWTO (1),
225b305b0f1Sespie     EMPTY_HOWTO (2),
226b305b0f1Sespie     EMPTY_HOWTO (3),
227b305b0f1Sespie     EMPTY_HOWTO (4),
228b305b0f1Sespie     EMPTY_HOWTO (5),
229b305b0f1Sespie     EMPTY_HOWTO (6),
230b305b0f1Sespie     EMPTY_HOWTO (7),
231b305b0f1Sespie     EMPTY_HOWTO (8),
232b305b0f1Sespie     EMPTY_HOWTO (9),
233b305b0f1Sespie     EMPTY_HOWTO (10),
234b305b0f1Sespie     EMPTY_HOWTO (11),
235b305b0f1Sespie     EMPTY_HOWTO (12),
236b305b0f1Sespie     EMPTY_HOWTO (13),
237b305b0f1Sespie     EMPTY_HOWTO (14),
238b305b0f1Sespie     EMPTY_HOWTO (15),
239b305b0f1Sespie     EMPTY_HOWTO (16),
240b305b0f1Sespie     EMPTY_HOWTO (17),
241b305b0f1Sespie     EMPTY_HOWTO (18),
242b305b0f1Sespie     EMPTY_HOWTO (19),
243b305b0f1Sespie     EMPTY_HOWTO (20),
244b305b0f1Sespie     EMPTY_HOWTO (21),
245b305b0f1Sespie     EMPTY_HOWTO (22),
246b305b0f1Sespie     EMPTY_HOWTO (23),
247c074d1c9Sdrahn     {R_IREL,    0, 3, 32, TRUE,  0, complain_overflow_signed,a29k_reloc,"IREL",    TRUE, 0xffffffff,0xffffffff, FALSE},
248c074d1c9Sdrahn     {R_IABS,    0, 3, 32, FALSE, 0, complain_overflow_bitfield, a29k_reloc,"IABS",    TRUE, 0xffffffff,0xffffffff, FALSE},
249c074d1c9Sdrahn     {R_ILOHALF, 0, 3, 16, TRUE,  0, complain_overflow_signed, a29k_reloc,"ILOHALF", TRUE, 0x0000ffff,0x0000ffff, FALSE},
250c074d1c9Sdrahn     {R_IHIHALF, 0, 3, 16, TRUE,  16, complain_overflow_signed, a29k_reloc,"IHIHALF", TRUE, 0xffff0000,0xffff0000, FALSE},
251c074d1c9Sdrahn     {R_IHCONST, 0, 3, 16, TRUE,  0, complain_overflow_signed, a29k_reloc,"IHCONST", TRUE, 0xffff0000,0xffff0000, FALSE},
252c074d1c9Sdrahn     {R_BYTE,    0, 0, 8, FALSE, 0, complain_overflow_bitfield, a29k_reloc,"BYTE",    TRUE, 0x000000ff,0x000000ff, FALSE},
253c074d1c9Sdrahn     {R_HWORD,   0, 1, 16, FALSE, 0, complain_overflow_bitfield, a29k_reloc,"HWORD",   TRUE, 0x0000ffff,0x0000ffff, FALSE},
254c074d1c9Sdrahn     {R_WORD,    0, 2, 32, FALSE, 0, complain_overflow_bitfield, a29k_reloc,"WORD",    TRUE, 0xffffffff,0xffffffff, FALSE},
2552159047fSniklas   };
2562159047fSniklas 
2572159047fSniklas #define BADMAG(x) A29KBADMAG(x)
2582159047fSniklas 
2592159047fSniklas #define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
2602159047fSniklas  reloc_processing(relent, reloc, symbols, abfd, section)
2612159047fSniklas 
2622159047fSniklas static void
reloc_processing(relent,reloc,symbols,abfd,section)2632159047fSniklas reloc_processing (relent,reloc, symbols, abfd, section)
2642159047fSniklas      arelent *relent;
2652159047fSniklas      struct internal_reloc *reloc;
2662159047fSniklas      asymbol **symbols;
2672159047fSniklas      bfd *abfd;
2682159047fSniklas      asection *section;
2692159047fSniklas {
2702159047fSniklas   static bfd_vma ihihalf_vaddr = (bfd_vma) -1;
2712159047fSniklas 
2722159047fSniklas   relent->address = reloc->r_vaddr;
2732159047fSniklas   relent->howto = howto_table + reloc->r_type;
2742159047fSniklas   if (reloc->r_type == R_IHCONST)
2752159047fSniklas     {
2762159047fSniklas       /* The address of an R_IHCONST should always be the address of
2772159047fSniklas 	 the immediately preceding R_IHIHALF.  relocs generated by gas
2782159047fSniklas 	 are correct, but relocs generated by High C are different (I
2792159047fSniklas 	 can't figure out what the address means for High C).  We can
2802159047fSniklas 	 handle both gas and High C by ignoring the address here, and
2812159047fSniklas 	 simply reusing the address saved for R_IHIHALF.  */
2822159047fSniklas       if (ihihalf_vaddr == (bfd_vma) -1)
2832159047fSniklas 	abort ();
2842159047fSniklas       relent->address = ihihalf_vaddr;
2852159047fSniklas       ihihalf_vaddr = (bfd_vma) -1;
2862159047fSniklas       relent->addend = reloc->r_symndx;
2872159047fSniklas       relent->sym_ptr_ptr= bfd_abs_section_ptr->symbol_ptr_ptr;
2882159047fSniklas     }
2892159047fSniklas   else
2902159047fSniklas     {
2912159047fSniklas       asymbol *ptr;
292c074d1c9Sdrahn 
2932159047fSniklas       relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
2942159047fSniklas 
2952159047fSniklas       ptr = *(relent->sym_ptr_ptr);
2962159047fSniklas 
2972159047fSniklas       if (ptr
2982159047fSniklas 	  && bfd_asymbol_bfd(ptr) == abfd
2992159047fSniklas 	  && ((ptr->flags & BSF_OLD_COMMON) == 0))
3002159047fSniklas 	relent->addend = 0;
3012159047fSniklas       else
3022159047fSniklas 	relent->addend = 0;
303c074d1c9Sdrahn 
3042159047fSniklas       relent->address-= section->vma;
3052159047fSniklas       if (reloc->r_type == R_IHIHALF)
3062159047fSniklas 	ihihalf_vaddr = relent->address;
3072159047fSniklas       else if (ihihalf_vaddr != (bfd_vma) -1)
3082159047fSniklas 	abort ();
3092159047fSniklas     }
3102159047fSniklas }
3112159047fSniklas 
3122159047fSniklas /* The reloc processing routine for the optimized COFF linker.  */
3132159047fSniklas 
314c074d1c9Sdrahn static bfd_boolean
coff_a29k_relocate_section(output_bfd,info,input_bfd,input_section,contents,relocs,syms,sections)3152159047fSniklas coff_a29k_relocate_section (output_bfd, info, input_bfd, input_section,
3162159047fSniklas 			    contents, relocs, syms, sections)
317b305b0f1Sespie      bfd *output_bfd ATTRIBUTE_UNUSED;
3182159047fSniklas      struct bfd_link_info *info;
3192159047fSniklas      bfd *input_bfd;
3202159047fSniklas      asection *input_section;
3212159047fSniklas      bfd_byte *contents;
3222159047fSniklas      struct internal_reloc *relocs;
3232159047fSniklas      struct internal_syment *syms;
3242159047fSniklas      asection **sections;
3252159047fSniklas {
3262159047fSniklas   struct internal_reloc *rel;
3272159047fSniklas   struct internal_reloc *relend;
328c074d1c9Sdrahn   bfd_boolean hihalf;
3292159047fSniklas   bfd_vma hihalf_val;
3302159047fSniklas 
331*007c2a45Smiod   /* If we are performing a relocatable link, we don't need to do a
3322159047fSniklas      thing.  The caller will take care of adjusting the reloc
3332159047fSniklas      addresses and symbol indices.  */
334*007c2a45Smiod   if (info->relocatable)
335c074d1c9Sdrahn     return TRUE;
3362159047fSniklas 
337c074d1c9Sdrahn   hihalf = FALSE;
3382159047fSniklas   hihalf_val = 0;
3392159047fSniklas 
3402159047fSniklas   rel = relocs;
3412159047fSniklas   relend = rel + input_section->reloc_count;
3422159047fSniklas   for (; rel < relend; rel++)
3432159047fSniklas     {
3442159047fSniklas       long symndx;
3452159047fSniklas       bfd_byte *loc;
3462159047fSniklas       struct coff_link_hash_entry *h;
3472159047fSniklas       struct internal_syment *sym;
3482159047fSniklas       asection *sec;
3492159047fSniklas       bfd_vma val;
350c074d1c9Sdrahn       bfd_boolean overflow;
3512159047fSniklas       unsigned long insn;
3522159047fSniklas       long signed_value;
3532159047fSniklas       unsigned long unsigned_value;
3542159047fSniklas       bfd_reloc_status_type rstat;
3552159047fSniklas 
3562159047fSniklas       symndx = rel->r_symndx;
3572159047fSniklas       loc = contents + rel->r_vaddr - input_section->vma;
3582159047fSniklas 
359b305b0f1Sespie       if (symndx == -1 || rel->r_type == R_IHCONST)
3602159047fSniklas 	h = NULL;
3612159047fSniklas       else
3622159047fSniklas 	h = obj_coff_sym_hashes (input_bfd)[symndx];
3632159047fSniklas 
3642159047fSniklas       sym = NULL;
3652159047fSniklas       sec = NULL;
3662159047fSniklas       val = 0;
3672159047fSniklas 
3682159047fSniklas       /* An R_IHCONST reloc does not have a symbol.  Instead, the
3692159047fSniklas          symbol index is an addend.  R_IHCONST is always used in
3702159047fSniklas          conjunction with R_IHHALF.  */
3712159047fSniklas       if (rel->r_type != R_IHCONST)
3722159047fSniklas 	{
3732159047fSniklas 	  if (h == NULL)
3742159047fSniklas 	    {
3752159047fSniklas 	      if (symndx == -1)
3762159047fSniklas 		sec = bfd_abs_section_ptr;
3772159047fSniklas 	      else
3782159047fSniklas 		{
3792159047fSniklas 		  sym = syms + symndx;
3802159047fSniklas 		  sec = sections[symndx];
3812159047fSniklas 		  val = (sec->output_section->vma
3822159047fSniklas 			 + sec->output_offset
3832159047fSniklas 			 + sym->n_value
3842159047fSniklas 			 - sec->vma);
3852159047fSniklas 		}
3862159047fSniklas 	    }
3872159047fSniklas 	  else
3882159047fSniklas 	    {
3892159047fSniklas 	      if (   h->root.type == bfd_link_hash_defined
3902159047fSniklas 		  || h->root.type == bfd_link_hash_defweak)
3912159047fSniklas 		{
3922159047fSniklas 		  sec = h->root.u.def.section;
3932159047fSniklas 		  val = (h->root.u.def.value
3942159047fSniklas 			 + sec->output_section->vma
3952159047fSniklas 			 + sec->output_offset);
3962159047fSniklas 		}
3972159047fSniklas 	      else
3982159047fSniklas 		{
3992159047fSniklas 		  if (! ((*info->callbacks->undefined_symbol)
4002159047fSniklas 			 (info, h->root.root.string, input_bfd, input_section,
401c074d1c9Sdrahn 			  rel->r_vaddr - input_section->vma, TRUE)))
402c074d1c9Sdrahn 		    return FALSE;
4032159047fSniklas 		}
4042159047fSniklas 	    }
4052159047fSniklas 
4062159047fSniklas 	  if (hihalf)
4072159047fSniklas 	    {
4082159047fSniklas 	      if (! ((*info->callbacks->reloc_dangerous)
409b305b0f1Sespie 		     (info, _("missing IHCONST reloc"), input_bfd,
4102159047fSniklas 		      input_section, rel->r_vaddr - input_section->vma)))
411c074d1c9Sdrahn 		return FALSE;
412c074d1c9Sdrahn 	      hihalf = FALSE;
4132159047fSniklas 	    }
4142159047fSniklas 	}
4152159047fSniklas 
416c074d1c9Sdrahn       overflow = FALSE;
4172159047fSniklas 
4182159047fSniklas       switch (rel->r_type)
4192159047fSniklas 	{
4202159047fSniklas 	default:
4212159047fSniklas 	  bfd_set_error (bfd_error_bad_value);
422c074d1c9Sdrahn 	  return FALSE;
4232159047fSniklas 
4242159047fSniklas 	case R_IREL:
4252159047fSniklas 	  insn = bfd_get_32 (input_bfd, loc);
4262159047fSniklas 
4272159047fSniklas 	  /* Extract the addend.  */
4282159047fSniklas 	  signed_value = EXTRACT_HWORD (insn);
4292159047fSniklas 	  signed_value = SIGN_EXTEND_HWORD (signed_value);
4302159047fSniklas 	  signed_value <<= 2;
4312159047fSniklas 
4322159047fSniklas 	  /* Unfortunately, there are two different versions of COFF
4332159047fSniklas 	     a29k.  In the original AMD version, the value stored in
4342159047fSniklas 	     the field for the R_IREL reloc is a simple addend.  In
4352159047fSniklas 	     the GNU version, the value is the negative of the address
4362159047fSniklas 	     of the reloc within section.  We try to cope here by
4372159047fSniklas 	     assuming the AMD version, unless the addend is exactly
4382159047fSniklas 	     the negative of the address; in the latter case we assume
4392159047fSniklas 	     the GNU version.  This means that something like
4402159047fSniklas 	         .text
4412159047fSniklas 		 nop
4422159047fSniklas 		 jmp i-4
4432159047fSniklas 	     will fail, because the addend of -4 will happen to equal
4442159047fSniklas 	     the negative of the address within the section.  The
4452159047fSniklas 	     compiler will never generate code like this.
4462159047fSniklas 
4472159047fSniklas 	     At some point in the future we may want to take out this
4482159047fSniklas 	     check.  */
4492159047fSniklas 
4502159047fSniklas 	  if (signed_value == - (long) (rel->r_vaddr - input_section->vma))
4512159047fSniklas 	    signed_value = 0;
4522159047fSniklas 
4532159047fSniklas 	  /* Determine the destination of the jump.  */
4542159047fSniklas 	  signed_value += val;
4552159047fSniklas 
4562159047fSniklas 	  if ((signed_value & ~0x3ffff) == 0)
4572159047fSniklas 	    {
4582159047fSniklas 	      /* We can use an absolute jump.  */
4592159047fSniklas 	      insn |= (1 << 24);
4602159047fSniklas 	    }
4612159047fSniklas 	  else
4622159047fSniklas 	    {
4632159047fSniklas 	      /* Make the destination PC relative.  */
4642159047fSniklas 	      signed_value -= (input_section->output_section->vma
4652159047fSniklas 			       + input_section->output_offset
4662159047fSniklas 			       + (rel->r_vaddr - input_section->vma));
4672159047fSniklas 	      if (signed_value > 0x1ffff || signed_value < - 0x20000)
4682159047fSniklas 		{
469c074d1c9Sdrahn 		  overflow = TRUE;
4702159047fSniklas 		  signed_value = 0;
4712159047fSniklas 		}
4722159047fSniklas 	    }
4732159047fSniklas 
4742159047fSniklas 	  /* Put the adjusted value back into the instruction.  */
4752159047fSniklas 	  signed_value >>= 2;
4762159047fSniklas 	  insn = INSERT_HWORD (insn, signed_value);
4772159047fSniklas 
4782159047fSniklas 	  bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
4792159047fSniklas 	  break;
4802159047fSniklas 
4812159047fSniklas 	case R_ILOHALF:
4822159047fSniklas 	  insn = bfd_get_32 (input_bfd, loc);
4832159047fSniklas 	  unsigned_value = EXTRACT_HWORD (insn);
4842159047fSniklas 	  unsigned_value += val;
4852159047fSniklas 	  insn = INSERT_HWORD (insn, unsigned_value);
486c074d1c9Sdrahn 	  bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
4872159047fSniklas 	  break;
4882159047fSniklas 
4892159047fSniklas 	case R_IHIHALF:
4902159047fSniklas 	  /* Save the value for the R_IHCONST reloc.  */
491c074d1c9Sdrahn 	  hihalf = TRUE;
4922159047fSniklas 	  hihalf_val = val;
4932159047fSniklas 	  break;
4942159047fSniklas 
4952159047fSniklas 	case R_IHCONST:
4962159047fSniklas 	  if (! hihalf)
4972159047fSniklas 	    {
4982159047fSniklas 	      if (! ((*info->callbacks->reloc_dangerous)
499b305b0f1Sespie 		     (info, _("missing IHIHALF reloc"), input_bfd,
5002159047fSniklas 		      input_section, rel->r_vaddr - input_section->vma)))
501c074d1c9Sdrahn 		return FALSE;
5022159047fSniklas 	      hihalf_val = 0;
5032159047fSniklas 	    }
5042159047fSniklas 
5052159047fSniklas 	  insn = bfd_get_32 (input_bfd, loc);
5062159047fSniklas 	  unsigned_value = rel->r_symndx + hihalf_val;
5072159047fSniklas 	  unsigned_value >>= 16;
5082159047fSniklas 	  insn = INSERT_HWORD (insn, unsigned_value);
5092159047fSniklas 	  bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
5102159047fSniklas 
511c074d1c9Sdrahn 	  hihalf = FALSE;
5122159047fSniklas 
5132159047fSniklas 	  break;
5142159047fSniklas 
5152159047fSniklas 	case R_BYTE:
5162159047fSniklas 	case R_HWORD:
5172159047fSniklas 	case R_WORD:
5182159047fSniklas 	  rstat = _bfd_relocate_contents (howto_table + rel->r_type,
5192159047fSniklas 					  input_bfd, val, loc);
5202159047fSniklas 	  if (rstat == bfd_reloc_overflow)
521c074d1c9Sdrahn 	    overflow = TRUE;
5222159047fSniklas 	  else if (rstat != bfd_reloc_ok)
5232159047fSniklas 	    abort ();
5242159047fSniklas 	  break;
5252159047fSniklas 	}
5262159047fSniklas 
5272159047fSniklas       if (overflow)
5282159047fSniklas 	{
5292159047fSniklas 	  const char *name;
5302159047fSniklas 	  char buf[SYMNMLEN + 1];
5312159047fSniklas 
5322159047fSniklas 	  if (symndx == -1)
5332159047fSniklas 	    name = "*ABS*";
5342159047fSniklas 	  else if (h != NULL)
5352159047fSniklas 	    name = h->root.root.string;
5362159047fSniklas 	  else if (sym == NULL)
5372159047fSniklas 	    name = "*unknown*";
5382159047fSniklas 	  else if (sym->_n._n_n._n_zeroes == 0
5392159047fSniklas 		   && sym->_n._n_n._n_offset != 0)
5402159047fSniklas 	    name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
5412159047fSniklas 	  else
5422159047fSniklas 	    {
5432159047fSniklas 	      strncpy (buf, sym->_n._n_name, SYMNMLEN);
5442159047fSniklas 	      buf[SYMNMLEN] = '\0';
5452159047fSniklas 	      name = buf;
5462159047fSniklas 	    }
5472159047fSniklas 
5482159047fSniklas 	  if (! ((*info->callbacks->reloc_overflow)
5492159047fSniklas 		 (info, name, howto_table[rel->r_type].name, (bfd_vma) 0,
5502159047fSniklas 		  input_bfd, input_section,
5512159047fSniklas 		  rel->r_vaddr - input_section->vma)))
552c074d1c9Sdrahn 	    return FALSE;
5532159047fSniklas 	}
5542159047fSniklas     }
5552159047fSniklas 
556c074d1c9Sdrahn   return TRUE;
5572159047fSniklas }
5582159047fSniklas 
5592159047fSniklas #define coff_relocate_section coff_a29k_relocate_section
5602159047fSniklas 
5612159047fSniklas /* We don't want to change the symndx of a R_IHCONST reloc, since it
5622159047fSniklas    is actually an addend, not a symbol index at all.  */
5632159047fSniklas 
564c074d1c9Sdrahn static bfd_boolean
coff_a29k_adjust_symndx(obfd,info,ibfd,sec,irel,adjustedp)5652159047fSniklas coff_a29k_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
566b305b0f1Sespie      bfd *obfd ATTRIBUTE_UNUSED;
567b305b0f1Sespie      struct bfd_link_info *info ATTRIBUTE_UNUSED;
568b305b0f1Sespie      bfd *ibfd ATTRIBUTE_UNUSED;
569b305b0f1Sespie      asection *sec ATTRIBUTE_UNUSED;
5702159047fSniklas      struct internal_reloc *irel;
571c074d1c9Sdrahn      bfd_boolean *adjustedp;
5722159047fSniklas {
5732159047fSniklas   if (irel->r_type == R_IHCONST)
574c074d1c9Sdrahn     *adjustedp = TRUE;
5752159047fSniklas   else
576c074d1c9Sdrahn     *adjustedp = FALSE;
577c074d1c9Sdrahn   return TRUE;
5782159047fSniklas }
5792159047fSniklas 
5802159047fSniklas #define coff_adjust_symndx coff_a29k_adjust_symndx
5812159047fSniklas 
5822159047fSniklas #include "coffcode.h"
5832159047fSniklas 
584*007c2a45Smiod CREATE_BIG_COFF_TARGET_VEC (a29kcoff_big_vec, "coff-a29k-big", 0, SEC_READONLY, '_', NULL, COFF_SWAP_TABLE)
585