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