1 /* Support for 32-bit i386 NLM (NetWare Loadable Module)
2 Copyright 1993, 1994, 2000, 2001, 2002, 2003, 2005, 2007
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 3 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., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
28 #include "nlm/i386-ext.h"
29 #define Nlm_External_Fixed_Header Nlm32_i386_External_Fixed_Header
33 /* Adjust the reloc location by an absolute value. */
35 static reloc_howto_type nlm_i386_abs_howto
=
38 2, /* Size (0 = byte, 1 = short, 2 = long). */
40 FALSE
, /* PC relative. */
42 complain_overflow_bitfield
, /* Complain_on_overflow. */
43 0, /* Special_function. */
45 TRUE
, /* Partial_inplace. */
46 0xffffffff, /* Source mask. */
47 0xffffffff, /* Dest mask. */
48 FALSE
); /* PR rel_offset. */
50 /* Adjust the reloc location by a PC relative displacement. */
52 static reloc_howto_type nlm_i386_pcrel_howto
=
55 2, /* Size (0 = byte, 1 = short, 2 = long). */
57 TRUE
, /* PC relative. */
59 complain_overflow_signed
, /* Complain_on_overflow. */
60 0, /* Special_function. */
62 TRUE
, /* Partial_inplace. */
63 0xffffffff, /* Source mask. */
64 0xffffffff, /* Dest mask. */
65 TRUE
); /* PR rel_offset. */
67 /* Read a NetWare i386 reloc. */
70 nlm_i386_read_reloc (bfd
*abfd
,
71 nlmNAME (symbol_type
) *sym
,
79 if (bfd_bread (temp
, (bfd_size_type
) sizeof (temp
), abfd
) != sizeof (temp
))
82 val
= bfd_get_32 (abfd
, temp
);
84 /* The value is an offset into either the code or data segment.
85 This is the location which needs to be adjusted.
87 If this is a relocation fixup rather than an imported symbol (the
88 sym argument is NULL) then the high bit is 0 if the location
89 needs to be adjusted by the address of the data segment, or 1 if
90 the location needs to be adjusted by the address of the code
91 segment. If this is an imported symbol, then the high bit is 0
92 if the location is 0 if the location should be adjusted by the
93 offset to the symbol, or 1 if the location should adjusted by the
94 absolute value of the symbol.
96 The second most significant bit is 0 if the value is an offset
97 into the data segment, or 1 if the value is an offset into the
100 All this translates fairly easily into a BFD reloc. */
104 if ((val
& NLM_HIBIT
) == 0)
105 name
= NLM_INITIALIZED_DATA_NAME
;
108 name
= NLM_CODE_NAME
;
111 rel
->sym_ptr_ptr
= bfd_get_section_by_name (abfd
, name
)->symbol_ptr_ptr
;
112 rel
->howto
= &nlm_i386_abs_howto
;
116 /* In this case we do not need to set the sym_ptr_ptr field. */
117 rel
->sym_ptr_ptr
= NULL
;
118 if ((val
& NLM_HIBIT
) == 0)
119 rel
->howto
= &nlm_i386_pcrel_howto
;
122 rel
->howto
= &nlm_i386_abs_howto
;
127 if ((val
& (NLM_HIBIT
>> 1)) == 0)
128 *secp
= bfd_get_section_by_name (abfd
, NLM_INITIALIZED_DATA_NAME
);
131 *secp
= bfd_get_section_by_name (abfd
, NLM_CODE_NAME
);
132 val
&=~ (NLM_HIBIT
>> 1);
141 /* Write a NetWare i386 reloc. */
144 nlm_i386_write_import (bfd
* abfd
, asection
* sec
, arelent
* rel
)
150 /* NetWare only supports two kinds of relocs. We should check
151 special_function here, as well, but at the moment coff-i386
152 relocs uses a special_function which does not affect what we do
155 || rel
->howto
== NULL
156 || rel
->howto
->rightshift
!= 0
157 || rel
->howto
->size
!= 2
158 || rel
->howto
->bitsize
!= 32
159 || rel
->howto
->bitpos
!= 0
160 || rel
->howto
->src_mask
!= 0xffffffff
161 || rel
->howto
->dst_mask
!= 0xffffffff)
163 bfd_set_error (bfd_error_invalid_operation
);
167 sym
= *rel
->sym_ptr_ptr
;
169 /* The value we write out is the offset into the appropriate
170 segment. This offset is the section vma, adjusted by the vma of
171 the lowest section in that segment, plus the address of the
173 val
= bfd_get_section_vma (abfd
, sec
) + rel
->address
;
175 /* The second most significant bit is 0 if the value is an offset
176 into the data segment, or 1 if the value is an offset into the
178 if (bfd_get_section_flags (abfd
, sec
) & SEC_CODE
)
180 val
-= nlm_get_text_low (abfd
);
181 val
|= NLM_HIBIT
>> 1;
184 val
-= nlm_get_data_low (abfd
);
186 if (! bfd_is_und_section (bfd_get_section (sym
)))
188 /* NetWare only supports absolute internal relocs. */
189 if (rel
->howto
->pc_relative
)
191 bfd_set_error (bfd_error_invalid_operation
);
195 /* The high bit is 1 if the reloc is against the code section, 0
196 if against the data section. */
197 if (bfd_get_section_flags (abfd
, bfd_get_section (sym
)) & SEC_CODE
)
202 /* The high bit is 1 if this is an absolute reloc, 0 if it is PC
204 if (! rel
->howto
->pc_relative
)
208 /* PC relative relocs on NetWare must be pcrel_offset. */
209 if (! rel
->howto
->pcrel_offset
)
211 bfd_set_error (bfd_error_invalid_operation
);
217 bfd_put_32 (abfd
, val
, temp
);
218 if (bfd_bwrite (temp
, (bfd_size_type
) sizeof (temp
), abfd
) != sizeof (temp
))
224 /* I want to be able to use objcopy to turn an i386 a.out or COFF file
225 into a NetWare i386 module. That means that the relocs from the
226 source file have to be mapped into relocs that apply to the target
227 file. This function is called by nlm_set_section_contents to give
228 it a chance to rework the relocs.
230 This is actually a fairly general concept. However, this is not a
231 general implementation. */
234 nlm_i386_mangle_relocs (bfd
*abfd
,
240 arelent
**rel_ptr_ptr
, **rel_end
;
242 rel_ptr_ptr
= sec
->orelocation
;
243 rel_end
= rel_ptr_ptr
+ sec
->reloc_count
;
244 for (; rel_ptr_ptr
< rel_end
; rel_ptr_ptr
++)
251 sym
= *rel
->sym_ptr_ptr
;
253 /* Note that no serious harm will ensue if we fail to change a
254 reloc. We will wind up failing in nlm_i386_write_import. */
256 /* Make sure this reloc is within the data we have. We only 4
257 byte relocs here, so we insist on having 4 bytes. */
258 if (rel
->address
< offset
259 || rel
->address
+ 4 > offset
+ count
)
262 /* NetWare doesn't support reloc addends, so we get rid of them
263 here by simply adding them into the object data. We handle
264 the symbol value, if any, the same way. */
265 addend
= rel
->addend
+ sym
->value
;
267 /* The value of a symbol is the offset into the section. If the
268 symbol is in the .bss segment, we need to include the size of
269 the data segment in the offset as well. Fortunately, we know
270 that at this point the size of the data section is in the NLM
272 if (((bfd_get_section_flags (abfd
, bfd_get_section (sym
))
274 && ((bfd_get_section_flags (abfd
, bfd_get_section (sym
))
276 addend
+= nlm_fixed_header (abfd
)->dataImageSize
;
279 && rel
->howto
!= NULL
280 && rel
->howto
->rightshift
== 0
281 && rel
->howto
->size
== 2
282 && rel
->howto
->bitsize
== 32
283 && rel
->howto
->bitpos
== 0
284 && rel
->howto
->src_mask
== 0xffffffff
285 && rel
->howto
->dst_mask
== 0xffffffff)
289 val
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ rel
->address
- offset
);
291 bfd_put_32 (abfd
, val
, (bfd_byte
*) data
+ rel
->address
- offset
);
295 /* NetWare uses a reloc with pcrel_offset set. We adjust
296 pc_relative relocs accordingly. We are going to change the
297 howto field, so we can only do this if the current one is
298 compatible. We should check special_function here, but at
299 the moment coff-i386 uses a special_function which does not
300 affect what we are doing here. */
301 if (rel
->howto
!= NULL
302 && rel
->howto
->pc_relative
303 && ! rel
->howto
->pcrel_offset
304 && rel
->howto
->rightshift
== 0
305 && rel
->howto
->size
== 2
306 && rel
->howto
->bitsize
== 32
307 && rel
->howto
->bitpos
== 0
308 && rel
->howto
->src_mask
== 0xffffffff
309 && rel
->howto
->dst_mask
== 0xffffffff)
313 /* When pcrel_offset is not set, it means that the negative
314 of the address of the memory location is stored in the
315 memory location. We must add it back in. */
316 val
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ rel
->address
- offset
);
318 bfd_put_32 (abfd
, val
, (bfd_byte
*) data
+ rel
->address
- offset
);
320 rel
->howto
= &nlm_i386_pcrel_howto
;
327 /* Read a NetWare i386 import record. */
330 nlm_i386_read_import (bfd
* abfd
, nlmNAME (symbol_type
) * sym
)
332 struct nlm_relent
*nlm_relocs
; /* Relocation records for symbol. */
333 bfd_size_type rcount
; /* Number of relocs. */
334 bfd_byte temp
[NLM_TARGET_LONG_SIZE
]; /* Temporary 32-bit value. */
335 unsigned char symlength
; /* Length of symbol name. */
338 if (bfd_bread (& symlength
, (bfd_size_type
) sizeof (symlength
), abfd
)
339 != sizeof (symlength
))
341 sym
-> symbol
.the_bfd
= abfd
;
342 name
= bfd_alloc (abfd
, (bfd_size_type
) symlength
+ 1);
345 if (bfd_bread (name
, (bfd_size_type
) symlength
, abfd
) != symlength
)
347 name
[symlength
] = '\0';
348 sym
-> symbol
.name
= name
;
349 sym
-> symbol
.flags
= 0;
350 sym
-> symbol
.value
= 0;
351 sym
-> symbol
.section
= bfd_und_section_ptr
;
352 if (bfd_bread (temp
, (bfd_size_type
) sizeof (temp
), abfd
) != sizeof (temp
))
354 rcount
= H_GET_32 (abfd
, temp
);
355 nlm_relocs
= bfd_alloc (abfd
, rcount
* sizeof (struct nlm_relent
));
358 sym
-> relocs
= nlm_relocs
;
360 while (sym
-> rcnt
< rcount
)
364 if (! nlm_i386_read_reloc (abfd
, sym
, §ion
, &nlm_relocs
-> reloc
))
366 nlm_relocs
-> section
= section
;
373 /* Write out an external reference. */
376 nlm_i386_write_external (bfd
*abfd
,
379 struct reloc_and_sec
*relocs
)
383 unsigned char temp
[NLM_TARGET_LONG_SIZE
];
385 len
= strlen (sym
->name
);
386 if ((bfd_bwrite (&len
, (bfd_size_type
) sizeof (bfd_byte
), abfd
)
387 != sizeof (bfd_byte
))
388 || bfd_bwrite (sym
->name
, (bfd_size_type
) len
, abfd
) != len
)
391 bfd_put_32 (abfd
, count
, temp
);
392 if (bfd_bwrite (temp
, (bfd_size_type
) sizeof (temp
), abfd
) != sizeof (temp
))
395 for (i
= 0; i
< count
; i
++)
396 if (! nlm_i386_write_import (abfd
, relocs
[i
].sec
, relocs
[i
].rel
))
404 static const struct nlm_backend_data nlm32_i386_backend
=
406 "NetWare Loadable Module\032",
407 sizeof (Nlm32_i386_External_Fixed_Header
),
408 0, /* Optional_prefix_size. */
412 0, /* Backend_object_p. */
413 0, /* Write_prefix_func. */
415 nlm_i386_mangle_relocs
,
416 nlm_i386_read_import
,
417 nlm_i386_write_import
,
418 0, /* Set_public_section. */
419 0, /* Set_public_offset. */
420 nlm_swap_fixed_header_in
,
421 nlm_swap_fixed_header_out
,
422 nlm_i386_write_external
,
423 0, /* Write_export. */
426 #define TARGET_LITTLE_NAME "nlm32-i386"
427 #define TARGET_LITTLE_SYM nlmNAME (i386_vec)
428 #define TARGET_BACKEND_DATA & nlm32_i386_backend
430 #include "nlm-target.h"