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