diff options
Diffstat (limited to 'gnu')
35 files changed, 12348 insertions, 0 deletions
diff --git a/gnu/usr.bin/binutils/bfd/aout-sparcle.c b/gnu/usr.bin/binutils/bfd/aout-sparcle.c new file mode 100644 index 00000000000..903b1367cb3 --- /dev/null +++ b/gnu/usr.bin/binutils/bfd/aout-sparcle.c @@ -0,0 +1,32 @@ +/* BFD backend for sparc little-endian aout binaries. + Copyright (C) 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGETNAME "a.out-sparc-little" +#define MY(OP) CAT(sparcle_aout_,OP) + +#include "bfd.h" +#include "bfdlink.h" +#include "libaout.h" + +#define MACHTYPE_OK(mtype) ((mtype) == M_SPARC || (mtype) == M_SPARCLET) + +/* Include the usual a.out support. */ +#define TARGET_IS_LITTLE_ENDIAN_P +#include "aoutf1.h" diff --git a/gnu/usr.bin/binutils/bfd/config.h-vms b/gnu/usr.bin/binutils/bfd/config.h-vms new file mode 100644 index 00000000000..66c4344973d --- /dev/null +++ b/gnu/usr.bin/binutils/bfd/config.h-vms @@ -0,0 +1,59 @@ +/* config.h-vms. Generated by hand by Klaus Kämpf, kkaempf@didymus.rmi.de. */ +/* config.in. Generated automatically from configure.in by autoheader. */ + +/* Whether malloc must be declared even if <stdlib.h> is included. */ +/* #undef NEED_DECLARATION_MALLOC */ + +/* Whether free must be declared even if <stdlib.h> is included. */ +/* #undef NEED_DECLARATION_FREE */ + +/* Define if you have a working `mmap' system call. */ +/* #define HAVE_MMAP 1 */ + +/* Do we need to use the b modifier when opening binary files? */ +/* #undef USE_BINARY_FOPEN */ + +/* Name of host specific header file to include in trad-core.c. */ +/* #undef TRAD_HEADER */ + +/* Define only if <sys/procfs.h> is available *and* it defines prstatus_t. */ +/* #undef HAVE_SYS_PROCFS_H */ + +/* Do we really want to use mmap if it's available? */ +/* #undef USE_MMAP */ + +/* Define if you have the fcntl function. */ +#define HAVE_FCNTL 1 + +/* Define if you have the getpagesize function. */ +#define HAVE_GETPAGESIZE 1 + +/* Define if you have the madvise function. */ +#define HAVE_MADVISE 1 + +/* Define if you have the mprotect function. */ +#define HAVE_MPROTECT 1 + +/* Define if you have the <fcntl.h> header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the <stddef.h> header file. */ +#define HAVE_STDDEF_H 1 + +/* Define if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define if you have the <sys/file.h> header file. */ +#define HAVE_SYS_FILE_H 1 + +/* Define if you have the <time.h> header file. */ +#define HAVE_TIME_H 1 + +/* Define if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 diff --git a/gnu/usr.bin/binutils/bfd/elf32-sh.c b/gnu/usr.bin/binutils/bfd/elf32-sh.c new file mode 100644 index 00000000000..c65114caac3 --- /dev/null +++ b/gnu/usr.bin/binutils/bfd/elf32-sh.c @@ -0,0 +1,1905 @@ +/* Hitachi SH specific support for 32-bit ELF + Copyright 1996 Free Software Foundation, Inc. + Contributed by Ian Lance Taylor, Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "elf-bfd.h" + +static bfd_reloc_status_type sh_elf_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static bfd_reloc_status_type sh_elf_ignore_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static reloc_howto_type *sh_elf_reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); +static void sh_elf_info_to_howto + PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); +static boolean sh_elf_relax_section + PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *)); +static boolean sh_elf_relax_delete_bytes + PARAMS ((bfd *, asection *, bfd_vma, int)); +static boolean sh_elf_align_loads + PARAMS ((bfd *, asection *, Elf_Internal_Rela *, bfd_byte *, boolean *)); +static boolean sh_elf_swap_insns + PARAMS ((bfd *, asection *, PTR, bfd_byte *, bfd_vma)); +static boolean sh_elf_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); +static bfd_byte *sh_elf_get_relocated_section_contents + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *, boolean, asymbol **)); + +enum sh_reloc_type +{ + R_SH_NONE = 0, + R_SH_DIR32, + R_SH_REL32, + R_SH_DIR8WPN, + R_SH_IND12W, + R_SH_DIR8WPL, + R_SH_DIR8WPZ, + R_SH_DIR8BP, + R_SH_DIR8W, + R_SH_DIR8L, + FIRST_INVALID_RELOC, + LAST_INVALID_RELOC = 24, + /* The remaining relocs are a GNU extension used for relaxation. We + use the same constants as COFF uses, not that it really matters. */ + R_SH_SWITCH16 = 25, + R_SH_SWITCH32, + R_SH_USES, + R_SH_COUNT, + R_SH_ALIGN, + R_SH_CODE, + R_SH_DATA, + R_SH_LABEL, + R_SH_max +}; + +static reloc_howto_type sh_elf_howto_table[] = +{ + /* No relocation. */ + HOWTO (R_SH_NONE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + sh_elf_reloc, /* special_function */ + "R_SH_NONE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32 bit absolute relocation. Setting partial_inplace to true and + src_mask to a non-zero value is similar to the COFF toolchain. */ + HOWTO (R_SH_DIR32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + sh_elf_reloc, /* special_function */ + "R_SH_DIR32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32 bit PC relative relocation. */ + HOWTO (R_SH_REL32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + sh_elf_reloc, /* special_function */ + "R_SH_REL32", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffff, /* dst_mask */ + true), /* pcrel_offset */ + + /* 8 bit PC relative branch divided by 2. */ + HOWTO (R_SH_DIR8WPN, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + sh_elf_reloc, /* special_function */ + "R_SH_DIR8WPN", /* name */ + true, /* partial_inplace */ + 0xff, /* src_mask */ + 0xff, /* dst_mask */ + true), /* pcrel_offset */ + + /* 12 bit PC relative branch divided by 2. */ + HOWTO (R_SH_IND12W, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + sh_elf_reloc, /* special_function */ + "R_SH_IND12W", /* name */ + true, /* partial_inplace */ + 0xfff, /* src_mask */ + 0xfff, /* dst_mask */ + true), /* pcrel_offset */ + + /* 8 bit unsigned PC relative divided by 4. */ + HOWTO (R_SH_DIR8WPL, /* type */ + 2, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_elf_reloc, /* special_function */ + "R_SH_DIR8WPL", /* name */ + true, /* partial_inplace */ + 0xff, /* src_mask */ + 0xff, /* dst_mask */ + true), /* pcrel_offset */ + + /* 8 bit unsigned PC relative divided by 2. */ + HOWTO (R_SH_DIR8WPZ, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_elf_reloc, /* special_function */ + "R_SH_DIR8WPZ", /* name */ + true, /* partial_inplace */ + 0xff, /* src_mask */ + 0xff, /* dst_mask */ + true), /* pcrel_offset */ + + /* 8 bit GBR relative. FIXME: This only makes sense if we have some + special symbol for the GBR relative area, and that is not + implemented. */ + HOWTO (R_SH_DIR8BP, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_elf_reloc, /* special_function */ + "R_SH_DIR8BP", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xff, /* dst_mask */ + true), /* pcrel_offset */ + + /* 8 bit GBR relative divided by 2. FIXME: This only makes sense if + we have some special symbol for the GBR relative area, and that + is not implemented. */ + HOWTO (R_SH_DIR8W, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_elf_reloc, /* special_function */ + "R_SH_DIR8W", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xff, /* dst_mask */ + true), /* pcrel_offset */ + + /* 8 bit GBR relative divided by 4. FIXME: This only makes sense if + we have some special symbol for the GBR relative area, and that + is not implemented. */ + HOWTO (R_SH_DIR8L, /* type */ + 2, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_elf_reloc, /* special_function */ + "R_SH_DIR8L", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xff, /* dst_mask */ + true), /* pcrel_offset */ + + { 10 }, + { 11 }, + { 12 }, + { 13 }, + { 14 }, + { 15 }, + { 16 }, + { 17 }, + { 18 }, + { 19 }, + { 20 }, + { 21 }, + { 22 }, + { 23 }, + { 24 }, + + /* The remaining relocs are a GNU extension used for relaxing. The + final pass of the linker never needs to do anything with any of + these relocs. Any required operations are handled by the + relaxation code. */ + + /* A 16 bit switch table entry. This is generated for an expression + such as ``.word L1 - L2''. The offset holds the difference + between the reloc address and L2. */ + HOWTO (R_SH_SWITCH16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_elf_ignore_reloc, /* special_function */ + "R_SH_SWITCH16", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + true), /* pcrel_offset */ + + /* A 32 bit switch table entry. This is generated for an expression + such as ``.long L1 - L2''. The offset holds the difference + between the reloc address and L2. */ + HOWTO (R_SH_SWITCH32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_elf_ignore_reloc, /* special_function */ + "R_SH_SWITCH32", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + true), /* pcrel_offset */ + + /* Indicates a .uses pseudo-op. The compiler will generate .uses + pseudo-ops when it finds a function call which can be relaxed. + The offset field holds the PC relative offset to the instruction + which loads the register used in the function call. */ + HOWTO (R_SH_USES, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_elf_ignore_reloc, /* special_function */ + "R_SH_USES", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + true), /* pcrel_offset */ + + /* The assembler will generate this reloc for addresses referred to + by the register loads associated with USES relocs. The offset + field holds the number of times the address is referenced in the + object file. */ + HOWTO (R_SH_COUNT, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_elf_ignore_reloc, /* special_function */ + "R_SH_COUNT", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + true), /* pcrel_offset */ + + /* Indicates an alignment statement. The offset field is the power + of 2 to which subsequent portions of the object file must be + aligned. */ + HOWTO (R_SH_ALIGN, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_elf_ignore_reloc, /* special_function */ + "R_SH_ALIGN", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + true), /* pcrel_offset */ + + /* The assembler will generate this reloc before a block of + instructions. A section should be processed as assumining it + contains data, unless this reloc is seen. */ + HOWTO (R_SH_CODE, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_elf_ignore_reloc, /* special_function */ + "R_SH_CODE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + true), /* pcrel_offset */ + + /* The assembler will generate this reloc after a block of + instructions when it sees data that is not instructions. */ + HOWTO (R_SH_DATA, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_elf_ignore_reloc, /* special_function */ + "R_SH_DATA", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + true), /* pcrel_offset */ + + /* The assembler generates this reloc for each label within a block + of instructions. This permits the linker to avoid swapping + instructions which are the targets of branches. */ + HOWTO (R_SH_LABEL, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_elf_ignore_reloc, /* special_function */ + "R_SH_LABEL", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + true) /* pcrel_offset */ +}; + +/* This function is used for normal relocs. This is like the COFF + function, and is almost certainly incorrect for other ELF targets. */ + +static bfd_reloc_status_type +sh_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol_in; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + unsigned long insn; + bfd_vma sym_value; + enum sh_reloc_type r_type; + bfd_vma addr = reloc_entry->address; + bfd_byte *hit_data = addr + (bfd_byte *) data; + + r_type = (enum sh_reloc_type) reloc_entry->howto->type; + + if (output_bfd != NULL) + { + /* Partial linking--do nothing. */ + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* Almost all relocs have to do with relaxing. If any work must be + done for them, it has been done in sh_relax_section. */ + if (r_type != R_SH_DIR32 + && (r_type != R_SH_IND12W + || (symbol_in->flags & BSF_LOCAL) != 0)) + return bfd_reloc_ok; + + if (symbol_in != NULL + && bfd_is_und_section (symbol_in->section)) + return bfd_reloc_undefined; + + if (bfd_is_com_section (symbol_in->section)) + sym_value = 0; + else + sym_value = (symbol_in->value + + symbol_in->section->output_section->vma + + symbol_in->section->output_offset); + + switch (r_type) + { + case R_SH_DIR32: + insn = bfd_get_32 (abfd, hit_data); + insn += sym_value + reloc_entry->addend; + bfd_put_32 (abfd, insn, hit_data); + break; + case R_SH_IND12W: + insn = bfd_get_16 (abfd, hit_data); + sym_value += reloc_entry->addend; + sym_value -= (input_section->output_section->vma + + input_section->output_offset + + addr + + 4); + sym_value += (insn & 0xfff) << 1; + if (insn & 0x800) + sym_value -= 0x1000; + insn = (insn & 0xf000) | (sym_value & 0xfff); + bfd_put_16 (abfd, insn, hit_data); + if (sym_value < (bfd_vma) -0x1000 || sym_value >= 0x1000) + return bfd_reloc_overflow; + break; + default: + abort (); + break; + } + + return bfd_reloc_ok; +} + +/* This function is used for relocs which are only used for relaxing, + which the linker should otherwise ignore. */ + +static bfd_reloc_status_type +sh_elf_ignore_reloc (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + if (output_bfd != NULL) + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; +} + +/* This structure is used to map BFD reloc codes to SH ELF relocs. */ + +struct elf_reloc_map +{ + unsigned char bfd_reloc_val; + unsigned char elf_reloc_val; +}; + +/* An array mapping BFD reloc codes to SH ELF relocs. */ + +static const struct elf_reloc_map sh_reloc_map[] = +{ + { BFD_RELOC_NONE, R_SH_NONE }, + { BFD_RELOC_32, R_SH_DIR32 }, + { BFD_RELOC_CTOR, R_SH_DIR32 }, + { BFD_RELOC_32_PCREL, R_SH_REL32 }, + { BFD_RELOC_SH_PCDISP8BY2, R_SH_DIR8WPN }, + { BFD_RELOC_SH_PCDISP12BY2, R_SH_IND12W }, + { BFD_RELOC_SH_PCRELIMM8BY2, R_SH_DIR8WPZ }, + { BFD_RELOC_SH_PCRELIMM8BY4, R_SH_DIR8WPL }, + { BFD_RELOC_SH_SWITCH16, R_SH_SWITCH16 }, + { BFD_RELOC_SH_SWITCH32, R_SH_SWITCH32 }, + { BFD_RELOC_SH_USES, R_SH_USES }, + { BFD_RELOC_SH_COUNT, R_SH_COUNT }, + { BFD_RELOC_SH_ALIGN, R_SH_ALIGN }, + { BFD_RELOC_SH_CODE, R_SH_CODE }, + { BFD_RELOC_SH_DATA, R_SH_DATA }, + { BFD_RELOC_SH_LABEL, R_SH_LABEL } +}; + +/* Given a BFD reloc code, return the howto structure for the + corresponding SH ELf reloc. */ + +static reloc_howto_type * +sh_elf_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + unsigned int i; + + for (i = 0; i < sizeof (sh_reloc_map) / sizeof (struct elf_reloc_map); i++) + { + if (sh_reloc_map[i].bfd_reloc_val == code) + return &sh_elf_howto_table[(int) sh_reloc_map[i].elf_reloc_val]; + } + + return NULL; +} + +/* Given an ELF reloc, fill in the howto field of a relent. */ + +static void +sh_elf_info_to_howto (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf_Internal_Rela *dst; +{ + unsigned int r; + + r = ELF32_R_TYPE (dst->r_info); + + BFD_ASSERT (r < (unsigned int) R_SH_max); + BFD_ASSERT (r < FIRST_INVALID_RELOC || r > LAST_INVALID_RELOC); + + cache_ptr->howto = &sh_elf_howto_table[r]; +} + +/* This function handles relaxing for SH ELF. See the corresponding + function in coff-sh.c for a description of what this does. FIXME: + There is a lot of duplication here between this code and the COFF + specific code. The format of relocs and symbols is wound deeply + into this code, but it would still be better if the duplication + could be eliminated somehow. Note in particular that although both + functions use symbols like R_SH_CODE, those symbols have different + values; in coff-sh.c they come from include/coff/sh.h, whereas here + they come from enum sh_reloc_type in this file. */ + +static boolean +sh_elf_relax_section (abfd, sec, link_info, again) + bfd *abfd; + asection *sec; + struct bfd_link_info *link_info; + boolean *again; +{ + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *free_relocs = NULL; + boolean have_code; + Elf_Internal_Rela *irel, *irelend; + bfd_byte *contents = NULL; + bfd_byte *free_contents = NULL; + Elf32_External_Sym *extsyms = NULL; + Elf32_External_Sym *free_extsyms = NULL; + + *again = false; + + if (link_info->relocateable + || (sec->flags & SEC_RELOC) == 0 + || sec->reloc_count == 0) + return true; + + /* If this is the first time we have been called for this section, + initialize the cooked size. */ + if (sec->_cooked_size == 0) + sec->_cooked_size = sec->_raw_size; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + internal_relocs = (_bfd_elf32_link_read_relocs + (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL, + link_info->keep_memory)); + if (internal_relocs == NULL) + goto error_return; + if (! link_info->keep_memory) + free_relocs = internal_relocs; + + have_code = false; + + irelend = internal_relocs + sec->reloc_count; + for (irel = internal_relocs; irel < irelend; irel++) + { + bfd_vma laddr, paddr, symval; + unsigned short insn; + Elf_Internal_Rela *irelfn, *irelscan, *irelcount; + bfd_signed_vma foff; + + if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_CODE) + have_code = true; + + if (ELF32_R_TYPE (irel->r_info) != (int) R_SH_USES) + continue; + + /* Get the section contents. */ + if (contents == NULL) + { + if (elf_section_data (sec)->this_hdr.contents != NULL) + contents = elf_section_data (sec)->this_hdr.contents; + else + { + contents = (bfd_byte *) bfd_malloc (sec->_raw_size); + if (contents == NULL) + goto error_return; + free_contents = contents; + + if (! bfd_get_section_contents (abfd, sec, contents, + (file_ptr) 0, sec->_raw_size)) + goto error_return; + } + } + + /* The r_addend field of the R_SH_USES reloc will point us to + the register load. The 4 is because the r_addend field is + computed as though it were a jump offset, which are based + from 4 bytes after the jump instruction. */ + laddr = irel->r_offset + 4 + irel->r_addend; + if (laddr >= sec->_raw_size) + { + (*_bfd_error_handler) ("%s: 0x%lx: warning: bad R_SH_USES offset", + bfd_get_filename (abfd), + (unsigned long) irel->r_offset); + continue; + } + insn = bfd_get_16 (abfd, contents + laddr); + + /* If the instruction is not mov.l NN,rN, we don't know what to + do. */ + if ((insn & 0xf000) != 0xd000) + { + ((*_bfd_error_handler) + ("%s: 0x%lx: warning: R_SH_USES points to unrecognized insn 0x%x", + bfd_get_filename (abfd), (unsigned long) irel->r_offset, insn)); + continue; + } + + /* Get the address from which the register is being loaded. The + displacement in the mov.l instruction is quadrupled. It is a + displacement from four bytes after the movl instruction, but, + before adding in the PC address, two least significant bits + of the PC are cleared. We assume that the section is aligned + on a four byte boundary. */ + paddr = insn & 0xff; + paddr *= 4; + paddr += (laddr + 4) &~ 3; + if (paddr >= sec->_raw_size) + { + ((*_bfd_error_handler) + ("%s: 0x%lx: warning: bad R_SH_USES load offset", + bfd_get_filename (abfd), (unsigned long) irel->r_offset)); + continue; + } + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + for (irelfn = internal_relocs; irelfn < irelend; irelfn++) + if (irelfn->r_offset == paddr + && ELF32_R_TYPE (irelfn->r_info) == (int) R_SH_DIR32) + break; + if (irelfn >= irelend) + { + ((*_bfd_error_handler) + ("%s: 0x%lx: warning: could not find expected reloc", + bfd_get_filename (abfd), (unsigned long) paddr)); + continue; + } + + /* Read the local symbols. */ + if (extsyms == NULL) + { + if (symtab_hdr->contents != NULL) + extsyms = (Elf32_External_Sym *) symtab_hdr->contents; + else + { + extsyms = ((Elf32_External_Sym *) + bfd_malloc (symtab_hdr->sh_info + * sizeof (Elf32_External_Sym))); + if (extsyms == NULL) + goto error_return; + free_extsyms = extsyms; + if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0 + || (bfd_read (extsyms, sizeof (Elf32_External_Sym), + symtab_hdr->sh_info, abfd) + != (symtab_hdr->sh_info * sizeof (Elf32_External_Sym)))) + goto error_return; + } + } + + /* Get the value of the symbol referred to by the reloc. */ + if (ELF32_R_SYM (irelfn->r_info) < symtab_hdr->sh_info) + { + Elf_Internal_Sym isym; + + /* A local symbol. */ + bfd_elf32_swap_symbol_in (abfd, + extsyms + ELF32_R_SYM (irelfn->r_info), + &isym); + + if (isym.st_shndx != _bfd_elf_section_from_bfd_section (abfd, sec)) + { + ((*_bfd_error_handler) + ("%s: 0x%lx: warning: symbol in unexpected section", + bfd_get_filename (abfd), (unsigned long) paddr)); + continue; + } + + symval = (isym.st_value + + sec->output_section->vma + + sec->output_offset); + } + else + { + unsigned long indx; + struct elf_link_hash_entry *h; + + indx = ELF32_R_SYM (irelfn->r_info) - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + BFD_ASSERT (h != NULL); + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + { + /* This appears to be a reference to an undefined + symbol. Just ignore it--it will be caught by the + regular reloc processing. */ + continue; + } + + symval = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + } + + symval += bfd_get_32 (abfd, contents + paddr); + + /* See if this function call can be shortened. */ + foff = (symval + - (irel->r_offset + + sec->output_section->vma + + sec->output_offset + + 4)); + if (foff < -0x1000 || foff >= 0x1000) + { + /* After all that work, we can't shorten this function call. */ + continue; + } + + /* Shorten the function call. */ + + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ + + elf_section_data (sec)->relocs = internal_relocs; + free_relocs = NULL; + + elf_section_data (sec)->this_hdr.contents = contents; + free_contents = NULL; + + symtab_hdr->contents = (bfd_byte *) extsyms; + free_extsyms = NULL; + + /* Replace the jsr with a bsr. */ + + /* Change the R_SH_USES reloc into an R_SH_IND12W reloc, and + replace the jsr with a bsr. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irelfn->r_info), R_SH_IND12W); + if (ELF32_R_SYM (irelfn->r_info) < symtab_hdr->sh_info) + { + /* If this needs to be changed because of future relaxing, + it will be handled here like other internal IND12W + relocs. */ + bfd_put_16 (abfd, + 0xb000 | ((foff >> 1) & 0xfff), + contents + irel->r_offset); + } + else + { + /* We can't fully resolve this yet, because the external + symbol value may be changed by future relaxing. We let + the final link phase handle it. */ + bfd_put_16 (abfd, 0xb000, contents + irel->r_offset); + } + + /* See if there is another R_SH_USES reloc referring to the same + register load. */ + for (irelscan = internal_relocs; irelscan < irelend; irelscan++) + if (ELF32_R_TYPE (irelscan->r_info) == (int) R_SH_USES + && laddr == irelscan->r_offset + 4 + irelscan->r_addend) + break; + if (irelscan < irelend) + { + /* Some other function call depends upon this register load, + and we have not yet converted that function call. + Indeed, we may never be able to convert it. There is + nothing else we can do at this point. */ + continue; + } + + /* Look for a R_SH_COUNT reloc on the location where the + function address is stored. Do this before deleting any + bytes, to avoid confusion about the address. */ + for (irelcount = internal_relocs; irelcount < irelend; irelcount++) + if (irelcount->r_offset == paddr + && ELF32_R_TYPE (irelcount->r_info) == (int) R_SH_COUNT) + break; + + /* Delete the register load. */ + if (! sh_elf_relax_delete_bytes (abfd, sec, laddr, 2)) + goto error_return; + + /* That will change things, so, just in case it permits some + other function call to come within range, we should relax + again. Note that this is not required, and it may be slow. */ + *again = true; + + /* Now check whether we got a COUNT reloc. */ + if (irelcount >= irelend) + { + ((*_bfd_error_handler) + ("%s: 0x%lx: warning: could not find expected COUNT reloc", + bfd_get_filename (abfd), (unsigned long) paddr)); + continue; + } + + /* The number of uses is stored in the r_addend field. We've + just deleted one. */ + if (irelcount->r_addend == 0) + { + ((*_bfd_error_handler) ("%s: 0x%lx: warning: bad count", + bfd_get_filename (abfd), + (unsigned long) paddr)); + continue; + } + + --irelcount->r_addend; + + /* If there are no more uses, we can delete the address. Reload + the address from irelfn, in case it was changed by the + previous call to sh_elf_relax_delete_bytes. */ + if (irelcount->r_addend == 0) + { + if (! sh_elf_relax_delete_bytes (abfd, sec, irelfn->r_offset, 4)) + goto error_return; + } + + /* We've done all we can with that function call. */ + } + + /* Look for load and store instructions that we can align on four + byte boundaries. */ + if (have_code) + { + boolean swapped; + + /* Get the section contents. */ + if (contents == NULL) + { + if (elf_section_data (sec)->this_hdr.contents != NULL) + contents = elf_section_data (sec)->this_hdr.contents; + else + { + contents = (bfd_byte *) bfd_malloc (sec->_raw_size); + if (contents == NULL) + goto error_return; + free_contents = contents; + + if (! bfd_get_section_contents (abfd, sec, contents, + (file_ptr) 0, sec->_raw_size)) + goto error_return; + } + } + + if (! sh_elf_align_loads (abfd, sec, internal_relocs, contents, + &swapped)) + goto error_return; + + if (swapped) + { + elf_section_data (sec)->relocs = internal_relocs; + free_relocs = NULL; + + elf_section_data (sec)->this_hdr.contents = contents; + free_contents = NULL; + + symtab_hdr->contents = (bfd_byte *) extsyms; + free_extsyms = NULL; + } + } + + if (free_relocs != NULL) + { + free (free_relocs); + free_relocs = NULL; + } + + if (free_contents != NULL) + { + if (! link_info->keep_memory) + free (free_contents); + else + { + /* Cache the section contents for elf_link_input_bfd. */ + elf_section_data (sec)->this_hdr.contents = contents; + } + free_contents = NULL; + } + + if (free_extsyms != NULL) + { + if (! link_info->keep_memory) + free (free_extsyms); + else + { + /* Cache the symbols for elf_link_input_bfd. */ + symtab_hdr->contents = extsyms; + } + free_extsyms = NULL; + } + + return true; + + error_return: + if (free_relocs != NULL) + free (free_relocs); + if (free_contents != NULL) + free (free_contents); + if (free_extsyms != NULL) + free (free_extsyms); + return false; +} + +/* Delete some bytes from a section while relaxing. FIXME: There is a + lot of duplication between this function and sh_relax_delete_bytes + in coff-sh.c. */ + +static boolean +sh_elf_relax_delete_bytes (abfd, sec, addr, count) + bfd *abfd; + asection *sec; + bfd_vma addr; + int count; +{ + Elf_Internal_Shdr *symtab_hdr; + Elf32_External_Sym *extsyms; + int shndx; + bfd_byte *contents; + Elf_Internal_Rela *irel, *irelend; + Elf_Internal_Rela *irelalign; + bfd_vma toaddr; + Elf32_External_Sym *esym, *esymend; + struct elf_link_hash_entry **sym_hash, **sym_hash_end; + asection *o; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + extsyms = (Elf32_External_Sym *) symtab_hdr->contents; + + shndx = _bfd_elf_section_from_bfd_section (abfd, sec); + + contents = elf_section_data (sec)->this_hdr.contents; + + /* The deletion must stop at the next ALIGN reloc for an aligment + power larger than the number of bytes we are deleting. */ + + irelalign = NULL; + toaddr = sec->_cooked_size; + + irel = elf_section_data (sec)->relocs; + irelend = irel + sec->reloc_count; + for (; irel < irelend; irel++) + { + if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_ALIGN + && irel->r_offset > addr + && count < (1 << irel->r_addend)) + { + irelalign = irel; + toaddr = irel->r_offset; + break; + } + } + + /* Actually delete the bytes. */ + memmove (contents + addr, contents + addr + count, toaddr - addr - count); + if (irelalign == NULL) + sec->_cooked_size -= count; + else + { + int i; + +#define NOP_OPCODE (0x0009) + + BFD_ASSERT ((count & 1) == 0); + for (i = 0; i < count; i += 2) + bfd_put_16 (abfd, NOP_OPCODE, contents + toaddr - count + i); + } + + /* Adjust all the relocs. */ + for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) + { + bfd_vma nraddr, start, stop; + int insn = 0; + Elf_Internal_Sym sym; + int off, adjust, oinsn; + bfd_signed_vma voff; + boolean overflow; + + /* Get the new reloc address. */ + nraddr = irel->r_offset; + if ((irel->r_offset > addr + && irel->r_offset < toaddr) + || (ELF32_R_TYPE (irel->r_info) == (int) R_SH_ALIGN + && irel->r_offset == toaddr)) + nraddr -= count; + + /* See if this reloc was for the bytes we have deleted, in which + case we no longer care about it. Don't delete relocs which + represent addresses, though. */ + if (irel->r_offset >= addr + && irel->r_offset < addr + count + && ELF32_R_TYPE (irel->r_info) != (int) R_SH_ALIGN + && ELF32_R_TYPE (irel->r_info) != (int) R_SH_CODE + && ELF32_R_TYPE (irel->r_info) != (int) R_SH_DATA) + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + (int) R_SH_NONE); + + /* If this is a PC relative reloc, see if the range it covers + includes the bytes we have deleted. */ + switch ((enum sh_reloc_type) ELF32_R_TYPE (irel->r_info)) + { + default: + break; + + case R_SH_DIR8WPN: + case R_SH_IND12W: + case R_SH_DIR8WPZ: + case R_SH_DIR8WPL: + start = irel->r_offset; + insn = bfd_get_16 (abfd, contents + nraddr); + break; + } + + switch ((enum sh_reloc_type) ELF32_R_TYPE (irel->r_info)) + { + default: + start = stop = addr; + break; + + case R_SH_DIR32: + /* If this reloc is against a symbol defined in this + section, and the symbol will not be adjusted below, we + must check the addend to see it will put the value in + range to be adjusted, and hence must be changed. */ + if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) + { + bfd_elf32_swap_symbol_in (abfd, + extsyms + ELF32_R_SYM (irel->r_info), + &sym); + if (sym.st_shndx == shndx + && (sym.st_value <= addr + || sym.st_value >= toaddr)) + { + bfd_vma val; + + val = bfd_get_32 (abfd, contents + nraddr); + val += sym.st_value; + if (val >= addr && val < toaddr) + bfd_put_32 (abfd, val - count, contents + nraddr); + } + } + start = stop = addr; + break; + + case R_SH_DIR8WPN: + off = insn & 0xff; + if (off & 0x80) + off -= 0x100; + stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2); + break; + + case R_SH_IND12W: + if (ELF32_R_SYM (irel->r_info) >= symtab_hdr->sh_info) + start = stop = addr; + else + { + off = insn & 0xfff; + if (off & 0x800) + off -= 0x1000; + stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2); + } + break; + + case R_SH_DIR8WPZ: + off = insn & 0xff; + stop = start + 4 + off * 2; + break; + + case R_SH_DIR8WPL: + off = insn & 0xff; + stop = (start &~ (bfd_vma) 3) + 4 + off * 4; + break; + + case R_SH_SWITCH16: + case R_SH_SWITCH32: + /* These relocs types represent + .word L2-L1 + The r_offset field holds the difference between the reloc + address and L1. That is the start of the reloc, and + adding in the contents gives us the top. We must adjust + both the r_offset field and the section contents. */ + + start = irel->r_offset; + stop = (bfd_vma) ((bfd_signed_vma) start - (long) irel->r_addend); + + if (start > addr + && start < toaddr + && (stop <= addr || stop >= toaddr)) + irel->r_addend += count; + else if (stop > addr + && stop < toaddr + && (start <= addr || start >= toaddr)) + irel->r_addend -= count; + + start = stop; + + if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_SWITCH16) + voff = bfd_get_signed_16 (abfd, contents + nraddr); + else + voff = bfd_get_signed_32 (abfd, contents + nraddr); + stop = (bfd_vma) ((bfd_signed_vma) start + voff); + + break; + + case R_SH_USES: + start = irel->r_offset; + stop = (bfd_vma) ((bfd_signed_vma) start + + (long) irel->r_addend + + 4); + break; + } + + if (start > addr + && start < toaddr + && (stop <= addr || stop >= toaddr)) + adjust = count; + else if (stop > addr + && stop < toaddr + && (start <= addr || start >= toaddr)) + adjust = - count; + else + adjust = 0; + + if (adjust != 0) + { + oinsn = insn; + overflow = false; + switch ((enum sh_reloc_type) ELF32_R_TYPE (irel->r_info)) + { + default: + abort (); + break; + + case R_SH_DIR8WPN: + case R_SH_DIR8WPZ: + insn += adjust / 2; + if ((oinsn & 0xff00) != (insn & 0xff00)) + overflow = true; + bfd_put_16 (abfd, insn, contents + nraddr); + break; + + case R_SH_IND12W: + insn += adjust / 2; + if ((oinsn & 0xf000) != (insn & 0xf000)) + overflow = true; + bfd_put_16 (abfd, insn, contents + nraddr); + break; + + case R_SH_DIR8WPL: + BFD_ASSERT (adjust == count || count >= 4); + if (count >= 4) + insn += adjust / 4; + else + { + if ((irel->r_offset & 3) == 0) + ++insn; + } + if ((oinsn & 0xff00) != (insn & 0xff00)) + overflow = true; + bfd_put_16 (abfd, insn, contents + nraddr); + break; + + case R_SH_SWITCH16: + voff += adjust; + if (voff < - 0x8000 || voff >= 0x8000) + overflow = true; + bfd_put_signed_16 (abfd, voff, contents + nraddr); + break; + + case R_SH_SWITCH32: + voff += adjust; + bfd_put_signed_32 (abfd, voff, contents + nraddr); + break; + + case R_SH_USES: + irel->r_addend += adjust; + break; + } + + if (overflow) + { + ((*_bfd_error_handler) + ("%s: 0x%lx: fatal: reloc overflow while relaxing", + bfd_get_filename (abfd), (unsigned long) irel->r_offset)); + bfd_set_error (bfd_error_bad_value); + return false; + } + } + + irel->r_offset = nraddr; + } + + /* Look through all the other sections. If there contain any IMM32 + relocs against internal symbols which we are not going to adjust + below, we may need to adjust the addends. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irelscan, *irelscanend; + bfd_byte *ocontents; + + if (o == sec + || (o->flags & SEC_RELOC) == 0 + || o->reloc_count == 0) + continue; + + /* We always cache the relocs. Perhaps, if info->keep_memory is + false, we should free them, if we are permitted to, when we + leave sh_coff_relax_section. */ + internal_relocs = (_bfd_elf32_link_read_relocs + (abfd, o, (PTR) NULL, (Elf_Internal_Rela *) NULL, + true)); + if (internal_relocs == NULL) + return false; + + ocontents = NULL; + irelscanend = internal_relocs + o->reloc_count; + for (irelscan = internal_relocs; irelscan < irelscanend; irelscan++) + { + Elf_Internal_Sym sym; + + if (ELF32_R_TYPE (irelscan->r_info) != (int) R_SH_DIR32) + continue; + + if (ELF32_R_SYM (irelscan->r_info) >= symtab_hdr->sh_info) + continue; + + bfd_elf32_swap_symbol_in (abfd, + extsyms + ELF32_R_SYM (irelscan->r_info), + &sym); + + if (sym.st_shndx == shndx + && (sym.st_value <= addr + || sym.st_value >= toaddr)) + { + bfd_vma val; + + if (ocontents == NULL) + { + if (elf_section_data (o)->this_hdr.contents != NULL) + ocontents = elf_section_data (o)->this_hdr.contents; + else + { + /* We always cache the section contents. + Perhaps, if info->keep_memory is false, we + should free them, if we are permitted to, + when we leave sh_coff_relax_section. */ + ocontents = (bfd_byte *) bfd_malloc (o->_raw_size); + if (ocontents == NULL) + return false; + if (! bfd_get_section_contents (abfd, o, ocontents, + (file_ptr) 0, + o->_raw_size)) + return false; + elf_section_data (o)->this_hdr.contents = ocontents; + } + } + + val = bfd_get_32 (abfd, ocontents + irelscan->r_offset); + val += sym.st_value; + if (val >= addr && val < toaddr) + bfd_put_32 (abfd, val - count, + ocontents + irelscan->r_offset); + } + } + } + + /* Adjust all the symbols. */ + esym = extsyms; + esymend = esym + symtab_hdr->sh_info; + for (; esym < esymend; esym++) + { + Elf_Internal_Sym isym; + + bfd_elf32_swap_symbol_in (abfd, esym, &isym); + + if (isym.st_shndx == shndx + && isym.st_value > addr + && isym.st_value < toaddr) + { + isym.st_value -= count; + bfd_elf32_swap_symbol_out (abfd, &isym, esym); + } + } + + sym_hash = elf_sym_hashes (abfd); + sym_hash_end = (sym_hash + + (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) + - symtab_hdr->sh_info)); + for (; sym_hash < sym_hash_end; sym_hash++) + { + if (((*sym_hash)->root.type == bfd_link_hash_defined + || (*sym_hash)->root.type == bfd_link_hash_defweak) + && (*sym_hash)->root.u.def.section == sec + && (*sym_hash)->root.u.def.value > addr + && (*sym_hash)->root.u.def.value < toaddr) + { + (*sym_hash)->root.u.def.value -= count; + } + } + + /* See if we can move the ALIGN reloc forward. We have adjusted + r_offset for it already. */ + if (irelalign != NULL) + { + bfd_vma alignto, alignaddr; + + alignto = BFD_ALIGN (toaddr, 1 << irelalign->r_addend); + alignaddr = BFD_ALIGN (irelalign->r_offset, + 1 << irelalign->r_addend); + if (alignto != alignaddr) + { + /* Tail recursion. */ + return sh_elf_relax_delete_bytes (abfd, sec, alignaddr, + alignto - alignaddr); + } + } + + return true; +} + +/* Look for loads and stores which we can align to four byte + boundaries. This is like sh_align_loads in coff-sh.c. */ + +static boolean +sh_elf_align_loads (abfd, sec, internal_relocs, contents, pswapped) + bfd *abfd; + asection *sec; + Elf_Internal_Rela *internal_relocs; + bfd_byte *contents; + boolean *pswapped; +{ + Elf_Internal_Rela *irel, *irelend; + bfd_vma *labels = NULL; + bfd_vma *label, *label_end; + + *pswapped = false; + + irelend = internal_relocs + sec->reloc_count; + + /* Get all the addresses with labels on them. */ + labels = (bfd_vma *) bfd_malloc (sec->reloc_count * sizeof (bfd_vma)); + if (labels == NULL) + goto error_return; + label_end = labels; + for (irel = internal_relocs; irel < irelend; irel++) + { + if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_LABEL) + { + *label_end = irel->r_offset; + ++label_end; + } + } + + /* Note that the assembler currently always outputs relocs in + address order. If that ever changes, this code will need to sort + the label values and the relocs. */ + + label = labels; + + for (irel = internal_relocs; irel < irelend; irel++) + { + bfd_vma start, stop; + + if (ELF32_R_TYPE (irel->r_info) != (int) R_SH_CODE) + continue; + + start = irel->r_offset; + + for (irel++; irel < irelend; irel++) + if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_DATA) + break; + if (irel < irelend) + stop = irel->r_offset; + else + stop = sec->_cooked_size; + + if (! _bfd_sh_align_load_span (abfd, sec, contents, sh_elf_swap_insns, + (PTR) internal_relocs, &label, + label_end, start, stop, pswapped)) + goto error_return; + } + + free (labels); + + return true; + + error_return: + if (labels != NULL) + free (labels); + return false; +} + +/* Swap two SH instructions. This is like sh_swap_insns in coff-sh.c. */ + +static boolean +sh_elf_swap_insns (abfd, sec, relocs, contents, addr) + bfd *abfd; + asection *sec; + PTR relocs; + bfd_byte *contents; + bfd_vma addr; +{ + Elf_Internal_Rela *internal_relocs = (Elf_Internal_Rela *) relocs; + unsigned short i1, i2; + Elf_Internal_Rela *irel, *irelend; + + /* Swap the instructions themselves. */ + i1 = bfd_get_16 (abfd, contents + addr); + i2 = bfd_get_16 (abfd, contents + addr + 2); + bfd_put_16 (abfd, i2, contents + addr); + bfd_put_16 (abfd, i1, contents + addr + 2); + + /* Adjust all reloc addresses. */ + irelend = internal_relocs + sec->reloc_count; + for (irel = internal_relocs; irel < irelend; irel++) + { + enum sh_reloc_type type; + int add; + + /* There are a few special types of relocs that we don't want to + adjust. These relocs do not apply to the instruction itself, + but are only associated with the address. */ + type = (enum sh_reloc_type) ELF32_R_TYPE (irel->r_info); + if (type == R_SH_ALIGN + || type == R_SH_CODE + || type == R_SH_DATA + || type == R_SH_LABEL) + continue; + + /* If an R_SH_USES reloc points to one of the addresses being + swapped, we must adjust it. It would be incorrect to do this + for a jump, though, since we want to execute both + instructions after the jump. (We have avoided swapping + around a label, so the jump will not wind up executing an + instruction it shouldn't). */ + if (type == R_SH_USES) + { + bfd_vma off; + + off = irel->r_offset + 4 + irel->r_addend; + if (off == addr) + irel->r_offset += 2; + else if (off == addr + 2) + irel->r_offset -= 2; + } + + if (irel->r_offset == addr) + { + irel->r_offset += 2; + add = -2; + } + else if (irel->r_offset == addr + 2) + { + irel->r_offset -= 2; + add = 2; + } + else + add = 0; + + if (add != 0) + { + bfd_byte *loc; + unsigned short insn, oinsn; + boolean overflow; + + loc = contents + irel->r_offset; + overflow = false; + switch (type) + { + default: + break; + + case R_SH_DIR8WPN: + case R_SH_DIR8WPZ: + insn = bfd_get_16 (abfd, loc); + oinsn = insn; + insn += add / 2; + if ((oinsn & 0xff00) != (insn & 0xff00)) + overflow = true; + bfd_put_16 (abfd, insn, loc); + break; + + case R_SH_IND12W: + insn = bfd_get_16 (abfd, loc); + oinsn = insn; + insn += add / 2; + if ((oinsn & 0xf000) != (insn & 0xf000)) + overflow = true; + bfd_put_16 (abfd, insn, loc); + break; + + case R_SH_DIR8WPL: + /* This reloc ignores the least significant 3 bits of + the program counter before adding in the offset. + This means that if ADDR is at an even address, the + swap will not affect the offset. If ADDR is an at an + odd address, then the instruction will be crossing a + four byte boundary, and must be adjusted. */ + if ((addr & 3) != 0) + { + insn = bfd_get_16 (abfd, loc); + oinsn = insn; + insn += add / 2; + if ((oinsn & 0xff00) != (insn & 0xff00)) + overflow = true; + bfd_put_16 (abfd, insn, loc); + } + + break; + } + + if (overflow) + { + ((*_bfd_error_handler) + ("%s: 0x%lx: fatal: reloc overflow while relaxing", + bfd_get_filename (abfd), (unsigned long) irel->r_offset)); + bfd_set_error (bfd_error_bad_value); + return false; + } + } + } + + return true; +} + +/* Relocate an SH ELF section. */ + +static boolean +sh_elf_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, local_syms, local_sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + Elf_Internal_Rela *relocs; + Elf_Internal_Sym *local_syms; + asection **local_sections; +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + Elf_Internal_Rela *rel, *relend; + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + + rel = relocs; + relend = relocs + input_section->reloc_count; + for (; rel < relend; rel++) + { + int r_type; + reloc_howto_type *howto; + unsigned long r_symndx; + Elf_Internal_Sym *sym; + asection *sec; + struct elf_link_hash_entry *h; + bfd_vma relocation; + bfd_reloc_status_type r; + + if (info->relocateable) + { + /* This is a relocateable link. We don't have to change + anything, unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + sec = local_sections[r_symndx]; + rel->r_addend += sec->output_offset + sym->st_value; + } + } + + continue; + } + + r_type = ELF32_R_TYPE (rel->r_info); + + /* Many of the relocs are only used for relaxing, and are + handled entirely by the relaxation code. */ + if (r_type > (int) LAST_INVALID_RELOC) + continue; + + if (r_type < 0 + || r_type >= (int) FIRST_INVALID_RELOC) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* FIXME: This is certainly incorrect. However, it is how the + COFF linker works. */ + if (r_type != (int) R_SH_DIR32 + && r_type != (int) R_SH_IND12W) + continue; + + howto = sh_elf_howto_table + r_type; + + r_symndx = ELF32_R_SYM (rel->r_info); + + /* This is a final link. */ + h = NULL; + sym = NULL; + sec = NULL; + if (r_symndx < symtab_hdr->sh_info) + { + /* There is nothing to be done for an internal IND12W + relocation. FIXME: This is probably wrong, but it's how + the COFF relocations work. */ + if (r_type == (int) R_SH_IND12W) + continue; + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = (sec->output_section->vma + + sec->output_offset + + sym->st_value); + } + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + relocation = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_undefweak) + relocation = 0; + else + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, rel->r_offset))) + return false; + relocation = 0; + } + } + + /* FIXME: This is how the COFF relocations work. */ + if (r_type == (int) R_SH_IND12W) + relocation -= 4; + + /* FIXME: We should use the addend, but the COFF relocations + don't. */ + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, 0); + + if (r != bfd_reloc_ok) + { + switch (r) + { + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + { + const char *name; + + if (h != NULL) + name = h->root.root.string; + else + { + name = (bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name)); + if (name == NULL) + return false; + if (*name == '\0') + name = bfd_section_name (input_bfd, sec); + } + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset))) + return false; + } + break; + } + } + } + + return true; +} + +/* This is a version of bfd_generic_get_relocated_section_contents + which uses sh_elf_relocate_section. */ + +static bfd_byte * +sh_elf_get_relocated_section_contents (output_bfd, link_info, link_order, + data, relocateable, symbols) + bfd *output_bfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + bfd_byte *data; + boolean relocateable; + asymbol **symbols; +{ + Elf_Internal_Shdr *symtab_hdr; + asection *input_section = link_order->u.indirect.section; + bfd *input_bfd = input_section->owner; + asection **sections = NULL; + Elf_Internal_Rela *internal_relocs = NULL; + Elf32_External_Sym *external_syms = NULL; + Elf_Internal_Sym *internal_syms = NULL; + + /* We only need to handle the case of relaxing, or of having a + particular set of section contents, specially. */ + if (relocateable + || elf_section_data (input_section)->this_hdr.contents == NULL) + return bfd_generic_get_relocated_section_contents (output_bfd, link_info, + link_order, data, + relocateable, + symbols); + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + + memcpy (data, elf_section_data (input_section)->this_hdr.contents, + input_section->_raw_size); + + if ((input_section->flags & SEC_RELOC) != 0 + && input_section->reloc_count > 0) + { + Elf_Internal_Sym *isymp; + asection **secpp; + Elf32_External_Sym *esym, *esymend; + + if (symtab_hdr->contents != NULL) + external_syms = (Elf32_External_Sym *) symtab_hdr->contents; + else + { + external_syms = ((Elf32_External_Sym *) + bfd_malloc (symtab_hdr->sh_info + * sizeof (Elf32_External_Sym))); + if (external_syms == NULL && symtab_hdr->sh_info > 0) + goto error_return; + if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0 + || (bfd_read (external_syms, sizeof (Elf32_External_Sym), + symtab_hdr->sh_info, input_bfd) + != (symtab_hdr->sh_info * sizeof (Elf32_External_Sym)))) + goto error_return; + } + + internal_relocs = (_bfd_elf32_link_read_relocs + (input_bfd, input_section, (PTR) NULL, + (Elf_Internal_Rela *) NULL, false)); + if (internal_relocs == NULL) + goto error_return; + + internal_syms = ((Elf_Internal_Sym *) + bfd_malloc (symtab_hdr->sh_info + * sizeof (Elf_Internal_Sym))); + if (internal_syms == NULL && symtab_hdr->sh_info > 0) + goto error_return; + + sections = (asection **) bfd_malloc (symtab_hdr->sh_info + * sizeof (asection *)); + if (sections == NULL && symtab_hdr->sh_info > 0) + goto error_return; + + isymp = internal_syms; + secpp = sections; + esym = external_syms; + esymend = esym + symtab_hdr->sh_info; + for (; esym < esymend; ++esym, ++isymp, ++secpp) + { + asection *isec; + + bfd_elf32_swap_symbol_in (input_bfd, esym, isymp); + + if (isymp->st_shndx == SHN_UNDEF) + isec = bfd_und_section_ptr; + else if (isymp->st_shndx > 0 && isymp->st_shndx < SHN_LORESERVE) + isec = bfd_section_from_elf_index (input_bfd, isymp->st_shndx); + else if (isymp->st_shndx == SHN_ABS) + isec = bfd_abs_section_ptr; + else if (isymp->st_shndx == SHN_COMMON) + isec = bfd_com_section_ptr; + else + { + /* Who knows? */ + isec = NULL; + } + + *secpp = isec; + } + + if (! sh_elf_relocate_section (output_bfd, link_info, input_bfd, + input_section, data, internal_relocs, + internal_syms, sections)) + goto error_return; + + if (sections != NULL) + free (sections); + sections = NULL; + if (internal_syms != NULL) + free (internal_syms); + internal_syms = NULL; + if (external_syms != NULL && symtab_hdr->contents == NULL) + free (external_syms); + external_syms = NULL; + if (internal_relocs != elf_section_data (input_section)->relocs) + free (internal_relocs); + internal_relocs = NULL; + } + + return data; + + error_return: + if (internal_relocs != NULL + && internal_relocs != elf_section_data (input_section)->relocs) + free (internal_relocs); + if (external_syms != NULL && symtab_hdr->contents == NULL) + free (external_syms); + if (internal_syms != NULL) + free (internal_syms); + if (sections != NULL) + free (sections); + return NULL; +} + +#define TARGET_BIG_SYM bfd_elf32_sh_vec +#define TARGET_BIG_NAME "elf32-sh" +#define TARGET_LITTLE_SYM bfd_elf32_shl_vec +#define TARGET_LITTLE_NAME "elf32-shl" +#define ELF_ARCH bfd_arch_sh +#define ELF_MACHINE_CODE EM_SH +#define ELF_MAXPAGESIZE 0x1 + +#define elf_symbol_leading_char '_' + +#define bfd_elf32_bfd_reloc_type_lookup sh_elf_reloc_type_lookup +#define elf_info_to_howto sh_elf_info_to_howto +#define bfd_elf32_bfd_relax_section sh_elf_relax_section +#define elf_backend_relocate_section sh_elf_relocate_section +#define bfd_elf32_bfd_get_relocated_section_contents \ + sh_elf_get_relocated_section_contents + +#include "elf32-target.h" diff --git a/gnu/usr.bin/binutils/bfd/elf64-alpha.c b/gnu/usr.bin/binutils/bfd/elf64-alpha.c new file mode 100644 index 00000000000..52d1732b2d0 --- /dev/null +++ b/gnu/usr.bin/binutils/bfd/elf64-alpha.c @@ -0,0 +1,3335 @@ +/* ALPHA-specific support for 64-bit ELF + Copyright 1996 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@tamu.edu>. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* We need a published ABI spec for this. Until one comes out, don't + assume this'll remain unchanged forever. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "elf-bfd.h" + +#include "elf/alpha.h" + +#define ALPHAECOFF + +#define NO_COFF_RELOCS +#define NO_COFF_SYMBOLS +#define NO_COFF_LINENOS + +/* Get the ECOFF swapping routines. Needed for the debug information. */ +#include "coff/internal.h" +#include "coff/sym.h" +#include "coff/symconst.h" +#include "coff/ecoff.h" +#include "coff/alpha.h" +#include "aout/ar.h" +#include "libcoff.h" +#include "libecoff.h" +#define ECOFF_64 +#include "ecoffswap.h" + +static struct bfd_hash_entry * elf64_alpha_link_hash_newfunc + PARAMS((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static struct bfd_link_hash_table * elf64_alpha_bfd_link_hash_table_create + PARAMS((bfd *)); + +static bfd_reloc_status_type elf64_alpha_reloc_nil + PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static bfd_reloc_status_type elf64_alpha_do_reloc_gpdisp + PARAMS((bfd *, bfd_vma, bfd_byte *, bfd_byte *)); +static bfd_reloc_status_type elf64_alpha_reloc_gpdisp + PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static bfd_reloc_status_type elf64_alpha_reloc_op_push + PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static bfd_reloc_status_type elf64_alpha_reloc_op_store + PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static bfd_reloc_status_type elf64_alpha_reloc_op_psub + PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static bfd_reloc_status_type elf64_alpha_reloc_op_prshift + PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); + +static reloc_howto_type * elf64_alpha_bfd_reloc_type_lookup + PARAMS((bfd *, bfd_reloc_code_real_type)); +static void elf64_alpha_info_to_howto + PARAMS((bfd *, arelent *, Elf64_Internal_Rela *)); + +static boolean elf64_alpha_object_p + PARAMS((bfd *)); +static boolean elf64_alpha_section_from_shdr + PARAMS((bfd *, Elf64_Internal_Shdr *, char *)); +static boolean elf64_alpha_fake_sections + PARAMS((bfd *, Elf64_Internal_Shdr *, asection *)); +static int elf64_alpha_additional_program_headers + PARAMS((bfd *)); +static boolean elf64_alpha_create_got_section + PARAMS((bfd *, struct bfd_link_info *)); +static boolean elf64_alpha_create_dynamic_sections + PARAMS((bfd *, struct bfd_link_info *)); + +static boolean elf64_alpha_read_ecoff_info + PARAMS((bfd *, asection *, struct ecoff_debug_info *)); +static boolean elf64_alpha_is_local_label + PARAMS((bfd *, asymbol *)); +static boolean elf64_alpha_find_nearest_line + PARAMS((bfd *, asection *, asymbol **, bfd_vma, const char **, + const char **, unsigned int *)); + +#if defined(__STDC__) || defined(ALMOST_STDC) +struct alpha_elf_link_hash_entry; +#endif + +static boolean elf64_alpha_output_extsym + PARAMS((struct alpha_elf_link_hash_entry *, PTR)); + +static boolean elf64_alpha_check_relocs + PARAMS((bfd *, struct bfd_link_info *, asection *sec, + const Elf_Internal_Rela *)); +static boolean elf64_alpha_adjust_dynamic_symbol + PARAMS((struct bfd_link_info *, struct elf_link_hash_entry *)); +static boolean elf64_alpha_size_dynamic_sections + PARAMS((bfd *, struct bfd_link_info *)); +static boolean elf64_alpha_adjust_dynindx + PARAMS((struct elf_link_hash_entry *, PTR)); +static boolean elf64_alpha_relocate_section + PARAMS((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); +static boolean elf64_alpha_finish_dynamic_symbol + PARAMS((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, + Elf_Internal_Sym *)); +static boolean elf64_alpha_finish_dynamic_sections + PARAMS((bfd *, struct bfd_link_info *)); +static boolean elf64_alpha_final_link + PARAMS((bfd *, struct bfd_link_info *)); + + +#define alpha_elf_tdata(bfd) \ + ((struct alpha_elf_obj_tdata *)elf_tdata(bfd)->tdata) + +struct alpha_elf_link_hash_entry +{ + struct elf_link_hash_entry root; + + /* External symbol information. */ + EXTR esym; + + unsigned char flags; + /* Contexts (LITUSE) in which a literal was referenced. */ +#define ALPHA_ELF_LINK_HASH_LU_ADDR 01 +#define ALPHA_ELF_LINK_HASH_LU_MEM 02 +#define ALPHA_ELF_LINK_HASH_LU_FUNC 04 +}; + +/* Alpha ELF linker hash table. */ + +struct alpha_elf_link_hash_table +{ + struct elf_link_hash_table root; +}; + +/* Look up an entry in a Alpha ELF linker hash table. */ + +#define alpha_elf_link_hash_lookup(table, string, create, copy, follow) \ + ((struct alpha_elf_link_hash_entry *) \ + elf_link_hash_lookup (&(table)->root, (string), (create), \ + (copy), (follow))) + +/* Traverse a Alpha ELF linker hash table. */ + +#define alpha_elf_link_hash_traverse(table, func, info) \ + (elf_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct elf_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the Alpha ELF linker hash table from a link_info structure. */ + +#define alpha_elf_hash_table(p) \ + ((struct alpha_elf_link_hash_table *) ((p)->hash)) + +/* Create an entry in a Alpha ELF linker hash table. */ + +static struct bfd_hash_entry * +elf64_alpha_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct alpha_elf_link_hash_entry *ret = + (struct alpha_elf_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct alpha_elf_link_hash_entry *) NULL) + ret = ((struct alpha_elf_link_hash_entry *) + bfd_hash_allocate (table, + sizeof (struct alpha_elf_link_hash_entry))); + if (ret == (struct alpha_elf_link_hash_entry *) NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct alpha_elf_link_hash_entry *) + _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + if (ret != (struct alpha_elf_link_hash_entry *) NULL) + { + /* Set local fields. */ + memset (&ret->esym, 0, sizeof (EXTR)); + /* We use -2 as a marker to indicate that the information has + not been set. -1 means there is no associated ifd. */ + ret->esym.ifd = -2; + ret->flags = 0; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Create a Alpha ELF linker hash table. */ + +static struct bfd_link_hash_table * +elf64_alpha_bfd_link_hash_table_create (abfd) + bfd *abfd; +{ + struct alpha_elf_link_hash_table *ret; + + ret = ((struct alpha_elf_link_hash_table *) + bfd_zalloc (abfd, sizeof (struct alpha_elf_link_hash_table))); + if (ret == (struct alpha_elf_link_hash_table *) NULL) + return NULL; + + if (! _bfd_elf_link_hash_table_init (&ret->root, abfd, + elf64_alpha_link_hash_newfunc)) + { + bfd_release (abfd, ret); + return NULL; + } + + return &ret->root.root; +} + + +/* In case we're on a 32-bit machine, construct a 64-bit "-1" value + from smaller values. Start with zero, widen, *then* decrement. */ +#define MINUS_ONE (((bfd_vma)0) - 1) + +static reloc_howto_type elf64_alpha_howto_table[] = +{ + HOWTO (R_ALPHA_NONE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + elf64_alpha_reloc_nil, /* special_function */ + "NONE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + true), /* pcrel_offset */ + + /* A 32 bit reference to a symbol. */ + HOWTO (R_ALPHA_REFLONG, /* 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 */ + "REFLONG", /* name */ + false, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 64 bit reference to a symbol. */ + HOWTO (R_ALPHA_REFQUAD, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "REFQUAD", /* name */ + false, /* partial_inplace */ + MINUS_ONE, /* src_mask */ + MINUS_ONE, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 32 bit GP relative offset. This is just like REFLONG except + that when the value is used the value of the gp register will be + added in. */ + HOWTO (R_ALPHA_GPREL32, /* 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 */ + "GPREL32", /* name */ + false, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Used for an instruction that refers to memory off the GP register. */ + HOWTO (R_ALPHA_LITERAL, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "LITERAL", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* This reloc only appears immediately following a LITERAL reloc. + It identifies a use of the literal. The symbol index is special: + 1 means the literal address is in the base register of a memory + format instruction; 2 means the literal address is in the byte + offset register of a byte-manipulation instruction; 3 means the + literal address is in the target register of a jsr instruction. + This does not actually do any relocation. */ + HOWTO (R_ALPHA_LITUSE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + elf64_alpha_reloc_nil, /* special_function */ + "LITUSE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Load the gp register. This is always used for a ldah instruction + which loads the upper 16 bits of the gp register. The symbol + index of the GPDISP instruction is an offset in bytes to the lda + instruction that loads the lower 16 bits. The value to use for + the relocation is the difference between the GP value and the + current location; the load will always be done against a register + holding the current address. + + NOTE: Unlike ECOFF, partial inplace relocation is not done. If + any offset is present in the instructions, it is an offset from + the register to the ldah instruction. This lets us avoid any + stupid hackery like inventing a gp value to do partial relocation + against. Also unlike ECOFF, we do the whole relocation off of + the GPDISP rather than a GPDISP_HI16/GPDISP_LO16 pair. An odd, + space consuming bit, that, since all the information was present + in the GPDISP_HI16 reloc. */ + HOWTO (R_ALPHA_GPDISP, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + elf64_alpha_reloc_gpdisp, /* special_function */ + "GPDISP", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + true), /* pcrel_offset */ + + /* A 21 bit branch. */ + HOWTO (R_ALPHA_BRADDR, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "BRADDR", /* name */ + false, /* partial_inplace */ + 0x1fffff, /* src_mask */ + 0x1fffff, /* dst_mask */ + true), /* pcrel_offset */ + + /* A hint for a jump to a register. */ + HOWTO (R_ALPHA_HINT, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 14, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "HINT", /* name */ + false, /* partial_inplace */ + 0x3fff, /* src_mask */ + 0x3fff, /* dst_mask */ + true), /* pcrel_offset */ + + /* 16 bit PC relative offset. */ + HOWTO (R_ALPHA_SREL16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "SREL16", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32 bit PC relative offset. */ + HOWTO (R_ALPHA_SREL32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "SREL32", /* name */ + false, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 64 bit PC relative offset. */ + HOWTO (R_ALPHA_SREL64, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "SREL64", /* name */ + false, /* partial_inplace */ + MINUS_ONE, /* src_mask */ + MINUS_ONE, /* dst_mask */ + false), /* pcrel_offset */ + + /* Push a value on the reloc evaluation stack. */ + HOWTO (ALPHA_R_OP_PUSH, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + elf64_alpha_reloc_op_push, /* special_function */ + "OP_PUSH", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Store the value from the stack at the given address. Store it in + a bitfield of size r_size starting at bit position r_offset. */ + HOWTO (ALPHA_R_OP_STORE, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + elf64_alpha_reloc_op_store, /* special_function */ + "OP_STORE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + MINUS_ONE, /* dst_mask */ + false), /* pcrel_offset */ + + /* Subtract the reloc address from the value on the top of the + relocation stack. */ + HOWTO (ALPHA_R_OP_PSUB, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + elf64_alpha_reloc_op_psub, /* special_function */ + "OP_PSUB", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Shift the value on the top of the relocation stack right by the + given value. */ + HOWTO (ALPHA_R_OP_PRSHIFT, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + elf64_alpha_reloc_op_prshift, /* special_function */ + "OP_PRSHIFT", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Misc ELF relocations. */ + HOWTO (R_ALPHA_COPY, + 0, + 0, + 0, + false, + 0, + complain_overflow_dont, + bfd_elf_generic_reloc, + "COPY", + false, + 0, + 0, + true), + + HOWTO (R_ALPHA_GLOB_DAT, + 0, + 0, + 0, + false, + 0, + complain_overflow_dont, + bfd_elf_generic_reloc, + "GLOB_DAT", + false, + 0, + 0, + true), + + HOWTO (R_ALPHA_JMP_SLOT, + 0, + 0, + 0, + false, + 0, + complain_overflow_dont, + bfd_elf_generic_reloc, + "JMP_SLOT", + false, + 0, + 0, + true), + + HOWTO (R_ALPHA_RELATIVE, + 0, + 0, + 0, + false, + 0, + complain_overflow_dont, + bfd_elf_generic_reloc, + "RELATIVE", + false, + 0, + 0, + true) +}; + +static bfd_reloc_status_type +elf64_alpha_reloc_nil (abfd, reloc, sym, data, sec, output_bfd, error_message) + bfd *abfd; + arelent *reloc; + asymbol *sym; + PTR data; + asection *sec; + bfd *output_bfd; + char **error_message; +{ + if (output_bfd) + reloc->address += sec->output_offset; + return bfd_reloc_ok; +} + +static bfd_reloc_status_type +elf64_alpha_do_reloc_gpdisp (abfd, gpdisp, p_ldah, p_lda) + bfd *abfd; + bfd_vma gpdisp; + bfd_byte *p_ldah, *p_lda; +{ + bfd_reloc_status_type ret = bfd_reloc_ok; + bfd_vma addend; + unsigned long i_ldah, i_lda; + + i_ldah = bfd_get_32(abfd, p_ldah); + i_lda = bfd_get_32(abfd, p_lda); + + /* Complain if the instructions are not correct. */ + if (((i_ldah >> 26) & 0x3f) != 0x09 + || ((i_lda >> 26) & 0x3f) != 0x08) + ret = bfd_reloc_dangerous; + + /* Extract the user-supplied offset, mirroring the sign extensions + that the instructions perform. */ + addend = ((i_ldah & 0xffff) << 16) | (i_lda & 0xffff); + addend = (addend ^ 0x80008000) - 0x80008000; + + gpdisp += addend; + + if ((bfd_signed_vma)gpdisp < -(bfd_signed_vma)0x80000000 + || gpdisp >= 0x7fff8000) + ret = bfd_reloc_overflow; + + /* compensate for the sign extension again. */ + i_ldah = ((i_ldah & 0xffff0000) + | (((gpdisp >> 16) + ((gpdisp >> 15) & 1)) & 0xffff)); + i_lda = (i_lda & 0xffff0000) | (gpdisp & 0xffff); + + bfd_put_32 (abfd, i_ldah, p_ldah); + bfd_put_32 (abfd, i_lda, p_lda); + + return ret; +} + +static bfd_reloc_status_type +elf64_alpha_reloc_gpdisp (abfd, reloc_entry, sym, data, input_section, + output_bfd, err_msg) + bfd *abfd; + arelent *reloc_entry; + asymbol *sym; + PTR data; + asection *input_section; + bfd *output_bfd; + char **err_msg; +{ + bfd_reloc_status_type ret; + bfd_vma gp, relocation; + bfd_byte *p_ldah, *p_lda; + + /* Don't do anything if we're not doing a final link. */ + if (output_bfd) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (reloc_entry->address > input_section->_cooked_size || + reloc_entry->address + reloc_entry->addend > input_section->_cooked_size) + return bfd_reloc_outofrange; + + /* The gp used in the portion of the output object to which this + input object belongs is cached on the input bfd. */ + gp = _bfd_get_gp_value (abfd); + + relocation = (input_section->output_section->vma + + input_section->output_offset + + reloc_entry->address); + + p_ldah = (bfd_byte *)data + reloc_entry->address; + p_lda = p_ldah + reloc_entry->addend; + + ret = elf64_alpha_do_reloc_gpdisp (abfd, gp - relocation, p_ldah, p_lda); + + /* Complain if the instructions are not correct. */ + if (ret == bfd_reloc_dangerous) + { + *err_msg = "GPDISP relocation did not find ldah and lda instructions"; + } + + return ret; +} + +/* Due to the nature of the stack operations, I don't think more + that one entry is useful. Test this theory by setting the + stack size to a minimum. */ +/* FIXME: BFD should not use static variables. */ +#define OP_STACK_SIZE 1 +static bfd_vma elf64_alpha_op_stack[OP_STACK_SIZE]; +static int elf64_alpha_op_tos; + +static bfd_reloc_status_type +elf64_alpha_reloc_op_push (abfd, reloc_entry, sym, data, input_section, + output_bfd, err_msg) + bfd *abfd; + arelent *reloc_entry; + asymbol *sym; + PTR data; + asection *input_section; + bfd *output_bfd; + char **err_msg; +{ + bfd_reloc_status_type r = bfd_reloc_ok; + bfd_vma value; + + /* Don't do anything if we're not doing a final link. */ + if (output_bfd) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (elf64_alpha_op_tos >= OP_STACK_SIZE) + { + *err_msg = "operation stack overflow"; + return bfd_reloc_dangerous; + } + + /* Get the symbol value. */ + /* FIXME: We should fail if this is a dynamic symbol. Check on that. */ + if (bfd_is_und_section (sym->section)) + r = bfd_reloc_undefined; + if (bfd_is_com_section (sym->section)) + value = 0; + else + value = sym->value; + value += sym->section->output_section->vma; + value += sym->section->output_offset; + value += reloc_entry->addend; + + elf64_alpha_op_stack[elf64_alpha_op_tos++] = value; + + return r; +} + +static bfd_reloc_status_type +elf64_alpha_reloc_op_store (abfd, reloc_entry, sym, data, input_section, + output_bfd, err_msg) + bfd *abfd; + arelent *reloc_entry; + asymbol *sym; + PTR data; + asection *input_section; + bfd *output_bfd; + char **err_msg; +{ + int size, offset; + bfd_vma value; + + /* Don't do anything before the final link. */ + if (output_bfd) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (elf64_alpha_op_tos <= 0) + { + *err_msg = "operation stack underflow"; + return bfd_reloc_dangerous; + } + + /* The offset and size for this reloc are encoded into the addend + field by alpha_adjust_reloc_in. */ + offset = (reloc_entry->addend >> 8) & 0xff; + size = reloc_entry->addend & 0xff; + + value = bfd_get_64 (abfd, data + reloc_entry->address); + value &= ~((((bfd_vma)1 << size) - 1) << offset); + value |= (elf64_alpha_op_stack[--elf64_alpha_op_tos] + & (((bfd_vma)1 << size) - 1)) << offset; + bfd_put_64 (abfd, value, data + reloc_entry->address); + + return bfd_reloc_ok; +} + +static bfd_reloc_status_type +elf64_alpha_reloc_op_psub (abfd, reloc_entry, sym, data, input_section, + output_bfd, err_msg) + bfd *abfd; + arelent *reloc_entry; + asymbol *sym; + PTR data; + asection *input_section; + bfd *output_bfd; + char **err_msg; +{ + bfd_reloc_status_type r; + bfd_vma value; + + /* Don't do anything before the final link. */ + if (output_bfd) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (elf64_alpha_op_tos <= 0) + { + *err_msg = "operation stack underflow"; + return bfd_reloc_dangerous; + } + + if (bfd_is_und_section (sym->section)) + r = bfd_reloc_undefined; + if (bfd_is_com_section (sym->section)) + value = 0; + else + value = sym->value; + value += sym->section->output_section->vma; + value += sym->section->output_offset; + value += reloc_entry->addend; + + elf64_alpha_op_stack[elf64_alpha_op_tos-1] -= value; + + return r; +} + +static bfd_reloc_status_type +elf64_alpha_reloc_op_prshift (abfd, reloc_entry, sym, data, input_section, + output_bfd, err_msg) + bfd *abfd; + arelent *reloc_entry; + asymbol *sym; + PTR data; + asection *input_section; + bfd *output_bfd; + char **err_msg; +{ + /* Don't do anything before the final link. */ + if (output_bfd) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (elf64_alpha_op_tos <= 0) + { + *err_msg = "operation stack underflow"; + return bfd_reloc_dangerous; + } + + elf64_alpha_op_stack[elf64_alpha_op_tos-1] >>= reloc_entry->addend; + + return bfd_reloc_ok; +} + +/* A mapping from BFD reloc types to Alpha ELF reloc types. */ + +struct elf_reloc_map +{ + bfd_reloc_code_real_type bfd_reloc_val; + int elf_reloc_val; +}; + +static const struct elf_reloc_map elf64_alpha_reloc_map[] = +{ + {BFD_RELOC_NONE, R_ALPHA_NONE}, + {BFD_RELOC_32, R_ALPHA_REFLONG}, + {BFD_RELOC_64, R_ALPHA_REFQUAD}, + {BFD_RELOC_CTOR, R_ALPHA_REFQUAD}, + {BFD_RELOC_GPREL32, R_ALPHA_GPREL32}, + {BFD_RELOC_ALPHA_LITERAL, R_ALPHA_LITERAL}, + {BFD_RELOC_ALPHA_LITUSE, R_ALPHA_LITUSE}, + {BFD_RELOC_ALPHA_GPDISP, R_ALPHA_GPDISP}, + {BFD_RELOC_23_PCREL_S2, R_ALPHA_BRADDR}, + {BFD_RELOC_ALPHA_HINT, R_ALPHA_HINT}, + {BFD_RELOC_16_PCREL, R_ALPHA_SREL16}, + {BFD_RELOC_32_PCREL, R_ALPHA_SREL32}, + {BFD_RELOC_64_PCREL, R_ALPHA_SREL64}, +#if 0 + {BFD_RELOC_ALPHA_OP_PUSH, R_ALPHA_OP_PUSH}, + {BFD_RELOC_ALPHA_OP_STORE, R_ALPHA_OP_STORE}, + {BFD_RELOC_ALPHA_OP_PSUB, R_ALPHA_OP_PSUB}, + {BFD_RELOC_ALPHA_OP_PRSHIFT, R_ALPHA_OP_PRSHIFT} +#endif +}; + +/* Given a BFD reloc type, return a HOWTO structure. */ + +static reloc_howto_type * +elf64_alpha_bfd_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + const struct elf_reloc_map *i, *e; + i = e = elf64_alpha_reloc_map; + e += sizeof (elf64_alpha_reloc_map) / sizeof (struct elf_reloc_map); + for (; i != e; ++i) + { + if (i->bfd_reloc_val == code) + return &elf64_alpha_howto_table[i->elf_reloc_val]; + } + return 0; +} + +/* Given an Alpha ELF reloc type, fill in an arelent structure. */ + +static void +elf64_alpha_info_to_howto (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf64_Internal_Rela *dst; +{ + unsigned r_type; + + r_type = ELF64_R_TYPE(dst->r_info); + BFD_ASSERT (r_type < (unsigned int) R_ALPHA_max); + cache_ptr->howto = &elf64_alpha_howto_table[r_type]; +} + +/* PLT/GOT Stuff */ +#define PLT_HEADER_SIZE 32 +#define PLT_HEADER_WORD1 0xc3600000 /* br $27,.+4 */ +#define PLT_HEADER_WORD2 0xa77b000c /* ldq $27,12($27) */ +#define PLT_HEADER_WORD3 0x47ff041f /* nop */ +#define PLT_HEADER_WORD4 0x6b7b0000 /* jmp $27,($27) */ + +#define PLT_ENTRY_SIZE 12 +#define PLT_ENTRY_WORD1 0x279f0000 /* ldah $28, 0($31) */ +#define PLT_ENTRY_WORD2 0x239c0000 /* lda $28, 0($28) */ +#define PLT_ENTRY_WORD3 0xc3e00000 /* br $31, plt0 */ + +#define RESERVED_GOT_ENTRIES 1 + +#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so" + +/* Set the right machine number for an Alpha ELF file. */ + +static boolean +elf64_alpha_object_p (abfd) + bfd *abfd; +{ + return bfd_default_set_arch_mach (abfd, bfd_arch_alpha, 0); +} + +/* Handle a alpha specific section when reading an object file. This + is called when elfcode.h finds a section with an unknown type. + FIXME: We need to handle the SHF_MIPS_GPREL flag, but I'm not sure + how to. */ + +static boolean +elf64_alpha_section_from_shdr (abfd, hdr, name) + bfd *abfd; + Elf64_Internal_Shdr *hdr; + char *name; +{ + asection *newsect; + + /* There ought to be a place to keep ELF backend specific flags, but + at the moment there isn't one. We just keep track of the + sections by their name, instead. Fortunately, the ABI gives + suggested names for all the MIPS specific sections, so we will + probably get away with this. */ + switch (hdr->sh_type) + { + case SHT_ALPHA_DEBUG: + if (strcmp (name, ".mdebug") != 0) + return false; + break; +#ifdef ERIC_neverdef + case SHT_ALPHA_REGINFO: + if (strcmp (name, ".reginfo") != 0 + || hdr->sh_size != sizeof (Elf64_External_RegInfo)) + return false; + break; +#endif + default: + return false; + } + + if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) + return false; + newsect = hdr->bfd_section; + + if (hdr->sh_type == SHT_ALPHA_DEBUG) + { + if (! bfd_set_section_flags (abfd, newsect, + (bfd_get_section_flags (abfd, newsect) + | SEC_DEBUGGING))) + return false; + } + +#ifdef ERIC_neverdef + /* For a .reginfo section, set the gp value in the tdata information + from the contents of this section. We need the gp value while + processing relocs, so we just get it now. */ + if (hdr->sh_type == SHT_ALPHA_REGINFO) + { + Elf64_External_RegInfo ext; + Elf64_RegInfo s; + + if (! bfd_get_section_contents (abfd, newsect, (PTR) &ext, + (file_ptr) 0, sizeof ext)) + return false; + bfd_alpha_elf64_swap_reginfo_in (abfd, &ext, &s); + elf_gp (abfd) = s.ri_gp_value; + } +#endif + + return true; +} + +/* Set the correct type for an Alpha ELF section. We do this by the + section name, which is a hack, but ought to work. */ + +static boolean +elf64_alpha_fake_sections (abfd, hdr, sec) + bfd *abfd; + Elf64_Internal_Shdr *hdr; + asection *sec; +{ + register const char *name; + + name = bfd_get_section_name (abfd, sec); + + if (strcmp (name, ".mdebug") == 0) + { + hdr->sh_type = SHT_ALPHA_DEBUG; + /* In a shared object on Irix 5.3, the .mdebug section has an + entsize of 0. FIXME: Does this matter? */ + if ((abfd->flags & DYNAMIC) != 0 ) + hdr->sh_entsize = 0; + else + hdr->sh_entsize = 1; + } +#ifdef ERIC_neverdef + else if (strcmp (name, ".reginfo") == 0) + { + hdr->sh_type = SHT_ALPHA_REGINFO; + /* In a shared object on Irix 5.3, the .reginfo section has an + entsize of 0x18. FIXME: Does this matter? */ + if ((abfd->flags & DYNAMIC) != 0) + hdr->sh_entsize = sizeof (Elf64_External_RegInfo); + else + hdr->sh_entsize = 1; + + /* Force the section size to the correct value, even if the + linker thinks it is larger. The link routine below will only + write out this much data for .reginfo. */ + hdr->sh_size = sec->_raw_size = sizeof (Elf64_External_RegInfo); + } + else if (strcmp (name, ".hash") == 0 + || strcmp (name, ".dynamic") == 0 + || strcmp (name, ".dynstr") == 0) + { + hdr->sh_entsize = 0; + hdr->sh_info = SIZEOF_ALPHA_DYNSYM_SECNAMES; + } + else if (strcmp (name, ".sdata") == 0 + || strcmp (name, ".sbss") == 0 + || strcmp (name, ".lit4") == 0 + || strcmp (name, ".lit8") == 0) + hdr->sh_flags |= SHF_ALPHA_GPREL; +#endif + + return true; +} + +static int +elf64_alpha_additional_program_headers (abfd) + bfd *abfd; +{ + asection *s; + int ret; + + ret = 0; + + s = bfd_get_section_by_name (abfd, ".reginfo"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) + { + /* We need a PT_ALPHA_REGINFO segment. */ + ++ret; + } + + if (bfd_get_section_by_name (abfd, ".dynamic") != NULL + && bfd_get_section_by_name (abfd, ".mdebug") != NULL) + { + /* We need a PT_ALPHA_RTPROC segment. */ + ++ret; + } + + return ret; +} + +static boolean +elf64_alpha_create_got_section(abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + asection *s; + struct elf_link_hash_entry *h; + + if (bfd_get_section_by_name (abfd, ".got")) + return true; + + s = bfd_make_section(abfd, ".rela.got"); + if (s == NULL + || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_READONLY)) + || !bfd_set_section_alignment (abfd, s, 3)) + return false; + + s = bfd_make_section(abfd, ".got"); + if (s == NULL + || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS | SEC_IN_MEMORY)) + || !bfd_set_section_alignment (abfd, s, 3)) + return false; + + s->_raw_size = RESERVED_GOT_ENTRIES * 8; + + /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got + (or .got.plt) section. We don't do this in the linker script + because we don't want to define the symbol if we are not creating + a global offset table. */ + h = NULL; + if (!(_bfd_generic_link_add_one_symbol + (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, (bfd_vma) 0, + (const char *) NULL, false, get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h))) + return false; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->type = STT_OBJECT; + + if (info->shared + && ! _bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + + elf_hash_table (info)->hgot = h; + + return true; +} + +static boolean +elf64_alpha_create_dynamic_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + register asection *s; + struct elf_link_hash_entry *h; + + /* We need to create .plt, .rela.plt, .got, and .rela.got sections. */ + + s = bfd_make_section (abfd, ".plt"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_CODE)) + || ! bfd_set_section_alignment (abfd, s, 3)) + return false; + + /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the + .plt section. */ + h = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s, + (bfd_vma) 0, (const char *) NULL, false, + get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h))) + return false; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->type = STT_OBJECT; + + if (info->shared + && ! _bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + + s = bfd_make_section (abfd, ".rela.plt"); + if (s == NULL + || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_READONLY)) + || ! bfd_set_section_alignment (abfd, s, 3)) + return false; + + if (!elf64_alpha_create_got_section (abfd, info)) + return false; + + return true; +} + +/* The structure of the runtile procedure descriptor created by the + loader for use by the static exception system. */ + +/* FIXME */ + +/* Read ECOFF debugging information from a .mdebug section into a + ecoff_debug_info structure. */ + +static boolean +elf64_alpha_read_ecoff_info (abfd, section, debug) + bfd *abfd; + asection *section; + struct ecoff_debug_info *debug; +{ + HDRR *symhdr; + const struct ecoff_debug_swap *swap; + char *ext_hdr = NULL; + + swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; + + ext_hdr = (char *) bfd_malloc ((size_t) swap->external_hdr_size); + if (ext_hdr == NULL && swap->external_hdr_size != 0) + goto error_return; + + if (bfd_get_section_contents (abfd, section, ext_hdr, (file_ptr) 0, + swap->external_hdr_size) + == false) + goto error_return; + + symhdr = &debug->symbolic_header; + (*swap->swap_hdr_in) (abfd, ext_hdr, symhdr); + + /* The symbolic header contains absolute file offsets and sizes to + read. */ +#define READ(ptr, offset, count, size, type) \ + if (symhdr->count == 0) \ + debug->ptr = NULL; \ + else \ + { \ + debug->ptr = (type) bfd_malloc ((size_t) (size * symhdr->count)); \ + if (debug->ptr == NULL) \ + goto error_return; \ + if (bfd_seek (abfd, (file_ptr) symhdr->offset, SEEK_SET) != 0 \ + || (bfd_read (debug->ptr, size, symhdr->count, \ + abfd) != size * symhdr->count)) \ + goto error_return; \ + } + + READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *); + READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR); + READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR); + READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR); + READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR); + READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext), + union aux_ext *); + READ (ss, cbSsOffset, issMax, sizeof (char), char *); + READ (ssext, cbSsExtOffset, issExtMax, sizeof (char), char *); + READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR); + READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR); + READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size, PTR); +#undef READ + + debug->fdr = NULL; + debug->adjust = NULL; + + return true; + + error_return: + if (ext_hdr != NULL) + free (ext_hdr); + if (debug->line != NULL) + free (debug->line); + if (debug->external_dnr != NULL) + free (debug->external_dnr); + if (debug->external_pdr != NULL) + free (debug->external_pdr); + if (debug->external_sym != NULL) + free (debug->external_sym); + if (debug->external_opt != NULL) + free (debug->external_opt); + if (debug->external_aux != NULL) + free (debug->external_aux); + if (debug->ss != NULL) + free (debug->ss); + if (debug->ssext != NULL) + free (debug->ssext); + if (debug->external_fdr != NULL) + free (debug->external_fdr); + if (debug->external_rfd != NULL) + free (debug->external_rfd); + if (debug->external_ext != NULL) + free (debug->external_ext); + return false; +} + +/* Alpha ELF local labels start with '$'. */ + +static boolean +elf64_alpha_is_local_label (abfd, symbol) + bfd *abfd; + asymbol *symbol; +{ + return symbol->name[0] == '$'; +} + +/* Alpha ELF follows MIPS ELF in using a special find_nearest_line + routine in order to handle the ECOFF debugging information. We + still call this mips_elf_find_line because of the slot + find_line_info in elf_obj_tdata is declared that way. */ + +struct mips_elf_find_line +{ + struct ecoff_debug_info d; + struct ecoff_find_line i; +}; + +static boolean +elf64_alpha_find_nearest_line (abfd, section, symbols, offset, filename_ptr, + functionname_ptr, line_ptr) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + const char **filename_ptr; + const char **functionname_ptr; + unsigned int *line_ptr; +{ + asection *msec; + + msec = bfd_get_section_by_name (abfd, ".mdebug"); + if (msec != NULL) + { + flagword origflags; + struct mips_elf_find_line *fi; + const struct ecoff_debug_swap * const swap = + get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; + + /* If we are called during a link, alpha_elf_final_link may have + cleared the SEC_HAS_CONTENTS field. We force it back on here + if appropriate (which it normally will be). */ + origflags = msec->flags; + if (elf_section_data (msec)->this_hdr.sh_type != SHT_NOBITS) + msec->flags |= SEC_HAS_CONTENTS; + + fi = elf_tdata (abfd)->find_line_info; + if (fi == NULL) + { + bfd_size_type external_fdr_size; + char *fraw_src; + char *fraw_end; + struct fdr *fdr_ptr; + + fi = ((struct mips_elf_find_line *) + bfd_zalloc (abfd, sizeof (struct mips_elf_find_line))); + if (fi == NULL) + { + msec->flags = origflags; + return false; + } + + if (!elf64_alpha_read_ecoff_info (abfd, msec, &fi->d)) + { + msec->flags = origflags; + return false; + } + + /* Swap in the FDR information. */ + fi->d.fdr = ((struct fdr *) + bfd_alloc (abfd, + (fi->d.symbolic_header.ifdMax * + sizeof (struct fdr)))); + if (fi->d.fdr == NULL) + { + msec->flags = origflags; + return false; + } + external_fdr_size = swap->external_fdr_size; + fdr_ptr = fi->d.fdr; + fraw_src = (char *) fi->d.external_fdr; + fraw_end = (fraw_src + + fi->d.symbolic_header.ifdMax * external_fdr_size); + for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++) + (*swap->swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr); + + elf_tdata (abfd)->find_line_info = fi; + + /* Note that we don't bother to ever free this information. + find_nearest_line is either called all the time, as in + objdump -l, so the information should be saved, or it is + rarely called, as in ld error messages, so the memory + wasted is unimportant. Still, it would probably be a + good idea for free_cached_info to throw it away. */ + } + + if (_bfd_ecoff_locate_line (abfd, section, offset, &fi->d, swap, + &fi->i, filename_ptr, functionname_ptr, + line_ptr)) + { + msec->flags = origflags; + return true; + } + + msec->flags = origflags; + } + + /* Fall back on the generic ELF find_nearest_line routine. */ + + return _bfd_elf_find_nearest_line (abfd, section, symbols, offset, + filename_ptr, functionname_ptr, + line_ptr); +} + +/* Structure used to pass information to alpha_elf_output_extsym. */ + +struct extsym_info +{ + bfd *abfd; + struct bfd_link_info *info; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; + boolean failed; +}; + +static boolean +elf64_alpha_output_extsym (h, data) + struct alpha_elf_link_hash_entry *h; + PTR data; +{ + struct extsym_info *einfo = (struct extsym_info *) data; + boolean strip; + asection *sec, *output_section; + + if (h->root.indx == -2) + strip = false; + else if (((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + || (h->root.elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0) + && (h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 + && (h->root.elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0) + strip = true; + else if (einfo->info->strip == strip_all + || (einfo->info->strip == strip_some + && bfd_hash_lookup (einfo->info->keep_hash, + h->root.root.root.string, + false, false) == NULL)) + strip = true; + else + strip = false; + + if (strip) + return true; + + if (h->esym.ifd == -2) + { + h->esym.jmptbl = 0; + h->esym.cobol_main = 0; + h->esym.weakext = 0; + h->esym.reserved = 0; + h->esym.ifd = ifdNil; + h->esym.asym.value = 0; + h->esym.asym.st = stGlobal; + + if (h->root.root.type != bfd_link_hash_defined + && h->root.root.type != bfd_link_hash_defweak) + h->esym.asym.sc = scAbs; + else + { + const char *name; + + sec = h->root.root.u.def.section; + output_section = sec->output_section; + + /* When making a shared library and symbol h is the one from + the another shared library, OUTPUT_SECTION may be null. */ + if (output_section == NULL) + h->esym.asym.sc = scUndefined; + else + { + name = bfd_section_name (output_section->owner, output_section); + + if (strcmp (name, ".text") == 0) + h->esym.asym.sc = scText; + else if (strcmp (name, ".data") == 0) + h->esym.asym.sc = scData; + else if (strcmp (name, ".sdata") == 0) + h->esym.asym.sc = scSData; + else if (strcmp (name, ".rodata") == 0 + || strcmp (name, ".rdata") == 0) + h->esym.asym.sc = scRData; + else if (strcmp (name, ".bss") == 0) + h->esym.asym.sc = scBss; + else if (strcmp (name, ".sbss") == 0) + h->esym.asym.sc = scSBss; + else if (strcmp (name, ".init") == 0) + h->esym.asym.sc = scInit; + else if (strcmp (name, ".fini") == 0) + h->esym.asym.sc = scFini; + else + h->esym.asym.sc = scAbs; + } + } + + h->esym.asym.reserved = 0; + h->esym.asym.index = indexNil; + } + + if (h->root.root.type == bfd_link_hash_common) + h->esym.asym.value = h->root.root.u.c.size; + else if (h->root.root.type == bfd_link_hash_defined + || h->root.root.type == bfd_link_hash_defweak) + { + if (h->esym.asym.sc == scCommon) + h->esym.asym.sc = scBss; + else if (h->esym.asym.sc == scSCommon) + h->esym.asym.sc = scSBss; + + sec = h->root.root.u.def.section; + output_section = sec->output_section; + if (output_section != NULL) + h->esym.asym.value = (h->root.root.u.def.value + + sec->output_offset + + output_section->vma); + else + h->esym.asym.value = 0; + } + else if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) + { + /* Set type and value for a symbol with a function stub. */ + h->esym.asym.st = stProc; + sec = bfd_get_section_by_name (einfo->abfd, ".plt"); + if (sec == NULL) + h->esym.asym.value = 0; + else + { + output_section = sec->output_section; + if (output_section != NULL) + h->esym.asym.value = (h->root.plt_offset + + sec->output_offset + + output_section->vma); + else + h->esym.asym.value = 0; + } +#if 0 /* FIXME? */ + h->esym.ifd = 0; +#endif + } + + if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap, + h->root.root.root.string, + &h->esym)) + { + einfo->failed = true; + return false; + } + + return true; +} + +/* FIXME: Create a runtime procedure table from the .mdebug section. + +static boolean +mips_elf_create_procedure_table (handle, abfd, info, s, debug) + PTR handle; + bfd *abfd; + struct bfd_link_info *info; + asection *s; + struct ecoff_debug_info *debug; + */ + + +static boolean +elf64_alpha_check_relocs (abfd, info, sec, relocs) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + const Elf_Internal_Rela *relocs; +{ + bfd *dynobj; + asection *sgot; + asection *srelgot; + asection *sreloc; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + const Elf_Internal_Rela *rel, *relend; + + if (info->relocateable) + return true; + + sgot = srelgot = sreloc = NULL; + symtab_hdr = &elf_tdata(abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes(abfd); + dynobj = elf_hash_table(info)->dynobj; + if (dynobj) + { + sgot = bfd_get_section_by_name(dynobj, ".got"); + srelgot = bfd_get_section_by_name(dynobj, ".rela.got"); + } + + relend = relocs + sec->reloc_count; + for (rel = relocs; rel < relend; ++rel) + { + unsigned long r_symndx; + struct alpha_elf_link_hash_entry *h; + + r_symndx = ELF64_R_SYM (rel->r_info); + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + h = ((struct alpha_elf_link_hash_entry *) + sym_hashes[r_symndx - symtab_hdr->sh_info]); + + switch (ELF64_R_TYPE (rel->r_info)) + { + case R_ALPHA_LITERAL: + /* If this is a load of a function symbol and we are building a + shared library or calling a shared library, then we need a + .plt entry as well. + + We can tell if it is a function either by noticing the + type of the symbol, or, if the type is undefined, by + noticing that we have a LITUSE(3) reloc next. + + Note that it is not fatal to be wrong guessing that a symbol + is an object, but it is fatal to be wrong guessing that a + symbol is a function. + + Furthermore, the .plt trampoline does not give constant + function addresses, so if we ever see a function's address + taken, we cannot do lazy binding on that function. */ + + if (h) + { + if (rel+1 < relend + && ELF64_R_TYPE (rel[1].r_info) == R_ALPHA_LITUSE) + { + switch (rel[1].r_addend) + { + case 1: /* Memory reference */ + h->flags |= ALPHA_ELF_LINK_HASH_LU_MEM; + break; + case 3: /* Call reference */ + h->flags |= ALPHA_ELF_LINK_HASH_LU_FUNC; + break; + } + } + else + h->flags |= ALPHA_ELF_LINK_HASH_LU_ADDR; + + if (h->root.root.type != bfd_link_hash_undefweak + && (info->shared + || !(h->root.elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR)) + && (h->root.type == STT_FUNC + || (h->root.type == STT_NOTYPE + && (h->flags & ALPHA_ELF_LINK_HASH_LU_FUNC)))) + { + h->root.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + } + } + + if (dynobj == NULL) + { + elf_hash_table(info)->dynobj = dynobj = abfd; + + /* Create the .got section. */ + if (!elf64_alpha_create_got_section(dynobj, info)) + return false; + + sgot = bfd_get_section_by_name(dynobj, ".got"); + srelgot = bfd_get_section_by_name(dynobj, ".rela.got"); + } + + if (h != NULL) + { + if (h->root.got_offset != MINUS_ONE) + { + /* We have already allocated space in this .got. */ + break; + } + + /* Make sure this becomes a dynamic symbol. */ + if (h->root.dynindx == -1 + && ! _bfd_elf_link_record_dynamic_symbol (info, &h->root)) + return false; + + /* Reserve space for a reloc even if we won't use it. */ + srelgot->_raw_size += sizeof(Elf64_External_Rela); + + /* Create the relocation in adjust_dynamic_symbol */ + + h->root.got_offset = sgot->_raw_size; + sgot->_raw_size += 8; + } + else + { + bfd_vma *lgotoff = elf_local_got_offsets(abfd); + if (lgotoff == NULL) + { + size_t size; + + size = elf_tdata(abfd)->symtab_hdr.sh_info * sizeof(bfd_vma); + lgotoff = (bfd_vma *)bfd_alloc(abfd, size); + if (lgotoff == NULL) + return false; + + elf_local_got_offsets(abfd) = lgotoff; + memset(lgotoff, -1, size); + } + + if (lgotoff[ELF64_R_SYM(rel->r_info)] != MINUS_ONE) + { + /* We have already allocated space in the .got. */ + break; + } + lgotoff[ELF64_R_SYM(rel->r_info)] = sgot->_raw_size; + sgot->_raw_size += 8; + + if (info->shared) + { + /* If we are generating a shared object, we need to + output a R_ALPHA_RELATIVE reloc so that the dynamic + linker can adjust this GOT entry. */ + srelgot->_raw_size += sizeof(Elf64_External_Rela); + } + } + break; + + case R_ALPHA_SREL16: + case R_ALPHA_SREL32: + case R_ALPHA_SREL64: + if (h == NULL) + break; + /* FALLTHRU */ + + case R_ALPHA_REFLONG: + case R_ALPHA_REFQUAD: + if (info->shared + || (h != NULL + && !(h->root.elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR))) + { + /* When creating a shared object or referring to a symbol in + a shared object, we must copy these relocs into the + object file. We create a reloc section in dynobj and + make room for the reloc. */ + if (sreloc == NULL) + { + const char *name; + name = (bfd_elf_string_from_elf_section + (abfd, elf_elfheader(abfd)->e_shstrndx, + elf_section_data(sec)->rel_hdr.sh_name)); + if (name == NULL) + return false; + + BFD_ASSERT (strncmp (name, ".rela", 5) == 0 + && strcmp (bfd_get_section_name (abfd, sec), + name+5) == 0); + + sreloc = bfd_get_section_by_name (dynobj, name); + if (sreloc == NULL) + { + sreloc = bfd_make_section (dynobj, name); + if (sreloc == NULL + || !bfd_set_section_flags (dynobj, sreloc, + (SEC_ALLOC|SEC_LOAD + |SEC_HAS_CONTENTS + |SEC_IN_MEMORY + |SEC_READONLY)) + || !bfd_set_section_alignment (dynobj, sreloc, 3)) + return false; + } + } + sreloc->_raw_size += sizeof (Elf64_External_Rela); + } + break; + } + } + + return true; +} + +/* Adjust a symbol defined by a dynamic object and referenced by a + regular object. The current definition is in some section of the + dynamic object, but we're not including those sections. We have to + change the definition to something the rest of the link can + understand. */ + +static boolean +elf64_alpha_adjust_dynamic_symbol (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + bfd *dynobj; + asection *s; + + dynobj = elf_hash_table(info)->dynobj; + + /* If this is a function, put it in the procedure linkage table. We + will fill in the contents of the procedure linkage table later, + though we could actually do it here. */ + + if (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) + { + /* We hadn't seen all of the input symbols or all of the relocations + when we guessed that we needed a .plt entry. Revise our decision. */ + if ((!info->shared + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)) + || (((struct alpha_elf_link_hash_entry *) h)->flags + & ALPHA_ELF_LINK_HASH_LU_ADDR)) + { + h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + return true; + } + + s = bfd_get_section_by_name(dynobj, ".plt"); + BFD_ASSERT(s != NULL); + + /* The first bit of the .plt is reserved. */ + if (s->_raw_size == 0) + s->_raw_size = PLT_HEADER_SIZE; + + h->plt_offset = s->_raw_size; + + /* If this symbol is not defined in a regular file, and we are not + generating a shared library, then set the symbol to the location + in the .plt. This is required to make function pointers compare + equal between the normal executable and the shared library. */ + if (!info->shared) + { + h->root.u.def.section = s; + h->root.u.def.value = s->_raw_size; + } + + s->_raw_size += PLT_ENTRY_SIZE; + + /* We also need an entry in the .rela.plt section. */ + s = bfd_get_section_by_name(dynobj, ".rela.plt"); + BFD_ASSERT(s != NULL); + s->_raw_size += sizeof(Elf64_External_Rela); + + return true; + } + + /* If this is a weak symbol, and there is a real definition, the + processor independent code will have arranged for us to see the + real definition first, and we can just use the same value. */ + if (h->weakdef != NULL) + { + BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined + || h->weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->weakdef->root.u.def.section; + h->root.u.def.value = h->weakdef->root.u.def.value; + return true; + } + + /* This is a reference to a symbol defined by a dynamic object which + is not a function. The Alpha, since it uses .got entries for + symbols even in regular objects, does not need the hackery of a + .dynbss section and COPY dynamic relocations. */ + + return true; +} + +/* Set the sizes of the dynamic sections. */ + +static boolean +elf64_alpha_size_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *s; + boolean reltext; + boolean relplt; + + dynobj = elf_hash_table(info)->dynobj; + BFD_ASSERT(dynobj != NULL); + + if (elf_hash_table(info)->dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (!info->shared) + { + s = bfd_get_section_by_name(dynobj, ".interp"); + BFD_ASSERT(s != NULL); + s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *)ELF_DYNAMIC_INTERPRETER; + } + } + else + { + /* We may have created entries in the .rela.got section. + However, if we are not creating the dynamic sections, we will + not actually use these entries. Reset the size of .rel.got, + which will cause it to get stripped from the output file + below. */ + s = bfd_get_section_by_name (dynobj, ".rela.got"); + if (s != NULL) + s->_raw_size = 0; + } + + /* The check_relocs and adjust_dynamic_symbol entry points have + determined the sizes of the various dynamic sections. Allocate + memory for them. */ + reltext = false; + relplt = false; + for (s = dynobj->sections; s != NULL; s = s->next) + { + const char *name; + boolean strip; + + if (!(s->flags & SEC_IN_MEMORY)) + continue; + + /* It's OK to base decisions on the section name, because none + of the dynobj section names depend upon the input files. */ + name = bfd_get_section_name(dynobj, s); + + /* If we don't need this section, strip it from the output file. + This is to handle .rela.bss and .rela.plt. We must create it + in create_dynamic_sections, because it must be created before + the linker maps input sections to output sections. The + linker does that before adjust_dynamic_symbol is called, and + it is that function which decides whether anything needs to + go into these sections. */ + + strip = false; + + if (strncmp(name, ".rela", 5) == 0) + { + strip = (s->_raw_size == 0); + + if (!strip) + { + asection *target; + + /* If this relocation section applies to a read only + section, then we probably need a DT_TEXTREL entry. */ + target = bfd_get_section_by_name (output_bfd, name + 5); + if (target != NULL + && (target->flags & SEC_READONLY) != 0) + reltext = true; + + if (strcmp(name, ".rela.plt") == 0) + relplt = true; + + /* We use the reloc_count field as a counter if we need + to copy relocs into the output file. */ + s->reloc_count = 0; + } + } + else if (strcmp(name, ".got") == 0) + { + /* If we are generating a shared library, we generate a + section symbol for each output section. These are local + symbols, which means that they must come first in the + dynamic symbol table. That means we must increment the + dynamic symbol index of every other dynamic symbol. */ + if (info->shared) + { + long c[2], i; + asection *p; + + c[0] = 0; + c[1] = bfd_count_sections(output_bfd); + + elf_link_hash_traverse (elf_hash_table(info), + elf64_alpha_adjust_dynindx, + (PTR)c); + elf_hash_table (info)->dynsymcount += c[1]; + + for (i = 1, p = output_bfd->sections; + p != NULL; + p = p->next, i++) + { + elf_section_data (p)->dynindx = i; + /* These symbols will have no names, so we don't need to + fiddle with dynstr_index. */ + } + } + } + else if (strcmp (name, ".plt") != 0) + { + /* It's not one of our sections, so don't allocate space. */ + continue; + } + + if (strip) + { + asection **spp; + + for (spp = &s->output_section->owner->sections; + *spp != s->output_section; + spp = &(*spp)->next) + continue; + *spp = s->output_section->next; + --s->output_section->owner->section_count; + + continue; + } + + /* Allocate memory for the section contents. */ + s->contents = (bfd_byte *) bfd_zalloc(dynobj, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) + return false; + } + + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Add some entries to the .dynamic section. We fill in the + values later, in elf64_alpha_finish_dynamic_sections, but we + must add the entries now so that we get the correct size for + the .dynamic section. The DT_DEBUG entry is filled in by the + dynamic linker and used by the debugger. */ + if (!info->shared) + { + if (!bfd_elf64_add_dynamic_entry (info, DT_DEBUG, 0)) + return false; + } + + if (! bfd_elf64_add_dynamic_entry (info, DT_PLTGOT, 0)) + return false; + + if (relplt) + { + if (! bfd_elf64_add_dynamic_entry (info, DT_PLTRELSZ, 0) + || ! bfd_elf64_add_dynamic_entry (info, DT_PLTREL, DT_RELA) + || ! bfd_elf64_add_dynamic_entry (info, DT_JMPREL, 0)) + return false; + } + + if (! bfd_elf64_add_dynamic_entry (info, DT_RELA, 0) + || ! bfd_elf64_add_dynamic_entry (info, DT_RELASZ, 0) + || ! bfd_elf64_add_dynamic_entry (info, DT_RELAENT, + sizeof(Elf64_External_Rela))) + return false; + + if (reltext) + { + if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0)) + return false; + } + } + + return true; +} + +/* Increment the index of a dynamic symbol by a given amount. Called + via elf_link_hash_traverse. */ + +static boolean +elf64_alpha_adjust_dynindx (h, cparg) + struct elf_link_hash_entry *h; + PTR cparg; +{ + long *cp = (long *)cparg; + + if (h->dynindx >= cp[0]) + h->dynindx += cp[1]; + + return true; +} + +/* Relocate an Alpha ELF section. */ + +static boolean +elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, local_syms, local_sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + Elf_Internal_Rela *relocs; + Elf_Internal_Sym *local_syms; + asection **local_sections; +{ + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + asection *sec, *sgot, *splt; + bfd *dynobj; + bfd_vma gp; + + symtab_hdr = &elf_tdata(input_bfd)->symtab_hdr; + + /* Find the gp value for this input bfd. */ + sgot = NULL; + gp = 0; + dynobj = elf_hash_table(info)->dynobj; + if (dynobj) + { + sgot = bfd_get_section_by_name (dynobj, ".got"); + splt = bfd_get_section_by_name (dynobj, ".plt"); + + gp = _bfd_get_gp_value(dynobj); + if (gp == 0) + { + gp = (sgot->output_section->vma + + sgot->output_offset + + 0x8000); + _bfd_set_gp_value(dynobj, gp); + } + } + + rel = relocs; + relend = relocs + input_section->reloc_count; + for (; rel < relend; rel++) + { + int r_type; + reloc_howto_type *howto; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + bfd_vma relocation; + bfd_vma addend; + bfd_reloc_status_type r; + + r_type = ELF64_R_TYPE(rel->r_info); + if (r_type < 0 || r_type >= (int) R_ALPHA_max) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + howto = elf64_alpha_howto_table + r_type; + + r_symndx = ELF64_R_SYM(rel->r_info); + + if (info->relocateable) + { + /* This is a relocateable link. We don't have to change + anything, unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) + { + sec = local_sections[r_symndx]; + rel->r_addend += sec->output_offset + sym->st_value; + } + } + + continue; + } + + /* This is a final link. */ + + h = NULL; + sym = NULL; + sec = NULL; + + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = (sec->output_section->vma + + sec->output_offset + + sym->st_value); + } + else + { + h = elf_sym_hashes(input_bfd)[r_symndx - symtab_hdr->sh_info]; + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *)h->root.u.i.link; + + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + + /* If the symbol was defined as a common symbol in a + regular object file, and there was no definition in + any dynamic object, then the linker will have + allocated space for the symbol in a common section + but the ELF_LINK_HASH_DEF_REGULAR flag will not have + been set. This is done for dynamic symbols in + elf_adjust_dynamic_symbol but this is not done for + non-dynamic symbols, somehow. */ + if ((h->elf_link_hash_flags + & (ELF_LINK_HASH_DEF_REGULAR + | ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_DEF_DYNAMIC)) + == ELF_LINK_HASH_REF_REGULAR + && !(sec->owner->flags & DYNAMIC)) + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + +#if rth_notdef + if ((r_type == R_ALPHA_LITERAL + && elf_hash_table(info)->dynamic_sections_created + && (!info->shared + || !info->symbolic + || !(h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR))) + || (info->shared + && (!info->symbolic + || !(h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR)) + && (input_section->flags & SEC_ALLOC) + && (r_type == R_ALPHA_REFLONG + || r_type == R_ALPHA_REFQUAD + || r_type == R_ALPHA_LITERAL))) + { + /* In these cases, we don't need the relocation value. + We check specially because in some obscure cases + sec->output_section will be NULL. */ + relocation = 0; + } +#else + /* FIXME: Are not these obscure cases simply bugs? Let's + get something working and come back to this. */ + if (sec->output_section == NULL) + relocation = 0; +#endif /* rth_notdef */ + else + { + relocation = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + } + else if (h->root.type == bfd_link_hash_undefweak) + relocation = 0; + else if (info->shared && !info->symbolic) + relocation = 0; + else + { + if (!((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, rel->r_offset))) + return false; + relocation = 0; + } + } + addend = rel->r_addend; + + switch (r_type) + { + case R_ALPHA_GPDISP: + { + bfd_byte *p_ldah, *p_lda; + + relocation = (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset); + + p_ldah = contents + rel->r_offset - input_section->vma; + p_lda = p_ldah + rel->r_addend; + + r = elf64_alpha_do_reloc_gpdisp (input_bfd, gp - relocation, + p_ldah, p_lda); + } + break; + + case R_ALPHA_OP_PUSH: + case R_ALPHA_OP_STORE: + case R_ALPHA_OP_PSUB: + case R_ALPHA_OP_PRSHIFT: + /* FIXME */ + abort(); + + case R_ALPHA_LITERAL: + { + bfd_vma gotoff; + + BFD_ASSERT(gp != 0); + BFD_ASSERT(sgot != NULL); + if (h != NULL) + { + gotoff = h->got_offset; + } + else + { + gotoff = elf_local_got_offsets (input_bfd)[r_symndx]; + + /* Use the lsb as a flag indicating that we've already + output the relocation entry. */ + if (info->shared) + if (gotoff & 1) + gotoff &= ~(bfd_vma)1; + else + { + asection *srel; + Elf_Internal_Rela outrel; + + srel = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT(srel != NULL); + + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + gotoff); + outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE); + outrel.r_addend = 0; + + bfd_elf64_swap_reloca_out (output_bfd, &outrel, + ((Elf64_External_Rela *) + srel->contents) + + srel->reloc_count++); + + elf_local_got_offsets (input_bfd)[r_symndx] |= 1; + } + } + + /* Initialize the .got entry. */ + bfd_put_64 (output_bfd, relocation, sgot->contents + gotoff); + + /* Figure the gprel relocation. */ + addend = 0; + relocation = (sgot->output_section->vma + + sgot->output_offset + + gotoff); + relocation -= gp; + } + /* overflow handled by _bfd_final_link_relocate */ + goto default_reloc; + + case R_ALPHA_GPREL32: + BFD_ASSERT(gp != 0); + relocation -= gp; + goto default_reloc; + + case R_ALPHA_BRADDR: + case R_ALPHA_HINT: + /* The regular PC-relative stuff measures from the start of + the instruction rather than the end. */ + addend -= 4; + goto default_reloc; + + case R_ALPHA_REFLONG: + case R_ALPHA_REFQUAD: + if (info->shared + || (h && !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) + { + asection *srel; + const char *name; + Elf_Internal_Rela outrel; + + name = (bfd_elf_string_from_elf_section + (input_bfd, elf_elfheader(input_bfd)->e_shstrndx, + elf_section_data(input_section)->rel_hdr.sh_name)); + BFD_ASSERT(name != NULL); + + srel = bfd_get_section_by_name(dynobj, name); + BFD_ASSERT(srel != NULL); + + outrel.r_offset = (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset); + outrel.r_addend = 0; + if (h) + { + BFD_ASSERT(h->dynindx != -1); + outrel.r_info = ELF64_R_INFO(h->dynindx, r_type); + relocation = 0; + } + else + { + outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE); + } + + bfd_elf64_swap_reloca_out (output_bfd, &outrel, + ((Elf64_External_Rela *) + srel->contents) + + srel->reloc_count++); + } + goto default_reloc; + + default: + default_reloc: + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, relocation, + addend); + break; + } + + switch (r) + { + case bfd_reloc_ok: + break; + + case bfd_reloc_overflow: + { + const char *name; + + if (h != NULL) + name = h->root.root.string; + else + { + name = (bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name)); + if (name == NULL) + return false; + if (*name == '\0') + name = bfd_section_name (input_bfd, sec); + } + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset))) + return false; + } + break; + + default: + case bfd_reloc_outofrange: + abort (); + } + } + + return true; +} + +/* Finish up dynamic symbol handling. We set the contents of various + dynamic sections here. */ + +static boolean +elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym) + bfd *output_bfd; + struct bfd_link_info *info; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; +{ + bfd *dynobj = elf_hash_table(info)->dynobj; + + if (h->plt_offset != MINUS_ONE) + { + asection *splt, *sgot, *srel; + Elf_Internal_Rela outrel; + bfd_vma got_addr, plt_addr; + bfd_vma plt_index; + + /* This symbol has an entry in the procedure linkage table. */ + + BFD_ASSERT(h->dynindx != -1); + BFD_ASSERT(h->got_offset != MINUS_ONE); + + splt = bfd_get_section_by_name(dynobj, ".plt"); + BFD_ASSERT(splt != NULL); + srel = bfd_get_section_by_name(dynobj, ".rela.plt"); + BFD_ASSERT(srel != NULL); + sgot = bfd_get_section_by_name(dynobj, ".got"); + BFD_ASSERT(sgot != NULL); + + got_addr = (sgot->output_section->vma + + sgot->output_offset + + h->got_offset); + plt_addr = (splt->output_section->vma + + splt->output_offset + + h->plt_offset); + + plt_index = (h->plt_offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE; + + /* Fill in the entry in the procedure linkage table. */ + { + unsigned insn1, insn2, insn3; + long hi, lo; + + /* decompose the reloc offset for the plt for ldah+lda */ + hi = plt_index * sizeof(Elf64_External_Rela); + lo = ((hi & 0xffff) ^ 0x8000) - 0x8000; + hi = (hi - lo) >> 16; + + insn1 = PLT_ENTRY_WORD1 | (hi & 0xffff); + insn2 = PLT_ENTRY_WORD2 | (lo & 0xffff); + insn3 = PLT_ENTRY_WORD3 | ((-(h->plt_offset + 12) >> 2) & 0x1fffff); + + bfd_put_32 (output_bfd, insn1, splt->contents + h->plt_offset); + bfd_put_32 (output_bfd, insn2, splt->contents + h->plt_offset + 4); + bfd_put_32 (output_bfd, insn3, splt->contents + h->plt_offset + 8); + } + + /* Fill in the entry in the .rela.plt section. */ + outrel.r_offset = got_addr; + outrel.r_info = ELF64_R_INFO(h->dynindx, R_ALPHA_JMP_SLOT); + outrel.r_addend = 0; + + bfd_elf64_swap_reloca_out (output_bfd, &outrel, + ((Elf64_External_Rela *)srel->contents + + plt_index)); + + if (!(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)) + { + /* Mark the symbol as undefined, rather than as defined in the + .plt section. Leave the value alone. */ + sym->st_shndx = SHN_UNDEF; + } + + /* Fill in the entry in the global offset table. */ + bfd_put_64 (output_bfd, plt_addr, sgot->contents + h->got_offset); + } + else if (h->got_offset != MINUS_ONE) + { + asection *sgot, *srel; + Elf_Internal_Rela outrel; + + BFD_ASSERT(h->dynindx != -1); + + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + srel = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT (srel != NULL); + + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + h->got_offset); + outrel.r_addend = 0; + if (info->shared + && info->symbolic + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)) + outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE); + else + { + bfd_put_64(output_bfd, (bfd_vma)0, sgot->contents + h->got_offset); + outrel.r_info = ELF64_R_INFO(h->dynindx, R_ALPHA_GLOB_DAT); + } + + bfd_elf64_swap_reloca_out (output_bfd, &outrel, + ((Elf64_External_Rela *)srel->contents + + srel->reloc_count++)); + } + + /* Mark some specially defined symbols as absolute. */ + if (strcmp (h->root.root.string, "_DYNAMIC") == 0 + || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 + || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0) + sym->st_shndx = SHN_ABS; + + return true; +} + +/* Finish up the dynamic sections. */ + +static boolean +elf64_alpha_finish_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *sdyn; + asection *sgot; + + dynobj = elf_hash_table (info)->dynobj; + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + + if (elf_hash_table (info)->dynamic_sections_created) + { + asection *splt; + Elf64_External_Dyn *dyncon, *dynconend; + + splt = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (splt != NULL && sdyn != NULL); + + dyncon = (Elf64_External_Dyn *) sdyn->contents; + dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + const char *name; + asection *s; + + bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + case DT_PLTGOT: + name = ".plt"; + goto get_vma; + case DT_PLTRELSZ: + name = ".rela.plt"; + goto get_size; + case DT_JMPREL: + name = ".rela.plt"; + goto get_vma; + + case DT_RELASZ: + /* My interpretation of the TIS v1.1 ELF document indicates + that RELASZ should not include JMPREL. This is not what + the rest of the BFD does. It is, however, what the + glibc ld.so wants. Do this fixup here until we found + out who is right. */ + s = bfd_get_section_by_name (output_bfd, ".rela.plt"); + if (s) + { + dyn.d_un.d_val -= + (s->_cooked_size ? s->_cooked_size : s->_raw_size); + } + break; + + get_vma: + s = bfd_get_section_by_name (output_bfd, name); + dyn.d_un.d_ptr = (s ? s->vma : 0); + break; + + get_size: + s = bfd_get_section_by_name (output_bfd, name); + dyn.d_un.d_val = + (s->_cooked_size ? s->_cooked_size : s->_raw_size); + break; + } + + bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); + } + + /* Initialize the PLT0 entry */ + if (splt->_raw_size > 0) + { + bfd_put_32 (output_bfd, PLT_HEADER_WORD1, splt->contents); + bfd_put_32 (output_bfd, PLT_HEADER_WORD2, splt->contents + 4); + bfd_put_32 (output_bfd, PLT_HEADER_WORD3, splt->contents + 8); + bfd_put_32 (output_bfd, PLT_HEADER_WORD4, splt->contents + 12); + + /* The next two words will be filled in by ld.so */ + bfd_put_64 (output_bfd, 0, splt->contents + 16); + bfd_put_64 (output_bfd, 0, splt->contents + 24); + + elf_section_data (splt->output_section)->this_hdr.sh_entsize = + PLT_HEADER_SIZE; + } + } + + /* Set the first entry in the global offset table to the address of + the dynamic section. */ + sgot = bfd_get_section_by_name (dynobj, ".got"); + if (sgot && sgot->_raw_size > 0) + { + if (sdyn == NULL) + bfd_put_64 (output_bfd, (bfd_vma)0, sgot->contents); + else + bfd_put_64 (output_bfd, + sdyn->output_section->vma + sdyn->output_offset, + sgot->contents); + + elf_section_data (sgot->output_section)->this_hdr.sh_entsize = + 8 * RESERVED_GOT_ENTRIES; + } + + if (info->shared) + { + asection *sdynsym; + asection *s; + Elf_Internal_Sym sym; + + /* Set up the section symbols for the output sections. */ + + sdynsym = bfd_get_section_by_name (dynobj, ".dynsym"); + BFD_ASSERT (sdynsym != NULL); + + sym.st_size = 0; + sym.st_name = 0; + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); + sym.st_other = 0; + + for (s = output_bfd->sections; s != NULL; s = s->next) + { + int indx; + + sym.st_value = s->vma; + + indx = elf_section_data (s)->this_idx; + BFD_ASSERT (indx > 0); + sym.st_shndx = indx; + + bfd_elf64_swap_symbol_out (output_bfd, &sym, + (PTR) (((Elf64_External_Sym *) + sdynsym->contents) + + elf_section_data (s)->dynindx)); + } + + /* Set the sh_info field of the output .dynsym section to the + index of the first global symbol. */ + elf_section_data (sdynsym->output_section)->this_hdr.sh_info = + bfd_count_sections (output_bfd) + 1; + } + + return true; +} + +/* We need to use a special link routine to handle the .reginfo and + the .mdebug sections. We need to merge all instances of these + sections together, not write them all out sequentially. */ + +static boolean +elf64_alpha_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + asection *o; + struct bfd_link_order *p; + asection *reginfo_sec, *mdebug_sec, *gptab_data_sec, *gptab_bss_sec; + struct ecoff_debug_info debug; + const struct ecoff_debug_swap *swap + = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; + HDRR *symhdr = &debug.symbolic_header; + PTR mdebug_handle = NULL; + + /* Go through the sections and collect the .reginfo and .mdebug + information. */ + reginfo_sec = NULL; + mdebug_sec = NULL; + gptab_data_sec = NULL; + gptab_bss_sec = NULL; + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { +#ifdef ERIC_neverdef + if (strcmp (o->name, ".reginfo") == 0) + { + memset (®info, 0, sizeof reginfo); + + /* We have found the .reginfo section in the output file. + Look through all the link_orders comprising it and merge + the information together. */ + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + asection *input_section; + bfd *input_bfd; + Elf64_External_RegInfo ext; + Elf64_RegInfo sub; + + if (p->type != bfd_indirect_link_order) + { + if (p->type == bfd_fill_link_order) + continue; + abort (); + } + + input_section = p->u.indirect.section; + input_bfd = input_section->owner; + + /* The linker emulation code has probably clobbered the + size to be zero bytes. */ + if (input_section->_raw_size == 0) + input_section->_raw_size = sizeof (Elf64_External_RegInfo); + + if (! bfd_get_section_contents (input_bfd, input_section, + (PTR) &ext, + (file_ptr) 0, + sizeof ext)) + return false; + + bfd_alpha_elf64_swap_reginfo_in (input_bfd, &ext, &sub); + + reginfo.ri_gprmask |= sub.ri_gprmask; + reginfo.ri_cprmask[0] |= sub.ri_cprmask[0]; + reginfo.ri_cprmask[1] |= sub.ri_cprmask[1]; + reginfo.ri_cprmask[2] |= sub.ri_cprmask[2]; + reginfo.ri_cprmask[3] |= sub.ri_cprmask[3]; + + /* ri_gp_value is set by the function + alpha_elf_section_processing when the section is + finally written out. */ + + /* Hack: reset the SEC_HAS_CONTENTS flag so that + elf_link_input_bfd ignores this section. */ + input_section->flags &=~ SEC_HAS_CONTENTS; + } + + /* Force the section size to the value we want. */ + o->_raw_size = sizeof (Elf64_External_RegInfo); + + /* Skip this section later on (I don't think this currently + matters, but someday it might). */ + o->link_order_head = (struct bfd_link_order *) NULL; + + reginfo_sec = o; + } +#endif + + if (strcmp (o->name, ".mdebug") == 0) + { + struct extsym_info einfo; + + /* We have found the .mdebug section in the output file. + Look through all the link_orders comprising it and merge + the information together. */ + symhdr->magic = swap->sym_magic; + /* FIXME: What should the version stamp be? */ + symhdr->vstamp = 0; + symhdr->ilineMax = 0; + symhdr->cbLine = 0; + symhdr->idnMax = 0; + symhdr->ipdMax = 0; + symhdr->isymMax = 0; + symhdr->ioptMax = 0; + symhdr->iauxMax = 0; + symhdr->issMax = 0; + symhdr->issExtMax = 0; + symhdr->ifdMax = 0; + symhdr->crfd = 0; + symhdr->iextMax = 0; + + /* We accumulate the debugging information itself in the + debug_info structure. */ + debug.line = NULL; + debug.external_dnr = NULL; + debug.external_pdr = NULL; + debug.external_sym = NULL; + debug.external_opt = NULL; + debug.external_aux = NULL; + debug.ss = NULL; + debug.ssext = debug.ssext_end = NULL; + debug.external_fdr = NULL; + debug.external_rfd = NULL; + debug.external_ext = debug.external_ext_end = NULL; + + mdebug_handle = bfd_ecoff_debug_init (abfd, &debug, swap, info); + if (mdebug_handle == (PTR) NULL) + return false; + + if (1) + { + asection *s; + EXTR esym; + bfd_vma last; + unsigned int i; + static const char * const name[] = + { + ".text", ".init", ".fini", ".data", + ".rodata", ".sdata", ".sbss", ".bss" + }; + static const int sc[] = { scText, scInit, scFini, scData, + scRData, scSData, scSBss, scBss }; + + esym.jmptbl = 0; + esym.cobol_main = 0; + esym.weakext = 0; + esym.reserved = 0; + esym.ifd = ifdNil; + esym.asym.iss = issNil; + esym.asym.st = stLocal; + esym.asym.reserved = 0; + esym.asym.index = indexNil; + for (i = 0; i < 8; i++) + { + esym.asym.sc = sc[i]; + s = bfd_get_section_by_name (abfd, name[i]); + if (s != NULL) + { + esym.asym.value = s->vma; + last = s->vma + s->_raw_size; + } + else + esym.asym.value = last; + + if (! bfd_ecoff_debug_one_external (abfd, &debug, swap, + name[i], &esym)) + return false; + } + } + + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + asection *input_section; + bfd *input_bfd; + const struct ecoff_debug_swap *input_swap; + struct ecoff_debug_info input_debug; + char *eraw_src; + char *eraw_end; + + if (p->type != bfd_indirect_link_order) + { + if (p->type == bfd_fill_link_order) + continue; + abort (); + } + + input_section = p->u.indirect.section; + input_bfd = input_section->owner; + + if (bfd_get_flavour (input_bfd) != bfd_target_elf_flavour + || (get_elf_backend_data (input_bfd) + ->elf_backend_ecoff_debug_swap) == NULL) + { + /* I don't know what a non ALPHA ELF bfd would be + doing with a .mdebug section, but I don't really + want to deal with it. */ + continue; + } + + input_swap = (get_elf_backend_data (input_bfd) + ->elf_backend_ecoff_debug_swap); + + BFD_ASSERT (p->size == input_section->_raw_size); + + /* The ECOFF linking code expects that we have already + read in the debugging information and set up an + ecoff_debug_info structure, so we do that now. */ + if (!elf64_alpha_read_ecoff_info (input_bfd, input_section, + &input_debug)) + return false; + + if (! (bfd_ecoff_debug_accumulate + (mdebug_handle, abfd, &debug, swap, input_bfd, + &input_debug, input_swap, info))) + return false; + + /* Loop through the external symbols. For each one with + interesting information, try to find the symbol in + the linker global hash table and save the information + for the output external symbols. */ + eraw_src = input_debug.external_ext; + eraw_end = (eraw_src + + (input_debug.symbolic_header.iextMax + * input_swap->external_ext_size)); + for (; + eraw_src < eraw_end; + eraw_src += input_swap->external_ext_size) + { + EXTR ext; + const char *name; + struct alpha_elf_link_hash_entry *h; + + (*input_swap->swap_ext_in) (input_bfd, (PTR) eraw_src, &ext); + if (ext.asym.sc == scNil + || ext.asym.sc == scUndefined + || ext.asym.sc == scSUndefined) + continue; + + name = input_debug.ssext + ext.asym.iss; + h = alpha_elf_link_hash_lookup (alpha_elf_hash_table (info), + name, false, false, true); + if (h == NULL || h->esym.ifd != -2) + continue; + + if (ext.ifd != -1) + { + BFD_ASSERT (ext.ifd + < input_debug.symbolic_header.ifdMax); + ext.ifd = input_debug.ifdmap[ext.ifd]; + } + + h->esym = ext; + } + + /* Free up the information we just read. */ + free (input_debug.line); + free (input_debug.external_dnr); + free (input_debug.external_pdr); + free (input_debug.external_sym); + free (input_debug.external_opt); + free (input_debug.external_aux); + free (input_debug.ss); + free (input_debug.ssext); + free (input_debug.external_fdr); + free (input_debug.external_rfd); + free (input_debug.external_ext); + + /* Hack: reset the SEC_HAS_CONTENTS flag so that + elf_link_input_bfd ignores this section. */ + input_section->flags &=~ SEC_HAS_CONTENTS; + } + +#ifdef ERIC_neverdef + if (info->shared) + { + /* Create .rtproc section. */ + rtproc_sec = bfd_get_section_by_name (abfd, ".rtproc"); + if (rtproc_sec == NULL) + { + flagword flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_READONLY); + + rtproc_sec = bfd_make_section (abfd, ".rtproc"); + if (rtproc_sec == NULL + || ! bfd_set_section_flags (abfd, rtproc_sec, flags) + || ! bfd_set_section_alignment (abfd, rtproc_sec, 12)) + return false; + } + + if (! alpha_elf_create_procedure_table (mdebug_handle, abfd, + info, rtproc_sec, &debug)) + return false; + } +#endif + + + /* Build the external symbol information. */ + einfo.abfd = abfd; + einfo.info = info; + einfo.debug = &debug; + einfo.swap = swap; + einfo.failed = false; + elf_link_hash_traverse (elf_hash_table (info), + elf64_alpha_output_extsym, + (PTR) &einfo); + if (einfo.failed) + return false; + + /* Set the size of the .mdebug section. */ + o->_raw_size = bfd_ecoff_debug_size (abfd, &debug, swap); + + /* Skip this section later on (I don't think this currently + matters, but someday it might). */ + o->link_order_head = (struct bfd_link_order *) NULL; + + mdebug_sec = o; + } + +#ifdef ERIC_neverdef + if (strncmp (o->name, ".gptab.", sizeof ".gptab." - 1) == 0) + { + const char *subname; + unsigned int c; + Elf64_gptab *tab; + Elf64_External_gptab *ext_tab; + unsigned int i; + + /* The .gptab.sdata and .gptab.sbss sections hold + information describing how the small data area would + change depending upon the -G switch. These sections + not used in executables files. */ + if (! info->relocateable) + { + asection **secpp; + + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + asection *input_section; + + if (p->type != bfd_indirect_link_order) + { + if (p->type == bfd_fill_link_order) + continue; + abort (); + } + + input_section = p->u.indirect.section; + + /* Hack: reset the SEC_HAS_CONTENTS flag so that + elf_link_input_bfd ignores this section. */ + input_section->flags &=~ SEC_HAS_CONTENTS; + } + + /* Skip this section later on (I don't think this + currently matters, but someday it might). */ + o->link_order_head = (struct bfd_link_order *) NULL; + + /* Really remove the section. */ + for (secpp = &abfd->sections; + *secpp != o; + secpp = &(*secpp)->next) + ; + *secpp = (*secpp)->next; + --abfd->section_count; + + continue; + } + + /* There is one gptab for initialized data, and one for + uninitialized data. */ + if (strcmp (o->name, ".gptab.sdata") == 0) + gptab_data_sec = o; + else if (strcmp (o->name, ".gptab.sbss") == 0) + gptab_bss_sec = o; + else + { + (*_bfd_error_handler) + ("%s: illegal section name `%s'", + bfd_get_filename (abfd), o->name); + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } + + /* The linker script always combines .gptab.data and + .gptab.sdata into .gptab.sdata, and likewise for + .gptab.bss and .gptab.sbss. It is possible that there is + no .sdata or .sbss section in the output file, in which + case we must change the name of the output section. */ + subname = o->name + sizeof ".gptab" - 1; + if (bfd_get_section_by_name (abfd, subname) == NULL) + { + if (o == gptab_data_sec) + o->name = ".gptab.data"; + else + o->name = ".gptab.bss"; + subname = o->name + sizeof ".gptab" - 1; + BFD_ASSERT (bfd_get_section_by_name (abfd, subname) != NULL); + } + + /* Set up the first entry. */ + c = 1; + tab = (Elf64_gptab *) bfd_malloc (c * sizeof (Elf64_gptab)); + if (tab == NULL) + return false; + tab[0].gt_header.gt_current_g_value = elf_gp_size (abfd); + tab[0].gt_header.gt_unused = 0; + + /* Combine the input sections. */ + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + asection *input_section; + bfd *input_bfd; + bfd_size_type size; + unsigned long last; + bfd_size_type gpentry; + + if (p->type != bfd_indirect_link_order) + { + if (p->type == bfd_fill_link_order) + continue; + abort (); + } + + input_section = p->u.indirect.section; + input_bfd = input_section->owner; + + /* Combine the gptab entries for this input section one + by one. We know that the input gptab entries are + sorted by ascending -G value. */ + size = bfd_section_size (input_bfd, input_section); + last = 0; + for (gpentry = sizeof (Elf64_External_gptab); + gpentry < size; + gpentry += sizeof (Elf64_External_gptab)) + { + Elf64_External_gptab ext_gptab; + Elf64_gptab int_gptab; + unsigned long val; + unsigned long add; + boolean exact; + unsigned int look; + + if (! (bfd_get_section_contents + (input_bfd, input_section, (PTR) &ext_gptab, + gpentry, sizeof (Elf64_External_gptab)))) + { + free (tab); + return false; + } + + bfd_alpha_elf64_swap_gptab_in (input_bfd, &ext_gptab, + &int_gptab); + val = int_gptab.gt_entry.gt_g_value; + add = int_gptab.gt_entry.gt_bytes - last; + + exact = false; + for (look = 1; look < c; look++) + { + if (tab[look].gt_entry.gt_g_value >= val) + tab[look].gt_entry.gt_bytes += add; + + if (tab[look].gt_entry.gt_g_value == val) + exact = true; + } + + if (! exact) + { + Elf64_gptab *new_tab; + unsigned int max; + + /* We need a new table entry. */ + new_tab = ((Elf64_gptab *) + bfd_realloc ((PTR) tab, + (c + 1) * sizeof (Elf64_gptab))); + if (new_tab == NULL) + { + free (tab); + return false; + } + tab = new_tab; + tab[c].gt_entry.gt_g_value = val; + tab[c].gt_entry.gt_bytes = add; + + /* Merge in the size for the next smallest -G + value, since that will be implied by this new + value. */ + max = 0; + for (look = 1; look < c; look++) + { + if (tab[look].gt_entry.gt_g_value < val + && (max == 0 + || (tab[look].gt_entry.gt_g_value + > tab[max].gt_entry.gt_g_value))) + max = look; + } + if (max != 0) + tab[c].gt_entry.gt_bytes += + tab[max].gt_entry.gt_bytes; + + ++c; + } + + last = int_gptab.gt_entry.gt_bytes; + } + + /* Hack: reset the SEC_HAS_CONTENTS flag so that + elf_link_input_bfd ignores this section. */ + input_section->flags &=~ SEC_HAS_CONTENTS; + } + + /* The table must be sorted by -G value. */ + if (c > 2) + qsort (tab + 1, c - 1, sizeof (tab[0]), gptab_compare); + + /* Swap out the table. */ + ext_tab = ((Elf64_External_gptab *) + bfd_alloc (abfd, c * sizeof (Elf64_External_gptab))); + if (ext_tab == NULL) + { + free (tab); + return false; + } + + for (i = 0; i < c; i++) + bfd_alpha_elf64_swap_gptab_out (abfd, tab + i, ext_tab + i); + free (tab); + + o->_raw_size = c * sizeof (Elf64_External_gptab); + o->contents = (bfd_byte *) ext_tab; + + /* Skip this section later on (I don't think this currently + matters, but someday it might). */ + o->link_order_head = (struct bfd_link_order *) NULL; + } +#endif + + } + + /* Invoke the regular ELF backend linker to do all the work. */ + if (! bfd_elf64_bfd_final_link (abfd, info)) + return false; + + /* Now write out the computed sections. */ + +#ifdef ERIC_neverdef + if (reginfo_sec != (asection *) NULL) + { + Elf64_External_RegInfo ext; + + bfd_alpha_elf64_swap_reginfo_out (abfd, ®info, &ext); + if (! bfd_set_section_contents (abfd, reginfo_sec, (PTR) &ext, + (file_ptr) 0, sizeof ext)) + return false; + } +#endif + + if (mdebug_sec != (asection *) NULL) + { + BFD_ASSERT (abfd->output_has_begun); + if (! bfd_ecoff_write_accumulated_debug (mdebug_handle, abfd, &debug, + swap, info, + mdebug_sec->filepos)) + return false; + + bfd_ecoff_debug_free (mdebug_handle, abfd, &debug, swap, info); + } + + if (gptab_data_sec != (asection *) NULL) + { + if (! bfd_set_section_contents (abfd, gptab_data_sec, + gptab_data_sec->contents, + (file_ptr) 0, + gptab_data_sec->_raw_size)) + return false; + } + + if (gptab_bss_sec != (asection *) NULL) + { + if (! bfd_set_section_contents (abfd, gptab_bss_sec, + gptab_bss_sec->contents, + (file_ptr) 0, + gptab_bss_sec->_raw_size)) + return false; + } + + return true; +} + +/* ECOFF swapping routines. These are used when dealing with the + .mdebug section, which is in the ECOFF debugging format. Copied + from elf32-mips.c. */ +static const struct ecoff_debug_swap +elf64_alpha_ecoff_debug_swap = +{ + /* Symbol table magic number. */ + magicSym2, + /* Alignment of debugging information. E.g., 4. */ + 8, + /* Sizes of external symbolic information. */ + sizeof (struct hdr_ext), + sizeof (struct dnr_ext), + sizeof (struct pdr_ext), + sizeof (struct sym_ext), + sizeof (struct opt_ext), + sizeof (struct fdr_ext), + sizeof (struct rfd_ext), + sizeof (struct ext_ext), + /* Functions to swap in external symbolic data. */ + ecoff_swap_hdr_in, + ecoff_swap_dnr_in, + ecoff_swap_pdr_in, + ecoff_swap_sym_in, + ecoff_swap_opt_in, + ecoff_swap_fdr_in, + ecoff_swap_rfd_in, + ecoff_swap_ext_in, + _bfd_ecoff_swap_tir_in, + _bfd_ecoff_swap_rndx_in, + /* Functions to swap out external symbolic data. */ + ecoff_swap_hdr_out, + ecoff_swap_dnr_out, + ecoff_swap_pdr_out, + ecoff_swap_sym_out, + ecoff_swap_opt_out, + ecoff_swap_fdr_out, + ecoff_swap_rfd_out, + ecoff_swap_ext_out, + _bfd_ecoff_swap_tir_out, + _bfd_ecoff_swap_rndx_out, + /* Function to read in symbolic data. */ + elf64_alpha_read_ecoff_info +}; + +#define TARGET_LITTLE_SYM bfd_elf64_alpha_vec +#define TARGET_LITTLE_NAME "elf64-alpha" +#define ELF_ARCH bfd_arch_alpha +#define ELF_MACHINE_CODE EM_ALPHA +#define ELF_MAXPAGESIZE 0x100000 + +#define bfd_elf64_bfd_link_hash_table_create \ + elf64_alpha_bfd_link_hash_table_create + +#define bfd_elf64_bfd_reloc_type_lookup \ + elf64_alpha_bfd_reloc_type_lookup +#define elf_info_to_howto \ + elf64_alpha_info_to_howto + +#define elf_backend_object_p \ + elf64_alpha_object_p +#define elf_backend_section_from_shdr \ + elf64_alpha_section_from_shdr +#define elf_backend_fake_sections \ + elf64_alpha_fake_sections +#define elf_backend_additional_program_headers \ + elf64_alpha_additional_program_headers + +#define bfd_elf64_bfd_is_local_label \ + elf64_alpha_is_local_label +#define bfd_elf64_find_nearest_line \ + elf64_alpha_find_nearest_line + +#define elf_backend_check_relocs \ + elf64_alpha_check_relocs +#define elf_backend_create_dynamic_sections \ + elf64_alpha_create_dynamic_sections +#define elf_backend_adjust_dynamic_symbol \ + elf64_alpha_adjust_dynamic_symbol +#define elf_backend_size_dynamic_sections \ + elf64_alpha_size_dynamic_sections +#define elf_backend_relocate_section \ + elf64_alpha_relocate_section +#define elf_backend_finish_dynamic_symbol \ + elf64_alpha_finish_dynamic_symbol +#define elf_backend_finish_dynamic_sections \ + elf64_alpha_finish_dynamic_sections +#define bfd_elf64_bfd_final_link \ + elf64_alpha_final_link + +#define elf_backend_ecoff_debug_swap \ + &elf64_alpha_ecoff_debug_swap + +/* + * A few constants that determine how the .plt section is set up. + */ +#define elf_backend_want_got_plt 0 +#define elf_backend_plt_readonly 0 +#define elf_backend_want_plt_sym 1 + +#include "elf64-target.h" diff --git a/gnu/usr.bin/binutils/bfd/evax-alpha.c b/gnu/usr.bin/binutils/bfd/evax-alpha.c new file mode 100644 index 00000000000..20a5a979fd2 --- /dev/null +++ b/gnu/usr.bin/binutils/bfd/evax-alpha.c @@ -0,0 +1,1783 @@ +/* evax-alpha.c -- BFD back-end for ALPHA EVAX (openVMS/AXP) files. + Copyright 1996 Free Software Foundation, Inc. + Written by Klaus Kämpf (kkaempf@progis.de) + of proGIS Softwareentwicklung, Aachen, Germany + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include <stdio.h> + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" + +#include "evax.h" + +static boolean evax_initialize PARAMS ((bfd *)); +static boolean fill_section_ptr PARAMS ((struct bfd_hash_entry *, PTR)); +static boolean evax_fixup_sections PARAMS ((bfd *)); +static boolean copy_symbols PARAMS ((struct bfd_hash_entry *, PTR)); +static bfd_reloc_status_type reloc_nil + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static const struct bfd_target *evax_object_p PARAMS ((bfd *abfd)); +static const struct bfd_target *evax_archive_p PARAMS ((bfd *abfd)); +static boolean evax_mkobject PARAMS ((bfd *abfd)); +static boolean evax_write_object_contents PARAMS ((bfd *abfd)); +static boolean evax_close_and_cleanup PARAMS ((bfd *abfd)); +static boolean evax_bfd_free_cached_info PARAMS ((bfd *abfd)); +static boolean evax_new_section_hook PARAMS ((bfd *abfd, asection *section)); +static boolean evax_get_section_contents + PARAMS ((bfd *abfd, asection *section, PTR x1, file_ptr x2, + bfd_size_type x3)); +static boolean evax_get_section_contents_in_window + PARAMS ((bfd *abfd, asection *section, bfd_window *w, file_ptr offset, + bfd_size_type count)); +static boolean evax_bfd_copy_private_bfd_data PARAMS ((bfd *src, bfd *dest)); +static boolean evax_bfd_copy_private_section_data + PARAMS ((bfd *srcbfd, asection *srcsec, bfd *dstbfd, asection *dstsec)); +static boolean evax_bfd_copy_private_symbol_data + PARAMS ((bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym)); +static boolean evax_bfd_print_private_bfd_data + PARAMS ((bfd *abfd, void *file)); +static char *evax_core_file_failing_command PARAMS ((bfd *abfd)); +static int evax_core_file_failing_signal PARAMS ((bfd *abfd)); +static boolean evax_core_file_matches_executable_p + PARAMS ((bfd *abfd, bfd *bbfd)); +static boolean evax_slurp_armap PARAMS ((bfd *abfd)); +static boolean evax_slurp_extended_name_table PARAMS ((bfd *abfd)); +static boolean evax_construct_extended_name_table + PARAMS ((bfd *abfd, char **tabloc, bfd_size_type *tablen, + const char **name)); +static void evax_truncate_arname + PARAMS ((bfd *abfd, CONST char *pathname, char *arhdr)); +static boolean evax_write_armap + PARAMS ((bfd *arch, unsigned int elength, struct orl *map, + unsigned int orl_count, int stridx)); +static PTR evax_read_ar_hdr PARAMS ((bfd *abfd)); +static bfd *evax_get_elt_at_index PARAMS ((bfd *abfd, symindex index)); +static bfd *evax_openr_next_archived_file PARAMS ((bfd *arch, bfd *prev)); +static boolean evax_update_armap_timestamp PARAMS ((bfd *abfd)); +static int evax_generic_stat_arch_elt PARAMS ((bfd *abfd, struct stat *stat)); +static long evax_get_symtab_upper_bound PARAMS ((bfd *abfd)); +static long evax_get_symtab PARAMS ((bfd *abfd, asymbol **symbols)); +static void evax_print_symbol + PARAMS ((bfd *abfd, PTR file, asymbol *symbol, bfd_print_symbol_type how)); +static void evax_get_symbol_info + PARAMS ((bfd *abfd, asymbol *symbol, symbol_info *ret)); +static boolean evax_bfd_is_local_label PARAMS ((bfd *abfd, asymbol *symbol)); +static alent *evax_get_lineno PARAMS ((bfd *abfd, asymbol *symbol)); +static boolean evax_find_nearest_line + PARAMS ((bfd *abfd, asection *section, asymbol **symbols, bfd_vma offset, + const char **file, const char **func, unsigned int *line)); +static asymbol *evax_bfd_make_debug_symbol + PARAMS ((bfd *abfd, void *ptr, unsigned long size)); +static long evax_read_minisymbols + PARAMS ((bfd *abfd, boolean dynamic, PTR *minisymsp, unsigned int *sizep)); +static asymbol *evax_minisymbol_to_symbol + PARAMS ((bfd *abfd, boolean dynamic, const PTR minisym, asymbol *sym)); +static long evax_get_reloc_upper_bound PARAMS ((bfd *abfd, asection *sect)); +static long evax_canonicalize_reloc + PARAMS ((bfd *abfd, asection *srcsec, arelent **location, + asymbol **symbols)); +static const struct reloc_howto_struct *evax_bfd_reloc_type_lookup + PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); +static boolean evax_set_arch_mach + PARAMS ((bfd *abfd, enum bfd_architecture arch, unsigned long mach)); +static boolean evax_set_section_contents + PARAMS ((bfd *abfd, asection *section, PTR location, file_ptr offset, + bfd_size_type count)); +static int evax_sizeof_headers PARAMS ((bfd *abfd, boolean reloc)); +static bfd_byte *evax_bfd_get_relocated_section_contents + PARAMS ((bfd *abfd, struct bfd_link_info *link_info, + struct bfd_link_order *link_order, bfd_byte *data, + boolean relocateable, asymbol **symbols)); +static boolean evax_bfd_relax_section + PARAMS ((bfd *abfd, asection *section, struct bfd_link_info *link_info, + boolean *again)); +static struct bfd_link_hash_table *evax_bfd_link_hash_table_create + PARAMS ((bfd *abfd)); +static boolean evax_bfd_link_add_symbols + PARAMS ((bfd *abfd, struct bfd_link_info *link_info)); +static boolean evax_bfd_final_link + PARAMS ((bfd *abfd, struct bfd_link_info *link_info)); +static boolean evax_bfd_link_split_section + PARAMS ((bfd *abfd, asection *section)); +static long evax_get_dynamic_symtab_upper_bound PARAMS ((bfd *abfd)); +static long evax_canonicalize_dynamic_symtab + PARAMS ((bfd *abfd, asymbol **symbols)); +static long evax_get_dynamic_reloc_upper_bound PARAMS ((bfd *abfd)); +static long evax_canonicalize_dynamic_reloc + PARAMS ((bfd *abfd, arelent **arel, asymbol **symbols)); +static boolean evax_bfd_merge_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd)); +static boolean evax_bfd_set_private_flags PARAMS ((bfd *abfd, flagword flags)); + +#define evax_make_empty_symbol _bfd_evax_make_empty_symbol + +/*===========================================================================*/ + +const bfd_target evax_alpha_vec = +{ + + "evax-alpha", /* name */ + bfd_target_evax_flavour, + false, /* data byte order is little */ + false, /* header byte order is little */ + + (HAS_RELOC | HAS_SYMS + | WP_TEXT | D_PAGED), /* object flags */ + (SEC_ALLOC | SEC_LOAD | SEC_RELOC + | SEC_READONLY | SEC_CODE | SEC_DATA + | SEC_HAS_CONTENTS | SEC_IN_MEMORY), /* sect flags */ + 0, /* symbol_leading_char */ + ' ', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, + + {_bfd_dummy_target, evax_object_p, /* bfd_check_format */ + evax_archive_p, _bfd_dummy_target}, + {bfd_false, evax_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, evax_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (evax), + BFD_JUMP_TABLE_COPY (evax), + BFD_JUMP_TABLE_CORE (evax), + BFD_JUMP_TABLE_ARCHIVE (evax), + BFD_JUMP_TABLE_SYMBOLS (evax), + BFD_JUMP_TABLE_RELOCS (evax), + BFD_JUMP_TABLE_WRITE (evax), + BFD_JUMP_TABLE_LINK (evax), + BFD_JUMP_TABLE_DYNAMIC (evax), + + (PTR) 0 +}; + + +/*===========================================================================*/ + +/* Initialize private data */ + +static boolean +evax_initialize (abfd) + bfd *abfd; +{ + int i; + + if (abfd->tdata.any != 0) + return true; + + bfd_set_start_address (abfd, (bfd_vma)-1); + + abfd->tdata.any = ((struct evax_private_data_struct*) + bfd_malloc (sizeof (struct evax_private_data_struct))); + if (abfd->tdata.any == 0) + return false; + PRIV(evax_buf) = 0; + PRIV(buf_size) = 0; + PRIV(rec_length) = 0; + PRIV(file_format) = FF_UNKNOWN; + PRIV(filename) = NULL; + PRIV(fixup_done) = false; + PRIV(sections) = NULL; + + PRIV(stack) = ((struct stack_struct *) + bfd_malloc (sizeof (struct stack_struct) * STACKSIZE)); + if (PRIV(stack) == 0) + { + evax_init_no_mem1: + free (abfd->tdata.any); + abfd->tdata.any = 0; + return false; + } + PRIV(stackptr) = 0; + + PRIV(evax_symbol_table) = ((struct bfd_hash_table *) + bfd_malloc (sizeof (struct bfd_hash_table))); + if (PRIV(evax_symbol_table) == 0) + { + evax_init_no_mem2: + free (PRIV(stack)); + PRIV(stack) = 0; + goto evax_init_no_mem1; + } + + if (!bfd_hash_table_init (PRIV(evax_symbol_table), _bfd_evax_hash_newfunc)) + return false; + + PRIV(location_stack) = ((struct location_struct *) + bfd_malloc (sizeof (struct location_struct) + * LOCATION_SAVE_SIZE)); + if (PRIV(location_stack) == 0) + { + evax_init_no_mem3: + free (PRIV(evax_symbol_table)); + PRIV(evax_symbol_table) = 0; + goto evax_init_no_mem2; + } + + for (i = 0; i < EVAX_SECTION_COUNT; i++) + PRIV(evax_section_table)[i] = NULL; + + PRIV(output_buf) = (unsigned char *) malloc (MAX_OUTREC_SIZE); + if (PRIV(output_buf) == 0) + { + free (PRIV(location_stack)); + PRIV(location_stack) = 0; + goto evax_init_no_mem3; + } + PRIV(push_level) = 0; + PRIV(pushed_size) = 0; + PRIV(length_pos) = 2; + PRIV(output_size) = 0; + PRIV(output_alignment) = 1; + + return true; +} + + +/* Fill symbol->section with section ptr + symbol->section is filled with the section index for defined symbols + during reading the EGSD section. But we need the pointer to the + bfd section later. + + It has the correct value for referenced (undefined section) symbols + + called from bfd_hash_traverse in evax_fixup_sections */ + +static boolean +fill_section_ptr (entry, sections) + struct bfd_hash_entry *entry; + PTR sections; +{ + asection *sec; + asymbol *sym; + + sym = ((evax_symbol_entry *)entry)->symbol; + sec = sym->section; + + if (!bfd_is_und_section (sec)) + { + sec = ((evax_symbol_entry *)entry)->symbol->section = + ((asection **)sections)[(int)sec]; + } + + if (strcmp (sym->name, sec->name) == 0) + sym->flags |= BSF_SECTION_SYM; + + return true; +} + + +/* Fixup sections + set up all pointers and arrays, counters and sizes are fixed now + + we build a private sections vector for easy access since sections + are always referenced by an index number. + + alloc PRIV(sections) according to abfd->section_count + copy abfd->sections to PRIV(sections) */ + +static boolean +evax_fixup_sections (abfd) + bfd *abfd; +{ + asection *s; + + if (PRIV(fixup_done)) + return true; + + PRIV(sections) = ((asection **) + bfd_malloc (abfd->section_count * sizeof (asection *))); + if (PRIV(sections) == 0) + return false; + PRIV(egsd_sec_count) = abfd->section_count; + s = abfd->sections; + while (s) + { + PRIV(sections)[s->index] = s; + s = s->next; + } + + /* + * traverse symbol table and fill in all section pointers + */ + + bfd_hash_traverse (PRIV(evax_symbol_table), fill_section_ptr, + (PTR)(PRIV(sections))); + + PRIV(fixup_done) = true; + + return true; +} + +/*===========================================================================*/ + +/* Check the format for a file being read. + Return a (bfd_target *) if it's an object file or zero if not. */ + +static const struct bfd_target * +evax_object_p (abfd) + bfd *abfd; +{ + int err = 0; + int prev_type; +#if EVAX_DEBUG + evax_debug (1, "evax_object_p(%p)\n", abfd); +#endif + if (bfd_seek (abfd, 0L, SEEK_SET)) + { + bfd_set_error (bfd_error_file_truncated); + return 0; + } + + prev_type = -1; + + do + { +#if EVAX_DEBUG + evax_debug (3, "reading at %08lx\n", bfd_tell(abfd)); +#endif + if (_bfd_evax_next_record (abfd) < 0) + { +#if EVAX_DEBUG + evax_debug (2, "next_record failed\n"); +#endif + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + if ((prev_type == EOBJ_S_C_EGSD) && (PRIV(rec_type) != EOBJ_S_C_EGSD)) + { + if (evax_fixup_sections (abfd) == false) + { +#if EVAX_DEBUG + evax_debug (2, "evax_fixup_sections failed\n"); +#endif + bfd_set_error (bfd_error_wrong_format); + return 0; + } + } + + prev_type = PRIV(rec_type); + + switch (PRIV(rec_type)) + { + case EOBJ_S_C_EMH: + err = _bfd_evax_slurp_emh (abfd); + break; + case EOBJ_S_C_EEOM: + err = _bfd_evax_slurp_eeom (abfd); + break; + case EOBJ_S_C_EGSD: + err = _bfd_evax_slurp_egsd (abfd); + break; + case EOBJ_S_C_ETIR: + err = _bfd_evax_slurp_etir (abfd); + break; + case EOBJ_S_C_EDBG: + err = _bfd_evax_slurp_edbg (abfd); + break; + case EOBJ_S_C_ETBT: + err = _bfd_evax_slurp_etbt (abfd); + break; + default: + err = -1; + } + if (err != 0) + { +#if EVAX_DEBUG + evax_debug (2, "slurp type %d failed with %d\n", PRIV(rec_type), err); +#endif + bfd_set_error (bfd_error_wrong_format); + return 0; + } + } + while (prev_type != EOBJ_S_C_EEOM); + + /* set arch_info to alpha */ + + { + const bfd_arch_info_type *arch = bfd_scan_arch ("alpha"); + if (arch == 0) + { +#if EVAX_DEBUG + evax_debug (2, "arch not found\n"); +#endif + bfd_set_error (bfd_error_wrong_format); + return 0; + } + abfd->arch_info = arch; + } + + return &evax_alpha_vec; +} + + +/* Check the format for a file being read. + Return a (bfd_target *) if it's an archive file or zero. */ + +static const struct bfd_target * +evax_archive_p (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_archive_p(%p)\n", abfd); +#endif + + if (!evax_initialize (abfd)) + return 0; + + return 0; +} + + +/* Set the format of a file being written. */ + +static boolean +evax_mkobject (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_mkobject(%p)\n", abfd); +#endif + + if (!evax_initialize (abfd)) + return 0; + + { + const bfd_arch_info_type *arch = bfd_scan_arch ("alpha"); + if (arch == 0) + { + bfd_set_error(bfd_error_wrong_format); + return 0; + } + abfd->arch_info = arch; + } + + return true; +} + + +/* Write cached information into a file being written, at bfd_close. */ + +static boolean +evax_write_object_contents (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_write_object_contents(%p)\n", abfd); +#endif + + if (abfd->section_count > 0) /* we have sections */ + { + if (_bfd_evax_write_emh (abfd) != 0) + return false; + if (_bfd_evax_write_egsd (abfd) != 0) + return false; + if (_bfd_evax_write_etir (abfd) != 0) + return false; + if (_bfd_evax_write_etbt (abfd) != 0) + return false; + if (_bfd_evax_write_eeom (abfd) != 0) + return false; + } + return true; +} + +/*-- 4.1, generic -----------------------------------------------------------*/ + +/* Called when the BFD is being closed to do any necessary cleanup. */ + +static boolean +evax_close_and_cleanup (abfd) + bfd *abfd; +{ + asection *sec; + evax_section *es, *es1; + evax_reloc *er, *er1; + int i; + +#if EVAX_DEBUG + evax_debug (1, "evax_close_and_cleanup(%p)\n", abfd); +#endif + if (abfd == 0) + return true; + + if (PRIV(evax_buf) != NULL) + { + free (PRIV(evax_buf)); + PRIV(evax_buf) = NULL; + } + PRIV(buf_size) = 0; + + if (PRIV(filename) != NULL) + { + free (PRIV(filename)); + PRIV(filename) = NULL; + } + + if (PRIV(output_buf) != 0) + { + free (PRIV(output_buf)); + PRIV(output_buf) = 0; + } + + sec = abfd->sections; + while (sec != NULL) + { + if (sec->contents) + free (sec->contents); + sec = sec->next; + } + + if (PRIV(sections) != NULL) + { + free (PRIV(sections)); + PRIV(sections) = NULL; + } + + if (PRIV(evax_symbol_table)) + { + bfd_hash_table_free (PRIV(evax_symbol_table)); + PRIV(evax_symbol_table) = 0; + } + + if (PRIV(stack)) + { + free (PRIV(stack)); + PRIV(stack) = 0; + } + + if (PRIV(location_stack)) + { + free (PRIV(location_stack)); + PRIV(location_stack) = 0; + } + + for (i = 0; i < EVAX_SECTION_COUNT; i++) + { + es = PRIV(evax_section_table)[i]; + while (es != NULL) + { + es1 = es->next; + free (es); + es = es1; + } + PRIV(evax_section_table)[i] = NULL; + } + + free (abfd->tdata.any); + abfd->tdata.any = NULL; + + return true; +} + + +/* Ask the BFD to free all cached information. */ +static boolean +evax_bfd_free_cached_info (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_bfd_free_cached_info(%p)\n", abfd); +#endif + return true; +} + + +/* Called when a new section is created. */ + +static boolean +evax_new_section_hook (abfd, section) + bfd *abfd; + asection *section; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_new_section_hook(%p, %s)\n", abfd, section->name); +#endif + bfd_set_section_alignment(abfd, section, 4); + return true; +} + + +/* Read the contents of a section. + buf points to a buffer of buf_size bytes to be filled with + section data (starting at offset into section) */ + +static boolean +evax_get_section_contents (abfd, section, buf, offset, buf_size) + bfd *abfd; + asection *section; + PTR buf; + file_ptr offset; + bfd_size_type buf_size; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_get_section_contents(%p, %s, %p, off %ld, size %d)\n", + abfd, section->name, buf, offset, (int)buf_size); +#endif + + /* shouldn't be called, since all sections are IN_MEMORY */ + + return false; +} + +/* Read the contents of a section. + buf points to a buffer of buf_size bytes to be filled with + section data (starting at offset into section) */ + +static boolean +evax_get_section_contents_in_window (abfd, section, w, offset, count) + bfd *abfd; + asection *section; + bfd_window *w; + file_ptr offset; + bfd_size_type count; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_get_section_contents_in_window(%p, %s, %p, off %ld, count %d)\n", + abfd, section->name, w, offset, (int)count); +#endif + + /* shouldn't be called, since all sections are IN_MEMORY */ + + return false; +} + +/*-- Part 4.2, copy private data --------------------------------------------*/ + +/* Called to copy BFD general private data from one object file + to another. */ + +static boolean +evax_bfd_copy_private_bfd_data (src, dest) + bfd *src; + bfd *dest; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_bfd_copy_private_bfd_data(%p, %p)\n", src, dest); +#endif + return true; +} + + +/* Merge private BFD information from the BFD @var{ibfd} to the + the output file BFD @var{obfd} when linking. Return <<true>> + on success, <<false>> on error. Possible error returns are: + + o <<bfd_error_no_memory>> - + Not enough memory exists to create private data for @var{obfd}. */ + +static boolean +evax_bfd_merge_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ +#if EVAX_DEBUG + evax_debug (1,"evax_bfd_merge_private_bfd_data(%p, %p)\n", ibfd, obfd); +#endif + return true; +} + + +/* Set private BFD flag information in the BFD @var{abfd}. + Return <<true>> on success, <<false>> on error. Possible error + returns are: + + o <<bfd_error_no_memory>> - + Not enough memory exists to create private data for @var{obfd}. */ + +static boolean +evax_bfd_set_private_flags (abfd, flags) + bfd *abfd; + flagword flags; +{ +#if EVAX_DEBUG + evax_debug (1,"evax_bfd_set_private_flags(%p, %lx)\n", abfd, (long)flags); +#endif + return true; +} + + +/* Called to copy BFD private section data from one object file + to another. */ + +static boolean +evax_bfd_copy_private_section_data (srcbfd, srcsec, dstbfd, dstsec) + bfd *srcbfd; + asection *srcsec; + bfd *dstbfd; + asection *dstsec; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_bfd_copy_private_section_data(%p, %s, %p, %s)\n", + srcbfd, srcsec->name, dstbfd, dstsec->name); +#endif + return true; +} + +/* Called to copy BFD private symbol data from one object file + to another. */ + +static boolean +evax_bfd_copy_private_symbol_data (ibfd, isym, obfd, osym) + bfd *ibfd; + asymbol *isym; + bfd *obfd; + asymbol *osym; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_bfd_copy_private_symbol_data(%p, %s, %p, %s)\n", + ibfd, isym->name, obfd, osym->name); +#endif + return true; +} + +/*-- Part 4.3, core file ----------------------------------------------------*/ + +/* Return a read-only string explaining which program was running + when it failed and produced the core file abfd. */ + +static char * +evax_core_file_failing_command (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_core_file_failing_command(%p)\n", abfd); +#endif + return 0; +} + + +/* Returns the signal number which caused the core dump which + generated the file the BFD abfd is attached to. */ + +static int +evax_core_file_failing_signal (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_core_file_failing_signal(%p)\n", abfd); +#endif + return 0; +} + + +/* Return true if the core file attached to core_bfd was generated + by a run of the executable file attached to exec_bfd, false otherwise. */ + +static boolean +evax_core_file_matches_executable_p (abfd, bbfd) + bfd *abfd; + bfd *bbfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_core_file_matches_executable_p(%p, %p)\n", abfd, bbfd); +#endif + return false; +} + +/*-- Part 4.4, archive ------------------------------------------------------*/ + +/* ??? do something with an archive map. + Return false on error, true otherwise. */ + +static boolean +evax_slurp_armap (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_slurp_armap(%p)\n", abfd); +#endif + return false; +} + + +/* ??? do something with an extended name table. + Return false on error, true otherwise. */ + +static boolean +evax_slurp_extended_name_table (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_slurp_extended_name_table(%p)\n", abfd); +#endif + return false; +} + + +/* ??? do something with an extended name table. + Return false on error, true otherwise. */ + +static boolean +evax_construct_extended_name_table (abfd, tabloc, tablen, name) + bfd *abfd; + char **tabloc; + bfd_size_type *tablen; + const char **name; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_construct_extended_name_table(%p)\n", abfd); +#endif + return false; +} + + +/* Truncate the name of an archive to match system-dependent restrictions */ + +static void +evax_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + CONST char *pathname; + char *arhdr; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_truncate_arname(%p, %s, %s)\n", abfd, pathname, arhdr); +#endif + return; +} + + +/* ??? write archive map */ + +static boolean +evax_write_armap (arch, elength, map, orl_count, stridx) + bfd *arch; + unsigned int elength; + struct orl *map; + unsigned int orl_count; + int stridx; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_write_armap(%p, %d, %p, %d %d)\n", + arch, elength, map, orl_count, stridx); +#endif + return true; +} + +/* Read archive header ??? */ + +static PTR +evax_read_ar_hdr (abfd) + bfd * abfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_read_ar_hdr(%p)\n", abfd); +#endif + return (PTR)0; +} + + +/* Provided a BFD, @var{archive}, containing an archive and NULL, open + an input BFD on the first contained element and returns that. + Subsequent calls should pass the archive and the previous return value + to return a created BFD to the next contained element. + NULL is returned when there are no more. */ + +static bfd * +evax_openr_next_archived_file (arch, prev) + bfd *arch; + bfd *prev; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_openr_next_archived_file(%p, %p)\n", arch, prev); +#endif + return false; +} + + +/* Return the BFD which is referenced by the symbol in ABFD indexed by + INDEX. INDEX should have been returned by bfd_get_next_mapent. */ + +static bfd * +evax_get_elt_at_index (abfd, index) + bfd *abfd; + symindex index; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_get_elt_at_index(%p, %p)\n", abfd, index); +#endif + return _bfd_generic_get_elt_at_index(abfd, index); +} + + +/* ??? + -> bfd_generic_stat_arch_elt */ + +static int +evax_generic_stat_arch_elt (abfd, stat) + bfd *abfd; + struct stat *stat; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_generic_stat_arch_elt(%p, %p)\n", abfd, stat); +#endif + return bfd_generic_stat_arch_elt(abfd, stat); +} + + +/* This is a new function in bfd 2.5 */ + +static boolean +evax_update_armap_timestamp (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_update_armap_timestamp(%p)\n", abfd); +#endif + return true; +} + +/*-- Part 4.5, symbols --------------------------------------------------------*/ + +/* Return the number of bytes required to store a vector of pointers + to asymbols for all the symbols in the BFD abfd, including a + terminal NULL pointer. If there are no symbols in the BFD, + then return 0. If an error occurs, return -1. */ + +static long +evax_get_symtab_upper_bound (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_get_symtab_upper_bound(%p), %d symbols\n", abfd, PRIV(egsd_sym_count)); +#endif + return (PRIV(egsd_sym_count)+1) * sizeof(asymbol *); +} + + +/* Copy symbols from hash table to symbol vector + + called from bfd_hash_traverse in evax_get_symtab + init counter to 0 if entry == 0 */ + +static boolean +copy_symbols (entry, arg) + struct bfd_hash_entry *entry; + PTR arg; +{ + bfd *abfd = (bfd *) arg; + + if (entry == NULL) /* init counter */ + PRIV(symnum) = 0; + else /* fill vector, inc counter */ + PRIV(symcache)[PRIV(symnum)++] = ((evax_symbol_entry *)entry)->symbol; + + return true; +} + + +/* Read the symbols from the BFD abfd, and fills in the vector + location with pointers to the symbols and a trailing NULL. + + return # of symbols read */ + +static long +evax_get_symtab (abfd, symbols) + bfd *abfd; + asymbol **symbols; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_get_symtab(%p, <ret>)\n", abfd); +#endif + + /* init counter */ + (void)copy_symbols((struct bfd_hash_entry *)0, abfd); + + /* traverse table and fill symbols vector */ + + PRIV(symcache) = symbols; + bfd_hash_traverse(PRIV(evax_symbol_table), copy_symbols, (PTR)abfd); + + symbols[bfd_get_symcount(abfd)] = NULL; + + return bfd_get_symcount(abfd); +} + + +/* Create a new asymbol structure for the BFD abfd and return a pointer + to it. + This routine is necessary because each back end has private information + surrounding the asymbol. Building your own asymbol and pointing to it + will not create the private information, and will cause problems later on. */ + +asymbol * +_bfd_evax_make_empty_symbol (abfd) + bfd *abfd; +{ + asymbol *symbol = (asymbol *)bfd_zalloc(abfd, sizeof(asymbol)); + +#if EVAX_DEBUG + evax_debug (1, "_bfd_evax_make_empty_symbol(%p)\n", abfd); +#endif + + if (symbol == 0) + { + bfd_set_error (bfd_error_no_memory); + return 0; + } + symbol->the_bfd = abfd; + + return symbol; +} + + +/* Print symbol to file according to how. how is one of + bfd_print_symbol_name just print the name + bfd_print_symbol_more print more (???) + bfd_print_symbol_all print all we know, which is not much right now :-) */ + +static void +evax_print_symbol (abfd, file, symbol, how) + bfd *abfd; + PTR file; + asymbol *symbol; + bfd_print_symbol_type how; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_print_symbol(%p, %p, %p, %d)\n", abfd, file, symbol, how); +#endif + + switch (how) + { + case bfd_print_symbol_name: + case bfd_print_symbol_more: + fprintf((FILE *)file," %s", symbol->name); + break; + + break; + + case bfd_print_symbol_all: + { + CONST char *section_name = symbol->section->name; + + bfd_print_symbol_vandf((PTR)file,symbol); + + fprintf((FILE *)file," %-8s %s", section_name, symbol->name); + } + break; + } + return; +} + + +/* Return information about symbol in ret. + + fill type, value and name + type: + A absolute + B bss segment symbol + C common symbol + D data segment symbol + f filename + t a static function symbol + T text segment symbol + U undefined + - debug */ + +static void +evax_get_symbol_info (abfd, symbol, ret) + bfd *abfd; + asymbol *symbol; + symbol_info *ret; +{ + asection *sec; + +#if EVAX_DEBUG + evax_debug (1, "evax_get_symbol_info(%p, %p, <ret>)\n", abfd, symbol); +#endif + + sec = symbol->section; + + if (bfd_is_com_section (sec)) + ret->type = 'C'; + else if (bfd_is_abs_section (sec)) + ret->type = 'A'; + else if (bfd_is_und_section (sec)) + ret->type = 'U'; + else if (bfd_is_abs_section (sec)) + ret->type = 'A'; + else if (bfd_is_ind_section (sec)) + ret->type = 'I'; + else if (bfd_get_section_flags (abfd, sec) & SEC_CODE) + ret->type = 'T'; + else if (bfd_get_section_flags (abfd, sec) & SEC_DATA) + ret->type = 'D'; + else if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC) + ret->type = 'B'; + else + ret->type = '-'; + + if (ret->type != 'U') + ret->value = symbol->value + symbol->section->vma; + else + ret->value = 0; + ret->name = symbol->name; + + return; +} + + +/* Return true if the given symbol sym in the BFD abfd is + a compiler generated local label, else return false. */ + +static boolean +evax_bfd_is_local_label (abfd, symbol) + bfd *abfd; + asymbol *symbol; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_bfd_is_local_label(%p, %p)\n", abfd, symbol); +#endif + return false; +} + + +/* Get source line number for symbol */ + +static alent * +evax_get_lineno (abfd, symbol) + bfd *abfd; + asymbol *symbol; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_get_lineno(%p, %p)\n", abfd, symbol); +#endif + return 0; +} + + +/* Provided a BFD, a section and an offset into the section, calculate and + return the name of the source file and the line nearest to the wanted + location. */ + +static boolean +evax_find_nearest_line (abfd, section, symbols, offset, file, func, line) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + CONST char **file; + CONST char **func; + unsigned int *line; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_find_nearest_line(%p, %s, %p, %ld, <ret>, <ret>, <ret>)\n", + abfd, section->name, symbols, (long int)offset); +#endif + return false; +} + + +/* Back-door to allow format-aware applications to create debug symbols + while using BFD for everything else. Currently used by the assembler + when creating COFF files. */ + +static asymbol * +evax_bfd_make_debug_symbol (abfd, ptr, size) + bfd *abfd; + void *ptr; + unsigned long size; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_bfd_make_debug_symbol(%p, %p, %ld)\n", abfd, ptr, size); +#endif + return 0; +} + + +/* Read minisymbols. For minisymbols, we use the unmodified a.out + symbols. The minisymbol_to_symbol function translates these into + BFD asymbol structures. */ + +static long +evax_read_minisymbols (abfd, dynamic, minisymsp, sizep) + bfd *abfd; + boolean dynamic; + PTR *minisymsp; + unsigned int *sizep; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_read_minisymbols(%p, %d, %p, %d)\n", abfd, dynamic, minisymsp, *sizep); +#endif + return _bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep); +} + +/* Convert a minisymbol to a BFD asymbol. A minisymbol is just an + unmodified a.out symbol. The SYM argument is a structure returned + by bfd_make_empty_symbol, which we fill in here. */ + +static asymbol * +evax_minisymbol_to_symbol (abfd, dynamic, minisym, sym) + bfd *abfd; + boolean dynamic; + const PTR minisym; + asymbol *sym; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_minisymbol_to_symbol(%p, %d, %p, %p)\n", abfd, dynamic, minisym, sym); +#endif + return _bfd_generic_minisymbol_to_symbol (abfd, dynamic, minisym, sym); +} + +/*-- Part 4.6, relocations --------------------------------------------------*/ + +/* Return the number of bytes required to store the relocation information + associated with section sect attached to bfd abfd. + If an error occurs, return -1. */ + +static long +evax_get_reloc_upper_bound (abfd, section) + bfd *abfd; + asection *section; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_get_reloc_upper_bound(%p, %s)\n", abfd, section->name); +#endif + return -1L; +} + + +/* Call the back end associated with the open BFD abfd and translate the + external form of the relocation information attached to sec into the + internal canonical form. Place the table into memory at loc, which has + been preallocated, usually by a call to bfd_get_reloc_upper_bound. + Returns the number of relocs, or -1 on error. */ + +static long +evax_canonicalize_reloc (abfd, section, location, symbols) + bfd *abfd; + asection *section; + arelent **location; + asymbol **symbols; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_canonicalize_reloc(%p, %s, <ret>, <ret>)\n", abfd, section->name); +#endif + return false; +} + +/*---------------------------------------------------------------------------*/ +/* this is just copied from ecoff-alpha, needs to be fixed probably */ + +/* How to process the various reloc types. */ + +static bfd_reloc_status_type +reloc_nil (abfd, reloc, sym, data, sec, output_bfd, error_message) + bfd *abfd; + arelent *reloc; + asymbol *sym; + PTR data; + asection *sec; + bfd *output_bfd; + char **error_message; +{ +#if EVAX_DEBUG + evax_debug (1, "reloc_nil(abfd %p, output_bfd %p)\n", abfd, output_bfd); + evax_debug (2, "In section %s, symbol %s\n", + sec->name, sym->name); + evax_debug (2, "reloc sym %s, addr %08lx, addend %08lx, reloc is a %s\n", + reloc->sym_ptr_ptr[0]->name, + (unsigned long)reloc->address, + (unsigned long)reloc->addend, reloc->howto->name); + evax_debug (2, "data at %p\n", data); +/* _bfd_hexdump (2, data, bfd_get_reloc_size(reloc->howto),0); */ +#endif + + return bfd_reloc_ok; +} + +/* In case we're on a 32-bit machine, construct a 64-bit "-1" value + from smaller values. Start with zero, widen, *then* decrement. */ +#define MINUS_ONE (((bfd_vma)0) - 1) + +static reloc_howto_type alpha_howto_table[] = +{ + HOWTO (ALPHA_R_IGNORE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "IGNORE", /* name */ + true, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + true), /* pcrel_offset */ + + /* A 64 bit reference to a symbol. */ + HOWTO (ALPHA_R_REFQUAD, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "REFQUAD", /* name */ + true, /* partial_inplace */ + MINUS_ONE, /* src_mask */ + MINUS_ONE, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 21 bit branch. The native assembler generates these for + branches within the text segment, and also fills in the PC + relative offset in the instruction. */ + HOWTO (ALPHA_R_BRADDR, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "BRADDR", /* name */ + true, /* partial_inplace */ + 0x1fffff, /* src_mask */ + 0x1fffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A hint for a jump to a register. */ + HOWTO (ALPHA_R_HINT, /* type */ + 2, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 14, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "HINT", /* name */ + true, /* partial_inplace */ + 0x3fff, /* src_mask */ + 0x3fff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16 bit PC relative offset. */ + HOWTO (ALPHA_R_SREL16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "SREL16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32 bit PC relative offset. */ + HOWTO (ALPHA_R_SREL32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "SREL32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 64 bit PC relative offset. */ + HOWTO (ALPHA_R_SREL64, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "SREL64", /* name */ + true, /* partial_inplace */ + MINUS_ONE, /* src_mask */ + MINUS_ONE, /* dst_mask */ + false), /* pcrel_offset */ + + /* Push a value on the reloc evaluation stack. */ + HOWTO (ALPHA_R_OP_PUSH, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "OP_PUSH", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Store the value from the stack at the given address. Store it in + a bitfield of size r_size starting at bit position r_offset. */ + HOWTO (ALPHA_R_OP_STORE, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "OP_STORE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + MINUS_ONE, /* dst_mask */ + false), /* pcrel_offset */ + + /* Subtract the reloc address from the value on the top of the + relocation stack. */ + HOWTO (ALPHA_R_OP_PSUB, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "OP_PSUB", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Shift the value on the top of the relocation stack right by the + given value. */ + HOWTO (ALPHA_R_OP_PRSHIFT, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "OP_PRSHIFT", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Hack. Linkage is done by linker. */ + HOWTO (ALPHA_R_LINKAGE, /* type */ + 0, /* rightshift */ + 8, /* size (0 = byte, 1 = short, 2 = long) */ + 256, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "LINKAGE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 32 bit reference to a symbol. */ + HOWTO (ALPHA_R_REFLONG, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "REFLONG", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + +}; + +/* Return a pointer to a howto structure which, when invoked, will perform + the relocation code on data from the architecture noted. */ + +static const struct reloc_howto_struct * +evax_bfd_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + int alpha_type; + +#if EVAX_DEBUG + evax_debug (1, "evax_bfd_reloc_type_lookup(%p, %d)\t", abfd, code); +#endif + + switch (code) + { + case BFD_RELOC_16: alpha_type = ALPHA_R_SREL16; break; + case BFD_RELOC_32: alpha_type = ALPHA_R_REFLONG; break; + case BFD_RELOC_64: alpha_type = ALPHA_R_REFQUAD; break; + case BFD_RELOC_CTOR: alpha_type = ALPHA_R_REFQUAD; break; + case BFD_RELOC_23_PCREL_S2: alpha_type = ALPHA_R_BRADDR; break; + case BFD_RELOC_ALPHA_HINT: alpha_type = ALPHA_R_HINT; break; + case BFD_RELOC_16_PCREL: alpha_type = ALPHA_R_SREL16; break; + case BFD_RELOC_32_PCREL: alpha_type = ALPHA_R_SREL32; break; + case BFD_RELOC_64_PCREL: alpha_type = ALPHA_R_SREL64; break; + case BFD_RELOC_ALPHA_LINKAGE: alpha_type = ALPHA_R_LINKAGE; break; +#if 0 + case ???: alpha_type = ALPHA_R_OP_PUSH; break; + case ???: alpha_type = ALPHA_R_OP_STORE; break; + case ???: alpha_type = ALPHA_R_OP_PSUB; break; + case ???: alpha_type = ALPHA_R_OP_PRSHIFT;break; + case ???: alpha_type = ALPHA_R_GPVALUE; break; +#endif + default: + (*_bfd_error_handler) ("reloc (%d) is *UNKNOWN*", code); + return (const struct reloc_howto_struct *) NULL; + } +#if EVAX_DEBUG + evax_debug (2, "reloc is %s\n", alpha_howto_table[alpha_type].name); +#endif + return &alpha_howto_table[alpha_type]; +} + + +/*-- Part 4.7, writing an object file ---------------------------------------*/ + +/* Set the architecture and machine type in BFD abfd to arch and mach. + Find the correct pointer to a structure and insert it into the arch_info + pointer. */ + +static boolean +evax_set_arch_mach (abfd, arch, mach) + bfd *abfd; + enum bfd_architecture arch; + unsigned long mach; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_set_arch_mach(%p, %d, %ld)\n", abfd, arch, mach); +#endif + abfd->arch_info = bfd_scan_arch("alpha"); + + return true; +} + + +/* Sets the contents of the section section in BFD abfd to the data starting + in memory at data. The data is written to the output section starting at + offset offset for count bytes. + + Normally true is returned, else false. Possible error returns are: + o bfd_error_no_contents - The output section does not have the + SEC_HAS_CONTENTS attribute, so nothing can be written to it. + o and some more too */ + +static boolean +evax_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_set_section_contents(%p, sec %s, loc %p, off %ld, count %d)\n", + abfd, section->name, location, (long int)offset, (int)count); + evax_debug (2, "secraw %d, seccooked %d\n", (int)section->_raw_size, (int)section->_cooked_size); +#endif + return _bfd_save_evax_section(abfd, section, location, offset, count); +} + + +/*-- Part 4.8, linker -------------------------------------------------------*/ + +/* Get the size of the section headers. */ + +static int +evax_sizeof_headers (abfd, reloc) + bfd *abfd; + boolean reloc; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_sizeof_headers(%p, %s)\n", abfd, (reloc)?"True":"False"); +#endif + return 0; +} + + +/* Provides default handling of relocation effort for back ends + which can't be bothered to do it efficiently. */ + +static bfd_byte * +evax_bfd_get_relocated_section_contents (abfd, link_info, link_order, data, + relocateable, symbols) + bfd *abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + bfd_byte *data; + boolean relocateable; + asymbol **symbols; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_bfd_get_relocated_section_contents(%p, %p, %p, %p, %s, %p)\n", + abfd, link_info, link_order, data, (relocateable)?"True":"False", symbols); +#endif + return 0; +} + + +/* ??? */ + +static boolean +evax_bfd_relax_section (abfd, section, link_info, again) + bfd *abfd; + asection *section; + struct bfd_link_info *link_info; + boolean *again; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_bfd_relax_section(%p, %s, %p, <ret>)\n", + abfd, section->name, link_info); +#endif + return true; +} + + +/* Create a hash table for the linker. Different backends store + different information in this table. */ + +static struct bfd_link_hash_table * +evax_bfd_link_hash_table_create (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_bfd_link_hash_table_create(%p)\n", abfd); +#endif + return 0; +} + + +/* Add symbols from this object file into the hash table. */ + +static boolean +evax_bfd_link_add_symbols (abfd, link_info) + bfd *abfd; + struct bfd_link_info *link_info; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_bfd_link_add_symbols(%p, %p)\n", abfd, link_info); +#endif + return false; +} + + +/* Do a link based on the link_order structures attached to each + section of the BFD. */ + +static boolean +evax_bfd_final_link (abfd, link_info) + bfd *abfd; + struct bfd_link_info *link_info; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_bfd_final_link(%p, %p)\n", abfd, link_info); +#endif + return true; +} + +/* Should this section be split up into smaller pieces during linking. */ + +static boolean +evax_bfd_link_split_section (abfd, section) + bfd *abfd; + asection *section; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_bfd_link_split_section(%p, %s)\n", abfd, section->name); +#endif + return false; +} + +/*-- Part 4.9, dynamic symbols and relocations ------------------------------*/ + +/* Get the amount of memory required to hold the dynamic symbols. */ + +static long +evax_get_dynamic_symtab_upper_bound (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_get_dynamic_symtab_upper_bound(%p)\n", abfd); +#endif + return 0; +} + +static boolean +evax_bfd_print_private_bfd_data (abfd, file) + bfd *abfd; + void *file; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_bfd_print_private_bfd_data(%p)\n", abfd); +#endif + return 0; +} + + +/* Read in the dynamic symbols. */ + +static long +evax_canonicalize_dynamic_symtab (abfd, symbols) + bfd *abfd; + asymbol **symbols; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_canonicalize_dynamic_symtab(%p, <ret>)\n", abfd); +#endif + return 0L; +} + + +/* Get the amount of memory required to hold the dynamic relocs. */ + +static long +evax_get_dynamic_reloc_upper_bound (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_get_dynamic_reloc_upper_bound(%p)\n", abfd); +#endif + return 0L; +} + + +/* Read in the dynamic relocs. */ + +static long +evax_canonicalize_dynamic_reloc (abfd, arel, symbols) + bfd *abfd; + arelent **arel; + asymbol **symbols; +{ +#if EVAX_DEBUG + evax_debug (1, "evax_canonicalize_dynamic_reloc(%p)\n", abfd); +#endif + return 0L; +} diff --git a/gnu/usr.bin/binutils/bfd/evax-egsd.c b/gnu/usr.bin/binutils/bfd/evax-egsd.c new file mode 100644 index 00000000000..f5275a98567 --- /dev/null +++ b/gnu/usr.bin/binutils/bfd/evax-egsd.c @@ -0,0 +1,582 @@ +/* evax-egsd.c -- BFD back-end for ALPHA EVAX (openVMS/AXP) files. + Copyright 1996 Free Software Foundation Inc. + + go and read the openVMS linker manual (esp. appendix B) + if you don't know what's going on here :-) + + Written by Klaus Kämpf (kkaempf@progis.de) + of proGIS Softwareentwicklung, Aachen, Germany + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include <stdio.h> +#include <ctype.h> + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" + +#include "evax.h" + +/*-----------------------------------------------------------------------------*/ + +/* sections every evax object file has */ + +#define EVAX_ABS_NAME "$ABS$" +#define EVAX_CODE_NAME "$CODE$" +#define EVAX_LINK_NAME "$LINK$" +#define EVAX_DATA_NAME "$DATA$" +#define EVAX_BSS_NAME "$BSS$" +#define EVAX_READONLY_NAME "$READONLY$" +#define EVAX_LITERAL_NAME "$LITERAL$" + +struct sec_flags_struct { + char *name; /* name of section */ + int eflags_always; + flagword flags_always; /* flags we set always */ + int eflags_hassize; + flagword flags_hassize; /* flags we set if the section has a size > 0 */ +}; + +/* just a dummy flag array since i don't understand it yet */ + +static struct sec_flags_struct evax_section_flags[] = { + { EVAX_ABS_NAME, + (EGPS_S_V_SHR), + (SEC_DATA), + (EGPS_S_V_SHR), + (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_LOAD) }, + { EVAX_CODE_NAME, + (EGPS_S_V_PIC|EGPS_S_V_REL|EGPS_S_V_SHR|EGPS_S_V_EXE), + (SEC_CODE), + (EGPS_S_V_PIC|EGPS_S_V_REL|EGPS_S_V_SHR|EGPS_S_V_EXE), + (SEC_IN_MEMORY|SEC_CODE|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_LOAD) }, + { EVAX_LINK_NAME, + (EGPS_S_V_REL|EGPS_S_V_RD), + (SEC_DATA|SEC_READONLY), + (EGPS_S_V_REL|EGPS_S_V_RD), + (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_READONLY|SEC_LOAD) }, + { EVAX_DATA_NAME, + (EGPS_S_V_REL|EGPS_S_V_RD|EGPS_S_V_WRT), + (SEC_DATA), + (EGPS_S_V_REL|EGPS_S_V_RD|EGPS_S_V_WRT), + (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_LOAD) }, + { EVAX_BSS_NAME, + (EGPS_S_V_REL|EGPS_S_V_RD|EGPS_S_V_WRT|EGPS_S_V_NOMOD), + (SEC_NO_FLAGS), + (EGPS_S_V_REL|EGPS_S_V_RD|EGPS_S_V_WRT|EGPS_S_V_NOMOD), + (SEC_IN_MEMORY|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_LOAD) }, + { EVAX_READONLY_NAME, + (EGPS_S_V_PIC|EGPS_S_V_REL|EGPS_S_V_SHR|EGPS_S_V_RD), + (SEC_DATA|SEC_READONLY), + (EGPS_S_V_PIC|EGPS_S_V_REL|EGPS_S_V_SHR|EGPS_S_V_RD), + (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_READONLY|SEC_LOAD) }, + { EVAX_LITERAL_NAME, + (EGPS_S_V_PIC|EGPS_S_V_REL|EGPS_S_V_SHR|EGPS_S_V_RD), + (SEC_DATA|SEC_READONLY), + (EGPS_S_V_PIC|EGPS_S_V_REL|EGPS_S_V_SHR|EGPS_S_V_RD), + (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_READONLY|SEC_LOAD) }, + { NULL, + (EGPS_S_V_REL|EGPS_S_V_RD|EGPS_S_V_WRT), + (SEC_DATA), + (EGPS_S_V_REL|EGPS_S_V_RD|EGPS_S_V_WRT), + (SEC_IN_MEMORY|SEC_DATA|SEC_HAS_CONTENTS|SEC_ALLOC|SEC_LOAD) } +}; + +/* Retrieve bfd section flags by name and size */ + +static flagword +evax_secflag_by_name(name, size) + char *name; + int size; +{ + int i = 0; + + while (evax_section_flags[i].name != NULL) + { + if (strcmp (name, evax_section_flags[i].name) == 0) + { + if (size > 0) + return evax_section_flags[i].flags_hassize; + else + return evax_section_flags[i].flags_always; + } + i++; + } + if (size > 0) + return evax_section_flags[i].flags_hassize; + return evax_section_flags[i].flags_always; +} + + +/* Retrieve evax section flags by name and size */ + +static flagword +evax_esecflag_by_name(name, size) + char *name; + int size; +{ + int i = 0; + + while (evax_section_flags[i].name != NULL) + { + if (strcmp (name, evax_section_flags[i].name) == 0) + { + if (size > 0) + return evax_section_flags[i].eflags_hassize; + else + return evax_section_flags[i].eflags_always; + } + i++; + } + if (size > 0) + return evax_section_flags[i].eflags_hassize; + return evax_section_flags[i].eflags_always; +} + +/*-----------------------------------------------------------------------------*/ +#if EVAX_DEBUG +/* debug */ + +struct flagdescstruct { char *name; flagword value; }; + +/* Convert flag to printable string */ + +static char * +flag2str(flagdesc, flags) + struct flagdescstruct *flagdesc; + flagword flags; +{ + + static char res[64]; + int next = 0; + + res[0] = 0; + while (flagdesc->name != NULL) + { + if ((flags & flagdesc->value) != 0) + { + if (next) + strcat(res, ","); + else + next = 1; + strcat (res, flagdesc->name); + } + flagdesc++; + } + return res; +} +#endif + +/*-----------------------------------------------------------------------------*/ +/* input routines */ + +/* Process EGSD record + return 0 on success, -1 on error */ + +int +_bfd_evax_slurp_egsd (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + static struct flagdescstruct gpsflagdesc[] = + { + { "PIC", 0x0001 }, + { "LIB", 0x0002 }, + { "OVR", 0x0004 }, + { "REL", 0x0008 }, + { "GBL", 0x0010 }, + { "SHR", 0x0020 }, + { "EXE", 0x0040 }, + { "RD", 0x0080 }, + { "WRT", 0x0100 }, + { "VEC", 0x0200 }, + { "NOMOD", 0x0400 }, + { "COM", 0x0800 }, + { NULL, 0 } + }; + + static struct flagdescstruct gsyflagdesc[] = + { + { "WEAK", 0x0001 }, + { "DEF", 0x0002 }, + { "UNI", 0x0004 }, + { "REL", 0x0008 }, + { "COMM", 0x0010 }, + { "VECEP", 0x0020 }, + { "NORM", 0x0040 }, + { NULL, 0 } + }; +#endif + + int gsd_type, gsd_size; + asection *section; + unsigned char *evax_rec; + flagword new_flags, old_flags; + char *name; + asymbol *symbol; + evax_symbol_entry *entry; + unsigned long base_addr; + unsigned long align_addr; + +#if EVAX_DEBUG + evax_debug (2, "EGSD\n"); +#endif + + PRIV(evax_rec) += 8; /* skip type, size, l_temp */ + PRIV(rec_size) -= 8; + + /* calculate base address for each section */ + base_addr = 0L; + + abfd->symcount = 0; + + while (PRIV(rec_size) > 0) + { + evax_rec = PRIV(evax_rec); + _bfd_evax_get_header_values (abfd, evax_rec, &gsd_type, &gsd_size); + switch (gsd_type) + { + case EGSD_S_C_PSC: + { + /* program section definition */ + + name = _bfd_evax_save_counted_string ((char *)evax_rec+12); + section = bfd_make_section (abfd, name); + if (!section) + return -1; + old_flags = bfd_getl16 (evax_rec + 6); + section->_raw_size = bfd_getl32 (evax_rec + 8); /* allocation */ + new_flags = evax_secflag_by_name (name, (int) section->_raw_size); + if (old_flags & EGPS_S_V_REL) + new_flags |= SEC_RELOC; + if (!bfd_set_section_flags (abfd, section, new_flags)) + return -1; + section->alignment_power = evax_rec[4]; + align_addr = (1 << section->alignment_power); + if ((base_addr % align_addr) != 0) + base_addr += (align_addr - (base_addr % align_addr)); + section->vma = (bfd_vma)base_addr; + base_addr += section->_raw_size; + section->contents = ((unsigned char *) + bfd_malloc (section->_raw_size)); + if (section->contents == NULL) + return -1; + memset (section->contents, 0, (size_t) section->_raw_size); + section->_cooked_size = section->_raw_size; +#if EVAX_DEBUG + evax_debug(3, "egsd psc %d (%s, flags %04x=%s) ", + section->index, name, old_flags, flag2str(gpsflagdesc, old_flags)); + evax_debug(3, "%d bytes at 0x%08lx (mem %p)\n", + section->_raw_size, section->vma, section->contents); +#endif + } + break; + + case EGSD_S_C_SYM: + { + /* symbol specification (definition or reference) */ + + symbol = _bfd_evax_make_empty_symbol (abfd); + if (symbol == 0) + return -1; + + old_flags = bfd_getl16 (evax_rec + 6); + new_flags = BSF_NO_FLAGS; + + if (old_flags & EGSY_S_V_WEAK) + new_flags |= BSF_WEAK; + + if (evax_rec[6] & EGSY_S_V_DEF) /* symbol definition */ + { + symbol->name = + _bfd_evax_save_counted_string ((char *)evax_rec+32); + if (old_flags & EGSY_S_V_NORM) + { /* proc def */ + new_flags |= BSF_FUNCTION; + } + symbol->value = bfd_getl64 (evax_rec+8); + symbol->section = (asection *)((unsigned long) bfd_getl32 (evax_rec+28)); +#if EVAX_DEBUG + evax_debug(3, "egsd sym def #%d (%s, %d, %04x=%s)\n", abfd->symcount, + symbol->name, (int)symbol->section, old_flags, flag2str(gsyflagdesc, old_flags)); +#endif + } + else /* symbol reference */ + { +#if EVAX_DEBUG + evax_debug(3, "egsd sym ref #%d (%s, %04x=%s)\n", abfd->symcount, evax_rec+9, old_flags, flag2str(gsyflagdesc, old_flags)); +#endif + symbol->name = + _bfd_evax_save_counted_string ((char *)evax_rec+8); + symbol->section = bfd_make_section (abfd, BFD_UND_SECTION_NAME); + } + + symbol->flags = new_flags; + + /* save symbol in evax_symbol_table */ + + entry = (evax_symbol_entry *) bfd_hash_lookup (PRIV(evax_symbol_table), symbol->name, true, false); + if (entry == (evax_symbol_entry *)NULL) + { + bfd_set_error (bfd_error_no_memory); + return -1; + } + if (entry->symbol != (asymbol *)NULL) + { /* FIXME ?, DEC C generates this */ +#if EVAX_DEBUG + evax_debug(3, "EGSD_S_C_SYM: duplicate \"%s\"\n", symbol->name); +#endif + } + else + { + entry->symbol = symbol; + PRIV(egsd_sym_count)++; + abfd->symcount++; + } + } + break; + + case EGSD_S_C_IDC: + break; + + default: + (*_bfd_error_handler) ("unknown egsd subtype %d", gsd_type); + bfd_set_error (bfd_error_bad_value); + return -1; + + } /* switch */ + + PRIV(rec_size) -= gsd_size; + PRIV(evax_rec) += gsd_size; + + } /* while (recsize > 0) */ + + if (abfd->symcount > 0) + abfd->flags |= HAS_SYMS; + + return 0; +} + +/*-----------------------------------------------------------------------------*/ +/* output routines */ + +/* Write section and symbol directory of bfd abfd */ + +int +_bfd_evax_write_egsd (abfd) + bfd *abfd; +{ + asection *section; + asymbol *symbol; + int symnum; + int last_index = -1; + char dummy_name[10]; + char *sname; + flagword new_flags, old_flags; + char uname[200]; + char *nptr, *uptr; + +#if EVAX_DEBUG + evax_debug (2, "evax_write_egsd(%p)\n", abfd); +#endif + + /* output sections */ + + section = abfd->sections; +#if EVAX_DEBUG + evax_debug (3, "%d sections found\n", abfd->section_count); +#endif + + /* egsd is quadword aligned */ + + _bfd_evax_output_alignment (abfd, 8); + + _bfd_evax_output_begin (abfd, EOBJ_S_C_EGSD, -1); + _bfd_evax_output_long (abfd, 0); + _bfd_evax_output_push (abfd); /* prepare output for subrecords */ + + while (section != 0) + { +#if EVAX_DEBUG + evax_debug (3, "Section #%d %s, %d bytes\n", section->index, section->name, (int)section->_raw_size); +#endif + + /* 13 bytes egsd, max 31 chars name -> should be 44 bytes */ + if (_bfd_evax_output_check (abfd, 64) < 0) + { + _bfd_evax_output_pop (abfd); + _bfd_evax_output_end (abfd); + _bfd_evax_output_begin (abfd, EOBJ_S_C_EGSD, -1); + _bfd_evax_output_long (abfd, 0); + _bfd_evax_output_push (abfd); /* prepare output for subrecords */ + } + + /* Create dummy sections to keep consecutive indices */ + + while (section->index - last_index > 1) + { +#if EVAX_DEBUG + evax_debug (3, "index %d, last %d\n", section->index, last_index); +#endif + _bfd_evax_output_begin (abfd, EGSD_S_C_PSC, -1); + _bfd_evax_output_short (abfd, 0); + _bfd_evax_output_short (abfd, 0); + _bfd_evax_output_long (abfd, 0); + sprintf (dummy_name, ".DUMMY%02d", last_index); + _bfd_evax_output_counted (abfd, dummy_name); + _bfd_evax_output_flush (abfd); + last_index++; + } + + /* Don't know if this is neccesary for the linker but for now it keeps + evax_slurp_egsd happy */ + + sname = (char *)section->name; + if (*sname == '.') + { + sname++; + if ((*sname == 't') && (strcmp (sname, "text") == 0)) + sname = EVAX_CODE_NAME; + else if ((*sname == 'd') && (strcmp (sname, "data") == 0)) + sname = EVAX_DATA_NAME; + else if ((*sname == 'b') && (strcmp (sname, "bss") == 0)) + sname = EVAX_BSS_NAME; + else if ((*sname == 'l') && (strcmp (sname, "link") == 0)) + sname = EVAX_LINK_NAME; + else if ((*sname == 'r') && (strcmp (sname, "rdata") == 0)) + sname = EVAX_READONLY_NAME; + else if ((*sname == 'l') && (strcmp (sname, "literal") == 0)) + sname = EVAX_LITERAL_NAME; + } + + _bfd_evax_output_begin (abfd, EGSD_S_C_PSC, -1); + _bfd_evax_output_short (abfd, section->alignment_power & 0xff); + _bfd_evax_output_short (abfd, + evax_esecflag_by_name (sname, + section->_raw_size)); + _bfd_evax_output_long (abfd, section->_raw_size); + _bfd_evax_output_counted (abfd, sname); + _bfd_evax_output_flush (abfd); + + last_index = section->index; + section = section->next; + } + + /* output symbols */ + +#if EVAX_DEBUG + evax_debug (3, "%d symbols found\n", abfd->symcount); +#endif + + bfd_set_start_address (abfd, (bfd_vma)-1); + + for (symnum = 0; symnum < abfd->symcount; symnum++) + { + + symbol = abfd->outsymbols[symnum]; + if (*(symbol->name) == '_') + { + if (strcmp (symbol->name, "__main") == 0) + bfd_set_start_address (abfd, (bfd_vma)symbol->value); + } + old_flags = symbol->flags; + + if (((old_flags & BSF_GLOBAL) == 0) /* not xdef */ + && (!bfd_is_und_section (symbol->section))) /* and not xref */ + continue; /* dont output */ + + /* 13 bytes egsd, max 64 chars name -> should be 77 bytes */ + + if (_bfd_evax_output_check (abfd, 80) < 0) + { + _bfd_evax_output_pop (abfd); + _bfd_evax_output_end (abfd); + _bfd_evax_output_begin (abfd, EOBJ_S_C_EGSD, -1); + _bfd_evax_output_long (abfd, 0); + _bfd_evax_output_push (abfd); /* prepare output for subrecords */ + } + + _bfd_evax_output_begin (abfd, EGSD_S_C_SYM, -1); + + _bfd_evax_output_short (abfd, 0); /* data type, alignment */ + + new_flags = 0; + if (old_flags & BSF_WEAK) + new_flags |= EGSY_S_V_WEAK; + if (old_flags & BSF_FUNCTION) + { + new_flags |= EGSY_S_V_NORM; + new_flags |= EGSY_S_V_REL; + } + if (old_flags & BSF_GLOBAL) + { + new_flags |= EGSY_S_V_DEF; + if (!bfd_is_abs_section (symbol->section)) + new_flags |= EGSY_S_V_REL; + } + _bfd_evax_output_short (abfd, new_flags); + + if (old_flags & BSF_GLOBAL) /* symbol definition */ + { + if (old_flags & BSF_FUNCTION) + { + _bfd_evax_output_quad (abfd, symbol->value); + _bfd_evax_output_quad (abfd, + ((asymbol *)(symbol->udata.p))->value); + _bfd_evax_output_long (abfd, + (((asymbol *)(symbol->udata.p)) + ->section->index)); + _bfd_evax_output_long (abfd, symbol->section->index); + } + else + { + _bfd_evax_output_quad (abfd, symbol->value); /* L_VALUE */ + _bfd_evax_output_quad (abfd, 0); /* L_CODE_ADDRESS */ + _bfd_evax_output_long (abfd, 0); /* L_CA_PSINDX */ + _bfd_evax_output_long (abfd, symbol->section->index);/* L_PSINDX, FIXME */ + } + } + if (strlen ((char *)symbol->name) > 198) + { + (*_bfd_error_handler) ("Name '%s' too long\n", symbol->name); + abort (); + } + nptr = (char *)symbol->name; + uptr = uname; + while (*nptr) + { + if (islower (*nptr)) + *uptr = toupper (*nptr); + else + *uptr = *nptr; + uptr++; + nptr++; + } + *uptr = 0; + _bfd_evax_output_counted (abfd, uname); + + _bfd_evax_output_flush (abfd); + + } + + _bfd_evax_output_alignment (abfd, 8); + _bfd_evax_output_pop (abfd); + _bfd_evax_output_end (abfd); + + return 0; +} diff --git a/gnu/usr.bin/binutils/bfd/evax-emh.c b/gnu/usr.bin/binutils/bfd/evax-emh.c new file mode 100644 index 00000000000..69f7e0be91b --- /dev/null +++ b/gnu/usr.bin/binutils/bfd/evax-emh.c @@ -0,0 +1,266 @@ +/* evax-emh.c -- BFD back-end for ALPHA EVAX (openVMS/AXP) files. + Copyright 1996 Free Software Foundation, Inc. + + EMH record handling functions + and + EEOM record handling functions + + Written by Klaus Kämpf (kkaempf@progis.de) + of proGIS Softwareentwicklung, Aachen, Germany + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" + +#include "evax.h" + +/*---------------------------------------------------------------------------*/ + + +/* Read & process emh record + return 0 on success, -1 on error */ + +int +_bfd_evax_slurp_emh (abfd) + bfd *abfd; +{ + unsigned char *ptr; + unsigned char *evax_rec; + + evax_rec = PRIV(evax_rec); + +#if EVAX_DEBUG + evax_debug(2, "EMH\n"); +#endif + + switch (bfd_getl16 (evax_rec + 4)) + { + + case EMH_S_C_MHD: + /* + * module header + */ + PRIV(emh_data).emh_b_strlvl = evax_rec[6]; + PRIV(emh_data).emh_l_arch1 = bfd_getl32 (evax_rec + 8); + PRIV(emh_data).emh_l_arch2 = bfd_getl32 (evax_rec + 12); + PRIV(emh_data).emh_l_recsiz = bfd_getl32 (evax_rec + 16); + PRIV(emh_data).emh_t_name = + _bfd_evax_save_counted_string ((char *)evax_rec + 20); + ptr = evax_rec + 20 + evax_rec[20] + 1; + PRIV(emh_data).emh_t_version = + _bfd_evax_save_counted_string ((char *)ptr); + ptr += *ptr + 1; + PRIV(emh_data).emh_t_date = + _bfd_evax_save_sized_string ((char *)ptr, 17); + + break; + + case EMH_S_C_LNM: + /* + * + */ + PRIV(emh_data).emh_c_lnm = + _bfd_evax_save_sized_string ((char *)evax_rec, PRIV(rec_length-6)); + break; + + case EMH_S_C_SRC: + /* + * + */ + PRIV(emh_data).emh_c_src = + _bfd_evax_save_sized_string ((char *)evax_rec, PRIV(rec_length-6)); + break; + + case EMH_S_C_TTL: + /* + * + */ + PRIV(emh_data).emh_c_ttl = + _bfd_evax_save_sized_string ((char *)evax_rec, PRIV(rec_length-6)); + break; + + case EMH_S_C_CPR: + /* + * + */ + break; + + case EMH_S_C_MTC: + /* + * + */ + break; + + case EMH_S_C_GTX: + /* + * + */ + break; + + default: + bfd_set_error (bfd_error_wrong_format); + return -1; + + } /* switch */ + + return 0; +} + + +/* write object header for bfd abfd */ + +int +_bfd_evax_write_emh (abfd) + bfd *abfd; +{ + char *name; + +#if EVAX_DEBUG + evax_debug (2, "evax_write_emh(%p)\n", abfd); +#endif + + _bfd_evax_output_alignment (abfd, 2); + + /* MHD */ + + _bfd_evax_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_MHD); + _bfd_evax_output_short (abfd, EOBJ_S_C_STRLVL); + _bfd_evax_output_long (abfd, 0); + _bfd_evax_output_long (abfd, 0); + _bfd_evax_output_long (abfd, MAX_OUTREC_SIZE); + if (bfd_get_filename (abfd) != NULL) + { + name = strdup (bfd_get_filename (abfd)); + _bfd_evax_output_counted (abfd, _bfd_evax_basename (name)); + } + else + _bfd_evax_output_counted (abfd, "NONAME"); + _bfd_evax_output_counted (abfd, BFD_VERSION); + _bfd_evax_output_dump (abfd, (unsigned char *)_bfd_get_vms_time_string (), + 17); + _bfd_evax_output_fill (abfd, 0, 17); + _bfd_evax_output_flush (abfd); + + /* LMN */ + + _bfd_evax_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_LNM); + _bfd_evax_output_dump (abfd, (unsigned char *)"GAS proGIS", 10); + _bfd_evax_output_flush (abfd); + + /* SRC */ + + _bfd_evax_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_SRC); + if (PRIV(filename) != 0) + _bfd_evax_output_dump (abfd, (unsigned char *)PRIV(filename), strlen (PRIV(filename))); + else + _bfd_evax_output_dump (abfd, (unsigned char *)"noname", 6); + _bfd_evax_output_flush (abfd); + + /* TTL */ + + _bfd_evax_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_TTL); + _bfd_evax_output_dump (abfd, (unsigned char *)"TTL", 3); + _bfd_evax_output_flush (abfd); + + /* CPR */ + + _bfd_evax_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_CPR); + _bfd_evax_output_dump (abfd, + (unsigned char *)"GNU BFD ported by Klaus Kämpf 1994-1996", + 39); + _bfd_evax_output_flush (abfd); + + return 0; +} + +/*-----------------------------------------------------------------------------*/ + +/* Process EEOM record + return 0 on success, -1 on error */ + +int +_bfd_evax_slurp_eeom (abfd) + bfd *abfd; +{ + unsigned char *evax_rec; + +#if EVAX_DEBUG + evax_debug(2, "EEOM\n"); +#endif + + evax_rec = PRIV(evax_rec); + + PRIV(eeom_data).eeom_l_total_lps = bfd_getl32 (evax_rec + 4); + PRIV(eeom_data).eeom_b_comcod = *(evax_rec + 8); + if (PRIV(eeom_data).eeom_b_comcod > 1) + { + (*_bfd_error_handler) ("Object module NOT error-free !\n"); + bfd_set_error (bfd_error_bad_value); + return -1; + } + PRIV(eeom_data).eeom_has_transfer = false; + if (PRIV(rec_size) > 10) + { + PRIV(eeom_data).eeom_has_transfer = true; + PRIV(eeom_data).eeom_b_tfrflg = *(evax_rec + 9); + PRIV(eeom_data).eeom_l_psindx = bfd_getl32 (evax_rec + 12); + PRIV(eeom_data).eeom_l_tfradr = bfd_getl32 (evax_rec + 16); + + abfd->start_address = PRIV(eeom_data).eeom_l_tfradr; + } + return 0; +} + + +/* Write eom record for bfd abfd */ + +int +_bfd_evax_write_eeom (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (2, "evax_write_eeom(%p)\n", abfd); +#endif + + _bfd_evax_output_begin (abfd,EOBJ_S_C_EEOM, -1); + _bfd_evax_output_long (abfd, (unsigned long)(PRIV(evax_linkage_index) >> 1)); + _bfd_evax_output_byte (abfd, 0); /* completion code */ + _bfd_evax_output_byte (abfd, 0); /* fill byte */ + + if (bfd_get_start_address (abfd) != (bfd_vma)-1) + { + asection *section; + + section = bfd_get_section_by_name (abfd, ".link"); + if (section == 0) + { + bfd_set_error (bfd_error_nonrepresentable_section); + return -1; + } + _bfd_evax_output_short (abfd, 0); + _bfd_evax_output_long (abfd, (unsigned long)(section->index)); + _bfd_evax_output_long (abfd, + (unsigned long) bfd_get_start_address (abfd)); + _bfd_evax_output_long (abfd, 0); + } + + _bfd_evax_output_end (abfd); + return 0; +} diff --git a/gnu/usr.bin/binutils/bfd/evax-etir.c b/gnu/usr.bin/binutils/bfd/evax-etir.c new file mode 100644 index 00000000000..cb186f11e96 --- /dev/null +++ b/gnu/usr.bin/binutils/bfd/evax-etir.c @@ -0,0 +1,1553 @@ +/* evax-etir.c -- BFD back-end for ALPHA EVAX (openVMS/AXP) files. + Copyright 1996 Free Software Foundation, Inc. + ETIR record handling functions + + go and read the openVMS linker manual (esp. appendix B) + if you don't know what's going on here :-) + + Written by Klaus Kämpf (kkaempf@progis.de) + of proGIS Softwareentwicklung, Aachen, Germany + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* The following type abbreviations are used: + + cs counted string (ascii string with length byte) + by byte (1 byte) + sh short (2 byte, 16 bit) + lw longword (4 byte, 32 bit) + qw quadword (8 byte, 64 bit) + da data stream */ + +#include <stdio.h> +#include <ctype.h> + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" + +#include "evax.h" + +#if 0 +static void location_save + PARAMS ((bfd *abfd, unsigned long index, unsigned long loc, int section)); +static unsigned long location_restore + PARAMS ((bfd *abfd, unsigned long index, int *section)); +#endif /* 0 */ + +static void image_set_ptr PARAMS ((bfd *abfd, int psect, uquad offset)); +static void image_inc_ptr PARAMS ((bfd *abfd, uquad offset)); +static void image_dump PARAMS ((bfd *abfd, unsigned char *ptr, int size, int offset)); +static void image_write_b PARAMS ((bfd *abfd, unsigned int value)); +static void image_write_w PARAMS ((bfd *abfd, unsigned int value)); +static void image_write_l PARAMS ((bfd *abfd, unsigned long value)); +static void image_write_q PARAMS ((bfd *abfd, uquad value)); + +/*-----------------------------------------------------------------------------*/ + +#if 0 + +/* Save location counter at index */ + +static void +location_save (abfd, index, loc, section) + bfd *abfd; + unsigned long index; + unsigned long loc; + int section; +{ + PRIV(location_stack)[index].value = loc; + PRIV(location_stack)[index].psect = section; + + return; +} + +/* Restore location counter from index */ + +static unsigned long +location_restore (abfd, index, section) + bfd *abfd; + unsigned long index; + int *section; +{ + if (section != NULL) + *section = PRIV(location_stack)[index].psect; + return PRIV(location_stack)[index].value; +} + +#endif /* 0 */ + +/* routines to fill sections contents during etir read */ + +/* Initialize image buffer pointer to be filled */ + +static void +image_set_ptr (abfd, psect, offset) + bfd *abfd; + int psect; + uquad offset; +{ +#if EVAX_DEBUG + evax_debug (4, "image_set_ptr(%d=%s, %d)\n", + psect, PRIV(sections)[psect]->name, offset); +#endif + + PRIV(image_ptr) = PRIV(sections)[psect]->contents + offset; + return; +} + + +/* Increment image buffer pointer by offset */ + +static void +image_inc_ptr (abfd, offset) + bfd *abfd; + uquad offset; +{ +#if EVAX_DEBUG + evax_debug (4, "image_inc_ptr(%d)\n", offset); +#endif + + PRIV(image_ptr) += offset; + + return; +} + + +/* Dump multiple bytes to section image */ + +static void +image_dump (abfd, ptr, size, offset) + bfd *abfd; + unsigned char *ptr; + int size; + int offset; +{ +#if EVAX_DEBUG + evax_debug (6, "image_dump from (%p, %d) to (%p)\n", ptr, size, PRIV(image_ptr)); + _bfd_hexdump (7, ptr, size, offset); +#endif + + while (size-- > 0) + *PRIV(image_ptr)++ = *ptr++; + return; +} + + +/* Write byte to section image */ + +static void +image_write_b (abfd, value) + bfd *abfd; + unsigned int value; +{ +#if EVAX_DEBUG + evax_debug (6, "image_write_b(%02x)\n", (int)value); +#endif + + *PRIV(image_ptr)++ = (value & 0xff); + return; +} + + +/* Write 2-byte word to image */ + +static void +image_write_w (abfd, value) + bfd *abfd; + unsigned int value; +{ +#if EVAX_DEBUG + evax_debug (6, "image_write_w(%04x)\n", (int)value); +#endif + + bfd_putl16 (value, PRIV(image_ptr)); + PRIV(image_ptr) += 2; + + return; +} + + +/* Write 4-byte long to image */ + +static void +image_write_l (abfd, value) + bfd *abfd; + unsigned long value; +{ +#if EVAX_DEBUG + evax_debug (6, "image_write_l(%08lx)\n", value); +#endif + + bfd_putl32 (value, PRIV(image_ptr)); + PRIV(image_ptr) += 4; + + return; +} + + +/* Write 4-byte long to image */ + +static void +image_write_q (abfd, value) + bfd *abfd; + uquad value; +{ +#if EVAX_DEBUG + evax_debug (6, "image_write_q(%016lx)\n", value); +#endif + + bfd_putl64 (value, PRIV(image_ptr)); + PRIV(image_ptr) += 8; + + return; +} + + +#define HIGHBIT(op) ((op & 0x80000000L) == 0x80000000L) + +/* etir_sta + + evax stack commands + + handle sta_xxx commands in etir section + ptr points to data area in record + + see table B-8 of the openVMS linker manual */ + +static boolean +etir_sta (abfd, cmd, ptr) + bfd *abfd; + int cmd; + unsigned char *ptr; +{ + + switch (cmd) + { + /* stack */ + + /* stack global + arg: cs symbol name + + stack 32 bit value of symbol (high bits set to 0) */ + + case ETIR_S_C_STA_GBL: + { + char *name; + evax_symbol_entry *entry; + + name = _bfd_evax_save_counted_string ((char *)ptr); + entry = (evax_symbol_entry *) + bfd_hash_lookup (PRIV(evax_symbol_table), name, false, false); + if (entry == (evax_symbol_entry *)NULL) + { +#if EVAX_DEBUG + evax_debug (3, "ETIR_S_C_STA_GBL: no symbol \"%s\"\n", name); +#endif + return false; + } + else + { + _bfd_evax_push (abfd, (uquad)(entry->symbol->value), -1); + } + } + break; + + /* stack longword + arg: lw value + + stack 32 bit value, sign extend to 64 bit */ + + case ETIR_S_C_STA_LW: + _bfd_evax_push (abfd, (uquad)bfd_getl32 (ptr), -1); + break; + + /* stack global + arg: qw value + + stack 64 bit value of symbol */ + + case ETIR_S_C_STA_QW: + _bfd_evax_push (abfd, (uquad)bfd_getl64(ptr), -1); + break; + + /* stack psect base plus quadword offset + arg: lw section index + qw signed quadword offset (low 32 bits) + + stack qw argument and section index + (see ETIR_S_C_STO_OFF, ETIR_S_C_CTL_SETRB) */ + + case ETIR_S_C_STA_PQ: + { + uquad dummy; + int psect; + + psect = bfd_getl32 (ptr); + if (psect >= PRIV(egsd_sec_count)) + { + (*_bfd_error_handler) ("Bad section index in ETIR_S_C_STA_PQ"); + bfd_set_error (bfd_error_bad_value); + return false; + } + dummy = bfd_getl64 (ptr+4); + _bfd_evax_push (abfd, dummy, psect); + } + break; + + /* all not supported */ + + case ETIR_S_C_STA_LI: + case ETIR_S_C_STA_MOD: + case ETIR_S_C_STA_CKARG: + + (*_bfd_error_handler) ("Unsupported STA cmd %d", cmd); + return false; + break; + + default: + (*_bfd_error_handler) ("Reserved STA cmd %d", cmd); + return false; + break; + } + return true; +} + + +/* + etir_sto + + evax store commands + + handle sto_xxx commands in etir section + ptr points to data area in record + + see table B-9 of the openVMS linker manual */ + +static boolean +etir_sto (abfd, cmd, ptr) + bfd *abfd; + int cmd; + unsigned char *ptr; +{ + uquad dummy; + int psect; + + switch (cmd) + { + + /* store byte: pop stack, write byte + arg: - */ + + case ETIR_S_C_STO_B: + dummy = _bfd_evax_pop (abfd, &psect); +#if 0 + if (is_share) /* FIXME */ + (*_bfd_error_handler) ("ETIR_S_C_STO_B: byte fixups not supported"); +#endif + image_write_b (abfd, dummy & 0xff); /* FIXME: check top bits */ + break; + + /* store word: pop stack, write word + arg: - */ + + case ETIR_S_C_STO_W: + dummy = _bfd_evax_pop (abfd, &psect); +#if 0 + if (is_share) /* FIXME */ + (*_bfd_error_handler) ("ETIR_S_C_STO_B: word fixups not supported"); +#endif + image_write_w (abfd, dummy & 0xffff); /* FIXME: check top bits */ + break; + + /* store longword: pop stack, write longword + arg: - */ + + case ETIR_S_C_STO_LW: + dummy = _bfd_evax_pop (abfd, &psect); + dummy += (PRIV(sections)[psect])->vma; + image_write_l (abfd, dummy & 0xffffffff);/* FIXME: check top bits */ +#if 0 /* FIXME */ + if (is_rel) + evax_debug (3, "ETIR_S_C_STO_LW: Relocation !\n"); + if (is_share) + evax_debug (3, "ETIR_S_C_STO_LW: Fix-up share !\n"); +#endif + break; + + /* store quadword: pop stack, write quadword + arg: - */ + + case ETIR_S_C_STO_QW: + dummy = _bfd_evax_pop (abfd, &psect); + dummy += (PRIV(sections)[psect])->vma; + image_write_q(abfd, dummy); /* FIXME: check top bits */ +#if 0 /* FIXME */ + if (is_rel) + evax_debug (3, "ETIR_S_C_STO_LW: Relocation !\n"); + if (is_share) + evax_debug (3, "ETIR_S_C_STO_LW: Fix-up share !\n"); +#endif + break; + + /* store immediate repeated: pop stack for repeat count + arg: lw byte count + da data */ + + case ETIR_S_C_STO_IMMR: + { + unsigned long size; + + size = bfd_getl32 (ptr); + dummy = (unsigned long)_bfd_evax_pop (abfd, NULL); + while (dummy-- > 0L) + image_dump (abfd, ptr+4, size, 0); + } + break; + + /* store global: write symbol value + arg: cs global symbol name */ + + case ETIR_S_C_STO_GBL: + { + evax_symbol_entry *entry; + char *name; + + name = _bfd_evax_save_counted_string ((char *)ptr); + entry = (evax_symbol_entry *)bfd_hash_lookup (PRIV(evax_symbol_table), name, false, false); + if (entry == (evax_symbol_entry *)NULL) + { + (*_bfd_error_handler) ("ETIR_S_C_STO_GBL: no symbol \"%s\"", + name); + return false; + } + else + image_write_q (abfd, (uquad)(entry->symbol->value)); /* FIXME, reloc */ + } + break; + + /* store code address: write address of entry point + arg: cs global symbol name (procedure) */ + + case ETIR_S_C_STO_CA: + { + evax_symbol_entry *entry; + char *name; + + name = _bfd_evax_save_counted_string ((char *)ptr); + entry = (evax_symbol_entry *) bfd_hash_lookup (PRIV(evax_symbol_table), name, false, false); + if (entry == (evax_symbol_entry *)NULL) + { + (*_bfd_error_handler) ("ETIR_S_C_STO_CA: no symbol \"%s\"", + name); + return false; + } + else + image_write_q (abfd, (uquad)(entry->symbol->value)); /* FIXME, reloc */ + } + break; + + /* not supported */ + + case ETIR_S_C_STO_RB: + case ETIR_S_C_STO_AB: + (*_bfd_error_handler) ("ETIR_S_C_STO_RB/AB: Not supported"); + break; + + /* store offset to psect: pop stack, add low 32 bits to base of psect + arg: - */ + + case ETIR_S_C_STO_OFF: + { + uquad q; + int psect; + + q = _bfd_evax_pop (abfd, &psect); + q += (PRIV(sections)[psect])->vma; + image_write_q (abfd, q); + } + break; + + /* store immediate + arg: lw count of bytes + da data */ + + case ETIR_S_C_STO_IMM: + { + int size; + + size = bfd_getl32 (ptr); + image_dump (abfd, ptr+4, size, 0); + } + break; + + /* this code is 'reserved to digital' according to the openVMS linker manual, + however it is generated by the DEC C compiler and defined in the include file. + FIXME, since the following is just a guess + store global longword: store 32bit value of symbol + arg: cs symbol name */ + + case ETIR_S_C_STO_GBL_LW: + { + evax_symbol_entry *entry; + char *name; + + name = _bfd_evax_save_counted_string ((char *)ptr); + entry = (evax_symbol_entry *)bfd_hash_lookup (PRIV(evax_symbol_table), name, false, false); + if (entry == (evax_symbol_entry *)NULL) + { +#if EVAX_DEBUG + evax_debug (3, "ETIR_S_C_STO_GBL_LW: no symbol \"%s\"\n", name); +#endif + return false; + } + else + image_write_l (abfd, (unsigned long)(entry->symbol->value)); /* FIXME, reloc */ + } + break; + + /* not supported */ + + case ETIR_S_C_STO_LP_PSB: + (*_bfd_error_handler) ("ETIR_S_C_STO_LP_PSB: Not supported"); + break; + + /* */ + + case ETIR_S_C_STO_HINT_GBL: + (*_bfd_error_handler) ("ETIR_S_C_STO_HINT_GBL: not implemented"); + break; + + /* */ + + case ETIR_S_C_STO_HINT_PS: + (*_bfd_error_handler) ("ETIR_S_C_STO_HINT_PS: not implemented"); + break; + + default: + (*_bfd_error_handler) ("Reserved STO cmd %d", cmd); + break; + } + + return true; +} + +/* stack operator commands + all 32 bit signed arithmetic + all word just like a stack calculator + arguments are popped from stack, results are pushed on stack + + see table B-10 of the openVMS linker manual */ + +static boolean +etir_opr (abfd, cmd, ptr) + bfd *abfd; + int cmd; + unsigned char *ptr; +{ + long op1, op2; + + switch (cmd) + { + /* operation */ + + /* no-op */ + + case ETIR_S_C_OPR_NOP: + break; + + /* add */ + + case ETIR_S_C_OPR_ADD: + op1 = (long)_bfd_evax_pop (abfd, NULL); + op2 = (long)_bfd_evax_pop (abfd, NULL); + _bfd_evax_push (abfd, (uquad)(op1 + op2), -1); + break; + + /* subtract */ + + case ETIR_S_C_OPR_SUB: + op1 = (long)_bfd_evax_pop (abfd, NULL); + op2 = (long)_bfd_evax_pop (abfd, NULL); + _bfd_evax_push (abfd, (uquad)(op2 - op1), -1); + break; + + /* multiply */ + + case ETIR_S_C_OPR_MUL: + op1 = (long)_bfd_evax_pop (abfd, NULL); + op2 = (long)_bfd_evax_pop (abfd, NULL); + _bfd_evax_push (abfd, (uquad)(op1 * op2), -1); + break; + + /* divide */ + + case ETIR_S_C_OPR_DIV: + op1 = (long)_bfd_evax_pop (abfd, NULL); + op2 = (long)_bfd_evax_pop (abfd, NULL); + if (op2 == 0) + _bfd_evax_push (abfd, (uquad)0L, -1); + else + _bfd_evax_push (abfd, (uquad)(op2 / op1), -1); + break; + + /* logical and */ + + case ETIR_S_C_OPR_AND: + op1 = (long)_bfd_evax_pop (abfd, NULL); + op2 = (long)_bfd_evax_pop (abfd, NULL); + _bfd_evax_push (abfd, (uquad)(op1 & op2), -1); + break; + + /* logical inclusive or */ + + case ETIR_S_C_OPR_IOR: + op1 = (long)_bfd_evax_pop (abfd, NULL); + op2 = (long)_bfd_evax_pop (abfd, NULL); + _bfd_evax_push (abfd, (uquad)(op1 | op2), -1); + break; + + /* logical exclusive or */ + + case ETIR_S_C_OPR_EOR: + op1 = (long)_bfd_evax_pop (abfd, NULL); + op2 = (long)_bfd_evax_pop (abfd, NULL); + _bfd_evax_push (abfd, (uquad)(op1 ^ op2), -1); + break; + + /* negate */ + + case ETIR_S_C_OPR_NEG: + op1 = (long)_bfd_evax_pop (abfd, NULL); + _bfd_evax_push (abfd, (uquad)(-op1), -1); + break; + + /* complement */ + + case ETIR_S_C_OPR_COM: + op1 = (long)_bfd_evax_pop (abfd, NULL); + _bfd_evax_push (abfd, (uquad)(op1 ^ -1L), -1); + break; + + /* insert field */ + + case ETIR_S_C_OPR_INSV: + (void)_bfd_evax_pop (abfd, NULL); + (*_bfd_error_handler) ("ETIR_S_C_OPR_INSV: Not supported"); + break; + + /* arithmetic shift */ + + case ETIR_S_C_OPR_ASH: + op1 = (long)_bfd_evax_pop (abfd, NULL); + op2 = (long)_bfd_evax_pop (abfd, NULL); + if (op2 < 0) /* shift right */ + op1 >>= -op2; + else /* shift left */ + op1 <<= op2; + _bfd_evax_push (abfd, (uquad)op1, -1); + break; + + /* unsigned shift */ + + case ETIR_S_C_OPR_USH: + (*_bfd_error_handler) ("ETIR_S_C_OPR_USH: Not supported"); + break; + + /* rotate */ + + case ETIR_S_C_OPR_ROT: + (*_bfd_error_handler) ("ETIR_S_C_OPR_ROT: Not supported"); + break; + + /* select */ + + case ETIR_S_C_OPR_SEL: + if ((long)_bfd_evax_pop (abfd, NULL) & 0x01L) + (void)_bfd_evax_pop (abfd, NULL); + else + { + op1 = (long)_bfd_evax_pop (abfd, NULL); + (void)_bfd_evax_pop (abfd, NULL); + _bfd_evax_push (abfd, (uquad)op1, -1); + } + break; + + /* redefine symbol to current location */ + + case ETIR_S_C_OPR_REDEF: + (*_bfd_error_handler) ("ETIR_S_C_OPR_REDEF: Not supported"); + break; + + /* define a literal */ + + case ETIR_S_C_OPR_DFLIT: + (*_bfd_error_handler) ("ETIR_S_C_OPR_DFLIT: Not supported"); + break; + + default: + (*_bfd_error_handler) ("Reserved OPR cmd %d", cmd); + break; + } + + return true; +} + + +/* control commands + + see table B-11 of the openVMS linker manual */ + +static boolean +etir_ctl (abfd, cmd, ptr) + bfd *abfd; + int cmd; + unsigned char *ptr; +{ + uquad dummy; + int psect; + + switch (cmd) + { + /* set relocation base: pop stack, set image location counter + arg: - */ + + case ETIR_S_C_CTL_SETRB: + dummy = _bfd_evax_pop (abfd, &psect); + image_set_ptr (abfd, psect, dummy); + break; + + /* augment relocation base: increment image location counter by offset + arg: lw offset value */ + + case ETIR_S_C_CTL_AUGRB: + dummy = bfd_getl32 (ptr); + image_inc_ptr (abfd, dummy); + break; + + /* define location: pop index, save location counter under index + arg: - */ + + case ETIR_S_C_CTL_DFLOC: + dummy = _bfd_evax_pop (abfd, NULL); + /* FIXME */ + break; + + /* set location: pop index, restore location counter from index + arg: - */ + + case ETIR_S_C_CTL_STLOC: + dummy = _bfd_evax_pop (abfd, &psect); + /* FIXME */ + break; + + /* stack defined location: pop index, push location counter from index + arg: - */ + + case ETIR_S_C_CTL_STKDL: + dummy = _bfd_evax_pop (abfd, &psect); + /* FIXME */ + break; + + default: + (*_bfd_error_handler) ("Reserved CTL cmd %d", cmd); + break; + } + return true; +} + + +/* store conditional commands + + see table B-12 and B-13 of the openVMS linker manual */ + +static boolean +etir_stc (abfd, cmd, ptr) + bfd *abfd; + int cmd; + unsigned char *ptr; +{ + + switch (cmd) + { + /* 200 Store-conditional Linkage Pair + arg: */ + + case ETIR_S_C_STC_LP: + (*_bfd_error_handler) ("ETIR_S_C_STC_LP: not supported"); + break; + + /* 201 Store-conditional Linkage Pair with Procedure Signature + arg: lw linkage index + cs procedure name + by signature length + da signature */ + + case ETIR_S_C_STC_LP_PSB: + image_inc_ptr (abfd, 16); /* skip entry,procval */ + break; + + /* 202 Store-conditional Address at global address + arg: lw linkage index + cs global name */ + + case ETIR_S_C_STC_GBL: + (*_bfd_error_handler) ("ETIR_S_C_STC_GBL: not supported"); + break; + + /* 203 Store-conditional Code Address at global address + arg: lw linkage index + cs procedure name */ + + case ETIR_S_C_STC_GCA: + (*_bfd_error_handler) ("ETIR_S_C_STC_GCA: not supported"); + break; + + /* 204 Store-conditional Address at psect + offset + arg: lw linkage index + lw psect index + qw offset */ + + case ETIR_S_C_STC_PS: + (*_bfd_error_handler) ("ETIR_S_C_STC_PS: not supported"); + break; + + /* 205 Store-conditional NOP at address of global + arg: */ + + case ETIR_S_C_STC_NOP_GBL: + + /* 206 Store-conditional NOP at pect + offset + arg: */ + + case ETIR_S_C_STC_NOP_PS: + + /* 207 Store-conditional BSR at global address + arg: */ + + case ETIR_S_C_STC_BSR_GBL: + + /* 208 Store-conditional BSR at pect + offset + arg: */ + + case ETIR_S_C_STC_BSR_PS: + + /* 209 Store-conditional LDA at global address + arg: */ + + case ETIR_S_C_STC_LDA_GBL: + + /* 210 Store-conditional LDA at psect + offset + arg: */ + + case ETIR_S_C_STC_LDA_PS: + + /* 211 Store-conditional BSR or Hint at global address + arg: */ + + case ETIR_S_C_STC_BOH_GBL: + + /* 212 Store-conditional BSR or Hint at pect + offset + arg: */ + + case ETIR_S_C_STC_BOH_PS: + + /* 213 Store-conditional NOP,BSR or HINT at global address + arg: */ + + case ETIR_S_C_STC_NBH_GBL: + + /* 214 Store-conditional NOP,BSR or HINT at psect + offset + arg: */ + + case ETIR_S_C_STC_NBH_PS: +/* FIXME (*_bfd_error_handler) ("ETIR_S_C_STC_xx: (%d) not supported", cmd); */ + break; + + default: +#if EVAX_DEBUG + evax_debug (3, "Reserved STC cmd %d", cmd); +#endif + break; + } + return true; +} + + +/* handle command from ETIR section */ + +static boolean +tir_cmd (abfd, cmd, ptr) + bfd *abfd; + int cmd; + unsigned char *ptr; +{ + static struct { + int mincod; + int maxcod; + boolean (*explain) PARAMS((bfd *, int, unsigned char *)); + } tir_table[] = { + { ETIR_S_C_MINSTACOD, ETIR_S_C_MAXSTACOD, etir_sta }, + { ETIR_S_C_MINSTOCOD, ETIR_S_C_MAXSTOCOD, etir_sto }, + { ETIR_S_C_MINOPRCOD, ETIR_S_C_MAXOPRCOD, etir_opr }, + { ETIR_S_C_MINCTLCOD, ETIR_S_C_MAXCTLCOD, etir_ctl }, + { ETIR_S_C_MINSTCCOD, ETIR_S_C_MAXSTCCOD, etir_stc }, + { -1, -1, NULL } + }; + + int i = 0; + boolean res = true; + + while (tir_table[i].mincod >= 0) + { + if ( (tir_table[i].mincod <= cmd) + && (cmd <= tir_table[i].maxcod)) + { + res = tir_table[i].explain (abfd, cmd, ptr); + break; + } + i++; + } + + return res; +} + + +/* Text Information and Relocation Records (OBJ$C_TIR) + handle etir record */ + +static boolean +analyze_etir (abfd, ptr, length) + bfd *abfd; + unsigned char *ptr; + unsigned int length; +{ + int cmd; + unsigned char *maxptr; + boolean res = true; + + maxptr = ptr + length; + + while (ptr < maxptr) + { + cmd = bfd_getl16 (ptr); + length = bfd_getl16 (ptr + 2); + res = tir_cmd (abfd, cmd, ptr+4); + if (!res) + break; + ptr += length; + } + return res; +} + + +/* process ETIR record + + return 0 on success, -1 on error */ + +int +_bfd_evax_slurp_etir (abfd) + bfd *abfd; +{ + +#if EVAX_DEBUG + evax_debug (2, "ETIR\n"); +#endif + + PRIV(evax_rec) += 4; /* skip type, size */ + PRIV(rec_size) -= 4; + if (analyze_etir (abfd, PRIV(evax_rec), PRIV(rec_size))) + return 0; + + return -1; +} + + +/* process EDBG record + return 0 on success, -1 on error + + not implemented yet */ + +int +_bfd_evax_slurp_edbg (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (2, "EDBG\n"); +#endif + + abfd->flags |= (HAS_DEBUG | HAS_LINENO); + return 0; +} + + +/* process ETBT record + return 0 on success, -1 on error + + not implemented yet */ + +int +_bfd_evax_slurp_etbt (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (2, "ETBT\n"); +#endif + + return 0; +} + +/*----------------------------------------------------------------------*/ +/* */ +/* WRITE ETIR SECTION */ +/* */ +/* this is still under construction and therefore not documented */ +/* */ +/*----------------------------------------------------------------------*/ + +static void start_etir_record PARAMS ((bfd *abfd, int index, uquad offset, boolean justoffset)); +static void sto_imm PARAMS ((bfd *abfd, evax_section *sptr, bfd_vma vaddr, int index)); +static void end_etir_record PARAMS ((bfd *abfd)); + +static void +sto_imm (abfd, sptr, vaddr, index) + bfd *abfd; + evax_section *sptr; + bfd_vma vaddr; + int index; +{ + int size; + int ssize; + unsigned char *cptr; + +#if EVAX_DEBUG + evax_debug (8, "sto_imm %d bytes\n", sptr->size); + _bfd_hexdump (9, sptr->contents, (int)sptr->size, (int)vaddr); +#endif + + ssize = sptr->size; + cptr = sptr->contents; + + while (ssize > 0) + { + + size = ssize; /* try all the rest */ + + if (_bfd_evax_output_check (abfd, size) < 0) + { /* doesn't fit, split ! */ + end_etir_record (abfd); + start_etir_record (abfd, index, vaddr, false); + size = _bfd_evax_output_check (abfd, 0); /* get max size */ + if (size > ssize) /* more than what's left ? */ + size = ssize; + } + + _bfd_evax_output_begin (abfd, ETIR_S_C_STO_IMM, -1); + _bfd_evax_output_long (abfd, (unsigned long)(size)); + _bfd_evax_output_dump (abfd, cptr, size); + _bfd_evax_output_flush (abfd); + +#if EVAX_DEBUG + evax_debug (10, "dumped %d bytes\n", size); + _bfd_hexdump (10, cptr, (int)size, (int)vaddr); +#endif + + vaddr += size; + ssize -= size; + cptr += size; + } + + return; +} + +/*-------------------------------------------------------------------*/ + +/* start ETIR record for section #index at virtual addr offset. */ + +static void +start_etir_record (abfd, index, offset, justoffset) + bfd *abfd; + int index; + uquad offset; + boolean justoffset; +{ + if (!justoffset) + { + _bfd_evax_output_begin (abfd, EOBJ_S_C_ETIR, -1); /* one ETIR per section */ + _bfd_evax_output_push (abfd); + } + + _bfd_evax_output_begin (abfd, ETIR_S_C_STA_PQ, -1); /* push start offset */ + _bfd_evax_output_long (abfd, (unsigned long)index); + _bfd_evax_output_quad (abfd, (uquad)offset); + _bfd_evax_output_flush (abfd); + + _bfd_evax_output_begin (abfd, ETIR_S_C_CTL_SETRB, -1); /* start = pop() */ + _bfd_evax_output_flush (abfd); + + return; +} + + +/* end etir record */ +static void +end_etir_record (abfd) + bfd *abfd; +{ + _bfd_evax_output_pop (abfd); + _bfd_evax_output_end (abfd); +} + +/* write section contents for bfd abfd */ + +int +_bfd_evax_write_etir (abfd) + bfd *abfd; +{ + asection *section; + evax_section *sptr; + int nextoffset; + char uname[200]; + char *nptr, *uptr; + +#if EVAX_DEBUG + evax_debug (2, "evax_write_etir(%p)\n", abfd); +#endif + + _bfd_evax_output_alignment (abfd, 4); + + nextoffset = 0; + PRIV(evax_linkage_index) = 1; + + /* dump all other sections */ + + section = abfd->sections; + + while (section != NULL) + { + +#if EVAX_DEBUG + evax_debug (4, "writing %d. section '%s' (%d bytes)\n", section->index, section->name, (int)(section->_raw_size)); +#endif + + if (section->flags & SEC_RELOC) + { + int i; + + if ((i = section->reloc_count) <= 0) + { + (*_bfd_error_handler) ("SEC_RELOC with no relocs in section %s", + section->name); + } +#if EVAX_DEBUG + else + { + arelent **rptr; + evax_debug (4, "%d relocations:\n", i); + rptr = section->orelocation; + while (i-- > 0) + { + evax_debug (4, "sym %s in sec %s, value %08lx, addr %08lx, off %08lx, len %d: %s\n", + (*(*rptr)->sym_ptr_ptr)->name, + (*(*rptr)->sym_ptr_ptr)->section->name, + (long)(*(*rptr)->sym_ptr_ptr)->value, + (*rptr)->address, (*rptr)->addend, + bfd_get_reloc_size((*rptr)->howto), + (*rptr)->howto->name); + rptr++; + } + } +#endif + } + + if (section->flags & SEC_HAS_CONTENTS) + { + bfd_vma vaddr; /* virtual addr in section */ + + sptr = _bfd_get_evax_section (abfd, section->index); + if (sptr == NULL) + { + bfd_set_error (bfd_error_no_contents); + return -1; + } + + vaddr = (bfd_vma)(sptr->offset); + + start_etir_record (abfd, section->index, (uquad) sptr->offset, + false); + + while (sptr != NULL) /* one STA_PQ, CTL_SETRB per evax_section */ + { + + if (section->flags & SEC_RELOC) /* check for relocs */ + { + arelent **rptr = section->orelocation; + int i = section->reloc_count; + for (;;) + { + bfd_size_type addr = (*rptr)->address; + int len = bfd_get_reloc_size ((*rptr)->howto); + if (sptr->offset < addr) /* sptr starts before reloc */ + { + int before = addr - sptr->offset; + if (sptr->size <= before) /* complete before */ + { + sto_imm (abfd, sptr, vaddr, section->index); + vaddr += sptr->size; + break; + } + else /* partly before */ + { + int after = sptr->size - before; + sptr->size = before; + sto_imm (abfd, sptr, vaddr, section->index); + vaddr += sptr->size; + sptr->contents += before; + sptr->offset += before; + sptr->size = after; + } + } + else if (sptr->offset == addr) /* sptr starts at reloc */ + { + asymbol *sym = *(*rptr)->sym_ptr_ptr; + asection *sec = sym->section; + + switch ((*rptr)->howto->type) + { + case ALPHA_R_IGNORE: + break; + + case ALPHA_R_REFLONG: + { + if (bfd_is_und_section (sym->section)) + { + if (_bfd_evax_output_check (abfd, + strlen((char *)sym->name)) + < 0) + { + end_etir_record (abfd); + start_etir_record (abfd, + section->index, + vaddr, false); + } + _bfd_evax_output_begin (abfd, + ETIR_S_C_STO_GBL_LW, + -1); + uptr = uname; + nptr = (char *)sym->name; + while (*nptr) + { + if (islower (*nptr)) + *uptr = toupper (*nptr); + else + *uptr = *nptr; + nptr++; + uptr++; + } + *uptr = 0; + _bfd_evax_output_counted (abfd, uname); + _bfd_evax_output_flush (abfd); + } + else if (bfd_is_abs_section (sym->section)) + { + if (_bfd_evax_output_check (abfd, 16) < 0) + { + end_etir_record (abfd); + start_etir_record (abfd, + section->index, + vaddr, false); + } + _bfd_evax_output_begin (abfd, + ETIR_S_C_STA_LW, + -1); + _bfd_evax_output_quad (abfd, + (uquad)sym->value); + _bfd_evax_output_flush (abfd); + _bfd_evax_output_begin (abfd, + ETIR_S_C_STO_LW, + -1); + _bfd_evax_output_flush (abfd); + } + else + { + if (_bfd_evax_output_check (abfd, 32) < 0) + { + end_etir_record (abfd); + start_etir_record (abfd, + section->index, + vaddr, false); + } + _bfd_evax_output_begin (abfd, + ETIR_S_C_STA_PQ, + -1); + _bfd_evax_output_long (abfd, + (unsigned long)(sec->index)); + _bfd_evax_output_quad (abfd, + ((uquad)(*rptr)->addend + + (uquad)sym->value)); + _bfd_evax_output_flush (abfd); + _bfd_evax_output_begin (abfd, + ETIR_S_C_STO_LW, + -1); + _bfd_evax_output_flush (abfd); + } + } + break; + + case ALPHA_R_REFQUAD: + { + if (bfd_is_und_section (sym->section)) + { + if (_bfd_evax_output_check (abfd, + strlen((char *)sym->name)) + < 0) + { + end_etir_record (abfd); + start_etir_record (abfd, + section->index, + vaddr, false); + } + _bfd_evax_output_begin (abfd, + ETIR_S_C_STO_GBL, + -1); + uptr = uname; + nptr = (char *)sym->name; + while (*nptr) + { + if (islower (*nptr)) + *uptr = toupper (*nptr); + else + *uptr = *nptr; + nptr++; + uptr++; + } + *uptr = 0; + _bfd_evax_output_counted (abfd, uname); + _bfd_evax_output_flush (abfd); + } + else if (bfd_is_abs_section (sym->section)) + { + if (_bfd_evax_output_check (abfd, 16) < 0) + { + end_etir_record (abfd); + start_etir_record (abfd, + section->index, + vaddr, false); + } + _bfd_evax_output_begin (abfd, + ETIR_S_C_STA_QW, + -1); + _bfd_evax_output_quad (abfd, + (uquad)sym->value); + _bfd_evax_output_flush (abfd); + _bfd_evax_output_begin (abfd, + ETIR_S_C_STO_QW, + -1); + _bfd_evax_output_flush (abfd); + } + else + { + if (_bfd_evax_output_check (abfd, 32) < 0) + { + end_etir_record (abfd); + start_etir_record (abfd, + section->index, + vaddr, false); + } + _bfd_evax_output_begin (abfd, + ETIR_S_C_STA_PQ, + -1); + _bfd_evax_output_long (abfd, + (unsigned long)(sec->index)); + _bfd_evax_output_quad (abfd, + ((uquad)(*rptr)->addend + + (uquad)sym->value)); + _bfd_evax_output_flush (abfd); + _bfd_evax_output_begin (abfd, + ETIR_S_C_STO_OFF, + -1); + _bfd_evax_output_flush (abfd); + } + } + break; + + case ALPHA_R_HINT: + { + int hint_size; + + hint_size = sptr->size; + sptr->size = len; + sto_imm (abfd, sptr, vaddr, section->index); + sptr->size = hint_size; +#if 0 + evax_output_begin(abfd, ETIR_S_C_STO_HINT_GBL, -1); + evax_output_long(abfd, (unsigned long)(sec->index)); + evax_output_quad(abfd, (uquad)addr); + uptr = uname; + nptr = (char *)(*(*rptr)->sym_ptr_ptr)->name; + while (*nptr) + { + if (islower (*nptr)) + *uptr = toupper (*nptr); + else + *uptr = *nptr; + nptr++; + uptr++; + } + *uptr = 0; + + evax_output_counted(abfd, uname); + evax_output_flush(abfd); +#endif + } + break; +#if 0 + case ALPHA_R_BRADDR: + break; + case ALPHA_R_SREL16: + break; + case ALPHA_R_SREL32: + break; + case ALPHA_R_SREL64: + break; + case ALPHA_R_OP_PUSH: + break; + case ALPHA_R_OP_STORE: + break; + case ALPHA_R_OP_PSUB: + break; + case ALPHA_R_OP_PRSHIFT: + break; +#endif + case ALPHA_R_LINKAGE: + { + if (_bfd_evax_output_check (abfd, 64) < 0) + { + end_etir_record (abfd); + start_etir_record (abfd, section->index, + vaddr, false); + } + _bfd_evax_output_begin (abfd, + ETIR_S_C_STC_LP_PSB, + -1); + _bfd_evax_output_long (abfd, + (unsigned long)PRIV(evax_linkage_index)); + PRIV(evax_linkage_index) += 2; + uptr = uname; + nptr = (char *)(*(*rptr)->sym_ptr_ptr)->name; + while (*nptr) + { + if (islower (*nptr)) + *uptr = toupper (*nptr); + else + *uptr = *nptr; + nptr++; + uptr++; + } + *uptr = 0; + _bfd_evax_output_counted (abfd, uname); + _bfd_evax_output_byte (abfd, 0); + _bfd_evax_output_flush (abfd); + } + break; + + default: + (*_bfd_error_handler) ("Unhandled relocation %s", + (*rptr)->howto->name); + break; + } + + vaddr += len; + + if (len == sptr->size) + { + break; + } + else + { + sptr->contents += len; + sptr->offset += len; + sptr->size -= len; + i--; + rptr++; + } + } + else /* sptr starts after reloc */ + { + i--; /* check next reloc */ + rptr++; + } + + if (i==0) /* all reloc checked */ + { + if (sptr->size > 0) + { + sto_imm (abfd, sptr, vaddr, section->index); /* dump rest */ + vaddr += sptr->size; + } + break; + } + } /* for (;;) */ + } /* if SEC_RELOC */ + else /* no relocs, just dump */ + { + sto_imm (abfd, sptr, vaddr, section->index); + vaddr += sptr->size; + } + + sptr = sptr->next; + + } /* while (sptr != 0) */ + + end_etir_record (abfd); + + } /* has_contents */ + + section = section->next; + } + + _bfd_evax_output_alignment(abfd, 2); + return 0; +} + + +/* write traceback data for bfd abfd */ + +int +_bfd_evax_write_etbt (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (2, "evax_write_etbt(%p)\n", abfd); +#endif + + return 0; +} + + +/* write debug info for bfd abfd */ + +int +_bfd_evax_write_edbg (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (2, "evax_write_edbg(%p)\n", abfd); +#endif + + return 0; +} diff --git a/gnu/usr.bin/binutils/bfd/evax-misc.c b/gnu/usr.bin/binutils/bfd/evax-misc.c new file mode 100644 index 00000000000..3da89997805 --- /dev/null +++ b/gnu/usr.bin/binutils/bfd/evax-misc.c @@ -0,0 +1,1049 @@ +/* evax-misc.c -- Miscellaneous functions for ALPHA EVAX (openVMS/AXP) files. + Copyright 1996 Free Software Foundation, Inc. + Written by Klaus Kämpf (kkaempf@progis.de) + of proGIS Softwareentwicklung, Aachen, Germany + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#if __STDC__ +#include <stdarg.h> +#endif +#include <stdio.h> + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" + +#include "evax.h" + +/*-----------------------------------------------------------------------------*/ +#if EVAX_DEBUG +/* debug functions */ + +/* debug function for all evax extensions + evaluates environment variable EVAX_DEBUG for a + numerical value on the first call + all error levels below this value are printed + + levels: + 1 toplevel bfd calls (functions from the bfd vector) + 2 functions called by bfd calls + ... + 9 almost everything + + level is also identation level. Indentation is performed + if level > 0 + */ + +#if __STDC__ +void +_bfd_evax_debug (int level, char *format, ...) +{ + static int min_level = -1; + static FILE *output = NULL; + char *eptr; + va_list args; + int abslvl = (level > 0)?level:-level; + + if (min_level == -1) + { + if ((eptr = getenv("EVAX_DEBUG")) != NULL) + { + min_level = atoi(eptr); + output = stderr; + } + else + min_level = 0; + } + if (output == NULL) + return; + if (abslvl > min_level) + return; + + while(--level>0) + fprintf(output, " "); + va_start(args, format); + vfprintf(output, format, args); + fflush(output); + va_end(args); + + return; +} + +#else /* not __STDC__ */ + +void +_bfd_evax_debug (level, format, a1, a2, a3, a4, a5, a6) + int level; + char *format; + long a1; long a2; long a3; + long a4; long a5; long a6; +{ + static int min_level = -1; + static FILE *output = NULL; + char *eptr; + + if (min_level == -1) + { + if ((eptr = getenv("EVAX_DEBUG")) != NULL) + { + min_level = atoi(eptr); + output = stderr; + } + else + min_level = 0; + } + if (output == NULL) + return; + if (level > min_level) + return; + + while(--level>0) + fprintf(output, " "); + fprintf(output, format, a1, a2, a3, a4, a5, a6); + fflush(output); + + return; +} +#endif /* __STDC__ */ + + +/* a debug function + hex dump 'size' bytes starting at 'ptr' */ + +void +_bfd_hexdump (level, ptr, size, offset) + int level; + unsigned char *ptr; + int size; + int offset; +{ + unsigned char *lptr = ptr; + int count = 0; + long start = offset; + + while (size-- > 0) + { + if ((count%16) == 0) + evax_debug (level, "%08lx:", start); + evax_debug (-level, " %02x", *ptr++); + count++; + start++; + if (size == 0) + { + while ((count%16) != 0) + { + evax_debug (-level, " "); + count++; + } + } + if ((count%16) == 0) + { + evax_debug (-level, " "); + while (lptr < ptr) + { + evax_debug (-level, "%c", (*lptr < 32)?'.':*lptr); + lptr++; + } + evax_debug (-level, "\n"); + } + } + if ((count%16) != 0) + evax_debug (-level, "\n"); + + return; +} +#endif + + +/* hash functions + + These are needed when reading an object file. */ + +/* allocate new evax_hash_entry + keep the symbol name and a pointer to the bfd symbol in the table */ + +struct bfd_hash_entry * +_bfd_evax_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + evax_symbol_entry *ret = (evax_symbol_entry *)entry; + +#if EVAX_DEBUG + evax_debug (5, "_bfd_evax_hash_newfunc(%p, %p, %s)\n", entry, table, string); +#endif + + if (ret == (evax_symbol_entry *)NULL) + ret = ((evax_symbol_entry *) bfd_hash_allocate (table, sizeof (evax_symbol_entry))); + if (ret == (evax_symbol_entry *)NULL) + { + bfd_set_error (bfd_error_no_memory); + return (struct bfd_hash_entry *)NULL; + } + ret = (evax_symbol_entry *) bfd_hash_newfunc ((struct bfd_hash_entry *)ret, table, string); + + ret->symbol = (asymbol *)NULL; + + return (struct bfd_hash_entry *)ret; +} + + +/* object file input functions */ + +/* Return type and length from record header (buf) */ + +void +_bfd_evax_get_header_values (abfd, buf, type, length) + bfd *abfd; + unsigned char *buf; + int *type; + int *length; +{ + if (type != 0) + *type = bfd_getl16 (buf); + buf += 2; + if (length != 0) + *length = bfd_getl16 (buf); + + return; +} + + +/* Get next record from object file to evax_buf + set PRIV(buf_size) and return it + + this is a little tricky since it should be portable. + + the openVMS/AXP object file has 'variable length' which means that + read() returns data in chunks of (hopefully) correct and expected + size. The linker (and other tools on vms) depend on that. Unix doesn't + know about 'formatted' files, so reading and writing such an object + file in a unix environment is not trivial. + + With the tool 'file' (available on all vms ftp sites), one + can view and change the attributes of a file. Changing from + 'variable length' to 'fixed length, 512 bytes' reveals the + record length at the first 2 bytes of every record. The same + happens during the transfer of object files from vms to unix, + at least with ucx, dec's implementation of tcp/ip. + + The EVAX format repeats the length at bytes 2 & 3 of every record. + + On the first call (file_format == FF_UNKNOWN) we check if + the first and the third byte pair (!) of the record match. + If they do it's an object file in an unix environment or with + wrong attributes (FF_FOREIGN), else we should be in a vms + environment where read() returns the record size (FF_NATIVE). + + reading is always done in 2 steps. + first just the record header is read and the length extracted + by get_header_values + then the read buffer is adjusted and the remaining bytes are + read in. + + all file i/o is always done on even file positions */ + +int +_bfd_evax_get_record (abfd) + bfd *abfd; +{ + int test_len, test_start, remaining; + unsigned char *evax_buf; + +#if EVAX_DEBUG + evax_debug (8, "_bfd_evax_get_record\n"); +#endif + + /* minimum is 6 bytes + (2 bytes length, 2 bytes record id, 2 bytes length repeated) */ + + if (PRIV(buf_size) == 0) + { + PRIV(evax_buf) = (unsigned char *) malloc (6); +#if EVAX_DEBUG + evax_debug (9, "PRIV(evax_buf) %p\n", PRIV(evax_buf)); +#endif + } + + evax_buf = PRIV(evax_buf); + + if (evax_buf == 0) + { +#if EVAX_DEBUG + evax_debug (9, "can't alloc evax_buf\n"); +#endif + bfd_set_error (bfd_error_no_memory); + return -1; + } + + switch (PRIV(file_format)) + { + case FF_UNKNOWN: + case FF_FOREIGN: + test_len = 6; /* probe 6 bytes */ + test_start = 2; /* where the record starts */ + break; + + case FF_NATIVE: + test_len = 4; + test_start = 0; + break; + } + + /* skip odd alignment byte */ +#if 0 + if (PRIV(file_format) == FF_FOREIGN) + { +#endif + if (bfd_tell (abfd) & 1) + { +#if EVAX_DEBUG + evax_debug (10, "skip odd\n"); +#endif + if (bfd_read (PRIV(evax_buf), 1, 1, abfd) != 1) + { +#if EVAX_DEBUG + evax_debug (9, "skip odd failed\n"); +#endif + bfd_set_error (bfd_error_file_truncated); + return 0; + } + } +#if 0 + } +#endif + /* read the record header */ + + if (bfd_read (PRIV(evax_buf), 1, test_len, abfd) != test_len) + { +#if EVAX_DEBUG + evax_debug (9, "can't bfd_read test %d bytes\n", test_len); +#endif + bfd_set_error (bfd_error_file_truncated); + return 0; + } + + /* check file format on first call */ + + if (PRIV(file_format) == FF_UNKNOWN) + { /* record length repeats ? */ + if ( (evax_buf[0] == evax_buf[4]) + && (evax_buf[1] == evax_buf[5])) + { + PRIV(file_format) = FF_FOREIGN; /* Y: foreign environment */ + test_start = 2; + } + else + { + PRIV(file_format) = FF_NATIVE; /* N: native environment */ + test_start = 0; + } +#if EVAX_DEBUG + evax_debug (10, "File format is %s\n", (PRIV(file_format) == FF_FOREIGN)?"foreign":"native"); +#endif + } + + /* extract evax record length */ + + _bfd_evax_get_header_values (abfd, evax_buf+test_start, NULL, + &PRIV(rec_length)); + + if (PRIV(rec_length) <= 0) + { + bfd_set_error (bfd_error_file_truncated); + return 0; + } + + /* that's what the linker manual says */ + + if (PRIV(rec_length) > EOBJ_S_C_MAXRECSIZ) + { + bfd_set_error (bfd_error_file_truncated); + return 0; + } + + /* adjust the buffer */ + + if (PRIV(rec_length) > PRIV(buf_size)) + { + PRIV(evax_buf) = (unsigned char *) realloc (evax_buf, PRIV(rec_length)); +#if EVAX_DEBUG + evax_debug (3, "adjusted the buffer (%p) from %d to %d\n", PRIV(evax_buf), PRIV(buf_size), PRIV(rec_length)); +#endif + evax_buf = PRIV(evax_buf); + if (evax_buf == 0) + { +#if EVAX_DEBUG + evax_debug (9, "can't realloc evax_buf to %d bytes\n", PRIV(rec_length)); +#endif + bfd_set_error (bfd_error_no_memory); + return -1; + } + PRIV(buf_size) = PRIV(rec_length); + } + + /* read the remaining record */ + + remaining = PRIV(rec_length) - test_len + test_start; + + if (bfd_read (evax_buf + test_len, 1, remaining, abfd) != remaining) + { +#if EVAX_DEBUG + evax_debug (9, "can't bfd_read remaining %d bytes\n", remaining); +#endif + bfd_set_error (bfd_error_file_truncated); + return 0; + } + + PRIV(evax_rec) = evax_buf + test_start; + + return PRIV(rec_length); +} + + +/* get next EVAX record from file + update evax_rec and rec_length to new (remaining) values */ + +int +_bfd_evax_next_record (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (8, "_bfd_evax_next_record (len %d, size %d)\n", + PRIV(rec_length), PRIV(rec_size)); +#endif + + if (PRIV(rec_length) > 0) + { + PRIV(evax_rec) += PRIV(rec_size); + } + else + { + if (_bfd_evax_get_record (abfd) <= 0) + return -1; + } + _bfd_evax_get_header_values (abfd, PRIV(evax_rec), &PRIV(rec_type), + &PRIV(rec_size)); + PRIV(rec_length) -= PRIV(rec_size); + +#if EVAX_DEBUG + evax_debug (8, "_bfd_evax_next_record: rec %p, size %d, length %d, type %d\n", + PRIV(evax_rec), PRIV(rec_size), PRIV(rec_length), + PRIV(rec_type)); +#endif + + return PRIV(rec_type); +} + + + +/* Copy sized string (string with fixed length) to new allocated area + size is string length (size of record) */ + +char * +_bfd_evax_save_sized_string (str, size) + char *str; + int size; +{ + char *newstr = bfd_malloc (size + 1); + + if (newstr == NULL) + return 0; + strncpy (newstr, str, size); + newstr[size] = 0; + + return newstr; +} + +/* Copy counted string (string with length at first byte) to new allocated area + ptr points to length byte on entry */ + +char * +_bfd_evax_save_counted_string (ptr) + char *ptr; +{ + int len = *ptr++; + + return _bfd_evax_save_sized_string (ptr, len); +} + + +/* stack routines for EVAX ETIR commands */ + +/* Push value and section index */ + +void +_bfd_evax_push (abfd, val, psect) + bfd *abfd; + uquad val; + int psect; +{ + static int last_psect; + +#if EVAX_DEBUG + evax_debug (4, "<push %016lx(%d) at %d>\n", val, psect, PRIV(stackptr)); +#endif + + if (psect >= 0) + last_psect = psect; + + PRIV(stack[PRIV(stackptr)]).value = val; + PRIV(stack[PRIV(stackptr)]).psect = last_psect; + PRIV(stackptr)++; + if (PRIV(stackptr) >= STACKSIZE) + { + bfd_set_error (bfd_error_bad_value); + exit(1); + } + return; +} + + +/* Pop value and section index */ + +uquad +_bfd_evax_pop (abfd, psect) + bfd *abfd; + int *psect; +{ + uquad value; + + if (PRIV(stackptr) == 0) + { + bfd_set_error (bfd_error_bad_value); + exit(1); + } + PRIV(stackptr)--; + value = PRIV(stack[PRIV(stackptr)]).value; + if ((psect != NULL) && (PRIV(stack[PRIV(stackptr)]).psect >= 0)) + *psect = PRIV(stack[PRIV(stackptr)]).psect; + +#if EVAX_DEBUG + evax_debug (4, "<pop %016lx(%d)>\n", value, PRIV(stack[PRIV(stackptr)]).psect); +#endif + + return value; +} + + +/* object file output functions */ + +/* GAS tends to write sections in little chunks (bfd_set_section_contents) + which we can't use directly. So we save the little chunks in linked + lists (one per section) and write them later. */ + +/* Add a new evax_section structure to evax_section_table + - forward chaining - */ + +static evax_section * +add_new_contents (abfd, section) + bfd *abfd; + sec_ptr section; +{ + evax_section *sptr, *newptr; + + sptr = PRIV(evax_section_table)[section->index]; + if (sptr != NULL) + return sptr; + + newptr = (evax_section *) bfd_malloc (sizeof (evax_section)); + if (newptr == (evax_section *) NULL) + return NULL; + newptr->contents = (unsigned char *) bfd_alloc (abfd, section->_raw_size); + if (newptr->contents == (unsigned char *)NULL) + return NULL; + newptr->offset = 0; + newptr->size = section->_raw_size; + newptr->next = 0; + PRIV(evax_section_table)[section->index] = newptr; + return newptr; +} + + +/* Save section data & offset to an evax_section structure + evax_section_table[] holds the evax_section chain */ + +boolean +_bfd_save_evax_section (abfd, section, data, offset, count) + bfd *abfd; + sec_ptr section; + PTR data; + file_ptr offset; + bfd_size_type count; +{ + evax_section *sptr; + + if (section->index >= EVAX_SECTION_COUNT) + { + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } + if (count == (bfd_size_type)0) + return true; + sptr = add_new_contents (abfd, section); + if (sptr == NULL) + return false; + memcpy (sptr->contents + offset, data, (size_t) count); + + return true; +} + + +/* Get evax_section pointer to saved contents for section # index */ + +evax_section * +_bfd_get_evax_section (abfd, index) + bfd *abfd; + int index; +{ + if (index >= EVAX_SECTION_COUNT) + { + bfd_set_error (bfd_error_nonrepresentable_section); + return NULL; + } + return PRIV(evax_section_table)[index]; +} + + +/* Object output routines */ + +/* Begin new record or record header + write 2 bytes rectype + write 2 bytes record length (filled in at flush) + write 2 bytes header type (ommitted if rechead == -1) */ + +void +_bfd_evax_output_begin (abfd, rectype, rechead) + bfd *abfd; + int rectype; + int rechead; +{ +#if EVAX_DEBUG + evax_debug (6, "_bfd_evax_output_begin(type %d, head %d)\n", rectype, + rechead); +#endif + + _bfd_evax_output_short (abfd,rectype); + + /* save current output position to fill in lenght later */ + + if (PRIV(push_level) > 0) + PRIV(length_pos) = PRIV(output_size); + +#if EVAX_DEBUG + evax_debug (6, "_bfd_evax_output_begin: length_pos = %d\n", + PRIV(length_pos)); +#endif + + _bfd_evax_output_short (abfd,0); /* placeholder for length */ + + if (rechead != -1) + _bfd_evax_output_short (abfd,rechead); + + return; +} + + +/* Set record/subrecord alignment */ + +void +_bfd_evax_output_alignment (abfd, alignto) + bfd *abfd; + int alignto; +{ +#if EVAX_DEBUG + evax_debug (6, "_bfd_evax_output_alignment(%d)\n", alignto); +#endif + + PRIV(output_alignment) = alignto; + return; +} + + +/* Prepare for subrecord fields */ + +void +_bfd_evax_output_push (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (6, "evax_output_push(pushed_size = %d)\n", PRIV(output_size)); +#endif + + PRIV(push_level)++; + PRIV(pushed_size) = PRIV(output_size); + return; +} + + +/* End of subrecord fields */ + +void +_bfd_evax_output_pop (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (6, "evax_output_pop(pushed_size = %d)\n", PRIV(pushed_size)); +#endif + + _bfd_evax_output_flush (abfd); + PRIV(length_pos) = 2; + +#if EVAX_DEBUG + evax_debug (6, "evax_output_pop: length_pos = %d\n", PRIV(length_pos)); +#endif + + PRIV(pushed_size) = 0; + PRIV(push_level)--; + return; +} + + +/* Flush unwritten output, ends current record */ + +void +_bfd_evax_output_flush (abfd) + bfd *abfd; +{ + int real_size = PRIV(output_size); + int aligncount; + int length; + +#if EVAX_DEBUG + evax_debug (6, "_bfd_evax_output_flush(real_size = %d, pushed_size %d at lenpos %d)\n", + real_size, PRIV(pushed_size), PRIV(length_pos)); +#endif + + if (PRIV(push_level) > 0) + length = real_size - PRIV(pushed_size); + else + length = real_size; + + if (length == 0) + return; + aligncount = (PRIV(output_alignment) + - (length % PRIV(output_alignment))) % PRIV(output_alignment); + +#if EVAX_DEBUG + evax_debug (6, "align: adding %d bytes\n", aligncount); +#endif + + while(aligncount-- > 0) + { + PRIV(output_buf)[real_size++] = 0; +#if 0 + /* this is why I *love* vms: inconsistency :-} + alignment is added to the subrecord length + but not to the record length */ + if (PRIV(push_level) > 0) +#endif + length++; + } + + /* put length to buffer */ + PRIV(output_size) = PRIV(length_pos); + _bfd_evax_output_short (abfd, (unsigned int)length); + + if (PRIV(push_level) == 0) + { +#ifndef VMS + /* write length first, see FF_FOREIGN in the input routines */ + fwrite (PRIV(output_buf)+2, 2, 1, (FILE *)abfd->iostream); +#endif + fwrite (PRIV(output_buf), real_size, 1, (FILE *)abfd->iostream); + + PRIV(output_size) = 0; + } + else + { + PRIV(output_size) = real_size; + PRIV(pushed_size) = PRIV(output_size); + } + + return; +} + + +/* End record output */ + +void +_bfd_evax_output_end (abfd) + bfd *abfd; +{ +#if EVAX_DEBUG + evax_debug (6, "_bfd_evax_output_end\n"); +#endif + + _bfd_evax_output_flush (abfd); + + return; +} + + +/* check remaining buffer size + + return what's left. */ + +int +_bfd_evax_output_check (abfd, size) + bfd *abfd; + int size; +{ +#if EVAX_DEBUG + evax_debug (6, "_bfd_evax_output_check(%d)\n", size); +#endif + + return (MAX_OUTREC_SIZE - (PRIV(output_size) + size + MIN_OUTREC_LUFT)); +} + + +/* Output byte (8 bit) value */ + +void +_bfd_evax_output_byte (abfd, value) + bfd *abfd; + unsigned int value; +{ +#if EVAX_DEBUG + evax_debug (6, "_bfd_evax_output_byte(%02x)\n", value); +#endif + + bfd_put_8 (abfd, value & 0xff, PRIV(output_buf) + PRIV(output_size)); + PRIV(output_size) += 1; + return; +} + + +/* Output short (16 bit) value */ + +void +_bfd_evax_output_short (abfd, value) + bfd *abfd; + unsigned int value; +{ +#if EVAX_DEBUG + evax_debug (6, "_bfd_evax_output_short (%04x)\n", value); +#endif + + bfd_put_16 (abfd, value & 0xffff, PRIV(output_buf) + PRIV(output_size)); + PRIV(output_size) += 2; + return; +} + + +/* Output long (32 bit) value */ + +void +_bfd_evax_output_long (abfd, value) + bfd *abfd; + unsigned long value; +{ +#if EVAX_DEBUG + evax_debug (6, "_bfd_evax_output_long (%08lx)\n", value); +#endif + + bfd_put_32 (abfd, value, PRIV(output_buf) + PRIV(output_size)); + PRIV(output_size) += 4; + return; +} + + +/* Output quad (64 bit) value */ + +void +_bfd_evax_output_quad (abfd, value) + bfd *abfd; + uquad value; +{ +#if EVAX_DEBUG + evax_debug (6, "_bfd_evax_output_quad(%016lx)\n", value); +#endif + + bfd_put_64(abfd, value, PRIV(output_buf) + PRIV(output_size)); + PRIV(output_size) += 8; + return; +} + + +/* Output c-string as counted string */ + +void +_bfd_evax_output_counted (abfd, value) + bfd *abfd; + char *value; +{ +int len; + +#if EVAX_DEBUG + evax_debug (6, "_bfd_evax_output_counted(%s)\n", value); +#endif + + len = strlen (value); + if (len == 0) + { + (*_bfd_error_handler) ("_bfd_evax_output_counted called with zero bytes"); + return; + } + if (len > 255) + { + (*_bfd_error_handler) ("_bfd_evax_output_counted called with too many bytes"); + return; + } + _bfd_evax_output_byte (abfd, len & 0xff); + _bfd_evax_output_dump (abfd, (unsigned char *)value, len); +} + + +/* Output character area */ + +void +_bfd_evax_output_dump (abfd, data, length) + bfd *abfd; + unsigned char *data; + int length; +{ +#if EVAX_DEBUG + evax_debug (6, "_bfd_evax_output_dump(%d)\n", length); +#endif + + if (length == 0) + return; + + memcpy (PRIV(output_buf) + PRIV(output_size), data, length); + PRIV(output_size) += length; + + return; +} + + +/* Output count bytes of value */ + +void +_bfd_evax_output_fill (abfd, value, count) + bfd *abfd; + int value; + int count; +{ +#if EVAX_DEBUG + evax_debug (6, "_bfd_evax_output_fill(val %02x times %d)\n", value, count); +#endif + + if (count == 0) + return; + memset (PRIV(output_buf) + PRIV(output_size), value, count); + PRIV(output_size) += count; + + return; +} + +/*-----------------------------------------------------------------------------*/ + +/* Return basename (stripped of directory information) of filename */ + +char * +_bfd_evax_basename (name) + char *name; +{ + char *ptr; + +#if EVAX_DEBUG + evax_debug (6, "_bfd_evax_basename %s -> ", name); +#endif + +#ifndef VMS + /* assume unix host */ + ptr = strrchr (name, '.'); + if (ptr) + *ptr = 0; + ptr = strrchr (name, '/'); + if (ptr) + *ptr++ = 0; + else + ptr = name; +#else + /* assume vms host */ + ptr = strrchr (name, '.'); + if (ptr) + { + *ptr = 0; + ptr = name; + } + else + { + ptr = strrchr (name, ']'); + if (ptr) + *ptr++ = 0; + else + { + ptr = strrchr (name, ':'); + if (ptr) + *ptr++ = 0; + else + ptr = name; + } + } +#endif + +#if EVAX_DEBUG + evax_debug (6, "%s\n", ptr); +#endif + + return ptr; +} + + +/* Manufacure a VMS like time on a unix based system. + stolen from obj-vms.c */ + +char * +_bfd_get_vms_time_string () +{ + static char tbuf[18]; +#ifndef VMS +#include <sys/types.h> +#include <time.h> + + char *pnt; + time_t timeb; + time (&timeb); + pnt = ctime (&timeb); + pnt[3] = 0; + pnt[7] = 0; + pnt[10] = 0; + pnt[16] = 0; + pnt[24] = 0; + sprintf (tbuf, "%2s-%3s-%s %s", pnt + 8, pnt + 4, pnt + 20, pnt + 11); +#else +#include <starlet.h> + struct + { + int Size; + char *Ptr; + } Descriptor; + Descriptor.Size = 17; + Descriptor.Ptr = tbuf; + sys$asctim (0, &Descriptor, 0, 0); +#endif /* not VMS */ + +#if EVAX_DEBUG + evax_debug (6, "vmstimestring:'%s'\n", tbuf); +#endif + + return tbuf; +} diff --git a/gnu/usr.bin/binutils/bfd/evax.h b/gnu/usr.bin/binutils/bfd/evax.h new file mode 100644 index 00000000000..7d6c9b4ec42 --- /dev/null +++ b/gnu/usr.bin/binutils/bfd/evax.h @@ -0,0 +1,379 @@ +/* evax.h -- Header file for ALPHA EVAX (openVMS/AXP) support. + Copyright 1996 Free Software Foundation, Inc. + Written by Klaus Kämpf (kkaempf@progis.de) + of proGIS Softwareentwicklung, Aachen, Germany + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef EVAX_H +#define EVAX_H + +/* EVAX Text, information and relocation record (ETIR) definitions. */ + +#define ETIR_S_C_MINSTACOD 0 /* Minimum store code */ +#define ETIR_S_C_STA_GBL 0 /* Stack global symbol value */ +#define ETIR_S_C_STA_LW 1 /* Stack longword */ +#define ETIR_S_C_STA_QW 2 /* Stack quadword */ +#define ETIR_S_C_STA_PQ 3 /* Stack psect base plus quadword offset */ +#define ETIR_S_C_STA_LI 4 /* Stack literal */ +#define ETIR_S_C_STA_MOD 5 /* Stack module */ +#define ETIR_S_C_STA_CKARG 6 /* Check Arguments */ +#define ETIR_S_C_MAXSTACOD 6 /* Maximum stack code */ +#define ETIR_S_C_MINSTOCOD 50 /* Minimum store code */ +#define ETIR_S_C_STO_B 50 /* Store byte */ +#define ETIR_S_C_STO_W 51 /* Store word */ +#define ETIR_S_C_STO_LW 52 /* Store longword */ +#define ETIR_S_C_STO_QW 53 /* Store quadword */ +#define ETIR_S_C_STO_IMMR 54 /* Store immediate Repeated */ +#define ETIR_S_C_STO_GBL 55 /* Store global */ +#define ETIR_S_C_STO_CA 56 /* Store code address */ +#define ETIR_S_C_STO_RB 57 /* Store relative branch */ +#define ETIR_S_C_STO_AB 58 /* Store absolute branch */ +#define ETIR_S_C_STO_OFF 59 /* Store offset within psect */ +#define ETIR_S_C_STO_IMM 61 /* Store immediate */ +#define ETIR_S_C_STO_GBL_LW 62 /* Store global Longword */ +#define ETIR_S_C_STO_LP_PSB 63 /* STO_LP_PSB not valid in level 2 use STC_LP_PSB */ +#define ETIR_S_C_STO_HINT_GBL 64 /* Store 14 bit HINT at global address */ +#define ETIR_S_C_STO_HINT_PS 65 /* Store 14 bit HINT at psect + offset */ +#define ETIR_S_C_MAXSTOCOD 65 /* Maximum store code */ +#define ETIR_S_C_MINOPRCOD 100 /* Minimum operate code */ +#define ETIR_S_C_OPR_NOP 100 /* No-op */ +#define ETIR_S_C_OPR_ADD 101 /* Add */ +#define ETIR_S_C_OPR_SUB 102 /* Subtract */ +#define ETIR_S_C_OPR_MUL 103 /* Multiply */ +#define ETIR_S_C_OPR_DIV 104 /* Divide */ +#define ETIR_S_C_OPR_AND 105 /* Logical AND */ +#define ETIR_S_C_OPR_IOR 106 /* Logical inclusive OR */ +#define ETIR_S_C_OPR_EOR 107 /* Logical exclusive OR */ +#define ETIR_S_C_OPR_NEG 108 /* Negate */ +#define ETIR_S_C_OPR_COM 109 /* Complement */ +#define ETIR_S_C_OPR_INSV 110 /* Insert bit field */ +#define ETIR_S_C_OPR_ASH 111 /* Arithmetic shift */ +#define ETIR_S_C_OPR_USH 112 /* Unsigned shift */ +#define ETIR_S_C_OPR_ROT 113 /* Rotate */ +#define ETIR_S_C_OPR_SEL 114 /* Select one of three longwords on top of stack */ +#define ETIR_S_C_OPR_REDEF 115 /* Redefine this symbol after pass 2 */ +#define ETIR_S_C_OPR_DFLIT 116 /* Define a literal */ +#define ETIR_S_C_MAXOPRCOD 116 /* Maximum operate code */ +#define ETIR_S_C_MINCTLCOD 150 /* Minimum control code */ +#define ETIR_S_C_CTL_SETRB 150 /* Set relocation base */ +#define ETIR_S_C_CTL_AUGRB 151 /* Augment relocation base */ +#define ETIR_S_C_CTL_DFLOC 152 /* Define debug location */ +#define ETIR_S_C_CTL_STLOC 153 /* Set debug location */ +#define ETIR_S_C_CTL_STKDL 154 /* Stack debug location */ +#define ETIR_S_C_MAXCTLCOD 154 /* Maximum control code */ +#define ETIR_S_C_MINSTCCOD 200 /* Minimum store-conditional code */ +#define ETIR_S_C_STC_LP 200 /* Store-conditional Linkage Pair */ +#define ETIR_S_C_STC_LP_PSB 201 /* Store-conditional Linkage Pair with Procedure Signature */ +#define ETIR_S_C_STC_GBL 202 /* Store-conditional Address at global address */ +#define ETIR_S_C_STC_GCA 203 /* Store-conditional Code Address at global address */ +#define ETIR_S_C_STC_PS 204 /* Store-conditional Address at psect + offset */ +#define ETIR_S_C_STC_NOP_GBL 205 /* Store-conditional NOP at address of global */ +#define ETIR_S_C_STC_NOP_PS 206 /* Store-conditional NOP at pect + offset */ +#define ETIR_S_C_STC_BSR_GBL 207 /* Store-conditional BSR at global address */ +#define ETIR_S_C_STC_BSR_PS 208 /* Store-conditional BSR at pect + offset */ +#define ETIR_S_C_STC_LDA_GBL 209 /* Store-conditional LDA at global address */ +#define ETIR_S_C_STC_LDA_PS 210 /* Store-conditional LDA at psect + offset */ +#define ETIR_S_C_STC_BOH_GBL 211 /* Store-conditional BSR or Hint at global address */ +#define ETIR_S_C_STC_BOH_PS 212 /* Store-conditional BSR or Hint at pect + offset */ +#define ETIR_S_C_STC_NBH_GBL 213 /* Store-conditional NOP,BSR or HINT at global address */ +#define ETIR_S_C_STC_NBH_PS 214 /* Store-conditional NOP,BSR or HINT at psect + offset */ +#define ETIR_S_C_MAXSTCCOD 214 /* Maximum store-conditional code */ + +/* EVAX Global symbol definition record (EGSD). */ + +#define EGSD_S_K_ENTRIES 2 /* Offset to first entry in record */ +#define EGSD_S_C_ENTRIES 2 /* Offset to first entry in record */ +#define EGSD_S_C_PSC 0 /* Psect definition */ +#define EGSD_S_C_SYM 1 /* Symbol specification */ +#define EGSD_S_C_IDC 2 /* Random entity check */ +#define EGSD_S_C_SPSC 5 /* Shareable image psect definition */ +#define EGSD_S_C_SYMV 6 /* Vectored (dual-valued) versions of SYM, */ +#define EGSD_S_C_SYMM 7 /* Masked versions of SYM, */ +#define EGSD_S_C_SYMG 8 /* EGST - gst version of SYM */ +#define EGSD_S_C_MAXRECTYP 8 /* Maximum entry type defined */ + +#define EGPS_S_V_PIC 0x0001 +#define EGPS_S_V_LIB 0x0002 +#define EGPS_S_V_OVR 0x0004 +#define EGPS_S_V_REL 0x0008 +#define EGPS_S_V_GBL 0x0010 +#define EGPS_S_V_SHR 0x0020 +#define EGPS_S_V_EXE 0x0040 +#define EGPS_S_V_RD 0x0080 +#define EGPS_S_V_WRT 0x0100 +#define EGPS_S_V_VEC 0x0200 +#define EGPS_S_V_NOMOD 0x0400 +#define EGPS_S_V_COM 0x0800 + +#define EGSY_S_V_WEAK 0x0001 +#define EGSY_S_V_DEF 0x0002 +#define EGSY_S_V_UNI 0x0004 +#define EGSY_S_V_REL 0x0008 +#define EGSY_S_V_COMM 0x0010 +#define EGSY_S_V_VECEP 0x0020 +#define EGSY_S_V_NORM 0x0040 + +/* EVAX Module header record (EMH) definitions. */ + +#define EMH_S_C_MHD 0 /* Main header record */ +#define EMH_S_C_LNM 1 /* Language name and version */ +#define EMH_S_C_SRC 2 /* Source file specification */ +#define EMH_S_C_TTL 3 /* Title text of module */ +#define EMH_S_C_CPR 4 /* Copyright notice */ +#define EMH_S_C_MTC 5 /* Maintenance status */ +#define EMH_S_C_GTX 6 /* General text */ +#define EMH_S_C_MAXHDRTYP 6 /* Maximum allowable type */ + +/* evax-alpha.c. */ + +extern asymbol *_bfd_evax_make_empty_symbol PARAMS ((bfd *abfd)); + +/* evax-egsd.c. */ + +extern int _bfd_evax_slurp_egsd PARAMS ((bfd *abfd)); +extern int _bfd_evax_write_egsd PARAMS ((bfd *abfd)); + +/* evax-emh.c. */ + +extern int _bfd_evax_slurp_emh PARAMS ((bfd *abfd)); +extern int _bfd_evax_write_emh PARAMS ((bfd *abfd)); +extern int _bfd_evax_slurp_eeom PARAMS ((bfd *abfd)); +extern int _bfd_evax_write_eeom PARAMS ((bfd *abfd)); + +/* evax-etir.c. */ + +extern int _bfd_evax_slurp_etir PARAMS ((bfd *abfd)); +extern int _bfd_evax_slurp_edbg PARAMS ((bfd *abfd)); +extern int _bfd_evax_slurp_etbt PARAMS ((bfd *abfd)); + +extern int _bfd_evax_write_etir PARAMS ((bfd *abfd)); +extern int _bfd_evax_write_etbt PARAMS ((bfd *abfd)); +extern int _bfd_evax_write_edbg PARAMS ((bfd *abfd)); + +/* The r_type field in a reloc is one of the following values. */ +#define ALPHA_R_IGNORE 0 +#define ALPHA_R_REFQUAD 1 +#define ALPHA_R_BRADDR 2 +#define ALPHA_R_HINT 3 +#define ALPHA_R_SREL16 4 +#define ALPHA_R_SREL32 5 +#define ALPHA_R_SREL64 6 +#define ALPHA_R_OP_PUSH 7 +#define ALPHA_R_OP_STORE 8 +#define ALPHA_R_OP_PSUB 9 +#define ALPHA_R_OP_PRSHIFT 10 +#define ALPHA_R_LINKAGE 11 +#define ALPHA_R_REFLONG 12 + +/* Object language definitions. */ + +#define EOBJ_S_C_EMH 8 /*EVAX module header record */ +#define EOBJ_S_C_EEOM 9 /*EVAX end of module record */ +#define EOBJ_S_C_EGSD 10 /*EVAX global symbol definition record */ +#define EOBJ_S_C_ETIR 11 /*EVAX text information record */ +#define EOBJ_S_C_EDBG 12 /*EVAX Debugger information record */ +#define EOBJ_S_C_ETBT 13 /*EVAX Traceback information record */ +#define EOBJ_S_C_MAXRECTYP 13 /*Last assigned record type */ +#define EOBJ_S_K_SUBTYP 4 +#define EOBJ_S_C_SUBTYP 4 +#define EOBJ_S_C_MAXRECSIZ 8192 /*Maximum legal record size */ +#define EOBJ_S_C_STRLVL 2 /*Structure level */ +#define EOBJ_S_C_SYMSIZ 64 /*Maxymum symbol length */ +#define EOBJ_S_C_STOREPLIM -1 /*Maximum repeat count on store commands */ +#define EOBJ_S_C_PSCALILIM 16 /*Maximum p-sect alignment */ + +/* Miscellaneous definitions. */ + +#if __GNUC__ +typedef unsigned long long uquad; +#else +typedef unsigned long uquad; +#endif + +#define MAX_OUTREC_SIZE 4096 +#define MIN_OUTREC_LUFT 64 + +typedef struct _evax_section { + unsigned char *contents; + bfd_vma offset; + bfd_size_type size; + struct _evax_section *next; +} evax_section; + +extern boolean _bfd_save_evax_section + PARAMS ((bfd *abfd, asection *section, PTR data, file_ptr offset, + bfd_size_type count)); +extern evax_section *_bfd_get_evax_section PARAMS ((bfd *abfd, int index)); + +typedef struct _evax_reloc { + struct _evax_reloc *next; + arelent *reloc; + asection *section; +} evax_reloc; + +/* evax module header */ + +struct emh_struc { + int emh_b_strlvl; + long emh_l_arch1; + long emh_l_arch2; + long emh_l_recsiz; + char *emh_t_name; + char *emh_t_version; + char *emh_t_date; + char *emh_c_lnm; + char *emh_c_src; + char *emh_c_ttl; +}; + + +/* evax end of module */ + +struct eeom_struc { + long eeom_l_total_lps; + unsigned char eeom_b_comcod; + boolean eeom_has_transfer; + unsigned char eeom_b_tfrflg; + long eeom_l_psindx; + long eeom_l_tfradr; +}; + +enum file_format_enum { FF_UNKNOWN, FF_FOREIGN, FF_NATIVE }; + +typedef struct evax_symbol_struct { + struct bfd_hash_entry bfd_hash; + asymbol *symbol; +} evax_symbol_entry; + +/* stack value for push/pop commands */ + +struct stack_struct { + uquad value; + int psect; +}; +#define STACKSIZE 50 + +/* location stack definitions for CTL_DFLOC, CTL_STLOC, and CTL_STKDL */ + +struct location_struct { + unsigned long value; + int psect; +}; +#define LOCATION_SAVE_SIZE 32 + +#define EVAX_SECTION_COUNT 32 + +struct evax_private_data_struct { + char *filename; /* Filename of object file */ + boolean fixup_done; /* Flag to indicate if all + section pointers and PRIV(sections) + are set up correctly */ + unsigned char *evax_buf; /* buffer to record */ + int buf_size; /* max size of buffer */ + unsigned char *evax_rec; /* actual record ptr */ + int rec_length; /* remaining record length */ + int rec_size; /* actual record size */ + int rec_type; /* actual record type */ + enum file_format_enum file_format; + + struct emh_struc emh_data; /* data from EMH record */ + struct eeom_struc eeom_data; /* data from EEOM record */ + int egsd_sec_count; /* # of EGSD sections */ + asection **sections; /* vector of EGSD sections */ + int egsd_sym_count; /* # of EGSD symbols */ + asymbol **symbols; /* vector of EGSD symbols */ + struct proc_value *procedure; + + struct stack_struct *stack; + int stackptr; + + evax_section *evax_section_table[EVAX_SECTION_COUNT]; + + struct bfd_hash_table *evax_symbol_table; + struct symbol_cache_entry **symcache; + int symnum; + + struct location_struct *location_stack; + + unsigned char *image_ptr; /* a pointer to section->contents */ + + unsigned char pdsc[8]; /* procedure descriptor */ + + /* Output routine storage */ + + unsigned char *output_buf; /* output data */ + int push_level; + int pushed_size; + int length_pos; + int output_size; + int output_alignment; + + /* linkage index counter + used by conditional store commands (ETIR_S_C_STC_) */ + + int evax_linkage_index; + +}; + +#define PRIV(name) ((struct evax_private_data_struct *)abfd->tdata.any)->name + +#if EVAX_DEBUG +extern void _bfd_evax_debug PARAMS((int level, char *format, ...)); +extern void _bfd_hexdump + PARAMS ((int level, unsigned char *ptr, int size, int offset)); + +#define evax_debug _bfd_evax_debug + +#endif + +extern struct bfd_hash_entry *_bfd_evax_hash_newfunc + PARAMS ((struct bfd_hash_entry *entry, struct bfd_hash_table *table, + const char *string)); +extern void _bfd_evax_get_header_values + PARAMS ((bfd *abfd, unsigned char *buf, int *type, int *length)); +extern int _bfd_evax_get_record PARAMS ((bfd *abfd)); +extern int _bfd_evax_next_record PARAMS ((bfd *abfd)); + +extern char *_bfd_evax_save_sized_string PARAMS ((char *str, int size)); +extern char *_bfd_evax_save_counted_string PARAMS ((char *ptr)); +extern void _bfd_evax_push PARAMS ((bfd *abfd, uquad val, int psect)); +extern uquad _bfd_evax_pop PARAMS ((bfd *abfd, int *psect)); + +extern boolean _bfd_save_evax_section + PARAMS ((bfd *abfd, asection *section, PTR data, file_ptr offset, + bfd_size_type count)); +extern void _bfd_evax_output_begin + PARAMS ((bfd *abfd, int rectype, int rechead)); +extern void _bfd_evax_output_alignment PARAMS ((bfd *abfd, int alignto)); +extern void _bfd_evax_output_push PARAMS ((bfd *abfd)); +extern void _bfd_evax_output_pop PARAMS ((bfd *abfd)); +extern void _bfd_evax_output_flush PARAMS ((bfd *abfd)); +extern void _bfd_evax_output_end PARAMS ((bfd *abfd)); +extern int _bfd_evax_output_check PARAMS ((bfd *abfd, int size)); +extern void _bfd_evax_output_byte PARAMS ((bfd *abfd, unsigned int value)); +extern void _bfd_evax_output_short PARAMS ((bfd *abfd, unsigned int value)); +extern void _bfd_evax_output_long PARAMS ((bfd *abfd, unsigned long value)); +extern void _bfd_evax_output_quad PARAMS ((bfd *abfd, uquad value)); +extern void _bfd_evax_output_counted PARAMS ((bfd *abfd, char *value)); +extern void _bfd_evax_output_dump PARAMS ((bfd *abfd, unsigned char *data, + int length)); +extern void _bfd_evax_output_fill PARAMS ((bfd *abfd, int value, int length)); +extern char *_bfd_get_vms_time_string PARAMS ((void)); +extern char *_bfd_evax_basename PARAMS ((char *name)); + +#endif /* EVAX_H */ diff --git a/gnu/usr.bin/binutils/bfd/hosts/alphavms.h b/gnu/usr.bin/binutils/bfd/hosts/alphavms.h new file mode 100644 index 00000000000..eee391a97fb --- /dev/null +++ b/gnu/usr.bin/binutils/bfd/hosts/alphavms.h @@ -0,0 +1,69 @@ +/* alphavms.h -- BFD definitions for an openVMS host + Copyright 1996 Free Software Foundation, Inc. + Written by Klaus Kämpf (kkaempf@progis.de) + of proGIS Softwareentwicklung, Aachen, Germany + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stddef.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <ctype.h> +#include <string.h> +#include <sys/file.h> +#include <stdlib.h> +#include <unixlib.h> +#include <unixio.h> +#include <time.h> + +#include "bfd.h" + +#ifndef BFD_HOST_64_BIT +/* Make the basic types 64-bit quantities on the host. + Also provide the support macros BFD needs. */ +# ifdef __GNUC__ +# define BFD_HOST_64_BIT long long +# else +# define BFD_HOST_64_BIT long +# endif +typedef unsigned BFD_HOST_64_BIT uint64_type; +typedef BFD_HOST_64_BIT int64_type; + +# define sprintf_vma(s,x) sprintf (s, "%016lx", x) /* BFD_HOST_64_BIT */ +# define fprintf_vma(f,x) fprintf (f, "%016lx", x) /* BFD_HOST_64_BIT */ + +# define BYTES_IN_PRINTF_INT 4 + +/* These must have type unsigned long because they are used as + arguments in printf functions. */ +# define uint64_typeLOW(x) ((unsigned long) (((x) & 0xffffffff))) /* BFD_HOST_64_BIT */ +# define uint64_typeHIGH(x) ((unsigned long) (((x) >> 32) & 0xffffffff)) /* BFD_HOST_64_BIT */ + +#endif /* BFD_HOST_64_BIT */ + +#include "fopen-vms.h" + +#define NO_FCNTL 1 + +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) +#endif + +extern int getpagesize PARAMS ((void)); diff --git a/gnu/usr.bin/binutils/bfd/makefile.vms b/gnu/usr.bin/binutils/bfd/makefile.vms new file mode 100644 index 00000000000..1d131d63379 --- /dev/null +++ b/gnu/usr.bin/binutils/bfd/makefile.vms @@ -0,0 +1,46 @@ +# +# Makefile for bfd library under openVMS/AXP +# +# For use with gnu-make for vms +# +# Created by Klaus Kaempf, kkaempf@progis.de +# +# +CC=gcc + +OBJS=archive.obj,archures.obj,bfd.obj,cache.obj,coffgen.obj,corefile.obj,format.obj,\ + init.obj,libbfd.obj,opncls.obj,reloc.obj,section.obj,syms.obj,targets.obj,\ + hash.obj,linker.obj,elf.obj,srec.obj,binary.obj,tekhex.obj,ihex.obj,stab-syms.obj,\ + evax-alpha.obj,evax-emh.obj,evax-egsd.obj,evax-etir.obj,evax-misc.obj,\ + cpu-alpha.obj + +ifeq ($(CC),gcc) +DEFS=/define=(SELECT_VECS="&evax_alpha_vec",SELECT_ARCHITECTURES="&bfd_alpha_arch","unlink=remove") +CFLAGS=/include=([],[-.include])$(DEFS) +else +DEFS=/define=(DEFAULT_VECTOR="evax_alpha_vec",SELECT_VECS="&evax_alpha_vec",\ +SELECT_ARCHITECTURES="&bfd_alpha_arch","unlink=remove","const=",\ +"_bfd_generic_get_section_contents_in_window"="_bfd_generic_get_win_section_cont",\ +"_bfd_elf_section_from_bfd_section"="_bfd_elf_sec_from_bfd_sec") +CFLAGS=/noopt/debug/include=([],[-.include])$(DEFS)/warnings=disable=(missingreturn,implicitfunc) +endif + + +libbfd.olb: sysdep.h bfd.h $(OBJS) + purge + lib/create libbfd $(OBJS) + +sysdep.h: [.hosts]alphavms.h config.h + $(CP) $< $@ + +bfd.h: bfd.h-vms + $(CP) $< $@ + +config.h: config.h-vms + $(CP) $< $@ + +evax-alpha.c: evax.h +evax-emh.c: evax.h +evax-egsd.c: evax.h +evax-etir.c: evax.h +evax-misc.c: evax.h diff --git a/gnu/usr.bin/binutils/include/fopen-vms.h b/gnu/usr.bin/binutils/include/fopen-vms.h new file mode 100644 index 00000000000..da76b7fb59c --- /dev/null +++ b/gnu/usr.bin/binutils/include/fopen-vms.h @@ -0,0 +1,24 @@ +/* Macros for the 'type' part of an fopen, freopen or fdopen. + + <Read|Write>[Update]<Binary file|text file> + + This version is for VMS systems, where text and binary files are + different. + This file is designed for inclusion by host-dependent .h files. No + user application should include it directly, since that would make + the application unable to be configured for both "same" and "binary" + variant systems. */ + +#define FOPEN_RB "rb","rfm=var" +#define FOPEN_WB "wb","rfm=var" +#define FOPEN_AB "ab","rfm=var" +#define FOPEN_RUB "r+b","rfm=var" +#define FOPEN_WUB "w+b","rfm=var" +#define FOPEN_AUB "a+b","rfm=var" + +#define FOPEN_RT "r" +#define FOPEN_WT "w" +#define FOPEN_AT "a" +#define FOPEN_RUT "r+" +#define FOPEN_WUT "w+" +#define FOPEN_AUT "a+" diff --git a/gnu/usr.bin/binutils/ld/emulparams/elf32ebmip.sh b/gnu/usr.bin/binutils/ld/emulparams/elf32ebmip.sh new file mode 100644 index 00000000000..3bc284e6d0c --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emulparams/elf32ebmip.sh @@ -0,0 +1,28 @@ +SCRIPT_NAME=elfmips +OUTPUT_FORMAT="elf32-bigmips" +BIG_OUTPUT_FORMAT="elf32-bigmips" +LITTLE_OUTPUT_FORMAT="elf32-littlemips" +TEXT_START_ADDR=0x0400000 +DATA_ADDR=0x10000000 +MAXPAGESIZE=0x40000 +NONPAGED_TEXT_START_ADDR=0x0400000 +SHLIB_TEXT_START_ADDR=0x5ffe0000 +OTHER_READONLY_SECTIONS='.reginfo : { *(.reginfo) }' +OTHER_GOT_SYMBOLS=' + _gp = ALIGN(16) + 0x7ff0; +' +OTHER_READWRITE_SECTIONS=' + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } +' +TEXT_START_SYMBOLS='_ftext = . ;' +DATA_START_SYMBOLS='_fdata = . ;' +OTHER_BSS_SYMBOLS='_fbss = .;' +OTHER_SECTIONS=' + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } +' +ARCH=mips +TEMPLATE_NAME=elf32 +GENERATE_SHLIB_SCRIPT=yes +EMBEDDED=yes diff --git a/gnu/usr.bin/binutils/ld/emulparams/elf32elmip.sh b/gnu/usr.bin/binutils/ld/emulparams/elf32elmip.sh new file mode 100644 index 00000000000..c892dc17cbb --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emulparams/elf32elmip.sh @@ -0,0 +1,28 @@ +SCRIPT_NAME=elfmips +OUTPUT_FORMAT="elf32-littlemips" +BIG_OUTPUT_FORMAT="elf32-bigmips" +LITTLE_OUTPUT_FORMAT="elf32-littlemips" +TEXT_START_ADDR=0x0400000 +DATA_ADDR=0x10000000 +MAXPAGESIZE=0x40000 +NONPAGED_TEXT_START_ADDR=0x0400000 +SHLIB_TEXT_START_ADDR=0x5ffe0000 +OTHER_READONLY_SECTIONS='.reginfo : { *(.reginfo) }' +OTHER_GOT_SYMBOLS=' + _gp = ALIGN(16) + 0x7ff0; +' +OTHER_READWRITE_SECTIONS=' + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } +' +TEXT_START_SYMBOLS='_ftext = . ;' +DATA_START_SYMBOLS='_fdata = . ;' +OTHER_BSS_SYMBOLS='_fbss = .;' +OTHER_SECTIONS=' + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } +' +ARCH=mips +TEMPLATE_NAME=elf32 +GENERATE_SHLIB_SCRIPT=yes +EMBEDDED=yes diff --git a/gnu/usr.bin/binutils/ld/emulparams/elf64alpha.sh b/gnu/usr.bin/binutils/ld/emulparams/elf64alpha.sh new file mode 100644 index 00000000000..ca2d230ebdd --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emulparams/elf64alpha.sh @@ -0,0 +1,14 @@ +ENTRY=__start +SCRIPT_NAME=elf +ELFSIZE=64 +TEMPLATE_NAME=elf32 +OUTPUT_FORMAT="elf64-alpha" +TEXT_START_ADDR="0x120000000" +MAXPAGESIZE=0x100000 +NONPAGED_TEXT_START_ADDR="0x120000000" +ARCH=alpha +GENERATE_SHLIB_SCRIPT=yes +DATA_PLT= +NOP=0x47ff041f + +OTHER_READONLY_SECTIONS='.reginfo : { *(.reginfo) }' diff --git a/gnu/usr.bin/binutils/ld/emulparams/h8300s.sh b/gnu/usr.bin/binutils/ld/emulparams/h8300s.sh new file mode 100644 index 00000000000..e27b4f523f1 --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emulparams/h8300s.sh @@ -0,0 +1,5 @@ +SCRIPT_NAME=h8300s +OUTPUT_FORMAT="coff-h8300" +TEXT_START_ADDR=0x8000 +TARGET_PAGE_SIZE=128 +ARCH=h8300 diff --git a/gnu/usr.bin/binutils/ld/emulparams/pc532macha.sh b/gnu/usr.bin/binutils/ld/emulparams/pc532macha.sh new file mode 100644 index 00000000000..9c1d0791c8d --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emulparams/pc532macha.sh @@ -0,0 +1,6 @@ +SCRIPT_NAME=aout +OUTPUT_FORMAT="a.out-pc532-mach" +TARGET_PAGE_SIZE=0x1000 +TEXT_START_ADDR="0x10020" +NONPAGED_TEXT_START_ADDR=0x10000 +ARCH=ns32k diff --git a/gnu/usr.bin/binutils/ld/emulparams/shelf.sh b/gnu/usr.bin/binutils/ld/emulparams/shelf.sh new file mode 100644 index 00000000000..a392e933c42 --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emulparams/shelf.sh @@ -0,0 +1,16 @@ +SCRIPT_NAME=elf +OUTPUT_FORMAT="elf32-sh" +TEXT_START_ADDR=0x1000 +MAXPAGESIZE=128 +ARCH=sh +TEMPLATE_NAME=elf32 +GENERATE_SHLIB_SCRIPT=yes +EMBEDDED=yes + +# These are for compatibility with the COFF toolchain. +ENTRY=start +CTOR_START='___ctors = .;' +CTOR_END='___ctors_end = .;' +DTOR_START='___dtors = .;' +DTOR_END='___dtors_end = .;' +OTHER_RELOCATING_SECTIONS='.stack 0x30000 : { _stack = .; *(.stack) }' diff --git a/gnu/usr.bin/binutils/ld/emulparams/shlelf.sh b/gnu/usr.bin/binutils/ld/emulparams/shlelf.sh new file mode 100644 index 00000000000..93777f63de3 --- /dev/null +++ b/gnu/usr.bin/binutils/ld/emulparams/shlelf.sh @@ -0,0 +1,16 @@ +SCRIPT_NAME=elf +OUTPUT_FORMAT="elf32-shl" +TEXT_START_ADDR=0x1000 +MAXPAGESIZE=128 +ARCH=sh +TEMPLATE_NAME=elf32 +GENERATE_SHLIB_SCRIPT=yes +EMBEDDED=yes + +# These are for compatibility with the COFF toolchain. +ENTRY=start +CTOR_START='___ctors = .;' +CTOR_END='___ctors_end = .;' +DTOR_START='___dtors = .;' +DTOR_END='___dtors_end = .;' +OTHER_RELOCATING_SECTIONS='.stack 0x30000 : { _stack = .; *(.stack) }' diff --git a/gnu/usr.bin/binutils/ld/fnmatch.c b/gnu/usr.bin/binutils/ld/fnmatch.c new file mode 100644 index 00000000000..998c0c4582f --- /dev/null +++ b/gnu/usr.bin/binutils/ld/fnmatch.c @@ -0,0 +1,217 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@prep.ai.mit.edu. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Modified for GNU ld to include sysdep.h. */ +#include "sysdep.h" + +#ifdef HAVE_CONFIG_H +#if defined (CONFIG_BROKETS) +/* We use <config.h> instead of "config.h" so that a compilation + using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h + (which it would do because it found this file in $srcdir). */ +#include <config.h> +#else +#include "config.h" +#endif +#endif + + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <errno.h> +#include <fnmatch.h> +#include <ctype.h> + + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) +extern int errno; +#endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, nonzero if not. */ +int +fnmatch (pattern, string, flags) + const char *pattern; + const char *string; + int flags; +{ + register const char *p = pattern, *n = string; + register char c; + +/* Note that this evalutes C many times. */ +#define FOLD(c) ((flags & FNM_CASEFOLD) && isupper (c) ? tolower (c) : (c)) + + while ((c = *p++) != '\0') + { + c = FOLD (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if ((flags & FNM_FILE_NAME) && *n == '/') + return FNM_NOMATCH; + else if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + c = FOLD (c); + } + if (FOLD (*n) != c) + return FNM_NOMATCH; + break; + + case '*': + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) + if (((flags & FNM_FILE_NAME) && *n == '/') || + (c == '?' && *n == '\0')) + return FNM_NOMATCH; + + if (c == '\0') + return 0; + + { + char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; + c1 = FOLD (c1); + for (--p; *n != '\0'; ++n) + if ((c == '[' || FOLD (*n) == c1) && + fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + return 0; + return FNM_NOMATCH; + } + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + register int not; + + if (*n == '\0') + return FNM_NOMATCH; + + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + not = (*p == '!' || *p == '^'); + if (not) + ++p; + + c = *p++; + for (;;) + { + register char cstart = c, cend = c; + + if (!(flags & FNM_NOESCAPE) && c == '\\') + cstart = cend = *p++; + + cstart = cend = FOLD (cstart); + + if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + c = FOLD (c); + + if ((flags & FNM_FILE_NAME) && c == '/') + /* [/] can never match. */ + return FNM_NOMATCH; + + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + cend = FOLD (cend); + + c = *p++; + } + + if (FOLD (*n) >= cstart && FOLD (*n) <= cend) + goto matched; + + if (c == ']') + break; + } + if (!not) + return FNM_NOMATCH; + break; + + matched:; + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + if (not) + return FNM_NOMATCH; + } + break; + + default: + if (c != FOLD (*n)) + return FNM_NOMATCH; + } + + ++n; + } + + if (*n == '\0') + return 0; + + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return FNM_NOMATCH; +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/gnu/usr.bin/binutils/ld/fnmatch.h b/gnu/usr.bin/binutils/ld/fnmatch.h new file mode 100644 index 00000000000..1a653ab6314 --- /dev/null +++ b/gnu/usr.bin/binutils/ld/fnmatch.h @@ -0,0 +1,69 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@prep.ai.mit.edu. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _FNMATCH_H + +#define _FNMATCH_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#undef __P +#define __P(args) args +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(args) () +/* We can get away without defining `const' here only because in this file + it is used only inside the prototype for `fnmatch', which is elided in + non-ANSI C where `const' is problematical. */ +#endif /* C++ or ANSI C. */ + + +/* We #undef these before defining them because some losing systems + (HP-UX A.08.07 for example) define these in <unistd.h>. */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ + +#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE) +#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#define FNM_NOMATCH 1 + +/* Match STRING against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch __P ((const char *__pattern, const char *__string, + int __flags)); + +#ifdef __cplusplus +} +#endif + +#endif /* fnmatch.h */ diff --git a/gnu/usr.bin/binutils/ld/scripttempl/h8300s.sc b/gnu/usr.bin/binutils/ld/scripttempl/h8300s.sc new file mode 100644 index 00000000000..b43abdf55d9 --- /dev/null +++ b/gnu/usr.bin/binutils/ld/scripttempl/h8300s.sc @@ -0,0 +1,76 @@ +cat <<EOF +OUTPUT_FORMAT("${OUTPUT_FORMAT}") +OUTPUT_ARCH(h8300s) +ENTRY("_start") + +/* The memory size is 256KB to coincide with the simulator. + Don't change either without considering the other. */ + +MEMORY +{ + /* 0xc4 is a magic entry. We should have the linker just + skip over it one day... */ + vectors : o = 0x0000, l = 0xc4 + magicvectors : o = 0xc4, l = 0x3c + /* We still only use 256k as the main ram size. */ + ram : o = 0x0100, l = 0x3fefc + /* The stack starts at the top of main ram. */ + topram : o = 0x3fffc, l = 0x4 + /* This holds variables in the "tiny" sections. */ + tiny : o = 0xff8000, l = 7f00 + /* At the very top of the address space is the 8-bit area. */ + eight : o = 0xffff00, l = 0x100 +} + +SECTIONS +{ +.vectors : { + /* Use something like this to place a specific function's address + into the vector table. + + LONG(ABSOLUTE(_foobar)) */ + + *(.vectors) + } ${RELOCATING+ > vectors} +.text : { + *(.rodata) + *(.text) + *(.strings) + ${RELOCATING+ _etext = . ; } + } ${RELOCATING+ > ram} +.tors : { + ___ctors = . ; + *(.ctors) + ___ctors_end = . ; + ___dtors = . ; + *(.dtors) + ___dtors_end = . ; + } ${RELOCATING+ > ram} +.data : { + *(.data) + ${RELOCATING+ _edata = . ; } + } ${RELOCATING+ > ram} +.bss : { + ${RELOCATING+ _bss_start = . ;} + *(.bss) + *(COMMON) + ${RELOCATING+ _end = . ; } + } ${RELOCATING+ >ram} +.stack : { + ${RELOCATING+ _stack = . ; } + *(.stack) + } ${RELOCATING+ > topram} +.tiny : { + *(.tiny) + } ${RELOCATING+ > tiny} +.eight : { + *(.eight) + } ${RELOCATING+ > eight} +.stab 0 ${RELOCATING+(NOLOAD)} : { + [ .stab ] + } +.stabstr 0 ${RELOCATING+(NOLOAD)} : { + [ .stabstr ] + } +} +EOF diff --git a/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross1.c b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross1.c new file mode 100644 index 00000000000..56789452a5b --- /dev/null +++ b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross1.c @@ -0,0 +1,6 @@ +extern int foo (); +int +func () +{ + return foo (); +} diff --git a/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross1.t b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross1.t new file mode 100644 index 00000000000..e1948c9e09f --- /dev/null +++ b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross1.t @@ -0,0 +1,6 @@ +NOCROSSREFS ( .text .data ) +SECTIONS +{ + .text : { tmpdir/cross1.o } + .data : { tmpdir/cross2.o } +} diff --git a/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross2.c b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross2.c new file mode 100644 index 00000000000..414317712d1 --- /dev/null +++ b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross2.c @@ -0,0 +1,5 @@ +int +foo () +{ + return 1; +} diff --git a/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross2.t b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross2.t new file mode 100644 index 00000000000..cf046f6c36b --- /dev/null +++ b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross2.t @@ -0,0 +1,6 @@ +NOCROSSREFS ( .text .data ) +SECTIONS +{ + .text : { *(.text) *(.pr) } + .data : { *(.data) *(.sdata) *(.rw) *(.tc0) *(.tc) } +} diff --git a/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross3.c b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross3.c new file mode 100644 index 00000000000..1848c32fd0b --- /dev/null +++ b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/cross3.c @@ -0,0 +1,7 @@ +int i = 4; + +int +foo () +{ + return i; +} diff --git a/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/crossref.exp b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/crossref.exp new file mode 100644 index 00000000000..04bb16ff61c --- /dev/null +++ b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/crossref.exp @@ -0,0 +1,72 @@ +# Test NOCROSSREFS in a linker script. +# By Ian Lance Taylor, Cygnus Support. + +set test1 "NOCROSSREFS 1" +set test2 "NOCROSSREFS 2" + +if { [which $CC] == 0 } { + untested $test1 + untested $test2 + return +} + +if { ![ld_compile $CC "$srcdir/$subdir/cross1.c" tmpdir/cross1.o] \ + || ![ld_compile $CC "$srcdir/$subdir/cross2.c" tmpdir/cross2.o] } { + unresolved $test1 + unresolved $test2 + return +} + +set flags "" + +# The a29k compiled code calls V_SPILL and V_FILL. Since we don't +# need to run this code, but we don't have definitions for those +# functions, we just define them out. +if [istarget a29k*-*-*] { + set flags "$flags --defsym V_SPILL=0 --defsym V_FILL=0" +} + +verbose -log "$ld $flags -o tmpdir/cross1 -T $srcdir/$subdir/cross1.t tmpdir/cross1.o tmpdir/cross2.o" + +catch "exec $ld $flags -o tmpdir/cross1 -T $srcdir/$subdir/cross1.t tmpdir/cross1.o tmpdir/cross2.o" exec_output + +set exec_output [prune_system_crud $host_triplet $exec_output] + +regsub -all "(^|\n)($ld: warning: cannot find entry symbol\[^\n\]*\n?)" $exec_output "\\1" exec_output + +if [string match "" $exec_output] then { + fail $test1 +} else { + verbose -log "$exec_output" + if [regexp "prohibited cross reference from .* to `foo' in" $exec_output] { + pass $test1 + } else { + fail $test1 + } +} + +# Check cross references within a single object. + +if { ![ld_compile $CC "$srcdir/$subdir/cross3.c" tmpdir/cross3.o] } { + unresolved $test2 + return +} + +verbose -log "$ld $flags -o tmpdir/cross2 -T $srcdir/$subdir/cross2.t tmpdir/cross3.o" + +catch "exec $ld $flags -o tmpdir/cross2 -T $srcdir/$subdir/cross2.t tmpdir/cross3.o" exec_output + +set exec_output [prune_system_crud $host_triplet $exec_output] + +regsub -all "(^|\n)($ld: warning: cannot find entry symbol\[^\n\]*\n?)" $exec_output "\\1" exec_output + +if [string match "" $exec_output] then { + fail $test2 +} else { + verbose -log "$exec_output" + if [regexp "prohibited cross reference from .* to `.*' in" $exec_output] { + pass $test2 + } else { + fail $test2 + } +} diff --git a/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/phdrs.exp b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/phdrs.exp new file mode 100644 index 00000000000..3271252701c --- /dev/null +++ b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/phdrs.exp @@ -0,0 +1,50 @@ +# Test PHDRS in a linker script. +# By Ian Lance Taylor, Cygnus Support. + +# PHDRS is only meaningful for ELF. +if { ![istarget *-*-sysv4*] \ + && ![istarget *-*-unixware*] \ + && ![istarget *-*-elf*] \ + && ![istarget *-*-linux*] \ + && ![istarget *-*-irix5*] \ + && ![istarget *-*-irix6*] \ + && ![istarget *-*-solaris2*] } { + return +} + +if { [istarget *-*-linuxaout*] \ + || [istarget *-*-linuxoldld*] } { + return +} + +# This is a very simplistic test. + +set testname "PHDRS" + +if ![ld_assemble $as $srcdir/$subdir/phdrs.s tmpdir/phdrs.o] { + unresolved $testname + return +} + +set phdrs_regexp \ +".*Program Header:.*PHDR *off *0x00*34 *vaddr *0x00*80034 *paddr *0x00*80034.*filesz *0x0\[0-9a-f\]* *memsz *0x0\[0-9a-f\]* flags r--.*LOAD *off *0x00* *vaddr *0x00*80000 *paddr *0x00*80000.*filesz *0x00*\[0-9a-f\]* *memsz *0x0\[0-9a-f\]* *flags r-x.*LOAD *off *0x0\[0-9a-f\]* *vaddr *0x00*80*\[0-9a-f\]* *paddr *0x00*80*\[0-9a-f\]*.*filesz *0x0\[0-9a-f\]* *memsz *0x0\[0-9a-f\]* *flags *rw-.*" + +if ![ld_simple_link $ld tmpdir/phdrs "-T $srcdir/$subdir/phdrs.t tmpdir/phdrs.o"] { + fail $testname +} else { + if {[which $objdump] == 0} { + unresolved $testname + return + } + + verbose -log "$objdump --private tmpdir/phdrs" + catch "exec $objdump --private tmpdir/phdrs" exec_output + set exec_output [prune_system_crud $host_triplet $exec_output] + verbose -log $exec_output + + if [regexp $phdrs_regexp $exec_output] { + pass $testname + } else { + fail $testname + } +} diff --git a/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/phdrs.s b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/phdrs.s new file mode 100644 index 00000000000..ec1f0d17e6e --- /dev/null +++ b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/phdrs.s @@ -0,0 +1,8 @@ + .text + + .long 1 + + .data + + .long 2 + diff --git a/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/phdrs.t b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/phdrs.t new file mode 100644 index 00000000000..8f710e23fdc --- /dev/null +++ b/gnu/usr.bin/binutils/ld/testsuite/ld-scripts/phdrs.t @@ -0,0 +1,14 @@ +PHDRS +{ + header PT_PHDR PHDRS ; + text PT_LOAD FILEHDR PHDRS ; + data PT_LOAD ; +} + +SECTIONS +{ + . = 0x80000 + SIZEOF_HEADERS; + .text : { *(.text) } :text + .data : { *(.data) } :data + /DISCARD/ : { *(.reginfo) } +} diff --git a/gnu/usr.bin/binutils/libiberty/config.h-vms b/gnu/usr.bin/binutils/libiberty/config.h-vms new file mode 100644 index 00000000000..ccac6a2bcc7 --- /dev/null +++ b/gnu/usr.bin/binutils/libiberty/config.h-vms @@ -0,0 +1,13 @@ +#ifndef NEED_strerror +#define NEED_strerror +#endif +#ifndef NEED_basename +#define NEED_basename +#endif +#ifndef NEED_psignal +#define NEED_psignal +#endif +#ifndef NEED_on_exit +#define NEED_on_exit +#endif + diff --git a/gnu/usr.bin/binutils/libiberty/makefile.vms b/gnu/usr.bin/binutils/libiberty/makefile.vms new file mode 100644 index 00000000000..5f908e85056 --- /dev/null +++ b/gnu/usr.bin/binutils/libiberty/makefile.vms @@ -0,0 +1,31 @@ +# +# Makefile for libiberty under openVMS/AXP +# +# For use with gnu-make for vms +# +# Created by Klaus Kämpf, kkaempf@progis.de +# +# +CC=gcc + +OBJS=bcopy.obj,bcmp.obj,getopt.obj,obstack.obj,xexit.obj,xmalloc.obj,hex.obj,\ + getopt1.obj,cplus-dem.obj,strncasecmp.obj,strcasecmp.obj,strdup.obj,\ + concat.obj,getruntime.obj,getpagesize.obj,alloca.obj,xstrerror.obj,\ + xstrdup.obj,xatexit.obj + +ifeq ($(CC),gcc) +CFLAGS=/include=([],[-.include]) +else +CFLAGS=/noopt/debug/include=([],[-.include])/define=("const=")/warnings=disable=(missingreturn,implicitfunc) +endif + +libiberty.olb: config.h alloca-conf.h $(OBJS) + purge + lib/create libiberty *.obj + +alloca-conf.h: alloca-norm.h + $(CP) $< $@ + +config.h: config.h-vms + $(CP) $< $@ + diff --git a/gnu/usr.bin/binutils/libiberty/pexecute.c b/gnu/usr.bin/binutils/libiberty/pexecute.c new file mode 100644 index 00000000000..7ffe9caead5 --- /dev/null +++ b/gnu/usr.bin/binutils/libiberty/pexecute.c @@ -0,0 +1,573 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. + Copyright (C) 1996 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* This file exports two functions: pexecute and pwait. */ + +/* This file lives in at least two places: libiberty and gcc. + Don't change one without the other. */ + +#include <stdio.h> +#include <errno.h> + +#ifdef IN_GCC +#include "config.h" +#include "gansidecl.h" +/* ??? Need to find a suitable header file. */ +#define PEXECUTE_FIRST 1 +#define PEXECUTE_LAST 2 +#define PEXECUTE_ONE (PEXECUTE_FIRST + PEXECUTE_LAST) +#define PEXECUTE_SEARCH 4 +#define PEXECUTE_VERBOSE 8 +#else +#include "libiberty.h" +#endif + +/* stdin file number. */ +#define STDIN_FILE_NO 0 + +/* stdout file number. */ +#define STDOUT_FILE_NO 1 + +/* value of `pipe': port index for reading. */ +#define READ_PORT 0 + +/* value of `pipe': port index for writing. */ +#define WRITE_PORT 1 + +static char *install_error_msg = "installation problem, cannot exec `%s'"; + +/* pexecute: execute a program. + + PROGRAM and ARGV are the arguments to execv/execvp. + + THIS_PNAME is name of the calling program (i.e. argv[0]). + + TEMP_BASE is the path name, sans suffix, of a temporary file to use + if needed. This is currently only needed for MSDOS ports that don't use + GO32 (do any still exist?). Ports that don't need it can pass NULL. + + (FLAGS & PEXECUTE_SEARCH) is non-zero if $PATH should be searched + (??? It's not clear that GCC passes this flag correctly). + (FLAGS & PEXECUTE_FIRST) is nonzero for the first process in chain. + (FLAGS & PEXECUTE_FIRST) is nonzero for the last process in chain. + FIRST_LAST could be simplified to only mark the last of a chain of processes + but that requires the caller to always mark the last one (and not give up + early if some error occurs). It's more robust to require the caller to + mark both ends of the chain. + + The result is the pid on systems like Unix where we fork/exec and on systems + like WIN32 and OS2 where we use spawn. It is up to the caller to wait for + the child. + + The result is the WEXITSTATUS on systems like MSDOS where we spawn and wait + for the child here. + + Upon failure, ERRMSG_FMT and ERRMSG_ARG are set to the text of the error + message with an optional argument (if not needed, ERRMSG_ARG is set to + NULL), and -1 is returned. `errno' is available to the caller to use. + + pwait: cover function for wait. + + PID is the process id of the task to wait for. + STATUS is the `status' argument to wait. + FLAGS is currently unused (allows future enhancement without breaking + upward compatibility). Pass 0 for now. + + The result is the pid of the child reaped, + or -1 for failure (errno says why). + + On systems that don't support waiting for a particular child, PID is + ignored. On systems like MSDOS that don't really multitask pwait + is just a mechanism to provide a consistent interface for the caller. + + pfinish: finish generation of script + + pfinish is necessary for systems like MPW where a script is generated that + runs the requested programs. +*/ + +#ifdef __MSDOS__ + +/* MSDOS doesn't multitask, but for the sake of a consistent interface + the code behaves like it does. pexecute runs the program, tucks the + exit code away, and returns a "pid". pwait must be called to fetch the + exit code. */ + +#include <process.h> + +/* For communicating information from pexecute to pwait. */ +static int last_pid = 0; +static int last_status = 0; +static int last_reaped = 0; + +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + int rc; + + last_pid++; + if (last_pid < 0) + last_pid = 1; + + if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE) + abort (); + +#ifdef __GO32__ + /* ??? What are the possible return values from spawnv? */ + rc = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (1, program, argv); +#else + char *scmd, *rf; + FILE *argfile; + int i, el = flags & PEXECUTE_SEARCH ? 4 : 0; + + scmd = (char *) xmalloc (strlen (program) + strlen (temp_base) + 6 + el); + rf = scmd + strlen(program) + 2 + el; + sprintf (scmd, "%s%s @%s.gp", program, + (flags & PEXECUTE_SEARCH ? ".exe" : ""), temp_base); + argfile = fopen (rf, "w"); + if (argfile == 0) + { + int errno_save = errno; + free (scmd); + errno = errno_save; + *errmsg_fmt = "cannot open `%s.gp'"; + *errmsg_arg = temp_base; + return -1; + } + + for (i=1; argv[i]; i++) + { + char *cp; + for (cp = argv[i]; *cp; cp++) + { + if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp)) + fputc ('\\', argfile); + fputc (*cp, argfile); + } + fputc ('\n', argfile); + } + fclose (argfile); + + rc = system (scmd); + + { + int errno_save = errno; + remove (rf); + free (scmd); + errno = errno_save; + } +#endif + + if (rc == -1) + { + *errmsg_fmt = install_error_msg; + *errmsg_arg = program; + return -1; + } + + /* Tuck the status away for pwait, and return a "pid". */ + last_status = rc << 8; + return last_pid; +} + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags; +{ + /* On MSDOS each pexecute must be followed by it's associated pwait. */ + if (pid != last_pid + /* Called twice for the same child? */ + || pid == last_reaped) + { + /* ??? ECHILD would be a better choice. Can we use it here? */ + errno = EINVAL; + return -1; + } + /* ??? Here's an opportunity to canonicalize the values in STATUS. + Needed? */ + *status = last_status; + last_reaped = last_pid; + return last_pid; +} + +#endif /* MSDOS */ + +#if defined (_WIN32) && !defined (__CYGWIN32__) + +#include <process.h> +/* ??? Why are these __spawnv{,p} and not _spawnv{,p}? */ +extern int __spawnv (); +extern int __spawnvp (); + +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + int pid; + + if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE) + abort (); + pid = (flags & PEXECUTE_SEARCH ? __spawnvp : __spawnv) (_P_NOWAIT, program, argv); + if (pid == -1) + { + *errmsg_fmt = install_error_msg; + *errmsg_arg = program; + return -1; + } + return pid; +} + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags; +{ + /* ??? Here's an opportunity to canonicalize the values in STATUS. + Needed? */ + int pid = cwait (status, pid, WAIT_CHILD); + return pid; +} + +#endif /* WIN32 */ + +#ifdef OS2 + +/* ??? Does OS2 have process.h? */ +extern int spawnv (); +extern int spawnvp (); + +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + int pid; + + if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE) + abort (); + /* ??? Presumably 1 == _P_NOWAIT. */ + pid = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (1, program, argv); + if (pid == -1) + { + *errmsg_fmt = install_error_msg; + *errmsg_arg = program; + return -1; + } + return pid; +} + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags; +{ + /* ??? Here's an opportunity to canonicalize the values in STATUS. + Needed? */ + int pid = wait (status); + return pid; +} + +#endif /* OS2 */ + +#ifdef MPW + +/* MPW pexecute doesn't actually run anything; instead, it writes out + script commands that, when run, will do the actual executing. + + For example, in GCC's case, GCC will write out several script commands: + + cpp ... + cc1 ... + as ... + ld ... + + and then exit. None of the above programs will have run yet. The task + that called GCC will then execute the script and cause cpp,etc. to run. + The caller must invoke pfinish before calling exit. This adds + the finishing touches to the generated script. */ + +static int first_time = 1; + +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char **argv; + const char *this_pname; + const char *temp_base; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + char tmpprogram[255]; + char *cp, *tmpname; + int i; + + mpwify_filename (program, tmpprogram); + if (first_time) + { + printf ("Set Failed 0\n"); + first_time = 0; + } + + fputs ("If {Failed} == 0\n", stdout); + /* If being verbose, output a copy of the command. It should be + accurate enough and escaped enough to be "clickable". */ + if (flags & PEXECUTE_VERBOSE) + { + fputs ("\tEcho ", stdout); + fputc ('\'', stdout); + fputs (tmpprogram, stdout); + fputc ('\'', stdout); + fputc (' ', stdout); + for (i=1; argv[i]; i++) + { + /* We have to quote every arg, so that when the echo is + executed, the quotes are stripped and the original arg + is left. */ + fputc ('\'', stdout); + for (cp = argv[i]; *cp; cp++) + { + /* Write an Option-d esc char in front of special chars. */ + if (strchr ("\"'+", *cp)) + fputc ('\266', stdout); + fputc (*cp, stdout); + } + fputc ('\'', stdout); + fputc (' ', stdout); + } + fputs ("\n", stdout); + } + fputs ("\t", stdout); + fputs (tmpprogram, stdout); + fputc (' ', stdout); + + for (i=1; argv[i]; i++) + { + if (strchr (argv[i], ' ')) + fputc ('\'', stdout); + for (cp = argv[i]; *cp; cp++) + { + /* Write an Option-d esc char in front of special chars. */ + if (strchr ("\"'+", *cp)) + { + fputc ('\266', stdout); + } + fputc (*cp, stdout); + } + if (strchr (argv[i], ' ')) + fputc ('\'', stdout); + fputc (' ', stdout); + } + + fputs ("\n", stdout); + + /* Output commands that arrange to clean up and exit if a failure occurs. + We have to be careful to collect the status from the program that was + run, rather than some other script command. Also, we don't exit + immediately, since necessary cleanups are at the end of the script. */ + fputs ("\tSet TmpStatus {Status}\n", stdout); + fputs ("\tIf {TmpStatus} != 0\n", stdout); + fputs ("\t\tSet Failed {TmpStatus}\n", stdout); + fputs ("\tEnd\n", stdout); + fputs ("End\n", stdout); + + /* We're just composing a script, can't fail here. */ + return 0; +} + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags; +{ + *status = 0; + return 0; +} + +/* Write out commands that will exit with the correct error code + if something in the script failed. */ + +void +pfinish () +{ + printf ("\tExit \"{Failed}\"\n"); +} + +#endif /* MPW */ + +/* include for Unix-like environments but not for Dos-like environments */ +#if ! defined (__MSDOS__) && ! defined (OS2) && ! defined (MPW) \ + && (defined (__CYGWIN32__) || ! defined (_WIN32)) + +#ifdef USG +#define vfork fork +#endif + +extern int execv (); +extern int execvp (); + +int +pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) + const char *program; + char * const *argv; + const char *this_pname; + const char *temp_base; + char **errmsg_fmt, **errmsg_arg; + int flags; +{ + int (*func)() = (flags & PEXECUTE_SEARCH ? execvp : execv); + int pid; + int pdes[2]; + int input_desc, output_desc; + int retries, sleep_interval; + /* Pipe waiting from last process, to be used as input for the next one. + Value is STDIN_FILE_NO if no pipe is waiting + (i.e. the next command is the first of a group). */ + static int last_pipe_input; + + /* If this is the first process, initialize. */ + if (flags & PEXECUTE_FIRST) + last_pipe_input = STDIN_FILE_NO; + + input_desc = last_pipe_input; + + /* If this isn't the last process, make a pipe for its output, + and record it as waiting to be the input to the next process. */ + if (! (flags & PEXECUTE_LAST)) + { + if (pipe (pdes) < 0) + { + *errmsg_fmt = "pipe"; + *errmsg_arg = NULL; + return -1; + } + output_desc = pdes[WRITE_PORT]; + last_pipe_input = pdes[READ_PORT]; + } + else + { + /* Last process. */ + output_desc = STDOUT_FILE_NO; + last_pipe_input = STDIN_FILE_NO; + } + + /* Fork a subprocess; wait and retry if it fails. */ + sleep_interval = 1; + for (retries = 0; retries < 4; retries++) + { + pid = vfork (); + if (pid >= 0) + break; + sleep (sleep_interval); + sleep_interval *= 2; + } + + switch (pid) + { + case -1: + { +#ifdef vfork + *errmsg_fmt = "fork"; +#else + *errmsg_fmt = "vfork"; +#endif + *errmsg_arg = NULL; + return -1; + } + + case 0: /* child */ + /* Move the input and output pipes into place, if necessary. */ + if (input_desc != STDIN_FILE_NO) + { + close (STDIN_FILE_NO); + dup (input_desc); + close (input_desc); + } + if (output_desc != STDOUT_FILE_NO) + { + close (STDOUT_FILE_NO); + dup (output_desc); + close (output_desc); + } + + /* Close the parent's descs that aren't wanted here. */ + if (last_pipe_input != STDIN_FILE_NO) + close (last_pipe_input); + + /* Exec the program. */ + (*func) (program, argv); + + /* Note: Calling fprintf and exit here doesn't seem right for vfork. */ + fprintf (stderr, "%s: ", this_pname); + fprintf (stderr, install_error_msg, program); +#ifdef IN_GCC + fprintf (stderr, ": %s\n", my_strerror (errno)); +#else + fprintf (stderr, ": %s\n", xstrerror (errno)); +#endif + exit (-1); + /* NOTREACHED */ + return 0; + + default: + /* In the parent, after forking. + Close the descriptors that we made for this child. */ + if (input_desc != STDIN_FILE_NO) + close (input_desc); + if (output_desc != STDOUT_FILE_NO) + close (output_desc); + + /* Return child's process number. */ + return pid; + } +} + +int +pwait (pid, status, flags) + int pid; + int *status; + int flags; +{ + /* ??? Here's an opportunity to canonicalize the values in STATUS. + Needed? */ + pid = wait (status); + return pid; +} + +#endif /* ! __MSDOS__ && ! OS2 && ! MPW && (__CYGWIN32___ || ! _WIN32) */ |