1/* Support for 32-bit SPARC NLM (NetWare Loadable Module)
2   Copyright 1993, 1994, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3   2007 Free Software Foundation, Inc.
4
5   This file is part of BFD, the Binary File Descriptor library.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20   MA 02110-1301, USA.  */
21
22#include "sysdep.h"
23#include "bfd.h"
24#include "libbfd.h"
25
26#define ARCH_SIZE 32
27
28#include "nlm/sparc32-ext.h"
29#define Nlm_External_Fixed_Header	Nlm32_sparc_External_Fixed_Header
30
31#include "libnlm.h"
32
33enum reloc_type
34{
35  R_SPARC_NONE = 0,
36  R_SPARC_8,		R_SPARC_16,		R_SPARC_32,
37  R_SPARC_DISP8,	R_SPARC_DISP16,		R_SPARC_DISP32,
38  R_SPARC_WDISP30,	R_SPARC_WDISP22,
39  R_SPARC_HI22,		R_SPARC_22,
40  R_SPARC_13,		R_SPARC_LO10,
41  R_SPARC_GOT10,	R_SPARC_GOT13,		R_SPARC_GOT22,
42  R_SPARC_PC10,		R_SPARC_PC22,
43  R_SPARC_WPLT30,
44  R_SPARC_COPY,
45  R_SPARC_GLOB_DAT,	R_SPARC_JMP_SLOT,
46  R_SPARC_RELATIVE,
47  R_SPARC_UA32,
48  R_SPARC_max
49};
50
51static reloc_howto_type nlm32_sparc_howto_table[] =
52{
53  HOWTO (R_SPARC_NONE,    0,0, 0,FALSE,0,complain_overflow_dont,    0,"R_SPARC_NONE",    FALSE,0,0x00000000,TRUE),
54  HOWTO (R_SPARC_8,       0,0, 8,FALSE,0,complain_overflow_bitfield,0,"R_SPARC_8",       FALSE,0,0x000000ff,TRUE),
55  HOWTO (R_SPARC_16,      0,1,16,FALSE,0,complain_overflow_bitfield,0,"R_SPARC_16",      FALSE,0,0x0000ffff,TRUE),
56  HOWTO (R_SPARC_32,      0,2,32,FALSE,0,complain_overflow_bitfield,0,"R_SPARC_32",      FALSE,0,0xffffffff,TRUE),
57  HOWTO (R_SPARC_DISP8,   0,0, 8,TRUE, 0,complain_overflow_signed,  0,"R_SPARC_DISP8",   FALSE,0,0x000000ff,TRUE),
58  HOWTO (R_SPARC_DISP16,  0,1,16,TRUE, 0,complain_overflow_signed,  0,"R_SPARC_DISP16",  FALSE,0,0x0000ffff,TRUE),
59  HOWTO (R_SPARC_DISP32,  0,2,32,TRUE, 0,complain_overflow_signed,  0,"R_SPARC_DISP32",  FALSE,0,0x00ffffff,TRUE),
60  HOWTO (R_SPARC_WDISP30, 2,2,30,TRUE, 0,complain_overflow_signed,  0,"R_SPARC_WDISP30", FALSE,0,0x3fffffff,TRUE),
61  HOWTO (R_SPARC_WDISP22, 2,2,22,TRUE, 0,complain_overflow_signed,  0,"R_SPARC_WDISP22", FALSE,0,0x003fffff,TRUE),
62  HOWTO (R_SPARC_HI22,   10,2,22,FALSE,0,complain_overflow_dont,    0,"R_SPARC_HI22",    FALSE,0,0x003fffff,TRUE),
63  HOWTO (R_SPARC_22,      0,2,22,FALSE,0,complain_overflow_bitfield,0,"R_SPARC_22",      FALSE,0,0x003fffff,TRUE),
64  HOWTO (R_SPARC_13,      0,2,13,FALSE,0,complain_overflow_bitfield,0,"R_SPARC_13",      FALSE,0,0x00001fff,TRUE),
65  HOWTO (R_SPARC_LO10,    0,2,10,FALSE,0,complain_overflow_dont,    0,"R_SPARC_LO10",    FALSE,0,0x000003ff,TRUE),
66  HOWTO (R_SPARC_GOT10,   0,2,10,FALSE,0,complain_overflow_bitfield,0,"R_SPARC_GOT10",   FALSE,0,0x000003ff,TRUE),
67  HOWTO (R_SPARC_GOT13,   0,2,13,FALSE,0,complain_overflow_bitfield,0,"R_SPARC_GOT13",   FALSE,0,0x00001fff,TRUE),
68  HOWTO (R_SPARC_GOT22,  10,2,22,FALSE,0,complain_overflow_bitfield,0,"R_SPARC_GOT22",   FALSE,0,0x003fffff,TRUE),
69  HOWTO (R_SPARC_PC10,    0,2,10,FALSE,0,complain_overflow_bitfield,0,"R_SPARC_PC10",    FALSE,0,0x000003ff,TRUE),
70  HOWTO (R_SPARC_PC22,    0,2,22,FALSE,0,complain_overflow_bitfield,0,"R_SPARC_PC22",    FALSE,0,0x003fffff,TRUE),
71  HOWTO (R_SPARC_WPLT30,  0,0,00,FALSE,0,complain_overflow_dont,    0,"R_SPARC_WPLT30",  FALSE,0,0x00000000,TRUE),
72  HOWTO (R_SPARC_COPY,    0,0,00,FALSE,0,complain_overflow_dont,    0,"R_SPARC_COPY",    FALSE,0,0x00000000,TRUE),
73  HOWTO (R_SPARC_GLOB_DAT,0,0,00,FALSE,0,complain_overflow_dont,    0,"R_SPARC_GLOB_DAT",FALSE,0,0x00000000,TRUE),
74  HOWTO (R_SPARC_JMP_SLOT,0,0,00,FALSE,0,complain_overflow_dont,    0,"R_SPARC_JMP_SLOT",FALSE,0,0x00000000,TRUE),
75  HOWTO (R_SPARC_RELATIVE,0,0,00,FALSE,0,complain_overflow_dont,    0,"R_SPARC_RELATIVE",FALSE,0,0x00000000,TRUE),
76  HOWTO (R_SPARC_UA32,    0,0,00,FALSE,0,complain_overflow_dont,    0,"R_SPARC_UA32",    FALSE,0,0x00000000,TRUE),
77};
78
79/* Read a NetWare sparc reloc.  */
80
81struct nlm32_sparc_reloc_ext
82{
83  unsigned char offset[4];
84  unsigned char addend[4];
85  unsigned char type[1];
86  unsigned char pad1[3];
87};
88
89static bfd_boolean
90nlm_sparc_read_reloc (bfd *abfd,
91		      nlmNAME (symbol_type) *sym ATTRIBUTE_UNUSED,
92		      asection **secp,
93		      arelent *rel)
94{
95  bfd_vma val, addend;
96  unsigned int index;
97  unsigned int type;
98  struct nlm32_sparc_reloc_ext tmp_reloc;
99  asection *code_sec, *data_sec;
100
101  if (bfd_bread (&tmp_reloc, (bfd_size_type) 12, abfd) != 12)
102    return FALSE;
103
104  code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
105  data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
106
107  *secp = code_sec;
108
109  val = bfd_get_32 (abfd, tmp_reloc.offset);
110  addend = bfd_get_32 (abfd, tmp_reloc.addend);
111  type = bfd_get_8 (abfd, tmp_reloc.type);
112
113  rel->address = val;
114  rel->addend = addend;
115  rel->howto = NULL;
116
117  for (index = 0;
118       index < sizeof (nlm32_sparc_howto_table) / sizeof (reloc_howto_type);
119       index++)
120    if (nlm32_sparc_howto_table[index].type == type)
121      {
122	rel->howto = &nlm32_sparc_howto_table[index];
123	break;
124      }
125
126#ifdef DEBUG
127  fprintf (stderr, "%s:  address = %08lx, addend = %08lx, type = %u, howto = %p\n",
128	   __FUNCTION__, (unsigned long) rel->address,
129	   (unsigned long) rel->addend, type, rel->howto);
130#endif
131  return TRUE;
132
133}
134
135/* Write a NetWare sparc reloc.  */
136
137static bfd_boolean
138nlm_sparc_write_reloc (bfd * abfd, asection * sec, arelent * rel)
139{
140  bfd_vma val;
141  struct nlm32_sparc_reloc_ext tmp_reloc;
142  unsigned int index;
143  int type = -1;
144  reloc_howto_type *tmp;
145
146  for (index = 0;
147       index < sizeof (nlm32_sparc_howto_table) / sizeof (reloc_howto_type);
148       index++)
149    {
150      tmp = &nlm32_sparc_howto_table[index];
151
152      if (tmp->rightshift == rel->howto->rightshift
153	  && tmp->size == rel->howto->size
154	  && tmp->bitsize == rel->howto->bitsize
155	  && tmp->pc_relative == rel->howto->pc_relative
156	  && tmp->bitpos == rel->howto->bitpos
157	  && tmp->src_mask == rel->howto->src_mask
158	  && tmp->dst_mask == rel->howto->dst_mask)
159	{
160	  type = tmp->type;
161	  break;
162	}
163    }
164  if (type == -1)
165    abort ();
166
167  /* Netware wants a list of relocs for each address.
168     Format is:
169    	long	offset
170    	long	addend
171    	char	type
172     That should be it.  */
173
174  /* The value we write out is the offset into the appropriate
175     segment.  This offset is the section vma, adjusted by the vma of
176     the lowest section in that segment, plus the address of the
177     relocation.  */
178  val = bfd_get_section_vma (abfd, sec) + rel->address;
179
180#ifdef DEBUG
181  fprintf (stderr, "%s:  val = %08lx, addend = %08lx, type = %u\n",
182	   __FUNCTION__, (unsigned long) val, (unsigned long) rel->addend,
183	   rel->howto->type);
184#endif
185  bfd_put_32 (abfd, val, tmp_reloc.offset);
186  bfd_put_32 (abfd, rel->addend, tmp_reloc.addend);
187  bfd_put_8 (abfd, (short) (rel->howto->type), tmp_reloc.type);
188
189  if (bfd_bwrite (&tmp_reloc, (bfd_size_type) 12, abfd) != 12)
190    return FALSE;
191
192  return TRUE;
193}
194
195/* Mangle relocs for SPARC NetWare.  We can just use the standard
196   SPARC relocs.  */
197
198static bfd_boolean
199nlm_sparc_mangle_relocs (bfd *abfd ATTRIBUTE_UNUSED,
200			 asection *sec ATTRIBUTE_UNUSED,
201			 const void * data ATTRIBUTE_UNUSED,
202			 bfd_vma offset ATTRIBUTE_UNUSED,
203			 bfd_size_type count ATTRIBUTE_UNUSED)
204{
205  return TRUE;
206}
207
208/* Read a NetWare sparc import record.  */
209
210static bfd_boolean
211nlm_sparc_read_import (bfd *abfd, nlmNAME (symbol_type) *sym)
212{
213  struct nlm_relent *nlm_relocs;	/* Relocation records for symbol.  */
214  bfd_size_type rcount;			/* Number of relocs.  */
215  bfd_byte temp[NLM_TARGET_LONG_SIZE];	/* Temporary 32-bit value.  */
216  unsigned char symlength;		/* Length of symbol name.  */
217  char *name;
218
219  /* First, read in the number of relocation
220     entries for this symbol.  */
221  if (bfd_bread (temp, (bfd_size_type) 4, abfd) != 4)
222    return FALSE;
223
224  rcount = bfd_get_32 (abfd, temp);
225
226  /* Next, read in the length of the symbol.  */
227  if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
228      != sizeof (symlength))
229    return FALSE;
230  sym -> symbol.the_bfd = abfd;
231  name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
232  if (name == NULL)
233    return FALSE;
234
235  /* Then read in the symbol.  */
236  if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
237    return FALSE;
238  name[symlength] = '\0';
239  sym -> symbol.name = name;
240  sym -> symbol.flags = 0;
241  sym -> symbol.value = 0;
242  sym -> symbol.section = bfd_und_section_ptr;
243
244  /* Next, start reading in the relocs.  */
245  nlm_relocs = bfd_alloc (abfd, rcount * sizeof (struct nlm_relent));
246  if (!nlm_relocs)
247    return FALSE;
248  sym -> relocs = nlm_relocs;
249  sym -> rcnt = 0;
250  while (sym -> rcnt < rcount)
251    {
252      asection *section;
253
254      if (! nlm_sparc_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
255	return FALSE;
256      nlm_relocs -> section = section;
257      nlm_relocs++;
258      sym -> rcnt++;
259    }
260
261  return TRUE;
262}
263
264static bfd_boolean
265nlm_sparc_write_import (bfd * abfd, asection * sec, arelent * rel)
266{
267  char temp[4];
268  asection *code, *data, *bss, *symsec;
269  bfd_vma base;
270
271  code = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
272  data = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
273  bss = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
274  symsec = (*rel->sym_ptr_ptr)->section;
275
276  if (symsec == code)
277    base = 0;
278  else if (symsec == data)
279    base = code->size;
280  else if (symsec == bss)
281    base = code->size + data->size;
282  else
283    base = 0;
284
285#ifdef DEBUG
286  fprintf (stderr, "%s:  <%lx, 1>\n\t",
287	   __FUNCTION__, (unsigned long) (base + (*rel->sym_ptr_ptr)->value));
288#endif
289  bfd_put_32 (abfd, base + (*rel->sym_ptr_ptr)->value, temp);
290  if (bfd_bwrite (temp, (bfd_size_type) 4, abfd) != 4)
291    return FALSE;
292  bfd_put_32 (abfd, (bfd_vma) 1, temp);
293  if (bfd_bwrite (temp, (bfd_size_type) 4, abfd) != 4)
294    return FALSE;
295  if (! nlm_sparc_write_reloc (abfd, sec, rel))
296    return FALSE;
297  return TRUE;
298}
299
300/* Write out an external reference.  */
301
302static bfd_boolean
303nlm_sparc_write_external (bfd *abfd,
304			  bfd_size_type count,
305			  asymbol *sym,
306			  struct reloc_and_sec *relocs)
307{
308  unsigned int i;
309  bfd_byte len;
310  unsigned char temp[NLM_TARGET_LONG_SIZE];
311
312  bfd_put_32 (abfd, count, temp);
313  if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
314    return FALSE;
315
316  len = strlen (sym->name);
317  if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
318       != sizeof (bfd_byte))
319      || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
320    return FALSE;
321
322  for (i = 0; i < count; i++)
323    if (! nlm_sparc_write_reloc (abfd, relocs[i].sec, relocs[i].rel))
324      return FALSE;
325
326  return TRUE;
327}
328
329static bfd_boolean
330nlm_sparc_write_export (bfd * abfd, asymbol * sym, bfd_vma value)
331{
332  bfd_byte len;
333  bfd_byte temp[4];
334
335#ifdef DEBUG
336  fprintf (stderr, "%s: <%lx, %u, %s>\n",
337	   __FUNCTION__, (unsigned long) value, strlen (sym->name), sym->name);
338#endif
339  bfd_put_32 (abfd, value, temp);
340  len = strlen (sym->name);
341
342  if (bfd_bwrite (temp, (bfd_size_type) 4, abfd) != 4
343      || bfd_bwrite (&len, (bfd_size_type) 1, abfd) != 1
344      || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
345    return FALSE;
346
347  return TRUE;
348}
349
350#undef nlm_swap_fixed_header_in
351#undef nlm_swap_fixed_header_out
352
353#include "nlmswap.h"
354
355static const struct nlm_backend_data nlm32_sparc_backend =
356{
357  "NetWare SPARC Module   \032",
358  sizeof (Nlm32_sparc_External_Fixed_Header),
359  0,	/* Optional_prefix_size.  */
360  bfd_arch_sparc,
361  0,
362  FALSE,
363  0,	/* Backend_object_p.  */
364  0,	/* Write_prefix_func.  */
365  nlm_sparc_read_reloc,
366  nlm_sparc_mangle_relocs,
367  nlm_sparc_read_import,
368  nlm_sparc_write_import,
369  0,	/* Set_public_section.  */
370  0,	/* Get_public_offset.  */
371  nlm_swap_fixed_header_in,
372  nlm_swap_fixed_header_out,
373  nlm_sparc_write_external,
374  nlm_sparc_write_export
375};
376
377#define TARGET_BIG_NAME		"nlm32-sparc"
378#define TARGET_BIG_SYM		nlmNAME (sparc_vec)
379#define TARGET_BACKEND_DATA	& nlm32_sparc_backend
380
381#include "nlm-target.h"
382