154a96282da6adce78c132a304c729feecace187
[external/binutils.git] / bfd / nlm32-sparc.c
1 /* Support for 32-bit SPARC NLM (NetWare Loadable Module)
2    Copyright 1993, 1994, 2000 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   for (index = 0;
178        index < sizeof (nlm32_sparc_howto_table) / sizeof (reloc_howto_type);
179        index++) {
180     tmp = &nlm32_sparc_howto_table[index];
181
182     if (tmp->rightshift == rel->howto->rightshift
183         && tmp->size == rel->howto->size
184         && tmp->bitsize == rel->howto->bitsize
185         && tmp->pc_relative == rel->howto->pc_relative
186         && tmp->bitpos == rel->howto->bitpos
187         && tmp->src_mask == rel->howto->src_mask
188         && tmp->dst_mask == rel->howto->dst_mask) {
189       type = tmp->type;
190       break;
191     }
192   }
193   if (type == -1)
194     abort ();
195
196   /*
197    * Netware wants a list of relocs for each address.
198    * Format is:
199    *    long    offset
200    *    long    addend
201    *    char    type
202    * That should be it.
203    */
204
205   /* The value we write out is the offset into the appropriate
206      segment.  This offset is the section vma, adjusted by the vma of
207      the lowest section in that segment, plus the address of the
208      relocation.  */
209 #if 0
210   val = bfd_get_section_vma (abfd, (*rel->sym_ptr_ptr)->section) + rel->address;
211 #else
212   val = bfd_get_section_vma (abfd, sec) + rel->address;
213 #endif
214
215 #ifdef DEBUG
216   fprintf (stderr, "%s:  val = %08lx, addend = %08lx, type = %d\n",
217            __FUNCTION__, val, rel->addend, rel->howto->type);
218 #endif
219   bfd_put_32 (abfd, val, tmp_reloc.offset);
220   bfd_put_32 (abfd, rel->addend, tmp_reloc.addend);
221   bfd_put_8 (abfd, (short) (rel->howto->type), tmp_reloc.type);
222
223   if (bfd_write (&tmp_reloc, 12, 1, abfd) != 12)
224     return false;
225
226   return true;
227 }
228
229 /* Mangle relocs for SPARC NetWare.  We can just use the standard
230    SPARC relocs.  */
231
232 static boolean
233 nlm_sparc_mangle_relocs (abfd, sec, data, offset, count)
234      bfd *abfd ATTRIBUTE_UNUSED;
235      asection *sec ATTRIBUTE_UNUSED;
236      PTR data ATTRIBUTE_UNUSED;
237      bfd_vma offset ATTRIBUTE_UNUSED;
238      bfd_size_type count ATTRIBUTE_UNUSED;
239 {
240   return true;
241 }
242
243 /* Read a NetWare sparc import record */
244 static boolean
245 nlm_sparc_read_import (abfd, sym)
246      bfd *abfd;
247      nlmNAME(symbol_type) *sym;
248 {
249   struct nlm_relent *nlm_relocs;        /* relocation records for symbol */
250   bfd_size_type rcount;                 /* number of relocs */
251   bfd_byte temp[NLM_TARGET_LONG_SIZE];  /* temporary 32-bit value */
252   unsigned char symlength;              /* length of symbol name */
253   char *name;
254
255   /*
256    * First, read in the number of relocation
257    * entries for this symbol
258    */
259   if (bfd_read ((PTR) temp, 4, 1, abfd) != 4)
260     return false;
261
262   rcount = bfd_get_32 (abfd, temp);
263
264   /*
265    * Next, read in the length of the symbol
266    */
267
268   if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd)
269       != sizeof (symlength))
270     return false;
271   sym -> symbol.the_bfd = abfd;
272   name = bfd_alloc (abfd, symlength + 1);
273   if (name == NULL)
274     return false;
275
276   /*
277    * Then read in the symbol
278    */
279
280   if (bfd_read (name, symlength, 1, 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   /*
289    * Next, start reading in the relocs.
290    */
291
292   nlm_relocs = ((struct nlm_relent *)
293                 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
294   if (!nlm_relocs)
295     return false;
296   sym -> relocs = nlm_relocs;
297   sym -> rcnt = 0;
298   while (sym -> rcnt < rcount)
299     {
300       asection *section;
301
302       if (nlm_sparc_read_reloc (abfd, sym, &section,
303                               &nlm_relocs -> reloc)
304           == false)
305         return false;
306       nlm_relocs -> section = section;
307       nlm_relocs++;
308       sym -> rcnt++;
309     }
310   return true;
311 }
312
313 static boolean
314 nlm_sparc_write_import (abfd, sec, rel)
315      bfd *abfd;
316      asection *sec;
317      arelent *rel;
318 {
319   char temp[4];
320   asection *code, *data, *bss, *symsec;
321   bfd_vma base;
322
323   code = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
324   data = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
325   bss = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
326   symsec = (*rel->sym_ptr_ptr)->section;
327
328   if (symsec == code) {
329     base = 0;
330   } else if (symsec == data) {
331     base = bfd_section_size (abfd, code);
332   } else if (symsec == bss) {
333     base = bfd_section_size (abfd, code) + bfd_section_size (abfd, data);
334   } else
335     base = 0;
336
337 #ifdef DEBUG
338   fprintf (stderr, "%s:  <%x, 1>\n\t",
339            __FUNCTION__, base + (*rel->sym_ptr_ptr)->value);
340 #endif
341   bfd_put_32 (abfd, base + (*rel->sym_ptr_ptr)->value, temp);
342   if (bfd_write ((PTR)temp, 4, 1, abfd) != 4)
343     return false;
344   bfd_put_32 (abfd, 1, temp);
345   if (bfd_write ((PTR)temp, 4, 1, abfd) != 4)
346     return false;
347   if (nlm_sparc_write_reloc (abfd, sec, rel) == false)
348     return false;
349   return true;
350 }
351
352 /* Write out an external reference.  */
353
354 static boolean
355 nlm_sparc_write_external (abfd, count, sym, relocs)
356      bfd *abfd;
357      bfd_size_type count;
358      asymbol *sym;
359      struct reloc_and_sec *relocs;
360 {
361   unsigned int i;
362   bfd_byte len;
363   unsigned char temp[NLM_TARGET_LONG_SIZE];
364
365   bfd_put_32 (abfd, count, temp);
366   if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp))
367     return false;
368
369   len = strlen (sym->name);
370   if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof (bfd_byte))
371       || bfd_write (sym->name, len, 1, abfd) != len)
372     return false;
373
374   for (i = 0; i < count; i++)
375     {
376       if (nlm_sparc_write_reloc (abfd, relocs[i].sec,
377                                  relocs[i].rel) == false)
378         return false;
379     }
380
381   return true;
382 }
383
384 static boolean
385 nlm_sparc_write_export (abfd, sym, value)
386      bfd *abfd;
387      asymbol *sym;
388      bfd_vma value;
389 {
390   bfd_byte len;
391   bfd_byte temp[4];
392
393 #ifdef DEBUG
394   fprintf (stderr, "%s: <%x, %d, %s>\n",
395            __FUNCTION__, value, strlen (sym->name), sym->name);
396 #endif
397   bfd_put_32 (abfd, value, temp);
398   len = strlen (sym->name);
399
400   if (bfd_write (temp, 4, 1, abfd) != 4
401       || bfd_write (&len, 1, 1, abfd) != 1
402       || bfd_write (sym->name, len, 1, abfd) != len)
403     return false;
404
405   return true;
406 }
407
408 #undef nlm_swap_fixed_header_in
409 #undef nlm_swap_fixed_header_out
410
411 #include "nlmswap.h"
412
413 static const struct nlm_backend_data nlm32_sparc_backend =
414 {
415   "NetWare SPARC Module   \032",
416   sizeof (Nlm32_sparc_External_Fixed_Header),
417   0,    /* optional_prefix_size */
418   bfd_arch_sparc,
419   0,
420   false,
421   0,    /* backend_object_p */
422   0,    /* write_prefix_func */
423   nlm_sparc_read_reloc,
424   nlm_sparc_mangle_relocs,
425   nlm_sparc_read_import,
426   nlm_sparc_write_import,
427   0,    /* set_public_section */
428   0,    /* get_public_offset */
429   nlm_swap_fixed_header_in,
430   nlm_swap_fixed_header_out,
431   nlm_sparc_write_external,
432   nlm_sparc_write_export
433 };
434
435 #define TARGET_BIG_NAME         "nlm32-sparc"
436 #define TARGET_BIG_SYM          nlmNAME(sparc_vec)
437 #define TARGET_BACKEND_DATA             &nlm32_sparc_backend
438
439 #include "nlm-target.h"