2009-02-23 Tristan Gingold <gingold@adacore.com>
authorTristan Gingold <gingold@adacore.com>
Mon, 23 Feb 2009 09:28:43 +0000 (09:28 +0000)
committerTristan Gingold <gingold@adacore.com>
Mon, 23 Feb 2009 09:28:43 +0000 (09:28 +0000)
* vms.h: Update copyright year, fix comments, reorder declarations.
(_bfd_save_vms_section): Remove the prototype.
(EGPS_S_V_NO_SHIFT): New constant.
(bfd_vms_set_section_flags): New prototype.
(EGPS_S_B_ALIGN, EGPS_S_W_FLAGS, EGPS_S_L_ALLOC, EGPS_S_B_NAMLNG): New
constants.
(EGSY_S_W_FLAGS): Ditto.
(EGSY_S_V_QUAD_VAL): Ditto.
(ESDF_S_L_VALUE, ESDF_S_L_PSINDX, ESDF_S_B_NAMLNG): Ditto.
(EGST_S_W_FLAGS, EGST_S_Q_LP_1, EGST_S_Q_LP_2, EGST_S_L_PSINDX,
EGST_S_B_NAMLNG): Ditto.
(ESRF_S_B_NAMLNG): Ditto.
(ETIR_S_C_HEADER_SIZE): Ditto.
(EGPS_S_V_ALLOC_64BIT): Ditto.
(DST_S_C_EPILOG): Ditto.
(DST_S_C_SRC_SETLNUM_L, DST_S_C_SRC_SETLNUM_W) : Ditto.
(DST_S_C_SRC_INCRLNUM_B): Ditto.
(DST_S_B_PCLINE_UNSBYTE, DST_S_W_PCLINE_UNSWORD): Ditto.
(DST_S_L_PCLINE_UNSLONG): Ditto.
(DST_S_B_MODBEG_NAME, DST_S_L_RTNBEG_ADDRESS) : Ditto
(DST_S_B_RTNBEG_NAME, DST_S_L_RTNEND_SIZE): Ditto
(DST_S_C_SOURCE_HEADER_SIZE): Ditto.
(DST_S_B_SRC_DF_LENGTH, DST_S_W_SRC_DF_FILEID): Ditto.
(DST_S_B_SRC_DF_FILENAME, DST_S_B_SRC_UNSBYTE): Ditto.
(DST_S_B_SRC_UNSBYTE): Ditto.
(DST_S_W_SRC_UNSWORD, DST_S_L_SRC_UNSLONG): Ditto.
Add prototypes.
(vms_section, vms_reloc): Remove types.
(hdr_struc): Replaced by ...
(hdr_struct): ... new type.
(EMH_S_W_HDRTYP, EMH_S_B_STRLVL, EMH_S_L_ARCH1): New constants.
(EMH_S_L_ARCH2, EMH_S_L_RECSIZ, EMH_S_B_NAMLNG): Ditto.
(EMH_DATE_LENGTH): Ditto.
(eom_struc): Replaced by ...
(eom_struct): ... new type.
(EEOM_S_L_TOTAL_LPS, EEOM_S_W_COMCOD, EEOM_S_B_TFRFLG): New constants.
(EEOM_S_L_PSINDX, EEOM_S_L_TFRADR): Ditto.
(EIHD_S_K_MAJORID, EIHD_S_K_MINORID, EIHD_S_K_EXE): Ditto.
(EIHD_S_L_SIZE, EIHD_S_L_ISDOFF, EIHD_S_L_SYMDBGOFF): Ditto.
(EIHD_S_Q_SYMVVA, EIHD_S_L_IMGTYPE): Ditto.
(EISD_S_L_EISDSIZE, EISD_S_L_SECSIZE, EISD_S_Q_VIR_ADDR): Ditto.
(EISD_S_L_FLAGS, EISD_S_L_VBN, EISD_S_R_CONTROL): Ditto.
(EISD_S_L_IDENT, EISD_S_T_GBLNAM): Ditto.
(EISD_S_M_GBL, EISD_S_M_CRF, EISD_S_M_DZRO, EISD_S_M_WRT): Ditto.
(EISD_S_M_INITALCODE, EISD_S_M_BASED, EISD_S_M_FIXUPVEC): Ditto.
(EISD_S_M_RESIDENT, EISD_S_M_VECTOR, EISD_S_M_PROTECT): Ditto.
(EISD_S_M_LASTCLU, EISD_S_M_EXE, EISD_S_M_NONSHRADR): Ditto.
(EISD_S_M_QUAD_LENGTH, EISD_S_M_ALLOC_64BIT): Ditto.
(EIHS_S_L_DSTVBN, EIHS_S_L_DSTSIZE, EIHS_S_L_GSTVBN): Ditto.
(EIHS_S_L_GSTSIZE, EIHS_S_L_DMTVBN, EIHS_S_L_DMTBYTES): Ditto.
(DBG_S_L_DMT_MODBEG, DBG_S_L_DST_SIZE): Ditto.
(DBG_S_W_DMT_PSECT_COUNT, DBG_S_C_DMT_HEADER_SIZE): Ditto.
(DBG_S_L_DMT_PSECT_START, DBG_S_L_DMT_PSECT_LENGTH)
(DBG_S_C_DMT_PSECT_SIZE): Ditto.
(enum file_type_enum): New type.
(struct location_struct): Removed.
(struct fileinfo, struct srecinfo, struct lineinfo): New types.
(struct funcinfo, struct module): Ditto.
(struct vms_private_data_struct): Update fields.
(struct vms_section_data_struct): New type.

* vms.c: Update copyright year, fix comments,
Fix includes for DECC, add prototypes.
(vms_initialize): Use bfd_alloc instead of bfd_zalloc and remove
some initializers.
Use flavour to set is_vax, location_stack is removed.
(struct pair): Declare.
(fill_section_ptr): Initialize variables at declaration.
Add guard to set SECTION_SYM flag, handlde und section.
(vms_fixup_sections): Use struct pair for fill_section_ptr argument.
(_bfd_vms_slurp_object_records): New function, replaces previous
vms_object_p.
(vms_slurp_module): New function.
(vms_slurp_image): Ditto.
(vms_object_p): Complete rewrite.
(vms_mkobject): Use is_vax field to slect architecture.
(free_reloc_stream): New function.
(vms_convert_to_var): Ditto.
(vms_convert_to_var_1): Ditto.
(vms_convert_to_var_unix_filename): Ditto.
(vms_close_and_cleanup): Call free_reloc_stream, convert file to
VAR format on VMS.
(vms_new_section_hook): Set alignment to 0, allocate private data.
(vms_get_section_contents): Load content.
(vms_get_symbol_info): Handle undefined section.
(vms_find_nearest_line): Handle.
(alloc_reloc_stream): New function.
(vms_slurp_reloc_table): Ditto.
(vms_get_reloc_upper_bound): Make it real.
(vms_canonicalize_reloc): Do the real work.
(alpha_howto_table): Add ALPHA_R_NOP, ALPHA_R_BSR, ALPHA_R_LDA,
ALPHA_R_BOH.
(vms_bfd_reloc_type_lookup): Handle NOP, BSR, LDA and BOH.
(vms_set_arch_mach): Check arch.
(vms_set_section_contents): Copy the content after allocation.
(vms_alpha_vec): Update object flags.

* vms-tir.c: Update copyright year, fix comments,
add prototypes for new functions.
(dst_define_location): New function.
(dst_restore_location): New function.
(dst_retrieve_location): New function.
(dst_check_allocation): New function.
(image_dump): Call dst_check_allocation.
(image_write_b): Ditto.
(image_write_w): Ditto.
(image_write_l): Ditto.
(image_write_q): Ditto.
(cmd_name): Handle STA_LW, STA_QW, STO_OFF, STO_IMM, STO_IMMR, STO_LW,
STO_QW, OPR_ADD, CTL_SETRB, STC_LP_PSB, CTL_DFLOC, CTL_STLOC,
CTL_STKDL.
Call error handler instead of abort if name is not known.
(etir_sta): Add quarter_relocs argument and set it.
Fix cast.
(etir_sto): Ditto.
(etir_opr): Ditto, return FALSE in case of error.
(etir_ctl): Add quarter_relocs argument and set it, fix cast.
Fix CTL_DFLOC, CTL_STLOC, CTL_STKDL.
(etir_stc): Add quarter_relocs argument and set it, fix cast.
Fix STC_LP, STC_LP_PSB, STC_GBL and STC_CGA.
Handle STC_LP_PSB, STC_BSR_GBL, STC_LDA_GBL, STC_BOH_GBL.
Move STC_NOP_PS, STC_BSR_PS, STC_LDA_PS, STC_BOH_PS, STC_NBH_PS.
Return FALSE in case of error.
(tir_sta): Change sign of psect.
(tir_ctl): Ditto.
(tir_cmd): Fix cast. Makes tir_table static const.
(etir_cmd): Add quarter_relocs argument, makes etir_table const,
add argument to explain.
(analyze_etir): Initialize maxptr, add quarter_relocs
declaration, move some declarations into inner scopes.
Handle quarter_relocs and STO_IMM.
(_bfd_vms_slurp_tir): Use constant instead of hard-coded values.
(_bfd_vms_slurp_relocs): New function.
(_bfd_vms_decode_relocs): New function.
(sto_imm): Rewritten.
(start_first_etbt_record): New function.
(start_another_etbt_record): Ditto.
(etir_output_check): Ditto.
(defer_reloc_p): Ditto.
(_bfd_vms_write_tir): Remove nextoffset, convert a while-loop to
a for-loop.  Correctly deals with contents, deals with .vmsdebug,
rewritte relocations handling.
(_bfd_vms_write_tbt): Removed.
(_bfd_vms_write_dbg): Ditto.

* vms-misc.c: Update copyright year, Fix comments.
(_bfd_vms_get_header_values): Use 'size' instead of 'length'.
(maybe_adjust_record_pointer_for_object): New function.
(_bfd_vms_get_first_record): New function, replaces ...
(_bfd_vms_get_record): ..  removed.
(_bfd_vms_get_object_record): New function.
(_bfd_vms_get_object_record): New function.
(vms_get_remaining_object_record): New function, replaces ...
(_bfd_vms_get_next_record): ... removed.
(add_new_contents): Removed.
(_bfd_save_vms_section): Removed.
(_bfd_get_vms_section): Removed.
(_bfd_vms_output_flush): Write in VAR format.
(new_symbol): Don't make UND section.

* vms-hdr.c: Update copyright year, update list of record handled.
(_bfd_vms_slurp_hdr): rec_length renamed to rec_size.
(_bfd_vms_write_hdr): Strip vms and unix patches,
add comments, truncate module name at 31 characters,
use constants instead of hard-coded value,
write BFD version instead of a fixed string.
(_bfd_vms_slurp_ihd): New function.
(_bfd_vms_slurp_isd): Ditto.
(_bfd_vms_slurp_ihs): Ditto.
(new_module): Ditto.
(parse_module): Ditto
(build_module_list): Ditto.
(module_find_nearest_line): Ditto.
(_bfd_vms_find_nearest_dst_line): Ditto.
(vms_slurp_debug): Ditto.
(_bfd_vms_slurp_dbg): Ditto.
(_bfd_vms_slurp_tbt): Ditto.
(_bfd_vms_write_dbg): Ditto.
(_bfd_vms_write_tbt): Ditto.

* vms-gsd.c: Update copyright year, update list of records handled.
(EVAX_LITERALS_NAME): New macro.
(evax_section_flags): Add an entry for EVAX_LITERALS_NAME.
(gpsflagdesc, gsyflagdesc): Moved out of _bfd_vms_slurp_gsd.
(register_universal_symbol): New function and prototype.
(_bfd_vms_slurp_gsd): Fix indentations and casts,
improve debug messages,
use constants instead of hard-coded value,
fix missing endianness conversion,
handle global symbol (SYMG).
(bfd_vms_set_section_flags): New function.
(_bfd_vms_write_gsd): Don't write .vmsdebug section,
handle section literals,
fix indentation,
handle section bfd and vms flags,
don't output LIB$INITIALIZE symbol,
fix handling of weak symbols,
fix evax vs vax procedure descriptor,
handle absolute symbols.

* reloc.c (BFD_RELOC_ALPHA_NOP, BFD_RELOC_ALPHA_BSR,
BFD_RELOC_ALPHA_LDA, BFD_RELOC_ALPHA_BOH): New relocations.

* makefile.vms (DEFS): Fix flags for VMS.

* bfdio.c (real_fopen): Handle multiple VMS fopen attributes.

* bfd-in2.h: Regenerated.
* libbfd.h: Regenerated.

12 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/bfdio.c
bfd/libbfd.h
bfd/makefile.vms
bfd/reloc.c
bfd/vms-gsd.c
bfd/vms-hdr.c
bfd/vms-misc.c
bfd/vms-tir.c
bfd/vms.c
bfd/vms.h

index 32ae0d89dc15d62601a88ae2389bfd314af10781..17a23d71db4297ae7f9f432ed00c495fc8d386c4 100644 (file)
@@ -1,3 +1,215 @@
+2009-02-23  Tristan Gingold  <gingold@adacore.com>
+
+       * vms.h: Update copyright year, fix comments, reorder declarations.
+       (_bfd_save_vms_section): Remove the prototype.
+       (EGPS_S_V_NO_SHIFT): New constant.
+       (bfd_vms_set_section_flags): New prototype.
+       (EGPS_S_B_ALIGN, EGPS_S_W_FLAGS, EGPS_S_L_ALLOC, EGPS_S_B_NAMLNG): New
+       constants.
+       (EGSY_S_W_FLAGS): Ditto.
+       (EGSY_S_V_QUAD_VAL): Ditto.
+       (ESDF_S_L_VALUE, ESDF_S_L_PSINDX, ESDF_S_B_NAMLNG): Ditto.
+       (EGST_S_W_FLAGS, EGST_S_Q_LP_1, EGST_S_Q_LP_2, EGST_S_L_PSINDX,
+       EGST_S_B_NAMLNG): Ditto.
+       (ESRF_S_B_NAMLNG): Ditto.
+       (ETIR_S_C_HEADER_SIZE): Ditto.
+       (EGPS_S_V_ALLOC_64BIT): Ditto.
+       (DST_S_C_EPILOG): Ditto.
+       (DST_S_C_SRC_SETLNUM_L, DST_S_C_SRC_SETLNUM_W) : Ditto.
+       (DST_S_C_SRC_INCRLNUM_B): Ditto.
+       (DST_S_B_PCLINE_UNSBYTE, DST_S_W_PCLINE_UNSWORD): Ditto.
+       (DST_S_L_PCLINE_UNSLONG): Ditto.
+       (DST_S_B_MODBEG_NAME, DST_S_L_RTNBEG_ADDRESS) : Ditto
+       (DST_S_B_RTNBEG_NAME, DST_S_L_RTNEND_SIZE): Ditto
+       (DST_S_C_SOURCE_HEADER_SIZE): Ditto.
+       (DST_S_B_SRC_DF_LENGTH, DST_S_W_SRC_DF_FILEID): Ditto.
+       (DST_S_B_SRC_DF_FILENAME, DST_S_B_SRC_UNSBYTE): Ditto.
+       (DST_S_B_SRC_UNSBYTE): Ditto.
+       (DST_S_W_SRC_UNSWORD, DST_S_L_SRC_UNSLONG): Ditto.
+       Add prototypes.
+       (vms_section, vms_reloc): Remove types.
+       (hdr_struc): Replaced by ...
+       (hdr_struct): ... new type.
+       (EMH_S_W_HDRTYP, EMH_S_B_STRLVL, EMH_S_L_ARCH1): New constants.
+       (EMH_S_L_ARCH2, EMH_S_L_RECSIZ, EMH_S_B_NAMLNG): Ditto.
+       (EMH_DATE_LENGTH): Ditto.
+       (eom_struc): Replaced by ...
+       (eom_struct): ... new type.
+       (EEOM_S_L_TOTAL_LPS, EEOM_S_W_COMCOD, EEOM_S_B_TFRFLG): New constants.
+       (EEOM_S_L_PSINDX, EEOM_S_L_TFRADR): Ditto.
+       (EIHD_S_K_MAJORID, EIHD_S_K_MINORID, EIHD_S_K_EXE): Ditto.
+       (EIHD_S_L_SIZE, EIHD_S_L_ISDOFF, EIHD_S_L_SYMDBGOFF): Ditto.
+       (EIHD_S_Q_SYMVVA, EIHD_S_L_IMGTYPE): Ditto.
+       (EISD_S_L_EISDSIZE, EISD_S_L_SECSIZE, EISD_S_Q_VIR_ADDR): Ditto.
+       (EISD_S_L_FLAGS, EISD_S_L_VBN, EISD_S_R_CONTROL): Ditto.
+       (EISD_S_L_IDENT, EISD_S_T_GBLNAM): Ditto.
+       (EISD_S_M_GBL, EISD_S_M_CRF, EISD_S_M_DZRO, EISD_S_M_WRT): Ditto.
+       (EISD_S_M_INITALCODE, EISD_S_M_BASED, EISD_S_M_FIXUPVEC): Ditto.
+       (EISD_S_M_RESIDENT, EISD_S_M_VECTOR, EISD_S_M_PROTECT): Ditto.
+       (EISD_S_M_LASTCLU, EISD_S_M_EXE, EISD_S_M_NONSHRADR): Ditto.
+       (EISD_S_M_QUAD_LENGTH, EISD_S_M_ALLOC_64BIT): Ditto.
+       (EIHS_S_L_DSTVBN, EIHS_S_L_DSTSIZE, EIHS_S_L_GSTVBN): Ditto.
+       (EIHS_S_L_GSTSIZE, EIHS_S_L_DMTVBN, EIHS_S_L_DMTBYTES): Ditto.
+       (DBG_S_L_DMT_MODBEG, DBG_S_L_DST_SIZE): Ditto.
+       (DBG_S_W_DMT_PSECT_COUNT, DBG_S_C_DMT_HEADER_SIZE): Ditto.
+       (DBG_S_L_DMT_PSECT_START, DBG_S_L_DMT_PSECT_LENGTH)
+       (DBG_S_C_DMT_PSECT_SIZE): Ditto.
+       (enum file_type_enum): New type.
+       (struct location_struct): Removed.
+       (struct fileinfo, struct srecinfo, struct lineinfo): New types.
+       (struct funcinfo, struct module): Ditto.
+       (struct vms_private_data_struct): Update fields.
+       (struct vms_section_data_struct): New type.
+
+       * vms.c: Update copyright year, fix comments,
+       Fix includes for DECC, add prototypes.
+       (vms_initialize): Use bfd_alloc instead of bfd_zalloc and remove
+       some initializers.
+       Use flavour to set is_vax, location_stack is removed.
+       (struct pair): Declare.
+       (fill_section_ptr): Initialize variables at declaration.
+       Add guard to set SECTION_SYM flag, handlde und section.
+       (vms_fixup_sections): Use struct pair for fill_section_ptr argument.
+       (_bfd_vms_slurp_object_records): New function, replaces previous
+       vms_object_p.
+       (vms_slurp_module): New function.
+       (vms_slurp_image): Ditto.
+       (vms_object_p): Complete rewrite.
+       (vms_mkobject): Use is_vax field to slect architecture.
+       (free_reloc_stream): New function.
+       (vms_convert_to_var): Ditto.
+       (vms_convert_to_var_1): Ditto.
+       (vms_convert_to_var_unix_filename): Ditto.
+       (vms_close_and_cleanup): Call free_reloc_stream, convert file to
+       VAR format on VMS.
+       (vms_new_section_hook): Set alignment to 0, allocate private data.
+       (vms_get_section_contents): Load content.
+       (vms_get_symbol_info): Handle undefined section.
+       (vms_find_nearest_line): Handle.
+       (alloc_reloc_stream): New function.
+       (vms_slurp_reloc_table): Ditto.
+       (vms_get_reloc_upper_bound): Make it real.
+       (vms_canonicalize_reloc): Do the real work.
+       (alpha_howto_table): Add ALPHA_R_NOP, ALPHA_R_BSR, ALPHA_R_LDA,
+       ALPHA_R_BOH.
+       (vms_bfd_reloc_type_lookup): Handle NOP, BSR, LDA and BOH.
+       (vms_set_arch_mach): Check arch.
+       (vms_set_section_contents): Copy the content after allocation.
+       (vms_alpha_vec): Update object flags.
+
+       * vms-tir.c: Update copyright year, fix comments,
+       add prototypes for new functions.
+       (dst_define_location): New function.
+       (dst_restore_location): New function.
+       (dst_retrieve_location): New function.
+       (dst_check_allocation): New function.
+       (image_dump): Call dst_check_allocation.
+       (image_write_b): Ditto.
+       (image_write_w): Ditto.
+       (image_write_l): Ditto.
+       (image_write_q): Ditto.
+       (cmd_name): Handle STA_LW, STA_QW, STO_OFF, STO_IMM, STO_IMMR, STO_LW,
+       STO_QW, OPR_ADD, CTL_SETRB, STC_LP_PSB, CTL_DFLOC, CTL_STLOC,
+       CTL_STKDL.
+       Call error handler instead of abort if name is not known.
+       (etir_sta): Add quarter_relocs argument and set it.
+       Fix cast.
+       (etir_sto): Ditto.
+       (etir_opr): Ditto, return FALSE in case of error.
+       (etir_ctl): Add quarter_relocs argument and set it, fix cast.
+       Fix CTL_DFLOC, CTL_STLOC, CTL_STKDL.
+       (etir_stc): Add quarter_relocs argument and set it, fix cast.
+       Fix STC_LP, STC_LP_PSB, STC_GBL and STC_CGA.
+       Handle STC_LP_PSB, STC_BSR_GBL, STC_LDA_GBL, STC_BOH_GBL.
+       Move STC_NOP_PS, STC_BSR_PS, STC_LDA_PS, STC_BOH_PS, STC_NBH_PS.
+       Return FALSE in case of error.
+       (tir_sta): Change sign of psect.
+       (tir_ctl): Ditto.
+       (tir_cmd): Fix cast. Makes tir_table static const.
+       (etir_cmd): Add quarter_relocs argument, makes etir_table const,
+       add argument to explain.
+       (analyze_etir): Initialize maxptr, add quarter_relocs
+       declaration, move some declarations into inner scopes.
+       Handle quarter_relocs and STO_IMM.
+       (_bfd_vms_slurp_tir): Use constant instead of hard-coded values.
+       (_bfd_vms_slurp_relocs): New function.
+       (_bfd_vms_decode_relocs): New function.
+       (sto_imm): Rewritten.
+       (start_first_etbt_record): New function.
+       (start_another_etbt_record): Ditto.
+       (etir_output_check): Ditto.
+       (defer_reloc_p): Ditto.
+       (_bfd_vms_write_tir): Remove nextoffset, convert a while-loop to
+       a for-loop.  Correctly deals with contents, deals with .vmsdebug,
+       rewritte relocations handling.
+       (_bfd_vms_write_tbt): Removed.
+       (_bfd_vms_write_dbg): Ditto.
+
+       * vms-misc.c: Update copyright year, Fix comments.
+       (_bfd_vms_get_header_values): Use 'size' instead of 'length'.
+       (maybe_adjust_record_pointer_for_object): New function.
+       (_bfd_vms_get_first_record): New function, replaces ...
+       (_bfd_vms_get_record): ..  removed.
+       (_bfd_vms_get_object_record): New function.
+       (_bfd_vms_get_object_record): New function.
+       (vms_get_remaining_object_record): New function, replaces ...
+       (_bfd_vms_get_next_record): ... removed.
+       (add_new_contents): Removed.
+       (_bfd_save_vms_section): Removed.
+       (_bfd_get_vms_section): Removed.
+       (_bfd_vms_output_flush): Write in VAR format.
+       (new_symbol): Don't make UND section.
+
+       * vms-hdr.c: Update copyright year, update list of record handled.
+       (_bfd_vms_slurp_hdr): rec_length renamed to rec_size.
+       (_bfd_vms_write_hdr): Strip vms and unix patches,
+       add comments, truncate module name at 31 characters,
+       use constants instead of hard-coded value,
+       write BFD version instead of a fixed string.
+       (_bfd_vms_slurp_ihd): New function.
+       (_bfd_vms_slurp_isd): Ditto.
+       (_bfd_vms_slurp_ihs): Ditto.
+       (new_module): Ditto.
+       (parse_module): Ditto
+       (build_module_list): Ditto.
+       (module_find_nearest_line): Ditto.
+       (_bfd_vms_find_nearest_dst_line): Ditto.
+       (vms_slurp_debug): Ditto.
+       (_bfd_vms_slurp_dbg): Ditto.
+       (_bfd_vms_slurp_tbt): Ditto.
+       (_bfd_vms_write_dbg): Ditto.
+       (_bfd_vms_write_tbt): Ditto.
+
+       * vms-gsd.c: Update copyright year, update list of records handled.
+       (EVAX_LITERALS_NAME): New macro.
+       (evax_section_flags): Add an entry for EVAX_LITERALS_NAME.
+       (gpsflagdesc, gsyflagdesc): Moved out of _bfd_vms_slurp_gsd.
+       (register_universal_symbol): New function and prototype.
+       (_bfd_vms_slurp_gsd): Fix indentations and casts,
+       improve debug messages,
+       use constants instead of hard-coded value,
+       fix missing endianness conversion,
+       handle global symbol (SYMG).
+       (bfd_vms_set_section_flags): New function.
+       (_bfd_vms_write_gsd): Don't write .vmsdebug section,
+       handle section literals,
+       fix indentation,
+       handle section bfd and vms flags,
+       don't output LIB$INITIALIZE symbol,
+       fix handling of weak symbols,
+       fix evax vs vax procedure descriptor,
+       handle absolute symbols.
+
+       * reloc.c (BFD_RELOC_ALPHA_NOP, BFD_RELOC_ALPHA_BSR,
+       BFD_RELOC_ALPHA_LDA, BFD_RELOC_ALPHA_BOH): New relocations.
+
+       * makefile.vms (DEFS): Fix flags for VMS.
+
+       * bfdio.c (real_fopen): Handle multiple VMS fopen attributes.
+
+       * bfd-in2.h: Regenerated.
+       * libbfd.h: Regenerated.
+
 2009-02-20  Cary Coutant  <ccoutant@google.com>
 
        * vmsutil.c (vms_file_stats_name): Fix incorrect use of st_mtime
index 994759d9b110931d16bffcbae52f875a215c8f0b..7870962f1af4f12dc338bffe81f46b1ec8d0641c 100644 (file)
@@ -2586,6 +2586,22 @@ share a common GP, and the target address is adjusted for
 STO_ALPHA_STD_GPLOAD.  */
   BFD_RELOC_ALPHA_BRSGP,
 
+/* The NOP relocation outputs a NOP if the longword displacement
+between two procedure entry points is < 2^21.  */
+  BFD_RELOC_ALPHA_NOP,
+
+/* The BSR relocation outputs a BSR if the longword displacement
+between two procedure entry points is < 2^21.  */
+  BFD_RELOC_ALPHA_BSR,
+
+/* The LDA relocation outputs a LDA if the longword displacement
+between two procedure entry points is < 2^16.  */
+  BFD_RELOC_ALPHA_LDA,
+
+/* The BOH relocation outputs a BSR if the longword displacement
+between two procedure entry points is < 2^21, or else a hint.  */
+  BFD_RELOC_ALPHA_BOH,
+
 /* Alpha thread-local storage relocations.  */
   BFD_RELOC_ALPHA_TLSGD,
   BFD_RELOC_ALPHA_TLSLDM,
index 7cba51ff83726f193e0ce01909004a47eef615ef..d3a295c214d7503a75d4055d34f26dc7b4128539 100644 (file)
@@ -102,13 +102,21 @@ real_fopen (const char *filename, const char *modes)
     }
   else
     {
-      /* Attribute found - rebuild modes.  */
-      size_t modes_len = vms_attr - modes;
-
-      BFD_ASSERT (modes_len < sizeof (vms_modes));
-      memcpy (vms_modes, modes, modes_len);
-      vms_modes[modes_len] = 0;
-      return close_on_exec (fopen (filename, vms_modes, vms_attr + 1));
+      /* Attributes found.  Split.  */
+      size_t modes_len = strlen (modes) + 1;
+      char attrs[modes_len + 1];
+      char *at[3];
+      int i;
+
+      memcpy (attrs, modes, modes_len);
+      at[0] = attrs;
+      for (i = 0; i < 2; i++)
+       {
+         at[i + 1] = strchr (at[i], ',');
+         BFD_ASSERT (at[i + 1] != NULL);
+         *(at[i + 1]++) = 0; /* Replace ',' with a nul, and skip it.  */
+       }
+      return close_on_exec (fopen (filename, at[0], at[1], at[2]));
     }
 #else /* !VMS */
 #if defined (HAVE_FOPEN64)
index 26238b550ffe334b76c4736b44de7ca216100b2b..2ba7fc8b9dfd5e9c69e7602e9b546cb03dc85527 100644 (file)
@@ -957,6 +957,10 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_ALPHA_GPREL_HI16",
   "BFD_RELOC_ALPHA_GPREL_LO16",
   "BFD_RELOC_ALPHA_BRSGP",
+  "BFD_RELOC_ALPHA_NOP",
+  "BFD_RELOC_ALPHA_BSR",
+  "BFD_RELOC_ALPHA_LDA",
+  "BFD_RELOC_ALPHA_BOH",
   "BFD_RELOC_ALPHA_TLSGD",
   "BFD_RELOC_ALPHA_TLSLDM",
   "BFD_RELOC_ALPHA_DTPMOD64",
index 963441a62d0b166fd7a21e1171f67b065b9eede2..2e2d2a1f855870a2cccbd18fa59087421e84ee1e 100644 (file)
@@ -36,13 +36,15 @@ endif
 CFLAGS=/include=([],[-.include])$(DEFS)
 else
 ifeq ($(ARCH),ALPHA)
-DEFS=/define=(SELECT_VECS="&vms_alpha_vec",SELECT_ARCHITECTURES="&bfd_alpha_arch",\
-"HAVE_vms_alpha_vec=1","unlink=remove","DEBUGDIR=NULL")
+DEFS=/define=(SELECT_VECS="&vms_alpha_vec",\
+  SELECT_ARCHITECTURES="&bfd_alpha_arch",\
+  "HAVE_vms_alpha_vec=1","unlink=remove","DEBUGDIR=NULL")
 else
 DEFS=/define=(SELECT_VECS="&vms_vax_vec",SELECT_ARCHITECTURES="&bfd_vax_arch",\
-"HAVE_vms_vax_vec=1","unlink=remove","const=")
+  "HAVE_vms_vax_vec=1","unlink=remove")
 endif
-CFLAGS=/noopt/debug/show=incl/name=(as_is,shortened)/include=([],[-.include])$(DEFS)/warnings=disable=(missingreturn,longextern)
+OPT=/noopt/debug
+CFLAGS=/name=(as_is,shortened)/include=([],[-.include])$(DEFS)$(OPT)
 endif
 
 
index 0c0fb1d3129cb5a27b51f64ff996a35d3a0babdc..781147e98aa790923759b1f421a5aededc4747cc 100644 (file)
@@ -2109,6 +2109,30 @@ ENUMDOC
   share a common GP, and the target address is adjusted for
   STO_ALPHA_STD_GPLOAD.
 
+ENUM
+  BFD_RELOC_ALPHA_NOP
+ENUMDOC
+  The NOP relocation outputs a NOP if the longword displacement
+     between two procedure entry points is < 2^21.
+
+ENUM
+  BFD_RELOC_ALPHA_BSR
+ENUMDOC
+  The BSR relocation outputs a BSR if the longword displacement
+     between two procedure entry points is < 2^21.
+
+ENUM
+  BFD_RELOC_ALPHA_LDA
+ENUMDOC
+  The LDA relocation outputs a LDA if the longword displacement
+     between two procedure entry points is < 2^16.
+
+ENUM
+  BFD_RELOC_ALPHA_BOH
+ENUMDOC
+  The BOH relocation outputs a BSR if the longword displacement
+     between two procedure entry points is < 2^21, or else a hint.
+
 ENUM
   BFD_RELOC_ALPHA_TLSGD
 ENUMX
index 4bdc27c98d1d54dbf57ddb77ed954617af3f3bb5..e641d0de422ff78cab80509c346b5c413f8f31b2 100644 (file)
@@ -1,9 +1,12 @@
 /* vms-gsd.c -- BFD back-end for VAX (openVMS/VAX) and
    EVAX (openVMS/Alpha) files.
    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2007 Free Software Foundation, Inc.
+   2007, 2009 Free Software Foundation, Inc.
 
-   go and read the openVMS linker manual (esp. appendix B)
+   GSD record handling functions
+   EGSD 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"ampf (kkaempf@rmi.de)
@@ -46,6 +49,7 @@
 #define EVAX_READONLYADDR_NAME "$READONLY_ADDR$"
 #define EVAX_READONLY_NAME     "$READONLY$"
 #define EVAX_LITERAL_NAME      "$LITERAL$"
+#define EVAX_LITERALS_NAME     "$LITERALS"
 #define EVAX_COMMON_NAME       "$COMMON$"
 #define EVAX_LOCAL_NAME                "$LOCAL$"
 
@@ -133,6 +137,11 @@ static struct sec_flags_struct evax_section_flags[] =
       (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_LITERALS_NAME,
+      (EGPS_S_V_PIC | EGPS_S_V_OVR),
+      (SEC_DATA | SEC_READONLY),
+      (EGPS_S_V_PIC | EGPS_S_V_OVR),
+      (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),
@@ -197,6 +206,37 @@ vms_esecflag_by_name (struct sec_flags_struct *section_flags,
 
 struct flagdescstruct { char *name; flagword value; };
 
+static const struct flagdescstruct gpsflagdesc[] =
+{
+  { "PIC", GPS_S_M_PIC },
+  { "LIB", GPS_S_M_LIB },
+  { "OVR", GPS_S_M_OVR },
+  { "REL", GPS_S_M_REL },
+  { "GBL", GPS_S_M_GBL },
+  { "SHR", GPS_S_M_SHR },
+  { "EXE", GPS_S_M_EXE },
+  { "RD",  GPS_S_M_RD },
+  { "WRT", GPS_S_M_WRT },
+  { "VEC", GPS_S_M_VEC },
+  { "NOMOD", EGPS_S_V_NOMOD },
+  { "COM", EGPS_S_V_COM },
+  { NULL, 0 }
+};
+
+static const struct flagdescstruct gsyflagdesc[] =
+{
+  { "WEAK", GSY_S_M_WEAK },
+  { "DEF",  GSY_S_M_DEF },
+  { "UNI",  GSY_S_M_UNI },
+  { "REL",  GSY_S_M_REL },
+  { "COMM", EGSY_S_V_COMM },
+  { "VECEP", EGSY_S_V_VECEP },
+  { "NORM", EGCY_S_V_NORM },
+  { NULL, 0 }
+};
+
+static char *flag2str (struct flagdescstruct *, flagword);
+
 /* Convert flag to printable string.  */
 
 static char *
