+ 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 (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
+