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