1 /* Support for 32-bit i386 NLM (NetWare Loadable Module)
2 Copyright (C) 1993 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., 675 Mass Ave, Cambridge, MA 02139, 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_read (temp, sizeof (temp), 1, abfd) != sizeof (temp))
91 bfd_error = system_call_error;
95 val = bfd_get_32 (abfd, temp);
97 /* The value is an offset into either the code or data segment.
98 This is the location which needs to be adjusted.
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.
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
113 All this translates fairly easily into a BFD reloc. */
117 if ((val & NLM_HIBIT) == 0)
118 name = NLM_INITIALIZED_DATA_NAME;
121 name = NLM_CODE_NAME;
124 rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
125 rel->howto = &nlm_i386_abs_howto;
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;
135 rel->howto = &nlm_i386_abs_howto;
140 if ((val & (NLM_HIBIT >> 1)) == 0)
141 *secp = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
144 *secp = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
145 val &=~ (NLM_HIBIT >> 1);
154 /* Write a NetWare i386 reloc. */
157 nlm_i386_write_import (abfd, sec, rel)
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
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)
179 bfd_error = invalid_operation;
183 sym = *rel->sym_ptr_ptr;
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
189 val = bfd_get_section_vma (abfd, sec) + rel->address;
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
194 if (bfd_get_section_flags (abfd, sec) & SEC_CODE)
196 val -= nlm_get_text_low (abfd);
197 val |= NLM_HIBIT >> 1;
200 val -= nlm_get_data_low (abfd);
202 if (bfd_get_section (sym) != &bfd_und_section)
204 /* NetWare only supports absolute internal relocs. */
205 if (rel->howto->pc_relative)
207 bfd_error = invalid_operation;
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)
218 /* The high bit is 1 if this is an absolute reloc, 0 if it is PC
220 if (! rel->howto->pc_relative)
224 /* PC relative relocs on NetWare must be pcrel_offset. */
225 if (! rel->howto->pcrel_offset)
227 bfd_error = invalid_operation;
233 bfd_put_32 (abfd, val, temp);
234 if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp))
236 bfd_error = system_call_error;
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.
249 This is actually a fairly general concept. However, this is not a
250 general implementation. */
253 nlm_i386_mangle_relocs (abfd, sec, data, offset, count)
260 arelent **rel_ptr_ptr, **rel_end;
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++)
271 sym = *rel->sym_ptr_ptr;
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. */
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)
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;
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
292 if (((bfd_get_section_flags (abfd, bfd_get_section (sym))
294 && ((bfd_get_section_flags (abfd, bfd_get_section (sym))
296 addend += nlm_fixed_header (abfd)->dataImageSize;
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)
309 val = bfd_get_32 (abfd, (bfd_byte *) data + rel->address - offset);
311 bfd_put_32 (abfd, val, (bfd_byte *) data + rel->address - offset);
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)
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);
338 bfd_put_32 (abfd, val, (bfd_byte *) data + rel->address - offset);
340 rel->howto = &nlm_i386_pcrel_howto;
347 /* Read a NetWare i386 import record */
349 nlm_i386_read_import (abfd, sym)
351 nlmNAME(symbol_type) *sym;
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 */
358 if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd)
359 != sizeof (symlength))
361 bfd_error = system_call_error;
364 sym -> symbol.the_bfd = abfd;
365 sym -> symbol.name = bfd_alloc (abfd, symlength + 1);
366 if (!sym -> symbol.name)
368 bfd_error = no_memory;
371 if (bfd_read ((PTR) sym -> symbol.name, symlength, 1, abfd)
374 bfd_error = system_call_error;
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))
382 bfd_error = system_call_error;
385 rcount = bfd_h_get_32 (abfd, temp);
386 nlm_relocs = ((struct nlm_relent *)
387 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
390 bfd_error = no_memory;
393 sym -> relocs = nlm_relocs;
395 while (sym -> rcnt < rcount)
399 if (nlm_i386_read_reloc (abfd, sym, §ion,
400 &nlm_relocs -> reloc)
403 nlm_relocs -> section = section;
410 /* Write out an external reference. */
413 nlm_i386_write_external (abfd, count, sym, relocs)
417 struct reloc_and_sec *relocs;
421 unsigned char temp[NLM_TARGET_LONG_SIZE];
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)
427 bfd_error = system_call_error;
431 bfd_put_32 (abfd, count, temp);
432 if (bfd_write (temp, sizeof(temp), 1, abfd) != sizeof (temp))
434 bfd_error = system_call_error;
438 for (i = 0; i < count; i++)
440 if (nlm_i386_write_import (abfd, relocs[i].sec,
441 relocs[i].rel) == false)
450 static const struct nlm_backend_data nlm32_i386_backend =
452 "NetWare Loadable Module\032",
453 sizeof (Nlm32_i386_External_Fixed_Header),
454 0, /* optional_prefix_size */
458 0, /* backend_object_p */
459 0, /* write_prefix_func */
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 */
472 #define TARGET_LITTLE_NAME "nlm32-i386"
473 #define TARGET_LITTLE_SYM nlmNAME(i386_vec)
474 #define TARGET_BACKEND_DATA &nlm32_i386_backend
476 #include "nlm-target.h"