xref: /openbsd-src/gnu/usr.bin/binutils/bfd/pe-mips.c (revision cf2f2c5620d6d9a4fd01930983c4b9a1f76d7aa3)
1f7cc78ecSespie /* BFD back-end for MIPS PE COFF files.
25f210c2aSfgsch    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3*cf2f2c56Smiod    2000, 2001, 2002, 2003 Free Software Foundation, Inc.
4f7cc78ecSespie    Modified from coff-i386.c by DJ Delorie, dj@cygnus.com
5f7cc78ecSespie 
6f7cc78ecSespie This file is part of BFD, the Binary File Descriptor library.
7f7cc78ecSespie 
8f7cc78ecSespie This program is free software; you can redistribute it and/or modify
9f7cc78ecSespie it under the terms of the GNU General Public License as published by
10f7cc78ecSespie the Free Software Foundation; either version 2 of the License, or
11f7cc78ecSespie (at your option) any later version.
12f7cc78ecSespie 
13f7cc78ecSespie This program is distributed in the hope that it will be useful,
14f7cc78ecSespie but WITHOUT ANY WARRANTY; without even the implied warranty of
15f7cc78ecSespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16f7cc78ecSespie GNU General Public License for more details.
17f7cc78ecSespie 
18f7cc78ecSespie You should have received a copy of the GNU General Public License
19f7cc78ecSespie along with this program; if not, write to the Free Software
20f7cc78ecSespie Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21f7cc78ecSespie 
22f7cc78ecSespie #define COFF_WITH_PE
23f7cc78ecSespie #define COFF_LONG_SECTION_NAMES
24d2201f2fSdrahn #define PCRELOFFSET TRUE
25f7cc78ecSespie 
26f7cc78ecSespie #include "bfd.h"
27f7cc78ecSespie #include "sysdep.h"
28f7cc78ecSespie #include "libbfd.h"
29f7cc78ecSespie 
30f7cc78ecSespie #include "coff/mipspe.h"
31f7cc78ecSespie 
32f7cc78ecSespie #include "coff/internal.h"
33f7cc78ecSespie 
34f7cc78ecSespie #include "coff/pe.h"
35f7cc78ecSespie 
36f7cc78ecSespie #include "libcoff.h"
37f7cc78ecSespie 
38f7cc78ecSespie static bfd_reloc_status_type coff_mips_reloc
39f7cc78ecSespie   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
40f7cc78ecSespie static reloc_howto_type *coff_mips_rtype_to_howto
41f7cc78ecSespie   PARAMS ((bfd *, asection *, struct internal_reloc *,
42f7cc78ecSespie 	   struct coff_link_hash_entry *, struct internal_syment *,
43f7cc78ecSespie 	   bfd_vma *));
44f7cc78ecSespie #if 0
45d2201f2fSdrahn static void mips_ecoff_swap_reloc_in
46d2201f2fSdrahn   PARAMS ((bfd *, PTR, struct internal_reloc *));
47d2201f2fSdrahn static void mips_ecoff_swap_reloc_out
48d2201f2fSdrahn   PARAMS ((bfd *, const struct internal_reloc *, PTR));
49d2201f2fSdrahn static void mips_adjust_reloc_in
50d2201f2fSdrahn   PARAMS ((bfd *, const struct internal_reloc *, arelent *));
51d2201f2fSdrahn static void mips_adjust_reloc_out
52d2201f2fSdrahn   PARAMS ((bfd *, const arelent *, struct internal_reloc *));
53f7cc78ecSespie #endif
54d2201f2fSdrahn 
55d2201f2fSdrahn static bfd_boolean in_reloc_p
56d2201f2fSdrahn   PARAMS ((bfd *, reloc_howto_type *));
57d2201f2fSdrahn static reloc_howto_type * coff_mips_reloc_type_lookup
58d2201f2fSdrahn   PARAMS ((bfd *, bfd_reloc_code_real_type));
59d2201f2fSdrahn static void mips_swap_reloc_in
60d2201f2fSdrahn   PARAMS ((bfd *, PTR, PTR));
61d2201f2fSdrahn static unsigned int mips_swap_reloc_out
62d2201f2fSdrahn   PARAMS ((bfd *, PTR, PTR));
63d2201f2fSdrahn static bfd_boolean coff_pe_mips_relocate_section
64d2201f2fSdrahn   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
65d2201f2fSdrahn 	   struct internal_reloc *, struct internal_syment *, asection **));
66d2201f2fSdrahn 
67f7cc78ecSespie #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
68f7cc78ecSespie /* The page size is a guess based on ELF.  */
69f7cc78ecSespie 
70f7cc78ecSespie #define COFF_PAGE_SIZE 0x1000
71f7cc78ecSespie 
72f7cc78ecSespie /* For some reason when using mips COFF the value stored in the .text
73f7cc78ecSespie    section for a reference to a common symbol is the value itself plus
74f7cc78ecSespie    any desired offset.  Ian Taylor, Cygnus Support.  */
75f7cc78ecSespie 
76*cf2f2c56Smiod /* If we are producing relocatable output, we need to do some
77f7cc78ecSespie    adjustments to the object file that are not done by the
78f7cc78ecSespie    bfd_perform_relocation function.  This function is called by every
79f7cc78ecSespie    reloc type to make any required adjustments.  */
80f7cc78ecSespie 
81f7cc78ecSespie static bfd_reloc_status_type
coff_mips_reloc(abfd,reloc_entry,symbol,data,input_section,output_bfd,error_message)82f7cc78ecSespie coff_mips_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd,
83f7cc78ecSespie 		 error_message)
84f7cc78ecSespie      bfd *abfd;
85f7cc78ecSespie      arelent *reloc_entry;
86f7cc78ecSespie      asymbol *symbol;
87f7cc78ecSespie      PTR data;
88f7cc78ecSespie      asection *input_section ATTRIBUTE_UNUSED;
89f7cc78ecSespie      bfd *output_bfd;
90f7cc78ecSespie      char **error_message ATTRIBUTE_UNUSED;
91f7cc78ecSespie {
92f7cc78ecSespie   symvalue diff;
93f7cc78ecSespie 
94f7cc78ecSespie   if (output_bfd == (bfd *) NULL)
95f7cc78ecSespie     return bfd_reloc_continue;
96f7cc78ecSespie 
97f7cc78ecSespie   if (bfd_is_com_section (symbol->section))
98f7cc78ecSespie     {
99f7cc78ecSespie #ifndef COFF_WITH_PE
100f7cc78ecSespie       /* We are relocating a common symbol.  The current value in the
101f7cc78ecSespie 	 object file is ORIG + OFFSET, where ORIG is the value of the
102f7cc78ecSespie 	 common symbol as seen by the object file when it was compiled
103f7cc78ecSespie 	 (this may be zero if the symbol was undefined) and OFFSET is
104f7cc78ecSespie 	 the offset into the common symbol (normally zero, but may be
105f7cc78ecSespie 	 non-zero when referring to a field in a common structure).
106f7cc78ecSespie 	 ORIG is the negative of reloc_entry->addend, which is set by
107f7cc78ecSespie 	 the CALC_ADDEND macro below.  We want to replace the value in
108f7cc78ecSespie 	 the object file with NEW + OFFSET, where NEW is the value of
109f7cc78ecSespie 	 the common symbol which we are going to put in the final
110f7cc78ecSespie 	 object file.  NEW is symbol->value.  */
111f7cc78ecSespie       diff = symbol->value + reloc_entry->addend;
112f7cc78ecSespie #else
113f7cc78ecSespie       /* In PE mode, we do not offset the common symbol.  */
114f7cc78ecSespie       diff = reloc_entry->addend;
115f7cc78ecSespie #endif
116f7cc78ecSespie     }
117f7cc78ecSespie   else
118f7cc78ecSespie     {
119f7cc78ecSespie       /* For some reason bfd_perform_relocation always effectively
120f7cc78ecSespie 	 ignores the addend for a COFF target when producing
121*cf2f2c56Smiod 	 relocatable output.  This seems to be always wrong for 386
122f7cc78ecSespie 	 COFF, so we handle the addend here instead.  */
123f7cc78ecSespie       diff = reloc_entry->addend;
124f7cc78ecSespie     }
125f7cc78ecSespie 
126f7cc78ecSespie #ifdef COFF_WITH_PE
127f7cc78ecSespie #if 0
128f7cc78ecSespie   /* dj - handle it like any other reloc? */
129f7cc78ecSespie   /* FIXME: How should this case be handled?  */
130f7cc78ecSespie   if (reloc_entry->howto->type == MIPS_R_RVA && diff != 0)
131f7cc78ecSespie     abort ();
132f7cc78ecSespie #endif
133f7cc78ecSespie #endif
134f7cc78ecSespie 
135f7cc78ecSespie #define DOIT(x) \
136f7cc78ecSespie   x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + (diff >> howto->rightshift)) & howto->dst_mask))
137f7cc78ecSespie 
138f7cc78ecSespie     if (diff != 0)
139f7cc78ecSespie       {
140f7cc78ecSespie 	reloc_howto_type *howto = reloc_entry->howto;
141f7cc78ecSespie 	unsigned char *addr = (unsigned char *) data + reloc_entry->address;
142f7cc78ecSespie 
143f7cc78ecSespie 	switch (howto->size)
144f7cc78ecSespie 	  {
145f7cc78ecSespie 	  case 0:
146f7cc78ecSespie 	    {
147f7cc78ecSespie 	      char x = bfd_get_8 (abfd, addr);
148f7cc78ecSespie 	      DOIT (x);
149f7cc78ecSespie 	      bfd_put_8 (abfd, x, addr);
150f7cc78ecSespie 	    }
151f7cc78ecSespie 	    break;
152f7cc78ecSespie 
153f7cc78ecSespie 	  case 1:
154f7cc78ecSespie 	    {
155f7cc78ecSespie 	      short x = bfd_get_16 (abfd, addr);
156f7cc78ecSespie 	      DOIT (x);
157d2201f2fSdrahn 	      bfd_put_16 (abfd, (bfd_vma) x, addr);
158f7cc78ecSespie 	    }
159f7cc78ecSespie 	    break;
160f7cc78ecSespie 
161f7cc78ecSespie 	  case 2:
162f7cc78ecSespie 	    {
163f7cc78ecSespie 	      long x = bfd_get_32 (abfd, addr);
164f7cc78ecSespie 	      DOIT (x);
165d2201f2fSdrahn 	      bfd_put_32 (abfd, (bfd_vma) x, addr);
166f7cc78ecSespie 	    }
167f7cc78ecSespie 	    break;
168f7cc78ecSespie 
169f7cc78ecSespie 	  default:
170f7cc78ecSespie 	    abort ();
171f7cc78ecSespie 	  }
172f7cc78ecSespie       }
173f7cc78ecSespie 
174f7cc78ecSespie   /* Now let bfd_perform_relocation finish everything up.  */
175f7cc78ecSespie   return bfd_reloc_continue;
176f7cc78ecSespie }
177f7cc78ecSespie 
178f7cc78ecSespie #ifdef COFF_WITH_PE
179d2201f2fSdrahn /* Return TRUE if this relocation should
180f7cc78ecSespie    appear in the output .reloc section.  */
181f7cc78ecSespie 
182d2201f2fSdrahn static bfd_boolean
in_reloc_p(abfd,howto)183d2201f2fSdrahn in_reloc_p (abfd, howto)
184f7cc78ecSespie      bfd * abfd ATTRIBUTE_UNUSED;
185f7cc78ecSespie      reloc_howto_type *howto;
186f7cc78ecSespie {
187f7cc78ecSespie   return ! howto->pc_relative && howto->type != MIPS_R_RVA;
188f7cc78ecSespie }
189f7cc78ecSespie #endif
190f7cc78ecSespie 
191f7cc78ecSespie #ifndef PCRELOFFSET
192d2201f2fSdrahn #define PCRELOFFSET FALSE
193f7cc78ecSespie #endif
194f7cc78ecSespie 
195f7cc78ecSespie static reloc_howto_type howto_table[] =
196f7cc78ecSespie {
197f7cc78ecSespie   /* Reloc type 0 is ignored.  The reloc reading code ensures that
198f7cc78ecSespie      this is a reference to the .abs section, which will cause
199f7cc78ecSespie      bfd_perform_relocation to do nothing.  */
200f7cc78ecSespie   HOWTO (MIPS_R_ABSOLUTE,	/* type */
201f7cc78ecSespie 	 0,			/* rightshift */
202f7cc78ecSespie 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
203f7cc78ecSespie 	 8,			/* bitsize */
204d2201f2fSdrahn 	 FALSE,			/* pc_relative */
205f7cc78ecSespie 	 0,			/* bitpos */
206f7cc78ecSespie 	 complain_overflow_dont, /* complain_on_overflow */
207f7cc78ecSespie 	 0,			/* special_function */
208f7cc78ecSespie 	 "IGNORE",		/* name */
209d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
210f7cc78ecSespie 	 0,			/* src_mask */
211f7cc78ecSespie 	 0,			/* dst_mask */
212d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
213f7cc78ecSespie 
214f7cc78ecSespie   /* A 16 bit reference to a symbol, normally from a data section.  */
215f7cc78ecSespie   HOWTO (MIPS_R_REFHALF,	/* type */
216f7cc78ecSespie 	 0,			/* rightshift */
217f7cc78ecSespie 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
218f7cc78ecSespie 	 16,			/* bitsize */
219d2201f2fSdrahn 	 FALSE,			/* pc_relative */
220f7cc78ecSespie 	 0,			/* bitpos */
221f7cc78ecSespie 	 complain_overflow_bitfield, /* complain_on_overflow */
222f7cc78ecSespie 	 coff_mips_reloc,	/* special_function */
223f7cc78ecSespie 	 "REFHALF",		/* name */
224d2201f2fSdrahn 	 TRUE,			/* partial_inplace */
225f7cc78ecSespie 	 0xffff,		/* src_mask */
226f7cc78ecSespie 	 0xffff,		/* dst_mask */
227d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
228f7cc78ecSespie 
229f7cc78ecSespie   /* A 32 bit reference to a symbol, normally from a data section.  */
230f7cc78ecSespie   HOWTO (MIPS_R_REFWORD,	/* type */
231f7cc78ecSespie 	 0,			/* rightshift */
232f7cc78ecSespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
233f7cc78ecSespie 	 32,			/* bitsize */
234d2201f2fSdrahn 	 FALSE,			/* pc_relative */
235f7cc78ecSespie 	 0,			/* bitpos */
236f7cc78ecSespie 	 complain_overflow_bitfield, /* complain_on_overflow */
237f7cc78ecSespie 	 coff_mips_reloc,	/* special_function */
238f7cc78ecSespie 	 "REFWORD",		/* name */
239d2201f2fSdrahn 	 TRUE,			/* partial_inplace */
240f7cc78ecSespie 	 0xffffffff,		/* src_mask */
241f7cc78ecSespie 	 0xffffffff,		/* dst_mask */
242d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
243f7cc78ecSespie 
244f7cc78ecSespie   /* A 26 bit absolute jump address.  */
245f7cc78ecSespie   HOWTO (MIPS_R_JMPADDR,	/* type */
246f7cc78ecSespie 	 2,			/* rightshift */
247f7cc78ecSespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
248f7cc78ecSespie 	 26,			/* bitsize */
249d2201f2fSdrahn 	 FALSE,			/* pc_relative */
250f7cc78ecSespie 	 0,			/* bitpos */
251f7cc78ecSespie 	 complain_overflow_dont, /* complain_on_overflow */
252f7cc78ecSespie 	 			/* This needs complex overflow
253f7cc78ecSespie 				   detection, because the upper four
254f7cc78ecSespie 				   bits must match the PC.  */
255f7cc78ecSespie 	 coff_mips_reloc,	/* special_function */
256f7cc78ecSespie 	 "JMPADDR",		/* name */
257d2201f2fSdrahn 	 TRUE,			/* partial_inplace */
258f7cc78ecSespie 	 0x3ffffff,		/* src_mask */
259f7cc78ecSespie 	 0x3ffffff,		/* dst_mask */
260d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
261f7cc78ecSespie 
262f7cc78ecSespie   /* The high 16 bits of a symbol value.  Handled by the function
263f7cc78ecSespie      mips_refhi_reloc.  */
264f7cc78ecSespie   HOWTO (MIPS_R_REFHI,		/* type */
265f7cc78ecSespie 	 16,			/* rightshift */
266f7cc78ecSespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
267f7cc78ecSespie 	 16,			/* bitsize */
268d2201f2fSdrahn 	 FALSE,			/* pc_relative */
269f7cc78ecSespie 	 0,			/* bitpos */
270f7cc78ecSespie 	 complain_overflow_bitfield, /* complain_on_overflow */
271f7cc78ecSespie 	 coff_mips_reloc,	/* special_function */
272f7cc78ecSespie 	 "REFHI",		/* name */
273d2201f2fSdrahn 	 TRUE,			/* partial_inplace */
274f7cc78ecSespie 	 0xffff,		/* src_mask */
275f7cc78ecSespie 	 0xffff,		/* dst_mask */
276d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
277f7cc78ecSespie 
278f7cc78ecSespie   /* The low 16 bits of a symbol value.  */
279f7cc78ecSespie   HOWTO (MIPS_R_REFLO,		/* type */
280f7cc78ecSespie 	 0,			/* rightshift */
281f7cc78ecSespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
282f7cc78ecSespie 	 16,			/* bitsize */
283d2201f2fSdrahn 	 FALSE,			/* pc_relative */
284f7cc78ecSespie 	 0,			/* bitpos */
285f7cc78ecSespie 	 complain_overflow_dont, /* complain_on_overflow */
286f7cc78ecSespie 	 coff_mips_reloc,	/* special_function */
287f7cc78ecSespie 	 "REFLO",		/* name */
288d2201f2fSdrahn 	 TRUE,			/* partial_inplace */
289f7cc78ecSespie 	 0xffff,		/* src_mask */
290f7cc78ecSespie 	 0xffff,		/* dst_mask */
291d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
292f7cc78ecSespie 
293f7cc78ecSespie   /* A reference to an offset from the gp register.  Handled by the
294f7cc78ecSespie      function mips_gprel_reloc.  */
295f7cc78ecSespie   HOWTO (MIPS_R_GPREL,		/* type */
296f7cc78ecSespie 	 0,			/* rightshift */
297f7cc78ecSespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
298f7cc78ecSespie 	 16,			/* bitsize */
299d2201f2fSdrahn 	 FALSE,			/* pc_relative */
300f7cc78ecSespie 	 0,			/* bitpos */
301f7cc78ecSespie 	 complain_overflow_signed, /* complain_on_overflow */
302f7cc78ecSespie 	 coff_mips_reloc,	/* special_function */
303f7cc78ecSespie 	 "GPREL",		/* name */
304d2201f2fSdrahn 	 TRUE,			/* partial_inplace */
305f7cc78ecSespie 	 0xffff,		/* src_mask */
306f7cc78ecSespie 	 0xffff,		/* dst_mask */
307d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
308f7cc78ecSespie 
309f7cc78ecSespie   /* A reference to a literal using an offset from the gp register.
310f7cc78ecSespie      Handled by the function mips_gprel_reloc.  */
311f7cc78ecSespie   HOWTO (MIPS_R_LITERAL,	/* type */
312f7cc78ecSespie 	 0,			/* rightshift */
313f7cc78ecSespie 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
314f7cc78ecSespie 	 16,			/* bitsize */
315d2201f2fSdrahn 	 FALSE,			/* pc_relative */
316f7cc78ecSespie 	 0,			/* bitpos */
317f7cc78ecSespie 	 complain_overflow_signed, /* complain_on_overflow */
318f7cc78ecSespie 	 coff_mips_reloc,	/* special_function */
319f7cc78ecSespie 	 "LITERAL",		/* name */
320d2201f2fSdrahn 	 TRUE,			/* partial_inplace */
321f7cc78ecSespie 	 0xffff,		/* src_mask */
322f7cc78ecSespie 	 0xffff,		/* dst_mask */
323d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
324f7cc78ecSespie 
325f7cc78ecSespie   EMPTY_HOWTO (8),
326f7cc78ecSespie   EMPTY_HOWTO (9),
327f7cc78ecSespie   EMPTY_HOWTO (10),
328f7cc78ecSespie   EMPTY_HOWTO (11),
329f7cc78ecSespie   EMPTY_HOWTO (12),
330f7cc78ecSespie   EMPTY_HOWTO (13),
331f7cc78ecSespie   EMPTY_HOWTO (14),
332f7cc78ecSespie   EMPTY_HOWTO (15),
333f7cc78ecSespie   EMPTY_HOWTO (16),
334f7cc78ecSespie   EMPTY_HOWTO (17),
335f7cc78ecSespie   EMPTY_HOWTO (18),
336f7cc78ecSespie   EMPTY_HOWTO (19),
337f7cc78ecSespie   EMPTY_HOWTO (20),
338f7cc78ecSespie   EMPTY_HOWTO (21),
339f7cc78ecSespie   EMPTY_HOWTO (22),
340f7cc78ecSespie   EMPTY_HOWTO (23),
341f7cc78ecSespie   EMPTY_HOWTO (24),
342f7cc78ecSespie   EMPTY_HOWTO (25),
343f7cc78ecSespie   EMPTY_HOWTO (26),
344f7cc78ecSespie   EMPTY_HOWTO (27),
345f7cc78ecSespie   EMPTY_HOWTO (28),
346f7cc78ecSespie   EMPTY_HOWTO (29),
347f7cc78ecSespie   EMPTY_HOWTO (30),
348f7cc78ecSespie   EMPTY_HOWTO (31),
349f7cc78ecSespie   EMPTY_HOWTO (32),
350f7cc78ecSespie   EMPTY_HOWTO (33),
351f7cc78ecSespie   HOWTO (MIPS_R_RVA,            /* type */
352f7cc78ecSespie 	 0,	                /* rightshift */
353f7cc78ecSespie 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
354f7cc78ecSespie 	 32,	                /* bitsize */
355d2201f2fSdrahn 	 FALSE,	                /* pc_relative */
356f7cc78ecSespie 	 0,	                /* bitpos */
357f7cc78ecSespie 	 complain_overflow_bitfield, /* complain_on_overflow */
358f7cc78ecSespie 	 coff_mips_reloc,       /* special_function */
359f7cc78ecSespie 	 "rva32",	        /* name */
360d2201f2fSdrahn 	 TRUE,	                /* partial_inplace */
361f7cc78ecSespie 	 0xffffffff,            /* src_mask */
362f7cc78ecSespie 	 0xffffffff,            /* dst_mask */
363d2201f2fSdrahn 	 FALSE),                /* pcrel_offset */
364f7cc78ecSespie   EMPTY_HOWTO (35),
365f7cc78ecSespie   EMPTY_HOWTO (36),
366f7cc78ecSespie   HOWTO (MIPS_R_PAIR,           /* type */
367f7cc78ecSespie 	 0,	                /* rightshift */
368f7cc78ecSespie 	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
369f7cc78ecSespie 	 32,	                /* bitsize */
370d2201f2fSdrahn 	 FALSE,	                /* pc_relative */
371f7cc78ecSespie 	 0,	                /* bitpos */
372f7cc78ecSespie 	 complain_overflow_bitfield, /* complain_on_overflow */
373f7cc78ecSespie 	 coff_mips_reloc,       /* special_function */
374f7cc78ecSespie 	 "PAIR",	        /* name */
375d2201f2fSdrahn 	 TRUE,	                /* partial_inplace */
376f7cc78ecSespie 	 0xffffffff,            /* src_mask */
377f7cc78ecSespie 	 0xffffffff,            /* dst_mask */
378d2201f2fSdrahn 	 FALSE),                /* pcrel_offset */
379f7cc78ecSespie };
380f7cc78ecSespie 
381f7cc78ecSespie /* Turn a howto into a reloc  nunmber */
382f7cc78ecSespie 
383f7cc78ecSespie #define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
384f7cc78ecSespie #define BADMAG(x) MIPSBADMAG(x)
385f7cc78ecSespie #define MIPS 1			/* Customize coffcode.h */
386f7cc78ecSespie 
387f7cc78ecSespie #define RTYPE2HOWTO(cache_ptr, dst) \
388f7cc78ecSespie 	    (cache_ptr)->howto = howto_table + (dst)->r_type;
389f7cc78ecSespie 
390f7cc78ecSespie /* Compute the addend of a reloc.  If the reloc is to a common symbol,
391f7cc78ecSespie    the object file contains the value of the common symbol.  By the
392f7cc78ecSespie    time this is called, the linker may be using a different symbol
393f7cc78ecSespie    from a different object file with a different value.  Therefore, we
394f7cc78ecSespie    hack wildly to locate the original symbol from this file so that we
395f7cc78ecSespie    can make the correct adjustment.  This macro sets coffsym to the
396f7cc78ecSespie    symbol from the original file, and uses it to set the addend value
397f7cc78ecSespie    correctly.  If this is not a common symbol, the usual addend
398f7cc78ecSespie    calculation is done, except that an additional tweak is needed for
399f7cc78ecSespie    PC relative relocs.
400f7cc78ecSespie    FIXME: This macro refers to symbols and asect; these are from the
401f7cc78ecSespie    calling function, not the macro arguments.  */
402f7cc78ecSespie 
403f7cc78ecSespie #define CALC_ADDEND(abfd, ptr, reloc, cache_ptr)		\
404f7cc78ecSespie   {								\
405f7cc78ecSespie     coff_symbol_type *coffsym = (coff_symbol_type *) NULL;	\
406f7cc78ecSespie     if (ptr && bfd_asymbol_bfd (ptr) != abfd)			\
407f7cc78ecSespie       coffsym = (obj_symbols (abfd)				\
408f7cc78ecSespie 	         + (cache_ptr->sym_ptr_ptr - symbols));		\
409f7cc78ecSespie     else if (ptr)						\
410f7cc78ecSespie       coffsym = coff_symbol_from (abfd, ptr);			\
411f7cc78ecSespie     if (coffsym != (coff_symbol_type *) NULL			\
412f7cc78ecSespie 	&& coffsym->native->u.syment.n_scnum == 0)		\
413f7cc78ecSespie       cache_ptr->addend = - coffsym->native->u.syment.n_value;	\
414f7cc78ecSespie     else if (ptr && bfd_asymbol_bfd (ptr) == abfd		\
415f7cc78ecSespie 	     && ptr->section != (asection *) NULL)		\
416f7cc78ecSespie       cache_ptr->addend = - (ptr->section->vma + ptr->value);	\
417f7cc78ecSespie     else							\
418f7cc78ecSespie       cache_ptr->addend = 0;					\
419f7cc78ecSespie     if (ptr && howto_table[reloc.r_type].pc_relative)		\
420f7cc78ecSespie       cache_ptr->addend += asect->vma;				\
421f7cc78ecSespie   }
422f7cc78ecSespie 
423f7cc78ecSespie /* Convert an rtype to howto for the COFF backend linker.  */
424f7cc78ecSespie 
425f7cc78ecSespie static reloc_howto_type *
coff_mips_rtype_to_howto(abfd,sec,rel,h,sym,addendp)426f7cc78ecSespie coff_mips_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
427f7cc78ecSespie      bfd *abfd ATTRIBUTE_UNUSED;
428f7cc78ecSespie      asection *sec;
429f7cc78ecSespie      struct internal_reloc *rel;
430f7cc78ecSespie      struct coff_link_hash_entry *h;
431f7cc78ecSespie      struct internal_syment *sym;
432f7cc78ecSespie      bfd_vma *addendp;
433f7cc78ecSespie {
434f7cc78ecSespie 
435f7cc78ecSespie   reloc_howto_type *howto;
436f7cc78ecSespie 
437f7cc78ecSespie   howto = howto_table + rel->r_type;
438f7cc78ecSespie 
439f7cc78ecSespie #ifdef COFF_WITH_PE
440f7cc78ecSespie   *addendp = 0;
441f7cc78ecSespie #endif
442f7cc78ecSespie 
443f7cc78ecSespie   if (howto->pc_relative)
444f7cc78ecSespie     *addendp += sec->vma;
445f7cc78ecSespie 
446f7cc78ecSespie   if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0)
447f7cc78ecSespie     {
448f7cc78ecSespie       /* This is a common symbol.  The section contents include the
449f7cc78ecSespie 	 size (sym->n_value) as an addend.  The relocate_section
450f7cc78ecSespie 	 function will be adding in the final value of the symbol.  We
451f7cc78ecSespie 	 need to subtract out the current size in order to get the
452f7cc78ecSespie 	 correct result.  */
453f7cc78ecSespie 
454f7cc78ecSespie       BFD_ASSERT (h != NULL);
455f7cc78ecSespie 
456f7cc78ecSespie #ifndef COFF_WITH_PE
457f7cc78ecSespie       /* I think we *do* want to bypass this.  If we don't, I have
458f7cc78ecSespie 	 seen some data parameters get the wrong relocation address.
459f7cc78ecSespie 	 If I link two versions with and without this section bypassed
460f7cc78ecSespie 	 and then do a binary comparison, the addresses which are
461f7cc78ecSespie 	 different can be looked up in the map.  The case in which
462f7cc78ecSespie 	 this section has been bypassed has addresses which correspond
463f7cc78ecSespie 	 to values I can find in the map.  */
464f7cc78ecSespie       *addendp -= sym->n_value;
465f7cc78ecSespie #endif
466f7cc78ecSespie     }
467f7cc78ecSespie 
468f7cc78ecSespie #ifndef COFF_WITH_PE
469f7cc78ecSespie   /* If the output symbol is common (in which case this must be a
470*cf2f2c56Smiod      relocatable link), we need to add in the final size of the
471f7cc78ecSespie      common symbol.  */
472f7cc78ecSespie   if (h != NULL && h->root.type == bfd_link_hash_common)
473f7cc78ecSespie     *addendp += h->root.u.c.size;
474f7cc78ecSespie #endif
475f7cc78ecSespie 
476f7cc78ecSespie #ifdef COFF_WITH_PE
477f7cc78ecSespie   if (howto->pc_relative)
478f7cc78ecSespie     {
479f7cc78ecSespie       *addendp -= 4;
480f7cc78ecSespie 
481f7cc78ecSespie       /* If the symbol is defined, then the generic code is going to
482f7cc78ecSespie          add back the symbol value in order to cancel out an
483f7cc78ecSespie          adjustment it made to the addend.  However, we set the addend
484f7cc78ecSespie          to 0 at the start of this function.  We need to adjust here,
485f7cc78ecSespie          to avoid the adjustment the generic code will make.  FIXME:
486f7cc78ecSespie          This is getting a bit hackish.  */
487f7cc78ecSespie       if (sym != NULL && sym->n_scnum != 0)
488f7cc78ecSespie 	*addendp -= sym->n_value;
489f7cc78ecSespie     }
490f7cc78ecSespie 
491f7cc78ecSespie   if (rel->r_type == MIPS_R_RVA)
492f7cc78ecSespie     {
493f7cc78ecSespie       *addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase;
494f7cc78ecSespie     }
495f7cc78ecSespie #endif
496f7cc78ecSespie 
497f7cc78ecSespie   return howto;
498f7cc78ecSespie }
499f7cc78ecSespie 
500f7cc78ecSespie #define coff_rtype_to_howto coff_mips_rtype_to_howto
501f7cc78ecSespie 
502f7cc78ecSespie #define coff_bfd_reloc_type_lookup coff_mips_reloc_type_lookup
503f7cc78ecSespie 
504f7cc78ecSespie /* Get the howto structure for a generic reloc type.  */
505f7cc78ecSespie 
506f7cc78ecSespie static reloc_howto_type *
coff_mips_reloc_type_lookup(abfd,code)507f7cc78ecSespie coff_mips_reloc_type_lookup (abfd, code)
508f7cc78ecSespie      bfd *abfd ATTRIBUTE_UNUSED;
509f7cc78ecSespie      bfd_reloc_code_real_type code;
510f7cc78ecSespie {
511f7cc78ecSespie   int mips_type;
512f7cc78ecSespie 
513f7cc78ecSespie   switch (code)
514f7cc78ecSespie     {
515f7cc78ecSespie     case BFD_RELOC_16:
516f7cc78ecSespie       mips_type = MIPS_R_REFHALF;
517f7cc78ecSespie       break;
518f7cc78ecSespie     case BFD_RELOC_32:
519f7cc78ecSespie     case BFD_RELOC_CTOR:
520f7cc78ecSespie       mips_type = MIPS_R_REFWORD;
521f7cc78ecSespie       break;
522f7cc78ecSespie     case BFD_RELOC_MIPS_JMP:
523f7cc78ecSespie       mips_type = MIPS_R_JMPADDR;
524f7cc78ecSespie       break;
525f7cc78ecSespie     case BFD_RELOC_HI16_S:
526f7cc78ecSespie       mips_type = MIPS_R_REFHI;
527f7cc78ecSespie       break;
528f7cc78ecSespie     case BFD_RELOC_LO16:
529f7cc78ecSespie       mips_type = MIPS_R_REFLO;
530f7cc78ecSespie       break;
531d2201f2fSdrahn     case BFD_RELOC_GPREL16:
532f7cc78ecSespie       mips_type = MIPS_R_GPREL;
533f7cc78ecSespie       break;
534f7cc78ecSespie     case BFD_RELOC_MIPS_LITERAL:
535f7cc78ecSespie       mips_type = MIPS_R_LITERAL;
536f7cc78ecSespie       break;
537f7cc78ecSespie /* FIXME?
538f7cc78ecSespie     case BFD_RELOC_16_PCREL_S2:
539f7cc78ecSespie       mips_type = MIPS_R_PCREL16;
540f7cc78ecSespie       break;
541f7cc78ecSespie     case BFD_RELOC_PCREL_HI16_S:
542f7cc78ecSespie       mips_type = MIPS_R_RELHI;
543f7cc78ecSespie       break;
544f7cc78ecSespie     case BFD_RELOC_PCREL_LO16:
545f7cc78ecSespie       mips_type = MIPS_R_RELLO;
546f7cc78ecSespie       break;
547f7cc78ecSespie     case BFD_RELOC_GPREL32:
548f7cc78ecSespie       mips_type = MIPS_R_SWITCH;
549f7cc78ecSespie       break;
550f7cc78ecSespie */
551f7cc78ecSespie     case BFD_RELOC_RVA:
552f7cc78ecSespie       mips_type = MIPS_R_RVA;
553f7cc78ecSespie       break;
554f7cc78ecSespie     default:
555f7cc78ecSespie       return (reloc_howto_type *) NULL;
556f7cc78ecSespie     }
557f7cc78ecSespie 
558f7cc78ecSespie   return &howto_table[mips_type];
559f7cc78ecSespie }
560f7cc78ecSespie 
561f7cc78ecSespie static void
mips_swap_reloc_in(abfd,src,dst)562f7cc78ecSespie mips_swap_reloc_in (abfd, src, dst)
563f7cc78ecSespie      bfd *abfd;
564f7cc78ecSespie      PTR src;
565f7cc78ecSespie      PTR dst;
566f7cc78ecSespie {
567f7cc78ecSespie   static struct internal_reloc pair_prev;
568f7cc78ecSespie   RELOC *reloc_src = (RELOC *) src;
569f7cc78ecSespie   struct internal_reloc *reloc_dst = (struct internal_reloc *) dst;
570f7cc78ecSespie 
571d2201f2fSdrahn   reloc_dst->r_vaddr = H_GET_32 (abfd, reloc_src->r_vaddr);
572d2201f2fSdrahn   reloc_dst->r_symndx = H_GET_S32 (abfd, reloc_src->r_symndx);
573d2201f2fSdrahn   reloc_dst->r_type = H_GET_16 (abfd, reloc_src->r_type);
574f7cc78ecSespie   reloc_dst->r_size = 0;
575f7cc78ecSespie   reloc_dst->r_extern = 0;
576f7cc78ecSespie   reloc_dst->r_offset = 0;
577f7cc78ecSespie 
578f7cc78ecSespie   switch (reloc_dst->r_type)
579f7cc78ecSespie   {
580f7cc78ecSespie   case MIPS_R_REFHI:
581f7cc78ecSespie     pair_prev = *reloc_dst;
582f7cc78ecSespie     break;
583f7cc78ecSespie   case MIPS_R_PAIR:
584f7cc78ecSespie     reloc_dst->r_offset = reloc_dst->r_symndx;
585f7cc78ecSespie     if (reloc_dst->r_offset & 0x8000)
586f7cc78ecSespie       reloc_dst->r_offset -= 0x10000;
587f7cc78ecSespie     /*printf ("dj: pair offset is %08x\n", reloc_dst->r_offset);*/
588f7cc78ecSespie     reloc_dst->r_symndx = pair_prev.r_symndx;
589f7cc78ecSespie     break;
590f7cc78ecSespie   }
591f7cc78ecSespie }
592f7cc78ecSespie 
593f7cc78ecSespie static unsigned int
mips_swap_reloc_out(abfd,src,dst)594f7cc78ecSespie mips_swap_reloc_out (abfd, src, dst)
595f7cc78ecSespie      bfd       *abfd;
596f7cc78ecSespie      PTR	src;
597f7cc78ecSespie      PTR	dst;
598f7cc78ecSespie {
599f7cc78ecSespie   static int prev_offset = 1;
600f7cc78ecSespie   static bfd_vma prev_addr = 0;
601f7cc78ecSespie   struct internal_reloc *reloc_src = (struct internal_reloc *)src;
602f7cc78ecSespie   struct external_reloc *reloc_dst = (struct external_reloc *)dst;
603f7cc78ecSespie 
604f7cc78ecSespie   switch (reloc_src->r_type)
605f7cc78ecSespie     {
606f7cc78ecSespie     case MIPS_R_REFHI:
607f7cc78ecSespie       prev_addr = reloc_src->r_vaddr;
608f7cc78ecSespie       prev_offset = reloc_src->r_offset;
609f7cc78ecSespie       break;
610f7cc78ecSespie     case MIPS_R_REFLO:
611f7cc78ecSespie       if (reloc_src->r_vaddr == prev_addr)
612f7cc78ecSespie 	{
613f7cc78ecSespie 	  /* FIXME: only slightly hackish.  If we see a REFLO pointing to
614f7cc78ecSespie 	     the same address as a REFHI, we assume this is the matching
615f7cc78ecSespie 	     PAIR reloc and output it accordingly.  The symndx is really
616f7cc78ecSespie 	     the low 16 bits of the addend */
617d2201f2fSdrahn 	  H_PUT_32 (abfd, reloc_src->r_vaddr, reloc_dst->r_vaddr);
618d2201f2fSdrahn 	  H_PUT_32 (abfd, reloc_src->r_symndx, reloc_dst->r_symndx);
619d2201f2fSdrahn 	  H_PUT_16 (abfd, MIPS_R_PAIR, reloc_dst->r_type);
620f7cc78ecSespie 	  return RELSZ;
621f7cc78ecSespie 	}
622f7cc78ecSespie       break;
623f7cc78ecSespie     }
624f7cc78ecSespie 
625d2201f2fSdrahn   H_PUT_32 (abfd, reloc_src->r_vaddr, reloc_dst->r_vaddr);
626d2201f2fSdrahn   H_PUT_32 (abfd, reloc_src->r_symndx, reloc_dst->r_symndx);
627f7cc78ecSespie 
628d2201f2fSdrahn   H_PUT_16 (abfd, reloc_src->r_type, reloc_dst->r_type);
629f7cc78ecSespie   return RELSZ;
630f7cc78ecSespie }
631f7cc78ecSespie 
632f7cc78ecSespie #define coff_swap_reloc_in mips_swap_reloc_in
633f7cc78ecSespie #define coff_swap_reloc_out mips_swap_reloc_out
634f7cc78ecSespie #define NO_COFF_RELOCS
635f7cc78ecSespie 
636d2201f2fSdrahn static bfd_boolean
coff_pe_mips_relocate_section(output_bfd,info,input_bfd,input_section,contents,relocs,syms,sections)637f7cc78ecSespie coff_pe_mips_relocate_section (output_bfd, info, input_bfd,
638f7cc78ecSespie 			       input_section, contents, relocs, syms,
639f7cc78ecSespie 			       sections)
640f7cc78ecSespie      bfd *output_bfd;
641f7cc78ecSespie      struct bfd_link_info *info;
642f7cc78ecSespie      bfd *input_bfd;
643f7cc78ecSespie      asection *input_section;
644f7cc78ecSespie      bfd_byte *contents;
645f7cc78ecSespie      struct internal_reloc *relocs;
646f7cc78ecSespie      struct internal_syment *syms;
647f7cc78ecSespie      asection **sections;
648f7cc78ecSespie {
649f7cc78ecSespie   bfd_vma gp;
650d2201f2fSdrahn   bfd_boolean gp_undefined;
651f7cc78ecSespie   size_t adjust;
652f7cc78ecSespie   struct internal_reloc *rel;
653f7cc78ecSespie   struct internal_reloc *rel_end;
654f7cc78ecSespie   unsigned int i;
655d2201f2fSdrahn   bfd_boolean got_lo;
656f7cc78ecSespie 
657*cf2f2c56Smiod   if (info->relocatable)
658f7cc78ecSespie   {
659f7cc78ecSespie     (*_bfd_error_handler) (_("\
660f7cc78ecSespie %s: `ld -r' not supported with PE MIPS objects\n"),
661d2201f2fSdrahn 			   bfd_archive_filename (input_bfd));
662f7cc78ecSespie     bfd_set_error (bfd_error_bad_value);
663d2201f2fSdrahn     return FALSE;
664f7cc78ecSespie   }
665f7cc78ecSespie 
666f7cc78ecSespie   BFD_ASSERT (input_bfd->xvec->byteorder
667f7cc78ecSespie 	      == output_bfd->xvec->byteorder);
668f7cc78ecSespie 
669f7cc78ecSespie #if 0
670f7cc78ecSespie   printf ("dj: relocate %s(%s) %08x\n",
671f7cc78ecSespie 	 input_bfd->filename, input_section->name,
672f7cc78ecSespie 	 input_section->output_section->vma + input_section->output_offset);
673f7cc78ecSespie #endif
674f7cc78ecSespie 
675f7cc78ecSespie   gp = _bfd_get_gp_value (output_bfd);
676f7cc78ecSespie   if (gp == 0)
677d2201f2fSdrahn     gp_undefined = TRUE;
678f7cc78ecSespie   else
679d2201f2fSdrahn     gp_undefined = FALSE;
680f7cc78ecSespie 
681d2201f2fSdrahn   got_lo = FALSE;
682f7cc78ecSespie 
683f7cc78ecSespie   adjust = 0;
684f7cc78ecSespie 
685f7cc78ecSespie   rel = relocs;
686f7cc78ecSespie   rel_end = rel + input_section->reloc_count;
687f7cc78ecSespie   for (i = 0; rel < rel_end; rel++, i++)
688f7cc78ecSespie     {
689f7cc78ecSespie       long symndx;
690f7cc78ecSespie       struct coff_link_hash_entry *h;
691f7cc78ecSespie       struct internal_syment *sym;
692f7cc78ecSespie       bfd_vma addend = 0;
693f7cc78ecSespie       bfd_vma val, tmp, targ, src, low;
694f7cc78ecSespie       reloc_howto_type *howto;
695f7cc78ecSespie       unsigned char *mem = contents + rel->r_vaddr;
696f7cc78ecSespie 
697f7cc78ecSespie       symndx = rel->r_symndx;
698f7cc78ecSespie 
699f7cc78ecSespie       if (symndx == -1)
700f7cc78ecSespie 	{
701f7cc78ecSespie 	  h = NULL;
702f7cc78ecSespie 	  sym = NULL;
703f7cc78ecSespie 	}
704f7cc78ecSespie       else
705f7cc78ecSespie 	{
706f7cc78ecSespie 	  h = obj_coff_sym_hashes (input_bfd)[symndx];
707f7cc78ecSespie 	  sym = syms + symndx;
708f7cc78ecSespie 	}
709f7cc78ecSespie 
710f7cc78ecSespie       /* COFF treats common symbols in one of two ways.  Either the
711f7cc78ecSespie          size of the symbol is included in the section contents, or it
712f7cc78ecSespie          is not.  We assume that the size is not included, and force
713f7cc78ecSespie          the rtype_to_howto function to adjust the addend as needed.  */
714f7cc78ecSespie 
715f7cc78ecSespie       if (sym != NULL && sym->n_scnum != 0)
716f7cc78ecSespie 	addend = - sym->n_value;
717f7cc78ecSespie       else
718f7cc78ecSespie 	addend = 0;
719f7cc78ecSespie 
720f7cc78ecSespie       howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
721f7cc78ecSespie 				       sym, &addend);
722f7cc78ecSespie       if (howto == NULL)
723d2201f2fSdrahn 	return FALSE;
724f7cc78ecSespie 
725*cf2f2c56Smiod       /* If we are doing a relocatable link, then we can just ignore
726f7cc78ecSespie          a PC relative reloc that is pcrel_offset.  It will already
727*cf2f2c56Smiod          have the correct value.  If this is not a relocatable link,
728f7cc78ecSespie          then we should ignore the symbol value.  */
729f7cc78ecSespie       if (howto->pc_relative && howto->pcrel_offset)
730f7cc78ecSespie 	{
731*cf2f2c56Smiod 	  if (info->relocatable)
732f7cc78ecSespie 	    continue;
733f7cc78ecSespie 	  if (sym != NULL && sym->n_scnum != 0)
734f7cc78ecSespie 	    addend += sym->n_value;
735f7cc78ecSespie 	}
736f7cc78ecSespie 
737f7cc78ecSespie       val = 0;
738f7cc78ecSespie 
739f7cc78ecSespie       if (h == NULL)
740f7cc78ecSespie 	{
741f7cc78ecSespie 	  asection *sec;
742f7cc78ecSespie 
743f7cc78ecSespie 	  if (symndx == -1)
744f7cc78ecSespie 	    {
745f7cc78ecSespie 	      sec = bfd_abs_section_ptr;
746f7cc78ecSespie 	      val = 0;
747f7cc78ecSespie 	    }
748f7cc78ecSespie 	  else
749f7cc78ecSespie 	    {
750f7cc78ecSespie 	      sec = sections[symndx];
751f7cc78ecSespie               val = (sec->output_section->vma
752f7cc78ecSespie 		     + sec->output_offset
753f7cc78ecSespie 		     + sym->n_value);
754f7cc78ecSespie 	      if (! obj_pe (input_bfd))
755f7cc78ecSespie 		val -= sec->vma;
756f7cc78ecSespie 	    }
757f7cc78ecSespie 	}
758f7cc78ecSespie       else
759f7cc78ecSespie 	{
760f7cc78ecSespie 	  if (h->root.type == bfd_link_hash_defined
761f7cc78ecSespie 	      || h->root.type == bfd_link_hash_defweak)
762f7cc78ecSespie 	    {
763f7cc78ecSespie 	      asection *sec;
764f7cc78ecSespie 
765f7cc78ecSespie 	      sec = h->root.u.def.section;
766f7cc78ecSespie 	      val = (h->root.u.def.value
767f7cc78ecSespie 		     + sec->output_section->vma
768f7cc78ecSespie 		     + sec->output_offset);
769f7cc78ecSespie 	      }
770f7cc78ecSespie 
771*cf2f2c56Smiod 	  else if (! info->relocatable)
772f7cc78ecSespie 	    {
773f7cc78ecSespie 	      if (! ((*info->callbacks->undefined_symbol)
774f7cc78ecSespie 		     (info, h->root.root.string, input_bfd, input_section,
775d2201f2fSdrahn 		      rel->r_vaddr - input_section->vma, TRUE)))
776d2201f2fSdrahn 		return FALSE;
777f7cc78ecSespie 	    }
778f7cc78ecSespie 	}
779f7cc78ecSespie 
780f7cc78ecSespie       src = rel->r_vaddr + input_section->output_section->vma
781f7cc78ecSespie 	+ input_section->output_offset;
782f7cc78ecSespie #if 0
783f7cc78ecSespie       printf ("dj: reloc %02x %-8s a=%08x/%08x(%08x) v=%08x+%08x %s\n",
784f7cc78ecSespie 	     rel->r_type, howto_table[rel->r_type].name,
785f7cc78ecSespie 	     src, rel->r_vaddr, *(unsigned long *)mem, val, rel->r_offset,
786f7cc78ecSespie 	     h?h->root.root.string:"(none)");
787f7cc78ecSespie #endif
788f7cc78ecSespie 
789f7cc78ecSespie       /* OK, at this point the following variables are set up:
790f7cc78ecSespie 	   src = VMA of the memory we're fixing up
791f7cc78ecSespie 	   mem = pointer to memory we're fixing up
792f7cc78ecSespie 	   val = VMA of what we need to refer to
793f7cc78ecSespie       */
794f7cc78ecSespie 
795f7cc78ecSespie #define UI(x) (*_bfd_error_handler) (_("%s: unimplemented %s\n"), \
796d2201f2fSdrahn 				     bfd_archive_filename (input_bfd), x); \
797f7cc78ecSespie 	      bfd_set_error (bfd_error_bad_value);
798f7cc78ecSespie 
799f7cc78ecSespie       switch (rel->r_type)
800f7cc78ecSespie 	{
801f7cc78ecSespie 	case MIPS_R_ABSOLUTE:
802f7cc78ecSespie 	  /* ignore these */
803f7cc78ecSespie 	  break;
804f7cc78ecSespie 
805f7cc78ecSespie 	case MIPS_R_REFHALF:
806f7cc78ecSespie 	  UI("refhalf");
807f7cc78ecSespie 	  break;
808f7cc78ecSespie 
809f7cc78ecSespie 	case MIPS_R_REFWORD:
810f7cc78ecSespie 	  tmp = bfd_get_32(input_bfd, mem);
811f7cc78ecSespie 	  /* printf ("refword: src=%08x targ=%08x+%08x\n", src, tmp, val); */
812f7cc78ecSespie 	  tmp += val;
813f7cc78ecSespie 	  bfd_put_32(input_bfd, tmp, mem);
814f7cc78ecSespie 	  break;
815f7cc78ecSespie 
816f7cc78ecSespie 	case MIPS_R_JMPADDR:
817f7cc78ecSespie 	  tmp = bfd_get_32(input_bfd, mem);
818f7cc78ecSespie 	  targ = val + (tmp&0x03ffffff)*4;
819f7cc78ecSespie 	  if ((src & 0xf0000000) != (targ & 0xf0000000))
820f7cc78ecSespie 	    {
821f7cc78ecSespie 	      (*_bfd_error_handler) (_("%s: jump too far away\n"),
822d2201f2fSdrahn 				     bfd_archive_filename (input_bfd));
823f7cc78ecSespie 	      bfd_set_error (bfd_error_bad_value);
824d2201f2fSdrahn 	      return FALSE;
825f7cc78ecSespie 	    }
826f7cc78ecSespie 	  tmp &= 0xfc000000;
827f7cc78ecSespie 	  tmp |= (targ/4) & 0x3ffffff;
828f7cc78ecSespie 	  bfd_put_32(input_bfd, tmp, mem);
829f7cc78ecSespie 	  break;
830f7cc78ecSespie 
831f7cc78ecSespie 	case MIPS_R_REFHI:
832f7cc78ecSespie 	  tmp = bfd_get_32(input_bfd, mem);
833f7cc78ecSespie 	  switch (rel[1].r_type)
834f7cc78ecSespie 	    {
835f7cc78ecSespie 	    case MIPS_R_PAIR:
836f7cc78ecSespie 	      /* MS PE object */
837f7cc78ecSespie 	      targ = val + rel[1].r_offset + ((tmp & 0xffff) << 16);
838f7cc78ecSespie 	      break;
839f7cc78ecSespie 	    case MIPS_R_REFLO:
840f7cc78ecSespie 	      /* GNU COFF object */
841f7cc78ecSespie 	      low = bfd_get_32(input_bfd, contents + rel[1].r_vaddr);
842f7cc78ecSespie 	      low &= 0xffff;
843f7cc78ecSespie 	      if (low & 0x8000)
844f7cc78ecSespie 		low -= 0x10000;
845f7cc78ecSespie 	      targ = val + low + ((tmp & 0xffff) << 16);
846f7cc78ecSespie 	      break;
847f7cc78ecSespie 	    default:
848f7cc78ecSespie 	      (*_bfd_error_handler) (_("%s: bad pair/reflo after refhi\n"),
849d2201f2fSdrahn 				     bfd_archive_filename (input_bfd));
850f7cc78ecSespie 	      bfd_set_error (bfd_error_bad_value);
851d2201f2fSdrahn 	      return FALSE;
852f7cc78ecSespie 	    }
853f7cc78ecSespie 	  tmp &= 0xffff0000;
854f7cc78ecSespie 	  tmp |= (targ >> 16) & 0xffff;
855f7cc78ecSespie 	  bfd_put_32(input_bfd, tmp, mem);
856f7cc78ecSespie 	  break;
857f7cc78ecSespie 
858f7cc78ecSespie 	case MIPS_R_REFLO:
859f7cc78ecSespie 	  tmp = bfd_get_32(input_bfd, mem);
860f7cc78ecSespie 	  targ = val + (tmp & 0xffff);
861f7cc78ecSespie 	  /* printf ("refword: src=%08x targ=%08x\n", src, targ); */
862f7cc78ecSespie 	  tmp &= 0xffff0000;
863f7cc78ecSespie 	  tmp |= targ & 0xffff;
864f7cc78ecSespie 	  bfd_put_32(input_bfd, tmp, mem);
865f7cc78ecSespie 	  break;
866f7cc78ecSespie 
867f7cc78ecSespie 	case MIPS_R_GPREL:
868f7cc78ecSespie 	case MIPS_R_LITERAL:
869f7cc78ecSespie 	  UI("gprel");
870f7cc78ecSespie 	  break;
871f7cc78ecSespie 
872f7cc78ecSespie 	case MIPS_R_SECTION:
873f7cc78ecSespie 	  UI("section");
874f7cc78ecSespie 	  break;
875f7cc78ecSespie 
876f7cc78ecSespie 	case MIPS_R_SECREL:
877f7cc78ecSespie 	  UI("secrel");
878f7cc78ecSespie 	  break;
879f7cc78ecSespie 
880f7cc78ecSespie 	case MIPS_R_SECRELLO:
881f7cc78ecSespie 	  UI("secrello");
882f7cc78ecSespie 	  break;
883f7cc78ecSespie 
884f7cc78ecSespie 	case MIPS_R_SECRELHI:
885f7cc78ecSespie 	  UI("secrelhi");
886f7cc78ecSespie 	  break;
887f7cc78ecSespie 
888f7cc78ecSespie 	case MIPS_R_RVA:
889f7cc78ecSespie 	  tmp = bfd_get_32 (input_bfd, mem);
890f7cc78ecSespie 	  /* printf ("rva: src=%08x targ=%08x+%08x\n", src, tmp, val); */
891f7cc78ecSespie 	  tmp += val
892f7cc78ecSespie 	    - pe_data (input_section->output_section->owner)->pe_opthdr.ImageBase;
893f7cc78ecSespie 	  bfd_put_32 (input_bfd, tmp, mem);
894f7cc78ecSespie 	  break;
895f7cc78ecSespie 
896f7cc78ecSespie 	case MIPS_R_PAIR:
897f7cc78ecSespie 	  /* ignore these */
898f7cc78ecSespie 	  break;
899f7cc78ecSespie 	}
900f7cc78ecSespie     }
901f7cc78ecSespie 
902d2201f2fSdrahn   return TRUE;
903f7cc78ecSespie }
904f7cc78ecSespie 
905f7cc78ecSespie #define coff_relocate_section coff_pe_mips_relocate_section
906f7cc78ecSespie 
907f7cc78ecSespie #ifdef TARGET_UNDERSCORE
908f7cc78ecSespie 
909f7cc78ecSespie /* If mips gcc uses underscores for symbol names, then it does not use
910f7cc78ecSespie    a leading dot for local labels, so if TARGET_UNDERSCORE is defined
911f7cc78ecSespie    we treat all symbols starting with L as local.  */
912f7cc78ecSespie 
913d2201f2fSdrahn static bfd_boolean coff_mips_is_local_label_name
914d2201f2fSdrahn    PARAMS ((bfd *, const char *));
915f7cc78ecSespie 
916d2201f2fSdrahn static bfd_boolean
coff_mips_is_local_label_name(abfd,name)917f7cc78ecSespie coff_mips_is_local_label_name (abfd, name)
918f7cc78ecSespie      bfd *abfd;
919f7cc78ecSespie      const char *name;
920f7cc78ecSespie {
921f7cc78ecSespie   if (name[0] == 'L')
922d2201f2fSdrahn     return TRUE;
923f7cc78ecSespie 
924f7cc78ecSespie   return _bfd_coff_is_local_label_name (abfd, name);
925f7cc78ecSespie }
926f7cc78ecSespie 
927f7cc78ecSespie #define coff_bfd_is_local_label_name coff_mips_is_local_label_name
928f7cc78ecSespie 
929f7cc78ecSespie #endif /* TARGET_UNDERSCORE */
930f7cc78ecSespie 
931f7cc78ecSespie #define COFF_NO_HACK_SCNHDR_SIZE
932f7cc78ecSespie 
933f7cc78ecSespie #include "coffcode.h"
934f7cc78ecSespie 
935f7cc78ecSespie const bfd_target
936f7cc78ecSespie #ifdef TARGET_SYM
937f7cc78ecSespie   TARGET_SYM =
938f7cc78ecSespie #else
939f7cc78ecSespie   mipslpe_vec =
940f7cc78ecSespie #endif
941f7cc78ecSespie {
942f7cc78ecSespie #ifdef TARGET_NAME
943f7cc78ecSespie   TARGET_NAME,
944f7cc78ecSespie #else
945f7cc78ecSespie   "pe-mips",			/* name */
946f7cc78ecSespie #endif
947f7cc78ecSespie   bfd_target_coff_flavour,
948f7cc78ecSespie   BFD_ENDIAN_LITTLE,		/* data byte order is little */
949f7cc78ecSespie   BFD_ENDIAN_LITTLE,		/* header byte order is little */
950f7cc78ecSespie 
951f7cc78ecSespie   (HAS_RELOC | EXEC_P |		/* object flags */
952f7cc78ecSespie    HAS_LINENO | HAS_DEBUG |
953f7cc78ecSespie    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
954f7cc78ecSespie 
955f7cc78ecSespie #ifndef COFF_WITH_PE
956f7cc78ecSespie   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */
957f7cc78ecSespie    | SEC_CODE | SEC_DATA),
958f7cc78ecSespie #else
959f7cc78ecSespie   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */
960f7cc78ecSespie    | SEC_CODE | SEC_DATA
961f7cc78ecSespie    | SEC_LINK_ONCE | SEC_LINK_DUPLICATES),
962f7cc78ecSespie #endif
963f7cc78ecSespie 
964f7cc78ecSespie #ifdef TARGET_UNDERSCORE
965f7cc78ecSespie   TARGET_UNDERSCORE,		/* leading underscore */
966f7cc78ecSespie #else
967f7cc78ecSespie   0,				/* leading underscore */
968f7cc78ecSespie #endif
969f7cc78ecSespie   '/',				/* ar_pad_char */
970f7cc78ecSespie   15,				/* ar_max_namelen */
971f7cc78ecSespie 
972f7cc78ecSespie   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
973f7cc78ecSespie      bfd_getl32, bfd_getl_signed_32, bfd_putl32,
974f7cc78ecSespie      bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
975f7cc78ecSespie   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
976f7cc78ecSespie      bfd_getl32, bfd_getl_signed_32, bfd_putl32,
977f7cc78ecSespie      bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
978f7cc78ecSespie 
979f7cc78ecSespie /* Note that we allow an object file to be treated as a core file as well.  */
980f7cc78ecSespie     {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
981f7cc78ecSespie        bfd_generic_archive_p, coff_object_p},
982f7cc78ecSespie     {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
983f7cc78ecSespie        bfd_false},
984f7cc78ecSespie     {bfd_false, coff_write_object_contents, /* bfd_write_contents */
985f7cc78ecSespie        _bfd_write_archive_contents, bfd_false},
986f7cc78ecSespie 
987f7cc78ecSespie      BFD_JUMP_TABLE_GENERIC (coff),
988f7cc78ecSespie      BFD_JUMP_TABLE_COPY (coff),
989f7cc78ecSespie      BFD_JUMP_TABLE_CORE (_bfd_nocore),
990f7cc78ecSespie      BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
991f7cc78ecSespie      BFD_JUMP_TABLE_SYMBOLS (coff),
992f7cc78ecSespie      BFD_JUMP_TABLE_RELOCS (coff),
993f7cc78ecSespie      BFD_JUMP_TABLE_WRITE (coff),
994f7cc78ecSespie      BFD_JUMP_TABLE_LINK (coff),
995f7cc78ecSespie      BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
996f7cc78ecSespie 
997f7cc78ecSespie   NULL,
998f7cc78ecSespie 
999f7cc78ecSespie   COFF_SWAP_TABLE
1000f7cc78ecSespie };
1001