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