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