xref: /openbsd/gnu/usr.bin/binutils/bfd/coff-or32.c (revision cf2f2c56)
1d2201f2fSdrahn /* BFD back-end for OpenRISC 1000 COFF binaries.
2*cf2f2c56Smiod    Copyright 2002, 2003 Free Software Foundation, Inc.
3d2201f2fSdrahn    Contributed by Ivan Guzvinec  <ivang@opencores.org>
4d2201f2fSdrahn 
5d2201f2fSdrahn    This file is part of BFD, the Binary File Descriptor library.
6d2201f2fSdrahn 
7d2201f2fSdrahn    This program is free software; you can redistribute it and/or modify
8d2201f2fSdrahn    it under the terms of the GNU General Public License as published by
9d2201f2fSdrahn    the Free Software Foundation; either version 2 of the License, or
10d2201f2fSdrahn    (at your option) any later version.
11d2201f2fSdrahn 
12d2201f2fSdrahn    This program is distributed in the hope that it will be useful,
13d2201f2fSdrahn    but WITHOUT ANY WARRANTY; without even the implied warranty of
14d2201f2fSdrahn    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15d2201f2fSdrahn    GNU General Public License for more details.
16d2201f2fSdrahn 
17d2201f2fSdrahn    You should have received a copy of the GNU General Public License
18d2201f2fSdrahn    along with this program; if not, write to the Free Software
19d2201f2fSdrahn    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20d2201f2fSdrahn 
21d2201f2fSdrahn #define OR32 1
22d2201f2fSdrahn 
23d2201f2fSdrahn #include "bfd.h"
24d2201f2fSdrahn #include "sysdep.h"
25d2201f2fSdrahn #include "libbfd.h"
26d2201f2fSdrahn #include "coff/or32.h"
27d2201f2fSdrahn #include "coff/internal.h"
28d2201f2fSdrahn #include "libcoff.h"
29d2201f2fSdrahn 
30d2201f2fSdrahn static long get_symbol_value
31d2201f2fSdrahn   PARAMS ((asymbol *));
32d2201f2fSdrahn static bfd_reloc_status_type or32_reloc
33d2201f2fSdrahn   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
34d2201f2fSdrahn static bfd_boolean coff_or32_relocate_section
35d2201f2fSdrahn   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
36d2201f2fSdrahn 	   struct internal_reloc *, struct internal_syment *, asection **));
37d2201f2fSdrahn static bfd_boolean coff_or32_adjust_symndx
38d2201f2fSdrahn   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *,
39d2201f2fSdrahn 	   struct internal_reloc *, bfd_boolean *));
40d2201f2fSdrahn static void reloc_processing
41d2201f2fSdrahn   PARAMS ((arelent *, struct internal_reloc *, asymbol **, bfd *, asection *));
42d2201f2fSdrahn 
43d2201f2fSdrahn #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
44d2201f2fSdrahn 
45d2201f2fSdrahn #define INSERT_HWORD(WORD,HWORD)              \
46d2201f2fSdrahn     (((WORD) & 0xffff0000) | ((HWORD)& 0x0000ffff))
47d2201f2fSdrahn #define EXTRACT_HWORD(WORD)                   \
48d2201f2fSdrahn     ((WORD) & 0x0000ffff)
49d2201f2fSdrahn #define SIGN_EXTEND_HWORD(HWORD)              \
50d2201f2fSdrahn     ((HWORD) & 0x8000 ? (HWORD)|(~0xffffL) : (HWORD))
51d2201f2fSdrahn 
52d2201f2fSdrahn #define INSERT_JUMPTARG(WORD,JT)              \
53d2201f2fSdrahn     (((WORD) & 0xfc000000) | ((JT)& 0x03ffffff))
54d2201f2fSdrahn #define EXTRACT_JUMPTARG(WORD)                   \
55d2201f2fSdrahn     ((WORD) & 0x03ffffff)
56d2201f2fSdrahn #define SIGN_EXTEND_JUMPTARG(JT)              \
57d2201f2fSdrahn     ((JT) & 0x04000000 ? (JT)|(~0x03ffffffL) : (JT))
58d2201f2fSdrahn 
59d2201f2fSdrahn /* Provided the symbol, returns the value reffed.  */
60d2201f2fSdrahn 
61d2201f2fSdrahn static long
get_symbol_value(symbol)62d2201f2fSdrahn get_symbol_value (symbol)
63d2201f2fSdrahn      asymbol *symbol;
64d2201f2fSdrahn {
65d2201f2fSdrahn   long relocation = 0;
66d2201f2fSdrahn 
67d2201f2fSdrahn   if (bfd_is_com_section (symbol->section))
68d2201f2fSdrahn     relocation = 0;
69d2201f2fSdrahn   else
70d2201f2fSdrahn     relocation = symbol->value +
71d2201f2fSdrahn       symbol->section->output_section->vma +
72d2201f2fSdrahn       symbol->section->output_offset;
73d2201f2fSdrahn 
74d2201f2fSdrahn   return relocation;
75d2201f2fSdrahn }
76d2201f2fSdrahn 
77d2201f2fSdrahn /* This function is in charge of performing all the or32 relocations.  */
78d2201f2fSdrahn 
79d2201f2fSdrahn static bfd_reloc_status_type
or32_reloc(abfd,reloc_entry,symbol_in,data,input_section,output_bfd,error_message)80d2201f2fSdrahn or32_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
81d2201f2fSdrahn             error_message)
82d2201f2fSdrahn      bfd *abfd;
83d2201f2fSdrahn      arelent *reloc_entry;
84d2201f2fSdrahn      asymbol *symbol_in;
85d2201f2fSdrahn      PTR data;
86d2201f2fSdrahn      asection *input_section;
87d2201f2fSdrahn      bfd *output_bfd;
88d2201f2fSdrahn      char **error_message;
89d2201f2fSdrahn {
90d2201f2fSdrahn   /* The consth relocation comes in two parts, we have to remember
91d2201f2fSdrahn      the state between calls, in these variables.  */
92d2201f2fSdrahn   static bfd_boolean part1_consth_active = FALSE;
93d2201f2fSdrahn   static unsigned long part1_consth_value;
94d2201f2fSdrahn 
95d2201f2fSdrahn   unsigned long insn;
96d2201f2fSdrahn   unsigned long sym_value;
97d2201f2fSdrahn   unsigned long unsigned_value;
98d2201f2fSdrahn   unsigned short r_type;
99d2201f2fSdrahn   long signed_value;
100d2201f2fSdrahn 
101d2201f2fSdrahn   unsigned long addr = reloc_entry->address ;   /*+ input_section->vma*/
102d2201f2fSdrahn   bfd_byte *hit_data =addr + (bfd_byte *)(data);
103d2201f2fSdrahn 
104d2201f2fSdrahn   r_type = reloc_entry->howto->type;
105d2201f2fSdrahn 
106d2201f2fSdrahn   if (output_bfd)
107d2201f2fSdrahn     {
108d2201f2fSdrahn       /* Partial linking - do nothing.  */
109d2201f2fSdrahn       reloc_entry->address += input_section->output_offset;
110d2201f2fSdrahn       return bfd_reloc_ok;
111d2201f2fSdrahn     }
112d2201f2fSdrahn 
113d2201f2fSdrahn   if (symbol_in != NULL
114d2201f2fSdrahn       && bfd_is_und_section (symbol_in->section))
115d2201f2fSdrahn     {
116d2201f2fSdrahn       /* Keep the state machine happy in case we're called again.  */
117d2201f2fSdrahn       if (r_type == R_IHIHALF)
118d2201f2fSdrahn         {
119d2201f2fSdrahn           part1_consth_active = TRUE;
120d2201f2fSdrahn           part1_consth_value  = 0;
121d2201f2fSdrahn         }
122d2201f2fSdrahn 
123d2201f2fSdrahn       return bfd_reloc_undefined;
124d2201f2fSdrahn     }
125d2201f2fSdrahn 
126d2201f2fSdrahn   if ((part1_consth_active) && (r_type != R_IHCONST))
127d2201f2fSdrahn     {
128d2201f2fSdrahn       part1_consth_active = FALSE;
129d2201f2fSdrahn       *error_message = (char *) "Missing IHCONST";
130d2201f2fSdrahn 
131d2201f2fSdrahn       return bfd_reloc_dangerous;
132d2201f2fSdrahn     }
133d2201f2fSdrahn 
134d2201f2fSdrahn   sym_value = get_symbol_value (symbol_in);
135d2201f2fSdrahn 
136d2201f2fSdrahn   switch (r_type)
137d2201f2fSdrahn     {
138d2201f2fSdrahn     case R_IREL:
139d2201f2fSdrahn       insn = bfd_get_32(abfd, hit_data);
140d2201f2fSdrahn 
141d2201f2fSdrahn       /* Take the value in the field and sign extend it.  */
142d2201f2fSdrahn       signed_value = EXTRACT_JUMPTARG (insn);
143d2201f2fSdrahn       signed_value = SIGN_EXTEND_JUMPTARG (signed_value);
144d2201f2fSdrahn       signed_value <<= 2;
145d2201f2fSdrahn 
146d2201f2fSdrahn       /* See the note on the R_IREL reloc in coff_or32_relocate_section.  */
147d2201f2fSdrahn       if (signed_value == - (long) reloc_entry->address)
148d2201f2fSdrahn         signed_value = 0;
149d2201f2fSdrahn 
150d2201f2fSdrahn       signed_value += sym_value + reloc_entry->addend;
151d2201f2fSdrahn #if 0
152d2201f2fSdrahn       if ((signed_value & ~0x3ffff) == 0)
153d2201f2fSdrahn         {                     /* Absolute jmp/call.  */
154d2201f2fSdrahn           insn |= (1<<24);    /* Make it absolute.  */
155d2201f2fSdrahn           /* FIXME: Should we change r_type to R_IABS.  */
156d2201f2fSdrahn         }
157d2201f2fSdrahn       else
158d2201f2fSdrahn #endif
159d2201f2fSdrahn         {
160d2201f2fSdrahn           /* Relative jmp/call, so subtract from the value the
161d2201f2fSdrahn              address of the place we're coming from.  */
162d2201f2fSdrahn           signed_value -= (reloc_entry->address
163d2201f2fSdrahn                            + input_section->output_section->vma
164d2201f2fSdrahn                            + input_section->output_offset);
165d2201f2fSdrahn           if (signed_value > 0x7ffffff || signed_value < -0x8000000)
166d2201f2fSdrahn             return bfd_reloc_overflow;
167d2201f2fSdrahn         }
168d2201f2fSdrahn       signed_value >>= 2;
169d2201f2fSdrahn       insn = INSERT_JUMPTARG (insn, signed_value);
170d2201f2fSdrahn       bfd_put_32 (abfd, insn, hit_data);
171d2201f2fSdrahn       break;
172d2201f2fSdrahn 
173d2201f2fSdrahn     case R_ILOHALF:
174d2201f2fSdrahn       insn = bfd_get_32 (abfd, hit_data);
175d2201f2fSdrahn       unsigned_value = EXTRACT_HWORD (insn);
176d2201f2fSdrahn       unsigned_value +=  sym_value + reloc_entry->addend;
177d2201f2fSdrahn       insn = INSERT_HWORD (insn, unsigned_value);
178d2201f2fSdrahn       bfd_put_32 (abfd, insn, hit_data);
179d2201f2fSdrahn       break;
180d2201f2fSdrahn 
181d2201f2fSdrahn     case R_IHIHALF:
182d2201f2fSdrahn       insn = bfd_get_32 (abfd, hit_data);
183d2201f2fSdrahn 
184d2201f2fSdrahn       /* consth, part 1
185d2201f2fSdrahn          Just get the symbol value that is referenced.  */
186d2201f2fSdrahn       part1_consth_active = TRUE;
187d2201f2fSdrahn       part1_consth_value = sym_value + reloc_entry->addend;
188d2201f2fSdrahn 
189d2201f2fSdrahn       /* Don't modify insn until R_IHCONST.  */
190d2201f2fSdrahn       break;
191d2201f2fSdrahn 
192d2201f2fSdrahn     case R_IHCONST:
193d2201f2fSdrahn       insn = bfd_get_32 (abfd, hit_data);
194d2201f2fSdrahn 
195d2201f2fSdrahn       /* consth, part 2
196d2201f2fSdrahn          Now relocate the reference.  */
197d2201f2fSdrahn       if (! part1_consth_active)
198d2201f2fSdrahn         {
199d2201f2fSdrahn           *error_message = (char *) "Missing IHIHALF";
200d2201f2fSdrahn           return bfd_reloc_dangerous;
201d2201f2fSdrahn         }
202d2201f2fSdrahn 
203d2201f2fSdrahn       /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */
204d2201f2fSdrahn       unsigned_value = 0;   /*EXTRACT_HWORD(insn) << 16;*/
205d2201f2fSdrahn       unsigned_value += reloc_entry->addend; /* r_symndx */
206d2201f2fSdrahn       unsigned_value += part1_consth_value;
207d2201f2fSdrahn       unsigned_value = unsigned_value >> 16;
208d2201f2fSdrahn       insn = INSERT_HWORD (insn, unsigned_value);
209d2201f2fSdrahn       part1_consth_active = FALSE;
210d2201f2fSdrahn       bfd_put_32 (abfd, insn, hit_data);
211d2201f2fSdrahn       break;
212d2201f2fSdrahn 
213d2201f2fSdrahn     case R_BYTE:
214d2201f2fSdrahn       insn = bfd_get_8 (abfd, hit_data);
215d2201f2fSdrahn       unsigned_value = insn + sym_value + reloc_entry->addend;
216d2201f2fSdrahn       if (unsigned_value & 0xffffff00)
217d2201f2fSdrahn         return bfd_reloc_overflow;
218d2201f2fSdrahn       bfd_put_8 (abfd, unsigned_value, hit_data);
219d2201f2fSdrahn       break;
220d2201f2fSdrahn 
221d2201f2fSdrahn     case R_HWORD:
222d2201f2fSdrahn       insn = bfd_get_16 (abfd, hit_data);
223d2201f2fSdrahn       unsigned_value = insn + sym_value + reloc_entry->addend;
224d2201f2fSdrahn       if (unsigned_value & 0xffff0000)
225d2201f2fSdrahn         return bfd_reloc_overflow;
226d2201f2fSdrahn       bfd_put_16 (abfd, insn, hit_data);
227d2201f2fSdrahn       break;
228d2201f2fSdrahn 
229d2201f2fSdrahn     case R_WORD:
230d2201f2fSdrahn       insn = bfd_get_32 (abfd, hit_data);
231d2201f2fSdrahn       insn += sym_value + reloc_entry->addend;
232d2201f2fSdrahn       bfd_put_32 (abfd, insn, hit_data);
233d2201f2fSdrahn       break;
234d2201f2fSdrahn 
235d2201f2fSdrahn     default:
236d2201f2fSdrahn       *error_message = _("Unrecognized reloc");
237d2201f2fSdrahn       return bfd_reloc_dangerous;
238d2201f2fSdrahn     }
239d2201f2fSdrahn 
240d2201f2fSdrahn   return bfd_reloc_ok;
241d2201f2fSdrahn }
242d2201f2fSdrahn 
243d2201f2fSdrahn /*      type     rightshift
244d2201f2fSdrahn            size
245d2201f2fSdrahn         bitsize
246d2201f2fSdrahn              pc-relative
247d2201f2fSdrahn              bitpos
248d2201f2fSdrahn            absolute
249d2201f2fSdrahn                complain_on_overflow
250d2201f2fSdrahn               special_function
251d2201f2fSdrahn                 relocation name
252d2201f2fSdrahn                      partial_inplace
253d2201f2fSdrahn                       src_mask
254d2201f2fSdrahn */
255d2201f2fSdrahn 
256d2201f2fSdrahn /* FIXME: I'm not real sure about this table.  */
257d2201f2fSdrahn static reloc_howto_type howto_table[] =
258d2201f2fSdrahn {
259d2201f2fSdrahn   { R_ABS,      0, 3, 32, FALSE,  0, complain_overflow_bitfield,  or32_reloc, "ABS",     TRUE, 0xffffffff,0xffffffff, FALSE },
260d2201f2fSdrahn     EMPTY_HOWTO (1),
261d2201f2fSdrahn     EMPTY_HOWTO (2),
262d2201f2fSdrahn     EMPTY_HOWTO (3),
263d2201f2fSdrahn     EMPTY_HOWTO (4),
264d2201f2fSdrahn     EMPTY_HOWTO (5),
265d2201f2fSdrahn     EMPTY_HOWTO (6),
266d2201f2fSdrahn     EMPTY_HOWTO (7),
267d2201f2fSdrahn     EMPTY_HOWTO (8),
268d2201f2fSdrahn     EMPTY_HOWTO (9),
269d2201f2fSdrahn     EMPTY_HOWTO (10),
270d2201f2fSdrahn     EMPTY_HOWTO (11),
271d2201f2fSdrahn     EMPTY_HOWTO (12),
272d2201f2fSdrahn     EMPTY_HOWTO (13),
273d2201f2fSdrahn     EMPTY_HOWTO (14),
274d2201f2fSdrahn     EMPTY_HOWTO (15),
275d2201f2fSdrahn     EMPTY_HOWTO (16),
276d2201f2fSdrahn     EMPTY_HOWTO (17),
277d2201f2fSdrahn     EMPTY_HOWTO (18),
278d2201f2fSdrahn     EMPTY_HOWTO (19),
279d2201f2fSdrahn     EMPTY_HOWTO (20),
280d2201f2fSdrahn     EMPTY_HOWTO (21),
281d2201f2fSdrahn     EMPTY_HOWTO (22),
282d2201f2fSdrahn     EMPTY_HOWTO (23),
283d2201f2fSdrahn   { R_IREL,     0, 3, 32, TRUE,   0, complain_overflow_signed,    or32_reloc, "IREL",    TRUE, 0xffffffff,0xffffffff, FALSE },
284d2201f2fSdrahn   { R_IABS,     0, 3, 32, FALSE,  0, complain_overflow_bitfield,  or32_reloc, "IABS",    TRUE, 0xffffffff,0xffffffff, FALSE },
285d2201f2fSdrahn   { R_ILOHALF,  0, 3, 16, TRUE,   0, complain_overflow_signed,    or32_reloc, "ILOHALF", TRUE, 0x0000ffff,0x0000ffff, FALSE },
286d2201f2fSdrahn   { R_IHIHALF,  0, 3, 16, TRUE,   16,complain_overflow_signed,    or32_reloc, "IHIHALF", TRUE, 0xffff0000,0xffff0000, FALSE },
287d2201f2fSdrahn   { R_IHCONST,  0, 3, 16, TRUE,   0, complain_overflow_signed,    or32_reloc, "IHCONST", TRUE, 0xffff0000,0xffff0000, FALSE },
288d2201f2fSdrahn   { R_BYTE,     0, 0, 8,  FALSE,  0, complain_overflow_bitfield,  or32_reloc, "BYTE",    TRUE, 0x000000ff,0x000000ff, FALSE },
289d2201f2fSdrahn   { R_HWORD,    0, 1, 16, FALSE,  0, complain_overflow_bitfield,  or32_reloc, "HWORD",   TRUE, 0x0000ffff,0x0000ffff, FALSE },
290d2201f2fSdrahn   { R_WORD,     0, 2, 32, FALSE,  0, complain_overflow_bitfield,  or32_reloc, "WORD",    TRUE, 0xffffffff,0xffffffff, FALSE },
291d2201f2fSdrahn };
292d2201f2fSdrahn 
293d2201f2fSdrahn #define BADMAG(x) OR32BADMAG (x)
294d2201f2fSdrahn 
295d2201f2fSdrahn #define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
296d2201f2fSdrahn   reloc_processing (relent, reloc, symbols, abfd, section)
297d2201f2fSdrahn 
298d2201f2fSdrahn static void
reloc_processing(relent,reloc,symbols,abfd,section)299d2201f2fSdrahn reloc_processing (relent,reloc, symbols, abfd, section)
300d2201f2fSdrahn      arelent *relent;
301d2201f2fSdrahn      struct internal_reloc *reloc;
302d2201f2fSdrahn      asymbol **symbols;
303d2201f2fSdrahn      bfd *abfd;
304d2201f2fSdrahn      asection *section;
305d2201f2fSdrahn {
306d2201f2fSdrahn   static bfd_vma ihihalf_vaddr = (bfd_vma) -1;
307d2201f2fSdrahn 
308d2201f2fSdrahn   relent->address = reloc->r_vaddr;
309d2201f2fSdrahn   relent->howto = howto_table + reloc->r_type;
310d2201f2fSdrahn 
311d2201f2fSdrahn   if (reloc->r_type == R_IHCONST)
312d2201f2fSdrahn     {
313d2201f2fSdrahn       /* The address of an R_IHCONST should always be the address of
314d2201f2fSdrahn 	 the immediately preceding R_IHIHALF.  relocs generated by gas
315d2201f2fSdrahn 	 are correct, but relocs generated by High C are different (I
316d2201f2fSdrahn 	 can't figure out what the address means for High C).  We can
317d2201f2fSdrahn 	 handle both gas and High C by ignoring the address here, and
318d2201f2fSdrahn 	 simply reusing the address saved for R_IHIHALF.  */
319d2201f2fSdrahn       if (ihihalf_vaddr == (bfd_vma) -1)
320d2201f2fSdrahn 	abort ();
321d2201f2fSdrahn 
322d2201f2fSdrahn       relent->address = ihihalf_vaddr;
323d2201f2fSdrahn       ihihalf_vaddr = (bfd_vma) -1;
324d2201f2fSdrahn       relent->addend = reloc->r_symndx;
325d2201f2fSdrahn       relent->sym_ptr_ptr= bfd_abs_section_ptr->symbol_ptr_ptr;
326d2201f2fSdrahn     }
327d2201f2fSdrahn   else
328d2201f2fSdrahn     {
329d2201f2fSdrahn       asymbol *ptr;
330d2201f2fSdrahn       relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
331d2201f2fSdrahn 
332d2201f2fSdrahn       ptr = *(relent->sym_ptr_ptr);
333d2201f2fSdrahn 
334d2201f2fSdrahn       relent->addend = 0;
335d2201f2fSdrahn       relent->address-= section->vma;
336d2201f2fSdrahn 
337d2201f2fSdrahn       if (reloc->r_type == R_IHIHALF)
338d2201f2fSdrahn 	ihihalf_vaddr = relent->address;
339d2201f2fSdrahn       else if (ihihalf_vaddr != (bfd_vma) -1)
340d2201f2fSdrahn 	abort ();
341d2201f2fSdrahn     }
342d2201f2fSdrahn }
343d2201f2fSdrahn 
344d2201f2fSdrahn /* The reloc processing routine for the optimized COFF linker.  */
345d2201f2fSdrahn 
346d2201f2fSdrahn static bfd_boolean
coff_or32_relocate_section(output_bfd,info,input_bfd,input_section,contents,relocs,syms,sections)347d2201f2fSdrahn coff_or32_relocate_section (output_bfd, info, input_bfd, input_section,
348d2201f2fSdrahn                             contents, relocs, syms, sections)
349d2201f2fSdrahn      bfd *output_bfd ATTRIBUTE_UNUSED;
350d2201f2fSdrahn      struct bfd_link_info *info;
351d2201f2fSdrahn      bfd *input_bfd;
352d2201f2fSdrahn      asection *input_section;
353d2201f2fSdrahn      bfd_byte *contents;
354d2201f2fSdrahn      struct internal_reloc *relocs;
355d2201f2fSdrahn      struct internal_syment *syms;
356d2201f2fSdrahn      asection **sections;
357d2201f2fSdrahn {
358d2201f2fSdrahn   struct internal_reloc *rel;
359d2201f2fSdrahn   struct internal_reloc *relend;
360d2201f2fSdrahn   bfd_boolean hihalf;
361d2201f2fSdrahn   bfd_vma hihalf_val;
362d2201f2fSdrahn 
363*cf2f2c56Smiod   /* If we are performing a relocatable link, we don't need to do a
364d2201f2fSdrahn      thing.  The caller will take care of adjusting the reloc
365d2201f2fSdrahn      addresses and symbol indices.  */
366*cf2f2c56Smiod   if (info->relocatable)
367d2201f2fSdrahn     return TRUE;
368d2201f2fSdrahn 
369d2201f2fSdrahn   hihalf = FALSE;
370d2201f2fSdrahn   hihalf_val = 0;
371d2201f2fSdrahn 
372d2201f2fSdrahn   rel = relocs;
373d2201f2fSdrahn   relend = rel + input_section->reloc_count;
374d2201f2fSdrahn 
375d2201f2fSdrahn   for (; rel < relend; rel++)
376d2201f2fSdrahn     {
377d2201f2fSdrahn       long symndx;
378d2201f2fSdrahn       bfd_byte *loc;
379d2201f2fSdrahn       struct coff_link_hash_entry *h;
380d2201f2fSdrahn       struct internal_syment *sym;
381d2201f2fSdrahn       asection *sec;
382d2201f2fSdrahn       bfd_vma val;
383d2201f2fSdrahn       bfd_boolean overflow;
384d2201f2fSdrahn       unsigned long insn;
385d2201f2fSdrahn       long signed_value;
386d2201f2fSdrahn       unsigned long unsigned_value;
387d2201f2fSdrahn       bfd_reloc_status_type rstat;
388d2201f2fSdrahn 
389d2201f2fSdrahn       symndx = rel->r_symndx;
390d2201f2fSdrahn       loc = contents + rel->r_vaddr - input_section->vma;
391d2201f2fSdrahn 
392d2201f2fSdrahn       if (symndx == -1 || rel->r_type == R_IHCONST)
393d2201f2fSdrahn         h = NULL;
394d2201f2fSdrahn       else
395d2201f2fSdrahn         h = obj_coff_sym_hashes (input_bfd)[symndx];
396d2201f2fSdrahn 
397d2201f2fSdrahn       sym = NULL;
398d2201f2fSdrahn       sec = NULL;
399d2201f2fSdrahn       val = 0;
400d2201f2fSdrahn 
401d2201f2fSdrahn       /* An R_IHCONST reloc does not have a symbol.  Instead, the
402d2201f2fSdrahn          symbol index is an addend.  R_IHCONST is always used in
403d2201f2fSdrahn          conjunction with R_IHHALF.  */
404d2201f2fSdrahn       if (rel->r_type != R_IHCONST)
405d2201f2fSdrahn         {
406d2201f2fSdrahn           if (h == NULL)
407d2201f2fSdrahn             {
408d2201f2fSdrahn               if (symndx == -1)
409d2201f2fSdrahn                 sec = bfd_abs_section_ptr;
410d2201f2fSdrahn               else
411d2201f2fSdrahn                 {
412d2201f2fSdrahn                   sym = syms + symndx;
413d2201f2fSdrahn                   sec = sections[symndx];
414d2201f2fSdrahn                   val = (sec->output_section->vma
415d2201f2fSdrahn                          + sec->output_offset
416d2201f2fSdrahn                          + sym->n_value
417d2201f2fSdrahn                          - sec->vma);
418d2201f2fSdrahn                 }
419d2201f2fSdrahn             }
420d2201f2fSdrahn           else
421d2201f2fSdrahn             {
422d2201f2fSdrahn               if (h->root.type == bfd_link_hash_defined
423d2201f2fSdrahn                   || h->root.type == bfd_link_hash_defweak)
424d2201f2fSdrahn                 {
425d2201f2fSdrahn                   sec = h->root.u.def.section;
426d2201f2fSdrahn                   val = (h->root.u.def.value
427d2201f2fSdrahn                          + sec->output_section->vma
428d2201f2fSdrahn                          + sec->output_offset);
429d2201f2fSdrahn                 }
430d2201f2fSdrahn               else
431d2201f2fSdrahn                 {
432d2201f2fSdrahn                   if (! ((*info->callbacks->undefined_symbol)
433d2201f2fSdrahn                          (info, h->root.root.string, input_bfd, input_section,
434d2201f2fSdrahn                           rel->r_vaddr - input_section->vma, TRUE)))
435d2201f2fSdrahn                     return FALSE;
436d2201f2fSdrahn                 }
437d2201f2fSdrahn             }
438d2201f2fSdrahn 
439d2201f2fSdrahn           if (hihalf)
440d2201f2fSdrahn             {
441d2201f2fSdrahn               if (! ((*info->callbacks->reloc_dangerous)
442d2201f2fSdrahn                      (info, "missing IHCONST reloc", input_bfd,
443d2201f2fSdrahn                       input_section, rel->r_vaddr - input_section->vma)))
444d2201f2fSdrahn                 return FALSE;
445d2201f2fSdrahn               hihalf = FALSE;
446d2201f2fSdrahn             }
447d2201f2fSdrahn         }
448d2201f2fSdrahn 
449d2201f2fSdrahn       overflow = FALSE;
450d2201f2fSdrahn 
451d2201f2fSdrahn       switch (rel->r_type)
452d2201f2fSdrahn         {
453d2201f2fSdrahn         default:
454d2201f2fSdrahn           bfd_set_error (bfd_error_bad_value);
455d2201f2fSdrahn           return FALSE;
456d2201f2fSdrahn 
457d2201f2fSdrahn         case R_IREL:
458d2201f2fSdrahn           insn = bfd_get_32 (input_bfd, loc);
459d2201f2fSdrahn 
460d2201f2fSdrahn           /* Extract the addend.  */
461d2201f2fSdrahn           signed_value = EXTRACT_JUMPTARG (insn);
462d2201f2fSdrahn           signed_value = SIGN_EXTEND_JUMPTARG (signed_value);
463d2201f2fSdrahn           signed_value <<= 2;
464d2201f2fSdrahn 
465d2201f2fSdrahn           /* Determine the destination of the jump.  */
466d2201f2fSdrahn           signed_value += val;
467d2201f2fSdrahn 
468d2201f2fSdrahn #if 0
469d2201f2fSdrahn           if ((signed_value & ~0x3ffff) == 0)
470d2201f2fSdrahn             {
471d2201f2fSdrahn               /* We can use an absolute jump.  */
472d2201f2fSdrahn               insn |= (1 << 24);
473d2201f2fSdrahn             }
474d2201f2fSdrahn           else
475d2201f2fSdrahn #endif
476d2201f2fSdrahn             {
477d2201f2fSdrahn               /* Make the destination PC relative.  */
478d2201f2fSdrahn               signed_value -= (input_section->output_section->vma
479d2201f2fSdrahn                                + input_section->output_offset
480d2201f2fSdrahn                                + (rel->r_vaddr - input_section->vma));
481d2201f2fSdrahn               if (signed_value > 0x7ffffff || signed_value < - 0x8000000)
482d2201f2fSdrahn                 {
483d2201f2fSdrahn                   overflow = TRUE;
484d2201f2fSdrahn                   signed_value = 0;
485d2201f2fSdrahn                 }
486d2201f2fSdrahn             }
487d2201f2fSdrahn 
488d2201f2fSdrahn           /* Put the adjusted value back into the instruction.  */
489d2201f2fSdrahn           signed_value >>= 2;
490d2201f2fSdrahn           insn = INSERT_JUMPTARG(insn, signed_value);
491d2201f2fSdrahn 
492d2201f2fSdrahn           bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
493d2201f2fSdrahn           break;
494d2201f2fSdrahn 
495d2201f2fSdrahn         case R_ILOHALF:
496d2201f2fSdrahn           insn = bfd_get_32 (input_bfd, loc);
497d2201f2fSdrahn           unsigned_value = EXTRACT_HWORD (insn);
498d2201f2fSdrahn           unsigned_value += val;
499d2201f2fSdrahn           insn = INSERT_HWORD (insn, unsigned_value);
500d2201f2fSdrahn           bfd_put_32 (input_bfd, insn, loc);
501d2201f2fSdrahn           break;
502d2201f2fSdrahn 
503d2201f2fSdrahn         case R_IHIHALF:
504d2201f2fSdrahn           /* Save the value for the R_IHCONST reloc.  */
505d2201f2fSdrahn           hihalf = TRUE;
506d2201f2fSdrahn           hihalf_val = val;
507d2201f2fSdrahn           break;
508d2201f2fSdrahn 
509d2201f2fSdrahn         case R_IHCONST:
510d2201f2fSdrahn           if (! hihalf)
511d2201f2fSdrahn             {
512d2201f2fSdrahn               if (! ((*info->callbacks->reloc_dangerous)
513d2201f2fSdrahn                      (info, "missing IHIHALF reloc", input_bfd,
514d2201f2fSdrahn                       input_section, rel->r_vaddr - input_section->vma)))
515d2201f2fSdrahn                 return FALSE;
516d2201f2fSdrahn               hihalf_val = 0;
517d2201f2fSdrahn             }
518d2201f2fSdrahn 
519d2201f2fSdrahn           insn = bfd_get_32 (input_bfd, loc);
520d2201f2fSdrahn           unsigned_value = rel->r_symndx + hihalf_val;
521d2201f2fSdrahn           unsigned_value >>= 16;
522d2201f2fSdrahn           insn = INSERT_HWORD (insn, unsigned_value);
523d2201f2fSdrahn           bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
524d2201f2fSdrahn 
525d2201f2fSdrahn           hihalf = FALSE;
526d2201f2fSdrahn           break;
527d2201f2fSdrahn 
528d2201f2fSdrahn         case R_BYTE:
529d2201f2fSdrahn         case R_HWORD:
530d2201f2fSdrahn         case R_WORD:
531d2201f2fSdrahn           rstat = _bfd_relocate_contents (howto_table + rel->r_type,
532d2201f2fSdrahn                                           input_bfd, val, loc);
533d2201f2fSdrahn           if (rstat == bfd_reloc_overflow)
534d2201f2fSdrahn             overflow = TRUE;
535d2201f2fSdrahn           else if (rstat != bfd_reloc_ok)
536d2201f2fSdrahn             abort ();
537d2201f2fSdrahn           break;
538d2201f2fSdrahn         }
539d2201f2fSdrahn 
540d2201f2fSdrahn       if (overflow)
541d2201f2fSdrahn         {
542d2201f2fSdrahn           const char *name;
543d2201f2fSdrahn           char buf[SYMNMLEN + 1];
544d2201f2fSdrahn 
545d2201f2fSdrahn           if (symndx == -1)
546d2201f2fSdrahn             name = "*ABS*";
547d2201f2fSdrahn           else if (h != NULL)
548d2201f2fSdrahn             name = h->root.root.string;
549d2201f2fSdrahn           else if (sym == NULL)
550d2201f2fSdrahn             name = "*unknown*";
551d2201f2fSdrahn           else if (sym->_n._n_n._n_zeroes == 0
552d2201f2fSdrahn                    && sym->_n._n_n._n_offset != 0)
553d2201f2fSdrahn             name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
554d2201f2fSdrahn           else
555d2201f2fSdrahn             {
556d2201f2fSdrahn               strncpy (buf, sym->_n._n_name, SYMNMLEN);
557d2201f2fSdrahn               buf[SYMNMLEN] = '\0';
558d2201f2fSdrahn               name = buf;
559d2201f2fSdrahn             }
560d2201f2fSdrahn 
561d2201f2fSdrahn           if (! ((*info->callbacks->reloc_overflow)
562d2201f2fSdrahn                  (info, name, howto_table[rel->r_type].name, (bfd_vma) 0,
563d2201f2fSdrahn                   input_bfd, input_section,
564d2201f2fSdrahn                   rel->r_vaddr - input_section->vma)))
565d2201f2fSdrahn             return FALSE;
566d2201f2fSdrahn         }
567d2201f2fSdrahn     }
568d2201f2fSdrahn 
569d2201f2fSdrahn   return TRUE;
570d2201f2fSdrahn }
571d2201f2fSdrahn 
572d2201f2fSdrahn #define coff_relocate_section coff_or32_relocate_section
573d2201f2fSdrahn 
574d2201f2fSdrahn /* We don't want to change the symndx of a R_IHCONST reloc, since it
575d2201f2fSdrahn    is actually an addend, not a symbol index at all.  */
576d2201f2fSdrahn 
577d2201f2fSdrahn static bfd_boolean
coff_or32_adjust_symndx(obfd,info,ibfd,sec,irel,adjustedp)578d2201f2fSdrahn coff_or32_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
579d2201f2fSdrahn      bfd *obfd ATTRIBUTE_UNUSED;
580d2201f2fSdrahn      struct bfd_link_info *info ATTRIBUTE_UNUSED;
581d2201f2fSdrahn      bfd *ibfd ATTRIBUTE_UNUSED;
582d2201f2fSdrahn      asection *sec ATTRIBUTE_UNUSED;
583d2201f2fSdrahn      struct internal_reloc *irel;
584d2201f2fSdrahn      bfd_boolean *adjustedp;
585d2201f2fSdrahn {
586d2201f2fSdrahn   if (irel->r_type == R_IHCONST)
587d2201f2fSdrahn     *adjustedp = TRUE;
588d2201f2fSdrahn   else
589d2201f2fSdrahn     *adjustedp = FALSE;
590d2201f2fSdrahn   return TRUE;
591d2201f2fSdrahn }
592d2201f2fSdrahn 
593d2201f2fSdrahn #define coff_adjust_symndx coff_or32_adjust_symndx
594d2201f2fSdrahn 
595d2201f2fSdrahn #include "coffcode.h"
596d2201f2fSdrahn 
597d2201f2fSdrahn const bfd_target or32coff_big_vec =
598d2201f2fSdrahn {
599d2201f2fSdrahn   "coff-or32-big",  /* Name.  */
600d2201f2fSdrahn   bfd_target_coff_flavour,
601d2201f2fSdrahn   BFD_ENDIAN_BIG,   /* Data byte order is big.  */
602d2201f2fSdrahn   BFD_ENDIAN_BIG,   /* Header byte order is big.  */
603d2201f2fSdrahn 
604d2201f2fSdrahn   (HAS_RELOC  | EXEC_P |    /* Object flags.  */
605d2201f2fSdrahn    HAS_LINENO | HAS_DEBUG |
606d2201f2fSdrahn    HAS_SYMS   | HAS_LOCALS | WP_TEXT),
607d2201f2fSdrahn 
608d2201f2fSdrahn   (SEC_HAS_CONTENTS | SEC_ALLOC | /* Section flags.  */
609d2201f2fSdrahn    SEC_LOAD | SEC_RELOC |
610d2201f2fSdrahn    SEC_READONLY ),
611d2201f2fSdrahn   '_',        /* Leading underscore.  */
612d2201f2fSdrahn   '/',        /* ar_pad_char.  */
613d2201f2fSdrahn   15,         /* ar_max_namelen.  */
614d2201f2fSdrahn 
615d2201f2fSdrahn   /* Data.  */
616d2201f2fSdrahn   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
617d2201f2fSdrahn   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
618d2201f2fSdrahn   bfd_getb16, bfd_getb_signed_16, bfd_putb16,
619d2201f2fSdrahn 
620d2201f2fSdrahn   /* Headers.  */
621d2201f2fSdrahn   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
622d2201f2fSdrahn   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
623d2201f2fSdrahn   bfd_getb16, bfd_getb_signed_16, bfd_putb16,
624d2201f2fSdrahn 
625d2201f2fSdrahn   {
626d2201f2fSdrahn     _bfd_dummy_target,
627d2201f2fSdrahn     coff_object_p,
628d2201f2fSdrahn     bfd_generic_archive_p,
629d2201f2fSdrahn     _bfd_dummy_target
630d2201f2fSdrahn   },
631d2201f2fSdrahn   {
632d2201f2fSdrahn     bfd_false,
633d2201f2fSdrahn     coff_mkobject,
634d2201f2fSdrahn     _bfd_generic_mkarchive,
635d2201f2fSdrahn     bfd_false
636d2201f2fSdrahn   },
637d2201f2fSdrahn   {
638d2201f2fSdrahn     bfd_false,
639d2201f2fSdrahn     coff_write_object_contents,
640d2201f2fSdrahn     _bfd_write_archive_contents,
641d2201f2fSdrahn     bfd_false
642d2201f2fSdrahn   },
643d2201f2fSdrahn 
644d2201f2fSdrahn   BFD_JUMP_TABLE_GENERIC (coff),
645d2201f2fSdrahn   BFD_JUMP_TABLE_COPY (coff),
646d2201f2fSdrahn   BFD_JUMP_TABLE_CORE (_bfd_nocore),
647d2201f2fSdrahn   BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
648d2201f2fSdrahn   BFD_JUMP_TABLE_SYMBOLS (coff),
649d2201f2fSdrahn   BFD_JUMP_TABLE_RELOCS (coff),
650d2201f2fSdrahn   BFD_JUMP_TABLE_WRITE (coff),
651d2201f2fSdrahn   BFD_JUMP_TABLE_LINK (coff),
652d2201f2fSdrahn   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
653d2201f2fSdrahn 
654d2201f2fSdrahn  /* Alternative_target.  */
655d2201f2fSdrahn #ifdef TARGET_LITTLE_SYM
656d2201f2fSdrahn   & TARGET_LITTLE_SYM,
657d2201f2fSdrahn #else
658d2201f2fSdrahn   NULL,
659d2201f2fSdrahn #endif
660d2201f2fSdrahn 
661d2201f2fSdrahn   COFF_SWAP_TABLE
662d2201f2fSdrahn };
663