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