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