diff options
-rw-r--r-- | bfd/ChangeLog | 14 | ||||
-rw-r--r-- | bfd/nlm32-ppc.c | 278 | ||||
-rw-r--r-- | bfd/nlmcode.h | 29 |
3 files changed, 307 insertions, 14 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index c8f8c18..2602e18 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +Wed Apr 20 14:15:21 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) +start-sanitize-powerpc-netware + + * nlm32-ppc.c: Complete rewrite for new version of PowerPC + NetWare. Old code still present, but ifdeffed out. +end-sanitize-powerpc-netware + + * nlmcode.h (nlm_swap_auxiliary_headers_in): Don't assume a + particular format for the customer header. Allocate a block of + memory and read it into that. + (nlm_swap_auxiliary_headers_out): Write out the block of memory. + (nlm_compute_section_file_positions): Include length of customer + header when computing its size. + Mon Apr 18 14:27:17 1994 Jeffrey A. Law (law@snake.cs.utah.edu) * som.c (som_prep_headers): Get the space's number from the diff --git a/bfd/nlm32-ppc.c b/bfd/nlm32-ppc.c index c46f94b..62ac3d4 100644 --- a/bfd/nlm32-ppc.c +++ b/bfd/nlm32-ppc.c @@ -21,6 +21,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "sysdep.h" #include "libbfd.h" +/* The format of a PowerPC NLM changed. Define OLDFORMAT to get the + old format. */ + #define ARCH_SIZE 32 #include "nlm/ppc-ext.h" @@ -28,23 +31,41 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "libnlm.h" +#ifdef OLDFORMAT static boolean nlm_powerpc_backend_object_p PARAMS ((bfd *)); static boolean nlm_powerpc_write_prefix PARAMS ((bfd *)); +#endif + static boolean nlm_powerpc_read_reloc PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *)); static boolean nlm_powerpc_mangle_relocs PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type)); static boolean nlm_powerpc_read_import PARAMS ((bfd *, nlmNAME(symbol_type) *)); + +#ifdef OLDFORMAT static boolean nlm_powerpc_write_reloc PARAMS ((bfd *, asection *, arelent *, int)); +#endif + static boolean nlm_powerpc_write_import PARAMS ((bfd *, asection *, arelent *)); static boolean nlm_powerpc_write_external PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *)); + +#ifndef OLDFORMAT +static boolean nlm_powerpc_set_public_section + PARAMS ((bfd *, nlmNAME(symbol_type) *)); +static bfd_vma nlm_powerpc_get_public_offset + PARAMS ((bfd *, asymbol *)); +#endif +#ifdef OLDFORMAT + +/* The prefix header is only used in the old format. */ + /* PowerPC NLM's have a prefix header before the standard NLM. This function reads it in, verifies the version, and seeks the bfd to the location before the regular NLM header. */ @@ -85,7 +106,94 @@ nlm_powerpc_write_prefix (abfd) return true; } + +#endif /* OLDFORMAT */ +#ifndef OLDFORMAT + +/* There is only one type of reloc in a PowerPC NLM. */ + +static reloc_howto_type nlm_powerpc_howto = + HOWTO (0, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false); /* pcrel_offset */ + +/* Read a PowerPC NLM reloc. */ + +static boolean +nlm_powerpc_read_reloc (abfd, sym, secp, rel) + bfd *abfd; + nlmNAME(symbol_type) *sym; + asection **secp; + arelent *rel; +{ + bfd_byte temp[4]; + bfd_vma val; + const char *name; + + if (bfd_read (temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return false; + + val = bfd_get_32 (abfd, temp); + + /* The value is a word offset into either the code or data segment. + This is the location which needs to be adjusted. + + The high bit is 0 if the value is an offset into the data + segment, or 1 if the value is an offset into the text segment. + + If this is a relocation fixup rather than an imported symbol (the + sym argument is NULL), then the second most significant bit is 0 + if the address of the data segment should be added to the + location addressed by the value, or 1 if the address of the text + segment should be added. + + If this is an imported symbol, the second most significant bit is + not used and must be 0. */ + + if ((val & NLM_HIBIT) == 0) + name = NLM_INITIALIZED_DATA_NAME; + else + { + name = NLM_CODE_NAME; + val &=~ NLM_HIBIT; + } + *secp = bfd_get_section_by_name (abfd, NLM_CODE_NAME); + + if (sym == NULL) + { + if ((val & (NLM_HIBIT >> 1)) == 0) + name = NLM_INITIALIZED_DATA_NAME; + else + { + name = NLM_CODE_NAME; + val &=~ (NLM_HIBIT >> 1); + } + rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr; + } + + rel->howto = &nlm_powerpc_howto; + + rel->address = val << 2; + rel->addend = 0; + + return true; +} + +#else /* OLDFORMAT */ + +/* This reloc handling is only applicable to the old format. */ + /* How to process the various reloc types. PowerPC NLMs use XCOFF reloc types, and I have just copied the XCOFF reloc table here. */ @@ -525,6 +633,8 @@ nlm_powerpc_read_reloc (abfd, sym, secp, rel) return true; } +#endif /* OLDFORMAT */ + /* Mangle PowerPC NLM relocs for output. */ static boolean @@ -595,6 +705,79 @@ nlm_powerpc_read_import (abfd, sym) return true; } +#ifndef OLDFORMAT + +/* Write a PowerPC NLM reloc. */ + +static boolean +nlm_powerpc_write_import (abfd, sec, rel) + bfd *abfd; + asection *sec; + arelent *rel; +{ + asymbol *sym; + bfd_vma val; + bfd_byte temp[4]; + + /* PowerPC NetWare only supports one kind of reloc. */ + if (rel->addend != 0 + || rel->howto == NULL + || rel->howto->rightshift != 0 + || rel->howto->size != 2 + || rel->howto->bitsize != 32 + || rel->howto->bitpos != 0 + || rel->howto->pc_relative + || (rel->howto->src_mask != 0xffffffff && rel->addend != 0) + || rel->howto->dst_mask != 0xffffffff) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + sym = *rel->sym_ptr_ptr; + + /* The value we write out is the offset into the appropriate + segment, rightshifted by two. This offset is the section vma, + adjusted by the vma of the lowest section in that segment, plus + the address of the relocation. */ + val = bfd_get_section_vma (abfd, sec) + rel->address; + if ((val & 3) != 0) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + val >>= 2; + + /* The high bit is 0 if the reloc is in the data section, or 1 if + the reloc is in the code section. */ + if (bfd_get_section_flags (abfd, sec) & SEC_DATA) + val -= nlm_get_data_low (abfd); + else + { + val -= nlm_get_text_low (abfd); + val |= NLM_HIBIT; + } + + if (bfd_get_section (sym) != &bfd_und_section) + { + /* This is an internal relocation fixup. The second most + significant bit is 0 if this is a reloc against the data + segment, or 1 if it is a reloc against the text segment. */ + if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE) + val |= NLM_HIBIT >> 1; + } + + bfd_put_32 (abfd, val, temp); + if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return false; + + return true; +} + +#else /* OLDFORMAT */ + +/* This is used for the reloc handling in the old format. */ + /* Write a PowerPC NLM reloc. */ static boolean @@ -709,6 +892,8 @@ nlm_powerpc_write_import (abfd, sec, rel) return nlm_powerpc_write_reloc (abfd, sec, rel, -1); } +#endif /* OLDFORMAT */ + /* Write a PowerPC NLM external symbol. This routine keeps a static count of the symbol index. FIXME: I don't know if this is necessary, and the index never gets reset. */ @@ -723,7 +908,9 @@ nlm_powerpc_write_external (abfd, count, sym, relocs) int i; bfd_byte len; unsigned char temp[NLM_TARGET_LONG_SIZE]; +#ifdef OLDFORMAT static int indx; +#endif len = strlen (sym->name); if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof(bfd_byte)) @@ -736,34 +923,121 @@ nlm_powerpc_write_external (abfd, count, sym, relocs) for (i = 0; i < count; i++) { - if (nlm_powerpc_write_reloc (abfd, relocs[i].sec, - relocs[i].rel, indx) == false) +#ifndef OLDFORMAT + if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel)) return false; +#else + if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec, + relocs[i].rel, indx)) + return false; +#endif } +#ifdef OLDFORMAT ++indx; +#endif return true; } + +#ifndef OLDFORMAT +/* PowerPC Netware uses a word offset, not a byte offset, for public + symbols. */ + +/* Set the section for a public symbol. */ + +static boolean +nlm_powerpc_set_public_section (abfd, sym) + bfd *abfd; + nlmNAME(symbol_type) *sym; +{ + if (sym->symbol.value & NLM_HIBIT) + { + sym->symbol.value &= ~NLM_HIBIT; + sym->symbol.flags |= BSF_FUNCTION; + sym->symbol.section = + bfd_get_section_by_name (abfd, NLM_CODE_NAME); + } + else + { + sym->symbol.section = + bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); + } + + sym->symbol.value <<= 2; + + return true; +} + +/* Get the offset to write out for a public symbol. */ + +static bfd_vma +nlm_powerpc_get_public_offset (abfd, sym) + bfd *abfd; + asymbol *sym; +{ + bfd_vma offset; + asection *sec; + + offset = bfd_asymbol_value (sym); + sec = bfd_get_section (sym); + if (sec->flags & SEC_CODE) + { + offset -= nlm_get_text_low (abfd); + offset |= NLM_HIBIT; + } + else if (sec->flags & (SEC_DATA | SEC_ALLOC)) + { + /* SEC_ALLOC is for the .bss section. */ + offset -= nlm_get_data_low (abfd); + } + else + { + /* We can't handle an exported symbol that is not in the code or + data segment. */ + bfd_set_error (bfd_error_invalid_operation); + /* FIXME: No way to return error. */ + abort (); + } + + return offset; +} + +#endif /* ! defined (OLDFORMAT) */ + #include "nlmswap.h" static const struct nlm_backend_data nlm32_powerpc_backend = { "NetWare PowerPC Module \032", sizeof (Nlm32_powerpc_External_Fixed_Header), +#ifndef OLDFORMAT + 0, /* optional_prefix_size */ +#else sizeof (struct nlm32_powerpc_external_prefix_header), +#endif bfd_arch_powerpc, 0, false, +#ifndef OLDFORMAT + 0, /* backend_object_p */ + 0, /* write_prefix */ +#else nlm_powerpc_backend_object_p, nlm_powerpc_write_prefix, +#endif nlm_powerpc_read_reloc, nlm_powerpc_mangle_relocs, nlm_powerpc_read_import, nlm_powerpc_write_import, +#ifndef OLDFORMAT + nlm_powerpc_set_public_section, + nlm_powerpc_get_public_offset, +#else 0, /* set_public_section */ 0, /* get_public_offset */ +#endif nlm_swap_fixed_header_in, nlm_swap_fixed_header_out, nlm_powerpc_write_external, diff --git a/bfd/nlmcode.h b/bfd/nlmcode.h index 13e4319..61e748f 100644 --- a/bfd/nlmcode.h +++ b/bfd/nlmcode.h @@ -491,16 +491,20 @@ nlm_swap_auxiliary_headers_in (abfd) else if (strncmp (tempstr, "CuStHeAd", 8) == 0) { Nlm_External_Custom_Header thdr; - if (bfd_read ((PTR) & thdr, sizeof (thdr), 1, abfd) != sizeof (thdr)) - return (false); + if (bfd_read ((PTR) &thdr, sizeof (thdr), 1, abfd) != sizeof (thdr)) + return false; memcpy (nlm_custom_header (abfd)->stamp, thdr.stamp, sizeof (thdr.stamp)); nlm_custom_header (abfd)->dataLength = get_word (abfd, (bfd_byte *) thdr.dataLength); - nlm_custom_header (abfd)->debugRecOffset = - get_word (abfd, (bfd_byte *) thdr.debugRecOffset); - nlm_custom_header (abfd)->debugRecLength = - get_word (abfd, (bfd_byte *) thdr.debugRecLength); + nlm_custom_header (abfd)->data = + bfd_alloc (abfd, nlm_custom_header (abfd)->dataLength); + if (nlm_custom_header (abfd)->data == NULL) + return false; + if (bfd_read (nlm_custom_header (abfd)->data, 1, + nlm_custom_header (abfd)->dataLength, abfd) + != nlm_custom_header (abfd)->dataLength) + return false; } else if (strncmp (tempstr, "CoPyRiGhT=", 10) == 0) { @@ -685,11 +689,11 @@ nlm_swap_auxiliary_headers_out (abfd) memcpy (thdr.stamp, "CuStHeAd", 8); put_word (abfd, (bfd_vma) nlm_custom_header (abfd)->dataLength, (bfd_byte *) thdr.dataLength); - put_word (abfd, (bfd_vma) nlm_custom_header (abfd)->debugRecOffset, - (bfd_byte *) thdr.debugRecOffset); - put_word (abfd, (bfd_vma) nlm_custom_header (abfd)->debugRecLength, - (bfd_byte *) thdr.debugRecLength); - if (bfd_write ((PTR) & thdr, sizeof (thdr), 1, abfd) != sizeof (thdr)) + if (bfd_write ((PTR) &thdr, sizeof (thdr), 1, abfd) != sizeof (thdr)) + return false; + if (bfd_write (nlm_custom_header (abfd)->data, 1, + nlm_custom_header (abfd)->dataLength, abfd) + != nlm_custom_header (abfd)->dataLength) return false; } @@ -1249,7 +1253,8 @@ nlm_compute_section_file_positions (abfd) sofar += sizeof (Nlm_External_Extended_Header); if (find_nonzero ((PTR) nlm_custom_header (abfd), sizeof (Nlm_Internal_Custom_Header))) - sofar += sizeof (Nlm_External_Custom_Header); + sofar += (sizeof (Nlm_External_Custom_Header) + + nlm_custom_header (abfd)->dataLength); if (find_nonzero ((PTR) nlm_copyright_header (abfd), sizeof (Nlm_Internal_Copyright_Header))) sofar += (sizeof (Nlm_External_Copyright_Header) |