@@ -224,43 +264,15 @@ flag2str (struct flagdescstruct * flagdesc, flagword flags)
 
 /* Input routines.  */
 
+static int register_universal_symbol (bfd *abfd, asymbol *symbol,
+                                     int vms_flags);
+
 /* Process GSD/EGSD record
    return 0 on success, -1 on error.  */
 
 int
 _bfd_vms_slurp_gsd (bfd * abfd, int objtype)
 {
-#if VMS_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 *vms_rec;
@@ -300,7 +312,7 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype)
       vms_rec = PRIV (vms_rec);
 
       if (objtype == OBJ_S_C_GSD)
-       gsd_type = *vms_rec;
+       gsd_type = vms_rec[0];
       else
        {
          _bfd_vms_get_header_values (abfd, vms_rec, &gsd_type, &gsd_size);
@@ -322,7 +334,7 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype)
            vms_debug (4, "GSD_S_C_PSC\n");
 #endif
            /* If this section isn't a bfd section.  */
-           if (PRIV (is_vax) && (psect_idx < (abfd->section_count-1)))
+           if (PRIV (is_vax) && (psect_idx < (abfd->section_count - 1)))
              {
                /* Check for temporary section from TIR record.  */
                if (psect_idx < PRIV (section_count))
@@ -362,7 +374,6 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype)
            base_addr += section->size;
 
            /* Global section is common symbol.  */
-
            if (old_flags & GPS_S_M_GBL)
              {
                entry = _bfd_vms_enter_symbol (abfd, name);
@@ -496,21 +507,20 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype)
                else
                  psect = vms_rec[value_offset-1];
 
-               symbol->section = (asection *) (size_t) psect;
+               symbol->section = (asection *)(unsigned long)psect;
 #if VMS_DEBUG
-               vms_debug (4, "gsd sym def #%d (%s, %d [%p], %04x=%s)\n", abfd->symcount,
-                          symbol->name, (int)symbol->section, symbol->section, old_flags, flag2str (gsyflagdesc, old_flags));
+               vms_debug (4, "gsd sym def #%d (%s, %ld, %04x=%s)\n", abfd->symcount,
+                         symbol->name, (long)symbol->section, old_flags, flag2str(gsyflagdesc, old_flags));
 #endif
              }
            else
              {
                /* Symbol reference.  */
-               symbol->section = bfd_make_section (abfd, BFD_UND_SECTION_NAME);
 #if VMS_DEBUG
-               vms_debug (4, "gsd sym ref #%d (%s, %s [%p], %04x=%s)\n",
-                          abfd->symcount, symbol->name, symbol->section->name,
-                          symbol->section, old_flags, flag2str (gsyflagdesc, old_flags));
+               vms_debug (4, "gsd sym ref #%d (%s, %04x=%s)\n", abfd->symcount,
+                          symbol->name, old_flags, flag2str (gsyflagdesc, old_flags));
 #endif
+               symbol->section = (asection *)(unsigned long)-1;
              }
 
            gsd_size = vms_rec[name_offset] + name_offset + 1;
@@ -574,19 +584,19 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype)
        case EGSD_S_C_PSC + EVAX_OFFSET:
          {
            /* Program section definition.  */
-           name = _bfd_vms_save_counted_string (vms_rec + 12);
+           name = _bfd_vms_save_counted_string (vms_rec + EGPS_S_B_NAMLNG);
            section = bfd_make_section (abfd, name);
            if (!section)
              return -1;
-           old_flags = bfd_getl16 (vms_rec + 6);
-           section->size = bfd_getl32 (vms_rec + 8);   /* Allocation.  */
+           old_flags = bfd_getl16 (vms_rec + EGPS_S_W_FLAGS);
+           section->size = bfd_getl32 (vms_rec + EGPS_S_L_ALLOC);
            new_flags = vms_secflag_by_name (abfd, evax_section_flags, name,
                                             section->size > 0);
            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 = vms_rec[4];
+           section->alignment_power = vms_rec[EGPS_S_B_ALIGN];
            align_addr = (1 << section->alignment_power);
            if ((base_addr % align_addr) != 0)
              base_addr += (align_addr - (base_addr % align_addr));
@@ -595,9 +605,10 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype)
            section->contents = bfd_zmalloc (section->size);
            if (section->contents == NULL)
              return -1;
+           section->filepos = (unsigned int)-1;
 #if VMS_DEBUG
-           vms_debug (4, "egsd psc %d (%s, flags %04x=%s) ",
-                      section->index, name, old_flags, flag2str (gpsflagdesc, old_flags));
+           vms_debug (4, "EGSD P-section %d (%s, flags %04x=%s) ",
+                      section->index, name, old_flags, flag2str(gpsflagdesc, old_flags));
            vms_debug (4, "%d bytes at 0x%08lx (mem %p)\n",
                       section->size, section->vma, section->contents);
 #endif
@@ -606,50 +617,52 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype)
 
        case EGSD_S_C_SYM + EVAX_OFFSET:
          {
-           /* Symbol specification (definition or reference).  */
+           /* Global symbol specification (definition or reference).  */
            symbol = bfd_make_empty_symbol (abfd);
            if (symbol == 0)
              return -1;
 
-           old_flags = bfd_getl16 (vms_rec + 6);
+           old_flags = bfd_getl16 (vms_rec + EGSY_S_W_FLAGS);
            new_flags = BSF_NO_FLAGS;
 
            if (old_flags & EGSY_S_V_WEAK)
              new_flags |= BSF_WEAK;
 
-           if (vms_rec[6] & EGSY_S_V_DEF)
+           if (old_flags & EGSY_S_V_DEF)
              {
                /* Symbol definition.  */
-               symbol->name = _bfd_vms_save_counted_string (vms_rec + 32);
                if (old_flags & EGSY_S_V_NORM)
-                 /* Proc def.  */
                  new_flags |= BSF_FUNCTION;
-
-               symbol->value = bfd_getl64 (vms_rec + 8);
-               symbol->section = (asection *) ((unsigned long) bfd_getl32 (vms_rec + 28));
+               symbol->name =
+                 _bfd_vms_save_counted_string (vms_rec + ESDF_S_B_NAMLNG);
+               symbol->value = bfd_getl64 (vms_rec + ESDF_S_L_VALUE);
+               symbol->section =
+                 (asection *)(unsigned long) bfd_getl32 (vms_rec + ESDF_S_L_PSINDX);
 #if VMS_DEBUG
-               vms_debug (4, "egsd sym def #%d (%s, %d, %04x=%s)\n", abfd->symcount,
-                          symbol->name, (int) symbol->section, old_flags,
-                          flag2str (gsyflagdesc, old_flags));
+               vms_debug (4, "EGSD sym def #%d (%s, %ld, %04x=%s)\n",
+                          abfd->symcount, symbol->name, (long)symbol->section,
+                          old_flags, flag2str (gsyflagdesc, old_flags));
 #endif
              }
            else
              {
                /* Symbol reference.  */
-               symbol->name = _bfd_vms_save_counted_string (vms_rec + 8);
+               symbol->name =
+                 _bfd_vms_save_counted_string (vms_rec + ESRF_S_B_NAMLNG);
 #if VMS_DEBUG
-               vms_debug (4, "egsd sym ref #%d (%s, %04x=%s)\n", abfd->symcount,
-                         symbol->name, old_flags, flag2str (gsyflagdesc, old_flags));
+               vms_debug (4, "EGSD sym ref #%d (%s, %04x=%s)\n",
+                          abfd->symcount, symbol->name, old_flags,
+                          flag2str (gsyflagdesc, old_flags));
 #endif
-               symbol->section = bfd_make_section (abfd, BFD_UND_SECTION_NAME);
+               symbol->section = (asection *)(unsigned long)-1;
              }
 
            symbol->flags = new_flags;
 
-           /* Save symbol in vms_symbol_table.  */
-           entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table),
-                                                         symbol->name,
-                                                         TRUE, FALSE);
+           /* Register symbol in VMS symbol table.  */
+           entry = (vms_symbol_entry *) bfd_hash_lookup
+             (PRIV (vms_symbol_table), symbol->name, TRUE, FALSE);
+
            if (entry == NULL)
              {
                bfd_set_error (bfd_error_no_memory);
@@ -672,11 +685,73 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype)
          }
          break;
 
-       case EGSD_S_C_IDC + EVAX_OFFSET:
+       case EGSD_S_C_SYMG + EVAX_OFFSET:
+         {
+           /* Universal symbol specification (definition).  */
+           symbol = bfd_make_empty_symbol (abfd);
+           if (symbol == 0)
+             return -1;
+
+           old_flags = bfd_getl16 (vms_rec + EGST_S_W_FLAGS);
+           new_flags = BSF_NO_FLAGS;
+
+           if (old_flags & EGSY_S_V_WEAK)
+             new_flags |= BSF_WEAK;
+
+           if (old_flags & EGSY_S_V_DEF) /* symbol definition */
+             {
+               if (old_flags & EGSY_S_V_NORM)
+                 new_flags |= BSF_FUNCTION;
+
+               symbol->name =
+                 _bfd_vms_save_counted_string (vms_rec + EGST_S_B_NAMLNG);
+
+               /* For BSF_FUNCTION symbols, the entry point is in LP_1
+                  and the descriptor in LP_2.  For other symbols, the
+                  unique value is in LP_2.  */
+               symbol->value = bfd_getl64 (vms_rec + EGST_S_Q_LP_2);
+
+               /* Adding this offset is necessary in order for GDB to
+                  read the DWARF-2 debug info from shared libraries.  */
+               if (abfd->flags & DYNAMIC
+                   && strstr (symbol->name, "$DWARF2.DEBUG") != 0)
+                 symbol->value += PRIV (symvva);
+             }
+           else /* symbol reference */
+             (*_bfd_error_handler) ("Invalid EGST reference");
+
+           symbol->flags = new_flags;
+
+           if (register_universal_symbol (abfd, symbol, old_flags) < 0)
+             return -1;
+
+           /* Make a second symbol for the entry point.  */
+           if (symbol->flags & BSF_FUNCTION)
+             {
+               asymbol *en_sym;
+               char *name = bfd_alloc (abfd, strlen (symbol->name) + 5);
+
+               en_sym = bfd_make_empty_symbol (abfd);
+               if (en_sym == 0)
+                 return -1;
+
+               strcpy (name, symbol->name);
+               strcat (name, "..en");
+
+               en_sym->name = name;
+               en_sym->value = bfd_getl64 (vms_rec + EGST_S_Q_LP_1);
+
+               if (register_universal_symbol (abfd, en_sym, old_flags) < 0)
+                 return -1;
+             }
+         }
          break;
 
+       case EGSD_S_C_IDC + EVAX_OFFSET:
+         break;
+
        default:
-         (*_bfd_error_handler) (_("unknown gsd/egsd subtype %d"), gsd_type);
+         (*_bfd_error_handler) (_("Unknown GSD/EGSD subtype %d"), gsd_type);
          bfd_set_error (bfd_error_bad_value);
          return -1;
        }
@@ -691,7 +766,79 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype)
   return 0;
 }
 
-/* Output routines.  */
+/* Register a universal symbol in the VMS symbol table.  */
+
+static int
+register_universal_symbol (bfd *abfd, asymbol *symbol, int vms_flags)
+{
+  bfd_vma sbase = 0;
+  asection *s, *sec = NULL;
+  vms_symbol_entry *entry;
+
+  /* A universal symbol is by definition global...  */
+  symbol->flags |= BSF_GLOBAL;
+
+  /* ...and dynamic in shared libraries.  */
+  if (abfd->flags & DYNAMIC)
+    symbol->flags |= BSF_DYNAMIC;
+
+  /* Find containing section.  */
+  for (s = abfd->sections; s; s = s->next)
+    {
+      if (symbol->value >= s->vma
+         && s->vma > sbase
+         && !(s->flags & SEC_COFF_SHARED_LIBRARY)
+         && (s->size > 0 || !(vms_flags & EGSY_S_V_REL)))
+       {
+         sbase = s->vma;
+         sec = s;
+       }
+    }
+
+  symbol->value -= sbase;
+  symbol->section = sec;
+
+#if VMS_DEBUG
+  vms_debug (4, "EGST sym def #%d (%s, 0x%llx => 0x%llx, %04x=%s)\n",
+            abfd->symcount, symbol->name, symbol->value + sbase,
+            symbol->value, vms_flags,
+            flag2str(gsyflagdesc, vms_flags));
+#endif
+
+  entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table),
+                                               symbol->name,
+                                               TRUE, FALSE);
+
+  if (entry == NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return -1;
+    }
+
+  if (entry->symbol) /* FIXME: DEC C generates this */
+    {
+#if VMS_DEBUG
+      vms_debug (4, "EGSD_S_C_SYMG: duplicate \"%s\"\n", symbol->name);
+#endif
+    }
+  else
+    {
+      entry->symbol = symbol;
+      PRIV (gsd_sym_count)++;
+      abfd->symcount++;
+    }
+
+  return 0;
+}
+
+/* Set section VMS flags.  */
+
+void
+bfd_vms_set_section_flags (bfd *abfd ATTRIBUTE_UNUSED,
+                          asection *sec, flagword flags)
+{
+  vms_section_data (sec)->vflags = flags;
+}
 
 /* Write section and symbol directory of bfd abfd.  */
 
@@ -705,6 +852,7 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED)
   char dummy_name[10];
   char *sname;
   flagword new_flags, old_flags;
+  int abs_section_index = 0;
 
 #if VMS_DEBUG
   vms_debug (2, "vms_write_gsd (%p, %d)\n", abfd, objtype);
@@ -730,6 +878,11 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED)
       vms_debug (3, "Section #%d %s, %d bytes\n", section->index, section->name, (int)section->size);
 #endif
 
+      /* Don't write out the VMS debug info section since it is in the
+         ETBT and EDBG sections in etir. */
+      if (!strcmp (section->name, ".vmsdebug"))
+        goto done;
+
       /* 13 bytes egsd, max 31 chars name -> should be 44 bytes.  */
       if (_bfd_vms_output_check (abfd, 64) < 0)
        {
@@ -775,6 +928,11 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED)
            sname = EVAX_READONLY_NAME;
          else if ((*sname == 'l') && (strcmp (sname, "literal") == 0))
            sname = EVAX_LITERAL_NAME;
+         else if ((*sname == 'l') && (strcmp (sname, "literals") == 0))
+           {
+             sname = EVAX_LITERALS_NAME;
+             abs_section_index = section->index;
+           }
          else if ((*sname == 'c') && (strcmp (sname, "comm") == 0))
            sname = EVAX_COMMON_NAME;
          else if ((*sname == 'l') && (strcmp (sname, "lcomm") == 0))
@@ -785,18 +943,34 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED)
 
       _bfd_vms_output_begin (abfd, EGSD_S_C_PSC, -1);
       _bfd_vms_output_short (abfd, section->alignment_power & 0xff);
+
       if (bfd_is_com_section (section))
-       new_flags = (EGPS_S_V_OVR | EGPS_S_V_REL | EGPS_S_V_GBL | EGPS_S_V_RD | EGPS_S_V_WRT | EGPS_S_V_NOMOD | EGPS_S_V_COM);
+       new_flags = (EGPS_S_V_OVR | EGPS_S_V_REL | EGPS_S_V_GBL | EGPS_S_V_RD
+                    | EGPS_S_V_WRT | EGPS_S_V_NOMOD | EGPS_S_V_COM);
       else
        new_flags = vms_esecflag_by_name (evax_section_flags, sname,
                                          section->size > 0);
 
+      /* Modify them as directed.  */
+      if (section->flags & SEC_READONLY)
+       new_flags &= ~EGPS_S_V_WRT;
+
+      new_flags |= vms_section_data (section)->vflags & 0xffff;
+      new_flags &=
+       ~((vms_section_data (section)->vflags >> EGPS_S_V_NO_SHIFT) & 0xffff);
+
+#if VMS_DEBUG
+      vms_debug (3, "sec flags %x\n", section->flags);
+      vms_debug (3, "new_flags %x, _raw_size %d\n", new_flags, section->size);
+#endif
+
       _bfd_vms_output_short (abfd, new_flags);
       _bfd_vms_output_long (abfd, (unsigned long) section->size);
       _bfd_vms_output_counted (abfd, sname);
       _bfd_vms_output_flush (abfd);
 
       last_index = section->index;
+done:
       section = section->next;
     }
 
@@ -822,9 +996,11 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED)
       if (old_flags & BSF_FILE)
        continue;
 
-      if (((old_flags & (BSF_GLOBAL | BSF_WEAK)) == 0) /* Not xdef...  */
-         && (!bfd_is_und_section (symbol->section)))   /* ...and not xref.  */
-       continue;                                       /* Dont output.  */
+      if ((old_flags & BSF_GLOBAL) == 0                   /* Not xdef...  */
+         && !bfd_is_und_section (symbol->section) /* and not xref... */
+         && !((old_flags & BSF_SECTION_SYM) != 0  /* and not LIB$INITIALIZE.  */
+              && strcmp (symbol->section->name, "LIB$INITIALIZE") == 0))
+       continue;
 
       /* 13 bytes egsd, max 64 chars name -> should be 77 bytes.  */
       if (_bfd_vms_output_check (abfd, 80) < 0)
@@ -846,7 +1022,7 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED)
 
       if (old_flags & BSF_WEAK)
        new_flags |= EGSY_S_V_WEAK;
-      if (bfd_is_com_section (symbol->section))
+      if (bfd_is_com_section (symbol->section))                /* .comm  */
        new_flags |= (EGSY_S_V_WEAK | EGSY_S_V_COMM);
 
       if (old_flags & BSF_FUNCTION)
@@ -854,7 +1030,7 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED)
          new_flags |= EGSY_S_V_NORM;
          new_flags |= EGSY_S_V_REL;
        }
-      if (old_flags & (BSF_GLOBAL | BSF_WEAK))
+      if (old_flags & BSF_GLOBAL)
        {
          new_flags |= EGSY_S_V_DEF;
          if (!bfd_is_abs_section (symbol->section))
@@ -862,7 +1038,7 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED)
        }
       _bfd_vms_output_short (abfd, new_flags);
 
-      if (old_flags & (BSF_GLOBAL | BSF_WEAK))
+      if (old_flags & BSF_GLOBAL)
        {
          /* Symbol definition.  */
          uquad code_address = 0;
@@ -871,10 +1047,19 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED)
 
          if ((old_flags & BSF_FUNCTION) && symbol->udata.p != NULL)
            {
-             code_address = ((asymbol *) (symbol->udata.p))->value;
-             ca_psindx = ((asymbol *) (symbol->udata.p))->section->index;
+             asymbol *sym;
+
+             if (bfd_get_flavour (abfd) == bfd_target_evax_flavour)
+               sym = ((struct evax_private_udata_struct *)symbol->udata.p)->enbsym;
+             else
+               sym = (asymbol *)symbol->udata.p;
+             code_address = sym->value;
+             ca_psindx = sym->section->index;
            }
-         psindx = symbol->section->index;
+         if (bfd_is_abs_section (symbol->section))
+           psindx = abs_section_index;
+         else
+           psindx = symbol->section->index;
 
          _bfd_vms_output_quad (abfd, symbol->value);
          _bfd_vms_output_quad (abfd, code_address);
index 11e1af60103b4ddc6d2cc84483c99efc01a8c6c8..6ad84ddd2a539beddaa001db79d710a4f0632289 100644 (file)
@@ -1,14 +1,31 @@
 /* vms-hdr.c -- BFD back-end for VMS/VAX (openVMS/VAX) and
    EVAX (openVMS/Alpha) files.
    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006,
-   2007 Free Software Foundation, Inc.
+   2007, 2008, 2009 Free Software Foundation, Inc.
 
    HDR record handling functions
    EMH record handling functions
-   and
+
    EOM record handling functions
    EEOM record handling functions
 
+   IHD record handling functions
+   EIHD record handling functions
+
+   ISD record handling functions
+   EISD record handling functions
+
+   IHS record handling functions
+   EIHS record handling functions
+
+   DBG record handling functions
+   EDBG record handling functions
+
+   TBT record handling functions
+   ETBT record handling functions
+
+   DST/DMT section handling functions
+
    Written by Klaus K"ampf (kkaempf@rmi.de)
 
    This program is free software; you can redistribute it and/or modify
 #include <alloca.h>
 #endif
 
+static struct module *new_module (bfd *);
+static void parse_module
+  (bfd *, struct module *, unsigned char *, unsigned int);
+static struct module *build_module_list (bfd *);
+static bfd_boolean module_find_nearest_line
+  (bfd *, struct module *, bfd_vma, const char **, const char **,
+   unsigned int *);
+static int vms_slurp_debug (bfd *);
+
+#define SET_MODULE_PARSED(m) \
+  do { if ((m)->name == NULL) (m)->name = ""; } while (0)
+#define IS_MODULE_PARSED(m) ((m)->name != NULL)
+
+
 /* Read & process emh record
    return 0 on success, -1 on error.  */
 
@@ -85,15 +116,15 @@ _bfd_vms_slurp_hdr (bfd *abfd, int objtype)
       break;
 
     case MHD_S_C_LNM:
-      PRIV (hdr_data).hdr_c_lnm = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 2));
+      PRIV (hdr_data).hdr_c_lnm = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 2));
       break;
 
     case MHD_S_C_SRC:
-      PRIV (hdr_data).hdr_c_src = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 2));
+      PRIV (hdr_data).hdr_c_src = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 2));
       break;
 
     case MHD_S_C_TTL:
-      PRIV (hdr_data).hdr_c_ttl = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 2));
+      PRIV (hdr_data).hdr_c_ttl = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 2));
       break;
 
     case EMH_S_C_MHD + EVAX_OFFSET:
@@ -110,15 +141,15 @@ _bfd_vms_slurp_hdr (bfd *abfd, int objtype)
       break;
 
     case EMH_S_C_LNM + EVAX_OFFSET:
-      PRIV (hdr_data).hdr_c_lnm = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 6));
+      PRIV (hdr_data).hdr_c_lnm = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 6));
       break;
 
     case EMH_S_C_SRC + EVAX_OFFSET:
-      PRIV (hdr_data).hdr_c_src = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 6));
+      PRIV (hdr_data).hdr_c_src = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 6));
       break;
 
     case EMH_S_C_TTL + EVAX_OFFSET:
-      PRIV (hdr_data).hdr_c_ttl = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_length - 6));
+      PRIV (hdr_data).hdr_c_ttl = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 6));
       break;
 
     case MHD_S_C_CPR:
@@ -189,6 +220,7 @@ _bfd_vms_write_hdr (bfd *abfd, int objtype)
   unsigned int symnum;
   int had_case = 0;
   int had_file = 0;
+  char version [256];
 
 #if VMS_DEBUG
   vms_debug (2, "vms_write_hdr (%p)\n", abfd);
@@ -213,27 +245,34 @@ _bfd_vms_write_hdr (bfd *abfd, int objtype)
 
       fptr = bfd_get_filename (abfd);
       fname = strdup (fptr);
+
+      /* Strip VMS path.  */
       fout = strrchr (fname, ']');
-      if (fout == 0)
+      if (fout == NULL)
        fout = strchr (fname, ':');
-      if (fout != 0)
+      if (fout != NULL)
        fout++;
       else
        fout = fname;
 
+      /* Strip UNIX path.  */
+      fptr = strrchr (fout, '/');
+      if (fptr != NULL)
+       fout = fptr + 1;
+
       /* Strip .obj suffix.  */
-      fptr = strrchr (fname, '.');
-      if ((fptr != 0)
-         && (strcasecmp (fptr, ".OBJ") == 0))
+      fptr = strrchr (fout, '.');
+      if (fptr != 0 && strcasecmp (fptr, ".OBJ") == 0)
        *fptr = 0;
 
+      /* Convert to upper case and truncate at 31 characters.
+         (VMS object file format restricts module name length to 31).  */
       fptr = fout;
       while (*fptr != 0)
        {
          *fptr = TOUPPER (*fptr);
          fptr++;
-         if ((*fptr == ';')
-            || ((fptr - fout) > 31))
+         if (*fptr == ';' || (fptr - fout) >= 31)
            *fptr = 0;
        }
       _bfd_vms_output_counted (abfd, fout);
@@ -243,13 +282,14 @@ _bfd_vms_write_hdr (bfd *abfd, int objtype)
     _bfd_vms_output_counted (abfd, "NONAME");
 
   _bfd_vms_output_counted (abfd, BFD_VERSION_STRING);
-  _bfd_vms_output_dump (abfd, get_vms_time_string (), 17);
-  _bfd_vms_output_fill (abfd, 0, 17);
+  _bfd_vms_output_dump (abfd, get_vms_time_string (), EMH_DATE_LENGTH);
+  _bfd_vms_output_fill (abfd, 0, EMH_DATE_LENGTH);
   _bfd_vms_output_flush (abfd);
 
   /* LMN.  */
   _bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_LNM);
-  _bfd_vms_output_dump (abfd, (unsigned char *) STRING_COMMA_LEN ("GAS proGIS"));
+  snprintf (version, sizeof (version), "GAS BFD v%s", BFD_VERSION_STRING);
+  _bfd_vms_output_dump (abfd, (unsigned char *)version, strlen (version));
   _bfd_vms_output_flush (abfd);
 
   /* SRC.  */
