-int
-md_apply_fix3 (fixp, valuep, seg)
- fixS *fixp;
- valueT *valuep;
- segT seg;
-{
- char *where;
- unsigned long insn, insn2;
- long value;
-
- if (fixp->fx_addsy == (symbolS *) NULL)
- {
- value = *valuep;
- fixp->fx_done = 1;
- }
- else if (fixp->fx_pcrel)
- {
- value = *valuep;
- }
- else
- {
- value = fixp->fx_offset;
- if (fixp->fx_subsy != (symbolS *) NULL)
- {
- if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
- value -= S_GET_VALUE (fixp->fx_subsy);
- else
- {
- /* We don't actually support subtracting a symbol. */
- as_bad_where (fixp->fx_file, fixp->fx_line,
- _("expression too complex"));
- }
- }
- }
-
- /* Fetch the instruction, insert the fully resolved operand
- value, and stuff the instruction back again. */
- where = fixp->fx_frag->fr_literal + fixp->fx_where;
- insn = bfd_getb32 ((unsigned char *) where);
-
- switch (fixp->fx_r_type)
- {
- case BFD_RELOC_8:
- /* Caused by a bad .byte directive. */
- as_fatal (_("line %d: unable to place address of symbol '%s' into a byte"),
- fixp->fx_line, S_GET_NAME (fixp->fx_addsy));
- break;
-
- case BFD_RELOC_16:
- /* Caused by a bad .short directive. */
- as_fatal (_("line %d: unable to place address of symbol '%s' into a short"),
- fixp->fx_line, S_GET_NAME (fixp->fx_addsy));
- break;
-
- case BFD_RELOC_64:
- /* Caused by a bad .quad directive. */
- as_fatal (_("line %d: unable to place address of symbol '%s' into a .quad"),
- fixp->fx_line, S_GET_NAME (fixp->fx_addsy));
- break;
-
- case BFD_RELOC_D30V_6:
- check_size (value, 6, fixp->fx_file, fixp->fx_line);
- insn |= value & 0x3F;
- bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
- break;
-
- case BFD_RELOC_D30V_9_PCREL:
- if (fixp->fx_where & 0x7)
- {
- if (fixp->fx_done)
- value += 4;
- else
- fixp->fx_r_type = BFD_RELOC_D30V_9_PCREL_R;
- }
- check_size (value, 9, fixp->fx_file, fixp->fx_line);
- insn |= ((value >> 3) & 0x3F) << 12;
- bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
- break;
-
- case BFD_RELOC_D30V_15:
- check_size (value, 15, fixp->fx_file, fixp->fx_line);
- insn |= (value >> 3) & 0xFFF;
- bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
- break;
-
- case BFD_RELOC_D30V_15_PCREL:
- if (fixp->fx_where & 0x7)
- {
- if (fixp->fx_done)
- value += 4;
- else
- fixp->fx_r_type = BFD_RELOC_D30V_15_PCREL_R;
- }
- check_size (value, 15, fixp->fx_file, fixp->fx_line);
- insn |= (value >> 3) & 0xFFF;
- bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
- break;
-
- case BFD_RELOC_D30V_21:
- check_size (value, 21, fixp->fx_file, fixp->fx_line);
- insn |= (value >> 3) & 0x3FFFF;
- bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
- break;
-
- case BFD_RELOC_D30V_21_PCREL:
- if (fixp->fx_where & 0x7)
- {
- if (fixp->fx_done)
- value += 4;
- else
- fixp->fx_r_type = BFD_RELOC_D30V_21_PCREL_R;
- }
- check_size (value, 21, fixp->fx_file, fixp->fx_line);
- insn |= (value >> 3) & 0x3FFFF;
- bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
- break;
-
- case BFD_RELOC_D30V_32:
- insn2 = bfd_getb32 ((unsigned char *) where + 4);
- insn |= (value >> 26) & 0x3F; /* top 6 bits */
- insn2 |= ((value & 0x03FC0000) << 2); /* next 8 bits */
- insn2 |= value & 0x0003FFFF; /* bottom 18 bits */
- bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
- bfd_putb32 ((bfd_vma) insn2, (unsigned char *) where + 4);
- break;
-
- case BFD_RELOC_D30V_32_PCREL:
- insn2 = bfd_getb32 ((unsigned char *) where + 4);
- insn |= (value >> 26) & 0x3F; /* top 6 bits */
- insn2 |= ((value & 0x03FC0000) << 2); /* next 8 bits */
- insn2 |= value & 0x0003FFFF; /* bottom 18 bits */
- bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
- bfd_putb32 ((bfd_vma) insn2, (unsigned char *) where + 4);
- break;
-
- case BFD_RELOC_32:
- bfd_putb32 ((bfd_vma) value, (unsigned char *) where);
- break;
-
- default:
- as_fatal (_("line %d: unknown relocation type: 0x%x"),fixp->fx_line,fixp->fx_r_type);
- }
- return 0;
-}
-