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