@@ -320,10 +360,10 @@ _bfd_vms_slurp_eom (bfd *abfd, int objtype)
     }
   else
     {
-      PRIV (eom_data).eom_l_total_lps = bfd_getl32 (vms_rec + 4);
-      PRIV (eom_data).eom_b_comcod = *(vms_rec + 8);
-
-      if (PRIV (eom_data).eom_b_comcod > 1)
+      PRIV (eom_data).eom_l_total_lps
+        = bfd_getl32 (vms_rec + EEOM_S_L_TOTAL_LPS);
+      PRIV (eom_data).eom_w_comcod = bfd_getl16 (vms_rec + EEOM_S_W_COMCOD);
+      if (PRIV (eom_data).eom_w_comcod > 1)
        {
          (*_bfd_error_handler) (_("Object module NOT error-free !\n"));
          bfd_set_error (bfd_error_bad_value);
@@ -333,9 +373,11 @@ _bfd_vms_slurp_eom (bfd *abfd, int objtype)
       if (PRIV (rec_size) > 10)
        {
           PRIV (eom_data).eom_has_transfer = TRUE;
-          PRIV (eom_data).eom_b_tfrflg = *(vms_rec + 9);
-          PRIV (eom_data).eom_l_psindx = bfd_getl32 (vms_rec + 12);
-          PRIV (eom_data).eom_l_tfradr = bfd_getl32 (vms_rec + 16);
+          PRIV (eom_data).eom_b_tfrflg = vms_rec[EEOM_S_B_TFRFLG];
+          PRIV (eom_data).eom_l_psindx
+            = bfd_getl32 (vms_rec + EEOM_S_L_PSINDX);
+          PRIV (eom_data).eom_l_tfradr
+            = bfd_getl32 (vms_rec + EEOM_S_L_TFRADR);
 
           abfd->start_address = PRIV (eom_data).eom_l_tfradr;
        }
@@ -377,3 +419,1001 @@ _bfd_vms_write_eom (bfd *abfd, int objtype)
   _bfd_vms_output_end (abfd);
   return 0;
 }
+
+/* Read & process IHD/EIHD record.
+   Return 0 on success, -1 on error  */
+int
+_bfd_vms_slurp_ihd (bfd *abfd, unsigned int *isd_offset,
+                   unsigned int *ihs_offset)
+{
+  unsigned int imgtype, size;
+  bfd_vma symvva;
+
+#if VMS_DEBUG
+  vms_debug (8, "_bfd_vms_slurp_ihd\n");
+#endif
+
+  size = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_SIZE);
+  imgtype = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_IMGTYPE);
+
+  if (imgtype == EIHD_S_K_EXE)
+    abfd->flags |= EXEC_P;
+
+  symvva = bfd_getl64 (PRIV (vms_rec) + EIHD_S_Q_SYMVVA);
+  if (symvva != 0)
+    {
+      PRIV (symvva) = symvva;
+      abfd->flags |= DYNAMIC;
+    }
+
+  *isd_offset = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_ISDOFF);
+  *ihs_offset = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_SYMDBGOFF);
+
+#if VMS_DEBUG
+  vms_debug (4, "EIHD record size %d imgtype %d symvva 0x%llx isd %d ihs %d\n",
+            size, imgtype, symvva, *isd_offset, *ihs_offset);
+#endif
+
+  return 0;
+}
+
+/* Read & process ISD/EISD record
+   return 0 on success, -1 on error  */
+
+int
+_bfd_vms_slurp_isd (bfd *abfd, unsigned int offset)
+{
+  int section_count = 0;
+  unsigned char *p;
+  unsigned int rec_size;
+
+#if VMS_DEBUG
+  vms_debug (8, "_bfd_vms_slurp_isd\n");
+#endif
+
+  for (p = PRIV (vms_rec) + offset;
+       (rec_size = bfd_getl32 (p + EISD_S_L_EISDSIZE)) != 0;
+       p += rec_size)
+    {
+      unsigned long long vaddr = bfd_getl64 (p + EISD_S_Q_VIR_ADDR);
+      unsigned int size = bfd_getl32 (p + EISD_S_L_SECSIZE);
+      unsigned int flags = bfd_getl32 (p + EISD_S_L_FLAGS);
+      unsigned int vbn = bfd_getl32 (p + EISD_S_L_VBN);
+      char *name = NULL;
+      asection *section;
+      flagword bfd_flags;
+
+#if VMS_DEBUG
+      vms_debug (4, "EISD record at 0x%x size 0x%x addr 0x%x bfd_flags 0x%x block %d\n",
+                p - PRIV (vms_rec), size, vaddr, flags, vbn);
+#endif
+
+      /* VMS combines psects from .obj files into isects in the .exe.  This
+        process doesn't preserve enough information to reliably determine
+        what's in each section without examining the data.  This is
+        especially true of DWARF debug sections.  */
+      bfd_flags = SEC_ALLOC;
+
+      if (flags & EISD_S_M_EXE)
+       bfd_flags |= SEC_CODE | SEC_HAS_CONTENTS | SEC_LOAD;
+
+      if (flags & EISD_S_M_NONSHRADR)
+       bfd_flags |= SEC_DATA | SEC_HAS_CONTENTS | SEC_LOAD;
+
+      if (!(flags & EISD_S_M_WRT))
+       bfd_flags |= SEC_READONLY;
+
+      if (flags & EISD_S_M_DZRO)
+       bfd_flags |= SEC_DATA;
+
+      if (flags & EISD_S_M_FIXUPVEC)
+       bfd_flags |= SEC_DATA | SEC_HAS_CONTENTS | SEC_LOAD;
+
+      if (flags & EISD_S_M_CRF)
+       bfd_flags |= SEC_HAS_CONTENTS | SEC_LOAD;
+
+      if (flags & EISD_S_M_GBL)
+       {
+         name = _bfd_vms_save_counted_string (p + EISD_S_T_GBLNAM);
+         bfd_flags |= SEC_COFF_SHARED_LIBRARY;
+         bfd_flags &= ~(SEC_ALLOC | SEC_LOAD);
+       }
+      else
+       {
+         name = (char*) bfd_alloc (abfd, 32);
+         sprintf (name, "$LOCAL_%03d$", section_count++);
+       }
+
+      section = bfd_make_section (abfd, name);
+
+      if (!section)
+       return -1;
+
+      section->filepos = vbn ? VMS_BLOCK_SIZE * (vbn - 1) : (unsigned int)-1;
+      section->size = size;
+      section->vma = vaddr;
+
+      if (!bfd_set_section_flags (abfd, section, bfd_flags))
+       return -1;
+    }
+
+  return 0;
+}
+
+/* Read & process IHS/EIHS record
+   return 0 on success, -1 on error  */
+int
+_bfd_vms_slurp_ihs (bfd *abfd, unsigned int offset)
+{
+  unsigned char *p = PRIV (vms_rec) + offset;
+  unsigned int gstvbn = bfd_getl32 (p + EIHS_S_L_GSTVBN);
+  unsigned int gstsize ATTRIBUTE_UNUSED = bfd_getl32 (p + EIHS_S_L_GSTSIZE);
+  unsigned int dstvbn = bfd_getl32 (p + EIHS_S_L_DSTVBN);
+  unsigned int dstsize = bfd_getl32 (p + EIHS_S_L_DSTSIZE);
+  unsigned int dmtvbn = bfd_getl32 (p + EIHS_S_L_DMTVBN);
+  unsigned int dmtbytes = bfd_getl32 (p + EIHS_S_L_DMTBYTES);
+  asection *section;
+
+#if VMS_DEBUG
+  vms_debug (8, "_bfd_vms_slurp_ihs\n");
+  vms_debug (4, "EIHS record gstvbn %d gstsize %d dstvbn %d dstsize %d dmtvbn %d dmtbytes %d\n",
+            gstvbn, gstsize, dstvbn, dstsize, dmtvbn, dmtbytes);
+#endif
+
+  if (dstvbn)
+    {
+      flagword bfd_flags = SEC_HAS_CONTENTS | SEC_DEBUGGING;
+
+      section = bfd_make_section (abfd, "$DST$");
+      if (!section)
+       return -1;
+
+      section->size = dstsize;
+      section->filepos = VMS_BLOCK_SIZE * (dstvbn - 1);
+
+      if (!bfd_set_section_flags (abfd, section, bfd_flags))
+       return -1;
+
+      PRIV (dst_section) = section;
+      abfd->flags |= (HAS_DEBUG | HAS_LINENO);
+    }
+
+  if (dmtvbn)
+    {
+      flagword bfd_flags = SEC_HAS_CONTENTS | SEC_DEBUGGING;
+
+      section = bfd_make_section (abfd, "$DMT$");
+      if (!section)
+       return -1;
+
+      section->size = dmtbytes;
+      section->filepos = VMS_BLOCK_SIZE * (dmtvbn - 1);
+
+      if (!bfd_set_section_flags (abfd, section, bfd_flags))
+       return -1;
+    }
+
+  if (gstvbn)
+    {
+      flagword bfd_flags = SEC_HAS_CONTENTS;
+
+      section = bfd_make_section (abfd, "$GST$");
+      if (!section)
+       return -1;
+
+      if (bfd_seek (abfd, VMS_BLOCK_SIZE * (gstvbn - 1), SEEK_SET))
+       {
+         bfd_set_error (bfd_error_file_truncated);
+         return -1;
+       }
+
+      if (_bfd_vms_slurp_object_records (abfd) != 0)
+       return -1;
+
+      section->filepos = VMS_BLOCK_SIZE * (gstvbn - 1);
+      section->size = bfd_tell (abfd) - section->filepos;
+
+      if (!bfd_set_section_flags (abfd, section, bfd_flags))
+       return -1;
+
+      abfd->flags |= HAS_SYMS;
+    }
+
+  return 0;
+}
+
+/* Build a new module for the specified BFD.  */
+
+static struct module *
+new_module (bfd *abfd)
+{
+  struct module *module
+    = (struct module *) bfd_zalloc (abfd, sizeof (struct module));
+  module->file_table_count = 16; /* Arbitrary.  */
+  module->file_table
+    = bfd_malloc (module->file_table_count * sizeof (struct fileinfo));
+  return module;
+}
+
+/* Parse debug info for a module and internalize it.  */
+
+static void
+parse_module (bfd *abfd, struct module *module, unsigned char *ptr,
+             unsigned int length)
+{
+  unsigned char *maxptr = ptr + length, *src_ptr, *pcl_ptr;
+  unsigned int prev_linum = 0, curr_linenum = 0;
+  bfd_vma prev_pc = 0, curr_pc = 0;
+  struct srecinfo *curr_srec, *srec;
+  struct lineinfo *curr_line, *line;
+  struct funcinfo *funcinfo;
+
+  /* Initialize tables with zero element.  */
+  curr_srec = (struct srecinfo *) bfd_zalloc (abfd, sizeof (struct srecinfo));
+  module->srec_table = curr_srec;
+
+  curr_line = (struct lineinfo *) bfd_zalloc (abfd, sizeof (struct lineinfo));
+  module->line_table = curr_line;
+
+  while (ptr < maxptr)
+    {
+      /* The first byte is not counted in the recorded length.  */
+      int rec_length = bfd_getl16 (ptr) + 1;
+      int rec_type = bfd_getl16 (ptr + 2);
+
+#if VMS_DEBUG
+      _bfd_vms_debug (2, "DST record: length %d, type %d\n",
+                     rec_length, rec_type);
+#endif
+
+      switch (rec_type)
+       {
+       case DST_S_C_MODBEG:
+         module->name
+           = _bfd_vms_save_counted_string (ptr + DST_S_B_MODBEG_NAME);
+
+         curr_pc = 0;
+         prev_pc = 0;
+         curr_linenum = 0;
+         prev_linum = 0;
+
+#if VMS_DEBUG
+          _bfd_vms_debug (3, "module: %s\n", module->name);
+#endif
+         break;
+
+       case DST_S_C_MODEND:
+#if VMS_DEBUG
+          _bfd_vms_debug (3, "end module\n");
+#endif
+         break;
+
+       case DST_S_C_RTNBEG:
+         funcinfo = (struct funcinfo *)
+           bfd_zalloc (abfd, sizeof (struct funcinfo));
+          funcinfo->name
+           = _bfd_vms_save_counted_string (ptr + DST_S_B_RTNBEG_NAME);
+         funcinfo->low = bfd_getl32 (ptr + DST_S_L_RTNBEG_ADDRESS);
+         funcinfo->next = module->func_table;
+         module->func_table = funcinfo;
+    
+#if VMS_DEBUG
+          _bfd_vms_debug (3, "routine: %s at 0x%x\n",
+                         funcinfo->name, funcinfo->low);
+#endif
+         break;
+
+       case DST_S_C_RTNEND:
+         module->func_table->high = module->func_table->low
+           + bfd_getl32 (ptr + DST_S_L_RTNEND_SIZE) - 1;
+
+         if (module->func_table->high > module->high)
+           module->high = module->func_table->high;
+
+#if VMS_DEBUG
+          _bfd_vms_debug (3, "end routine\n");
+#endif
+         break;
+
+       case DST_S_C_PROLOG:
+#if VMS_DEBUG
+          _bfd_vms_debug (3, "prologue\n");
+#endif
+         break;
+
+       case DST_S_C_EPILOG:
+#if VMS_DEBUG
+          _bfd_vms_debug (3, "epilog\n");
+#endif
+         break;
+
+       case DST_S_C_BLKBEG:
+#if VMS_DEBUG
+          _bfd_vms_debug (3, "block\n");
+#endif
+         break;
+
+       case DST_S_C_BLKEND:
+#if VMS_DEBUG
+          _bfd_vms_debug (3, "end block\n");
+#endif
+         break;
+
+       case DST_S_C_SOURCE:
+         src_ptr = ptr + DST_S_C_SOURCE_HEADER_SIZE;
+
+#if VMS_DEBUG
+         _bfd_vms_debug (3, "source info\n");
+#endif
+
+         while (src_ptr < ptr + rec_length)
+           {
+             int cmd = src_ptr[0], cmd_length, data;
+
+             switch (cmd)
+               {
+               case DST_S_C_SRC_DECLFILE:
+                 {
+                   unsigned int fileid
+                     = bfd_getl16 (src_ptr + DST_S_W_SRC_DF_FILEID);
+                   char *filename
+                     = _bfd_vms_save_counted_string (src_ptr
+                         + DST_S_B_SRC_DF_FILENAME);
+
+                   while (fileid >= module->file_table_count)
+                     {
+                       module->file_table_count *= 2;
+                       module->file_table
+                         = bfd_realloc (module->file_table,
+                                        module->file_table_count
+                                          * sizeof (struct fileinfo));
+                     }
+
+                   module->file_table [fileid].name = filename;
+                   module->file_table [fileid].srec = 1;
+                   cmd_length = src_ptr[DST_S_B_SRC_DF_LENGTH] + 2;
+#if VMS_DEBUG
+                   _bfd_vms_debug (4, "DST_S_C_SRC_DECLFILE: %d, %s\n",
+                                   fileid,
+                                   module->file_table [fileid].name);
+#endif
+                 }
+                 break;
+
+               case DST_S_C_SRC_DEFLINES_B:
+                 /* Perform the association and set the next higher index
+                    to the limit.  */
+                 data = src_ptr[DST_S_B_SRC_UNSBYTE];
+                 srec = (struct srecinfo *)
+                   bfd_zalloc (abfd, sizeof (struct srecinfo));
+                 srec->line = curr_srec->line + data;
+                 srec->srec = curr_srec->srec + data;
+                 srec->sfile = curr_srec->sfile;
+                 curr_srec->next = srec;
+                 curr_srec = srec;
+                 cmd_length = 2;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_SRC_DEFLINES_B: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_SRC_DEFLINES_W:
+                 /* Perform the association and set the next higher index
+                    to the limit.  */
+                 data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD);
+                 srec = (struct srecinfo *)
+                   bfd_zalloc (abfd, sizeof (struct srecinfo));
+                 srec->line = curr_srec->line + data;
+                 srec->srec = curr_srec->srec + data,
+                 srec->sfile = curr_srec->sfile;
+                 curr_srec->next = srec;
+                 curr_srec = srec;
+                 cmd_length = 3;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_SRC_DEFLINES_W: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_SRC_INCRLNUM_B:
+                 data = src_ptr[DST_S_B_SRC_UNSBYTE];
+                 curr_srec->line += data;
+                 cmd_length = 2;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_SRC_INCRLNUM_B: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_SRC_SETFILE:
+                 data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD);
+                 curr_srec->sfile = data;
+                 curr_srec->srec = module->file_table[data].srec;
+                 cmd_length = 3;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_SRC_SETFILE: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_SRC_SETLNUM_L:
+                 data = bfd_getl32 (src_ptr + DST_S_L_SRC_UNSLONG);
+                 curr_srec->line = data;
+                 cmd_length = 5;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_SRC_SETLNUM_L: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_SRC_SETLNUM_W:
+                 data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD);
+                 curr_srec->line = data;
+                 cmd_length = 3;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_SRC_SETLNUM_W: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_SRC_SETREC_L:
+                 data = bfd_getl32 (src_ptr + DST_S_L_SRC_UNSLONG);
+                 curr_srec->srec = data;
+                 module->file_table[curr_srec->sfile].srec = data;
+                 cmd_length = 5;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_SRC_SETREC_L: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_SRC_SETREC_W:
+                 data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD);
+                 curr_srec->srec = data;
+                 module->file_table[curr_srec->sfile].srec = data;
+                 cmd_length = 3;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_SRC_SETREC_W: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_SRC_FORMFEED:
+                 cmd_length = 1;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_SRC_FORMFEED\n");
+#endif
+                 break;
+
+               default:
+                 (*_bfd_error_handler) (_("unknown source command %d"),
+                                        cmd);
+                 cmd_length = 2;
+                 break;
+               }
+
+             src_ptr += cmd_length;
+           }
+         break;
+
+       case DST_S_C_LINE_NUM:
+         pcl_ptr = ptr + DST_S_C_LINE_NUM_HEADER_SIZE;
+
+#if VMS_DEBUG
+         _bfd_vms_debug (3, "line info\n");
+#endif
+
+         while (pcl_ptr < ptr + rec_length)
+           {
+             /* The command byte is signed so we must sign-extend it.  */
+             int cmd = ((signed char *)pcl_ptr)[0], cmd_length, data;
+
+             switch (cmd)
+               {
+               case DST_S_C_DELTA_PC_W:
+                 data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD);
+                 curr_pc += data;
+                 curr_linenum += 1;
+                 cmd_length = 3;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_DELTA_PC_W: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_DELTA_PC_L:
+                 data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG);
+                 curr_pc += data;
+                 curr_linenum += 1;
+                 cmd_length = 5;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_DELTA_PC_L: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_INCR_LINUM:
+                 data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE];
+                 curr_linenum += data;
+                 cmd_length = 2;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_INCR_LINUM: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_INCR_LINUM_W:
+                 data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD);
+                 curr_linenum += data;
+                 cmd_length = 3;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_INCR_LINUM_W: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_INCR_LINUM_L:
+                 data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG);
+                 curr_linenum += data;
+                 cmd_length = 5;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_INCR_LINUM_L: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_SET_LINUM_INCR:
+                 (*_bfd_error_handler)
+                   (_("DST_S_C_SET_LINUM_INCR not implemented"));
+                 cmd_length = 2;
+                 break;
+
+               case DST_S_C_SET_LINUM_INCR_W:
+                 (*_bfd_error_handler)
+                   (_("DST_S_C_SET_LINUM_INCR_W not implemented"));
+                 cmd_length = 3;
+                 break;
+
+               case DST_S_C_RESET_LINUM_INCR:
+                 (*_bfd_error_handler)
+                   (_("DST_S_C_RESET_LINUM_INCR not implemented"));
+                 cmd_length = 1;
+                 break;
+
+               case DST_S_C_BEG_STMT_MODE:
+                 (*_bfd_error_handler)
+                   (_("DST_S_C_BEG_STMT_MODE not implemented"));
+                 cmd_length = 1;
+                 break;
+
+               case DST_S_C_END_STMT_MODE:
+                 (*_bfd_error_handler)
+                   (_("DST_S_C_END_STMT_MODE not implemented"));
+                 cmd_length = 1;
+                 break;
+
+               case DST_S_C_SET_LINUM_B:
+                 data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE];
+                 curr_linenum = data;
+                 cmd_length = 2;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_SET_LINUM_B: %d\n", data);
+#endif
+                 break;
+       
+               case DST_S_C_SET_LINE_NUM:
+                 data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD);
+                 curr_linenum = data;
+                 cmd_length = 3;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_SET_LINE_NUM: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_SET_LINUM_L:
+                 data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG);
+                 curr_linenum = data;
+                 cmd_length = 5;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_SET_LINUM_L: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_SET_PC:
+                 (*_bfd_error_handler)
+                   (_("DST_S_C_SET_PC not implemented"));
+                 cmd_length = 2;
+                 break;
+
+               case DST_S_C_SET_PC_W:
+                 (*_bfd_error_handler)
+                   (_("DST_S_C_SET_PC_W not implemented"));
+                 cmd_length = 3;
+                 break;
+
+               case DST_S_C_SET_PC_L:
+                 (*_bfd_error_handler)
+                   (_("DST_S_C_SET_PC_L not implemented"));
+                 cmd_length = 5;
+                 break;
+
+               case DST_S_C_SET_STMTNUM:
+                 (*_bfd_error_handler)
+                   (_("DST_S_C_SET_STMTNUM not implemented"));
+                 cmd_length = 2;
+                 break;
+
+               case DST_S_C_TERM:
+                 data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE];
+                 curr_pc += data;
+                 cmd_length = 2;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_TERM: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_TERM_W:
+                 data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD);
+                 curr_pc += data;
+                 cmd_length = 3;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_TERM_W: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_TERM_L:
+                 data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG);
+                 curr_pc += data;
+                 cmd_length = 5;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_TERM_L: %d\n", data);
+#endif
+                 break;
+
+               case DST_S_C_SET_ABS_PC:
+                 data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG);
+                 curr_pc = data;
+                 cmd_length = 5;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "DST_S_C_SET_ABS_PC: 0x%x\n", data);
+#endif
+                 break;
+
+               default:
+                 if (cmd <= 0)
+                   {
+                     curr_pc -= cmd;
+                     curr_linenum += 1;
+                     cmd_length = 1;
+#if VMS_DEBUG
+                     _bfd_vms_debug (4, "bump pc to 0x%llx and line to %d\n",
+                                     curr_pc, curr_linenum);
+#endif
+                   }
+                 else
+                   {
+                     (*_bfd_error_handler) (_("unknown line command %d"),
+                                            cmd);
+                     cmd_length = 2;
+                   }
+                 break;
+               }
+
+             if ((curr_linenum != prev_linum && curr_pc != prev_pc)
+                 || cmd <= 0
+                 || cmd == DST_S_C_DELTA_PC_L
+                 || cmd == DST_S_C_DELTA_PC_W)
+               {
+                 line = (struct lineinfo *)
+                   bfd_zalloc (abfd, sizeof (struct lineinfo));
+                 line->address = curr_pc;
+                 line->line = curr_linenum;
+
+                 curr_line->next = line;
+                 curr_line = line;
+
+                 prev_linum = curr_linenum;
+                 prev_pc = curr_pc;
+#if VMS_DEBUG
+                 _bfd_vms_debug (4, "-> correlate pc 0x%llx with line %d\n",
+                                 curr_pc, curr_linenum);
+#endif
+               }
+
+             pcl_ptr += cmd_length;
+           }
+         break;
+
+       case 0x17: /* Undocumented type used by DEC C to declare equates.  */
+#if VMS_DEBUG
+         _bfd_vms_debug (3, "undocumented type 0x17\n");
+#endif
+         break;
+
+       default:
+#if VMS_DEBUG
+         _bfd_vms_debug (3, "ignoring record\n");
+#endif
+         break;
+
+       }
+
+      ptr += rec_length;
+    }
+
+  /* Finalize tables with EOL marker.  */
+  srec = (struct srecinfo *) bfd_zalloc (abfd, sizeof (struct srecinfo));
+  srec->line = (unsigned int) -1;
+  srec->srec = (unsigned int) -1;
+  curr_srec->next = srec;
+
+  line = (struct lineinfo *) bfd_zalloc (abfd, sizeof (struct lineinfo));
+  line->line = (unsigned int) -1;
+  line->address = (bfd_vma) -1;
+  curr_line->next = line;
+
+  /* Advertise that this module has been parsed.  This is needed
+     because parsing can be either performed at module creation
+     or deferred until debug info is consumed.  */
+  SET_MODULE_PARSED (module);
+}
+
+/* Build the list of modules for the specified BFD.  */
+
+static struct module *
+build_module_list (bfd *abfd)
+{
+  struct module *module, *list = NULL;
+  asection *dmt;
+
+  if ((dmt = bfd_get_section_by_name (abfd, "$DMT$")))
+    {
+      /* We have a DMT section so this must be an image.  Parse the
+        section and build the list of modules.  This is sufficient
+        since we can compute the start address and the end address
+        of every module from the section contents.  */
+      bfd_size_type size = bfd_get_section_size (dmt);
+      unsigned char *ptr, *end;
+
+      ptr = (unsigned char *) bfd_alloc (abfd, size);
+      if (! ptr)
+       return NULL;
+
+      if (! bfd_get_section_contents (abfd, dmt, ptr, 0, size))
+       return NULL;
+
+#if VMS_DEBUG
+      _bfd_vms_debug (2, "DMT\n");
+#endif
+
+      end = ptr + size;
+
+      while (ptr < end)
+       {
+         /* Each header declares a module with its start offset and size
+            of debug info in the DST section, as well as the count of
+            program sections (i.e. address spans) it contains.  */
+         int modbeg = bfd_getl32 (ptr + DBG_S_L_DMT_MODBEG);
+         int size = bfd_getl32 (ptr + DBG_S_L_DST_SIZE);
+         int count = bfd_getl16 (ptr + DBG_S_W_DMT_PSECT_COUNT);
+         ptr += DBG_S_C_DMT_HEADER_SIZE;
+
+#if VMS_DEBUG
+         _bfd_vms_debug (3, "module: modbeg = %d, size = %d, count = %d\n",
+                         modbeg, size, count);
+#endif
+
+         /* We create a 'module' structure for each program section since
+            we only support contiguous addresses in a 'module' structure.
+            As a consequence, the actual debug info in the DST section is
+            shared and can be parsed multiple times; that doesn't seem to
+            cause problems in practice.  */
+         while (count-- > 0)
+           {
+             int start = bfd_getl32 (ptr + DBG_S_L_DMT_PSECT_START);
+             int length = bfd_getl32 (ptr + DBG_S_L_DMT_PSECT_LENGTH);
+             module = new_module (abfd);
+             module->modbeg = modbeg;
+             module->size = size;
+             module->low = start;
+             module->high = start + length;
+             module->next = list;
+             list = module;
+             ptr += DBG_S_C_DMT_PSECT_SIZE;
+
+#if VMS_DEBUG
+             _bfd_vms_debug (4, "section: start = 0x%x, length = %d\n",
+                             start, length);
+#endif
+           }
+       }
+    }
+  else
+    {
+      /* We don't have a DMT section so this must be an object.  Parse
+        the module right now in order to compute its start address and
+        end address.  */
+      module = new_module (abfd);
+      parse_module (abfd, module, PRIV (dst_section)->contents,
+                   PRIV (dst_ptr_end) - PRIV (dst_section)->contents);
+      list = module;
+    }
+
+  return list;
+}
+
+/* Calculate and return the name of the source file and the line nearest
+   to the wanted location in the specified module.  */
+
+static bfd_boolean
+module_find_nearest_line (bfd *abfd, struct module *module, bfd_vma addr,
+                         const char **file, const char **func, 
+                         unsigned int *line)
+{
+  struct funcinfo *funcinfo;
+  struct lineinfo *lineinfo;
+  struct srecinfo *srecinfo;
+  bfd_boolean ret = FALSE;
+
+  /* Parse this module if that was not done at module creation.  */
+  if (! IS_MODULE_PARSED (module))
+    {
+      unsigned int size = module->size;
+      unsigned int modbeg = PRIV (dst_section)->filepos + module->modbeg;
+      unsigned char *buffer = (unsigned char *) bfd_malloc (module->size);
+
+      if (bfd_seek (abfd, modbeg, SEEK_SET) != 0
+         || bfd_bread (buffer, size, abfd) != size)
+       {
+         bfd_set_error (bfd_error_no_debug_section);
+         return FALSE;
+       }
+
+      parse_module (abfd, module, buffer, size);
+      free (buffer);
+    }
+
+  /* Find out the function (if any) that contains the address.  */
+  for (funcinfo = module->func_table; funcinfo; funcinfo = funcinfo->next)
+    if (addr >= funcinfo->low && addr <= funcinfo->high)
+      {
+        *func = funcinfo->name;
+       ret = TRUE;
+       break;
+      }
+
+  /* Find out the source file and the line nearest to the address.  */
+  for (lineinfo = module->line_table; lineinfo; lineinfo = lineinfo->next)
+    if (lineinfo->next && addr < lineinfo->next->address)
+      {
+       for (srecinfo = module->srec_table; srecinfo; srecinfo = srecinfo->next)
+         if (srecinfo->next && lineinfo->line < srecinfo->next->line)
+           {
+             if (srecinfo->sfile > 0)
+               {
+                 *file = module->file_table[srecinfo->sfile].name;
+                 *line = srecinfo->srec + lineinfo->line - srecinfo->line;
+               }
+             else
+               {
+                 *file = module->name;
+                 *line = lineinfo->line;
+               }
+             return TRUE;
+           }
+
+       break;
+      }
+
+  return ret;
+}
+
+/* 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.  */
+
+bfd_boolean
+_bfd_vms_find_nearest_dst_line (bfd *abfd, asection *section,
+                               asymbol **symbols ATTRIBUTE_UNUSED,
+                               bfd_vma offset, const char **file,
+                               const char **func, unsigned int *line)
+{
+  struct module *module;
+
+  /* What address are we looking for?  */
+  bfd_vma addr = section->vma + offset;
+
+  *file = NULL;
+  *func = NULL;
+  *line = 0;
+
+  if (PRIV (dst_section) == NULL)
+    return FALSE;
+
+  if (PRIV (modules) == NULL)
+    {
+      PRIV (modules) = build_module_list (abfd);
+      if (PRIV (modules) == NULL)
+        return FALSE;
+    }
+
+  for (module = PRIV (modules); module; module = module->next)
+    if (addr >= module->low && addr <= module->high)
+      return module_find_nearest_line (abfd, module, addr, file, func, line);
+
+  return FALSE;
+}
+
+/* Process EDBG/ETBT record.
+   Return 0 on success, -1 on error  */
+
+static int
+vms_slurp_debug (bfd *abfd)
+{
+  if (PRIV (dst_section) == NULL)
+    {
+      /* We have no way to find out beforehand how much debug info there
+        is in an object file, so pick an initial amount and grow it as
+        needed later.  */
+      flagword flags = SEC_HAS_CONTENTS | SEC_DEBUGGING | SEC_RELOC;
+      asection *section = bfd_make_section (abfd, "$DST$");
+      if (!section)
+       return -1;
+      section->size = 1024;
+      if (!bfd_set_section_flags (abfd, section, flags))
+       return -1;
+      section->contents = ((unsigned char *)
+                          bfd_zmalloc (section->size));
+      if (section->contents == NULL)
+       return -1;
+      section->filepos = (unsigned int)-1;
+      PRIV (dst_section) = section;
+    }
+
+  PRIV (image_section) = PRIV (dst_section);
+  PRIV (image_ptr) = PRIV (dst_section)->contents;
+  return _bfd_vms_slurp_tir (abfd, EOBJ_S_C_ETIR);
+}
+
+/* Process DBG/EDBG record.
+   Return 0 on success, -1 on error.  */
+
+int
+_bfd_vms_slurp_dbg (bfd *abfd, int objtype ATTRIBUTE_UNUSED)
+{
+#if VMS_DEBUG
+  _bfd_vms_debug (2, "DBG/EDBG\n");
+#endif
+
+  abfd->flags |= (HAS_DEBUG | HAS_LINENO);
+
+  return vms_slurp_debug (abfd);
+}
+
+/* Process TBT/ETBT record.
+   Return 0 on success, -1 on error.  */
+
+int
+_bfd_vms_slurp_tbt (bfd *abfd, int objtype ATTRIBUTE_UNUSED)
+{
+#if VMS_DEBUG
+  _bfd_vms_debug (2, "TBT/ETBT\n");
+#endif
+
+  abfd->flags |= HAS_LINENO;
+
+  return vms_slurp_debug (abfd);
+}
+
+/* Write DBG/EDBG record.  */
+
+int
+_bfd_vms_write_dbg (bfd *abfd ATTRIBUTE_UNUSED, int objtype ATTRIBUTE_UNUSED)
+{
+#if VMS_DEBUG
+  _bfd_vms_debug (2, "vms_write_dbg (%p, objtype)\n", abfd, objtype);
+#endif
+
+  return 0;
+}
+
+/* Write TBT/ETBT record.  */
+
+int
+_bfd_vms_write_tbt (bfd *abfd ATTRIBUTE_UNUSED, int objtype ATTRIBUTE_UNUSED)
+{
+#if VMS_DEBUG
+  _bfd_vms_debug (2, "vms_write_tbt (%p, %d)\n", abfd, objtype);
+#endif
+
+  return 0;
+}
index 9d0ffdb27361a4fc78d037832908eeaae960737a..21816587ef458f7a32add36a53ce3e52ea287b26 100644 (file)
@@ -1,7 +1,9 @@
-/* vms-misc.c -- Miscellaneous functions for VAX (openVMS/VAX) and
+/* vms-misc.c -- BFD back-end for VMS/VAX (openVMS/VAX) and
    EVAX (openVMS/Alpha) files.
    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2007, 2008  Free Software Foundation, Inc.
+   2007, 2008, 2009  Free Software Foundation, Inc.
+
+   Miscellaneous functions.
 
    Written by Klaus K"ampf (kkaempf@rmi.de)
 
 #include "libbfd.h"
 
 #include "vms.h"
-\f
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+static int hash_string PARAMS ((const char *));
+static asymbol *new_symbol PARAMS ((bfd *, char *));
+static void maybe_adjust_record_pointer_for_object PARAMS ((bfd *));
+static int vms_get_remaining_object_record PARAMS ((bfd *, int ));
+static int vms_get_remaining_image_record PARAMS ((bfd *, int ));
+
 #if VMS_DEBUG
 /* Debug functions.  */
 
-/* Debug function for all vms extensions
-   evaluates environment variable VMS_DEBUG for a
-   numerical value on the first call
-   all error levels below this value are printed
+/* Debug function for all vms extensions evaluates environment
+   variable VMS_DEBUG for a numerical value on the first call all
+   error levels below this value are printed:
 
-   levels:
+   Levels:
    1   toplevel bfd calls (functions from the bfd vector)
    2   functions called by bfd calls
    ...
    9   almost everything
 
-   level is also indentation level. Indentation is performed
+   Level is also indentation level. Indentation is performed
    if level > 0.  */
 
 void
@@ -167,22 +176,23 @@ _bfd_vms_hash_newfunc (struct bfd_hash_entry *entry,
 \f
 /* Object file input functions.  */
 
-/* Return type and length from record header (buf) on Alpha.  */
+/* Return type and size from record header (buf) on Alpha.  */
 
 void
 _bfd_vms_get_header_values (bfd * abfd ATTRIBUTE_UNUSED,
                            unsigned char *buf,
                            int *type,
-                           int *length)
+                           int *size)
 {
-  if (type != 0)
+  if (type)
     *type = bfd_getl16 (buf);
-  buf += 2;
-  if (length != 0)
-    *length = bfd_getl16 (buf);
+
+  if (size)
+    *size = bfd_getl16 (buf+2);
 
 #if VMS_DEBUG
-  vms_debug (10, "_bfd_vms_get_header_values type %x, length %x\n", (type?*type:0), (length?*length:0));
+  vms_debug (10, "_bfd_vms_get_header_values type %x, size %x\n",
+            type ? *type : 0, size ? *size : 0);
 #endif
 }
 
