bfd/
[platform/upstream/binutils.git] / bfd / nlm32-sparc.c
1 /* Support for 32-bit SPARC NLM (NetWare Loadable Module)
2    Copyright 1993, 1994, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3    2007 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., 51 Franklin Street - Fifth Floor, Boston, 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
32 enum 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
50 static reloc_howto_type nlm32_sparc_howto_table[] =
51 {
52   HOWTO (R_SPARC_NONE,    0,0, 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
80 struct 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
88 static bfd_boolean
89 nlm_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 index;
96   unsigned int type;
97   struct nlm32_sparc_reloc_ext tmp_reloc;
98   asection *code_sec, *data_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   data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
105
106   *secp = code_sec;
107
108   val = bfd_get_32 (abfd, tmp_reloc.offset);
109   addend = bfd_get_32 (abfd, tmp_reloc.addend);
110   type = bfd_get_8 (abfd, tmp_reloc.type);
111
112   rel->address = val;
113   rel->addend = addend;
114   rel->howto = NULL;
115
116   for (index = 0;
117        index < sizeof (nlm32_sparc_howto_table) / sizeof (reloc_howto_type);
118        index++)
119     if (nlm32_sparc_howto_table[index].type == type)
120       {
121         rel->howto = &nlm32_sparc_howto_table[index];
122         break;
123       }
124
125 #ifdef DEBUG
126   fprintf (stderr, "%s:  address = %08lx, addend = %08lx, type = %u, howto = %p\n",
127            __FUNCTION__, (unsigned long) rel->address,
128            (unsigned long) rel->addend, type, rel->howto);
129 #endif
130   return TRUE;
131
132 }
133
134 /* Write a NetWare sparc reloc.  */
135
136 static bfd_boolean
137 nlm_sparc_write_reloc (bfd * abfd, asection * sec, arelent * rel)
138 {
139   bfd_vma val;
140   struct nlm32_sparc_reloc_ext tmp_reloc;
141   unsigned int index;
142   int type = -1;
143   reloc_howto_type *tmp;
144
145   for (index = 0;
146        index < sizeof (nlm32_sparc_howto_table) / sizeof (reloc_howto_type);
147        index++)
148     {
149       tmp = &nlm32_sparc_howto_table[index];
150
151       if (tmp->rightshift == rel->howto->rightshift
152           && tmp->size == rel->howto->size
153           && tmp->bitsize == rel->howto->bitsize
154           && tmp->pc_relative == rel->howto->pc_relative
155           && tmp->bitpos == rel->howto->bitpos
156           && tmp->src_mask == rel->howto->src_mask
157           && tmp->dst_mask == rel->howto->dst_mask)
158         {
159           type = tmp->type;
160           break;
161         }
162     }
163   if (type == -1)
164     abort ();
165
166   /* Netware wants a list of relocs for each address.
167      Format is:
168         long    offset
169         long    addend
170         char    type
171      That should be it.  */
172
173   /* The value we write out is the offset into the appropriate
174      segment.  This offset is the section vma, adjusted by the vma of
175      the lowest section in that segment, plus the address of the
176      relocation.  */
177   val = bfd_get_section_vma (abfd, sec) + rel->address;
178
179 #ifdef DEBUG
180   fprintf (stderr, "%s:  val = %08lx, addend = %08lx, type = %u\n",
181            __FUNCTION__, (unsigned long) val, (unsigned long) rel->addend,
182            rel->howto->type);
183 #endif
184   bfd_put_32 (abfd, val, tmp_reloc.offset);
185   bfd_put_32 (abfd, rel->addend, tmp_reloc.addend);
186   bfd_put_8 (abfd, (short) (rel->howto->type), tmp_reloc.type);
187
188   if (bfd_bwrite (&tmp_reloc, (bfd_size_type) 12, abfd) != 12)
189     return FALSE;
190
191   return TRUE;
192 }
193
194 /* Mangle relocs for SPARC NetWare.  We can just use the standard
195    SPARC relocs.  */
196
197 static bfd_boolean
198 nlm_sparc_mangle_relocs (bfd *abfd ATTRIBUTE_UNUSED,
199                          asection *sec ATTRIBUTE_UNUSED,
200                          const void * data ATTRIBUTE_UNUSED,
201                          bfd_vma offset ATTRIBUTE_UNUSED,
202                          bfd_size_type count ATTRIBUTE_UNUSED)
203 {
204   return TRUE;
205 }
206
207 /* Read a NetWare sparc import record.  */
208
209 static bfd_boolean
210 nlm_sparc_read_import (bfd *abfd, nlmNAME (symbol_type) *sym)
211 {
212   struct nlm_relent *nlm_relocs;        /* Relocation records for symbol.  */
213   bfd_size_type rcount;                 /* Number of relocs.  */
214   bfd_byte temp[NLM_TARGET_LONG_SIZE];  /* Temporary 32-bit value.  */
215   unsigned char symlength;              /* Length of symbol name.  */
216   char *name;
217
218   /* First, read in the number of relocation
219      entries for this symbol.  */
220   if (bfd_bread (temp, (bfd_size_type) 4, abfd) != 4)
221     return FALSE;
222
223   rcount = bfd_get_32 (abfd, temp);
224
225   /* Next, read in the length of the symbol.  */
226   if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
227       != sizeof (symlength))
228     return FALSE;
229   sym -> symbol.the_bfd = abfd;
230   name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
231   if (name == NULL)
232     return FALSE;
233
234   /* Then read in the symbol.  */
235   if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
236     return FALSE;
237   name[symlength] = '\0';
238   sym -> symbol.name = name;
239   sym -> symbol.flags = 0;
240   sym -> symbol.value = 0;
241   sym -> symbol.section = bfd_und_section_ptr;
242
243   /* Next, start reading in the relocs.  */
244   nlm_relocs = bfd_alloc (abfd, rcount * sizeof (struct nlm_relent));
245   if (!nlm_relocs)
246     return FALSE;
247   sym -> relocs = nlm_relocs;
248   sym -> rcnt = 0;
249   while (sym -> rcnt < rcount)
250     {
251       asection *section;
252
253       if (! nlm_sparc_read_reloc (abfd, sym, &section, &nlm_relocs -> reloc))
254         return FALSE;
255       nlm_relocs -> section = section;
256       nlm_relocs++;
257       sym -> rcnt++;
258     }
259
260   return TRUE;
261 }
262
263 static bfd_boolean
264 nlm_sparc_write_import (bfd * abfd, asection * sec, arelent * rel)
265 {
266   char temp[4];
267   asection *code, *data, *bss, *symsec;
268   bfd_vma base;
269
270   code = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
271   data = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
272   bss = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
273   symsec = (*rel->sym_ptr_ptr)->section;
274
275   if (symsec == code)
276     base = 0;
277   else if (symsec == data)
278     base = code->size;
279   else if (symsec == bss)
280     base = code->size + data->size;
281   else
282     base = 0;
283
284 #ifdef DEBUG
285   fprintf (stderr, "%s:  <%lx, 1>\n\t",
286            __FUNCTION__, (unsigned long) (base + (*rel->sym_ptr_ptr)->value));
287 #endif
288   bfd_put_32 (abfd, base + (*rel->sym_ptr_ptr)->value, temp);
289   if (bfd_bwrite (temp, (bfd_size_type) 4, abfd) != 4)
290     return FALSE;
291   bfd_put_32 (abfd, (bfd_vma) 1, temp);
292   if (bfd_bwrite (temp, (bfd_size_type) 4, abfd) != 4)
293     return FALSE;
294   if (! nlm_sparc_write_reloc (abfd, sec, rel))
295     return FALSE;
296   return TRUE;
297 }
298
299 /* Write out an external reference.  */
300
301 static bfd_boolean
302 nlm_sparc_write_external (bfd *abfd,
303                           bfd_size_type count,
304                           asymbol *sym,
305                           struct reloc_and_sec *relocs)
306 {
307   unsigned int i;
308   bfd_byte len;
309   unsigned char temp[NLM_TARGET_LONG_SIZE];
310
311   bfd_put_32 (abfd, count, temp);
312   if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
313     return FALSE;
314
315   len = strlen (sym->name);
316   if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
317        != sizeof (bfd_byte))
318       || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
319     return FALSE;
320
321   for (i = 0; i < count; i++)
322     if (! nlm_sparc_write_reloc (abfd, relocs[i].sec, relocs[i].rel))
323       return FALSE;
324
325   return TRUE;
326 }
327
328 static bfd_boolean
329 nlm_sparc_write_export (bfd * abfd, asymbol * sym, bfd_vma value)
330 {
331   bfd_byte len;
332   bfd_byte temp[4];
333
334 #ifdef DEBUG
335   fprintf (stderr, "%s: <%lx, %u, %s>\n",
336            __FUNCTION__, (unsigned long) value, strlen (sym->name), sym->name);
337 #endif
338   bfd_put_32 (abfd, value, temp);
339   len = strlen (sym->name);
340
341   if (bfd_bwrite (temp, (bfd_size_type) 4, abfd) != 4
342       || bfd_bwrite (&len, (bfd_size_type) 1, abfd) != 1
343       || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
344     return FALSE;
345
346   return TRUE;
347 }
348
349 #undef nlm_swap_fixed_header_in
350 #undef nlm_swap_fixed_header_out
351
352 #include "nlmswap.h"
353
354 static const struct nlm_backend_data nlm32_sparc_backend =
355 {
356   "NetWare SPARC Module   \032",
357   sizeof (Nlm32_sparc_External_Fixed_Header),
358   0,    /* Optional_prefix_size.  */
359   bfd_arch_sparc,
360   0,
361   FALSE,
362   0,    /* Backend_object_p.  */
363   0,    /* Write_prefix_func.  */
364   nlm_sparc_read_reloc,
365   nlm_sparc_mangle_relocs,
366   nlm_sparc_read_import,
367   nlm_sparc_write_import,
368   0,    /* Set_public_section.  */
369   0,    /* Get_public_offset.  */
370   nlm_swap_fixed_header_in,
371   nlm_swap_fixed_header_out,
372   nlm_sparc_write_external,
373   nlm_sparc_write_export
374 };
375
376 #define TARGET_BIG_NAME         "nlm32-sparc"
377 #define TARGET_BIG_SYM          nlmNAME (sparc_vec)
378 #define TARGET_BACKEND_DATA     & nlm32_sparc_backend
379
380 #include "nlm-target.h"