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. */
27 static boolean nlm_i386_read_reloc
28 PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *));
29 static boolean nlm_i386_write_reloc
30 PARAMS ((bfd *, asection *, arelent *));
31 static boolean nlm_i386_mangle_relocs
32 PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type));
34 /* Adjust the reloc location by an absolute value. */
36 static reloc_howto_type nlm_i386_abs_howto =
39 2, /* size (0 = byte, 1 = short, 2 = long) */
41 false, /* pc_relative */
43 complain_overflow_bitfield, /* complain_on_overflow */
44 0, /* special_function */
46 true, /* partial_inplace */
47 0xffffffff, /* src_mask */
48 0xffffffff, /* dst_mask */
49 false); /* pcrel_offset */
51 /* Adjust the reloc location by a PC relative displacement. */
53 static reloc_howto_type nlm_i386_pcrel_howto =
56 2, /* size (0 = byte, 1 = short, 2 = long) */
58 true, /* pc_relative */
60 complain_overflow_signed, /* complain_on_overflow */
61 0, /* special_function */
63 true, /* partial_inplace */
64 0xffffffff, /* src_mask */
65 0xffffffff, /* dst_mask */
66 true); /* pcrel_offset */
68 /* Read a NetWare i386 reloc. */
71 nlm_i386_read_reloc (abfd, sym, secp, rel)
73 nlmNAME(symbol_type) *sym;
81 if (bfd_read (temp, sizeof (temp), 1, abfd) != sizeof (temp))
83 bfd_error = system_call_error;
87 val = bfd_get_32 (abfd, temp);
89 /* The value is an offset into either the code or data segment.
90 This is the location which needs to be adjusted.
92 If this is a relocation fixup rather than an imported symbol (the
93 sym argument is NULL) then the high bit is 0 if the location
94 needs to be adjusted by the address of the data segment, or 1 if
95 the location needs to be adjusted by the address of the code
96 segment. If this is an imported symbol, then the high bit is 0
97 if the location is 0 if the location should be adjusted by the
98 offset to the symbol, or 1 if the location should adjusted by the
99 absolute value of the symbol.
101 The second most significant bit is 0 if the value is an offset
102 into the data segment, or 1 if the value is an offset into the
105 All this translates fairly easily into a BFD reloc. */
109 if ((val & NLM_HIBIT) == 0)
110 name = NLM_INITIALIZED_DATA_NAME;
113 name = NLM_CODE_NAME;
116 rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
117 rel->howto = &nlm_i386_abs_howto;
121 /* In this case we do not need to set the sym_ptr_ptr field. */
122 rel->sym_ptr_ptr = NULL;
123 if ((val & NLM_HIBIT) == 0)
124 rel->howto = &nlm_i386_pcrel_howto;
127 rel->howto = &nlm_i386_abs_howto;
132 if ((val & (NLM_HIBIT >> 1)) == 0)
133 *secp = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
136 *secp = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
137 val &=~ (NLM_HIBIT >> 1);
146 /* Write a NetWare i386 reloc. */
149 nlm_i386_write_reloc (abfd, sec, rel)
158 /* NetWare only supports two kinds of relocs. We should check
159 special_function here, as well, but at the moment coff-i386
160 relocs uses a special_function which does not affect what we do
163 || rel->howto == NULL
164 || rel->howto->rightshift != 0
165 || rel->howto->size != 2
166 || rel->howto->bitsize != 32
167 || rel->howto->bitpos != 0
168 || ! rel->howto->partial_inplace
169 || rel->howto->src_mask != 0xffffffff
170 || rel->howto->dst_mask != 0xffffffff)
172 bfd_error = invalid_operation;
176 sym = *rel->sym_ptr_ptr;
178 /* The value we write out is the offset into the appropriate
179 segment. This offset is the section vma, adjusted by the vma of
180 the lowest section in that segment, plus the address of the
182 val = bfd_get_section_vma (abfd, sec) + rel->address;
184 /* The second most significant bit is 0 if the value is an offset
185 into the data segment, or 1 if the value is an offset into the
187 if (bfd_get_section_flags (abfd, sec) & SEC_CODE)
189 val -= nlm_get_text_low (abfd);
190 val |= NLM_HIBIT >> 1;
193 val -= nlm_get_data_low (abfd);
195 if (bfd_get_section (sym) != &bfd_und_section)
197 /* NetWare only supports absolute internal relocs. */
198 if (rel->howto->pc_relative)
200 bfd_error = invalid_operation;
204 /* The high bit is 1 if the reloc is against the code section, 0
205 if against the data section. */
206 if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
211 /* The high bit is 1 if this is an absolute reloc, 0 if it is PC
213 if (! rel->howto->pc_relative)
217 /* PC relative relocs on NetWare must be pcrel_offset. */
218 if (! rel->howto->pcrel_offset)
220 bfd_error = invalid_operation;
226 bfd_put_32 (abfd, val, temp);
227 if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp))
229 bfd_error = system_call_error;
236 /* I want to be able to use objcopy to turn a i386 a.out or COFF file
237 into a NetWare i386 module. That means that the relocs from the
238 source file have to be mapped into relocs that apply to the target
239 file. This function is called by nlm_set_section_contents to give
240 it a chance to rework the relocs.
242 This is actually a fairly general concept. However, this is not a
243 general implementation. */
246 nlm_i386_mangle_relocs (abfd, sec, data, offset, count)
253 arelent **rel_ptr_ptr, **rel_end;
255 rel_ptr_ptr = sec->orelocation;
256 rel_end = rel_ptr_ptr + sec->reloc_count;
257 for (; rel_ptr_ptr < rel_end; rel_ptr_ptr++)
264 sym = *rel->sym_ptr_ptr;
266 /* Note that no serious harm will ensue if we fail to change a
267 reloc. We will wind up failing in nlm_i386_write_reloc. */
269 /* Make sure this reloc is within the data we have. We only 4
270 byte relocs here, so we insist on having 4 bytes. */
271 if (rel->address < offset
272 || rel->address + 4 > offset + count)
275 /* NetWare doesn't support reloc addends, so we get rid of them
276 here by simply adding them into the object data. We handle
277 the symbol value, if any, the same way. */
278 addend = rel->addend + sym->value;
280 /* The value of a symbol is the offset into the section. If the
281 symbol is in the .bss segment, we need to include the size of
282 the data segment in the offset as well. Fortunately, we know
283 that at this point the size of the data section is in the NLM
285 if (((bfd_get_section_flags (abfd, bfd_get_section (sym))
286 & (SEC_CODE | SEC_DATA)) == 0)
287 && ((bfd_get_section_flags (abfd, bfd_get_section (sym))
289 addend += nlm_fixed_header (abfd)->dataImageSize;
292 && rel->howto != NULL
293 && rel->howto->rightshift == 0
294 && rel->howto->size == 2
295 && rel->howto->bitsize == 32
296 && rel->howto->bitpos == 0
297 && rel->howto->partial_inplace
298 && rel->howto->src_mask == 0xffffffff
299 && rel->howto->dst_mask == 0xffffffff)
303 val = bfd_get_32 (abfd, (char *) data + rel->address - offset);
305 bfd_put_32 (abfd, val, (char *) 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->partial_inplace
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, (char *) data + rel->address - offset);
333 bfd_put_32 (abfd, val, (char *) data + rel->address - offset);
335 rel->howto = &nlm_i386_pcrel_howto;
342 static const struct nlm_backend_data nlm32_i386_backend =
346 nlm_i386_write_reloc,
347 nlm_i386_mangle_relocs
350 #define TARGET_LITTLE_NAME "nlm32-i386"
351 #define TARGET_LITTLE_SYM nlmNAME(i386_vec)
352 #define TARGET_BACKEND_DATA &nlm32_i386_backend
354 #include "nlm-target.h"