@@ -193,237 +203,341 @@ _bfd_vms_get_header_values (bfd * abfd ATTRIBUTE_UNUSED,
 
    The openVMS 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.
+   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
+   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.
+   record size 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, the DEC implementation of TCP/IP.
 
-   The vms format repeats the length at bytes 2 & 3 of every record.
+   The VMS format repeats the size 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
+   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.
+   Reading is always done in 2 steps:
+    1. first just the record header is read and the size extracted,
+    2. then the read buffer is adjusted and the remaining bytes are
+       read in.
+
+   All file I/O is done on even file positions.  */
 
-   All file i/o is always done on even file positions.  */
+#define VMS_OBJECT_ADJUSTMENT  2
+
+static void
+maybe_adjust_record_pointer_for_object (bfd *abfd)
+{
+  /* Set the file format once for all on the first invocation.  */
+  if (PRIV (file_format) == FF_UNKNOWN)
+    {
+      if (PRIV (vms_rec)[0] == PRIV (vms_rec)[4]
+         && PRIV (vms_rec)[1] == PRIV (vms_rec)[5])
+       PRIV (file_format) = FF_FOREIGN;
+      else
+       PRIV (file_format) = FF_NATIVE;
+    }
+
+  /* The adjustment is needed only in an Unix environment.  */
+  if (PRIV (file_format) == FF_FOREIGN)
+    PRIV (vms_rec) += VMS_OBJECT_ADJUSTMENT;
+}
+
+/* Get first record from file and return the file type.  */
 
 int
-_bfd_vms_get_record (bfd * abfd)
+_bfd_vms_get_first_record (bfd *abfd)
 {
-  int test_len, test_start, remaining;
-  unsigned char *vms_buf;
+  unsigned int test_len;
 
 #if VMS_DEBUG
-  vms_debug (8, "_bfd_vms_get_record\n");
+  vms_debug (8, "_bfd_vms_get_first_record\n");
 #endif
 
-  /* Minimum is 6 bytes on Alpha
-     (2 bytes length, 2 bytes record id, 2 bytes length repeated)
-
-     On the VAX there's no length information in the record
-     so start with OBJ_S_C_MAXRECSIZ.   */
+  if (PRIV (is_vax))
+    test_len = 0;
+  else
+    /* Minimum is 6 bytes for objects (2 bytes size, 2 bytes record id,
+       2 bytes size repeated) and 12 bytes for images (4 bytes major id,
+       4 bytes minor id, 4 bytes length).  */
+    test_len = 12;
 
+  /* Size the main buffer.  */
   if (PRIV (buf_size) == 0)
     {
-      bfd_size_type amt;
-
-      if (PRIV (is_vax))
-       {
-         amt = OBJ_S_C_MAXRECSIZ;
-         PRIV (file_format) = FF_VAX;
-       }
-      else
-       amt = 6;
-      PRIV (vms_buf) = bfd_malloc (amt);
+      /* On VAX there's no size information in the record, so
+        start with OBJ_S_C_MAXRECSIZ.  */
+      bfd_size_type amt = (test_len ? test_len : OBJ_S_C_MAXRECSIZ);
+      PRIV (vms_buf) = (unsigned char *) bfd_malloc (amt);
       PRIV (buf_size) = amt;
     }
 
-  vms_buf = PRIV (vms_buf);
+  /* Initialize the record pointer.  */
+  PRIV (vms_rec) = PRIV (vms_buf);
 
-  if (vms_buf == 0)
-    return -1;
-
-  switch (PRIV (file_format))
+  /* We only support modules on VAX.  */
+  if (PRIV (is_vax))
     {
-    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;
-
-    default:
-    case FF_VAX:
-      test_len = 0;
-      test_start = 0;
-      break;
+      if (vms_get_remaining_object_record (abfd, test_len) <= 0)
+       return FT_UNKNOWN;
+
+#if VMS_DEBUG
+      vms_debug (2, "file type is VAX module\n");
+#endif
+
+      return FT_MODULE;
     }
 
-  /* Skip odd alignment byte.  */
+  if (bfd_bread (PRIV (vms_buf), test_len, abfd) != test_len)
+    {
+      bfd_set_error (bfd_error_file_truncated);
+      return FT_UNKNOWN;
+    }
 
-  if (bfd_tell (abfd) & 1)
+  /* Is it an image?  */
+  if ((bfd_getl32 (PRIV (vms_rec)) == EIHD_S_K_MAJORID)
+      && (bfd_getl32 (PRIV (vms_rec) + 4) == EIHD_S_K_MINORID))
     {
-      if (bfd_bread (PRIV (vms_buf), (bfd_size_type) 1, abfd) != 1)
-       {
-         bfd_set_error (bfd_error_file_truncated);
-         return 0;
-       }
+      if (vms_get_remaining_image_record (abfd, test_len) <= 0)
+       return FT_UNKNOWN;
+
+#if VMS_DEBUG
+      vms_debug (2, "file type is image\n");
+#endif
+
+      return FT_IMAGE;
     }
 
-  /* Read the record header on Alpha.  */
-  if ((test_len != 0)
-      && (bfd_bread (PRIV (vms_buf), (bfd_size_type) test_len, abfd)
-         != (bfd_size_type) test_len))
+  /* Assume it's a module and adjust record pointer if necessary.  */
+  maybe_adjust_record_pointer_for_object (abfd);
+
+  /* But is it really a module?  */
+  if (bfd_getl16 (PRIV (vms_rec)) <= EOBJ_S_C_MAXRECTYP
+      && bfd_getl16 (PRIV (vms_rec) + 2) <= EOBJ_S_C_MAXRECSIZ)
     {
-      bfd_set_error (bfd_error_file_truncated);
-      return 0;
+      if (vms_get_remaining_object_record (abfd, test_len) <= 0)
+       return FT_UNKNOWN;
+
+#if VMS_DEBUG
+      vms_debug (2, "file type is module\n");
+#endif
+
+      return FT_MODULE;
     }
 
-  /* Check file format on first call.  */
-  if (PRIV (file_format) == FF_UNKNOWN)
-    {                                          /* Record length repeats ?  */
-      if (vms_buf[0] == vms_buf[4]
-         && vms_buf[1] == vms_buf[5])
+#if VMS_DEBUG
+  vms_debug (2, "file type is unknown\n");
+#endif
+
+  return FT_UNKNOWN;
+}
+
+/* Implement step #1 of the object record reading procedure.
+   Return the record type or -1 on failure.  */
+
+int
+_bfd_vms_get_object_record (bfd *abfd)
+{
+  unsigned int test_len;
+  int type;
+
+#if VMS_DEBUG
+  vms_debug (8, "_bfd_vms_get_obj_record\n");
+#endif
+
+  if (PRIV (is_vax))
+    test_len = 0;
+  else
+    {
+      /* See _bfd_vms_get_first_record.  */
+      test_len = 6;
+
+      /* Skip odd alignment byte.  */
+      if (bfd_tell (abfd) & 1)
        {
-         PRIV (file_format) = FF_FOREIGN;      /* Y: foreign environment.  */
-         test_start = 2;
+         if (bfd_bread (PRIV (vms_buf), 1, abfd) != 1)
+           {
+             bfd_set_error (bfd_error_file_truncated);
+             return -1;
+           }
        }
-      else
+
+      /* Read the record header  */
+      if (bfd_bread (PRIV (vms_buf), test_len, abfd) != test_len)
        {
-         PRIV (file_format) = FF_NATIVE;       /* N: native environment.  */
-         test_start = 0;
+         bfd_set_error (bfd_error_file_truncated);
+         return -1;
        }
+
+      /* Reset the record pointer.  */
+      PRIV (vms_rec) = PRIV (vms_buf);
+      maybe_adjust_record_pointer_for_object (abfd);
     }
 
+  if (vms_get_remaining_object_record (abfd, test_len) <= 0)
+    return -1;
+
+  if (PRIV (is_vax))
+    type = PRIV (vms_rec) [0];
+  else
+    type = bfd_getl16 (PRIV (vms_rec));
+
+#if VMS_DEBUG
+  vms_debug (8, "_bfd_vms_get_obj_record: rec %p, size %d, type %d\n",
+             PRIV (vms_rec), PRIV (rec_size), type);
+#endif
+
+  return type;
+}
+
+/* Implement step #2 of the object record reading procedure.
+   Return the size of the record or 0 on failure.  */
+
+static int
+vms_get_remaining_object_record (bfd *abfd, int read_so_far)
+{
+#if VMS_DEBUG
+  vms_debug (8, "vms_get_remaining_obj_record\n");
+#endif
+
   if (PRIV (is_vax))
     {
-      PRIV (rec_length) = bfd_bread (vms_buf, (bfd_size_type) PRIV (buf_size),
-                                    abfd);
-      if (PRIV (rec_length) <= 0)
+      if (read_so_far != 0)
+        abort ();
+
+      PRIV (rec_size) = bfd_bread (PRIV (vms_buf), PRIV (buf_size), abfd);
+
+      if (PRIV (rec_size) <= 0)
        {
          bfd_set_error (bfd_error_file_truncated);
          return 0;
        }
-      PRIV (vms_rec) = vms_buf;
+
+      /* Reset the record pointer.  */
+      PRIV (vms_rec) = PRIV (vms_buf);
     }
   else
     {
-      /* Alpha.   */
-      /* Extract vms record length.  */
+      unsigned int to_read;
 
-      _bfd_vms_get_header_values (abfd, vms_buf + test_start, NULL,
-                                 & PRIV (rec_length));
+      /* Extract record size.  */
+      PRIV (rec_size) = bfd_getl16 (PRIV (vms_rec) + 2);
 
-      if (PRIV (rec_length) <= 0)
+      if (PRIV (rec_size) <= 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)
+      if (PRIV (rec_size) > EOBJ_S_C_MAXRECSIZ)
        {
          bfd_set_error (bfd_error_file_truncated);
          return 0;
        }
 
-      /* Adjust the buffer.  */
+      /* Take into account object adjustment.  */
+      to_read = PRIV (rec_size);
+      if (PRIV (file_format) == FF_FOREIGN)
+       to_read += VMS_OBJECT_ADJUSTMENT;
 
-      if (PRIV (rec_length) > PRIV (buf_size))
+      /* Adjust the buffer.  */
+      if (to_read > PRIV (buf_size))
        {
-         PRIV (vms_buf) = bfd_realloc_or_free (vms_buf,
-                                       (bfd_size_type) PRIV (rec_length));
-         vms_buf = PRIV (vms_buf);
-         if (vms_buf == 0)
-           return -1;
-         PRIV (buf_size) = PRIV (rec_length);
+         PRIV (vms_buf)
+           = (unsigned char *) bfd_realloc (PRIV (vms_buf), to_read);
+         if (PRIV (vms_buf) == NULL)
+           return 0;
+         PRIV (buf_size) = to_read;
        }
 
       /* Read the remaining record.  */
-      remaining = PRIV (rec_length) - test_len + test_start;
+      to_read -= read_so_far;
 
 #if VMS_DEBUG
-      vms_debug (10, "bfd_bread remaining %d\n", remaining);
+      vms_debug (8, "vms_get_remaining_obj_record: to_read %d\n", to_read);
 #endif
-      if (bfd_bread (vms_buf + test_len, (bfd_size_type) remaining, abfd) !=
-         (bfd_size_type) remaining)
+
+      if (bfd_bread (PRIV (vms_buf) + read_so_far, to_read, abfd) != to_read)
        {
          bfd_set_error (bfd_error_file_truncated);
          return 0;
        }
-      PRIV (vms_rec) = vms_buf + test_start;
+
+      /* Reset the record pointer.  */
+      PRIV (vms_rec) = PRIV (vms_buf);
+      maybe_adjust_record_pointer_for_object (abfd);
     }
 
 #if VMS_DEBUG
-  vms_debug (11, "bfd_bread rec_length %d\n", PRIV (rec_length));
+  vms_debug (8, "vms_get_remaining_obj_record: size %d\n", PRIV (rec_size));
 #endif
 
-  return PRIV (rec_length);
+  return PRIV (rec_size);
 }
 
-/* Get next vms record from file
-   update vms_rec and rec_length to new (remaining) values.  */
+/* Implement step #2 of the record reading procedure for images.
+   Return the size of the record or 0 on failure.  */
 
-int
-_bfd_vms_next_record (bfd * abfd)
+static int
+vms_get_remaining_image_record (bfd *abfd, int read_so_far)
 {
-#if VMS_DEBUG
-  vms_debug (8, "_bfd_vms_next_record (len %d, size %d)\n",
-             PRIV (rec_length), PRIV (rec_size));
-#endif
+  unsigned int to_read;
+  int remaining;
 
-  if (PRIV (rec_length) > 0)
-    PRIV (vms_rec) += PRIV (rec_size);
-  else
+  /* Extract record size.  */
+  PRIV (rec_size) = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_SIZE);
+
+  if (PRIV (rec_size) > PRIV (buf_size))
     {
-      if (_bfd_vms_get_record (abfd) <= 0)
-       return -1;
+      PRIV (vms_buf) = bfd_realloc (PRIV (vms_buf), PRIV (rec_size));
+
+      if (PRIV (vms_buf) == NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return 0;
+       }
+
+      PRIV (buf_size) = PRIV (rec_size);
     }
 
-  if (!PRIV (vms_rec) || !PRIV (vms_buf)
-      || PRIV (vms_rec) >= (PRIV (vms_buf) + PRIV (buf_size)))
-    return -1;
+  /* Read the remaining record.  */
+  remaining = PRIV (rec_size) - read_so_far;
+  to_read = MIN (VMS_BLOCK_SIZE - read_so_far, remaining);
 
-  if (PRIV (is_vax))
+  while (remaining > 0)
     {
-      PRIV (rec_type) = *(PRIV (vms_rec));
-      PRIV (rec_size) = PRIV (rec_length);
-    }
-  else
-    _bfd_vms_get_header_values (abfd, PRIV (vms_rec), &PRIV (rec_type),
-                               &PRIV (rec_size));
+      if (bfd_bread (PRIV (vms_buf) + read_so_far, to_read, abfd) != to_read)
+       {
+         bfd_set_error (bfd_error_file_truncated);
+         return 0;
+       }
 
-  PRIV (rec_length) -= PRIV (rec_size);
+      read_so_far += to_read;
+      remaining -= to_read;
 
-#if VMS_DEBUG
-  vms_debug (8, "_bfd_vms_next_record: rec %p, size %d, length %d, type %d\n",
-             PRIV (vms_rec), PRIV (rec_size), PRIV (rec_length),
-             PRIV (rec_type));
-#endif
+      /* Eat trailing 0xff's.  */
+      if (remaining > 0)
+       while (PRIV (vms_buf) [read_so_far - 1] == 0xff)
+         read_so_far--;
+
+      to_read = MIN (VMS_BLOCK_SIZE, remaining);
+    }
 
-  return PRIV (rec_type);
+  /* Reset the record pointer.  */
+  PRIV (vms_rec) = PRIV (vms_buf);
+
+  return PRIV (rec_size);
 }
-\f
-/* Copy sized string (string with fixed length) to new allocated area
-   size is string length (size of record)  */
+
+/* Copy sized string (string with fixed size) to new allocated area
+   size is string size (size of record)  */
 
 char *
 _bfd_vms_save_sized_string (unsigned char *str, int size)
@@ -438,8 +552,8 @@ _bfd_vms_save_sized_string (unsigned char *str, int size)
   return newstr;
 }
 
-/* Copy counted string (string with length at first byte) to new allocated area
-   ptr points to length byte on entry  */
+/* Copy counted string (string with size at first byte) to new allocated area
+   ptr points to size byte on entry  */
 
 char *
 _bfd_vms_save_counted_string (unsigned char *ptr)
@@ -501,83 +615,12 @@ _bfd_vms_pop (bfd * abfd, int *psect)
   return value;
 }
 \f
-/* 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 vms_section structure to vms_section_table
-   - forward chaining -.  */
-
-static vms_section *
-add_new_contents (bfd * abfd, sec_ptr section)
-{
-  vms_section *sptr, *newptr;
-
-  sptr = PRIV (vms_section_table)[section->index];
-  if (sptr != NULL)
-    return sptr;
-
-  newptr = bfd_alloc (abfd, (bfd_size_type) sizeof (vms_section));
-  if (newptr == NULL)
-    return NULL;
-  newptr->contents = bfd_alloc (abfd, section->size);
-  if (newptr->contents == NULL)
-    return NULL;
-  newptr->offset = 0;
-  newptr->size = section->size;
-  newptr->next = 0;
-  PRIV (vms_section_table)[section->index] = newptr;
-  return newptr;
-}
-
-/* Save section data & offset to a vms_section structure
-   vms_section_table[] holds the vms_section chain.  */
-
-bfd_boolean
-_bfd_save_vms_section (bfd * abfd,
-                      sec_ptr section,
-                      const void * data,
-                      file_ptr offset,
-                      bfd_size_type count)
-{
-  vms_section *sptr;
-
-  if (section->index >= VMS_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 vms_section pointer to saved contents for section # index  */
-
-vms_section *
-_bfd_get_vms_section (bfd * abfd, int index)
-{
-  if (index >=  VMS_SECTION_COUNT)
-    {
-      bfd_set_error (bfd_error_nonrepresentable_section);
-      return NULL;
-    }
-  return PRIV (vms_section_table)[index];
-}
-\f
 /* 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).   */
+   write 2 bytes header type (ommitted if rechead == -1).  */
 
 void
 _bfd_vms_output_begin (bfd * abfd, int rectype, int rechead)
@@ -691,18 +734,11 @@ _bfd_vms_output_flush (bfd * abfd)
 
   if (PRIV (push_level) == 0)
     {
-      if (0
-#ifndef VMS
-         /* Write length first, see FF_FOREIGN in the input routines.  */
-         || fwrite (PRIV (output_buf) + 2, 2, 1,
-                    (FILE *) abfd->iostream) != 1
-#endif
-         || (real_size != 0
-             && fwrite (PRIV (output_buf), (size_t) real_size, 1,
-                        (FILE *) abfd->iostream) != 1))
-       /* FIXME: Return error status.  */
-       abort ();
-
+      /* File is open in undefined (UDF) format on VMS, but ultimately will be
+        converted to variable length (VAR) format.  VAR format has a length
+        word first which must be explicitly output in UDF format.  */
+      bfd_bwrite (PRIV (output_buf) + 2, 2, abfd);
+      bfd_bwrite (PRIV (output_buf), (size_t) real_size, abfd);
       PRIV (output_size) = 0;
     }
   else
@@ -948,7 +984,7 @@ new_symbol (bfd * abfd, char *name)
   if (symbol == 0)
     return symbol;
   symbol->name = name;
-  symbol->section = bfd_make_section (abfd, BFD_UND_SECTION_NAME);
+  symbol->section = (asection *)(unsigned long)-1;
 
   return symbol;
 }
index e6ec6ebcc37610f3d32241517168072e6d1d1a2f..5bc61da87aa748f6d79b0d23c425129502518c14 100644 (file)
@@ -1,12 +1,12 @@
 /* vms-tir.c -- BFD back-end for VAX (openVMS/VAX) and
    EVAX (openVMS/Alpha) files.
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2007, 2008
-   Free Software Foundation, Inc.
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2007,
+   2008, 2009 Free Software Foundation, Inc.
 
    TIR record handling functions
    ETIR record handling functions
 
-   go and read the openVMS linker manual (esp. appendix B)
+   Go and read the openVMS linker manual (esp. appendix B)
    if you don't know what's going on here :-)
 
    Written by Klaus K"ampf (kkaempf@rmi.de)
@@ -26,7 +26,6 @@
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
    MA 02110-1301, USA.  */
 
-
 /* The following type abbreviations are used:
 
        cs      counted string (ascii string with length byte)
 #include "bfdlink.h"
 #include "libbfd.h"
 #include "vms.h"
+
+static int check_section (bfd *, int);
+static void image_set_ptr (bfd *abfd, int psect, uquad offset);
+static void image_inc_ptr (bfd *abfd, uquad offset);
+static void dst_define_location (bfd *abfd, uquad loc);
+static void dst_restore_location (bfd *abfd, uquad loc);
+static unsigned int dst_retrieve_location (bfd *abfd, uquad loc);
+static void dst_check_allocation (bfd *abfd, unsigned int size);
+static void image_dump (bfd *abfd, unsigned char *ptr, int size, int offset);
+static void image_write_b (bfd *abfd, unsigned int value);
+static void image_write_w (bfd *abfd, unsigned int value);
+static void image_write_l (bfd *abfd, unsigned long value);
+static void image_write_q (bfd *abfd, uquad value);
+static bfd_boolean etir_sta (bfd *, int, unsigned char *, int *);
+static bfd_boolean etir_sto (bfd *, int, unsigned char *, int *);
+static bfd_boolean etir_opr (bfd *, int, unsigned char *, int *);
+static bfd_boolean etir_ctl (bfd *, int, unsigned char *, int *);
+static bfd_boolean etir_stc (bfd *, int, unsigned char *, int *);
+static asection *new_section (bfd *, int);
+static int alloc_section (bfd *, unsigned int);
+static int etir_cmd (bfd *, int, unsigned char *, int *);
+static int analyze_tir (bfd *, unsigned char *, unsigned int);
+static int analyze_etir (bfd *, unsigned char *, unsigned int);
+static unsigned char *tir_opr (bfd *, unsigned char *);
+static const char *tir_cmd_name (int);
+static const char *cmd_name (int);
+
 \f
 static int
 check_section (bfd * abfd, int size)
@@ -92,6 +118,77 @@ image_inc_ptr (bfd * abfd, uquad offset)
   PRIV (image_ptr) += offset;
 }
 
+/* Save current DST location counter under specified index.  */
+
+static void
+dst_define_location (bfd *abfd, uquad loc)
+{
+  asection *dst_section = PRIV (dst_section);
+
+#if VMS_DEBUG
+  _bfd_vms_debug (4, "dst_define_location (%d)\n", (int)loc);
+#endif
+
+  /* Grow the ptr offset table if necessary.  */
+  if (loc + 1 > PRIV (dst_ptr_offsets_count))
+    {
+      PRIV (dst_ptr_offsets) = bfd_realloc (PRIV (dst_ptr_offsets),
+                                          (loc + 1) * sizeof (unsigned int));
+      PRIV (dst_ptr_offsets_count) = loc + 1;
+    }
+
+  PRIV (dst_ptr_offsets)[loc] = PRIV (image_ptr) - dst_section->contents;
+}
+
+/* Restore saved DST location counter from specified index.  */
+
+static void
+dst_restore_location (bfd *abfd, uquad loc)
+{
+  asection *dst_section = PRIV (dst_section);
+
+#if VMS_DEBUG
+  _bfd_vms_debug (4, "dst_restore_location (%d)\n", (int)loc);
+#endif
+
+  PRIV (image_ptr) = dst_section->contents + PRIV (dst_ptr_offsets)[loc];
+}
+
+/* Retrieve saved DST location counter from specified index.  */
+
+static unsigned int
+dst_retrieve_location (bfd *abfd, uquad loc)
+{
+#if VMS_DEBUG
+  _bfd_vms_debug (4, "dst_retrieve_location (%d)\n", (int)loc);
+#endif
+
+  return PRIV (dst_ptr_offsets)[loc];
+}
+
+/* Check that the DST section is big enough for the specified
+   amount of bytes.  */
+
+static void
+dst_check_allocation (bfd *abfd, unsigned int size)
+{
+  asection *dst_section = PRIV (dst_section);
+
+  bfd_size_type used = PRIV (image_ptr) - dst_section->contents;
+  bfd_size_type left = dst_section->size - used;
+
+  /* Grow the DST section as necessary */
+  if (size > left)
+    {
+      dst_section->size *= 2;
+      dst_section->contents
+       = bfd_realloc (dst_section->contents, dst_section->size);
+      PRIV (image_ptr) = dst_section->contents + used;
+
+      dst_check_allocation (abfd, size);
+    }
+}
+
 /* Dump multiple bytes to section image.  */
 
 static void
@@ -109,6 +206,9 @@ image_dump (bfd * abfd,
   if (PRIV (is_vax) && check_section (abfd, size))
     return;
 
+  if (PRIV (dst_section))
+    dst_check_allocation (abfd, size);
+
   while (size-- > 0)
     *PRIV (image_ptr)++ = *ptr++;
 }
@@ -125,6 +225,9 @@ image_write_b (bfd * abfd, unsigned int value)
   if (PRIV (is_vax) && check_section (abfd, 1))
     return;
 
+  if (PRIV (dst_section))
+    dst_check_allocation (abfd, 1);
+
   *PRIV (image_ptr)++ = (value & 0xff);
 }
 
@@ -140,6 +243,9 @@ image_write_w (bfd * abfd, unsigned int value)
   if (PRIV (is_vax) && check_section (abfd, 2))
     return;
 
+  if (PRIV (dst_section))
+    dst_check_allocation (abfd, 2);
+
   bfd_putl16 ((bfd_vma) value, PRIV (image_ptr));
   PRIV (image_ptr) += 2;
 }
@@ -156,6 +262,9 @@ image_write_l (bfd * abfd, unsigned long value)
   if (PRIV (is_vax) && check_section (abfd, 4))
     return;
 
+  if (PRIV (dst_section))
+    dst_check_allocation (abfd, 4);
+
   bfd_putl32 ((bfd_vma) value, PRIV (image_ptr));
   PRIV (image_ptr) += 4;
 }
@@ -172,6 +281,9 @@ image_write_q (bfd * abfd, uquad value)
   if (PRIV (is_vax) && check_section (abfd, 8))
     return;
 
+  if (PRIV (dst_section))
+    dst_check_allocation (abfd, 8);
+
   bfd_putl64 (value, PRIV (image_ptr));
   PRIV (image_ptr) += 8;
 }
@@ -182,6 +294,8 @@ cmd_name (int cmd)
   switch (cmd)
     {
     case ETIR_S_C_STA_GBL: return "ETIR_S_C_STA_GBL";
+    case ETIR_S_C_STA_LW: return "ETIR_S_C_STA_LW";
+    case ETIR_S_C_STA_QW: return "ETIR_S_C_STA_QW";
     case ETIR_S_C_STA_PQ: return "ETIR_S_C_STA_PQ";
     case ETIR_S_C_STA_LI: return "ETIR_S_C_STA_LI";
     case ETIR_S_C_STA_MOD: return "ETIR_S_C_STA_MOD";
@@ -192,10 +306,16 @@ cmd_name (int cmd)
     case ETIR_S_C_STO_CA: return "ETIR_S_C_STO_CA";
     case ETIR_S_C_STO_RB: return "ETIR_S_C_STO_RB";
     case ETIR_S_C_STO_AB: return "ETIR_S_C_STO_AB";
+    case ETIR_S_C_STO_OFF: return "ETIR_S_C_STO_OFF";
+    case ETIR_S_C_STO_IMM: return "ETIR_S_C_STO_IMM";
+    case ETIR_S_C_STO_IMMR: return "ETIR_S_C_STO_IMMR";
+    case ETIR_S_C_STO_LW: return "ETIR_S_C_STO_LW";
+    case ETIR_S_C_STO_QW: return "ETIR_S_C_STO_QW";
     case ETIR_S_C_STO_GBL_LW: return "ETIR_S_C_STO_GBL_LW";
     case ETIR_S_C_STO_LP_PSB: return "ETIR_S_C_STO_LP_PSB";
     case ETIR_S_C_STO_HINT_GBL: return "ETIR_S_C_STO_HINT_GBL";
     case ETIR_S_C_STO_HINT_PS: return "ETIR_S_C_STO_HINT_PS";
+    case ETIR_S_C_OPR_ADD: return "ETIR_S_C_OPR_ADD";
     case ETIR_S_C_OPR_INSV: return "ETIR_S_C_OPR_INSV";
     case ETIR_S_C_OPR_USH: return "ETIR_S_C_OPR_USH";
     case ETIR_S_C_OPR_ROT: return "ETIR_S_C_OPR_ROT";
@@ -215,34 +335,41 @@ cmd_name (int cmd)
     case ETIR_S_C_STC_BOH_GBL: return "ETIR_S_C_STC_BOH_GBL";
     case ETIR_S_C_STC_BOH_PS: return "ETIR_S_C_STC_BOH_PS";
     case ETIR_S_C_STC_NBH_GBL: return "ETIR_S_C_STC_NBH_GBL";
+    case ETIR_S_C_CTL_SETRB: return "ETIR_S_C_CTL_SETRB";
+    case ETIR_S_C_STC_LP_PSB: return "ETIR_S_C_STC_LP_PSB";
+    case ETIR_S_C_CTL_DFLOC: return "ETIR_S_C_CTL_DFLOC";
+    case ETIR_S_C_CTL_STLOC: return "ETIR_S_C_CTL_STLOC";
+    case ETIR_S_C_CTL_STKDL: return "ETIR_S_C_CTL_STKDL";
 
     default:
       /* These names have not yet been added to this switch statement.  */
-      abort ();
+      (*_bfd_error_handler) (_("unknown ETIR command %d"), cmd);
     }
+
+  return NULL;
 }
 #define HIGHBIT(op) ((op & 0x80000000L) == 0x80000000L)
 
 /* etir_sta
 
-   vms stack commands
+   Vms stack commands.
 
-   handle sta_xxx commands in etir section
-   ptr points to data area in record
+   Handle sta_xxx commands in etir section,
+   ptr points to data area in record.
 
-   see table B-8 of the openVMS linker manual.  */
+   See table B-8 of the openVMS linker manual.  */
 
 static bfd_boolean
-etir_sta (bfd * abfd, int cmd, unsigned char *ptr)
+etir_sta (bfd *abfd, int cmd, unsigned char *ptr, int *quarter_relocs)
 {
 #if VMS_DEBUG
   _bfd_vms_debug (5, "etir_sta %d/%x\n", cmd, cmd);
-  _bfd_hexdump (8, ptr, 16, (int) ptr);
+  _bfd_hexdump (8, ptr, 16, (long) ptr);
 #endif
 
   switch (cmd)
     {
-      /* stack global
+      /* Stack global
         arg: cs        symbol name
 
         stack 32 bit value of symbol (high bits set to 0).  */
@@ -265,37 +392,50 @@ etir_sta (bfd * abfd, int cmd, unsigned char *ptr)
        else
          _bfd_vms_push (abfd, (uquad) (entry->symbol->value), -1);
       }
+      *quarter_relocs = 1;
       break;
 
-      /* stack longword
+      /* Stack longword
         arg: lw        value
 
         stack 32 bit value, sign extend to 64 bit.  */
     case ETIR_S_C_STA_LW:
       _bfd_vms_push (abfd, (uquad) bfd_getl32 (ptr), -1);
+      /* This one is special as it is both part of the section header
+         and of the ALPHA_R_REFLONG relocation.  */
+      if (bfd_getl16 (ptr - 4 + bfd_getl16 (ptr - 2)) == ETIR_S_C_CTL_DFLOC)
+       *quarter_relocs = 0;
+      else if (*quarter_relocs)
+       *quarter_relocs += 1;
+      else
+       *quarter_relocs = 2;
       break;
 
-      /* stack global
+      /* Stack quadword
         arg: qw        value
 
         stack 64 bit value of symbol.  */
     case ETIR_S_C_STA_QW:
       _bfd_vms_push (abfd, (uquad) bfd_getl64 (ptr), -1);
+      if (*quarter_relocs)
+       *quarter_relocs += 1;
+      else
+       *quarter_relocs = 2;
       break;
 
-      /* stack psect base plus quadword offset
+      /* Stack psect base plus quadword offset
         arg: lw        section index
         qw     signed quadword offset (low 32 bits)
 
-        stack qw argument and section index
+        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;
-       unsigned int psect;
+       int psect;
 
        psect = bfd_getl32 (ptr);
-       if (psect >= PRIV (section_count))
+       if ((unsigned int) psect >= PRIV (section_count))
          {
            (*_bfd_error_handler) (_("bad section index in %s"),
                                   cmd_name (cmd));
@@ -305,23 +445,31 @@ etir_sta (bfd * abfd, int cmd, unsigned char *ptr)
        dummy = bfd_getl64 (ptr + 4);
        _bfd_vms_push (abfd, dummy, (int) psect);
       }
+      /* This one is special as it is both part of the section header
+         and of the ALPHA_R_REFLONG and ALPHA_R_REFQUAD relocations.  */
+      if (bfd_getl16 (ptr - 4 + bfd_getl16 (ptr - 2)) == ETIR_S_C_CTL_SETRB)
+       *quarter_relocs = 0;
+      else
+       *quarter_relocs = 2;
       break;
 
     case ETIR_S_C_STA_LI:
     case ETIR_S_C_STA_MOD:
     case ETIR_S_C_STA_CKARG:
       (*_bfd_error_handler) (_("unsupported STA cmd %s"), cmd_name (cmd));
+      *quarter_relocs = 0;
       return FALSE;
-      break;
 
     default:
       (*_bfd_error_handler) (_("reserved STA cmd %d"), cmd);
+      *quarter_relocs = 0;
       return FALSE;
-      break;
     }
+
 #if VMS_DEBUG
   _bfd_vms_debug (5, "etir_sta true\n");
 #endif
+
   return TRUE;
 }
 
@@ -335,14 +483,14 @@ etir_sta (bfd * abfd, int cmd, unsigned char *ptr)
    see table B-9 of the openVMS linker manual.  */
 
 static bfd_boolean
-etir_sto (bfd * abfd, int cmd, unsigned char *ptr)
+etir_sto (bfd *abfd, int cmd, unsigned char *ptr, int *quarter_relocs)
 {
   uquad dummy;
   int psect;
 
 #if VMS_DEBUG
   _bfd_vms_debug (5, "etir_sto %d/%x\n", cmd, cmd);
-  _bfd_hexdump (8, ptr, 16, (int) ptr);
+  _bfd_hexdump (8, ptr, 16, (long) ptr);
 #endif
 
   switch (cmd)
@@ -353,6 +501,7 @@ etir_sto (bfd * abfd, int cmd, unsigned char *ptr)
       dummy = _bfd_vms_pop (abfd, &psect);
       /* FIXME: check top bits.  */
       image_write_b (abfd, (unsigned int) dummy & 0xff);
+      *quarter_relocs = 0;
       break;
 
       /* Store word: pop stack, write word
@@ -361,6 +510,7 @@ etir_sto (bfd * abfd, int cmd, unsigned char *ptr)
       dummy = _bfd_vms_pop (abfd, &psect);
       /* FIXME: check top bits */
       image_write_w (abfd, (unsigned int) dummy & 0xffff);
+      *quarter_relocs = 0;
       break;
 
       /* Store longword: pop stack, write longword
@@ -370,6 +520,10 @@ etir_sto (bfd * abfd, int cmd, unsigned char *ptr)
       dummy += (PRIV (sections)[psect])->vma;
       /* FIXME: check top bits.  */
       image_write_l (abfd, (unsigned int) dummy & 0xffffffff);
+      if (*quarter_relocs == 2)
+       *quarter_relocs = 4;
+      else
+       *quarter_relocs += 1;
       break;
 
       /* Store quadword: pop stack, write quadword
@@ -379,6 +533,10 @@ etir_sto (bfd * abfd, int cmd, unsigned char *ptr)
       dummy += (PRIV (sections)[psect])->vma;
       /* FIXME: check top bits.  */
       image_write_q (abfd, dummy);
+      if (*quarter_relocs == 2)
+       *quarter_relocs = 4;
+      else
+       *quarter_relocs += 1;
       break;
 
       /* Store immediate repeated: pop stack for repeat count
@@ -393,6 +551,7 @@ etir_sto (bfd * abfd, int cmd, unsigned char *ptr)
        while (dummy-- > 0)
          image_dump (abfd, ptr+4, size, 0);
       }
+      *quarter_relocs = 0;
       break;
 
       /* Store global: write symbol value
@@ -406,15 +565,13 @@ etir_sto (bfd * abfd, int cmd, unsigned char *ptr)
        entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table),
                                                      name, FALSE, FALSE);
        if (entry == NULL)
-         {
-           (*_bfd_error_handler) (_("%s: no symbol \"%s\""),
-                                  cmd_name (cmd), name);
-           return FALSE;
-         }
+         /* FIXME, reloc.  */
+         image_write_q (abfd, (uquad) (0));
        else
          /* FIXME, reloc.  */
          image_write_q (abfd, (uquad) (entry->symbol->value));
       }
+      *quarter_relocs = 4;
       break;
 
       /* Store code address: write address of entry point
@@ -428,15 +585,13 @@ etir_sto (bfd * abfd, int cmd, unsigned char *ptr)
        entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table),
                                                      name, FALSE, FALSE);
        if (entry == NULL)
-         {
-           (*_bfd_error_handler) (_("%s: no symbol \"%s\""),
-                                  cmd_name (cmd), name);
-           return FALSE;
-         }
+         /* FIXME, reloc.  */
+         image_write_q (abfd, (uquad) (0));
        else
          /* FIXME, reloc.  */
          image_write_q (abfd, (uquad) (entry->symbol->value));
       }
+      *quarter_relocs = 4;
       break;
 
       /* Store offset to psect: pop stack, add low 32 bits to base of psect
@@ -450,6 +605,7 @@ etir_sto (bfd * abfd, int cmd, unsigned char *ptr)
        q += (PRIV (sections)[psect1])->vma;
        image_write_q (abfd, q);
       }
+      *quarter_relocs += 2;
       break;
 
       /* Store immediate
@@ -462,6 +618,7 @@ etir_sto (bfd * abfd, int cmd, unsigned char *ptr)
        size = bfd_getl32 (ptr);
        image_dump (abfd, ptr+4, size, 0);
       }
+      *quarter_relocs = 0;
       break;
 
       /* This code is 'reserved to digital' according to the openVMS
@@ -489,22 +646,26 @@ etir_sto (bfd * abfd, int cmd, unsigned char *ptr)
          /* FIXME, reloc.  */
          image_write_l (abfd, (unsigned long) (entry->symbol->value));
       }
+      *quarter_relocs = 4;
       break;
 
     case ETIR_S_C_STO_RB:
     case ETIR_S_C_STO_AB:
     case ETIR_S_C_STO_LP_PSB:
       (*_bfd_error_handler) (_("%s: not supported"), cmd_name (cmd));
-      break;
+      *quarter_relocs = 0;
+      return FALSE;
 
     case ETIR_S_C_STO_HINT_GBL:
     case ETIR_S_C_STO_HINT_PS:
       (*_bfd_error_handler) (_("%s: not implemented"), cmd_name (cmd));
-      break;
+      *quarter_relocs = 0;
+      return FALSE;
 
     default:
       (*_bfd_error_handler) (_("reserved STO cmd %d"), cmd);
-      break;
+      *quarter_relocs = 0;
+      return FALSE;
     }
 
   return TRUE;
@@ -518,15 +679,22 @@ etir_sto (bfd * abfd, int cmd, unsigned char *ptr)
    see table B-10 of the openVMS linker manual.  */
 
 static bfd_boolean
