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