1/* Support for 32-bit SPARC NLM (NetWare Loadable Module)
2   Copyright (C) 1993-2017 Free Software Foundation, Inc.
3
4   This file is part of BFD, the Binary File Descriptor library.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19   MA 02110-1301, USA.  */
20
21#include "sysdep.h"
22#include "bfd.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,3, 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 howto_index;
96  unsigned int type;
97  struct nlm32_sparc_reloc_ext tmp_reloc;
98  asection *code_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  *secp = code_sec;
105
106  val = bfd_get_32 (abfd, tmp_reloc.offset);
107  addend = bfd_get_32 (abfd, tmp_reloc.addend);
108  type = bfd_get_8 (abfd, tmp_reloc.type);
109
110  rel->address = val;
111  rel->addend = addend;
112  rel->howto = NULL;
113
114  for (howto_index = 0;
115       howto_index < sizeof (nlm32_sparc_howto_table) / sizeof (reloc_howto_type);
116       howto_index++)
117    if (nlm32_sparc_howto_table[howto_index].type == type)
118      {
119	rel->howto = &nlm32_sparc_howto_table[howto_index];
120	break;
121      }
122
123#ifdef DEBUG
124  fprintf (stderr, "%s:  address = %08lx, addend = %08lx, type = %u, howto = %p\n",
125	   __FUNCTION__, (unsigned long) rel->address,
126	   (unsigned long) rel->addend, type, rel->howto);
127#endif
128  return TRUE;
129
130}
131
132/* Write a NetWare sparc reloc.  */
133
134static bfd_boolean
135nlm_sparc_write_reloc (bfd * abfd, asection * sec, arelent * rel)
136{
137  bfd_vma val;
138  struct nlm32_sparc_reloc_ext tmp_reloc;
139  unsigned int howto_index;
140  int type = -1;
141  reloc_howto_type *tmp;
142
143  for (howto_index = 0;
144       howto_index < sizeof (nlm32_sparc_howto_table) / sizeof (reloc_howto_type);
145       howto_index++)
146    {
147      tmp = &nlm32_sparc_howto_table[howto_index];
148
149      if (tmp->rightshift == rel->howto->rightshift
150	  && tmp->size == rel->howto->size
151	  && tmp->bitsize == rel->howto->bitsize
152	  && tmp->pc_relative == rel->howto->pc_relative
153	  && tmp->bitpos == rel->howto->bitpos
154	  && tmp->src_mask == rel->howto->src_mask
155	  && tmp->dst_mask == rel->howto->dst_mask)
156	{
157	  type = tmp->type;
158	  break;
159	}
160    }
161  if (type == -1)
162    abort ();
163
164  /* Netware wants a list of relocs for each address.
165     Format is:
166    	long	offset
167    	long	addend
168    	char	type
169     That should be it.  */
170
171  /* The value we write out is the offset into the appropriate
172     segment.  This offset is the section vma, adjusted by the vma of
173     the lowest section in that segment, plus the address of the
174     relocation.  */
175  val = bfd_get_section_vma (abfd, sec) + rel->address;
176
177#ifdef DEBUG
178  fprintf (stderr, "%s:  val = %08lx, addend = %08lx, type = %u\n",
179	   __FUNCTION__, (unsigned long) val, (unsigned long) rel->addend,
180	   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:  <%lx, 1>\n\t",
284	   __FUNCTION__, (unsigned long) (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: <%lx, %u, %s>\n",
334	   __FUNCTION__, (unsigned long) 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		sparc_nlm32_vec
376#define TARGET_BACKEND_DATA	& nlm32_sparc_backend
377
378#include "nlm-target.h"
379