-etir_opr (bfd * abfd, int cmd, unsigned char *ptr ATTRIBUTE_UNUSED)
+etir_opr (bfd *abfd, int cmd, unsigned char *ptr ATTRIBUTE_UNUSED,
+         int *quarter_relocs)
 {
   long op1, op2;
 
 #if VMS_DEBUG
   _bfd_vms_debug (5, "etir_opr %d/%x\n", cmd, cmd);
-  _bfd_hexdump (8, ptr, 16, (int) ptr);
+  _bfd_hexdump (8, ptr, 16, (long) ptr);
 #endif
 
+  /* No relocation uses OPR commands except ETIR_S_C_OPR_ADD.  */
+  if (cmd == ETIR_S_C_OPR_ADD)
+    *quarter_relocs += 1;
+  else
+    *quarter_relocs = 0;
+
   switch (cmd)
     {
     case ETIR_S_C_OPR_NOP:      /* No-op.  */
@@ -604,7 +772,7 @@ etir_opr (bfd * abfd, int cmd, unsigned char *ptr ATTRIBUTE_UNUSED)
     case ETIR_S_C_OPR_REDEF:     /* Redefine symbol to current location.  */
     case ETIR_S_C_OPR_DFLIT:     /* Define a literal.  */
       (*_bfd_error_handler) (_("%s: not supported"), cmd_name (cmd));
-      break;
+      return FALSE;
 
     case ETIR_S_C_OPR_SEL:      /* Select.  */
       if ((long) _bfd_vms_pop (abfd, NULL) & 0x01L)
@@ -619,7 +787,7 @@ etir_opr (bfd * abfd, int cmd, unsigned char *ptr ATTRIBUTE_UNUSED)
 
     default:
       (*_bfd_error_handler) (_("reserved OPR cmd %d"), cmd);
-      break;
+      return FALSE;
     }
 
   return TRUE;
@@ -630,16 +798,19 @@ etir_opr (bfd * abfd, int cmd, unsigned char *ptr ATTRIBUTE_UNUSED)
    See table B-11 of the openVMS linker manual.  */
 
 static bfd_boolean
-etir_ctl (bfd * abfd, int cmd, unsigned char *ptr)
+etir_ctl (bfd *abfd, int cmd, unsigned char *ptr, int *quarter_relocs)
 {
-  uquad         dummy;
+  uquad dummy;
   int psect;
 
 #if VMS_DEBUG
   _bfd_vms_debug (5, "etir_ctl %d/%x\n", cmd, cmd);
-  _bfd_hexdump (8, ptr, 16, (int) ptr);
+  _bfd_hexdump (8, ptr, 16, (long) ptr);
 #endif
 
+  /* No relocation uses CTL commands.  */
+  *quarter_relocs = 0;
+
   switch (cmd)
     {
       /* Det relocation base: pop stack, set image location counter
@@ -660,27 +831,28 @@ etir_ctl (bfd * abfd, int cmd, unsigned char *ptr)
         arg: none.  */
     case ETIR_S_C_CTL_DFLOC:
       dummy = _bfd_vms_pop (abfd, NULL);
-      /* FIXME */
+      dst_define_location (abfd, dummy);
       break;
 
       /* Set location: pop index, restore location counter from index
         arg: none.  */
     case ETIR_S_C_CTL_STLOC:
-      dummy = _bfd_vms_pop (abfd, &psect);
-      /* FIXME */
+      dummy = _bfd_vms_pop (abfd, NULL);
+      dst_restore_location (abfd, dummy);
       break;
 
       /* Stack defined location: pop index, push location counter from index
         arg: none.  */
     case ETIR_S_C_CTL_STKDL:
-      dummy = _bfd_vms_pop (abfd, &psect);
-      /* FIXME.  */
+      dummy = _bfd_vms_pop (abfd, NULL);
+      _bfd_vms_push (abfd, dst_retrieve_location (abfd, dummy), -1);
       break;
 
     default:
       (*_bfd_error_handler) (_("reserved CTL cmd %d"), cmd);
-      break;
+      return FALSE;
     }
+
   return TRUE;
 }
 
@@ -689,11 +861,12 @@ etir_ctl (bfd * abfd, int cmd, unsigned char *ptr)
    See table B-12 and B-13 of the openVMS linker manual.  */
 
 static bfd_boolean
-etir_stc (bfd * abfd, int cmd, unsigned char *ptr ATTRIBUTE_UNUSED)
+etir_stc (bfd *abfd, int cmd, unsigned char *ptr ATTRIBUTE_UNUSED,
+         int *quarter_relocs)
 {
 #if VMS_DEBUG
   _bfd_vms_debug (5, "etir_stc %d/%x\n", cmd, cmd);
-  _bfd_hexdump (8, ptr, 16, (int) ptr);
+  _bfd_hexdump (8, ptr, 16, (long) ptr);
 #endif
 
   switch (cmd)
@@ -701,32 +874,17 @@ etir_stc (bfd * abfd, int cmd, unsigned char *ptr ATTRIBUTE_UNUSED)
       /* 200 Store-conditional Linkage Pair
         arg: none.  */
     case ETIR_S_C_STC_LP:
-      (*_bfd_error_handler) (_("%s: not supported"), cmd_name (cmd));
-      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, (uquad) 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) (_("%s: not supported"), cmd_name (cmd));
-      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) (_("%s: not supported"), cmd_name (cmd));
-      break;
 
       /* 204 Store-conditional Address at psect + offset
         arg:   lw      linkage index
@@ -734,56 +892,82 @@ etir_stc (bfd * abfd, int cmd, unsigned char *ptr ATTRIBUTE_UNUSED)
                qw      offset.  */
     case ETIR_S_C_STC_PS:
       (*_bfd_error_handler) (_("%s: not supported"), cmd_name (cmd));
+      *quarter_relocs = 0;
+      return FALSE;
+
+      /* 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, (uquad) 16);        /* skip entry,procval */
+      *quarter_relocs = 4;
       break;
 
       /* 205 Store-conditional NOP at address of global
         arg: none.  */
     case ETIR_S_C_STC_NOP_GBL:
-
-      /* 206 Store-conditional NOP at pect + offset
-        arg: none.  */
-    case ETIR_S_C_STC_NOP_PS:
+      /* ALPHA_R_NOP */
 
       /* 207 Store-conditional BSR at global address
         arg: none.  */
-    case ETIR_S_C_STC_BSR_GBL:
 
-      /* 208 Store-conditional BSR at pect + offset
-        arg: none.  */
-    case ETIR_S_C_STC_BSR_PS:
+    case ETIR_S_C_STC_BSR_GBL:
+      /* ALPHA_R_BSR */
 
       /* 209 Store-conditional LDA at global address
         arg: none.  */
-    case ETIR_S_C_STC_LDA_GBL:
 
-      /* 210 Store-conditional LDA at psect + offset
-        arg: none.  */
-    case ETIR_S_C_STC_LDA_PS:
+    case ETIR_S_C_STC_LDA_GBL:
+      /* ALPHA_R_LDA */
 
       /* 211 Store-conditional BSR or Hint at global address
         arg: none.  */
-    case ETIR_S_C_STC_BOH_GBL:
 
-      /* 212 Store-conditional BSR or Hint at pect + offset
-        arg: none.  */
-    case ETIR_S_C_STC_BOH_PS:
+    case ETIR_S_C_STC_BOH_GBL:
+      *quarter_relocs = 4;
+      break;
 
       /* 213 Store-conditional NOP,BSR or HINT at global address
         arg: none.  */
+
     case ETIR_S_C_STC_NBH_GBL:
 
-      /* 214 Store-conditional NOP,BSR or HINT at psect + offset
+      /* 206 Store-conditional NOP at pect + offset
+        arg: none.  */
+
+    case ETIR_S_C_STC_NOP_PS:
+
+      /* 208 Store-conditional BSR at pect + offset
+        arg: none.  */
+
+    case ETIR_S_C_STC_BSR_PS:
+
+      /* 210 Store-conditional LDA at psect + offset
+        arg: none.  */
+
+    case ETIR_S_C_STC_LDA_PS:
+
+      /* 212 Store-conditional BSR or Hint at pect + offset
+        arg: none.  */
+
+    case ETIR_S_C_STC_BOH_PS:
+
+      /* 214 Store-conditional NOP, BSR or HINT at psect + offset
         arg: none.  */
     case ETIR_S_C_STC_NBH_PS:
-      /* FIXME */
-      break;
+      (*_bfd_error_handler) ("%s: not supported", cmd_name (cmd));
+      *quarter_relocs = 0;
+      return FALSE;
 
     default:
-#if VMS_DEBUG
-      _bfd_vms_debug (3,  "reserved STC cmd %d", cmd);
-#endif
-      break;
+      (*_bfd_error_handler) (_("reserved STC cmd %d"), cmd);
+      *quarter_relocs = 0;
+      return FALSE;
     }
+
   return TRUE;
 }
 
@@ -851,10 +1035,10 @@ alloc_section (bfd * abfd, unsigned int idx)
 
 /* tir_sta
 
-   vax stack commands
+   Vax stack commands.
 
-   Handle sta_xxx commands in tir section
-   ptr points to data area in record
+   Handle sta_xxx commands in tir section,
+   ptr points to data area in record.
 
    See table 7-3 of the VAX/VMS linker manual.  */
 
@@ -924,7 +1108,7 @@ tir_sta (bfd * abfd, unsigned char *ptr)
                by      signed byte offset.  */
       {
        unsigned long dummy;
-       unsigned int psect;
+       int psect;
 
        if (cmd == TIR_S_C_STA_PB)
          psect = *ptr++;
@@ -934,12 +1118,12 @@ tir_sta (bfd * abfd, unsigned char *ptr)
            ptr += 2;
          }
 
-       if (psect >= PRIV (section_count))
+       if ((unsigned int) psect >= PRIV (section_count))
          alloc_section (abfd, psect);
 
        dummy = (long) *ptr++;
        dummy += (PRIV (sections)[psect])->vma;
-       _bfd_vms_push (abfd, (uquad) dummy, (int) psect);
+       _bfd_vms_push (abfd, (uquad) dummy, psect);
       }
       break;
 
@@ -951,7 +1135,7 @@ tir_sta (bfd * abfd, unsigned char *ptr)
                sh      signed short offset.  */
       {
        unsigned long dummy;
-       unsigned int psect;
+       int psect;
 
        if (cmd == TIR_S_C_STA_PW)
          psect = *ptr++;
@@ -961,12 +1145,12 @@ tir_sta (bfd * abfd, unsigned char *ptr)
            ptr += 2;
          }
 
-       if (psect >= PRIV (section_count))
+       if ((unsigned int) psect >= PRIV (section_count))
          alloc_section (abfd, psect);
 
        dummy = bfd_getl16 (ptr); ptr+=2;
        dummy += (PRIV (sections)[psect])->vma;
-       _bfd_vms_push (abfd, (uquad) dummy, (int) psect);
+       _bfd_vms_push (abfd, (uquad) dummy, psect);
       }
       break;
 
@@ -978,7 +1162,7 @@ tir_sta (bfd * abfd, unsigned char *ptr)
                lw      signed longword offset.  */
       {
        unsigned long dummy;
-       unsigned int psect;
+       int psect;
 
        if (cmd == TIR_S_C_STA_PL)
          psect = *ptr++;
@@ -988,12 +1172,12 @@ tir_sta (bfd * abfd, unsigned char *ptr)
            ptr += 2;
          }
 
-       if (psect >= PRIV (section_count))
+       if ((unsigned int) psect >= PRIV (section_count))
          alloc_section (abfd, psect);
 
        dummy = bfd_getl32 (ptr); ptr += 4;
        dummy += (PRIV (sections)[psect])->vma;
-       _bfd_vms_push (abfd, (uquad) dummy, (int) psect);
+       _bfd_vms_push (abfd, (uquad) dummy, psect);
       }
       break;
 
