1 /* Support for 32-bit i386 NLM (NetWare Loadable Module)
2 Copyright 1993, 1994, 2000, 2001, 2002, 2003
3 Free Software Foundation, Inc.
5 This file is part of BFD, the Binary File Descriptor library.
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
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
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.
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
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
27 #include "nlm/i386-ext.h"
28 #define Nlm_External_Fixed_Header Nlm32_i386_External_Fixed_Header
32 static bfd_boolean nlm_i386_read_reloc
33 PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
34 static bfd_boolean nlm_i386_write_import
35 PARAMS ((bfd *, asection *, arelent *));
36 static bfd_boolean nlm_i386_mangle_relocs
37 PARAMS ((bfd *, asection *, const PTR, bfd_vma, bfd_size_type));
38 static bfd_boolean nlm_i386_read_import
39 PARAMS ((bfd *, nlmNAME(symbol_type) *));
40 static bfd_boolean nlm_i386_write_external
41 PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *));
43 /* Adjust the reloc location by an absolute value. */
45 static reloc_howto_type nlm_i386_abs_howto =
48 2, /* size (0 = byte, 1 = short, 2 = long) */
50 FALSE, /* pc_relative */
52 complain_overflow_bitfield, /* complain_on_overflow */
53 0, /* special_function */
55 TRUE, /* partial_inplace */
56 0xffffffff, /* src_mask */
57 0xffffffff, /* dst_mask */
58 FALSE); /* pcrel_offset */
60 /* Adjust the reloc location by a PC relative displacement. */
62 static reloc_howto_type nlm_i386_pcrel_howto =
65 2, /* size (0 = byte, 1 = short, 2 = long) */
67 TRUE, /* pc_relative */
69 complain_overflow_signed, /* complain_on_overflow */
70 0, /* special_function */
72 TRUE, /* partial_inplace */
73 0xffffffff, /* src_mask */
74 0xffffffff, /* dst_mask */
75 TRUE); /* pcrel_offset */
77 /* Read a NetWare i386 reloc. */
80 nlm_i386_read_reloc (abfd, sym, secp, rel)
82 nlmNAME(symbol_type) *sym;
90 if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
93 val = bfd_get_32 (abfd, temp);
95 /* The value is an offset into either the code or data segment.
96 This is the location which needs to be adjusted.
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.
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
111 All this translates fairly easily into a BFD reloc. */
115 if ((val & NLM_HIBIT) == 0)
116 name = NLM_INITIALIZED_DATA_NAME;
119 name = NLM_CODE_NAME;
122 rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
123 rel->howto = &nlm_i386_abs_howto;
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;
133 rel->howto = &nlm_i386_abs_howto;
138 if ((val & (NLM_HIBIT >> 1)) == 0)
139 *secp = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
142 *secp = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
143 val &=~ (NLM_HIBIT >> 1);
152 /* Write a NetWare i386 reloc. */
155 nlm_i386_write_import (abfd, sec, rel)
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
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)
177 bfd_set_error (bfd_error_invalid_operation);
181 sym = *rel->sym_ptr_ptr;
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
187 val = bfd_get_section_vma (abfd, sec) + rel->address;
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
192 if (bfd_get_section_flags (abfd, sec) & SEC_CODE)
194 val -= nlm_get_text_low (abfd);
195 val |= NLM_HIBIT >> 1;
198 val -= nlm_get_data_low (abfd);
200 if (! bfd_is_und_section (bfd_get_section (sym)))
202 /* NetWare only supports absolute internal relocs. */
203 if (rel->howto->pc_relative)
205 bfd_set_error (bfd_error_invalid_operation);
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)
216 /* The high bit is 1 if this is an absolute reloc, 0 if it is PC
218 if (! rel->howto->pc_relative)
222 /* PC relative relocs on NetWare must be pcrel_offset. */
223 if (! rel->howto->pcrel_offset)
225 bfd_set_error (bfd_error_invalid_operation);
231 bfd_put_32 (abfd, val, temp);
232 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
238 /* I want to be able to use objcopy to turn an i386 a.out or COFF file
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.
244 This is actually a fairly general concept. However, this is not a
245 general implementation. */
248 nlm_i386_mangle_relocs (abfd, sec, data, offset, count)
255 arelent **rel_ptr_ptr, **rel_end;
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++)
266 sym = *rel->sym_ptr_ptr;
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. */
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)
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;
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
287 if (((bfd_get_section_flags (abfd, bfd_get_section (sym))
289 && ((bfd_get_section_flags (abfd, bfd_get_section (sym))
291 addend += nlm_fixed_header (abfd)->dataImageSize;
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)
304 val = bfd_get_32 (abfd, (bfd_byte *) data + rel->address - offset);
306 bfd_put_32 (abfd, val, (bfd_byte *) data + rel->address - offset);
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)
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);
333 bfd_put_32 (abfd, val, (bfd_byte *) data + rel->address - offset);
335 rel->howto = &nlm_i386_pcrel_howto;
342 /* Read a NetWare i386 import record */
344 nlm_i386_read_import (abfd, sym)
346 nlmNAME(symbol_type) *sym;
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 */
354 if (bfd_bread ((PTR) &symlength, (bfd_size_type) sizeof (symlength), abfd)
355 != sizeof (symlength))
357 sym -> symbol.the_bfd = abfd;
358 name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
361 if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
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;
368 if (bfd_bread ((PTR) temp, (bfd_size_type) sizeof (temp), abfd)
371 rcount = H_GET_32 (abfd, temp);
372 nlm_relocs = ((struct nlm_relent *)
373 bfd_alloc (abfd, rcount * sizeof (struct nlm_relent)));
376 sym -> relocs = nlm_relocs;
378 while (sym -> rcnt < rcount)
382 if (! nlm_i386_read_reloc (abfd, sym, §ion, &nlm_relocs -> reloc))
384 nlm_relocs -> section = section;
391 /* Write out an external reference. */
394 nlm_i386_write_external (abfd, count, sym, relocs)
398 struct reloc_and_sec *relocs;
402 unsigned char temp[NLM_TARGET_LONG_SIZE];
404 len = strlen (sym->name);
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)
410 bfd_put_32 (abfd, count, temp);
411 if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
414 for (i = 0; i < count; i++)
416 if (! nlm_i386_write_import (abfd, relocs[i].sec, relocs[i].rel))
425 static const struct nlm_backend_data nlm32_i386_backend =
427 "NetWare Loadable Module\032",
428 sizeof (Nlm32_i386_External_Fixed_Header),
429 0, /* optional_prefix_size */
433 0, /* backend_object_p */
434 0, /* write_prefix_func */
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 */
447 #define TARGET_LITTLE_NAME "nlm32-i386"
448 #define TARGET_LITTLE_SYM nlmNAME(i386_vec)
449 #define TARGET_BACKEND_DATA &nlm32_i386_backend
451 #include "nlm-target.h"