1 /* Support for 32-bit i386 NLM (NetWare Loadable Module)
2 Copyright 1993, 1994, 2000, 2001 Free Software Foundation, Inc.
4 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
26 #include "nlm/i386-ext.h"
27 #define Nlm_External_Fixed_Header Nlm32_i386_External_Fixed_Header
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 *));
42 /* Adjust the reloc location by an absolute value. */
44 static reloc_howto_type nlm_i386_abs_howto =
47 2, /* size (0 = byte, 1 = short, 2 = long) */
49 false, /* pc_relative */
51 complain_overflow_bitfield, /* complain_on_overflow */
52 0, /* special_function */
54 true, /* partial_inplace */
55 0xffffffff, /* src_mask */
56 0xffffffff, /* dst_mask */
57 false); /* pcrel_offset */
59 /* Adjust the reloc location by a PC relative displacement. */
61 static reloc_howto_type nlm_i386_pcrel_howto =
64 2, /* size (0 = byte, 1 = short, 2 = long) */
66 true, /* pc_relative */
68 complain_overflow_signed, /* complain_on_overflow */
69 0, /* special_function */
71 true, /* partial_inplace */
72 0xffffffff, /* src_mask */
73 0xffffffff, /* dst_mask */
74 true); /* pcrel_offset */
76 /* Read a NetWare i386 reloc. */
79 nlm_i386_read_reloc (abfd, sym, secp, rel)
81 nlmNAME(symbol_type) *sym;
89 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
92 val = bfd_get_32 (abfd, temp);
94 /* The value is an offset into either the code or data segment.
95 This is the location which needs to be adjusted.
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.
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
110 All this translates fairly easily into a BFD reloc. */
114 if ((val & NLM_HIBIT) == 0)
115 name = NLM_INITIALIZED_DATA_NAME;
118 name = NLM_CODE_NAME;
121 rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
122 rel->howto = &nlm_i386_abs_howto;
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;
132 rel->howto = &nlm_i386_abs_howto;
137 if ((val & (NLM_HIBIT >> 1)) == 0)
138 *secp = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
141 *secp = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
142 val &=~ (NLM_HIBIT >> 1);
151 /* Write a NetWare i386 reloc. */
154 nlm_i386_write_import (abfd, sec, rel)
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
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)
176 bfd_set_error (bfd_error_invalid_operation);
180 sym = *rel->sym_ptr_ptr;
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
186 val = bfd_get_section_vma (abfd, sec) + rel->address;
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
191 if (bfd_get_section_flags (abfd, sec) & SEC_CODE)
193 val -= nlm_get_text_low (abfd);
194 val |= NLM_HIBIT >> 1;
197 val -= nlm_get_data_low (abfd);
199 if (! bfd_is_und_section (bfd_get_section (sym)))
201 /* NetWare only supports absolute internal relocs. */
202 if (rel->howto->pc_relative)
204 bfd_set_error (bfd_error_invalid_operation);
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)
215 /* The high bit is 1 if this is an absolute reloc, 0 if it is PC
217 if (! rel->howto->pc_relative)
221 /* PC relative relocs on NetWare must be pcrel_offset. */
222 if (! rel->howto->pcrel_offset)
224 bfd_set_error (bfd_error_invalid_operation);
230 bfd_put_32 (abfd, val, temp);
231 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
237 /* I want to be able to use objcopy to turn a i386 a.out or COFF file
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.
243 This is actually a fairly general concept. However, this is not a
244 general implementation. */
247 nlm_i386_mangle_relocs (abfd, sec, data, offset, count)
254 arelent **rel_ptr_ptr, **rel_end;
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++)
265 sym = *rel->sym_ptr_ptr;
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. */
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)
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;
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
286 if (((bfd_get_section_flags (abfd, bfd_get_section (sym))
288 && ((bfd_get_section_flags (abfd, bfd_get_section (sym))
290 addend += nlm_fixed_header (abfd)->dataImageSize;
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)
303 val = bfd_get_32 (abfd, (bfd_byte *) data + rel->address - offset);
305 bfd_put_32 (abfd, val, (bfd_byte *) data + rel->address - offset);
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)
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);
332 bfd_put_32 (abfd, val, (bfd_byte *) data + rel->address - offset);
334 rel->howto = &nlm_i386_pcrel_howto;
341 /* Read a NetWare i386 import record */
343 nlm_i386_read_import (abfd, sym)
345 nlmNAME(symbol_type) *sym;
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 */
353 if (bfd_bread ((PTR) &symlength, (bfd_size_type) sizeof (symlength), abfd)
354 != sizeof (symlength))
356 sym -> symbol.the_bfd = abfd;
357 name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
360 if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
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;
367 if (bfd_bread ((PTR) temp, (bfd_size_type) sizeof (temp), abfd)
370 rcount = H_GET_32 (abfd, temp);
371 nlm_relocs = ((struct nlm_relent *)
372 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
375 sym -> relocs = nlm_relocs;
377 while (sym -> rcnt < rcount)
381 if (nlm_i386_read_reloc (abfd, sym, §ion,
382 &nlm_relocs -> reloc)
385 nlm_relocs -> section = section;
392 /* Write out an external reference. */
395 nlm_i386_write_external (abfd, count, sym, relocs)
399 struct reloc_and_sec *relocs;
403 unsigned char temp[NLM_TARGET_LONG_SIZE];
405 len = strlen (sym->name);
406 if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
407 != sizeof (bfd_byte))
408 || bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
411 bfd_put_32 (abfd, count, temp);
412 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
415 for (i = 0; i < count; i++)
417 if (nlm_i386_write_import (abfd, relocs[i].sec,
418 relocs[i].rel) == false)
427 static const struct nlm_backend_data nlm32_i386_backend =
429 "NetWare Loadable Module\032",
430 sizeof (Nlm32_i386_External_Fixed_Header),
431 0, /* optional_prefix_size */
435 0, /* backend_object_p */
436 0, /* write_prefix_func */
438 nlm_i386_mangle_relocs,
439 nlm_i386_read_import,
440 nlm_i386_write_import,
441 0, /* set_public_section */
442 0, /* get_public_offset */
443 nlm_swap_fixed_header_in,
444 nlm_swap_fixed_header_out,
445 nlm_i386_write_external,
446 0, /* write_export */
449 #define TARGET_LITTLE_NAME "nlm32-i386"
450 #define TARGET_LITTLE_SYM nlmNAME(i386_vec)
451 #define TARGET_BACKEND_DATA &nlm32_i386_backend
453 #include "nlm-target.h"