1/* Support for 32-bit SPARC NLM (NetWare Loadable Module)
2   Copyright 1993, 1994, 1999, 2000, 2001, 2002, 2003, 2004, 2005
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 = %d, howto = %08lx\n",
127	   __FUNCTION__, rel->address, 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 index;
141  int type = -1;
142  reloc_howto_type *tmp;
143
144  for (index = 0;
145       index < sizeof (nlm32_sparc_howto_table) / sizeof (reloc_howto_type);
146       index++)
147    {
148      tmp = &nlm32_sparc_howto_table[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 = %d\n",
180	   __FUNCTION__, val, rel->addend, rel->howto->type);
181#endif
182  bfd_put_32 (abfd, val, tmp_reloc.offset);
183  bfd_put_32 (abfd, rel->addend, tmp_reloc.addend);
184  bfd_put_8 (abfd, (short) (rel->howto->type), tmp_reloc.type);
185
186  if (bfd_bwrite (&tmp_reloc, (bfd_size_type) 12, abfd) != 12)
187    return FALSE;
188
189  return TRUE;
190}
191
192/* Mangle relocs for SPARC NetWare.  We can just use the standard
193   SPARC relocs.  */
194
195static bfd_boolean
196nlm_sparc_mangle_relocs (bfd *abfd ATTRIBUTE_UNUSED,
197			 asection *sec ATTRIBUTE_UNUSED,
198			 const void * data ATTRIBUTE_UNUSED,
199			 bfd_vma offset ATTRIBUTE_UNUSED,
200			 bfd_size_type count ATTRIBUTE_UNUSED)
201{
202  return TRUE;
203}
204
205/* Read a NetWare sparc import record.  */
206
207static bfd_boolean
208nlm_sparc_read_import (bfd *abfd, nlmNAME (symbol_type) *sym)
209{
210  struct nlm_relent *nlm_relocs;	/* Relocation records for symbol.  */
211  bfd_size_type rcount;			/* Number of relocs.  */
212  bfd_byte temp[NLM_TARGET_LONG_SIZE];	/* Temporary 32-bit value.  */
213  unsigned char symlength;		/* Length of symbol name.  */
214  char *name;
215
216  /* First, read in the number of relocation
217     entries for this symbol.  */
218  if (bfd_bread (temp, (bfd_size_type) 4, abfd) != 4)
219    return FALSE;
220
221  rcount = bfd_get_32 (abfd, temp);
222
223  /* Next, read in the length of the symbol.  */
224  if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
225      != sizeof (symlength))
226    return FALSE;
227  sym -> symbol.the_bfd = abfd;
228  name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
229  if (name == NULL)
230    return FALSE;
231
232  /* Then read in the symbol.  */
233  if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
234    return FALSE;
235  name[symlength] = '\0';
236  sym -> symbol.name = name;
237  sym -> symbol.flags = 0;
238  sym -> symbol.value = 0;
239  sym -> symbol.section = bfd_und_section_ptr;
240
241  /* Next, start reading in the relocs.  */
242  nlm_relocs = bfd_alloc (abfd, rcount * sizeof (struct nlm_relent));
243  if (!nlm_relocs)
244    return FALSE;
245  sym -> relocs = nlm_relocs;
246  sym -> rcnt = 0;
247  while (sym -> rcnt < rcount)
248    {
249      asection *section;
250
251      if (! nlm_sparc_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
252	return FALSE;
253      nlm_relocs -> section = section;
254      nlm_relocs++;
255      sym -> rcnt++;
256    }
257
258  return TRUE;
259}
260
261static bfd_boolean
262nlm_sparc_write_import (bfd * abfd, asection * sec, arelent * rel)
263{
264  char temp[4];
265  asection *code, *data, *bss, *symsec;
266  bfd_vma base;
267
268  code = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
269  data = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
270  bss = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
271  symsec = (*rel->sym_ptr_ptr)->section;
272
273  if (symsec == code)
274    base = 0;
275  else if (symsec == data)
276    base = code->size;
277  else if (symsec == bss)
278    base = code->size + data->size;
279  else
280    base = 0;
281
282#ifdef DEBUG
283  fprintf (stderr, "%s:  <%x, 1>\n\t",
284	   __FUNCTION__, base + (*rel->sym_ptr_ptr)->value);
285#endif
286  bfd_put_32 (abfd, base + (*rel->sym_ptr_ptr)->value, temp);
287  if (bfd_bwrite (temp, (bfd_size_type) 4, abfd) != 4)
288    return FALSE;
289  bfd_put_32 (abfd, (bfd_vma) 1, temp);
290  if (bfd_bwrite (temp, (bfd_size_type) 4, abfd) != 4)
291    return FALSE;
292  if (! nlm_sparc_write_reloc (abfd, sec, rel))
293    return FALSE;
294  return TRUE;
295}
296
297/* Write out an external reference.  */
298
299static bfd_boolean
300nlm_sparc_write_external (bfd *abfd,
301			  bfd_size_type count,
302			  asymbol *sym,
303			  struct reloc_and_sec *relocs)
304{
305  unsigned int i;
306  bfd_byte len;
307  unsigned char temp[NLM_TARGET_LONG_SIZE];
308
309  bfd_put_32 (abfd, count, temp);
310  if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
311    return FALSE;
312
313  len = strlen (sym->name);
314  if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
315       != sizeof (bfd_byte))
316      || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
317    return FALSE;
318
319  for (i = 0; i < count; i++)
320    if (! nlm_sparc_write_reloc (abfd, relocs[i].sec, relocs[i].rel))
321      return FALSE;
322
323  return TRUE;
324}
325
326static bfd_boolean
327nlm_sparc_write_export (bfd * abfd, asymbol * sym, bfd_vma value)
328{
329  bfd_byte len;
330  bfd_byte temp[4];
331
332#ifdef DEBUG
333  fprintf (stderr, "%s: <%x, %d, %s>\n",
334	   __FUNCTION__, value, strlen (sym->name), sym->name);
335#endif
336  bfd_put_32 (abfd, value, temp);
337  len = strlen (sym->name);
338
339  if (bfd_bwrite (temp, (bfd_size_type) 4, abfd) != 4
340      || bfd_bwrite (&len, (bfd_size_type) 1, abfd) != 1
341      || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
342    return FALSE;
343
344  return TRUE;
345}
346
347#undef nlm_swap_fixed_header_in
348#undef nlm_swap_fixed_header_out
349
350#include "nlmswap.h"
351
352static const struct nlm_backend_data nlm32_sparc_backend =
353{
354  "NetWare SPARC Module   \032",
355  sizeof (Nlm32_sparc_External_Fixed_Header),
356  0,	/* Optional_prefix_size.  */
357  bfd_arch_sparc,
358  0,
359  FALSE,
360  0,	/* Backend_object_p.  */
361  0,	/* Write_prefix_func.  */
362  nlm_sparc_read_reloc,
363  nlm_sparc_mangle_relocs,
364  nlm_sparc_read_import,
365  nlm_sparc_write_import,
366  0,	/* Set_public_section.  */
367  0,	/* Get_public_offset.  */
368  nlm_swap_fixed_header_in,
369  nlm_swap_fixed_header_out,
370  nlm_sparc_write_external,
371  nlm_sparc_write_export
372};
373
374#define TARGET_BIG_NAME		"nlm32-sparc"
375#define TARGET_BIG_SYM		nlmNAME (sparc_vec)
376#define TARGET_BACKEND_DATA	& nlm32_sparc_backend
377
378#include "nlm-target.h"
379