pe-mips.c revision 179407
1179407Sobrien/* BFD back-end for MIPS PE COFF files.
2179407Sobrien   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3179407Sobrien   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
4179407Sobrien   Modified from coff-i386.c by DJ Delorie, dj@cygnus.com
5179407Sobrien
6179407SobrienThis file is part of BFD, the Binary File Descriptor library.
7179407Sobrien
8179407SobrienThis program is free software; you can redistribute it and/or modify
9179407Sobrienit under the terms of the GNU General Public License as published by
10179407Sobrienthe Free Software Foundation; either version 2 of the License, or
11179407Sobrien(at your option) any later version.
12179407Sobrien
13179407SobrienThis program is distributed in the hope that it will be useful,
14179407Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
15179407SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16179407SobrienGNU General Public License for more details.
17179407Sobrien
18179407SobrienYou should have received a copy of the GNU General Public License
19179407Sobrienalong with this program; if not, write to the Free Software
20179407SobrienFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21179407Sobrien
22179407Sobrien#define COFF_WITH_PE
23179407Sobrien#define COFF_LONG_SECTION_NAMES
24179407Sobrien#define PCRELOFFSET TRUE
25179407Sobrien
26179407Sobrien#include "bfd.h"
27179407Sobrien#include "sysdep.h"
28179407Sobrien#include "libbfd.h"
29179407Sobrien
30179407Sobrien#include "coff/mipspe.h"
31179407Sobrien
32179407Sobrien#include "coff/internal.h"
33179407Sobrien
34179407Sobrien#include "coff/pe.h"
35179407Sobrien
36179407Sobrien#include "libcoff.h"
37179407Sobrien
38179407Sobrienstatic bfd_reloc_status_type coff_mips_reloc
39179407Sobrien  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
40179407Sobrienstatic reloc_howto_type *coff_mips_rtype_to_howto
41179407Sobrien  PARAMS ((bfd *, asection *, struct internal_reloc *,
42179407Sobrien	   struct coff_link_hash_entry *, struct internal_syment *,
43179407Sobrien	   bfd_vma *));
44179407Sobrien#if 0
45179407Sobrienstatic void mips_ecoff_swap_reloc_in
46179407Sobrien  PARAMS ((bfd *, PTR, struct internal_reloc *));
47179407Sobrienstatic void mips_ecoff_swap_reloc_out
48179407Sobrien  PARAMS ((bfd *, const struct internal_reloc *, PTR));
49179407Sobrienstatic void mips_adjust_reloc_in
50179407Sobrien  PARAMS ((bfd *, const struct internal_reloc *, arelent *));
51179407Sobrienstatic void mips_adjust_reloc_out
52179407Sobrien  PARAMS ((bfd *, const arelent *, struct internal_reloc *));
53179407Sobrien#endif
54179407Sobrien
55179407Sobrienstatic bfd_boolean in_reloc_p
56179407Sobrien  PARAMS ((bfd *, reloc_howto_type *));
57179407Sobrienstatic reloc_howto_type * coff_mips_reloc_type_lookup
58179407Sobrien  PARAMS ((bfd *, bfd_reloc_code_real_type));
59179407Sobrienstatic void mips_swap_reloc_in
60179407Sobrien  PARAMS ((bfd *, PTR, PTR));
61179407Sobrienstatic unsigned int mips_swap_reloc_out
62179407Sobrien  PARAMS ((bfd *, PTR, PTR));
63179407Sobrienstatic bfd_boolean coff_pe_mips_relocate_section
64179407Sobrien  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
65179407Sobrien	   struct internal_reloc *, struct internal_syment *, asection **));
66179407Sobrien
67179407Sobrien#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
68179407Sobrien/* The page size is a guess based on ELF.  */
69179407Sobrien
70179407Sobrien#define COFF_PAGE_SIZE 0x1000
71179407Sobrien
72179407Sobrien/* For some reason when using mips COFF the value stored in the .text
73179407Sobrien   section for a reference to a common symbol is the value itself plus
74179407Sobrien   any desired offset.  Ian Taylor, Cygnus Support.  */
75179407Sobrien
76179407Sobrien/* If we are producing relocatable output, we need to do some
77179407Sobrien   adjustments to the object file that are not done by the
78179407Sobrien   bfd_perform_relocation function.  This function is called by every
79179407Sobrien   reloc type to make any required adjustments.  */
80179407Sobrien
81179407Sobrienstatic bfd_reloc_status_type
82179407Sobriencoff_mips_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd,
83179407Sobrien		 error_message)
84179407Sobrien     bfd *abfd;
85179407Sobrien     arelent *reloc_entry;
86179407Sobrien     asymbol *symbol;
87179407Sobrien     PTR data;
88179407Sobrien     asection *input_section ATTRIBUTE_UNUSED;
89179407Sobrien     bfd *output_bfd;
90179407Sobrien     char **error_message ATTRIBUTE_UNUSED;
91179407Sobrien{
92179407Sobrien  symvalue diff;
93179407Sobrien
94179407Sobrien  if (output_bfd == (bfd *) NULL)
95179407Sobrien    return bfd_reloc_continue;
96179407Sobrien
97179407Sobrien  if (bfd_is_com_section (symbol->section))
98179407Sobrien    {
99179407Sobrien#ifndef COFF_WITH_PE
100179407Sobrien      /* We are relocating a common symbol.  The current value in the
101179407Sobrien	 object file is ORIG + OFFSET, where ORIG is the value of the
102179407Sobrien	 common symbol as seen by the object file when it was compiled
103179407Sobrien	 (this may be zero if the symbol was undefined) and OFFSET is
104179407Sobrien	 the offset into the common symbol (normally zero, but may be
105179407Sobrien	 non-zero when referring to a field in a common structure).
106179407Sobrien	 ORIG is the negative of reloc_entry->addend, which is set by
107179407Sobrien	 the CALC_ADDEND macro below.  We want to replace the value in
108179407Sobrien	 the object file with NEW + OFFSET, where NEW is the value of
109179407Sobrien	 the common symbol which we are going to put in the final
110179407Sobrien	 object file.  NEW is symbol->value.  */
111179407Sobrien      diff = symbol->value + reloc_entry->addend;
112179407Sobrien#else
113179407Sobrien      /* In PE mode, we do not offset the common symbol.  */
114179407Sobrien      diff = reloc_entry->addend;
115179407Sobrien#endif
116179407Sobrien    }
117179407Sobrien  else
118179407Sobrien    {
119179407Sobrien      /* For some reason bfd_perform_relocation always effectively
120179407Sobrien	 ignores the addend for a COFF target when producing
121179407Sobrien	 relocatable output.  This seems to be always wrong for 386
122179407Sobrien	 COFF, so we handle the addend here instead.  */
123179407Sobrien      diff = reloc_entry->addend;
124179407Sobrien    }
125179407Sobrien
126179407Sobrien#ifdef COFF_WITH_PE
127179407Sobrien#if 0
128179407Sobrien  /* dj - handle it like any other reloc? */
129179407Sobrien  /* FIXME: How should this case be handled?  */
130179407Sobrien  if (reloc_entry->howto->type == MIPS_R_RVA && diff != 0)
131179407Sobrien    abort ();
132179407Sobrien#endif
133179407Sobrien#endif
134179407Sobrien
135179407Sobrien#define DOIT(x) \
136179407Sobrien  x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + (diff >> howto->rightshift)) & howto->dst_mask))
137179407Sobrien
138179407Sobrien    if (diff != 0)
139179407Sobrien      {
140179407Sobrien	reloc_howto_type *howto = reloc_entry->howto;
141179407Sobrien	unsigned char *addr = (unsigned char *) data + reloc_entry->address;
142179407Sobrien
143179407Sobrien	switch (howto->size)
144179407Sobrien	  {
145179407Sobrien	  case 0:
146179407Sobrien	    {
147179407Sobrien	      char x = bfd_get_8 (abfd, addr);
148179407Sobrien	      DOIT (x);
149179407Sobrien	      bfd_put_8 (abfd, x, addr);
150179407Sobrien	    }
151179407Sobrien	    break;
152179407Sobrien
153179407Sobrien	  case 1:
154179407Sobrien	    {
155179407Sobrien	      short x = bfd_get_16 (abfd, addr);
156179407Sobrien	      DOIT (x);
157179407Sobrien	      bfd_put_16 (abfd, (bfd_vma) x, addr);
158179407Sobrien	    }
159179407Sobrien	    break;
160179407Sobrien
161179407Sobrien	  case 2:
162179407Sobrien	    {
163179407Sobrien	      long x = bfd_get_32 (abfd, addr);
164179407Sobrien	      DOIT (x);
165179407Sobrien	      bfd_put_32 (abfd, (bfd_vma) x, addr);
166179407Sobrien	    }
167179407Sobrien	    break;
168179407Sobrien
169179407Sobrien	  default:
170179407Sobrien	    abort ();
171179407Sobrien	  }
172179407Sobrien      }
173179407Sobrien
174179407Sobrien  /* Now let bfd_perform_relocation finish everything up.  */
175179407Sobrien  return bfd_reloc_continue;
176179407Sobrien}
177179407Sobrien
178179407Sobrien#ifdef COFF_WITH_PE
179179407Sobrien/* Return TRUE if this relocation should
180179407Sobrien   appear in the output .reloc section.  */
181179407Sobrien
182179407Sobrienstatic bfd_boolean
183179407Sobrienin_reloc_p (abfd, howto)
184179407Sobrien     bfd * abfd ATTRIBUTE_UNUSED;
185179407Sobrien     reloc_howto_type *howto;
186179407Sobrien{
187179407Sobrien  return ! howto->pc_relative && howto->type != MIPS_R_RVA;
188179407Sobrien}
189179407Sobrien#endif
190179407Sobrien
191179407Sobrien#ifndef PCRELOFFSET
192179407Sobrien#define PCRELOFFSET FALSE
193179407Sobrien#endif
194179407Sobrien
195179407Sobrienstatic reloc_howto_type howto_table[] =
196179407Sobrien{
197179407Sobrien  /* Reloc type 0 is ignored.  The reloc reading code ensures that
198179407Sobrien     this is a reference to the .abs section, which will cause
199179407Sobrien     bfd_perform_relocation to do nothing.  */
200179407Sobrien  HOWTO (MIPS_R_ABSOLUTE,	/* type */
201179407Sobrien	 0,			/* rightshift */
202179407Sobrien	 0,			/* size (0 = byte, 1 = short, 2 = long) */
203179407Sobrien	 8,			/* bitsize */
204179407Sobrien	 FALSE,			/* pc_relative */
205179407Sobrien	 0,			/* bitpos */
206179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
207179407Sobrien	 0,			/* special_function */
208179407Sobrien	 "IGNORE",		/* name */
209179407Sobrien	 FALSE,			/* partial_inplace */
210179407Sobrien	 0,			/* src_mask */
211179407Sobrien	 0,			/* dst_mask */
212179407Sobrien	 FALSE),		/* pcrel_offset */
213179407Sobrien
214179407Sobrien  /* A 16 bit reference to a symbol, normally from a data section.  */
215179407Sobrien  HOWTO (MIPS_R_REFHALF,	/* type */
216179407Sobrien	 0,			/* rightshift */
217179407Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
218179407Sobrien	 16,			/* bitsize */
219179407Sobrien	 FALSE,			/* pc_relative */
220179407Sobrien	 0,			/* bitpos */
221179407Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
222179407Sobrien	 coff_mips_reloc,	/* special_function */
223179407Sobrien	 "REFHALF",		/* name */
224179407Sobrien	 TRUE,			/* partial_inplace */
225179407Sobrien	 0xffff,		/* src_mask */
226179407Sobrien	 0xffff,		/* dst_mask */
227179407Sobrien	 FALSE),		/* pcrel_offset */
228179407Sobrien
229179407Sobrien  /* A 32 bit reference to a symbol, normally from a data section.  */
230179407Sobrien  HOWTO (MIPS_R_REFWORD,	/* type */
231179407Sobrien	 0,			/* rightshift */
232179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
233179407Sobrien	 32,			/* bitsize */
234179407Sobrien	 FALSE,			/* pc_relative */
235179407Sobrien	 0,			/* bitpos */
236179407Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
237179407Sobrien	 coff_mips_reloc,	/* special_function */
238179407Sobrien	 "REFWORD",		/* name */
239179407Sobrien	 TRUE,			/* partial_inplace */
240179407Sobrien	 0xffffffff,		/* src_mask */
241179407Sobrien	 0xffffffff,		/* dst_mask */
242179407Sobrien	 FALSE),		/* pcrel_offset */
243179407Sobrien
244179407Sobrien  /* A 26 bit absolute jump address.  */
245179407Sobrien  HOWTO (MIPS_R_JMPADDR,	/* type */
246179407Sobrien	 2,			/* rightshift */
247179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
248179407Sobrien	 26,			/* bitsize */
249179407Sobrien	 FALSE,			/* pc_relative */
250179407Sobrien	 0,			/* bitpos */
251179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
252179407Sobrien	 			/* This needs complex overflow
253179407Sobrien				   detection, because the upper four
254179407Sobrien				   bits must match the PC.  */
255179407Sobrien	 coff_mips_reloc,	/* special_function */
256179407Sobrien	 "JMPADDR",		/* name */
257179407Sobrien	 TRUE,			/* partial_inplace */
258179407Sobrien	 0x3ffffff,		/* src_mask */
259179407Sobrien	 0x3ffffff,		/* dst_mask */
260179407Sobrien	 FALSE),		/* pcrel_offset */
261179407Sobrien
262179407Sobrien  /* The high 16 bits of a symbol value.  Handled by the function
263179407Sobrien     mips_refhi_reloc.  */
264179407Sobrien  HOWTO (MIPS_R_REFHI,		/* type */
265179407Sobrien	 16,			/* rightshift */
266179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
267179407Sobrien	 16,			/* bitsize */
268179407Sobrien	 FALSE,			/* pc_relative */
269179407Sobrien	 0,			/* bitpos */
270179407Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
271179407Sobrien	 coff_mips_reloc,	/* special_function */
272179407Sobrien	 "REFHI",		/* name */
273179407Sobrien	 TRUE,			/* partial_inplace */
274179407Sobrien	 0xffff,		/* src_mask */
275179407Sobrien	 0xffff,		/* dst_mask */
276179407Sobrien	 FALSE),		/* pcrel_offset */
277179407Sobrien
278179407Sobrien  /* The low 16 bits of a symbol value.  */
279179407Sobrien  HOWTO (MIPS_R_REFLO,		/* type */
280179407Sobrien	 0,			/* rightshift */
281179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
282179407Sobrien	 16,			/* bitsize */
283179407Sobrien	 FALSE,			/* pc_relative */
284179407Sobrien	 0,			/* bitpos */
285179407Sobrien	 complain_overflow_dont, /* complain_on_overflow */
286179407Sobrien	 coff_mips_reloc,	/* special_function */
287179407Sobrien	 "REFLO",		/* name */
288179407Sobrien	 TRUE,			/* partial_inplace */
289179407Sobrien	 0xffff,		/* src_mask */
290179407Sobrien	 0xffff,		/* dst_mask */
291179407Sobrien	 FALSE),		/* pcrel_offset */
292179407Sobrien
293179407Sobrien  /* A reference to an offset from the gp register.  Handled by the
294179407Sobrien     function mips_gprel_reloc.  */
295179407Sobrien  HOWTO (MIPS_R_GPREL,		/* type */
296179407Sobrien	 0,			/* rightshift */
297179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
298179407Sobrien	 16,			/* bitsize */
299179407Sobrien	 FALSE,			/* pc_relative */
300179407Sobrien	 0,			/* bitpos */
301179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
302179407Sobrien	 coff_mips_reloc,	/* special_function */
303179407Sobrien	 "GPREL",		/* name */
304179407Sobrien	 TRUE,			/* partial_inplace */
305179407Sobrien	 0xffff,		/* src_mask */
306179407Sobrien	 0xffff,		/* dst_mask */
307179407Sobrien	 FALSE),		/* pcrel_offset */
308179407Sobrien
309179407Sobrien  /* A reference to a literal using an offset from the gp register.
310179407Sobrien     Handled by the function mips_gprel_reloc.  */
311179407Sobrien  HOWTO (MIPS_R_LITERAL,	/* type */
312179407Sobrien	 0,			/* rightshift */
313179407Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
314179407Sobrien	 16,			/* bitsize */
315179407Sobrien	 FALSE,			/* pc_relative */
316179407Sobrien	 0,			/* bitpos */
317179407Sobrien	 complain_overflow_signed, /* complain_on_overflow */
318179407Sobrien	 coff_mips_reloc,	/* special_function */
319179407Sobrien	 "LITERAL",		/* name */
320179407Sobrien	 TRUE,			/* partial_inplace */
321179407Sobrien	 0xffff,		/* src_mask */
322179407Sobrien	 0xffff,		/* dst_mask */
323179407Sobrien	 FALSE),		/* pcrel_offset */
324179407Sobrien
325179407Sobrien  EMPTY_HOWTO (8),
326179407Sobrien  EMPTY_HOWTO (9),
327179407Sobrien  EMPTY_HOWTO (10),
328179407Sobrien  EMPTY_HOWTO (11),
329179407Sobrien  EMPTY_HOWTO (12),
330179407Sobrien  EMPTY_HOWTO (13),
331179407Sobrien  EMPTY_HOWTO (14),
332179407Sobrien  EMPTY_HOWTO (15),
333179407Sobrien  EMPTY_HOWTO (16),
334179407Sobrien  EMPTY_HOWTO (17),
335179407Sobrien  EMPTY_HOWTO (18),
336179407Sobrien  EMPTY_HOWTO (19),
337179407Sobrien  EMPTY_HOWTO (20),
338179407Sobrien  EMPTY_HOWTO (21),
339179407Sobrien  EMPTY_HOWTO (22),
340179407Sobrien  EMPTY_HOWTO (23),
341179407Sobrien  EMPTY_HOWTO (24),
342179407Sobrien  EMPTY_HOWTO (25),
343179407Sobrien  EMPTY_HOWTO (26),
344179407Sobrien  EMPTY_HOWTO (27),
345179407Sobrien  EMPTY_HOWTO (28),
346179407Sobrien  EMPTY_HOWTO (29),
347179407Sobrien  EMPTY_HOWTO (30),
348179407Sobrien  EMPTY_HOWTO (31),
349179407Sobrien  EMPTY_HOWTO (32),
350179407Sobrien  EMPTY_HOWTO (33),
351179407Sobrien  HOWTO (MIPS_R_RVA,            /* type */
352179407Sobrien	 0,	                /* rightshift */
353179407Sobrien	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
354179407Sobrien	 32,	                /* bitsize */
355179407Sobrien	 FALSE,	                /* pc_relative */
356179407Sobrien	 0,	                /* bitpos */
357179407Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
358179407Sobrien	 coff_mips_reloc,       /* special_function */
359179407Sobrien	 "rva32",	        /* name */
360179407Sobrien	 TRUE,	                /* partial_inplace */
361179407Sobrien	 0xffffffff,            /* src_mask */
362179407Sobrien	 0xffffffff,            /* dst_mask */
363179407Sobrien	 FALSE),                /* pcrel_offset */
364179407Sobrien  EMPTY_HOWTO (35),
365179407Sobrien  EMPTY_HOWTO (36),
366179407Sobrien  HOWTO (MIPS_R_PAIR,           /* type */
367179407Sobrien	 0,	                /* rightshift */
368179407Sobrien	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
369179407Sobrien	 32,	                /* bitsize */
370179407Sobrien	 FALSE,	                /* pc_relative */
371179407Sobrien	 0,	                /* bitpos */
372179407Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
373179407Sobrien	 coff_mips_reloc,       /* special_function */
374179407Sobrien	 "PAIR",	        /* name */
375179407Sobrien	 TRUE,	                /* partial_inplace */
376179407Sobrien	 0xffffffff,            /* src_mask */
377179407Sobrien	 0xffffffff,            /* dst_mask */
378179407Sobrien	 FALSE),                /* pcrel_offset */
379179407Sobrien};
380179407Sobrien
381179407Sobrien/* Turn a howto into a reloc  nunmber */
382179407Sobrien
383179407Sobrien#define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
384179407Sobrien#define BADMAG(x) MIPSBADMAG(x)
385179407Sobrien#define MIPS 1			/* Customize coffcode.h */
386179407Sobrien
387179407Sobrien#define RTYPE2HOWTO(cache_ptr, dst) \
388179407Sobrien	    (cache_ptr)->howto = howto_table + (dst)->r_type;
389179407Sobrien
390179407Sobrien/* Compute the addend of a reloc.  If the reloc is to a common symbol,
391179407Sobrien   the object file contains the value of the common symbol.  By the
392179407Sobrien   time this is called, the linker may be using a different symbol
393179407Sobrien   from a different object file with a different value.  Therefore, we
394179407Sobrien   hack wildly to locate the original symbol from this file so that we
395179407Sobrien   can make the correct adjustment.  This macro sets coffsym to the
396179407Sobrien   symbol from the original file, and uses it to set the addend value
397179407Sobrien   correctly.  If this is not a common symbol, the usual addend
398179407Sobrien   calculation is done, except that an additional tweak is needed for
399179407Sobrien   PC relative relocs.
400179407Sobrien   FIXME: This macro refers to symbols and asect; these are from the
401179407Sobrien   calling function, not the macro arguments.  */
402179407Sobrien
403179407Sobrien#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr)		\
404179407Sobrien  {								\
405179407Sobrien    coff_symbol_type *coffsym = (coff_symbol_type *) NULL;	\
406179407Sobrien    if (ptr && bfd_asymbol_bfd (ptr) != abfd)			\
407179407Sobrien      coffsym = (obj_symbols (abfd)				\
408179407Sobrien	         + (cache_ptr->sym_ptr_ptr - symbols));		\
409179407Sobrien    else if (ptr)						\
410179407Sobrien      coffsym = coff_symbol_from (abfd, ptr);			\
411179407Sobrien    if (coffsym != (coff_symbol_type *) NULL			\
412179407Sobrien	&& coffsym->native->u.syment.n_scnum == 0)		\
413179407Sobrien      cache_ptr->addend = - coffsym->native->u.syment.n_value;	\
414179407Sobrien    else if (ptr && bfd_asymbol_bfd (ptr) == abfd		\
415179407Sobrien	     && ptr->section != (asection *) NULL)		\
416179407Sobrien      cache_ptr->addend = - (ptr->section->vma + ptr->value);	\
417179407Sobrien    else							\
418179407Sobrien      cache_ptr->addend = 0;					\
419179407Sobrien    if (ptr && howto_table[reloc.r_type].pc_relative)		\
420179407Sobrien      cache_ptr->addend += asect->vma;				\
421179407Sobrien  }
422179407Sobrien
423179407Sobrien/* Convert an rtype to howto for the COFF backend linker.  */
424179407Sobrien
425179407Sobrienstatic reloc_howto_type *
426179407Sobriencoff_mips_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
427179407Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
428179407Sobrien     asection *sec;
429179407Sobrien     struct internal_reloc *rel;
430179407Sobrien     struct coff_link_hash_entry *h;
431179407Sobrien     struct internal_syment *sym;
432179407Sobrien     bfd_vma *addendp;
433179407Sobrien{
434179407Sobrien
435179407Sobrien  reloc_howto_type *howto;
436179407Sobrien
437179407Sobrien  howto = howto_table + rel->r_type;
438179407Sobrien
439179407Sobrien#ifdef COFF_WITH_PE
440179407Sobrien  *addendp = 0;
441179407Sobrien#endif
442179407Sobrien
443179407Sobrien  if (howto->pc_relative)
444179407Sobrien    *addendp += sec->vma;
445179407Sobrien
446179407Sobrien  if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0)
447179407Sobrien    {
448179407Sobrien      /* This is a common symbol.  The section contents include the
449179407Sobrien	 size (sym->n_value) as an addend.  The relocate_section
450179407Sobrien	 function will be adding in the final value of the symbol.  We
451179407Sobrien	 need to subtract out the current size in order to get the
452179407Sobrien	 correct result.  */
453179407Sobrien
454179407Sobrien      BFD_ASSERT (h != NULL);
455179407Sobrien
456179407Sobrien#ifndef COFF_WITH_PE
457179407Sobrien      /* I think we *do* want to bypass this.  If we don't, I have
458179407Sobrien	 seen some data parameters get the wrong relocation address.
459179407Sobrien	 If I link two versions with and without this section bypassed
460179407Sobrien	 and then do a binary comparison, the addresses which are
461179407Sobrien	 different can be looked up in the map.  The case in which
462179407Sobrien	 this section has been bypassed has addresses which correspond
463179407Sobrien	 to values I can find in the map.  */
464179407Sobrien      *addendp -= sym->n_value;
465179407Sobrien#endif
466179407Sobrien    }
467179407Sobrien
468179407Sobrien#ifndef COFF_WITH_PE
469179407Sobrien  /* If the output symbol is common (in which case this must be a
470179407Sobrien     relocatable link), we need to add in the final size of the
471179407Sobrien     common symbol.  */
472179407Sobrien  if (h != NULL && h->root.type == bfd_link_hash_common)
473179407Sobrien    *addendp += h->root.u.c.size;
474179407Sobrien#endif
475179407Sobrien
476179407Sobrien#ifdef COFF_WITH_PE
477179407Sobrien  if (howto->pc_relative)
478179407Sobrien    {
479179407Sobrien      *addendp -= 4;
480179407Sobrien
481179407Sobrien      /* If the symbol is defined, then the generic code is going to
482179407Sobrien         add back the symbol value in order to cancel out an
483179407Sobrien         adjustment it made to the addend.  However, we set the addend
484179407Sobrien         to 0 at the start of this function.  We need to adjust here,
485179407Sobrien         to avoid the adjustment the generic code will make.  FIXME:
486179407Sobrien         This is getting a bit hackish.  */
487179407Sobrien      if (sym != NULL && sym->n_scnum != 0)
488179407Sobrien	*addendp -= sym->n_value;
489179407Sobrien    }
490179407Sobrien
491179407Sobrien  if (rel->r_type == MIPS_R_RVA)
492179407Sobrien    {
493179407Sobrien      *addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase;
494179407Sobrien    }
495179407Sobrien#endif
496179407Sobrien
497179407Sobrien  return howto;
498179407Sobrien}
499179407Sobrien
500179407Sobrien#define coff_rtype_to_howto coff_mips_rtype_to_howto
501179407Sobrien
502179407Sobrien#define coff_bfd_reloc_type_lookup coff_mips_reloc_type_lookup
503179407Sobrien
504179407Sobrien/* Get the howto structure for a generic reloc type.  */
505179407Sobrien
506179407Sobrienstatic reloc_howto_type *
507179407Sobriencoff_mips_reloc_type_lookup (abfd, code)
508179407Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
509179407Sobrien     bfd_reloc_code_real_type code;
510179407Sobrien{
511179407Sobrien  int mips_type;
512179407Sobrien
513179407Sobrien  switch (code)
514179407Sobrien    {
515179407Sobrien    case BFD_RELOC_16:
516179407Sobrien      mips_type = MIPS_R_REFHALF;
517179407Sobrien      break;
518179407Sobrien    case BFD_RELOC_32:
519179407Sobrien    case BFD_RELOC_CTOR:
520179407Sobrien      mips_type = MIPS_R_REFWORD;
521179407Sobrien      break;
522179407Sobrien    case BFD_RELOC_MIPS_JMP:
523179407Sobrien      mips_type = MIPS_R_JMPADDR;
524179407Sobrien      break;
525179407Sobrien    case BFD_RELOC_HI16_S:
526179407Sobrien      mips_type = MIPS_R_REFHI;
527179407Sobrien      break;
528179407Sobrien    case BFD_RELOC_LO16:
529179407Sobrien      mips_type = MIPS_R_REFLO;
530179407Sobrien      break;
531179407Sobrien    case BFD_RELOC_GPREL16:
532179407Sobrien      mips_type = MIPS_R_GPREL;
533179407Sobrien      break;
534179407Sobrien    case BFD_RELOC_MIPS_LITERAL:
535179407Sobrien      mips_type = MIPS_R_LITERAL;
536179407Sobrien      break;
537179407Sobrien/* FIXME?
538179407Sobrien    case BFD_RELOC_16_PCREL_S2:
539179407Sobrien      mips_type = MIPS_R_PCREL16;
540179407Sobrien      break;
541179407Sobrien    case BFD_RELOC_PCREL_HI16_S:
542179407Sobrien      mips_type = MIPS_R_RELHI;
543179407Sobrien      break;
544179407Sobrien    case BFD_RELOC_PCREL_LO16:
545179407Sobrien      mips_type = MIPS_R_RELLO;
546179407Sobrien      break;
547179407Sobrien    case BFD_RELOC_GPREL32:
548179407Sobrien      mips_type = MIPS_R_SWITCH;
549179407Sobrien      break;
550179407Sobrien*/
551179407Sobrien    case BFD_RELOC_RVA:
552179407Sobrien      mips_type = MIPS_R_RVA;
553179407Sobrien      break;
554179407Sobrien    default:
555179407Sobrien      return (reloc_howto_type *) NULL;
556179407Sobrien    }
557179407Sobrien
558179407Sobrien  return &howto_table[mips_type];
559179407Sobrien}
560179407Sobrien
561179407Sobrienstatic void
562179407Sobrienmips_swap_reloc_in (abfd, src, dst)
563179407Sobrien     bfd *abfd;
564179407Sobrien     PTR src;
565179407Sobrien     PTR dst;
566179407Sobrien{
567179407Sobrien  static struct internal_reloc pair_prev;
568179407Sobrien  RELOC *reloc_src = (RELOC *) src;
569179407Sobrien  struct internal_reloc *reloc_dst = (struct internal_reloc *) dst;
570179407Sobrien
571179407Sobrien  reloc_dst->r_vaddr = H_GET_32 (abfd, reloc_src->r_vaddr);
572179407Sobrien  reloc_dst->r_symndx = H_GET_S32 (abfd, reloc_src->r_symndx);
573179407Sobrien  reloc_dst->r_type = H_GET_16 (abfd, reloc_src->r_type);
574179407Sobrien  reloc_dst->r_size = 0;
575179407Sobrien  reloc_dst->r_extern = 0;
576179407Sobrien  reloc_dst->r_offset = 0;
577179407Sobrien
578179407Sobrien  switch (reloc_dst->r_type)
579179407Sobrien  {
580179407Sobrien  case MIPS_R_REFHI:
581179407Sobrien    pair_prev = *reloc_dst;
582179407Sobrien    break;
583179407Sobrien  case MIPS_R_PAIR:
584179407Sobrien    reloc_dst->r_offset = reloc_dst->r_symndx;
585179407Sobrien    if (reloc_dst->r_offset & 0x8000)
586179407Sobrien      reloc_dst->r_offset -= 0x10000;
587179407Sobrien    /*printf ("dj: pair offset is %08x\n", reloc_dst->r_offset);*/
588179407Sobrien    reloc_dst->r_symndx = pair_prev.r_symndx;
589179407Sobrien    break;
590179407Sobrien  }
591179407Sobrien}
592179407Sobrien
593179407Sobrienstatic unsigned int
594179407Sobrienmips_swap_reloc_out (abfd, src, dst)
595179407Sobrien     bfd       *abfd;
596179407Sobrien     PTR	src;
597179407Sobrien     PTR	dst;
598179407Sobrien{
599179407Sobrien  static int prev_offset = 1;
600179407Sobrien  static bfd_vma prev_addr = 0;
601179407Sobrien  struct internal_reloc *reloc_src = (struct internal_reloc *)src;
602179407Sobrien  struct external_reloc *reloc_dst = (struct external_reloc *)dst;
603179407Sobrien
604179407Sobrien  switch (reloc_src->r_type)
605179407Sobrien    {
606179407Sobrien    case MIPS_R_REFHI:
607179407Sobrien      prev_addr = reloc_src->r_vaddr;
608179407Sobrien      prev_offset = reloc_src->r_offset;
609179407Sobrien      break;
610179407Sobrien    case MIPS_R_REFLO:
611179407Sobrien      if (reloc_src->r_vaddr == prev_addr)
612179407Sobrien	{
613179407Sobrien	  /* FIXME: only slightly hackish.  If we see a REFLO pointing to
614179407Sobrien	     the same address as a REFHI, we assume this is the matching
615179407Sobrien	     PAIR reloc and output it accordingly.  The symndx is really
616179407Sobrien	     the low 16 bits of the addend */
617179407Sobrien	  H_PUT_32 (abfd, reloc_src->r_vaddr, reloc_dst->r_vaddr);
618179407Sobrien	  H_PUT_32 (abfd, reloc_src->r_symndx, reloc_dst->r_symndx);
619179407Sobrien	  H_PUT_16 (abfd, MIPS_R_PAIR, reloc_dst->r_type);
620179407Sobrien	  return RELSZ;
621179407Sobrien	}
622179407Sobrien      break;
623179407Sobrien    }
624179407Sobrien
625179407Sobrien  H_PUT_32 (abfd, reloc_src->r_vaddr, reloc_dst->r_vaddr);
626179407Sobrien  H_PUT_32 (abfd, reloc_src->r_symndx, reloc_dst->r_symndx);
627179407Sobrien
628179407Sobrien  H_PUT_16 (abfd, reloc_src->r_type, reloc_dst->r_type);
629179407Sobrien  return RELSZ;
630179407Sobrien}
631179407Sobrien
632179407Sobrien#define coff_swap_reloc_in mips_swap_reloc_in
633179407Sobrien#define coff_swap_reloc_out mips_swap_reloc_out
634179407Sobrien#define NO_COFF_RELOCS
635179407Sobrien
636179407Sobrienstatic bfd_boolean
637179407Sobriencoff_pe_mips_relocate_section (output_bfd, info, input_bfd,
638179407Sobrien			       input_section, contents, relocs, syms,
639179407Sobrien			       sections)
640179407Sobrien     bfd *output_bfd;
641179407Sobrien     struct bfd_link_info *info;
642179407Sobrien     bfd *input_bfd;
643179407Sobrien     asection *input_section;
644179407Sobrien     bfd_byte *contents;
645179407Sobrien     struct internal_reloc *relocs;
646179407Sobrien     struct internal_syment *syms;
647179407Sobrien     asection **sections;
648179407Sobrien{
649179407Sobrien  bfd_vma gp;
650179407Sobrien  bfd_boolean gp_undefined;
651179407Sobrien  size_t adjust;
652179407Sobrien  struct internal_reloc *rel;
653179407Sobrien  struct internal_reloc *rel_end;
654179407Sobrien  unsigned int i;
655179407Sobrien  bfd_boolean got_lo;
656179407Sobrien
657179407Sobrien  if (info->relocatable)
658179407Sobrien  {
659179407Sobrien    (*_bfd_error_handler) (_("\
660179407Sobrien%s: `ld -r' not supported with PE MIPS objects\n"),
661179407Sobrien			   bfd_archive_filename (input_bfd));
662179407Sobrien    bfd_set_error (bfd_error_bad_value);
663179407Sobrien    return FALSE;
664179407Sobrien  }
665179407Sobrien
666179407Sobrien  BFD_ASSERT (input_bfd->xvec->byteorder
667179407Sobrien	      == output_bfd->xvec->byteorder);
668179407Sobrien
669179407Sobrien#if 0
670179407Sobrien  printf ("dj: relocate %s(%s) %08x\n",
671179407Sobrien	 input_bfd->filename, input_section->name,
672179407Sobrien	 input_section->output_section->vma + input_section->output_offset);
673179407Sobrien#endif
674179407Sobrien
675179407Sobrien  gp = _bfd_get_gp_value (output_bfd);
676179407Sobrien  if (gp == 0)
677179407Sobrien    gp_undefined = TRUE;
678179407Sobrien  else
679179407Sobrien    gp_undefined = FALSE;
680179407Sobrien
681179407Sobrien  got_lo = FALSE;
682179407Sobrien
683179407Sobrien  adjust = 0;
684179407Sobrien
685179407Sobrien  rel = relocs;
686179407Sobrien  rel_end = rel + input_section->reloc_count;
687179407Sobrien  for (i = 0; rel < rel_end; rel++, i++)
688179407Sobrien    {
689179407Sobrien      long symndx;
690179407Sobrien      struct coff_link_hash_entry *h;
691179407Sobrien      struct internal_syment *sym;
692179407Sobrien      bfd_vma addend = 0;
693179407Sobrien      bfd_vma val, tmp, targ, src, low;
694179407Sobrien      reloc_howto_type *howto;
695179407Sobrien      unsigned char *mem = contents + rel->r_vaddr;
696179407Sobrien
697179407Sobrien      symndx = rel->r_symndx;
698179407Sobrien
699179407Sobrien      if (symndx == -1)
700179407Sobrien	{
701179407Sobrien	  h = NULL;
702179407Sobrien	  sym = NULL;
703179407Sobrien	}
704179407Sobrien      else
705179407Sobrien	{
706179407Sobrien	  h = obj_coff_sym_hashes (input_bfd)[symndx];
707179407Sobrien	  sym = syms + symndx;
708179407Sobrien	}
709179407Sobrien
710179407Sobrien      /* COFF treats common symbols in one of two ways.  Either the
711179407Sobrien         size of the symbol is included in the section contents, or it
712179407Sobrien         is not.  We assume that the size is not included, and force
713179407Sobrien         the rtype_to_howto function to adjust the addend as needed.  */
714179407Sobrien
715179407Sobrien      if (sym != NULL && sym->n_scnum != 0)
716179407Sobrien	addend = - sym->n_value;
717179407Sobrien      else
718179407Sobrien	addend = 0;
719179407Sobrien
720179407Sobrien      howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
721179407Sobrien				       sym, &addend);
722179407Sobrien      if (howto == NULL)
723179407Sobrien	return FALSE;
724179407Sobrien
725179407Sobrien      /* If we are doing a relocatable link, then we can just ignore
726179407Sobrien         a PC relative reloc that is pcrel_offset.  It will already
727179407Sobrien         have the correct value.  If this is not a relocatable link,
728179407Sobrien         then we should ignore the symbol value.  */
729179407Sobrien      if (howto->pc_relative && howto->pcrel_offset)
730179407Sobrien	{
731179407Sobrien	  if (info->relocatable)
732179407Sobrien	    continue;
733179407Sobrien	  if (sym != NULL && sym->n_scnum != 0)
734179407Sobrien	    addend += sym->n_value;
735179407Sobrien	}
736179407Sobrien
737179407Sobrien      val = 0;
738179407Sobrien
739179407Sobrien      if (h == NULL)
740179407Sobrien	{
741179407Sobrien	  asection *sec;
742179407Sobrien
743179407Sobrien	  if (symndx == -1)
744179407Sobrien	    {
745179407Sobrien	      sec = bfd_abs_section_ptr;
746179407Sobrien	      val = 0;
747179407Sobrien	    }
748179407Sobrien	  else
749179407Sobrien	    {
750179407Sobrien	      sec = sections[symndx];
751179407Sobrien              val = (sec->output_section->vma
752179407Sobrien		     + sec->output_offset
753179407Sobrien		     + sym->n_value);
754179407Sobrien	      if (! obj_pe (input_bfd))
755179407Sobrien		val -= sec->vma;
756179407Sobrien	    }
757179407Sobrien	}
758179407Sobrien      else
759179407Sobrien	{
760179407Sobrien	  if (h->root.type == bfd_link_hash_defined
761179407Sobrien	      || h->root.type == bfd_link_hash_defweak)
762179407Sobrien	    {
763179407Sobrien	      asection *sec;
764179407Sobrien
765179407Sobrien	      sec = h->root.u.def.section;
766179407Sobrien	      val = (h->root.u.def.value
767179407Sobrien		     + sec->output_section->vma
768179407Sobrien		     + sec->output_offset);
769179407Sobrien	      }
770179407Sobrien
771179407Sobrien	  else if (! info->relocatable)
772179407Sobrien	    {
773179407Sobrien	      if (! ((*info->callbacks->undefined_symbol)
774179407Sobrien		     (info, h->root.root.string, input_bfd, input_section,
775179407Sobrien		      rel->r_vaddr - input_section->vma, TRUE)))
776179407Sobrien		return FALSE;
777179407Sobrien	    }
778179407Sobrien	}
779179407Sobrien
780179407Sobrien      src = rel->r_vaddr + input_section->output_section->vma
781179407Sobrien	+ input_section->output_offset;
782179407Sobrien#if 0
783179407Sobrien      printf ("dj: reloc %02x %-8s a=%08x/%08x(%08x) v=%08x+%08x %s\n",
784179407Sobrien	     rel->r_type, howto_table[rel->r_type].name,
785179407Sobrien	     src, rel->r_vaddr, *(unsigned long *)mem, val, rel->r_offset,
786179407Sobrien	     h?h->root.root.string:"(none)");
787179407Sobrien#endif
788179407Sobrien
789179407Sobrien      /* OK, at this point the following variables are set up:
790179407Sobrien	   src = VMA of the memory we're fixing up
791179407Sobrien	   mem = pointer to memory we're fixing up
792179407Sobrien	   val = VMA of what we need to refer to
793179407Sobrien      */
794179407Sobrien
795179407Sobrien#define UI(x) (*_bfd_error_handler) (_("%s: unimplemented %s\n"), \
796179407Sobrien				     bfd_archive_filename (input_bfd), x); \
797179407Sobrien	      bfd_set_error (bfd_error_bad_value);
798179407Sobrien
799179407Sobrien      switch (rel->r_type)
800179407Sobrien	{
801179407Sobrien	case MIPS_R_ABSOLUTE:
802179407Sobrien	  /* ignore these */
803179407Sobrien	  break;
804179407Sobrien
805179407Sobrien	case MIPS_R_REFHALF:
806179407Sobrien	  UI("refhalf");
807179407Sobrien	  break;
808179407Sobrien
809179407Sobrien	case MIPS_R_REFWORD:
810179407Sobrien	  tmp = bfd_get_32(input_bfd, mem);
811179407Sobrien	  /* printf ("refword: src=%08x targ=%08x+%08x\n", src, tmp, val); */
812179407Sobrien	  tmp += val;
813179407Sobrien	  bfd_put_32(input_bfd, tmp, mem);
814179407Sobrien	  break;
815179407Sobrien
816179407Sobrien	case MIPS_R_JMPADDR:
817179407Sobrien	  tmp = bfd_get_32(input_bfd, mem);
818179407Sobrien	  targ = val + (tmp&0x03ffffff)*4;
819179407Sobrien	  if ((src & 0xf0000000) != (targ & 0xf0000000))
820179407Sobrien	    {
821179407Sobrien	      (*_bfd_error_handler) (_("%s: jump too far away\n"),
822179407Sobrien				     bfd_archive_filename (input_bfd));
823179407Sobrien	      bfd_set_error (bfd_error_bad_value);
824179407Sobrien	      return FALSE;
825179407Sobrien	    }
826179407Sobrien	  tmp &= 0xfc000000;
827179407Sobrien	  tmp |= (targ/4) & 0x3ffffff;
828179407Sobrien	  bfd_put_32(input_bfd, tmp, mem);
829179407Sobrien	  break;
830179407Sobrien
831179407Sobrien	case MIPS_R_REFHI:
832179407Sobrien	  tmp = bfd_get_32(input_bfd, mem);
833179407Sobrien	  switch (rel[1].r_type)
834179407Sobrien	    {
835179407Sobrien	    case MIPS_R_PAIR:
836179407Sobrien	      /* MS PE object */
837179407Sobrien	      targ = val + rel[1].r_offset + ((tmp & 0xffff) << 16);
838179407Sobrien	      break;
839179407Sobrien	    case MIPS_R_REFLO:
840179407Sobrien	      /* GNU COFF object */
841179407Sobrien	      low = bfd_get_32(input_bfd, contents + rel[1].r_vaddr);
842179407Sobrien	      low &= 0xffff;
843179407Sobrien	      if (low & 0x8000)
844179407Sobrien		low -= 0x10000;
845179407Sobrien	      targ = val + low + ((tmp & 0xffff) << 16);
846179407Sobrien	      break;
847179407Sobrien	    default:
848179407Sobrien	      (*_bfd_error_handler) (_("%s: bad pair/reflo after refhi\n"),
849179407Sobrien				     bfd_archive_filename (input_bfd));
850179407Sobrien	      bfd_set_error (bfd_error_bad_value);
851179407Sobrien	      return FALSE;
852179407Sobrien	    }
853179407Sobrien	  tmp &= 0xffff0000;
854179407Sobrien	  tmp |= (targ >> 16) & 0xffff;
855179407Sobrien	  bfd_put_32(input_bfd, tmp, mem);
856179407Sobrien	  break;
857179407Sobrien
858179407Sobrien	case MIPS_R_REFLO:
859179407Sobrien	  tmp = bfd_get_32(input_bfd, mem);
860179407Sobrien	  targ = val + (tmp & 0xffff);
861179407Sobrien	  /* printf ("refword: src=%08x targ=%08x\n", src, targ); */
862179407Sobrien	  tmp &= 0xffff0000;
863179407Sobrien	  tmp |= targ & 0xffff;
864179407Sobrien	  bfd_put_32(input_bfd, tmp, mem);
865179407Sobrien	  break;
866179407Sobrien
867179407Sobrien	case MIPS_R_GPREL:
868179407Sobrien	case MIPS_R_LITERAL:
869179407Sobrien	  UI("gprel");
870179407Sobrien	  break;
871179407Sobrien
872179407Sobrien	case MIPS_R_SECTION:
873179407Sobrien	  UI("section");
874179407Sobrien	  break;
875179407Sobrien
876179407Sobrien	case MIPS_R_SECREL:
877179407Sobrien	  UI("secrel");
878179407Sobrien	  break;
879179407Sobrien
880179407Sobrien	case MIPS_R_SECRELLO:
881179407Sobrien	  UI("secrello");
882179407Sobrien	  break;
883179407Sobrien
884179407Sobrien	case MIPS_R_SECRELHI:
885179407Sobrien	  UI("secrelhi");
886179407Sobrien	  break;
887179407Sobrien
888179407Sobrien	case MIPS_R_RVA:
889179407Sobrien	  tmp = bfd_get_32 (input_bfd, mem);
890179407Sobrien	  /* printf ("rva: src=%08x targ=%08x+%08x\n", src, tmp, val); */
891179407Sobrien	  tmp += val
892179407Sobrien	    - pe_data (input_section->output_section->owner)->pe_opthdr.ImageBase;
893179407Sobrien	  bfd_put_32 (input_bfd, tmp, mem);
894179407Sobrien	  break;
895179407Sobrien
896179407Sobrien	case MIPS_R_PAIR:
897179407Sobrien	  /* ignore these */
898179407Sobrien	  break;
899179407Sobrien	}
900179407Sobrien    }
901179407Sobrien
902179407Sobrien  return TRUE;
903179407Sobrien}
904179407Sobrien
905179407Sobrien#define coff_relocate_section coff_pe_mips_relocate_section
906179407Sobrien
907179407Sobrien#ifdef TARGET_UNDERSCORE
908179407Sobrien
909179407Sobrien/* If mips gcc uses underscores for symbol names, then it does not use
910179407Sobrien   a leading dot for local labels, so if TARGET_UNDERSCORE is defined
911179407Sobrien   we treat all symbols starting with L as local.  */
912179407Sobrien
913179407Sobrienstatic bfd_boolean coff_mips_is_local_label_name
914179407Sobrien   PARAMS ((bfd *, const char *));
915179407Sobrien
916179407Sobrienstatic bfd_boolean
917179407Sobriencoff_mips_is_local_label_name (abfd, name)
918179407Sobrien     bfd *abfd;
919179407Sobrien     const char *name;
920179407Sobrien{
921179407Sobrien  if (name[0] == 'L')
922179407Sobrien    return TRUE;
923179407Sobrien
924179407Sobrien  return _bfd_coff_is_local_label_name (abfd, name);
925179407Sobrien}
926179407Sobrien
927179407Sobrien#define coff_bfd_is_local_label_name coff_mips_is_local_label_name
928179407Sobrien
929179407Sobrien#endif /* TARGET_UNDERSCORE */
930179407Sobrien
931179407Sobrien#define COFF_NO_HACK_SCNHDR_SIZE
932179407Sobrien
933179407Sobrien#include "coffcode.h"
934179407Sobrien
935179407Sobrienconst bfd_target
936179407Sobrien#ifdef TARGET_SYM
937179407Sobrien  TARGET_SYM =
938179407Sobrien#else
939179407Sobrien  mipslpe_vec =
940179407Sobrien#endif
941179407Sobrien{
942179407Sobrien#ifdef TARGET_NAME
943179407Sobrien  TARGET_NAME,
944179407Sobrien#else
945179407Sobrien  "pe-mips",			/* name */
946179407Sobrien#endif
947179407Sobrien  bfd_target_coff_flavour,
948179407Sobrien  BFD_ENDIAN_LITTLE,		/* data byte order is little */
949179407Sobrien  BFD_ENDIAN_LITTLE,		/* header byte order is little */
950179407Sobrien
951179407Sobrien  (HAS_RELOC | EXEC_P |		/* object flags */
952179407Sobrien   HAS_LINENO | HAS_DEBUG |
953179407Sobrien   HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
954179407Sobrien
955179407Sobrien#ifndef COFF_WITH_PE
956179407Sobrien  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */
957179407Sobrien   | SEC_CODE | SEC_DATA),
958179407Sobrien#else
959179407Sobrien  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */
960179407Sobrien   | SEC_CODE | SEC_DATA
961179407Sobrien   | SEC_LINK_ONCE | SEC_LINK_DUPLICATES),
962179407Sobrien#endif
963179407Sobrien
964179407Sobrien#ifdef TARGET_UNDERSCORE
965179407Sobrien  TARGET_UNDERSCORE,		/* leading underscore */
966179407Sobrien#else
967179407Sobrien  0,				/* leading underscore */
968179407Sobrien#endif
969179407Sobrien  '/',				/* ar_pad_char */
970179407Sobrien  15,				/* ar_max_namelen */
971179407Sobrien
972179407Sobrien  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
973179407Sobrien     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
974179407Sobrien     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
975179407Sobrien  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
976179407Sobrien     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
977179407Sobrien     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
978179407Sobrien
979179407Sobrien/* Note that we allow an object file to be treated as a core file as well.  */
980179407Sobrien    {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
981179407Sobrien       bfd_generic_archive_p, coff_object_p},
982179407Sobrien    {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
983179407Sobrien       bfd_false},
984179407Sobrien    {bfd_false, coff_write_object_contents, /* bfd_write_contents */
985179407Sobrien       _bfd_write_archive_contents, bfd_false},
986179407Sobrien
987179407Sobrien     BFD_JUMP_TABLE_GENERIC (coff),
988179407Sobrien     BFD_JUMP_TABLE_COPY (coff),
989179407Sobrien     BFD_JUMP_TABLE_CORE (_bfd_nocore),
990179407Sobrien     BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
991179407Sobrien     BFD_JUMP_TABLE_SYMBOLS (coff),
992179407Sobrien     BFD_JUMP_TABLE_RELOCS (coff),
993179407Sobrien     BFD_JUMP_TABLE_WRITE (coff),
994179407Sobrien     BFD_JUMP_TABLE_LINK (coff),
995179407Sobrien     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
996179407Sobrien
997179407Sobrien  NULL,
998179407Sobrien
999179407Sobrien  COFF_SWAP_TABLE
1000179407Sobrien};
1001