]> Git Repo - binutils.git/blob - bfd/nlm32-i386.c
* bfd-in.h (BFD_VERSION): Use @VERSION@.
[binutils.git] / bfd / nlm32-i386.c
1 /* Support for 32-bit i386 NLM (NetWare Loadable Module)
2    Copyright (C) 1993 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "libbfd.h"
23
24 #define ARCH_SIZE 32
25
26 #include "nlm/i386-ext.h"
27 #define Nlm_External_Fixed_Header       Nlm32_i386_External_Fixed_Header
28
29 #include "libnlm.h"
30
31 static boolean nlm_i386_read_reloc
32   PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
33 static boolean nlm_i386_write_import
34   PARAMS ((bfd *, asection *, arelent *));
35 static boolean nlm_i386_mangle_relocs
36   PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type));
37 static boolean nlm_i386_read_import
38   PARAMS ((bfd *, nlmNAME(symbol_type) *));
39 static boolean nlm_i386_write_external
40   PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *));
41
42 /* Adjust the reloc location by an absolute value.  */
43
44 static reloc_howto_type nlm_i386_abs_howto =
45   HOWTO (0,                     /* type */
46          0,                     /* rightshift */
47          2,                     /* size (0 = byte, 1 = short, 2 = long) */
48          32,                    /* bitsize */
49          false,                 /* pc_relative */
50          0,                     /* bitpos */
51          complain_overflow_bitfield, /* complain_on_overflow */
52          0,                     /* special_function */
53          "32",                  /* name */
54          true,                  /* partial_inplace */
55          0xffffffff,            /* src_mask */
56          0xffffffff,            /* dst_mask */
57          false);                /* pcrel_offset */
58
59 /* Adjust the reloc location by a PC relative displacement.  */
60
61 static reloc_howto_type nlm_i386_pcrel_howto =
62   HOWTO (1,                     /* type */
63          0,                     /* rightshift */
64          2,                     /* size (0 = byte, 1 = short, 2 = long) */
65          32,                    /* bitsize */
66          true,                  /* pc_relative */
67          0,                     /* bitpos */
68          complain_overflow_signed, /* complain_on_overflow */
69          0,                     /* special_function */
70          "DISP32",              /* name */
71          true,                  /* partial_inplace */
72          0xffffffff,            /* src_mask */
73          0xffffffff,            /* dst_mask */
74          true);                 /* pcrel_offset */
75
76 /* Read a NetWare i386 reloc.  */
77
78 static boolean
79 nlm_i386_read_reloc (abfd, sym, secp, rel)
80      bfd *abfd;
81      nlmNAME(symbol_type) *sym;
82      asection **secp;
83      arelent *rel;
84 {
85   bfd_byte temp[4];
86   bfd_vma val;
87   const char *name;
88
89   if (bfd_read (temp, sizeof (temp), 1, abfd) != sizeof (temp))
90     {
91       bfd_error = system_call_error;
92       return false;
93     }
94
95   val = bfd_get_32 (abfd, temp);
96
97   /* The value is an offset into either the code or data segment.
98      This is the location which needs to be adjusted.
99
100      If this is a relocation fixup rather than an imported symbol (the
101      sym argument is NULL) then the high bit is 0 if the location
102      needs to be adjusted by the address of the data segment, or 1 if
103      the location needs to be adjusted by the address of the code
104      segment.  If this is an imported symbol, then the high bit is 0
105      if the location is 0 if the location should be adjusted by the
106      offset to the symbol, or 1 if the location should adjusted by the
107      absolute value of the symbol.
108
109      The second most significant bit is 0 if the value is an offset
110      into the data segment, or 1 if the value is an offset into the
111      code segment.
112
113      All this translates fairly easily into a BFD reloc.  */
114
115   if (sym == NULL)
116     {
117       if ((val & NLM_HIBIT) == 0)
118         name = NLM_INITIALIZED_DATA_NAME;
119       else
120         {
121           name = NLM_CODE_NAME;
122           val &=~ NLM_HIBIT;
123         }
124       rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
125       rel->howto = &nlm_i386_abs_howto;
126     }
127   else
128     {
129       /* In this case we do not need to set the sym_ptr_ptr field.  */
130       rel->sym_ptr_ptr = NULL;
131       if ((val & NLM_HIBIT) == 0)
132         rel->howto = &nlm_i386_pcrel_howto;
133       else
134         {
135           rel->howto = &nlm_i386_abs_howto;
136           val &=~ NLM_HIBIT;
137         }
138     }
139
140   if ((val & (NLM_HIBIT >> 1)) == 0)
141     *secp = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
142   else
143     {
144       *secp = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
145       val &=~ (NLM_HIBIT >> 1);
146     }
147
148   rel->address = val;
149   rel->addend = 0;
150
151   return true;
152 }
153
154 /* Write a NetWare i386 reloc.  */
155
156 static boolean
157 nlm_i386_write_import (abfd, sec, rel)
158      bfd *abfd;
159      asection *sec;
160      arelent *rel;
161 {
162   asymbol *sym;
163   bfd_vma val;
164   bfd_byte temp[4];
165
166   /* NetWare only supports two kinds of relocs.  We should check
167      special_function here, as well, but at the moment coff-i386
168      relocs uses a special_function which does not affect what we do
169      here.  */
170   if (rel->addend != 0
171       || rel->howto == NULL
172       || rel->howto->rightshift != 0
173       || rel->howto->size != 2
174       || rel->howto->bitsize != 32
175       || rel->howto->bitpos != 0
176       || rel->howto->src_mask != 0xffffffff
177       || rel->howto->dst_mask != 0xffffffff)
178     {
179       bfd_error = invalid_operation;
180       return false;
181     }
182
183   sym = *rel->sym_ptr_ptr;
184
185   /* The value we write out is the offset into the appropriate
186      segment.  This offset is the section vma, adjusted by the vma of
187      the lowest section in that segment, plus the address of the
188      relocation.  */
189   val = bfd_get_section_vma (abfd, sec) + rel->address;
190
191   /* The second most significant bit is 0 if the value is an offset
192      into the data segment, or 1 if the value is an offset into the
193      code segment.  */
194   if (bfd_get_section_flags (abfd, sec) & SEC_CODE)
195     {
196       val -= nlm_get_text_low (abfd);
197       val |= NLM_HIBIT >> 1;
198     }
199   else
200     val -= nlm_get_data_low (abfd);
201
202   if (bfd_get_section (sym) != &bfd_und_section)
203     {
204       /* NetWare only supports absolute internal relocs.  */
205       if (rel->howto->pc_relative)
206         {
207           bfd_error = invalid_operation;
208           return false;
209         }
210
211       /* The high bit is 1 if the reloc is against the code section, 0
212          if against the data section.  */
213       if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
214         val |= NLM_HIBIT;
215     }
216   else
217     {
218       /* The high bit is 1 if this is an absolute reloc, 0 if it is PC
219          relative.  */
220       if (! rel->howto->pc_relative)
221         val |= NLM_HIBIT;
222       else
223         {
224           /* PC relative relocs on NetWare must be pcrel_offset.  */
225           if (! rel->howto->pcrel_offset)
226             {
227               bfd_error = invalid_operation;
228               return false;
229             }
230         }
231     }
232   
233   bfd_put_32 (abfd, val, temp);
234   if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp))
235     {
236       bfd_error = system_call_error;
237       return false;
238     }
239
240   return true;
241 }
242
243 /* I want to be able to use objcopy to turn a i386 a.out or COFF file
244    into a NetWare i386 module.  That means that the relocs from the
245    source file have to be mapped into relocs that apply to the target
246    file.  This function is called by nlm_set_section_contents to give
247    it a chance to rework the relocs.
248
249    This is actually a fairly general concept.  However, this is not a
250    general implementation.  */
251
252 static boolean
253 nlm_i386_mangle_relocs (abfd, sec, data, offset, count)
254      bfd *abfd;
255      asection *sec;
256      PTR data;
257      bfd_vma offset;
258      bfd_size_type count;
259 {
260   arelent **rel_ptr_ptr, **rel_end;
261
262   rel_ptr_ptr = sec->orelocation;
263   rel_end = rel_ptr_ptr + sec->reloc_count;
264   for (; rel_ptr_ptr < rel_end; rel_ptr_ptr++)
265     {
266       arelent *rel;
267       asymbol *sym;
268       bfd_vma addend;
269
270       rel = *rel_ptr_ptr;
271       sym = *rel->sym_ptr_ptr;
272
273       /* Note that no serious harm will ensue if we fail to change a
274          reloc.  We will wind up failing in nlm_i386_write_import.  */
275
276       /* Make sure this reloc is within the data we have.  We only 4
277          byte relocs here, so we insist on having 4 bytes.  */
278       if (rel->address < offset
279           || rel->address + 4 > offset + count)
280         continue;
281
282       /* NetWare doesn't support reloc addends, so we get rid of them
283          here by simply adding them into the object data.  We handle
284          the symbol value, if any, the same way.  */
285       addend = rel->addend + sym->value;
286
287       /* The value of a symbol is the offset into the section.  If the
288          symbol is in the .bss segment, we need to include the size of
289          the data segment in the offset as well.  Fortunately, we know
290          that at this point the size of the data section is in the NLM
291          header.  */
292       if (((bfd_get_section_flags (abfd, bfd_get_section (sym))
293             & SEC_LOAD) == 0)
294           && ((bfd_get_section_flags (abfd, bfd_get_section (sym))
295                & SEC_ALLOC) != 0))
296         addend += nlm_fixed_header (abfd)->dataImageSize;
297
298       if (addend != 0
299           && rel->howto != NULL
300           && rel->howto->rightshift == 0
301           && rel->howto->size == 2
302           && rel->howto->bitsize == 32
303           && rel->howto->bitpos == 0
304           && rel->howto->src_mask == 0xffffffff
305           && rel->howto->dst_mask == 0xffffffff)
306         {
307           bfd_vma val;
308
309           val = bfd_get_32 (abfd, (bfd_byte *) data + rel->address - offset);
310           val += addend;
311           bfd_put_32 (abfd, val, (bfd_byte *) data + rel->address - offset);
312           rel->addend = 0;
313         }
314
315       /* NetWare uses a reloc with pcrel_offset set.  We adjust
316          pc_relative relocs accordingly.  We are going to change the
317          howto field, so we can only do this if the current one is
318          compatible.  We should check special_function here, but at
319          the moment coff-i386 uses a special_function which does not
320          affect what we are doing here.  */
321       if (rel->howto != NULL
322           && rel->howto->pc_relative
323           && ! rel->howto->pcrel_offset
324           && rel->howto->rightshift == 0
325           && rel->howto->size == 2
326           && rel->howto->bitsize == 32
327           && rel->howto->bitpos == 0
328           && rel->howto->src_mask == 0xffffffff
329           && rel->howto->dst_mask == 0xffffffff)
330         {
331           bfd_vma val;
332
333           /* When pcrel_offset is not set, it means that the negative
334              of the address of the memory location is stored in the
335              memory location.  We must add it back in.  */
336           val = bfd_get_32 (abfd, (bfd_byte *) data + rel->address - offset);
337           val += rel->address;
338           bfd_put_32 (abfd, val, (bfd_byte *) data + rel->address - offset);
339
340           rel->howto = &nlm_i386_pcrel_howto;
341         }
342     }
343
344   return true;
345 }
346
347 /* Read a NetWare i386 import record */
348 static boolean
349 nlm_i386_read_import (abfd, sym)
350      bfd *abfd;
351      nlmNAME(symbol_type) *sym;
352 {
353   struct nlm_relent *nlm_relocs;        /* relocation records for symbol */
354   bfd_size_type rcount;                 /* number of relocs */
355   bfd_byte temp[NLM_TARGET_LONG_SIZE];  /* temporary 32-bit value */
356   unsigned char symlength;              /* length of symbol name */
357
358   if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd)
359       != sizeof (symlength))
360     {
361       bfd_error = system_call_error;
362       return (false);
363     }
364   sym -> symbol.the_bfd = abfd;
365   sym -> symbol.name = bfd_alloc (abfd, symlength + 1);
366   if (!sym -> symbol.name)
367     {
368       bfd_error = no_memory;
369       return false;
370     }
371   if (bfd_read ((PTR) sym -> symbol.name, symlength, 1, abfd)
372       != symlength)
373     {
374       bfd_error = system_call_error;
375       return (false);
376     }
377   sym -> symbol.flags = 0;
378   sym -> symbol.value = 0;
379   sym -> symbol.section = &bfd_und_section;
380   if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp))
381     {
382       bfd_error = system_call_error;
383       return (false);
384     }
385   rcount = bfd_h_get_32 (abfd, temp);
386   nlm_relocs = ((struct nlm_relent *)
387                 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
388   if (!nlm_relocs)
389     {
390       bfd_error = no_memory;
391       return false;
392     }
393   sym -> relocs = nlm_relocs;
394   sym -> rcnt = 0;
395   while (sym -> rcnt < rcount)
396     {
397       asection *section;
398       
399       if (nlm_i386_read_reloc (abfd, sym, &section,
400                                &nlm_relocs -> reloc)
401           == false)
402         return false;
403       nlm_relocs -> section = section;
404       nlm_relocs++;
405       sym -> rcnt++;
406     }
407   return true;
408 }
409
410 /* Write out an external reference.  */
411
412 static boolean
413 nlm_i386_write_external (abfd, count, sym, relocs)
414      bfd *abfd;
415      bfd_size_type count;
416      asymbol *sym;
417      struct reloc_and_sec *relocs;
418 {
419   int i;
420   bfd_byte len;
421   unsigned char temp[NLM_TARGET_LONG_SIZE];
422
423   len = strlen (sym->name);
424   if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof(bfd_byte))
425       || bfd_write (sym->name, len, 1, abfd) != len)
426     {
427       bfd_error = system_call_error;
428       return false;
429     }
430
431   bfd_put_32 (abfd, count, temp);
432   if (bfd_write (temp, sizeof(temp), 1, abfd) != sizeof (temp))
433     {
434       bfd_error = system_call_error;
435       return false;
436     }
437
438   for (i = 0; i < count; i++)
439     {
440       if (nlm_i386_write_import (abfd, relocs[i].sec,
441                                  relocs[i].rel) == false)
442         return false;
443     }
444
445   return true;
446 }
447
448 #include "nlmswap.h"
449
450 static const struct nlm_backend_data nlm32_i386_backend =
451 {
452   "NetWare Loadable Module\032",
453   sizeof (Nlm32_i386_External_Fixed_Header),
454   0,    /* optional_prefix_size */
455   bfd_arch_i386,
456   0,
457   false,
458   0,    /* backend_object_p */
459   0,    /* write_prefix_func */
460   nlm_i386_read_reloc,
461   nlm_i386_mangle_relocs,
462   nlm_i386_read_import,
463   nlm_i386_write_import,
464   0,    /* set_public_section */
465   0,    /* get_public_offset */
466   nlm_swap_fixed_header_in,
467   nlm_swap_fixed_header_out,
468   nlm_i386_write_external,
469   0,    /* write_export */
470 };
471
472 #define TARGET_LITTLE_NAME              "nlm32-i386"
473 #define TARGET_LITTLE_SYM               nlmNAME(i386_vec)
474 #define TARGET_BACKEND_DATA             &nlm32_i386_backend
475
476 #include "nlm-target.h"
This page took 0.049189 seconds and 4 git commands to generate.