@@ -1457,7 +1641,7 @@ static unsigned char *
 tir_ctl (bfd * abfd, unsigned char *ptr)
 {
   unsigned long dummy;
-  unsigned int psect;
+  int psect;
 
 #if VMS_DEBUG
   _bfd_vms_debug (5, "tir_ctl %d\n", *ptr);
@@ -1468,10 +1652,10 @@ tir_ctl (bfd * abfd, unsigned char *ptr)
     case TIR_S_C_CTL_SETRB:
       /* Set relocation base: pop stack, set image location counter
         arg: none.  */
-      dummy = _bfd_vms_pop (abfd, (int *) &psect);
-      if (psect >= PRIV (section_count))
+      dummy = _bfd_vms_pop (abfd, &psect);
+      if ((unsigned int) psect >= PRIV (section_count))
        alloc_section (abfd, psect);
-      image_set_ptr (abfd, (int) psect, (uquad) dummy);
+      image_set_ptr (abfd, psect, (uquad) dummy);
       break;
 
     case TIR_S_C_CTL_AUGRB:
@@ -1492,7 +1676,7 @@ tir_ctl (bfd * abfd, unsigned char *ptr)
     case TIR_S_C_CTL_STLOC:
       /* Set location: pop index, restore location counter from index
         arg: none.  */
-      dummy = _bfd_vms_pop (abfd, (int *) &psect);
+      dummy = _bfd_vms_pop (abfd, &psect);
       (*_bfd_error_handler) (_("%s: not fully implemented"),
                             tir_cmd_name (ptr[-1]));
       break;
@@ -1500,7 +1684,7 @@ tir_ctl (bfd * abfd, unsigned char *ptr)
     case TIR_S_C_CTL_STKDL:
       /* Stack defined location: pop index, push location counter from index
         arg: none.  */
-      dummy = _bfd_vms_pop (abfd, (int *) &psect);
+      dummy = _bfd_vms_pop (abfd, &psect);
       (*_bfd_error_handler) (_("%s: not fully implemented"),
                             tir_cmd_name (ptr[-1]));
       break;
@@ -1517,7 +1701,7 @@ tir_ctl (bfd * abfd, unsigned char *ptr)
 static unsigned char *
 tir_cmd (bfd * abfd, unsigned char *ptr)
 {
-  struct
+  static const struct
   {
     int mincod;
     int maxcod;
@@ -1535,7 +1719,7 @@ tir_cmd (bfd * abfd, unsigned char *ptr)
 
 #if VMS_DEBUG
   _bfd_vms_debug (4, "tir_cmd %d/%x\n", *ptr, *ptr);
-  _bfd_hexdump (8, ptr, 16, (int) ptr);
+  _bfd_hexdump (8, ptr, 16, (long) ptr);
 #endif
 
   if (*ptr & 0x80)
@@ -1570,13 +1754,13 @@ tir_cmd (bfd * abfd, unsigned char *ptr)
 /* Handle command from ETIR section.  */
 
 static int
-etir_cmd (bfd * abfd, int cmd, unsigned char *ptr)
+etir_cmd (bfd *abfd, int cmd, unsigned char *ptr, int *quarter_relocs)
 {
-  static struct
+  static const struct
   {
     int mincod;
     int maxcod;
-    bfd_boolean (*explain) (bfd *, int, unsigned char *);
+    bfd_boolean (*explain) (bfd *, int, unsigned char *, int *);
   }
   etir_table[] =
   {
@@ -1591,8 +1775,8 @@ etir_cmd (bfd * abfd, int cmd, unsigned char *ptr)
   int i = 0;
 
 #if VMS_DEBUG
-  _bfd_vms_debug (4, "etir_cmd %d/%x\n", cmd, cmd);
-  _bfd_hexdump (8, ptr, 16, (int) ptr);
+  _bfd_vms_debug (4, "etir_cmd: %s(%d)\n", cmd_name (cmd), cmd);
+  _bfd_hexdump (8, ptr, 16, (long) ptr);
 #endif
 
   while (etir_table[i].mincod >= 0)
@@ -1600,7 +1784,7 @@ etir_cmd (bfd * abfd, int cmd, unsigned char *ptr)
       if ( (etir_table[i].mincod <= cmd)
           && (cmd <= etir_table[i].maxcod))
        {
-         if (!etir_table[i].explain (abfd, cmd, ptr))
+         if (!etir_table[i].explain (abfd, cmd, ptr, quarter_relocs))
            return -1;
          break;
        }
@@ -1608,7 +1792,7 @@ etir_cmd (bfd * abfd, int cmd, unsigned char *ptr)
     }
 
 #if VMS_DEBUG
-  _bfd_vms_debug (4, "etir_cmd: = 0\n");
+  _bfd_vms_debug (4, "etir_cmd: result = 0\n");
 #endif
   return 0;
 }
@@ -1643,28 +1827,67 @@ analyze_tir (bfd * abfd, unsigned char *ptr, unsigned int length)
 static int
 analyze_etir (bfd * abfd, unsigned char *ptr, unsigned int length)
 {
-  int cmd;
-  unsigned char *maxptr;
+  unsigned char *maxptr = ptr + length;
+  /* Relocations are made of 1, 2 or 4 ETIR commands.
+     We therefore count them using quarters.  */
+  int quarter_relocs = 0;
   int result = 0;
 
 #if VMS_DEBUG
   _bfd_vms_debug (3, "analyze_etir: %d bytes\n", length);
 #endif
 
-  maxptr = ptr + length;
-
   while (ptr < maxptr)
     {
-      cmd = bfd_getl16 (ptr);
-      length = bfd_getl16 (ptr + 2);
-      result = etir_cmd (abfd, cmd, ptr+4);
+      int cmd = bfd_getl16 (ptr);
+      int cmd_length = bfd_getl16 (ptr + 2);
+      result = etir_cmd (abfd, cmd, ptr + 4, &quarter_relocs);
       if (result != 0)
        break;
-      ptr += length;
+
+      /* If we have a relocation, we record its length to size
+        future buffers and bump the reloc count of the section.  */
+      if (quarter_relocs)
+       {
+         vms_section_data (PRIV (image_section))->reloc_size += cmd_length;
+         abfd->flags |= HAS_RELOC;
+
+         if (quarter_relocs == 4)
+           {
+             PRIV (image_section)->reloc_count++;
+
+#if VMS_DEBUG
+             _bfd_vms_debug (4, "-> reloc %d at 0x%x\n",
+                             PRIV (image_section)->reloc_count-1,
+                             ptr - (maxptr - length));
+#endif
+
+             quarter_relocs = 0;
+           }
+         else if (quarter_relocs > 4)
+           {
+
+#if VMS_DEBUG
+             _bfd_vms_debug (4, "Reloc count error (%d) in section %s\n",
+                             PRIV (image_section)->reloc_count,
+                             PRIV (image_section)->name);
+#endif
+
+             quarter_relocs = 0;
+           }
+       }
+
+      /* If we have a Store Immediate, we reserve space for the
+        count argument.  */
+      else if (cmd == ETIR_S_C_STO_IMM)
+        vms_section_data (PRIV (image_section))->reloc_size
+         += ETIR_S_C_HEADER_SIZE + 4;
+
+      ptr += cmd_length;
     }
 
 #if VMS_DEBUG
-  _bfd_vms_debug (3, "analyze_etir: = %d\n", result);
+  _bfd_vms_debug (3, "analyze_etir: result = %d\n", result);
 #endif
 
   return result;
@@ -1685,8 +1908,8 @@ _bfd_vms_slurp_tir (bfd * abfd, int objtype)
   switch (objtype)
     {
     case EOBJ_S_C_ETIR:
-      PRIV (vms_rec) += 4;     /* Skip type, size.  */
-      PRIV (rec_size) -= 4;
+      PRIV (vms_rec) += ETIR_S_C_HEADER_SIZE;
+      PRIV (rec_size) -= ETIR_S_C_HEADER_SIZE;
       result = analyze_etir (abfd, PRIV (vms_rec), (unsigned) PRIV (rec_size));
       break;
     case OBJ_S_C_TIR:
@@ -1702,33 +1925,361 @@ _bfd_vms_slurp_tir (bfd * abfd, int objtype)
   return result;
 }
 
-/* Process EDBG record
-   Return 0 on success, -1 on error
-
-   Not implemented yet.  */
+ /* Slurp relocs from ETIR sections and (temporarily) save them
+    in the per-section reloc buffer.  */
 
 int
-_bfd_vms_slurp_dbg (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
+_bfd_vms_slurp_relocs (bfd *abfd)
 {
+  struct vms_section_data_struct *vsd;
+  unsigned char *begin = PRIV (vms_rec) + 4;
+  unsigned char *end = PRIV (vms_rec) + PRIV (rec_size);
+  unsigned char *ptr;
+  int cmd, length, slurped_length;
+
 #if VMS_DEBUG
-  _bfd_vms_debug (2, "DBG/EDBG\n");
+  _bfd_vms_debug (3, "_bfd_vms_slurp_relocs: %d bytes\n", PRIV (rec_size));
+#endif
+
+  for (ptr = begin; ptr < end; ptr += length)
+    {
+      cmd = bfd_getl16 (ptr);
+      length = bfd_getl16 (ptr + 2);
+      slurped_length = length;
+
+      switch (cmd)
+       {
+       case ETIR_S_C_STA_PQ: /* ALPHA_R_REF{LONG|QUAD}, others part 1 */
+         /* This one is special as it is both part of the section header
+            and of the ALPHA_R_REFLONG and ALPHA_R_REFQUAD relocations.  */
+         if (bfd_getl16 (ptr + length) == ETIR_S_C_CTL_SETRB)
+           {
+             int psect = bfd_getl32 (ptr + ETIR_S_C_HEADER_SIZE);
+             PRIV (image_section) = PRIV (sections)[psect];
+             continue;
+           }
+
+       case ETIR_S_C_STA_GBL: /* ALPHA_R_REFLONG und_section, step 1 */
+                              /* ALPHA_R_REFQUAD und_section, step 1 */
+         break;
+
+       case ETIR_S_C_STA_LW: /* ALPHA_R_REFLONG und_section, step 2 */
+                             /* ALPHA_R_REFLONG abs_section, step 1 */
+         /* This one is special as it is both part of the section header
+            and of the ALPHA_R_REFLONG relocation.  */
+         if (bfd_getl16 (ptr + length) == ETIR_S_C_CTL_DFLOC)
+           {
+             PRIV (image_section) = PRIV (dst_section);
+             continue;
+           }
+
+       case ETIR_S_C_STA_QW: /* ALPHA_R_REFQUAD und_section, step 2 */
+                             /* ALPHA_R_REFQUAD abs_section, step 1 */
+
+       case ETIR_S_C_STO_LW: /* ALPHA_R_REFLONG und_section, step 4 */
+                             /* ALPHA_R_REFLONG abs_section, step 2 */
+                             /* ALPHA_R_REFLONG others, step 2 */
+
+       case ETIR_S_C_STO_QW: /* ALPHA_R_REFQUAD und_section, step 4 */
+                             /* ALPHA_R_REFQUAD abs_section, step 2 */
+
+       case ETIR_S_C_STO_OFF: /* ALPHA_R_REFQUAD others, step 2 */
+
+       case ETIR_S_C_OPR_ADD: /* ALPHA_R_REFLONG und_section, step 3 */
+                              /* ALPHA_R_REFQUAD und_section, step 3 */
+
+       case ETIR_S_C_STO_CA:      /* ALPHA_R_CODEADDR */
+       case ETIR_S_C_STO_GBL:     /* ALPHA_R_REFQUAD und_section */
+       case ETIR_S_C_STO_GBL_LW:  /* ALPHA_R_REFLONG und_section */
+       case ETIR_S_C_STC_LP_PSB:  /* ALPHA_R_LINKAGE */
+       case ETIR_S_C_STC_NOP_GBL: /* ALPHA_R_NOP */
+       case ETIR_S_C_STC_BSR_GBL: /* ALPHA_R_BSR */
+       case ETIR_S_C_STC_LDA_GBL: /* ALPHA_R_LDA */
+       case ETIR_S_C_STC_BOH_GBL: /* ALPHA_R_BOH */
+         break;
+
+       case ETIR_S_C_STO_IMM:
+         if (PRIV (image_section)->reloc_count == 0)
+           continue;
+         /* This is not a relocation, but we nevertheless slurp the
+            count argument.  We'll use it to compute the addresses
+            of the relocations.  */
+         slurped_length = ETIR_S_C_HEADER_SIZE + 4;
+         break;
+
+       default:
+         continue;
+       }
+
+      vsd = vms_section_data (PRIV (image_section));
+      memcpy (vsd->reloc_stream + vsd->reloc_offset, ptr, slurped_length);
+      vsd->reloc_offset += slurped_length;
+      if (vsd->reloc_offset > vsd->reloc_size)
+        {
+         (*_bfd_error_handler) (_("Reloc size error in section %s"),
+                                PRIV (image_section)->name);
+         return -1;
+       }
+    }
+
+#if VMS_DEBUG
+  _bfd_vms_debug (3, "_bfd_vms_slurp_relocs: result = 0\n");
 #endif
 
-  abfd->flags |= (HAS_DEBUG | HAS_LINENO);
   return 0;
 }
 
-/* Process ETBT record
-   Return 0 on success, -1 on error
-
-   Not implemented yet.  */
+/* Decode relocs from the reloc buffer of the specified section
+   and internalize them in the specified buffer.  */
 
 int
-_bfd_vms_slurp_tbt (bfd * abfd ATTRIBUTE_UNUSED,
-                   int objtype ATTRIBUTE_UNUSED)
+_bfd_vms_decode_relocs (bfd *abfd, arelent *relocs, asection *section,
+                       asymbol **symbols ATTRIBUTE_UNUSED)
 {
+  int saved_cmd, saved_sym_offset, saved_sec_offset, saved_addend_offset;
+  int cmd, sym_offset, sec_offset, address_offset, addend_offset;
+  struct vms_section_data_struct *vsd = vms_section_data (section);
+  bfd_reloc_code_real_type reloc_code;
+  vms_symbol_entry *entry;
+  bfd_vma vaddr = 0;
+  unsigned char *begin = vsd->reloc_stream;
+  unsigned char *end = vsd->reloc_stream + vsd->reloc_size;
+  unsigned char *ptr, *arg_ptr;
+  const char *name;
+  int length;
+
 #if VMS_DEBUG
-  _bfd_vms_debug (2, "TBT/ETBT\n");
+  _bfd_vms_debug (3, "_bfd_vms_decode_relocs: %d bytes\n", vsd->reloc_size);
+#endif
+
+  #define PUSH_CMD()                                   \
+    {                                                  \
+      saved_cmd = cmd;                                 \
+      saved_sym_offset = sym_offset - length;          \
+      saved_sec_offset = sec_offset - length;          \
+      saved_addend_offset = addend_offset - length;    \
+      continue;                                                \
+    }
+
+  #define POP_CMD()                                    \
+    {                                                  \
+      cmd = saved_cmd;                                 \
+      saved_cmd = ETIR_S_C_MAXSTCCOD + 1;              \
+      sym_offset = saved_sym_offset;                   \
+      sec_offset = saved_sec_offset;                   \
+      addend_offset= saved_addend_offset;              \
+    }
+
+  #define CMD_PUSHED (saved_cmd != ETIR_S_C_MAXSTCCOD + 1)
+
+  #define NO_OFFSET -128
+
+  saved_cmd = ETIR_S_C_MAXSTCCOD + 1;
+  saved_sym_offset = NO_OFFSET;
+  saved_sec_offset = NO_OFFSET;
+  saved_addend_offset = NO_OFFSET;
+
+  for (ptr = begin; ptr < end; ptr += length)
+    {
+      cmd = bfd_getl16 (ptr);
+      length = bfd_getl16 (ptr + 2);
+
+      arg_ptr = ptr + ETIR_S_C_HEADER_SIZE;
+      sym_offset = NO_OFFSET;
+      sec_offset = NO_OFFSET;
+      address_offset = NO_OFFSET;
+      addend_offset = NO_OFFSET;
+
+      switch (cmd)
+       {
+       case ETIR_S_C_STA_GBL: /* ALPHA_R_REFLONG und_section, step 1 */
+                              /* ALPHA_R_REFQUAD und_section, step 1 */
+         sym_offset = 0;
+         PUSH_CMD ()
+
+       case ETIR_S_C_STA_PQ: /* ALPHA_R_REF{LONG|QUAD}, others part 1 */
+         sec_offset = 0;
+         addend_offset = 4;
+         PUSH_CMD ()
+
+       case ETIR_S_C_STA_LW: /* ALPHA_R_REFLONG abs_section, step 1 */
+                             /* ALPHA_R_REFLONG und_section, step 2 */
+         if (CMD_PUSHED)
+           {
+             POP_CMD ()
+             if (cmd != ETIR_S_C_STA_GBL)
+               {
+                 (*_bfd_error_handler) (_("Unknown reloc %s + %s"),
+                                        cmd_name (cmd),
+                                        cmd_name (ETIR_S_C_STA_LW));
+                 return 0;
+               }
+             cmd = ETIR_S_C_STA_LW;
+           }
+         addend_offset = 0;
+         PUSH_CMD ()
+
+       case ETIR_S_C_STA_QW: /* ALPHA_R_REFQUAD abs_section, step 1 */
+                             /* ALPHA_R_REFQUAD und_section, step 2 */
+         if (CMD_PUSHED)
+           {
+             POP_CMD ()
+             if (cmd != ETIR_S_C_STA_GBL)
+               {
+                 (*_bfd_error_handler) (_("Unknown reloc %s + %s"),
+                                        cmd_name (cmd),
+                                        cmd_name (ETIR_S_C_STA_QW));
+                 return 0;
+               }
+             cmd = ETIR_S_C_STA_QW;
+           }
+         addend_offset = 0;
+         PUSH_CMD ()
+
+       case ETIR_S_C_STO_LW: /* ALPHA_R_REFLONG und_section, step 4 */
+                             /* ALPHA_R_REFLONG abs_section, step 2 */
+                             /* ALPHA_R_REFLONG others, step 2 */
+         POP_CMD ()
+         if (cmd != ETIR_S_C_OPR_ADD
+             && cmd != ETIR_S_C_STA_LW
+             && cmd != ETIR_S_C_STA_PQ)
+           {
+             (*_bfd_error_handler) (_("Unknown reloc %s + %s"),
+               cmd_name (cmd), cmd_name (ETIR_S_C_STO_LW));
+             return 0;
+           }
+         reloc_code = BFD_RELOC_32;
+         break;
+
+       case ETIR_S_C_STO_QW: /* ALPHA_R_REFQUAD und_section, step 4 */
+                             /* ALPHA_R_REFQUAD abs_section, step 2 */
+         POP_CMD ()
+         if (cmd != ETIR_S_C_OPR_ADD && cmd != ETIR_S_C_STA_QW)
+           {
+             (*_bfd_error_handler) (_("Unknown reloc %s + %s"),
+               cmd_name (cmd), cmd_name (ETIR_S_C_STO_QW));
+             return 0;
+           }
+         reloc_code = BFD_RELOC_64;
+         break;
+
+       case ETIR_S_C_STO_OFF: /* ALPHA_R_REFQUAD others, step 2 */
+         POP_CMD ()
+         if (cmd != ETIR_S_C_STA_PQ)
+           {
+             (*_bfd_error_handler) (_("Unknown reloc %s + %s"),
+               cmd_name (cmd), cmd_name (ETIR_S_C_STO_OFF));
+             return 0;
+           }
+         reloc_code = BFD_RELOC_64;
+         break;
+
+       case ETIR_S_C_OPR_ADD: /* ALPHA_R_REFLONG und_section, step 3 */
+                              /* ALPHA_R_REFQUAD und_section, step 3 */
+         POP_CMD ()
+         if (cmd != ETIR_S_C_STA_LW && cmd != ETIR_S_C_STA_QW)
+           {
+             (*_bfd_error_handler) (_("Unknown reloc %s + %s"),
+               cmd_name (cmd), cmd_name (ETIR_S_C_OPR_ADD));
+             return 0;
+           }
+         cmd = ETIR_S_C_OPR_ADD;
+         PUSH_CMD ()
+
+       case ETIR_S_C_STO_CA: /* ALPHA_R_CODEADDR */
+         reloc_code = BFD_RELOC_ALPHA_CODEADDR;
+         sym_offset = 0;
+         break;
+
+       case ETIR_S_C_STO_GBL: /* ALPHA_R_REFQUAD und_section */
+         reloc_code = BFD_RELOC_64;
+         sym_offset = 0;
+         break;
+
+       case ETIR_S_C_STO_GBL_LW: /* ALPHA_R_REFLONG und_section */
+         reloc_code = BFD_RELOC_32;
+         sym_offset = 0;
+         break;
+
+       case ETIR_S_C_STC_LP_PSB: /* ALPHA_R_LINKAGE */
+         reloc_code = BFD_RELOC_ALPHA_LINKAGE;
+         sym_offset = 4;
+         break;
+
+       case ETIR_S_C_STC_NOP_GBL: /* ALPHA_R_NOP */
+         reloc_code = BFD_RELOC_ALPHA_NOP;
+         goto call_reloc;
+
+       case ETIR_S_C_STC_BSR_GBL: /* ALPHA_R_BSR */
+         reloc_code = BFD_RELOC_ALPHA_BSR;
+         goto call_reloc;
+
+       case ETIR_S_C_STC_LDA_GBL: /* ALPHA_R_LDA */
+         reloc_code = BFD_RELOC_ALPHA_LDA;
+         goto call_reloc;
+
+       case ETIR_S_C_STC_BOH_GBL: /* ALPHA_R_BOH */
+         reloc_code = BFD_RELOC_ALPHA_BOH;
+         goto call_reloc;
+
+       call_reloc:
+         sym_offset = 32;
+         address_offset = 8;
+         addend_offset = 24;
+         break;
+
+       case ETIR_S_C_STO_IMM:
+         vaddr += bfd_getl32 (arg_ptr);
+         length = ETIR_S_C_HEADER_SIZE + 4;
+         continue;
+
+       default:
+         continue;
+       }
+
+      relocs->howto = bfd_reloc_type_lookup (abfd, reloc_code);
+
+      if (sym_offset > NO_OFFSET)
+       {
+         name = _bfd_vms_save_counted_string (arg_ptr + sym_offset);
+         entry = (vms_symbol_entry *)
+           bfd_hash_lookup (PRIV (vms_symbol_table), name, FALSE, FALSE);
+         if (entry == NULL)
+           {
+             (*_bfd_error_handler) (_("Unknown symbol %s in command %s"),
+                                    name, cmd_name (cmd));
+             relocs->sym_ptr_ptr = NULL;
+           }
+         else
+           /* ??? This is a hack.  We should point in 'symbols'.  */
+           relocs->sym_ptr_ptr = &entry->symbol;
+       }
+      else if (sec_offset > NO_OFFSET)
+       relocs->sym_ptr_ptr
+         = PRIV (sections)[bfd_getl32 (arg_ptr + sec_offset)]->symbol_ptr_ptr;
+      else
+       relocs->sym_ptr_ptr = NULL;
+
+      if (address_offset > NO_OFFSET)
+       relocs->address = bfd_getl64 (arg_ptr + address_offset);
+      else
+       relocs->address = vaddr;
+
+      if (addend_offset > NO_OFFSET)
+       relocs->addend = bfd_getl64 (arg_ptr + addend_offset);
+      else
+       relocs->addend = 0;
+
+      vaddr += bfd_get_reloc_size (relocs->howto);
+      relocs++;     
+    }
+
+  #undef PUSH_CMD
+  #undef POP_CMD
+  #undef NO_OFFSET
+
+#if VMS_DEBUG
+  _bfd_vms_debug (3, "_bfd_vms_decode_relocs: result = 0\n");
 #endif
 
   return 0;
@@ -1750,6 +2301,20 @@ _bfd_vms_slurp_lnk (bfd * abfd ATTRIBUTE_UNUSED,
   return 0;
 }
 \f
+/* WRITE ETIR SECTION
+
+   This is still under construction and therefore not documented.  */
+
+static void start_etir_record (bfd *abfd, int index, uquad offset,
+                              bfd_boolean justoffset);
+static void start_first_etbt_record (bfd *abfd);
+static void start_another_etbt_record (bfd *abfd);
+static void sto_imm (bfd *abfd, bfd_size_type, unsigned char *, bfd_vma vaddr,
+                    int index, const char *name);
+static void end_etir_record (bfd *abfd);
+static void etir_output_check (bfd *abfd, asection *section, bfd_vma vaddr,
+                              int checklen);
+
 /* Start ETIR record for section #index at virtual addr offset.  */
 
 static void
@@ -1780,25 +2345,20 @@ end_etir_record (bfd * abfd)
   _bfd_vms_output_end (abfd);
 }
 
-/* WRITE ETIR SECTION
-
-   This is still under construction and therefore not documented.  */
+/* Output a STO_IMM command for SSIZE bytes of data from CPR at virtual
+   address VADDR in section specified by INDEX and NAME.  */
 
 static void
-sto_imm (bfd * abfd, vms_section *sptr, bfd_vma vaddr, int index)
+sto_imm (bfd *abfd, bfd_size_type ssize, unsigned char *cptr, bfd_vma vaddr,
+        int index, const char *name)
 {
-  int size;
-  int ssize;
-  unsigned char *cptr;
+  bfd_size_type size;
 
 #if VMS_DEBUG
-  _bfd_vms_debug (8, "sto_imm %d bytes\n", sptr->size);
-  _bfd_hexdump (9, sptr->contents, (int) sptr->size, (int) vaddr);
+  _bfd_vms_debug (8, "sto_imm %d bytes\n", ssize);
+  _bfd_hexdump (9, cptr, (int) ssize, (int) vaddr);
 #endif
 
-  ssize = sptr->size;
-  cptr = sptr->contents;
-
   while (ssize > 0)
     {
       /* Try all the rest.  */
@@ -1808,11 +2368,14 @@ sto_imm (bfd * abfd, vms_section *sptr, bfd_vma vaddr, int index)
        {
          /* Doesn't fit, split !  */
          end_etir_record (abfd);
-         start_etir_record (abfd, index, vaddr, FALSE);
-         /* Get max size.  */
-         size = _bfd_vms_output_check (abfd, 0);
-         /* More than what's left ?  */
-         if (size > ssize)
+
+         if (name [0] && name[1] == 'v' && !strcmp (name, ".vmsdebug"))
+           start_another_etbt_record (abfd);
+         else
+           start_etir_record (abfd, index, vaddr, FALSE);
+
+         size = _bfd_vms_output_check (abfd, 0);       /* get max size */
+         if (size > ssize)                     /* more than what's left ? */
            size = ssize;
        }
 
@@ -1827,8 +2390,63 @@ sto_imm (bfd * abfd, vms_section *sptr, bfd_vma vaddr, int index)
 #endif
 
       vaddr += size;
-      ssize -= size;
       cptr += size;
+      ssize -= size;
+    }
+}
+
+/* Start ETBT record for section #index at virtual addr offset.  */
+
+static void
+start_first_etbt_record (bfd *abfd)
+{
+  _bfd_vms_output_begin (abfd, EOBJ_S_C_ETBT, -1);
+  _bfd_vms_output_push (abfd);
+
+  _bfd_vms_output_begin (abfd, ETIR_S_C_STA_LW, -1);   /* push start offset */
+  _bfd_vms_output_long (abfd, (unsigned long) 0);
+  _bfd_vms_output_flush (abfd);
+
+  _bfd_vms_output_begin (abfd, ETIR_S_C_CTL_DFLOC, -1);        /* start = pop() */
+  _bfd_vms_output_flush (abfd);
+}
+
+static void
+start_another_etbt_record (bfd *abfd)
+{
+  _bfd_vms_output_begin (abfd, EOBJ_S_C_ETBT, -1);
+  _bfd_vms_output_push (abfd);
+}
+
+static void
+etir_output_check (bfd *abfd, asection *section, bfd_vma vaddr, int checklen)
+{
+  if (_bfd_vms_output_check (abfd, checklen) < 0)
+    {
+      end_etir_record (abfd);
+      if (section->name[0] && section->name[1] == 'v'
+         && !strcmp (section->name, ".vmsdebug"))
+       start_another_etbt_record (abfd);
+      else
+       start_etir_record (abfd, section->index, vaddr, FALSE);
+    }
+}
+
+/* Return whether RELOC must be deferred till the end.  */
+
+static int
+defer_reloc_p (arelent *reloc)
+{
+  switch (reloc->howto->type)
+    {
+    case ALPHA_R_NOP:
+    case ALPHA_R_LDA:
+    case ALPHA_R_BSR:
+    case ALPHA_R_BOH:
+      return 1;
+
+    default:
+      return 0;
     }
 }
 
@@ -1838,8 +2456,6 @@ int
 _bfd_vms_write_tir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
 {
   asection *section;
-  vms_section *sptr;
-  int nextoffset;
 
 #if VMS_DEBUG
   _bfd_vms_debug (2, "vms_write_tir (%p, %d)\n", abfd, objtype);
@@ -1847,391 +2463,346 @@ _bfd_vms_write_tir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
 
   _bfd_vms_output_alignment (abfd, 4);
 
-  nextoffset = 0;
   PRIV (vms_linkage_index) = 1;
 
-  /* Dump all other sections.  */
-  section = abfd->sections;
-
-  while (section != NULL)
+  for (section = abfd->sections; section; section = section->next)
     {
-
 #if VMS_DEBUG
       _bfd_vms_debug (4, "writing %d. section '%s' (%d bytes)\n",
                      section->index, section->name,
                      (int) (section->size));
 #endif
 
+      if (!(section->flags & SEC_HAS_CONTENTS)
+         || bfd_is_com_section (section))
+       continue;
+
+      if (!section->contents)
+       {
+         bfd_set_error (bfd_error_no_contents);
+         return -1;
+       }
+
+      if (section->name[0]
+         && section->name[1] == 'v'
+         && !strcmp (section->name, ".vmsdebug"))
+       start_first_etbt_record (abfd);
+      else
+       start_etir_record (abfd, section->index, 0, FALSE);
+
       if (section->flags & SEC_RELOC)
        {
-         int i;
+         bfd_vma curr_addr = 0;
+         unsigned char *curr_data = section->contents;
+         bfd_size_type size;
+         int pass2_needed = 0;
+         int pass2_in_progress = 0;
+         unsigned int irel;
+
+         if (section->reloc_count <= 0)
+           (*_bfd_error_handler)
+             (_("SEC_RELOC with no relocs in section %s"), section->name);
 
-         if ((i = section->reloc_count) <= 0)
-           (*_bfd_error_handler) (_("SEC_RELOC with no relocs in section %s"),
-                                  section->name);
 #if VMS_DEBUG
          else
            {
-             arelent **rptr;
+             int i = section->reloc_count;
+             arelent **rptr = section->orelocation;
              _bfd_vms_debug (4, "%d relocations:\n", i);
-             rptr = section->orelocation;
              while (i-- > 0)
                {
-                 _bfd_vms_debug (4, "sym %s in sec %s, value %08lx, addr %08lx, off %08lx, len %d: %s\n",
+                 _bfd_vms_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)->howto->name);
                  rptr++;
                }
            }
 #endif
-       }
 
-      if ((section->flags & SEC_HAS_CONTENTS)
-         && (! bfd_is_com_section (section)))
-       {
-         /* Virtual addr in section.  */
-         bfd_vma vaddr;
-
-         sptr = _bfd_get_vms_section (abfd, section->index);
-         if (sptr == NULL)
+       new_pass:
+         for (irel = 0; irel < section->reloc_count; irel++)
            {
-             bfd_set_error (bfd_error_no_contents);
-             return -1;
-           }
+             struct evax_private_udata_struct *udata;
+             arelent *rptr = section->orelocation [irel];
+             bfd_vma addr = rptr->address;
+             asymbol *sym = *rptr->sym_ptr_ptr;
+             asection *sec = sym->section;
+             int defer = defer_reloc_p (rptr);
+             unsigned int slen;
+             char *hash;
+
+             if (pass2_in_progress)
+               {
+                 /* Non-deferred relocs have already been output.  */
+                 if (!defer)
+                   continue;
+               }
+             else
+               {
+                 /* Deferred relocs must be output at the very end.  */
+                 if (defer)
+                   {
+                     pass2_needed = 1;
+                     continue;
+                   }
 
-         vaddr = (bfd_vma) (sptr->offset);
+                 /* Regular relocs are intertwined with binary data.  */
+                 if (curr_addr > addr)
+                   (*_bfd_error_handler) (_("Size error in section %s"),
+                                          section->name);
+                 size = addr - curr_addr;
+                 sto_imm (abfd, size, curr_data, curr_addr,
+                         section->index, section->name);
+                 curr_data += size;
+                 curr_addr += size;
+               }
 
-         start_etir_record (abfd, section->index, (uquad) sptr->offset,
-                            FALSE);
+             size = bfd_get_reloc_size (rptr->howto);
 
-         while (sptr != NULL)
-           {
-             /* One STA_PQ, CTL_SETRB per vms_section.  */
-             if (section->flags & SEC_RELOC)
-               {
-                 /* Check for relocs.  */
-                 arelent **rptr = section->orelocation;
-                 int i = section->reloc_count;
+             switch (rptr->howto->type)
+               {
+               case ALPHA_R_IGNORE:
+                 break;
 
-                 for (;;)
+               case ALPHA_R_REFLONG:
+                 if (bfd_is_und_section (sym->section))
                    {
-                     bfd_size_type addr = (*rptr)->address;
-                     bfd_size_type len = bfd_get_reloc_size ((*rptr)->howto);
-                     if (sptr->offset < addr)
-                       {
-                         /* Sptr starts before reloc.  */
-                         bfd_size_type 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)
+                     bfd_vma addend = rptr->addend;
+                     slen = strlen ((char *) sym->name);
+                     hash = _bfd_vms_length_hash_symbol
+                              (abfd, sym->name, EOBJ_S_C_SYMSIZ);
+                     etir_output_check (abfd, section, curr_addr, slen);
+                     if (addend)
                        {
-                         /* 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))
-                                 {
-                                   int slen = strlen ((char *) sym->name);
-                                   char *hash;
-
-                                   if (_bfd_vms_output_check (abfd, slen) < 0)
-                                     {
-                                       end_etir_record (abfd);
-                                       start_etir_record (abfd,
-                                                          section->index,
-                                                          vaddr, FALSE);
-                                     }
-                                   _bfd_vms_output_begin (abfd,
-                                                          ETIR_S_C_STO_GBL_LW,
-                                                          -1);
-                                   hash = (_bfd_vms_length_hash_symbol
-                                           (abfd, sym->name, EOBJ_S_C_SYMSIZ));
-                                   _bfd_vms_output_counted (abfd, hash);
-                                   _bfd_vms_output_flush (abfd);
-                                 }
-                               else if (bfd_is_abs_section (sym->section))
-                                 {
-                                   if (_bfd_vms_output_check (abfd, 16) < 0)
-                                     {
-                                       end_etir_record (abfd);
-                                       start_etir_record (abfd,
-                                                          section->index,
-                                                          vaddr, FALSE);
-                                     }
-                                   _bfd_vms_output_begin (abfd,
-                                                          ETIR_S_C_STA_LW,
-                                                          -1);
-                                   _bfd_vms_output_quad (abfd,
-                                                         (uquad) sym->value);
-                                   _bfd_vms_output_flush (abfd);
-                                   _bfd_vms_output_begin (abfd,
-                                                          ETIR_S_C_STO_LW,
-                                                          -1);
-                                   _bfd_vms_output_flush (abfd);
-                                 }
-                               else
-                                 {
-                                   if (_bfd_vms_output_check (abfd, 32) < 0)
-                                     {
-                                       end_etir_record (abfd);
-                                       start_etir_record (abfd,
-                                                          section->index,
-                                                          vaddr, FALSE);
-                                     }
-                                   _bfd_vms_output_begin (abfd,
-                                                          ETIR_S_C_STA_PQ,
-                                                          -1);
-                                   _bfd_vms_output_long (abfd,
-                                                         (unsigned long) (sec->index));
-                                   _bfd_vms_output_quad (abfd,
-                                                         ((uquad) (*rptr)->addend
-                                                          + (uquad) sym->value));
-                                   _bfd_vms_output_flush (abfd);
-                                   _bfd_vms_output_begin (abfd,
-                                                          ETIR_S_C_STO_LW,
-                                                          -1);
-                                   _bfd_vms_output_flush (abfd);
-                                 }
-                             }
-                             break;
-
-                           case ALPHA_R_REFQUAD:
-                             {
-                               if (bfd_is_und_section (sym->section))
-                                 {
-                                   int slen = strlen ((char *) sym->name);
-                                   char *hash;
-
-                                   if (_bfd_vms_output_check (abfd, slen) < 0)
-                                     {
-                                       end_etir_record (abfd);
-                                       start_etir_record (abfd,
-                                                          section->index,
-                                                          vaddr, FALSE);
-                                     }
-                                   _bfd_vms_output_begin (abfd,
-                                                          ETIR_S_C_STO_GBL,
-                                                          -1);
-                                   hash = (_bfd_vms_length_hash_symbol
-                                           (abfd, sym->name, EOBJ_S_C_SYMSIZ));
-                                   _bfd_vms_output_counted (abfd, hash);
-                                   _bfd_vms_output_flush (abfd);
-                                 }
-                               else if (bfd_is_abs_section (sym->section))
-                                 {
-                                   if (_bfd_vms_output_check (abfd, 16) < 0)
-                                     {
-                                       end_etir_record (abfd);
-                                       start_etir_record (abfd,
-                                                          section->index,
-                                                          vaddr, FALSE);
-                                     }
-                                   _bfd_vms_output_begin (abfd,
-                                                          ETIR_S_C_STA_QW,
-                                                          -1);
-                                   _bfd_vms_output_quad (abfd,
-                                                         (uquad) sym->value);
-                                   _bfd_vms_output_flush (abfd);
-                                   _bfd_vms_output_begin (abfd,
-                                                          ETIR_S_C_STO_QW,
-                                                          -1);
-                                   _bfd_vms_output_flush (abfd);
-                                 }
-                               else
-                                 {
-                                   if (_bfd_vms_output_check (abfd, 32) < 0)
-                                     {
-                                       end_etir_record (abfd);
-                                       start_etir_record (abfd,
-                                                          section->index,
-                                                          vaddr, FALSE);
-                                     }
-                                   _bfd_vms_output_begin (abfd,
-                                                          ETIR_S_C_STA_PQ,
-                                                          -1);
-                                   _bfd_vms_output_long (abfd,
-                                                         (unsigned long) (sec->index));
-                                   _bfd_vms_output_quad (abfd,
-                                                         ((uquad) (*rptr)->addend
-                                                          + (uquad) sym->value));
-                                   _bfd_vms_output_flush (abfd);
-                                   _bfd_vms_output_begin (abfd,
-                                                          ETIR_S_C_STO_OFF,
-                                                          -1);
-                                   _bfd_vms_output_flush (abfd);
-                                 }
-                             }
-                             break;
-
-                           case ALPHA_R_HINT:
-                             {
-                               int hint_size;
-                               char *hash ATTRIBUTE_UNUSED;
-
-                               hint_size = sptr->size;
-                               sptr->size = len;
-                               sto_imm (abfd, sptr, vaddr, section->index);
-                               sptr->size = hint_size;
-                             }
-                             break;
-                           case ALPHA_R_LINKAGE:
-                             {
-                               char *hash;
-
-                               if (_bfd_vms_output_check (abfd, 64) < 0)
-                                 {
-                                   end_etir_record (abfd);
-                                   start_etir_record (abfd, section->index,
-                                                      vaddr, FALSE);
-                                 }
-                               _bfd_vms_output_begin (abfd,
-                                                      ETIR_S_C_STC_LP_PSB,
-                                                      -1);
-                               _bfd_vms_output_long (abfd,
-                                                     (unsigned long) PRIV (vms_linkage_index));
-                               PRIV (vms_linkage_index) += 2;
-                               hash = (_bfd_vms_length_hash_symbol
-                                       (abfd, sym->name, EOBJ_S_C_SYMSIZ));
-                               _bfd_vms_output_counted (abfd, hash);
-                               _bfd_vms_output_byte (abfd, 0);
-                               _bfd_vms_output_flush (abfd);
-                             }
-                             break;
-
-                           case ALPHA_R_CODEADDR:
-                             {
-                               int slen = strlen ((char *) sym->name);
-                               char *hash;
-                               if (_bfd_vms_output_check (abfd, slen) < 0)
-                                 {
-                                   end_etir_record (abfd);
-                                   start_etir_record (abfd,
-                                                      section->index,
-                                                      vaddr, FALSE);
-                                 }
-                               _bfd_vms_output_begin (abfd,
-                                                      ETIR_S_C_STO_CA,
-                                                      -1);
-                               hash = (_bfd_vms_length_hash_symbol
-                                       (abfd, sym->name, EOBJ_S_C_SYMSIZ));
-                               _bfd_vms_output_counted (abfd, hash);
-                               _bfd_vms_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++;
-                           }
+                         _bfd_vms_output_begin (abfd, ETIR_S_C_STA_GBL, -1);
+                         _bfd_vms_output_counted (abfd, hash);
+                         _bfd_vms_output_flush (abfd);
+                         _bfd_vms_output_begin (abfd, ETIR_S_C_STA_LW, -1);
+                         _bfd_vms_output_long (abfd, (unsigned long) addend);
+                         _bfd_vms_output_flush (abfd);
+                         _bfd_vms_output_begin (abfd, ETIR_S_C_OPR_ADD, -1);
+                         _bfd_vms_output_flush (abfd);
+                         _bfd_vms_output_begin (abfd, ETIR_S_C_STO_LW, -1);
+                         _bfd_vms_output_flush (abfd);
                        }
                      else
                        {
-                         /* Sptr starts after reloc.  */
-                         i--;
-                         /* Check next reloc.  */
-                         rptr++;
+                         _bfd_vms_output_begin (abfd, ETIR_S_C_STO_GBL_LW, -1);
+                         _bfd_vms_output_counted (abfd, hash);
+                         _bfd_vms_output_flush (abfd);
                        }
+                   }
+                 else if (bfd_is_abs_section (sym->section))
+                   {
+                     etir_output_check (abfd, section, curr_addr, 16);
+                     _bfd_vms_output_begin (abfd, ETIR_S_C_STA_LW, -1);
+                     _bfd_vms_output_long (abfd, (unsigned long) sym->value);
+                     _bfd_vms_output_flush (abfd);
+                     _bfd_vms_output_begin (abfd, ETIR_S_C_STO_LW, -1);
+                     _bfd_vms_output_flush (abfd);
+                   }
+                 else
+                   {
+                     etir_output_check (abfd, section, curr_addr, 32);
+                     _bfd_vms_output_begin (abfd, ETIR_S_C_STA_PQ, -1);
+                     _bfd_vms_output_long (abfd, (unsigned long) sec->index);
+                     _bfd_vms_output_quad (abfd, (uquad) rptr->addend
+                                                   + (uquad) sym->value);
+                     _bfd_vms_output_flush (abfd);
+                     /* ??? Table B-8 of the OpenVMS Linker Utilily Manual
+                        says that we should have a ETIR_S_C_STO_OFF here.
+                        But the relocation would not be BFD_RELOC_32 then.
+                        This case is very likely unreachable.  */
+                     _bfd_vms_output_begin (abfd, ETIR_S_C_STO_LW, -1);
+                     _bfd_vms_output_flush (abfd);
+                   }
+                 break;
 
-                     if (i == 0)
+               case ALPHA_R_REFQUAD:
+                 if (bfd_is_und_section (sym->section))
+                   {
+                     bfd_vma addend = rptr->addend;
+                     slen = strlen ((char *) sym->name);
+                     hash = _bfd_vms_length_hash_symbol
+                              (abfd, sym->name, EOBJ_S_C_SYMSIZ);
+                     etir_output_check (abfd, section, curr_addr, slen);
+                     if (addend)
+                       {
+                         _bfd_vms_output_begin (abfd, ETIR_S_C_STA_GBL, -1);
+                         _bfd_vms_output_counted (abfd, hash);
+                         _bfd_vms_output_flush (abfd);
+                         _bfd_vms_output_begin (abfd, ETIR_S_C_STA_QW, -1);
+                         _bfd_vms_output_quad (abfd, (uquad) addend);
+                         _bfd_vms_output_flush (abfd);
+                         _bfd_vms_output_begin (abfd, ETIR_S_C_OPR_ADD, -1);
+                         _bfd_vms_output_flush (abfd);
+                         _bfd_vms_output_begin (abfd, ETIR_S_C_STO_QW, -1);
+                         _bfd_vms_output_flush (abfd);
+                       }
+                     else
                        {
-                         /* All reloc checked.  */
-                         if (sptr->size > 0)
-                           {
-                             /* Dump rest.  */
-                             sto_imm (abfd, sptr, vaddr, section->index);
-                             vaddr += sptr->size;
-                           }
-                         break;
+                         _bfd_vms_output_begin (abfd, ETIR_S_C_STO_GBL, -1);
+                         _bfd_vms_output_counted (abfd, hash);
+                         _bfd_vms_output_flush (abfd);
                        }
                    }
+                 else if (bfd_is_abs_section (sym->section))
+                   {
+                     etir_output_check (abfd, section, curr_addr, 16);
+                     _bfd_vms_output_begin (abfd, ETIR_S_C_STA_QW, -1);
+                     _bfd_vms_output_quad (abfd, (uquad) sym->value);
+                     _bfd_vms_output_flush (abfd);
+                     _bfd_vms_output_begin (abfd, ETIR_S_C_STO_QW, -1);
+                     _bfd_vms_output_flush (abfd);
+                   }
+                 else
+                   {
+                     etir_output_check (abfd, section, curr_addr, 32);
+                     _bfd_vms_output_begin (abfd, ETIR_S_C_STA_PQ, -1);
+                     _bfd_vms_output_long (abfd, (unsigned long) sec->index);
+                     _bfd_vms_output_quad (abfd, (uquad) rptr->addend
+                                                   + (uquad) sym->value);
+                     _bfd_vms_output_flush (abfd);
+                     _bfd_vms_output_begin (abfd, ETIR_S_C_STO_OFF, -1);
+                     _bfd_vms_output_flush (abfd);
+                   }
+                 break;
+
+               case ALPHA_R_HINT:
+                 sto_imm (abfd, size, curr_data, curr_addr,
+                          section->index, section->name);
+                 break;
+               
+               case ALPHA_R_LINKAGE:
+                 etir_output_check (abfd, section, curr_addr, 64);
+                 _bfd_vms_output_begin (abfd, ETIR_S_C_STC_LP_PSB, -1);
+                 _bfd_vms_output_long
+                   (abfd, (unsigned long) PRIV (vms_linkage_index));
+                 PRIV (vms_linkage_index) += 2;
+                 hash = _bfd_vms_length_hash_symbol
+                          (abfd, sym->name, EOBJ_S_C_SYMSIZ);
+                 _bfd_vms_output_counted (abfd, hash);
+                 _bfd_vms_output_byte (abfd, 0);
+                 _bfd_vms_output_flush (abfd);
+                 break;
+
+               case ALPHA_R_CODEADDR:
+                 slen = strlen ((char *) sym->name);
+                 hash = _bfd_vms_length_hash_symbol
+                          (abfd, sym->name, EOBJ_S_C_SYMSIZ);
+                 etir_output_check (abfd, section, curr_addr, slen);
+                 _bfd_vms_output_begin (abfd, ETIR_S_C_STO_CA, -1);
+                 _bfd_vms_output_counted (abfd, hash);
+                 _bfd_vms_output_flush (abfd);
+                 break;
+
+               case ALPHA_R_NOP:
+                 udata
+                   = (struct evax_private_udata_struct *) rptr->sym_ptr_ptr;
+                 etir_output_check (abfd, section, curr_addr,
+                                    32 + 1 + strlen (udata->origname));
+                 _bfd_vms_output_begin (abfd, ETIR_S_C_STC_NOP_GBL, -1);
+                 _bfd_vms_output_long (abfd, (unsigned long) udata->lkindex);
+                 _bfd_vms_output_long
+                   (abfd, (unsigned long) udata->enbsym->section->index);
+                 _bfd_vms_output_quad (abfd, (uquad) rptr->address);
+                 _bfd_vms_output_long (abfd, (unsigned long) 0x47ff041f);
+                 _bfd_vms_output_long
+                   (abfd, (unsigned long) udata->enbsym->section->index);
+                 _bfd_vms_output_quad (abfd, (uquad) rptr->addend);
+                 _bfd_vms_output_counted
+                   (abfd, _bfd_vms_length_hash_symbol
+                            (abfd, udata->origname, EOBJ_S_C_SYMSIZ));
+                 _bfd_vms_output_flush (abfd);
+                 break;
+
+               case ALPHA_R_BSR:
+                 (*_bfd_error_handler) (_("Spurious ALPHA_R_BSR reloc"));
+                 break;
+
+               case ALPHA_R_LDA:
+                 udata
+                   = (struct evax_private_udata_struct *) rptr->sym_ptr_ptr;
+                 etir_output_check (abfd, section, curr_addr,
+                                    32 + 1 + strlen (udata->origname));
+                 _bfd_vms_output_begin (abfd, ETIR_S_C_STC_LDA_GBL, -1);
+                 _bfd_vms_output_long
+                   (abfd, (unsigned long) udata->lkindex + 1);
+                 _bfd_vms_output_long
+                   (abfd, (unsigned long) udata->enbsym->section->index);
+                 _bfd_vms_output_quad (abfd, (uquad) rptr->address);
+                 _bfd_vms_output_long (abfd, (unsigned long) 0x237B0000);
+                 _bfd_vms_output_long
+                   (abfd, (unsigned long) udata->bsym->section->index);
+                 _bfd_vms_output_quad (abfd, (uquad) rptr->addend);
+                 _bfd_vms_output_counted
+                   (abfd, _bfd_vms_length_hash_symbol
+                           (abfd, udata->origname, EOBJ_S_C_SYMSIZ));
+                 _bfd_vms_output_flush (abfd);
+                 break;
+
+               case ALPHA_R_BOH:
+                 udata
+                   = (struct evax_private_udata_struct *) rptr->sym_ptr_ptr;
+                 etir_output_check (abfd, section, curr_addr,
+                                      32 + 1 + strlen (udata->origname));
+                 _bfd_vms_output_begin (abfd, ETIR_S_C_STC_BOH_GBL, -1);
+                 _bfd_vms_output_long (abfd, (unsigned long) udata->lkindex);
+                 _bfd_vms_output_long
+                   (abfd, (unsigned long) udata->enbsym->section->index);
+                 _bfd_vms_output_quad (abfd, (uquad) rptr->address);
+                 _bfd_vms_output_long (abfd, (unsigned long) 0xD3400000);
+                 _bfd_vms_output_long
+                   (abfd, (unsigned long) udata->enbsym->section->index);
+                 _bfd_vms_output_quad (abfd, (uquad) rptr->addend);
+                 _bfd_vms_output_counted
+                   (abfd, _bfd_vms_length_hash_symbol
+                            (abfd, udata->origname, EOBJ_S_C_SYMSIZ));
+                 _bfd_vms_output_flush (abfd);
+                 break;
+
+               default:
+                 (*_bfd_error_handler) (_("Unhandled relocation %s"),
+                                        rptr->howto->name);
+                 break;
                }
-             else
+
+             curr_data += size;
+             curr_addr += size;
+           } /* End of relocs loop.  */
+
+         if (!pass2_in_progress)
+           {
+             /* Output rest of section.  */
+             if (curr_addr > section->size)
+               (*_bfd_error_handler) (_("Size error in section %s"),
+                                      section->name);
+             size = section->size - curr_addr;
+             sto_imm (abfd, size, curr_data, curr_addr,
+                      section->index, section->name);
+             curr_data += size;
+             curr_addr += size;
+
+             if (pass2_needed)
                {
-                 /* No relocs, just dump.  */
-                 sto_imm (abfd, sptr, vaddr, section->index);
-                 vaddr += sptr->size;
+                 pass2_in_progress = 1;
+                 goto new_pass;
                }
-
-             sptr = sptr->next;
            }
-
-         end_etir_record (abfd);
        }
+  
+      else /* (section->flags & SEC_RELOC) */
+       sto_imm (abfd, section->size, section->contents, 0,
+                section->index, section->name);
 
-      section = section->next;
+      end_etir_record (abfd);
     }
 
   _bfd_vms_output_alignment (abfd, 2);
   return 0;
 }
-
-/* Write traceback data for bfd abfd.  */
-
-int
-_bfd_vms_write_tbt (bfd * abfd ATTRIBUTE_UNUSED,
-                   int objtype ATTRIBUTE_UNUSED)
-{
-#if VMS_DEBUG
-  _bfd_vms_debug (2, "vms_write_tbt (%p, %d)\n", abfd, objtype);
-#endif
-
-  return 0;
-}
-
-/* Write debug info for bfd abfd.  */
-
-int
-_bfd_vms_write_dbg (bfd * abfd ATTRIBUTE_UNUSED,
-                   int objtype ATTRIBUTE_UNUSED)
-{
-#if VMS_DEBUG
-  _bfd_vms_debug (2, "vms_write_dbg (%p, objtype)\n", abfd, objtype);
-#endif
-
-  return 0;
-}
index 1944c1ee06736cc6c032ebc81b2d16e5cb417616..8111d4955e2de5a99ea957b4d71627a3e97f5927 100644 (file)
--- a/bfd/vms.c
+++ b/bfd/vms.c
@@ -1,7 +1,9 @@
 /* vms.c -- BFD back-end for VAX (openVMS/VAX) and
    EVAX (openVMS/Alpha) files.
    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2006, 2007, 2008 Free Software Foundation, Inc.
+   2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+   Main file.
 
    Written by Klaus K"ampf (kkaempf@rmi.de)
 
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
    MA 02110-1301, USA.  */
 
+#ifdef VMS
+#include <rms.h>
+#include <starlet.h>
+#define RME$C_SETRFM 0x00000001
+#include <unistd.h>
+#endif
+
 #include "sysdep.h"
 #include "bfd.h"
 #include "bfdlink.h"
 
 #include "vms.h"
 
+static bfd_boolean vms_initialize (bfd *);
+static bfd_boolean fill_section_ptr (struct bfd_hash_entry *, PTR);
+static bfd_boolean vms_fixup_sections (bfd *);
+static bfd_boolean copy_symbols (struct bfd_hash_entry *, PTR);
+static bfd_reloc_status_type reloc_nil (bfd *, arelent *, asymbol *, PTR,
+                                       asection *, bfd *, char **);
+static int vms_slurp_module (bfd *abfd);
+static int vms_slurp_image (bfd *abfd);
+static const struct bfd_target *vms_object_p (bfd *abfd);
+static const struct bfd_target *vms_archive_p (bfd *abfd);
+static bfd_boolean vms_mkobject (bfd *abfd);
+static bfd_boolean vms_write_object_contents (bfd *abfd);
+static void free_reloc_stream (bfd *abfd, asection *section, void *data);
+static bfd_boolean vms_close_and_cleanup (bfd *abfd);
+static bfd_boolean vms_bfd_free_cached_info (bfd *abfd);
+static bfd_boolean vms_new_section_hook (bfd *abfd, asection *section);
+static bfd_boolean vms_get_section_contents
+  (bfd *abfd, asection *section, PTR x1, file_ptr x2, bfd_size_type x3);
+static bfd_boolean vms_get_section_contents_in_window
+  (bfd *abfd, asection *section, bfd_window *w, file_ptr offset,
+   bfd_size_type count);
+static bfd_boolean vms_bfd_copy_private_bfd_data (bfd *src, bfd *dest);
+static bfd_boolean vms_bfd_copy_private_section_data
+  (bfd *srcbfd, asection *srcsec, bfd *dstbfd, asection *dstsec);
+static bfd_boolean vms_bfd_copy_private_symbol_data
+  (bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym);
+static bfd_boolean vms_bfd_print_private_bfd_data (bfd *abfd, void *file);
+static char *vms_core_file_failing_command (bfd *abfd);
+static int vms_core_file_failing_signal (bfd *abfd);
+static bfd_boolean vms_core_file_matches_executable_p (bfd *abfd, bfd *bbfd);
+static bfd_boolean vms_slurp_armap (bfd *abfd);
+static bfd_boolean vms_slurp_extended_name_table (bfd *abfd);
+static bfd_boolean vms_construct_extended_name_table
+  (bfd *abfd, char **tabloc, bfd_size_type *tablen, const char **name);
+static void vms_truncate_arname (bfd *abfd, const char *pathname, char *arhdr);
+static bfd_boolean vms_write_armap
+  (bfd *arch, unsigned int elen, struct orl *map, unsigned int cnt, int idx);
+static PTR vms_read_ar_hdr (bfd *abfd);
+static bfd *vms_get_elt_at_index (bfd *abfd, symindex index);
+static bfd *vms_openr_next_archived_file (bfd *arch, bfd *prev);
+static bfd_boolean vms_update_armap_timestamp (bfd *abfd);
+static int vms_generic_stat_arch_elt (bfd *, struct stat *);
+static long vms_get_symtab_upper_bound (bfd *abfd);
+static long vms_canonicalize_symtab (bfd *abfd, asymbol **symbols);
+static void vms_print_symbol (bfd *abfd, PTR file, asymbol *symbol,
+                             bfd_print_symbol_type how);
+static void vms_get_symbol_info (bfd *abfd, asymbol *symbol, symbol_info *ret);
+static bfd_boolean vms_bfd_is_local_label_name (bfd *abfd, const char *);
+static alent *vms_get_lineno (bfd *abfd, asymbol *symbol);
+static bfd_boolean vms_find_nearest_line
+  (bfd *abfd, asection *section, asymbol **symbols, bfd_vma offset,
+   const char **file, const char **func, unsigned int *line);
+static asymbol *vms_bfd_make_debug_symbol (bfd *abfd, void *ptr,
+                                          unsigned long size);
+static long vms_read_minisymbols (bfd *abfd, bfd_boolean dynamic,
+                                 PTR *minisymsp, unsigned int *sizep);
+static asymbol *vms_minisymbol_to_symbol
+  (bfd *abfd, bfd_boolean dynamic, const PTR minisym, asymbol *sym);
+static void alloc_reloc_stream (bfd *abfd, asection *section,
+                               void *alloc_error);
+static bfd_boolean vms_slurp_reloc_table (bfd *abfd, asection *section,
+                                         asymbol **symbols);
+static long vms_get_reloc_upper_bound (bfd *abfd, asection *sect);
+static long vms_canonicalize_reloc (bfd *abfd, asection *srcsec,
+                                   arelent **location, asymbol **symbols);
+static const struct reloc_howto_struct *vms_bfd_reloc_type_lookup
+  (bfd *abfd, bfd_reloc_code_real_type code);
+static bfd_boolean vms_set_arch_mach
+  (bfd *abfd, enum bfd_architecture arch, unsigned long mach);
+static bfd_boolean vms_set_section_contents
+  (bfd *abfd, asection *section, const PTR location, file_ptr offset,
+   bfd_size_type count);
+static int vms_sizeof_headers (bfd *abfd,
+                              struct bfd_link_info *info ATTRIBUTE_UNUSED);
+static bfd_byte *vms_bfd_get_relocated_section_contents
+  (bfd *abfd, struct bfd_link_info *link_info,
+   struct bfd_link_order *link_order, bfd_byte *data,
+   bfd_boolean relocatable, asymbol **symbols);
+static bfd_boolean vms_bfd_relax_section
+  (bfd *abfd, asection *section, struct bfd_link_info *link_info,
+   bfd_boolean *again);
+static bfd_boolean vms_bfd_gc_sections
+  (bfd *abfd, struct bfd_link_info *link_info);
+static bfd_boolean vms_bfd_merge_sections
+  (bfd *abfd, struct bfd_link_info *link_info);
+static struct bfd_link_hash_table *vms_bfd_link_hash_table_create (bfd *abfd);
+static void vms_bfd_link_hash_table_free (struct bfd_link_hash_table *hash);
+static bfd_boolean vms_bfd_link_add_symbols
+  (bfd *abfd, struct bfd_link_info *link_info);
+static bfd_boolean vms_bfd_final_link (bfd *abfd,
+                                      struct bfd_link_info *link_info);
+static bfd_boolean vms_bfd_link_split_section (bfd *abfd, asection *section);
+static long vms_get_dynamic_symtab_upper_bound (bfd *abfd);
+static long vms_canonicalize_dynamic_symtab
+  (bfd *abfd, asymbol **symbols);
+#define vms_get_synthetic_symtab _bfd_nodynamic_get_synthetic_symtab
+static long vms_get_dynamic_reloc_upper_bound (bfd *abfd);
+static long vms_canonicalize_dynamic_reloc
+  (bfd *abfd, arelent **arel, asymbol **symbols);
+static bfd_boolean vms_bfd_merge_private_bfd_data (bfd *ibfd, bfd *obfd);
+static bfd_boolean vms_bfd_set_private_flags (bfd *abfd, flagword flags);
+
 #define vms_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
 #define vms_make_empty_symbol             _bfd_generic_make_empty_symbol
 #define vms_bfd_link_just_syms            _bfd_generic_link_just_syms
 #define vms_bfd_copy_private_header_data  _bfd_generic_bfd_copy_private_header_data
 #define vms_get_synthetic_symtab          _bfd_nodynamic_get_synthetic_symtab
 
-static unsigned int priv_section_count;
+\f
+#ifdef VMS_DEBUG
+/* Cause debug info to be emitted for the structure.  */
+struct vms_private_data_struct _vms_private_data_struct_dummy;
+struct vms_section_data_struct _vms_section_data_struct_dummy;
+#endif
+
 extern const bfd_target vms_vax_vec;
 extern const bfd_target vms_alpha_vec;
-\f
-/* Initialize private data.  */
 
+/* Initialize private data  */
 static bfd_boolean
 vms_initialize (bfd * abfd)
 {
-  int i;
   bfd_size_type amt;
 
   bfd_set_start_address (abfd, (bfd_vma) -1);
 
   amt = sizeof (struct vms_private_data_struct);
-  abfd->tdata.any = bfd_alloc (abfd, amt);
+  abfd->tdata.any = bfd_zalloc (abfd, amt);
   if (abfd->tdata.any == NULL)
     return FALSE;
 
-#ifdef __ALPHA
-  PRIV (is_vax) = FALSE;
-#else
-  PRIV (is_vax) = TRUE;
-#endif
-  PRIV (vms_buf) = NULL;
-  PRIV (buf_size) = 0;
-  PRIV (rec_length) = 0;
+  if (bfd_get_flavour (abfd) == bfd_target_ovax_flavour)
+    PRIV (is_vax) = TRUE;
+
   PRIV (file_format) = FF_UNKNOWN;
-  PRIV (fixup_done) = FALSE;
-  PRIV (sections) = NULL;
 
   amt = sizeof (struct stack_struct) * STACKSIZE;
   PRIV (stack) = bfd_alloc (abfd, amt);
   if (PRIV (stack) == NULL)
     goto error_ret1;
-  PRIV (stackptr) = 0;
 
   amt = sizeof (struct bfd_hash_table);
   PRIV (vms_symbol_table) = bfd_alloc (abfd, amt);
@@ -82,24 +189,12 @@ vms_initialize (bfd * abfd)
                            sizeof (vms_symbol_entry)))
     goto error_ret1;
 
-  amt = sizeof (struct location_struct) * LOCATION_SAVE_SIZE;
-  PRIV (location_stack) = bfd_alloc (abfd, amt);
-  if (PRIV (location_stack) == NULL)
-    goto error_ret2;
-
-  for (i = 0; i < VMS_SECTION_COUNT; i++)
-    PRIV (vms_section_table)[i] = NULL;
-
   amt = MAX_OUTREC_SIZE;
   PRIV (output_buf) = bfd_alloc (abfd, amt);
   if (PRIV (output_buf) == NULL)
     goto error_ret2;
 
-  PRIV (push_level) = 0;
-  PRIV (pushed_size) = 0;
   PRIV (length_pos) = 2;
-  PRIV (output_size) = 0;
-  PRIV (output_alignment) = 1;
 
   return TRUE;
 
@@ -111,154 +206,127 @@ vms_initialize (bfd * abfd)
   return FALSE;
 }
 
-/* Fill symbol->section with section ptr
+struct pair
+{
+  unsigned int section_count;
+  asection **sections;
+};
+
+/* Fill symbol->section with section pointer.
+
    symbol->section is filled with the section index for defined symbols
-   during reading the GSD/EGSD section. But we need the pointer to the
+   during reading the GSD/EGSD section.  But we need the pointer to the
    bfd section later.
 
-   It has the correct value for referenced (undefined section) symbols
+   It has the correct value for referenced (undefined section) symbols.
 
-   called from bfd_hash_traverse in vms_fixup_sections.  */
+   Called from bfd_hash_traverse in vms_fixup_sections.  */
 
 static bfd_boolean
-fill_section_ptr (struct bfd_hash_entry * entry, void * sections)
+fill_section_ptr (struct bfd_hash_entry *entry, void *sections)
 {
-  asection *sec;
-  asymbol *sym;
-
-  sym = ((vms_symbol_entry *) entry)->symbol;
-  sec = sym->section;
+  asymbol *sym = ((vms_symbol_entry *)entry)->symbol;
+  struct pair *data = (struct pair *)sections;
+  unsigned long sec = (unsigned long)sym->section;
 
 #if VMS_DEBUG
   vms_debug (6, "fill_section_ptr: sym %p, sec %p\n", sym, sec);
 #endif
 
-  /* Fill forward references (these contain section number, not section ptr).  */
-  if ((unsigned int) (size_t) sec < priv_section_count)
-    sec = ((vms_symbol_entry *) entry)->symbol->section =
-      ((asection **) sections)[(unsigned int) (size_t) sec];
-
-  if (strcmp (sym->name, sec->name) == 0)
-    sym->flags |= BSF_SECTION_SYM;
+  if (sec < data->section_count)
+    {
+      sym->section = data->sections[sec];
 
+      if (strcmp (sym->name, sym->section->name) == 0)
+       sym->flags |= BSF_SECTION_SYM;
+    }
+  else if (sec == (unsigned long)-1)
+    sym->section = &bfd_und_section;
+    
   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).  */
-
+/* Fixup section pointers in symbols.  */
 static bfd_boolean
 vms_fixup_sections (bfd * abfd)
 {
+  struct pair data;
+
   if (PRIV (fixup_done))
     return TRUE;
 
-  /* Traverse symbol table and fill in all section pointers.  */
-
-  /* Can't provide section count as argument to fill_section_ptr().  */
-  priv_section_count = PRIV (section_count);
-  bfd_hash_traverse (PRIV (vms_symbol_table), fill_section_ptr, (PRIV (sections)));
+  data.section_count = PRIV (section_count);
+  data.sections = PRIV (sections);
+  bfd_hash_traverse (PRIV (vms_symbol_table), fill_section_ptr, &data);
 
   PRIV (fixup_done) = TRUE;
-
   return TRUE;
 }
-\f
-/* 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 *
-vms_object_p (bfd * abfd)
+/* Slurp an ordered set of VMS object records.  */
+int
+_bfd_vms_slurp_object_records (bfd * abfd)
 {
-  int err = 0;
-  int prev_type;
-  const struct bfd_target *target_vector = NULL;
-  const bfd_arch_info_type *arch = NULL;
-  void * tdata_save = abfd->tdata.any;
-  bfd_vma saddr_save = bfd_get_start_address (abfd);
-
-#if VMS_DEBUG
-  vms_debug (1, "vms_object_p (%p)\n", abfd);
-#endif
-
-  if (!vms_initialize (abfd))
-    goto error_ret;
-
-  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET))
-    goto err_wrong_format;
-
-  prev_type = -1;
+  int err, new_type, type = -1;
 
   do
     {
 #if VMS_DEBUG
       vms_debug (7, "reading at %08lx\n", bfd_tell (abfd));
 #endif
-      if (_bfd_vms_next_record (abfd) < 0)
+      new_type = _bfd_vms_get_object_record (abfd);
+      if (new_type < 0)
        {
 #if VMS_DEBUG
          vms_debug (2, "next_record failed\n");
 #endif
-         goto err_wrong_format;
+         return -1;
        }
 
-      if ((prev_type == EOBJ_S_C_EGSD)
-          && (PRIV (rec_type) != EOBJ_S_C_EGSD))
+      if (type == EOBJ_S_C_EGSD && new_type != EOBJ_S_C_EGSD)
        {
          if (! vms_fixup_sections (abfd))
            {
 #if VMS_DEBUG
              vms_debug (2, "vms_fixup_sections failed\n");
 #endif
-             goto err_wrong_format;
+             return -1;
            }
        }
 
-      prev_type = PRIV (rec_type);
-
-      if (target_vector == NULL)
-       {
-         if (prev_type <= OBJ_S_C_MAXRECTYP)
-           target_vector = & vms_vax_vec;
-         else
-           target_vector = & vms_alpha_vec;
-       }
+      type = new_type;
 
-      switch (prev_type)
+      switch (type)
        {
          case OBJ_S_C_HDR:
          case EOBJ_S_C_EMH:
-           err = _bfd_vms_slurp_hdr (abfd, prev_type);
+           err = _bfd_vms_slurp_hdr (abfd, type);
            break;
          case OBJ_S_C_EOM:
          case OBJ_S_C_EOMW:
          case EOBJ_S_C_EEOM:
-           err = _bfd_vms_slurp_eom (abfd, prev_type);
+           err = _bfd_vms_slurp_eom (abfd, type);
            break;
          case OBJ_S_C_GSD:
          case EOBJ_S_C_EGSD:
-           err = _bfd_vms_slurp_gsd (abfd, prev_type);
+           err = _bfd_vms_slurp_gsd (abfd, type);
            break;
          case OBJ_S_C_TIR:
          case EOBJ_S_C_ETIR:
-           err = _bfd_vms_slurp_tir (abfd, prev_type);
+           err = _bfd_vms_slurp_tir (abfd, type);
            break;
          case OBJ_S_C_DBG:
          case EOBJ_S_C_EDBG:
-           err = _bfd_vms_slurp_dbg (abfd, prev_type);
+           err = _bfd_vms_slurp_dbg (abfd, type);
+           PRIV (dst_ptr_end) = PRIV (image_ptr);
            break;
          case OBJ_S_C_TBT:
          case EOBJ_S_C_ETBT:
-           err = _bfd_vms_slurp_tbt (abfd, prev_type);
+           err = _bfd_vms_slurp_tbt (abfd, type);
+           PRIV (dst_ptr_end) = PRIV (image_ptr);
            break;
          case OBJ_S_C_LNK:
-           err = _bfd_vms_slurp_lnk (abfd, prev_type);
+           err = _bfd_vms_slurp_lnk (abfd, type);
            break;
          default:
            err = -1;
@@ -266,14 +334,105 @@ vms_object_p (bfd * abfd)
       if (err != 0)
        {
 #if VMS_DEBUG
-         vms_debug (2, "slurp type %d failed with %d\n", prev_type, err);
+         vms_debug (2, "slurp type %d failed with %d\n", type, err);
 #endif
-         goto err_wrong_format;
+         return err;
        }
     }
-  while ((prev_type != EOBJ_S_C_EEOM) && (prev_type != OBJ_S_C_EOM) && (prev_type != OBJ_S_C_EOMW));
+  while (type != EOBJ_S_C_EEOM && type != OBJ_S_C_EOM && type != OBJ_S_C_EOMW);
+
+  return 0;
+}
+
+/* Slurp a VMS module and return an error status.  */
+
+static int
+vms_slurp_module (bfd *abfd)
+{
+  int type, err;
+
+  if (PRIV (is_vax))
+    type = PRIV (vms_rec)[0];
+  else
+    type = bfd_getl16 (PRIV (vms_rec));
+
+  err = _bfd_vms_slurp_hdr (abfd, type);
+  if (err != 0)
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return err;
+    }
+
+  return _bfd_vms_slurp_object_records (abfd);
+}
+
+/* Slurp a VMS image and return an error status.  */
+
+static int
+vms_slurp_image (bfd *abfd)
+{
+  unsigned int isd_offset, ihs_offset;
+  int err;
+
+  err = _bfd_vms_slurp_ihd (abfd, &isd_offset, &ihs_offset);
+  if (err != 0)
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return err;
+    }
 
-  if (target_vector == & vms_vax_vec)
+  err = _bfd_vms_slurp_isd (abfd, isd_offset);
+  if (err != 0)
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return err;
+    }
+
+  return _bfd_vms_slurp_ihs (abfd, ihs_offset);
+}
+
+/* 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 *
+vms_object_p (bfd *abfd)
+{
+  const struct bfd_target *target_vector;
+  const bfd_arch_info_type *arch;
+  PTR tdata_save = abfd->tdata.any;
+  bfd_vma saddr_save = bfd_get_start_address (abfd);
+  int err = 0;
+
+#if VMS_DEBUG
+  vms_debug (1, "vms_object_p(%p)\n", abfd);
+#endif
+
+  if (!vms_initialize (abfd))
+    goto error_ret;
+
+  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET))
+    goto err_wrong_format;
+
+  switch (_bfd_vms_get_first_record (abfd))
+    {
+    case FT_UNKNOWN:
+    default:
+      err = -1;
+      break;
+
+    case FT_MODULE:
+      err = vms_slurp_module (abfd);
+      break;
+
+    case FT_IMAGE:
+      err = vms_slurp_image (abfd);
+      break;
+    }
+
+  if (err != 0)
+    goto err_wrong_format;
+
+  if (PRIV (is_vax))
     {
       if (! vms_fixup_sections (abfd))
        {
@@ -283,38 +442,29 @@ vms_object_p (bfd * abfd)
          goto err_wrong_format;
        }
 
-      /* Set arch_info to vax.  */
-
+      target_vector = &vms_vax_vec;
       arch = bfd_scan_arch ("vax");
