1 /* Support for 32-bit SPARC NLM (NetWare Loadable Module)
2    Copyright 1993, 1994, 2000, 2001, 2002, 2003
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 
32 static bfd_boolean nlm_sparc_read_reloc
33   PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
34 static bfd_boolean nlm_sparc_write_reloc
35   PARAMS ((bfd *, asection *, arelent *));
36 static bfd_boolean nlm_sparc_mangle_relocs
37   PARAMS ((bfd *, asection *, const PTR, bfd_vma, bfd_size_type));
38 static bfd_boolean nlm_sparc_read_import
39   PARAMS ((bfd *, nlmNAME(symbol_type) *));
40 static bfd_boolean nlm_sparc_write_import
41   PARAMS ((bfd *, asection *, arelent *));
42 static bfd_boolean nlm_sparc_write_external
43   PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *));
44 static bfd_boolean nlm_sparc_write_export
45   PARAMS ((bfd *, asymbol *, bfd_vma));
46 
47 enum 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
66 static 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 
84 static 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 
114 struct 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 
122 static bfd_boolean
nlm_sparc_read_reloc(abfd,sym,secp,rel)123 nlm_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 
170 static bfd_boolean
nlm_sparc_write_reloc(abfd,sec,rel)171 nlm_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 
237 static bfd_boolean
nlm_sparc_mangle_relocs(abfd,sec,data,offset,count)238 nlm_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 
250 static bfd_boolean
nlm_sparc_read_import(abfd,sym)251 nlm_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 
310 static bfd_boolean
nlm_sparc_write_import(abfd,sec,rel)311 nlm_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 = bfd_section_size (abfd, code);
329   else if (symsec == bss)
330     base = bfd_section_size (abfd, code) + bfd_section_size (abfd, data);
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 
351 static bfd_boolean
nlm_sparc_write_external(abfd,count,sym,relocs)352 nlm_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 
381 static bfd_boolean
nlm_sparc_write_export(abfd,sym,value)382 nlm_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 
410 static 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