1/* Support for 32-bit SPARC NLM (NetWare Loadable Module)
2   Copyright 1993, 1994, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3   2007, 2009, 2010 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 howto_index;
97  unsigned int type;
98  struct nlm32_sparc_reloc_ext tmp_reloc;
99  asection *code_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  *secp = code_sec;
106
107  val = bfd_get_32 (abfd, tmp_reloc.offset);
108  addend = bfd_get_32 (abfd, tmp_reloc.addend);
109  type = bfd_get_8 (abfd, tmp_reloc.type);
110
111  rel->address = val;
112  rel->addend = addend;
113  rel->howto = NULL;
114
115  for (howto_index = 0;
116       howto_index < sizeof (nlm32_sparc_howto_table) / sizeof (reloc_howto_type);
117       howto_index++)
118    if (nlm32_sparc_howto_table[howto_index].type == type)
119      {
120	rel->howto = &nlm32_sparc_howto_table[howto_index];
121	break;
122      }
123
124#ifdef DEBUG
125  fprintf (stderr, "%s:  address = %08lx, addend = %08lx, type = %u, howto = %p\n",
126	   __FUNCTION__, (unsigned long) rel->address,
127	   (unsigned long) rel->addend, type, rel->howto);
128#endif
129  return TRUE;
130
131}
132
133/* Write a NetWare sparc reloc.  */
134
135static bfd_boolean
136nlm_sparc_write_reloc (bfd * abfd, asection * sec, arelent * rel)
137{
138  bfd_vma val;
139  struct nlm32_sparc_reloc_ext tmp_reloc;
140  unsigned int howto_index;
141  int type = -1;
142  reloc_howto_type *tmp;
143
144  for (howto_index = 0;
145       howto_index < sizeof (nlm32_sparc_howto_table) / sizeof (reloc_howto_type);
146       howto_index++)
147    {
148      tmp = &nlm32_sparc_howto_table[howto_index];
149
150      if (tmp->rightshift == rel->howto->rightshift
151	  && tmp->size == rel->howto->size
152	  && tmp->bitsize == rel->howto->bitsize
153	  && tmp->pc_relative == rel->howto->pc_relative
154	  && tmp->bitpos == rel->howto->bitpos
155	  && tmp->src_mask == rel->howto->src_mask
156	  && tmp->dst_mask == rel->howto->dst_mask)
157	{
158	  type = tmp->type;
159	  break;
160	}
161    }
162  if (type == -1)
163    abort ();
164
165  /* Netware wants a list of relocs for each address.
166     Format is:
167    	long	offset
168    	long	addend
169    	char	type
170     That should be it.  */
171
172  /* The value we write out is the offset into the appropriate
173     segment.  This offset is the section vma, adjusted by the vma of
174     the lowest section in that segment, plus the address of the
175     relocation.  */
176  val = bfd_get_section_vma (abfd, sec) + rel->address;
177
178#ifdef DEBUG
179  fprintf (stderr, "%s:  val = %08lx, addend = %08lx, type = %u\n",
180	   __FUNCTION__, (unsigned long) val, (unsigned long) rel->addend,
181	   rel->howto->type);
182#endif
183  bfd_put_32 (abfd, val, tmp_reloc.offset);
184  bfd_put_32 (abfd, rel->addend, tmp_reloc.addend);
185  bfd_put_8 (abfd, (short) (rel->howto->type), tmp_reloc.type);
186
187  if (bfd_bwrite (&tmp_reloc, (bfd_size_type) 12, abfd) != 12)
188    return FALSE;
189
190  return TRUE;
191}
192
193/* Mangle relocs for SPARC NetWare.  We can just use the standard
194   SPARC relocs.  */
195
196static bfd_boolean
197nlm_sparc_mangle_relocs (bfd *abfd ATTRIBUTE_UNUSED,
198			 asection *sec ATTRIBUTE_UNUSED,
199			 const void * data ATTRIBUTE_UNUSED,
200			 bfd_vma offset ATTRIBUTE_UNUSED,
201			 bfd_size_type count ATTRIBUTE_UNUSED)
202{
203  return TRUE;
204}
205
206/* Read a NetWare sparc import record.  */
207
208static bfd_boolean
209nlm_sparc_read_import (bfd *abfd, nlmNAME (symbol_type) *sym)
210{
211  struct nlm_relent *nlm_relocs;	/* Relocation records for symbol.  */
212  bfd_size_type rcount;			/* Number of relocs.  */
213  bfd_byte temp[NLM_TARGET_LONG_SIZE];	/* Temporary 32-bit value.  */
214  unsigned char symlength;		/* Length of symbol name.  */
215  char *name;
216
217  /* First, read in the number of relocation
218     entries for this symbol.  */
219  if (bfd_bread (temp, (bfd_size_type) 4, abfd) != 4)
220    return FALSE;
221
222  rcount = bfd_get_32 (abfd, temp);
223
224  /* Next, read in the length of the symbol.  */
225  if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
226      != sizeof (symlength))
227    return FALSE;
228  sym -> symbol.the_bfd = abfd;
229  name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
230  if (name == NULL)
231    return FALSE;
232
233  /* Then read in the symbol.  */
234  if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
235    return FALSE;
236  name[symlength] = '\0';
237  sym -> symbol.name = name;
238  sym -> symbol.flags = 0;
239  sym -> symbol.value = 0;
240  sym -> symbol.section = bfd_und_section_ptr;
241
242  /* Next, start reading in the relocs.  */
243  nlm_relocs = bfd_alloc (abfd, rcount * sizeof (struct nlm_relent));
244  if (!nlm_relocs)
245    return FALSE;
246  sym -> relocs = nlm_relocs;
247  sym -> rcnt = 0;
248  while (sym -> rcnt < rcount)
249    {
250      asection *section;
251
252      if (! nlm_sparc_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
253	return FALSE;
254      nlm_relocs -> section = section;
255      nlm_relocs++;
256      sym -> rcnt++;
257    }
258
259  return TRUE;
260}
261
262static bfd_boolean
263nlm_sparc_write_import (bfd * abfd, asection * sec, arelent * rel)
264{
265  char temp[4];
266  asection *code, *data, *bss, *symsec;
267  bfd_vma base;
268
269  code = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
270  data = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
271  bss = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
272  symsec = (*rel->sym_ptr_ptr)->section;
273
274  if (symsec == code)
275    base = 0;
276  else if (symsec == data)
277    base = code->size;
278  else if (symsec == bss)
279    base = code->size + data->size;
280  else
281    base = 0;
282
283#ifdef DEBUG
284  fprintf (stderr, "%s:  <%lx, 1>\n\t",
285	   __FUNCTION__, (unsigned long) (base + (*rel->sym_ptr_ptr)->value));
286#endif
287  bfd_put_32 (abfd, base + (*rel->sym_ptr_ptr)->value, temp);
288  if (bfd_bwrite (temp, (bfd_size_type) 4, abfd) != 4)
289    return FALSE;
290  bfd_put_32 (abfd, (bfd_vma) 1, temp);
291  if (bfd_bwrite (temp, (bfd_size_type) 4, abfd) != 4)
292    return FALSE;
293  if (! nlm_sparc_write_reloc (abfd, sec, rel))
294    return FALSE;
295  return TRUE;
296}
297
298/* Write out an external reference.  */
299
300static bfd_boolean
301nlm_sparc_write_external (bfd *abfd,
302			  bfd_size_type count,
303			  asymbol *sym,
304			  struct reloc_and_sec *relocs)
305{
306  unsigned int i;
307  bfd_byte len;
308  unsigned char temp[NLM_TARGET_LONG_SIZE];
309
310  bfd_put_32 (abfd, count, temp);
311  if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
312    return FALSE;
313
314  len = strlen (sym->name);
315  if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
316       != sizeof (bfd_byte))
317      || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
318    return FALSE;
319
320  for (i = 0; i < count; i++)
321    if (! nlm_sparc_write_reloc (abfd, relocs[i].sec, relocs[i].rel))
322      return FALSE;
323
324  return TRUE;
325}
326
327static bfd_boolean
328nlm_sparc_write_export (bfd * abfd, asymbol * sym, bfd_vma value)
329{
330  bfd_byte len;
331  bfd_byte temp[4];
332
333#ifdef DEBUG
334  fprintf (stderr, "%s: <%lx, %u, %s>\n",
335	   __FUNCTION__, (unsigned long) value, strlen (sym->name), sym->name);
336#endif
337  bfd_put_32 (abfd, value, temp);
338  len = strlen (sym->name);
339
340  if (bfd_bwrite (temp, (bfd_size_type) 4, abfd) != 4
341      || bfd_bwrite (&len, (bfd_size_type) 1, abfd) != 1
342      || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
343    return FALSE;
344
345  return TRUE;
346}
347
348#undef nlm_swap_fixed_header_in
349#undef nlm_swap_fixed_header_out
350
351#include "nlmswap.h"
352
353static const struct nlm_backend_data nlm32_sparc_backend =
354{
355  "NetWare SPARC Module   \032",
356  sizeof (Nlm32_sparc_External_Fixed_Header),
357  0,	/* Optional_prefix_size.  */
358  bfd_arch_sparc,
359  0,
360  FALSE,
361  0,	/* Backend_object_p.  */
362  0,	/* Write_prefix_func.  */
363  nlm_sparc_read_reloc,
364  nlm_sparc_mangle_relocs,
365  nlm_sparc_read_import,
366  nlm_sparc_write_import,
367  0,	/* Set_public_section.  */
368  0,	/* Get_public_offset.  */
369  nlm_swap_fixed_header_in,
370  nlm_swap_fixed_header_out,
371  nlm_sparc_write_external,
372  nlm_sparc_write_export
373};
374
375#define TARGET_BIG_NAME		"nlm32-sparc"
376#define TARGET_BIG_SYM		nlmNAME (sparc_vec)
377#define TARGET_BACKEND_DATA	& nlm32_sparc_backend
378
379#include "nlm-target.h"
380