-      PRIV (is_vax) = TRUE;
+
 #if VMS_DEBUG
       vms_debug (2, "arch is vax\n");
 #endif
     }
-  else if (target_vector == & vms_alpha_vec)
+  else
     {
       /* Set arch_info to alpha.   */
-
+      target_vector = &vms_alpha_vec;
       arch = bfd_scan_arch ("alpha");
-      PRIV (is_vax) = FALSE;
 #if VMS_DEBUG
       vms_debug (2, "arch is alpha\n");
 #endif
     }
 
-  if (arch == NULL)
-    {
-#if VMS_DEBUG
-      vms_debug (2, "arch not found\n");
-#endif
-      goto err_wrong_format;
-    }
   abfd->arch_info = arch;
-
   return target_vector;
 
  err_wrong_format:
   bfd_set_error (bfd_error_wrong_format);
+
  error_ret:
   if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL)
     bfd_release (abfd, abfd->tdata.any);
@@ -341,6 +491,8 @@ vms_archive_p (bfd * abfd ATTRIBUTE_UNUSED)
 static bfd_boolean
 vms_mkobject (bfd * abfd)
 {
+  const bfd_arch_info_type *arch;
+
 #if VMS_DEBUG
   vms_debug (1, "vms_mkobject (%p)\n", abfd);
 #endif
@@ -348,20 +500,18 @@ vms_mkobject (bfd * abfd)
   if (!vms_initialize (abfd))
     return FALSE;
 
-  {
-#ifdef __VAX
-    const bfd_arch_info_type *arch = bfd_scan_arch ("vax");
-#else
-    const bfd_arch_info_type *arch = bfd_scan_arch ("alpha");
-#endif
-    if (arch == NULL)
-      {
-       bfd_set_error (bfd_error_wrong_format);
-       return FALSE;
-      }
-    abfd->arch_info = arch;
-  }
+  if (PRIV (is_vax))
+    arch = bfd_scan_arch ("vax");
+  else
+    arch = bfd_scan_arch ("alpha");
+
+  if (arch == 0)
+    {
+      bfd_set_error(bfd_error_wrong_format);
+      return FALSE;
+    }
 
+  abfd->arch_info = arch;
   return TRUE;
 }
 
@@ -420,6 +570,62 @@ vms_write_object_contents (bfd * abfd)
 
 /* 4.1, generic.  */
 
+/* Free the reloc buffer for the specified section.  */
+
+static void
+free_reloc_stream (bfd *abfd ATTRIBUTE_UNUSED, asection *section,
+                  void *data ATTRIBUTE_UNUSED)
+{
+  if (vms_section_data (section)->reloc_stream)
+    free (vms_section_data (section)->reloc_stream);
+}
+
+#ifdef VMS
+/* Convert the file to variable record length format. This is done
+   using undocumented system call sys$modify().
+   Pure VMS version.  */
+
+static void
+vms_convert_to_var (char *vms_filename)
+{
+  struct FAB fab = cc$rms_fab;
+
+  fab.fab$l_fna = vms_filename;
+  fab.fab$b_fns = strlen (vms_filename);
+  fab.fab$b_fac = FAB$M_PUT;
+  fab.fab$l_fop = FAB$M_ESC;
+  fab.fab$l_ctx = RME$C_SETRFM;
+  
+  sys$open (&fab);
+  
+  fab.fab$b_rfm = FAB$C_VAR;
+  
+  sys$modify (&fab);
+  sys$close (&fab);
+}
+
+static int
+vms_convert_to_var_1 (char *filename, int type)
+{
+  if (type != DECC$K_FILE)
+    return FALSE;
+  vms_convert_to_var (filename);
+  return TRUE;
+}
+
+/* Convert the file to variable record length format. This is done
+   using undocumented system call sys$modify().
+   Unix filename version.  */
+
+static int
+vms_convert_to_var_unix_filename (const char *unix_filename)
+{
+  if (decc$to_vms (unix_filename, &vms_convert_to_var_1, 0, 1) != 1)
+    return FALSE;
+  return TRUE;
+}
+#endif /* VMS */
+
 /* Called when the BFD is being closed to do any necessary cleanup.  */
 
 static bfd_boolean
@@ -428,8 +634,7 @@ vms_close_and_cleanup (bfd * abfd)
 #if VMS_DEBUG
   vms_debug (1, "vms_close_and_cleanup (%p)\n", abfd);
 #endif
-  if (abfd == NULL
-      || abfd->tdata.any == NULL)
+  if (abfd == NULL || abfd->tdata.any == NULL)
     return TRUE;
 
   if (PRIV (vms_buf) != NULL)
@@ -441,9 +646,23 @@ vms_close_and_cleanup (bfd * abfd)
   if (PRIV (vms_symbol_table))
     bfd_hash_table_free (PRIV (vms_symbol_table));
 
+  bfd_map_over_sections (abfd, free_reloc_stream, NULL);
+
   bfd_release (abfd, abfd->tdata.any);
   abfd->tdata.any = NULL;
 
+#ifdef VMS
+  if (abfd->direction == write_direction)
+    {
+      /* Last step on VMS is to convert the file to variable record length
+        format.  */
+      if (bfd_cache_close (abfd) != TRUE)
+       return FALSE;
+      if (vms_convert_to_var_unix_filename (abfd->filename) != TRUE)
+       return FALSE;
+    }
+#endif
+
   return TRUE;
 }
 
@@ -463,6 +682,8 @@ vms_bfd_free_cached_info (bfd * abfd ATTRIBUTE_UNUSED)
 static bfd_boolean
 vms_new_section_hook (bfd * abfd, asection *section)
 {
+  bfd_size_type amt;
+
   /* Count hasn't been incremented yet.  */
   unsigned int section_count = abfd->section_count + 1;
 
@@ -470,7 +691,8 @@ vms_new_section_hook (bfd * abfd, asection *section)
   vms_debug (1, "vms_new_section_hook (%p, [%d]%s), count %d\n",
             abfd, section->index, section->name, section_count);
 #endif
-  bfd_set_section_alignment (abfd, section, 4);
+
+  bfd_set_section_alignment (abfd, section, 0);
 
   if (section_count > PRIV (section_count))
     {
@@ -481,14 +703,22 @@ vms_new_section_hook (bfd * abfd, asection *section)
        return FALSE;
       PRIV (section_count) = section_count;
     }
+
 #if VMS_DEBUG
   vms_debug (6, "section_count: %d\n", PRIV (section_count));
 #endif
+
   PRIV (sections)[section->index] = section;
+
 #if VMS_DEBUG
   vms_debug (7, "%d: %s\n", section->index, section->name);
 #endif
 
+  amt = sizeof (struct vms_section_data_struct);
+  section->used_by_bfd = (PTR) bfd_zalloc (abfd, amt);
+  if (section->used_by_bfd == NULL)
+    return FALSE;
+
   return _bfd_generic_new_section_hook (abfd, section);
 }
 
@@ -503,13 +733,42 @@ vms_get_section_contents (bfd * abfd ATTRIBUTE_UNUSED,
                          file_ptr offset ATTRIBUTE_UNUSED,
                          bfd_size_type buf_size ATTRIBUTE_UNUSED)
 {
+  bfd_size_type size = section->size;
+
 #if VMS_DEBUG
   vms_debug (1, "vms_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;
+  if (section->contents)
+    abort ();
+
+  section->contents = (unsigned char *) bfd_malloc (size);
+
+  if (section->contents == NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return FALSE;
+    }
+
+  if (bfd_seek (abfd, section->filepos, SEEK_SET))
+    {
+      bfd_set_error (bfd_error_file_truncated);
+      return FALSE;
+    }
+
+  if (bfd_bread (section->contents, size, abfd) != size)
+    {
+      bfd_set_error (bfd_error_file_truncated);
+      return FALSE;
+    }
+
+  section->flags |= SEC_IN_MEMORY;
+
+  if (buf)
+    memcpy (buf, section->contents + offset, (size_t) buf_size);
+
+  return TRUE;
 }
 
 /* Read the contents of a section.
@@ -703,7 +962,6 @@ vms_truncate_arname (bfd * abfd ATTRIBUTE_UNUSED,
 #if VMS_DEBUG
   vms_debug (1, "vms_truncate_arname (%p, %s, %s)\n", abfd, pathname, arhdr);
 #endif
-  return;
 }
 
 /* ??? write archive map.  */
@@ -906,7 +1164,9 @@ vms_get_symbol_info (bfd * abfd ATTRIBUTE_UNUSED,
   if (ret == NULL)
     return;
 
-  if (bfd_is_com_section (sec))
+  if (sec == 0)
+    ret->type = 'U';
+  else if (bfd_is_com_section (sec))
     ret->type = 'C';
   else if (bfd_is_abs_section (sec))
     ret->type = 'A';
@@ -972,7 +1232,7 @@ vms_find_nearest_line (bfd * abfd ATTRIBUTE_UNUSED,
   vms_debug (1, "vms_find_nearest_line (%p, %s, %p, %ld, <ret>, <ret>, <ret>)\n",
              abfd, section->name, symbols, (long int)offset);
 #endif
-  return FALSE;
+  return _bfd_vms_find_nearest_dst_line (abfd, section, symbols, offset, file, func, line);
 }
 
 static bfd_boolean
@@ -1037,36 +1297,160 @@ vms_minisymbol_to_symbol (bfd * abfd,
 
 /* 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.  */
+/* Allocate the reloc buffer for the specified section.  */
 
-static long
-vms_get_reloc_upper_bound (bfd * abfd ATTRIBUTE_UNUSED,
-                          asection *section ATTRIBUTE_UNUSED)
+static void
+alloc_reloc_stream (bfd *abfd ATTRIBUTE_UNUSED, asection *section,
+                   void *alloc_error)
 {
+  unsigned char *ptr;
+
+  /* If there were no relocations, there is nothing to do.  */
+  if (section->reloc_count == 0)
+    return;
+
+  ptr = bfd_malloc (vms_section_data (section)->reloc_size);
+  if (ptr == NULL)
+    {
+      *(bfd_boolean *)alloc_error = TRUE;
+      return;
+    }
+
+  vms_section_data (section)->reloc_stream = ptr;
+}
+
+/* Read in the relocs for the specified section and internalize them.
+
+   The implementation is loosely based on the SOM code and made up
+   of 3 distinct phases:
+
+   1. When the VMS object is opened and parsed, the number and the size
+      of the relocations are computed for all sections.  This makes it
+      possible to know upfront both which sections have no relocs and
+      the size of the reloc buffers for the other sections, at virtually
+      no cost for consumers that don't care about relocs at all.
+
+   2. When vms_slurp_reloc_table is invoked for the first time on a section
+      with relocs, the object is traversed and all the reloc information
+      is saved in per-section reloc buffers.  It would be very inefficient
+      to scan the whole file on each invocation, so we slurp for all the
+      sections at once.
+
+   3. On subsequent invocations of vms_slurp_reloc_table, the relocs for the
+      specified section are fetched from the buffer, decoded and internalized.
+      The buffer is then freed since the internalized relocs are attached to
+      the section, turning additional invocations of vms_slurp_reloc_table
+      on the same section into no-ops.
+
+   Since VMS objects have very few sections, it could be profitable to merge
+   phase #2 and phase #3, i.e. to decode and internalize the relocs for all
+   the sections at once.  The current implementation is more elegant.  */
+
+static bfd_boolean
+vms_slurp_reloc_table (bfd *abfd, asection *section, asymbol **symbols)
+{
+  arelent *internal_relocs;
+  bfd_size_type amt;
+  int err;
+
+  /* If there were no relocations, there is nothing to do.  */
+  if (section->reloc_count == 0)
+    return TRUE;
+
+  /* Return saved information about the relocations if it is available.  */
+  if (section->relocation != NULL)
+    return TRUE;
+
+  /* If the relocation stream has not been slurped, do it now.  */
+  if (vms_section_data (section)->reloc_stream == NULL)
+    {
+      bfd_boolean alloc_error = FALSE;
+      int type;
+
+      /* Size the reloc buffer for each section.  */
+      bfd_map_over_sections (abfd, alloc_reloc_stream, &alloc_error);
+      if (alloc_error)
+       return FALSE;
+
+      if (bfd_seek (abfd, 0, SEEK_SET) != 0)
+       return FALSE;
+
+      /* Reset section pointer.  */
+      PRIV (image_section) = NULL;
+
+      do
+       {
+         type = _bfd_vms_get_object_record (abfd);
+         if (type != EOBJ_S_C_ETIR
+             && type != EOBJ_S_C_EDBG
+             && type != EOBJ_S_C_ETBT)
+           continue;
+         err = _bfd_vms_slurp_relocs (abfd);
+         if (err != 0)
+           {
+#if VMS_DEBUG
+             vms_debug (2, "slurp relocs failed with %d\n", err);
+#endif
+             return FALSE;
+           }
+       }
+      while (type != EOBJ_S_C_EEOM);
+    }
+
+  amt = section->reloc_count * sizeof (arelent);
+  internal_relocs = (arelent *) bfd_zalloc (abfd, amt);
+  if (internal_relocs == NULL)
+    return FALSE;
+
+  /* Decode and internalize the relocations.  */
+  err = _bfd_vms_decode_relocs (abfd, internal_relocs, section, symbols);
+  if (err != 0)
+    {
 #if VMS_DEBUG
-  vms_debug (1, "vms_get_reloc_upper_bound (%p, %s)\n", abfd, section->name);
+      vms_debug (2, "decode relocs failed with %d\n", err);
 #endif
-  return -1L;
+      return FALSE;
+    }
+
+  /* We're done with the external relocations.  Free them.  */
+  free (vms_section_data (section)->reloc_stream);
+  vms_section_data (section)->reloc_stream = NULL;
+
+  /* Save our results and return success.  */
+  section->relocation = internal_relocs;
+  return TRUE;
 }
 
-/* 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.  */
+/* Return the number of bytes required to store the relocation
+   information associated with the given section.  */
 
 static long
-vms_canonicalize_reloc (bfd * abfd ATTRIBUTE_UNUSED,
-                       asection *section ATTRIBUTE_UNUSED,
-                       arelent **location ATTRIBUTE_UNUSED,
-                       asymbol **symbols ATTRIBUTE_UNUSED)
+vms_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *section)
 {
-#if VMS_DEBUG
-  vms_debug (1, "vms_canonicalize_reloc (%p, %s, <ret>, <ret>)\n", abfd, section->name);
-#endif
-  return FALSE;
+  return (section->reloc_count + 1) * sizeof (arelent *);  
+}
+
+/* Convert relocations from VMS (external) form into BFD internal
+   form.  Return the number of relocations.  */
+
+static long
+vms_canonicalize_reloc (bfd *abfd, asection *section, arelent **relptr,
+                       asymbol **symbols)
+{
+  arelent *tblptr;
+  int count;
+
+  if (! vms_slurp_reloc_table (abfd, section, symbols))
+    return -1;
+
+  count = section->reloc_count;
+  tblptr = section->relocation;
+
+  while (count--)
+    *relptr++ = tblptr++;
+
+  *relptr = (arelent *) NULL;
+  return section->reloc_count;
 }
 \f
 /* This is just copied from ecoff-alpha, needs to be fixed probably.  */
@@ -1317,6 +1701,64 @@ static reloc_howto_type alpha_howto_table[] =
         0xffffffff,            /* Dest mask.  */
         FALSE),                /* PC rel offset.  */
 
+  HOWTO (ALPHA_R_NOP,          /* Type.  */
+        0,                     /* Rightshift.  */
+        3,                     /* Size (0 = byte, 1 = short, 2 = long).  */
+        0,                     /* Bitsize.  */
+        /* The following value must match that of ALPHA_R_BSR/ALPHA_R_BOH
+           because the calculations for the 3 relocations are the same.
+           See B.4.5.2 of the OpenVMS Linker Utility Manual.  */
+        TRUE,                  /* PC relative.  */
+        0,                     /* Bitpos.   */
+        complain_overflow_dont,/* Complain_on_overflow.  */
+        reloc_nil,             /* Special_function.  */
+        "NOP",                 /* Name.  */
+        FALSE,                 /* Partial_inplace.  */
+        0xffffffff,            /* Source mask.  */
+        0xffffffff,            /* Dest mask.  */
+        FALSE),                /* PC rel offset.  */
+
+  HOWTO (ALPHA_R_BSR,          /* Type.  */
+        0,                     /* Rightshift.  */
+        3,                     /* Size (0 = byte, 1 = short, 2 = long).  */
+        0,                     /* Bitsize.  */
+        TRUE,                  /* PC relative.  */
+        0,                     /* Bitpos.  */
+        complain_overflow_dont,/* Complain_on_overflow.  */
+        reloc_nil,             /* Special_function.  */
+        "BSR",                 /* Name.  */
+        FALSE,                 /* Partial_inplace.  */
+        0xffffffff,            /* Source mask.  */
+        0xffffffff,            /* Dest mask.  */
+        FALSE),                /* PC rel offset.  */
+
+  HOWTO (ALPHA_R_LDA,          /* Type.  */
+        0,                     /* Rightshift.  */
+        3,                     /* Size (0 = byte, 1 = short, 2 = long).  */
+        0,                     /* Bitsize.  */
+        FALSE,                 /* PC relative.  */
+        0,                     /* Bitpos.  */
+        complain_overflow_dont,/* Complain_on_overflow.  */
+        reloc_nil,             /* Special_function.  */
+        "LDA",                 /* Name.  */
+        FALSE,                 /* Partial_inplace.  */
+        0xffffffff,            /* Source mask.  */
+        0xffffffff,            /* Dest mask.  */
+        FALSE),                /* PC rel offset.  */
+
+  HOWTO (ALPHA_R_BOH,          /* Type.  */
+        0,                     /* Rightshift.  */
+        3,                     /* Size (0 = byte, 1 = short, 2 = long, 3 = nil).  */
+        0,                     /* Bitsize.  */
+        TRUE,                  /* PC relative.  */
+        0,                     /* Bitpos.  */
+        complain_overflow_dont,/* Complain_on_overflow.  */
+        reloc_nil,             /* Special_function.  */
+        "BOH",                 /* Name.  */
+        FALSE,                 /* Partial_inplace.  */
+        0xffffffff,            /* Source mask.  */
+        0xffffffff,            /* Dest mask.  */
+        FALSE),                /* PC rel offset.  */
 };
 
 /* Return a pointer to a howto structure which, when invoked, will perform
@@ -1345,6 +1787,10 @@ vms_bfd_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
       case BFD_RELOC_64_PCREL:         alpha_type = ALPHA_R_SREL64;    break;
       case BFD_RELOC_ALPHA_LINKAGE:    alpha_type = ALPHA_R_LINKAGE;   break;
       case BFD_RELOC_ALPHA_CODEADDR:   alpha_type = ALPHA_R_CODEADDR;  break;
+      case BFD_RELOC_ALPHA_NOP:                alpha_type = ALPHA_R_NOP;       break;
+      case BFD_RELOC_ALPHA_BSR:                alpha_type = ALPHA_R_BSR;       break;
+      case BFD_RELOC_ALPHA_LDA:                alpha_type = ALPHA_R_LDA;       break;
+      case BFD_RELOC_ALPHA_BOH:                alpha_type = ALPHA_R_BOH;       break;
       default:
        (*_bfd_error_handler) ("reloc (%d) is *UNKNOWN*", code);
        return NULL;
@@ -1385,14 +1831,18 @@ vms_set_arch_mach (bfd * abfd,
 #if VMS_DEBUG
   vms_debug (1, "vms_set_arch_mach (%p, %d, %ld)\n", abfd, arch, mach);
 #endif
-  abfd->arch_info = bfd_scan_arch ("alpha");
 
-  return TRUE;
+  if (arch != bfd_arch_alpha
+      && arch != bfd_arch_vax
+      && arch != bfd_arch_unknown)
+    return FALSE;
+
+  return bfd_default_set_arch_mach (abfd, arch, mach);
 }
 
 /* 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.
+   in memory at LOCATION. 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
@@ -1411,7 +1861,16 @@ vms_set_section_contents (bfd * abfd,
             abfd, section->name, location, (long int)offset, (int)count);
   vms_debug (2, "size %d\n", (int) section->size);
 #endif
-  return _bfd_save_vms_section (abfd, section, location, offset, count);
+  if (count == (bfd_size_type)0)
+    return TRUE;
+
+  if (section->contents == NULL)
+    section->contents = bfd_alloc (abfd, section->size);
+  if (section->contents == NULL)
+    return FALSE;
+
+  memcpy (section->contents + offset, location, (size_t) count);
+  return TRUE;
 }
 
 /* Part 4.8, linker.  */
