160484Sobrien/* BFD back-end for Sparc COFF files.
2130561Sobrien   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1999, 2000, 2001,
3218822Sdim   2002, 2003, 2005, 2007 Free Software Foundation, Inc.
460484Sobrien   Written by Cygnus Support.
560484Sobrien
660484SobrienThis file is part of BFD, the Binary File Descriptor library.
760484Sobrien
860484SobrienThis program is free software; you can redistribute it and/or modify
960484Sobrienit under the terms of the GNU General Public License as published by
1060484Sobrienthe Free Software Foundation; either version 2 of the License, or
1160484Sobrien(at your option) any later version.
1260484Sobrien
1360484SobrienThis program is distributed in the hope that it will be useful,
1460484Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
1560484SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1660484SobrienGNU General Public License for more details.
1760484Sobrien
1860484SobrienYou should have received a copy of the GNU General Public License
1960484Sobrienalong with this program; if not, write to the Free Software
20218822SdimFoundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2160484Sobrien
22218822Sdim#include "sysdep.h"
2360484Sobrien#include "bfd.h"
2460484Sobrien#include "libbfd.h"
2560484Sobrien#include "coff/sparc.h"
2660484Sobrien#include "coff/internal.h"
2760484Sobrien#include "libcoff.h"
2860484Sobrien
2960484Sobrien#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3)
3060484Sobrien
3160484Sobrien#define BADMAG(x) ((x).f_magic != SPARCMAGIC && (x).f_magic != LYNXCOFFMAGIC)
3260484Sobrien
3360484Sobrien/* The page size is a guess based on ELF.  */
3460484Sobrien#define COFF_PAGE_SIZE 0x10000
3560484Sobrien
3689857Sobrien
3789857Sobrienstatic reloc_howto_type *coff_sparc_reloc_type_lookup
3889857Sobrien  PARAMS ((bfd *, bfd_reloc_code_real_type));
3989857Sobrienstatic void rtype2howto PARAMS ((arelent *, struct internal_reloc *));
4089857Sobrien
4160484Sobrienenum reloc_type
4260484Sobrien  {
4360484Sobrien    R_SPARC_NONE = 0,
4477298Sobrien    R_SPARC_8,		R_SPARC_16,		R_SPARC_32,
4577298Sobrien    R_SPARC_DISP8,	R_SPARC_DISP16,		R_SPARC_DISP32,
4660484Sobrien    R_SPARC_WDISP30,	R_SPARC_WDISP22,
4760484Sobrien    R_SPARC_HI22,	R_SPARC_22,
4860484Sobrien    R_SPARC_13,		R_SPARC_LO10,
4960484Sobrien    R_SPARC_GOT10,	R_SPARC_GOT13,		R_SPARC_GOT22,
5060484Sobrien    R_SPARC_PC10,	R_SPARC_PC22,
5160484Sobrien    R_SPARC_WPLT30,
5260484Sobrien    R_SPARC_COPY,
5360484Sobrien    R_SPARC_GLOB_DAT,	R_SPARC_JMP_SLOT,
5460484Sobrien    R_SPARC_RELATIVE,
5560484Sobrien    R_SPARC_UA32,
5660484Sobrien    R_SPARC_max
5760484Sobrien  };
5860484Sobrien
5960484Sobrien/* This is stolen pretty directly from elf.c.  */
6060484Sobrienstatic bfd_reloc_status_type
6160484Sobrienbfd_coff_generic_reloc PARAMS ((bfd *, arelent *, asymbol *, PTR,
6260484Sobrien				asection *, bfd *, char **));
6360484Sobrien
6460484Sobrienstatic bfd_reloc_status_type
6560484Sobrienbfd_coff_generic_reloc (abfd, reloc_entry, symbol, data, input_section,
6660484Sobrien			output_bfd, error_message)
6760484Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
6860484Sobrien     arelent *reloc_entry;
6960484Sobrien     asymbol *symbol;
7060484Sobrien     PTR data ATTRIBUTE_UNUSED;
7160484Sobrien     asection *input_section;
7260484Sobrien     bfd *output_bfd;
7360484Sobrien     char **error_message ATTRIBUTE_UNUSED;
7460484Sobrien{
7560484Sobrien  if (output_bfd != (bfd *) NULL
7660484Sobrien      && (symbol->flags & BSF_SECTION_SYM) == 0)
7760484Sobrien    {
7860484Sobrien      reloc_entry->address += input_section->output_offset;
7960484Sobrien      return bfd_reloc_ok;
8060484Sobrien    }
8160484Sobrien
8260484Sobrien  return bfd_reloc_continue;
8360484Sobrien}
8460484Sobrien
8577298Sobrienstatic reloc_howto_type coff_sparc_howto_table[] =
8660484Sobrien{
87130561Sobrien  HOWTO(R_SPARC_NONE,    0,0, 0,FALSE,0,complain_overflow_dont,    bfd_coff_generic_reloc,"R_SPARC_NONE",    FALSE,0,0x00000000,TRUE),
88130561Sobrien  HOWTO(R_SPARC_8,       0,0, 8,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_8",       FALSE,0,0x000000ff,TRUE),
89130561Sobrien  HOWTO(R_SPARC_16,      0,1,16,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_16",      FALSE,0,0x0000ffff,TRUE),
90130561Sobrien  HOWTO(R_SPARC_32,      0,2,32,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_32",      FALSE,0,0xffffffff,TRUE),
91130561Sobrien  HOWTO(R_SPARC_DISP8,   0,0, 8,TRUE, 0,complain_overflow_signed,  bfd_coff_generic_reloc,"R_SPARC_DISP8",   FALSE,0,0x000000ff,TRUE),
92130561Sobrien  HOWTO(R_SPARC_DISP16,  0,1,16,TRUE, 0,complain_overflow_signed,  bfd_coff_generic_reloc,"R_SPARC_DISP16",  FALSE,0,0x0000ffff,TRUE),
93130561Sobrien  HOWTO(R_SPARC_DISP32,  0,2,32,TRUE, 0,complain_overflow_signed,  bfd_coff_generic_reloc,"R_SPARC_DISP32",  FALSE,0,0x00ffffff,TRUE),
94130561Sobrien  HOWTO(R_SPARC_WDISP30, 2,2,30,TRUE, 0,complain_overflow_signed,  bfd_coff_generic_reloc,"R_SPARC_WDISP30", FALSE,0,0x3fffffff,TRUE),
95130561Sobrien  HOWTO(R_SPARC_WDISP22, 2,2,22,TRUE, 0,complain_overflow_signed,  bfd_coff_generic_reloc,"R_SPARC_WDISP22", FALSE,0,0x003fffff,TRUE),
96130561Sobrien  HOWTO(R_SPARC_HI22,   10,2,22,FALSE,0,complain_overflow_dont,    bfd_coff_generic_reloc,"R_SPARC_HI22",    FALSE,0,0x003fffff,TRUE),
97130561Sobrien  HOWTO(R_SPARC_22,      0,2,22,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_22",      FALSE,0,0x003fffff,TRUE),
98130561Sobrien  HOWTO(R_SPARC_13,      0,2,13,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_13",      FALSE,0,0x00001fff,TRUE),
99130561Sobrien  HOWTO(R_SPARC_LO10,    0,2,10,FALSE,0,complain_overflow_dont,    bfd_coff_generic_reloc,"R_SPARC_LO10",    FALSE,0,0x000003ff,TRUE),
100130561Sobrien  HOWTO(R_SPARC_GOT10,   0,2,10,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_GOT10",   FALSE,0,0x000003ff,TRUE),
101130561Sobrien  HOWTO(R_SPARC_GOT13,   0,2,13,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_GOT13",   FALSE,0,0x00001fff,TRUE),
102130561Sobrien  HOWTO(R_SPARC_GOT22,  10,2,22,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_GOT22",   FALSE,0,0x003fffff,TRUE),
103130561Sobrien  HOWTO(R_SPARC_PC10,    0,2,10,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_PC10",    FALSE,0,0x000003ff,TRUE),
104130561Sobrien  HOWTO(R_SPARC_PC22,    0,2,22,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_PC22",    FALSE,0,0x003fffff,TRUE),
105130561Sobrien  HOWTO(R_SPARC_WPLT30,  0,0,00,FALSE,0,complain_overflow_dont,    bfd_coff_generic_reloc,"R_SPARC_WPLT30",  FALSE,0,0x00000000,TRUE),
106130561Sobrien  HOWTO(R_SPARC_COPY,    0,0,00,FALSE,0,complain_overflow_dont,    bfd_coff_generic_reloc,"R_SPARC_COPY",    FALSE,0,0x00000000,TRUE),
107130561Sobrien  HOWTO(R_SPARC_GLOB_DAT,0,0,00,FALSE,0,complain_overflow_dont,    bfd_coff_generic_reloc,"R_SPARC_GLOB_DAT",FALSE,0,0x00000000,TRUE),
108130561Sobrien  HOWTO(R_SPARC_JMP_SLOT,0,0,00,FALSE,0,complain_overflow_dont,    bfd_coff_generic_reloc,"R_SPARC_JMP_SLOT",FALSE,0,0x00000000,TRUE),
109130561Sobrien  HOWTO(R_SPARC_RELATIVE,0,0,00,FALSE,0,complain_overflow_dont,    bfd_coff_generic_reloc,"R_SPARC_RELATIVE",FALSE,0,0x00000000,TRUE),
110130561Sobrien  HOWTO(R_SPARC_UA32,    0,0,00,FALSE,0,complain_overflow_dont,    bfd_coff_generic_reloc,"R_SPARC_UA32",    FALSE,0,0x00000000,TRUE),
11160484Sobrien};
11260484Sobrien
11360484Sobrienstruct coff_reloc_map {
11460484Sobrien  bfd_reloc_code_real_type bfd_reloc_val;
11560484Sobrien  unsigned char coff_reloc_val;
11660484Sobrien};
11760484Sobrien
11889857Sobrienstatic const struct coff_reloc_map sparc_reloc_map[] =
11960484Sobrien{
12060484Sobrien  { BFD_RELOC_NONE, R_SPARC_NONE, },
12160484Sobrien  { BFD_RELOC_16, R_SPARC_16, },
12260484Sobrien  { BFD_RELOC_8, R_SPARC_8 },
12360484Sobrien  { BFD_RELOC_8_PCREL, R_SPARC_DISP8 },
12460484Sobrien  { BFD_RELOC_CTOR, R_SPARC_32 }, /* @@ Assumes 32 bits.  */
12560484Sobrien  { BFD_RELOC_32, R_SPARC_32 },
12660484Sobrien  { BFD_RELOC_32_PCREL, R_SPARC_DISP32 },
12760484Sobrien  { BFD_RELOC_HI22, R_SPARC_HI22 },
12860484Sobrien  { BFD_RELOC_LO10, R_SPARC_LO10, },
12960484Sobrien  { BFD_RELOC_32_PCREL_S2, R_SPARC_WDISP30 },
13060484Sobrien  { BFD_RELOC_SPARC22, R_SPARC_22 },
13160484Sobrien  { BFD_RELOC_SPARC13, R_SPARC_13 },
13260484Sobrien  { BFD_RELOC_SPARC_GOT10, R_SPARC_GOT10 },
13360484Sobrien  { BFD_RELOC_SPARC_GOT13, R_SPARC_GOT13 },
13460484Sobrien  { BFD_RELOC_SPARC_GOT22, R_SPARC_GOT22 },
13560484Sobrien  { BFD_RELOC_SPARC_PC10, R_SPARC_PC10 },
13660484Sobrien  { BFD_RELOC_SPARC_PC22, R_SPARC_PC22 },
13760484Sobrien  { BFD_RELOC_SPARC_WPLT30, R_SPARC_WPLT30 },
13860484Sobrien  { BFD_RELOC_SPARC_COPY, R_SPARC_COPY },
13960484Sobrien  { BFD_RELOC_SPARC_GLOB_DAT, R_SPARC_GLOB_DAT },
14060484Sobrien  { BFD_RELOC_SPARC_JMP_SLOT, R_SPARC_JMP_SLOT },
14160484Sobrien  { BFD_RELOC_SPARC_RELATIVE, R_SPARC_RELATIVE },
14260484Sobrien  { BFD_RELOC_SPARC_WDISP22, R_SPARC_WDISP22 },
14360484Sobrien  /*  { BFD_RELOC_SPARC_UA32, R_SPARC_UA32 }, not used?? */
14460484Sobrien};
14560484Sobrien
14660484Sobrienstatic reloc_howto_type *
14760484Sobriencoff_sparc_reloc_type_lookup (abfd, code)
14860484Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
14960484Sobrien     bfd_reloc_code_real_type code;
15060484Sobrien{
15160484Sobrien  unsigned int i;
15260484Sobrien  for (i = 0; i < sizeof (sparc_reloc_map) / sizeof (struct coff_reloc_map); i++)
15360484Sobrien    {
15460484Sobrien      if (sparc_reloc_map[i].bfd_reloc_val == code)
15560484Sobrien	return &coff_sparc_howto_table[(int) sparc_reloc_map[i].coff_reloc_val];
15660484Sobrien    }
15760484Sobrien  return 0;
15860484Sobrien}
15960484Sobrien#define coff_bfd_reloc_type_lookup	coff_sparc_reloc_type_lookup
16060484Sobrien
161218822Sdimstatic reloc_howto_type *
162218822Sdimcoff_sparc_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
163218822Sdim			      const char *r_name)
164218822Sdim{
165218822Sdim  unsigned int i;
166218822Sdim
167218822Sdim  for (i = 0;
168218822Sdim       i < (sizeof (coff_sparc_howto_table)
169218822Sdim	    / sizeof (coff_sparc_howto_table[0]));
170218822Sdim       i++)
171218822Sdim    if (coff_sparc_howto_table[i].name != NULL
172218822Sdim	&& strcasecmp (coff_sparc_howto_table[i].name, r_name) == 0)
173218822Sdim      return &coff_sparc_howto_table[i];
174218822Sdim
175218822Sdim  return NULL;
176218822Sdim}
177218822Sdim#define coff_bfd_reloc_name_lookup coff_sparc_reloc_name_lookup
178218822Sdim
17960484Sobrienstatic void
18060484Sobrienrtype2howto (cache_ptr, dst)
18160484Sobrien     arelent *cache_ptr;
18260484Sobrien     struct internal_reloc *dst;
18360484Sobrien{
18460484Sobrien  BFD_ASSERT (dst->r_type < (unsigned int) R_SPARC_max);
18560484Sobrien  cache_ptr->howto = &coff_sparc_howto_table[dst->r_type];
18660484Sobrien}
18760484Sobrien
18860484Sobrien#define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry)
18960484Sobrien
19089857Sobrien#define SWAP_IN_RELOC_OFFSET	H_GET_32
19189857Sobrien#define SWAP_OUT_RELOC_OFFSET	H_PUT_32
19260484Sobrien#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \
19360484Sobrien  cache_ptr->addend = reloc.r_offset;
19460484Sobrien
19560484Sobrien/* Clear the r_spare field in relocs.  */
19660484Sobrien#define SWAP_OUT_RELOC_EXTRA(abfd,src,dst) \
19760484Sobrien  do { \
19860484Sobrien       dst->r_spare[0] = 0; \
19960484Sobrien       dst->r_spare[1] = 0; \
20060484Sobrien     } while (0)
20160484Sobrien
20260484Sobrien#define __A_MAGIC_SET__
20360484Sobrien
20477298Sobrien/* Enable Sparc-specific hacks in coffcode.h.  */
20560484Sobrien
20660484Sobrien#define COFF_SPARC
20760484Sobrien
20860484Sobrien#include "coffcode.h"
20960484Sobrien
21060484Sobrien#ifndef TARGET_SYM
21160484Sobrien#define TARGET_SYM sparccoff_vec
21260484Sobrien#endif
21360484Sobrien
21460484Sobrien#ifndef TARGET_NAME
21560484Sobrien#define TARGET_NAME "coff-sparc"
21660484Sobrien#endif
21760484Sobrien
218130561SobrienCREATE_BIG_COFF_TARGET_VEC (TARGET_SYM, TARGET_NAME, D_PAGED, 0, '_', NULL, COFF_SWAP_TABLE)
219