@@ -1550,7 +2009,7 @@ vms_get_dynamic_symtab_upper_bound (bfd * abfd ATTRIBUTE_UNUSED)
 #if VMS_DEBUG
   vms_debug (1, "vms_get_dynamic_symtab_upper_bound (%p)\n", abfd);
 #endif
-  return 0;
+  return 0L;
 }
 
 static bfd_boolean
@@ -1606,14 +2065,14 @@ const bfd_target vms_alpha_vec =
   BFD_ENDIAN_LITTLE,           /* Data byte order is little.  */
   BFD_ENDIAN_LITTLE,           /* Header byte order is little.  */
 
-  (HAS_RELOC | HAS_SYMS
+  (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS
    | 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.  */
+  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,
@@ -1640,7 +2099,7 @@ const bfd_target vms_alpha_vec =
 
   NULL,
 
-  NULL
+  (PTR) 0
 };
 
 const bfd_target vms_vax_vec =
@@ -1657,15 +2116,15 @@ const bfd_target vms_vax_vec =
   (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.  */
+  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, /* Data.  */
   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
-  bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Headers.  */
+  bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Hdrs.  */
 
   {_bfd_dummy_target, vms_object_p,            /* bfd_check_format.  */
    vms_archive_p, _bfd_dummy_target},
@@ -1686,5 +2145,5 @@ const bfd_target vms_vax_vec =
 
   NULL,
 
-  NULL
+  (PTR) 0
 };
index 223554086cf8f3550e212d507efc781101ec0f8c..b7d9344cf90a9ed4845ffe74a9d1b07823d66a25 100644 (file)
--- a/bfd/vms.h
+++ b/bfd/vms.h
@@ -1,6 +1,8 @@
 /* vms.h -- Header file for VMS (Alpha and Vax) support.
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2007
-   Free Software Foundation, Inc.
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2007,
+   2008, 2009 Free Software Foundation, Inc.
+
+   Main header file.
 
    Written by Klaus K"ampf (kkaempf@rmi.de)
 
 #ifndef VMS_H
 #define VMS_H
 
-/* Constants starting with 'Exxx_' are for openVMS/Alpha (EVAX object language)  */
+/* Constants starting with 'Exxx_' are for openVMS/Alpha (EVAX object
+   language).  */
+
+#define VMS_BLOCK_SIZE  512
 
-/* VMS Text, information and relocation record (TIR/ETIR) definitions.  */
+/* VMS Text Information and Relocation Records (TIR/ETIR).  */
 
 #define TIR_S_C_STA_GBL                0
 #define TIR_S_C_STA_SB         1
 #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_PQ 3              /* Stack psect base + quadword off.  */
 #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_STC_NBH_PS 214                /* Store-conditional NOP,BSR or HINT at psect + offset.  */
 #define ETIR_S_C_MAXSTCCOD 214         /* Maximum store-conditional code.   */
 
-/* VMS Global symbol definition record (GSD/EGSD).  */
+#define ETIR_S_C_HEADER_SIZE 4         /* Size of the header of a command */
+
+/* VMS Global Symbol Directory Records (GSD/EGSD).  */
 
 #define GSD_S_K_ENTRIES 1
 #define GSD_S_C_ENTRIES 1
 #define EGSD_S_C_SYMG 8                /* EGST - gst version of SYM.           */
 #define EGSD_S_C_MAXRECTYP 8   /* Maximum entry type defined.          */
 
+/* Program Section Definition.  */
 #define GPS_S_M_PIC     1
 #define GPS_S_M_LIB     2
 #define GPS_S_M_OVR     4
 #define GPS_S_K_NAME    9
 #define GPS_S_C_NAME    9
 
-#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 EGPS_S_B_ALIGN    4
+#define EGPS_S_W_FLAGS    6
+#define EGPS_S_L_ALLOC    8
+#define EGPS_S_B_NAMLNG  12
+
+#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 EGPS_S_V_ALLOC_64BIT   0x1000
+
+/* Symbol Defintion or Reference.  */
 #define GSY_S_M_WEAK    1
 #define GSY_S_M_DEF     2
 #define GSY_S_M_UNI     4
 #define GSY_S_M_REL     8
 
-#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
+#define EGSY_S_W_FLAGS  6
+
+#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
+#define EGSY_S_V_QUAD_VAL      0x0080
 
 #define LSY_S_M_DEF     2
 #define LSY_S_M_REL     8
 #define ENV_S_M_DEF     1
 #define ENV_S_M_NESTED  2
 
+/* Symbol Definition.  */
+#define ESDF_S_L_VALUE     8
+#define ESDF_S_L_PSINDX   28
+#define ESDF_S_B_NAMLNG   32
+
+/* Universal Symbol Definition.  */
+#define EGST_S_W_FLAGS    6
+#define EGST_S_Q_LP_1    16
+#define EGST_S_Q_LP_2    24
+#define EGST_S_L_PSINDX  32
+#define EGST_S_B_NAMLNG  36
+
+/* Symbol Reference.  */
+#define ESRF_S_B_NAMLNG   8
+
 /* Debugger symbol definitions:  These are done by hand,
    as no machine-readable version seems to be available.  */
 #define DST_S_C_C                7     /* Language == "C".     */
 #define DST_S_C_CXX             15     /* Language == "C++".   */
+#define DST_S_C_EPILOG         127
 #define DST_S_C_VERSION                153
 #define        DST_S_C_SOURCE          155     /* Source file.         */
 #define DST_S_C_PROLOG         162
 #define        DST_S_C_MODEND          189     /* End of module.       */
 #define        DST_S_C_RTNBEG          190     /* Beginning of routine.*/
 #define        DST_S_C_RTNEND          191     /* End of routine.      */
-#define        DST_S_C_DELTA_PC_W      1       /* Incr PC.             */
-#define        DST_S_C_INCR_LINUM      2       /* Incr Line #.         */
-#define        DST_S_C_INCR_LINUM_W    3       /* Incr Line #.         */
-#define DST_S_C_SET_LINUM_INCR 4
+
+/* These are used with DST_S_C_LINE_NUM.  */
+#define DST_S_C_LINE_NUM_HEADER_SIZE 4
+
+#define DST_S_C_DELTA_PC_W      1      /* Incr PC.             */
+#define DST_S_C_INCR_LINUM      2      /* Incr Line #.         */
+#define DST_S_C_INCR_LINUM_W    3      /* Incr Line #.         */
+#define DST_S_C_SET_LINUM_INCR  4
 #define DST_S_C_SET_LINUM_INCR_W 5
 #define DST_S_C_RESET_LINUM_INCR 6
-#define DST_S_C_BEG_STMT_MODE  7
-#define DST_S_C_END_STMT_MODE  8
-#define        DST_S_C_SET_LINE_NUM    9       /* Set Line #.          */
+#define DST_S_C_BEG_STMT_MODE   7
+#define DST_S_C_END_STMT_MODE   8
+#define DST_S_C_SET_LINE_NUM    9      /* Set Line #.          */
 #define DST_S_C_SET_PC         10
 #define DST_S_C_SET_PC_W       11
 #define DST_S_C_SET_PC_L       12
 #define DST_S_C_SRC_SETFILE     2      /* Set source file.      */
 #define DST_S_C_SRC_SETREC_L    3      /* Set record, longword value.  */
 #define DST_S_C_SRC_SETREC_W    4      /* Set record, word value.  */
+#define DST_S_C_SRC_SETLNUM_L   5      /* Set line, longword value.  */
+#define DST_S_C_SRC_SETLNUM_W   6      /* Set line, word value.  */
+#define DST_S_C_SRC_INCRLNUM_B  7      /* Increment line.  */
 #define DST_S_C_SRC_DEFLINES_W 10      /* # of line, word counter.  */
 #define DST_S_C_SRC_DEFLINES_B 11      /* # of line, byte counter.  */
 #define DST_S_C_SRC_FORMFEED   16      /* ^L counts as a record.  */
+
+#define DST_S_B_PCLINE_UNSBYTE  1
+#define DST_S_W_PCLINE_UNSWORD  1
+#define DST_S_L_PCLINE_UNSLONG  1
+
+#define DST_S_B_MODBEG_NAME    14
+#define DST_S_L_RTNBEG_ADDRESS  5
+#define DST_S_B_RTNBEG_NAME    13
+#define DST_S_L_RTNEND_SIZE     5
+
+/* These are used with DST_S_C_SOURCE.  */
+#define DST_S_C_SOURCE_HEADER_SIZE 4
+
+#define DST_S_B_SRC_DF_LENGTH    1
+#define DST_S_W_SRC_DF_FILEID    3
+#define DST_S_B_SRC_DF_FILENAME         20
+#define DST_S_B_SRC_UNSBYTE      1
+#define DST_S_W_SRC_UNSWORD      1
+#define DST_S_L_SRC_UNSLONG      1
+
 /* The following are the codes for the various data types.  Anything not on
    the list is included under 'advanced_type'.  */
 #define DBG_S_C_UCHAR          0x02
 #define DSC_K_CLASS_D          0x02    /* Dynamic string (not via malloc!).  */
 #define DSC_K_CLASS_A          0x04    /* Array.  */
 #define DSC_K_CLASS_UBS                0x0d    /* Unaligned bit string.  */
+
 /*  These are the codes that are used to generate the definitions of struct
     union and enum records.  */
 #define DBG_S_C_ENUM_ITEM              0xa4
 #define DBG_S_C_STRUCT_ITEM            DST_K_VFLAGS_BITOFFS    /* 0xff */
 #define DBG_S_C_STRUCT_START           0xab
 #define DBG_S_C_STRUCT_END             0xac
-#define DST_K_TYPSPEC                  0xaf            /* Type specification.  */
+#define DST_K_TYPSPEC                  0xaf    /* Type specification.  */
 /* These codes are used in the generation of the symbol definition records.  */
 #define DST_K_VFLAGS_NOVAL             0x80    /* Struct definition only.  */
 #define DST_K_VFLAGS_DSC               0xfa    /* Descriptor used.  */
 #define DBG_S_C_VOID                   DST_K_TS_PTR
 #define DBG_S_C_COMPLEX_ARRAY          DST_K_TS_ARRAY
 
-/* VMS Module header record (EMH) definitions.  */
+/* VMS Module Header Records (MHD/EMH).  */
 
 #define MHD_S_C_MHD 0
 #define MHD_S_C_LNM 1
 /* vms.c.  */
 
 extern asymbol *_bfd_vms_make_empty_symbol (bfd *);
+extern int _bfd_vms_slurp_object_records (bfd *abfd);
 
 /* vms-gsd.c.  */
 
-extern int _bfd_vms_slurp_gsd (bfd *, int);
-extern int _bfd_vms_write_gsd (bfd *, int);
+extern int _bfd_vms_slurp_gsd (bfd *abfd, int objtype);
+extern int _bfd_vms_write_gsd (bfd *abfd, int objtype);
+extern int _bfd_vms_slurp_dbg (bfd *abfd, int objtype);
+extern int _bfd_vms_write_dbg (bfd *abfd, int objtype);
+extern int _bfd_vms_slurp_tbt (bfd *abfd, int objtype);
+extern int _bfd_vms_write_tbt (bfd *abfd, int objtype);
 
-/* vms-mhd.c.  */
+/* vms-misc.c.  */
 
-extern int _bfd_vms_slurp_hdr (bfd *, int);
-extern int _bfd_vms_write_hdr (bfd *, int);
-extern int _bfd_vms_slurp_eom (bfd *, int);
-extern int _bfd_vms_write_eom (bfd *, int);
+extern int _bfd_vms_get_object_record (bfd *abfd);
+extern int _bfd_vms_get_first_record (bfd *abfd);
+
+/* vms-hdr.c.  */
+
+extern int _bfd_vms_slurp_hdr (bfd *abfd, int objtype);
+extern int _bfd_vms_write_hdr (bfd *abfd, int objtype);
+extern int _bfd_vms_slurp_eom (bfd *abfd, int objtype);
+extern int _bfd_vms_write_eom (bfd *abfd, int objtype);
+extern bfd_boolean _bfd_vms_find_nearest_dst_line
+  (bfd *abfd, asection *section, asymbol **symbols, bfd_vma offset,
+          const char **file, const char **func, unsigned int *line);
+extern int _bfd_vms_slurp_ihd
+  (bfd *abfd, unsigned int *isd_offset, unsigned int *ihs_offset);
+extern int _bfd_vms_slurp_isd (bfd *abfd, unsigned int offset);
+extern int _bfd_vms_slurp_ihs (bfd *abfd, unsigned int offset);
 
 /* vms-tir.c.  */
 
-extern int _bfd_vms_slurp_tir (bfd *, int);
-extern int _bfd_vms_slurp_dbg (bfd *, int);
-extern int _bfd_vms_slurp_tbt (bfd *, int);
-extern int _bfd_vms_slurp_lnk (bfd *, int);
-                                        
-extern int _bfd_vms_write_tir (bfd *, int);
-extern int _bfd_vms_write_tbt (bfd *, int);
-extern int _bfd_vms_write_dbg (bfd *, int);
-                                        
-/* The r_type field in a reloc is one of he 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       
-#define ALPHA_R_CODEADDR       13       
-                                        
-/* Object language definitions.  */     
-                                        
+extern int _bfd_vms_slurp_tir (bfd *abfd, int objtype);
+extern int _bfd_vms_write_tir (bfd *abfd, int objtype);
+extern int _bfd_vms_slurp_lnk (bfd *abfd, int objtype);
+
+extern int _bfd_vms_slurp_relocs (bfd *abfd);
+extern int _bfd_vms_decode_relocs
+  (bfd *abfd, arelent *relocs, asection *section, asymbol **symbols);
+
+/* 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
+#define ALPHA_R_CODEADDR       13
+#define ALPHA_R_NOP            14
+#define ALPHA_R_BSR            15
+#define ALPHA_R_LDA            16
+#define ALPHA_R_BOH            17
+
+/* VMS Object Language (OBJ/EOBJ).  */
+
 #define OBJ_S_C_HDR 0          /* VAX moule header record.             */
 #define OBJ_S_C_GSD 1          /* VAX glbal symbol definition record.  */
 #define OBJ_S_C_TIR 2          /* VAX tet information record.          */
@@ -453,13 +535,15 @@ extern int _bfd_vms_write_dbg (bfd *, int);
 #define OBJ_S_C_LNK 6          /* VAX liker options record.            */
 #define OBJ_S_C_EOMW 7         /* VAX en of module word-psect record.  */
 #define OBJ_S_C_MAXRECTYP 7    /* VAX Lat assigned record type.        */
+
 #define EOBJ_S_C_EMH 8         /* EVAX mdule header record.            */
 #define EOBJ_S_C_EEOM 9                /* EVAX ed of module record.            */
-#define EOBJ_S_C_EGSD 10       /* EVAX gobal symbol definition record.*/
-#define EOBJ_S_C_ETIR 11       /* EVAX txt information record. */
+#define EOBJ_S_C_EGSD 10       /* EVAX gobal symbol definition record. */
+#define EOBJ_S_C_ETIR 11       /* EVAX txt information record.         */
 #define EOBJ_S_C_EDBG 12       /* EVAX Dbugger information record.     */
 #define EOBJ_S_C_ETBT 13       /* EVAX Taceback information record.    */
 #define EOBJ_S_C_MAXRECTYP 13  /* EVAX Lst assigned record type.       */
+
 #define OBJ_S_K_SUBTYP 1                
 #define OBJ_S_C_SUBTYP 1                
 #define EOBJ_S_K_SUBTYP 4               
@@ -475,8 +559,9 @@ extern int _bfd_vms_write_dbg (bfd *, int);
 #define EOBJ_S_C_STOREPLIM -1  /* Maximu repeat count on store commands.  */
 #define OBJ_S_C_PSCALILIM 9    /* Maximu p-sect alignment.            */
 #define EOBJ_S_C_PSCALILIM 16  /* Maximu p-sect alignment.            */
-                                        
+
 #define EVAX_OFFSET    256     /* Type ofset for EVAX codes in switch.  */
+
 /* Miscellaneous definitions.  */       
 
 #if __GNUC__                            
@@ -484,140 +569,286 @@ typedef unsigned long long uquad;
 #else                                   
 typedef unsigned long uquad;            
 #endif                                  
-                                        
-#define MAX_OUTREC_SIZE 4096            
-#define MIN_OUTREC_LUFT 64              
-                                        
-typedef struct _vms_section             
-{                                       
-  unsigned char *contents;              
-  bfd_vma offset;                       
-  bfd_size_type size;                   
-  struct _vms_section *next;            
-} vms_section;                          
-                                        
-extern vms_section * _bfd_get_vms_section (bfd *, int);
-                                        
-typedef struct _vms_reloc               
-{                                       
-  struct _vms_reloc *next;              
-  arelent *reloc;                       
-  asection *section;                    
-} vms_reloc;                            
-                                        
+
+#define MAX_OUTREC_SIZE 4096
+#define MIN_OUTREC_LUFT 64
+
 /* VMS module header.  */               
-                                        
-struct hdr_struc                        
-{                                       
-  int    hdr_b_strlvl;                  
-  long   hdr_l_arch1;                   
-  long   hdr_l_arch2;                   
-  long   hdr_l_recsiz;                  
-  char * hdr_t_name;                    
-  char * hdr_t_version;                         
-  char * hdr_t_date;                    
-  char * hdr_c_lnm;                     
-  char * hdr_c_src;                     
-  char * hdr_c_ttl;                     
-};                                      
-                                        
-/* VMS end of module.  */               
-                                        
-struct eom_struc                        
-{                                       
-  long          eom_l_total_lps;        
-  unsigned char eom_b_comcod;           
-  bfd_boolean   eom_has_transfer;       
-  unsigned char eom_b_tfrflg;           
-  long          eom_l_psindx;           
-  long          eom_l_tfradr;           
-};                                      
-                                        
-enum file_format_enum { FF_UNKNOWN, FF_FOREIGN, FF_NATIVE, FF_VAX };
-                                        
-typedef struct vms_symbol_struct        
-{                                       
-  struct bfd_hash_entry bfd_hash;       
-  asymbol *symbol;                      
-} vms_symbol_entry;                     
-                                        
+
+struct hdr_struct
+{
+  char hdr_b_strlvl;
+  int hdr_l_arch1;
+  int hdr_l_arch2;
+  int hdr_l_recsiz;
+  char *hdr_t_name;
+  char *hdr_t_version;
+  char *hdr_t_date;
+  char *hdr_c_lnm;
+  char *hdr_c_src;
+  char *hdr_c_ttl;
+  char *hdr_c_cpr;
+};
+
+#define EMH_S_W_HDRTYP   4
+#define EMH_S_B_STRLVL   6
+#define EMH_S_L_ARCH1    8
+#define EMH_S_L_ARCH2   12
+#define EH_S_L_RECSIZ  16
+#define EMH_S_B_NAMLNG  20
+
+#define EMH_DATE_LENGTH  17
+
+/* VMS End-Of-Module records (EOM/EEOM).  */
+
+struct eom_struct
+{
+  int eom_l_total_lps;
+  short eom_w_comcod;
+  bfd_boolean eom_has_transfer;
+  char eom_b_tfrflg;
+  int eom_l_psindx;
+  int eom_l_tfradr;
+};
+
+#define EEOM_S_L_TOTAL_LPS   4
+#define EEOM_S_W_COMCOD      8
+#define EEOM_S_B_TFRFLG     10
+#define EEOM_S_L_PSINDX     12
+#define EEOM_S_L_TFRADR     16
+
+/* VMS Image Header Records (IHD/EIHD).  */
+
+#define EIHD_S_K_MAJORID       3       /* Major id constant    */
+#define EIHD_S_K_MINORID       0       /* Minor id constant    */
+#define EIHD_S_K_EXE           1       /* Executable image     */
+
+#define EIHD_S_L_SIZE          8
+#define EIHD_S_L_ISDOFF                12
+#define EIHD_S_L_SYMDBGOFF     20
+#define EIHD_S_Q_SYMVVA                40
+#define EIHD_S_L_IMGTYPE       52
+
+/* VMS Image Section Description Records (ISD/EISD).  */
+
+#define EISD_S_L_EISDSIZE       8
+#define EISD_S_L_SECSIZE       12
+#define EISD_S_Q_VIR_ADDR      16
+#define EISD_S_L_FLAGS         24
+#define EISD_S_L_VBN           28
+#define EISD_S_R_CONTROL       32
+#define EISD_S_L_IDENT         36
+#define EISD_S_T_GBLNAM                40
+
+#define EISD_S_M_GBL           0x0001
+#define EISD_S_M_CRF           0x0002
+#define EISD_S_M_DZRO          0x0004
+#define EISD_S_M_WRT           0x0008
+#define EISD_S_M_INITALCODE    0x0010
+#define EISD_S_M_BASED         0x0020
+#define EISD_S_M_FIXUPVEC      0x0040
+#define EISD_S_M_RESIDENT      0x0080
+#define EISD_S_M_VECTOR                0x0100
+#define EISD_S_M_PROTECT       0x0200
+#define EISD_S_M_LASTCLU       0x0400
+#define EISD_S_M_EXE           0x0800
+#define EISD_S_M_NONSHRADR     0x1000
+#define EISD_S_M_QUAD_LENGTH   0x2000
+#define EISD_S_M_ALLOC_64BIT   0x4000
+
+/* VMS Image Header Symbol Records (IHS/EIHS).  */
+
+#define EIHS_S_L_DSTVBN                 8
+#define EIHS_S_L_DSTSIZE       12
+#define EIHS_S_L_GSTVBN                16
+#define EIHS_S_L_GSTSIZE       20
+#define EIHS_S_L_DMTVBN                24
+#define EIHS_S_L_DMTBYTES      28
+
+/* Debugger symbol definitions.  */
+
+#define DBG_S_L_DMT_MODBEG       0
+#define DBG_S_L_DST_SIZE         4
+#define DBG_S_W_DMT_PSECT_COUNT  8
+#define DBG_S_C_DMT_HEADER_SIZE 12
+
+#define DBG_S_L_DMT_PSECT_START  0
+#define DBG_S_L_DMT_PSECT_LENGTH 4
+#define DBG_S_C_DMT_PSECT_SIZE   8
+
+
+enum file_format_enum { FF_UNKNOWN, FF_FOREIGN, FF_NATIVE };
+enum file_type_enum { FT_UNKNOWN, FT_MODULE, FT_IMAGE };
+
+typedef struct vms_symbol_struct
+{
+  struct bfd_hash_entry bfd_hash;
+  asymbol *symbol;
+} vms_symbol_entry;
+
 /* Stack value for push/pop commands.  */
-                                        
-struct stack_struct                     
-{                                       
-  uquad value;                          
-  int psect;                            
-};                                      
-#define STACKSIZE 8192                  
-                                        
-/* location stack definitions for CTL_DFLC, CTL_STLOC, and CTL_STKDL  */
-                                        
-struct location_struct                  
-{                                       
-  unsigned long value;                  
-  int psect;                            
-};                                      
-#define LOCATION_SAVE_SIZE 32           
-                                        
-#define VMS_SECTION_COUNT 1024          
-                                        
-struct vms_private_data_struct          
-{                                       
-  bfd_boolean is_vax;                           
+
+struct stack_struct
+{
+  uquad value;
+  int psect;
+};
+
+#define STACKSIZE 8192
+
+/* A minimal decoding of DST compilation units.  We only decode
+   what's needed to get to the line number information.  */
+
+struct fileinfo
+{
+  char *name;
+  unsigned int srec;
+};
+
+struct srecinfo
+{
+  struct srecinfo *next;
+  unsigned int line;
+  unsigned int sfile;
+  unsigned int srec;
+};
+
+struct lineinfo
+{
+  struct lineinfo *next;
+  bfd_vma address;
+  unsigned int line;
+};
+
+struct funcinfo
+{
+  struct funcinfo *next;
+  char *name;
+  bfd_vma low;
+  bfd_vma high;
+};
+
+struct module
+{
+  /* Chain the previously read compilation unit.  */
+  struct module *next;
+
+  /* The module name.  */
+  char *name;
+
+  /* The start offset and size of debug info in the DST section.  */
+  unsigned int modbeg;
+  unsigned int size;
+
+  /* The lowest and highest addresses contained in this compilation
+     unit as specified in the compilation unit header.  */
+  bfd_vma low;
+  bfd_vma high;
+
+  /* The listing line table.  */
+  struct lineinfo *line_table;
+
+  /* The source record table.  */
+  struct srecinfo *srec_table;
+
+  /* A list of the functions found in this module.  */
+  struct funcinfo *func_table;
+
+  /* Current allocation of file_table.  */
+  unsigned int file_table_count;
+
+  /* An array of the files making up this module.  */
+  struct fileinfo *file_table;
+};
+
+struct vms_private_data_struct
+{
+  bfd_boolean is_vax;
   bfd_boolean fixup_done;              /* Flag to indicate if all
                                           section pointers and PRIV(sections)
                                           are set up correctly.  */
-  unsigned char *vms_buf;              /* Buffer to record.  */
-  int buf_size;                                /* Max size of buffer.  */
-  unsigned char *vms_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 hdr_struc hdr_data;           /* Data from HDR/EMH record.  */
-  struct eom_struc eom_data;           /* Data from EOM/EEOM record.  */
-  unsigned int section_count;          /* # of sections in following array.  */
-  asection **sections;                 /* Array of GSD/EGSD sections.  */
-  int gsd_sym_count;                   /* # of GSD/EGSD symbols.  */
-  asymbol **symbols;                   /* Vector of GSD/EGSD symbols.  */
-  struct proc_value *procedure;                 
-                                        
-  struct stack_struct *stack;           
-  int stackptr;                                 
-                                        
-  vms_section *vms_section_table[VMS_SECTION_COUNT];
-                                        
+  unsigned char *vms_buf;              /* record buffer */
+  unsigned int buf_size;               /* size of record buffer  */
+  unsigned char *vms_rec;              /* record pointer in record buffer */
+  unsigned int rec_size;               /* record size  */
+  enum file_format_enum file_format;
+
+  struct hdr_struct hdr_data;          /* data from HDR/EMH record  */
+  struct eom_struct eom_data;          /* data from EOM/EEOM record  */
+  unsigned int section_count;          /* # of sections in following array  */
+  asection **sections;                 /* array of GSD/EGSD sections  */
+  unsigned int gsd_sym_count;          /* # of GSD/EGSD symbols  */
+  asymbol **symbols;                   /* vector of GSD/EGSD symbols  */
+  struct proc_value *procedure;
+
+  struct stack_struct *stack;
+  int stackptr;
+
   struct bfd_hash_table *vms_symbol_table;
-  struct bfd_symbol **symcache;                 
-  int symnum;                           
-                                        
-  struct location_struct *location_stack;
-                                        
-  asection *image_section;             /* Section for image_ptr.  */
-  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 (TIR_S_C_STC_).   */
-  int vms_linkage_index;                
-                                        
-  /* see tc-alpha.c of gas for a descripton.  */
-  int flag_hash_long_names;    /* -+, hash instead of truncate.  */
-  int flag_show_after_trunc;   /* -H, shw hashing/truncation.  */
-};                                      
-                                        
-#define PRIV(name)     ((struct vms_private_data_struct *) abfd->tdata.any)->name
-                                        
+  struct bfd_symbol **symcache;
+  int symnum;
+
+  asection *image_section;             /* section for image_ptr  */
+  unsigned char *image_ptr;            /* a pointer to section->contents */
+
+  unsigned char pdsc[8];               /* procedure descriptor */
+
+  struct module *modules;              /* list of all compilation units */
+
+  struct dst_info *dst_info;
+  asection *dst_section;
+  unsigned char *dst_ptr_end;
+  unsigned int dst_ptr_offsets_count;  /* # of offsets in following array  */
+  unsigned int *dst_ptr_offsets;       /* array of saved image_ptr offsets */
+
+  /* Shared library support */
+  bfd_vma symvva; /* relative virtual address of symbol vector */
+
+  /* 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 */
+  int vms_linkage_index;
+
+  /* see tc-alpha.c of gas for a description.  */
+  int flag_hash_long_names;    /* -+, hash instead of truncate */
+  int flag_show_after_trunc;   /* -H, show hashing/truncation */
+};
+
+#define PRIV(name) ((struct vms_private_data_struct *)abfd->tdata.any)->name
+
+/* Used to keep extra VMS specific information for a given section.
+
+   reloc_size holds the size of the relocation stream, note this
+   is very different from the number of relocations as VMS relocations
+   are variable length.
+
+   reloc_stream is the actual stream of relocation entries.  */
+
+struct vms_section_data_struct
+{
+  bfd_size_type reloc_size;
+  unsigned char *reloc_stream;
+  bfd_size_type reloc_offset;
+  flagword vflags;
+};
+
+#define vms_section_data(sec) \
+  ((struct vms_section_data_struct *)sec->used_by_bfd)
+struct evax_private_udata_struct
+{
+  asymbol *bsym;
+  asymbol *enbsym;
+  char *origname;
+  int lkindex;
+};
+
 #define SECTION_NAME_TEMPLATE "__SEC__%d"
                                         
 #if VMS_DEBUG                           
@@ -635,7 +866,6 @@ extern char *      _bfd_vms_save_sized_string (unsigned char *, int);
 extern char *      _bfd_vms_save_counted_string (unsigned char *);
 extern void        _bfd_vms_push (bfd *, uquad, int);
 extern uquad       _bfd_vms_pop (bfd *, int *);
-extern bfd_boolean _bfd_save_vms_section (bfd *, asection *, const void *, file_ptr, bfd_size_type);
 extern void        _bfd_vms_output_begin (bfd *, int, int);
 extern void        _bfd_vms_output_alignment (bfd *, int);
 extern void        _bfd_vms_output_push (bfd *);
@@ -653,4 +883,7 @@ extern void        _bfd_vms_output_fill (bfd *, int, int);
 extern char *      _bfd_vms_length_hash_symbol (bfd *, const char *, int);
 extern vms_symbol_entry * _bfd_vms_enter_symbol (bfd *, char *);
 
+#define EGPS_S_V_NO_SHIFT 16
+
+extern void        bfd_vms_set_section_flags (bfd *, asection *, flagword);
 #endif /* VMS_H */