📄 tc-avr.c
字号:
{ /* 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_getl16 (where); switch (fixp->fx_r_type) { case BFD_RELOC_AVR_7_PCREL: if (value & 1) as_bad_where (fixp->fx_file, fixp->fx_line, _("odd address operand: %ld"), value); /* Instruction addresses are always right-shifted by 1. */ value >>= 1; --value; /* Correct PC. */ if (value < -64 || value > 63) as_bad_where (fixp->fx_file, fixp->fx_line, _("operand out of range: %ld"), value); value = (value << 3) & 0x3f8; bfd_putl16 ((bfd_vma) (value | insn), where); break; case BFD_RELOC_AVR_13_PCREL: if (value & 1) as_bad_where (fixp->fx_file, fixp->fx_line, _("odd address operand: %ld"), value); /* Instruction addresses are always right-shifted by 1. */ value >>= 1; --value; /* Correct PC. */ if (value < -2048 || value > 2047) { /* No wrap for devices with >8K of program memory. */ if ((avr_mcu->isa & AVR_ISA_MEGA) || avr_opt.no_wrap) as_bad_where (fixp->fx_file, fixp->fx_line, _("operand out of range: %ld"), value); } value &= 0xfff; bfd_putl16 ((bfd_vma) (value | insn), where); break; case BFD_RELOC_32: bfd_putl16 ((bfd_vma) value, where); break; case BFD_RELOC_16: bfd_putl16 ((bfd_vma) value, where); break; case BFD_RELOC_AVR_16_PM: bfd_putl16 ((bfd_vma) (value >> 1), where); break; case BFD_RELOC_AVR_LO8_LDI: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value), where); break; case -BFD_RELOC_AVR_LO8_LDI: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value >> 16), where); break; case BFD_RELOC_AVR_HI8_LDI: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value >> 8), where); break; case -BFD_RELOC_AVR_HI8_LDI: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value >> 24), where); break; case BFD_RELOC_AVR_HH8_LDI: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value >> 16), where); break; case BFD_RELOC_AVR_LO8_LDI_NEG: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (-value), where); break; case -BFD_RELOC_AVR_LO8_LDI_NEG: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (-value >> 16), where); break; case BFD_RELOC_AVR_HI8_LDI_NEG: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (-value >> 8), where); break; case -BFD_RELOC_AVR_HI8_LDI_NEG: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (-value >> 24), where); break; case BFD_RELOC_AVR_HH8_LDI_NEG: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (-value >> 16), where); break; case BFD_RELOC_AVR_LO8_LDI_PM: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value >> 1), where); break; case BFD_RELOC_AVR_HI8_LDI_PM: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value >> 9), where); break; case BFD_RELOC_AVR_HH8_LDI_PM: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value >> 17), where); break; case BFD_RELOC_AVR_LO8_LDI_PM_NEG: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (-value >> 1), where); break; case BFD_RELOC_AVR_HI8_LDI_PM_NEG: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (-value >> 9), where); break; case BFD_RELOC_AVR_HH8_LDI_PM_NEG: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (-value >> 17), where); break; case BFD_RELOC_AVR_CALL: { unsigned long x; x = bfd_getl16 (where); if (value & 1) as_bad_where (fixp->fx_file, fixp->fx_line, _("odd address operand: %ld"), value); value >>= 1; x |= ((value & 0x10000) | ((value << 3) & 0x1f00000)) >> 16; bfd_putl16 ((bfd_vma) x, where); bfd_putl16 ((bfd_vma) (value & 0xffff), where + 2); } break; default: as_fatal (_("line %d: unknown relocation type: 0x%x"), fixp->fx_line, fixp->fx_r_type); break; } } else { switch (fixp->fx_r_type) { case -BFD_RELOC_AVR_HI8_LDI_NEG: case -BFD_RELOC_AVR_HI8_LDI: case -BFD_RELOC_AVR_LO8_LDI_NEG: case -BFD_RELOC_AVR_LO8_LDI: as_bad_where (fixp->fx_file, fixp->fx_line, _("only constant expression allowed")); fixp->fx_done = 1; break; default: break; } fixp->fx_addnumber = value; } return 0;}/* A `BFD_ASSEMBLER' GAS will call this to generate a reloc. GAS will pass the resulting reloc to `bfd_install_relocation'. This currently works poorly, as `bfd_install_relocation' often does the wrong thing, and instances of `tc_gen_reloc' have been written to work around the problems, which in turns makes it difficult to fix `bfd_install_relocation'. *//* If while processing a fixup, a reloc really needs to be created then it is done here. */arelent *tc_gen_reloc (seg, fixp) asection *seg ATTRIBUTE_UNUSED; fixS *fixp;{ arelent *reloc; reloc = (arelent *) xmalloc (sizeof (arelent)); reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); if (reloc->howto == (reloc_howto_type *) NULL) { as_bad_where (fixp->fx_file, fixp->fx_line, _("reloc %d not supported by object file format"), (int) fixp->fx_r_type); return NULL; } if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) reloc->address = fixp->fx_offset; reloc->addend = fixp->fx_offset; return reloc;}voidmd_assemble (str) char *str;{ struct avr_opcodes_s *opcode; char op[11]; str = skip_space (extract_word (str, op, sizeof (op))); if (!op[0]) as_bad (_("can't find opcode ")); opcode = (struct avr_opcodes_s *) hash_find (avr_hash, op); if (opcode == NULL) { as_bad (_("unknown opcode `%s'"), op); return; } /* Special case for opcodes with optional operands (lpm, elpm) - version with operands exists in avr_opcodes[] in the next entry. */ if (*str && *opcode->constraints == '?') ++opcode; if (!avr_opt.all_opcodes && (opcode->isa & avr_mcu->isa) != opcode->isa) as_bad (_("illegal opcode %s for mcu %s"), opcode->name, avr_mcu->name); /* We used to set input_line_pointer to the result of get_operands, but that is wrong. Our caller assumes we don't change it. */ { char *t = input_line_pointer; avr_operands (opcode, &str); if (*skip_space (str)) as_bad (_("garbage at end of line")); input_line_pointer = t; }}/* Parse ordinary expression. */static char *parse_exp (s, op) char *s; expressionS *op;{ input_line_pointer = s; expression (op); if (op->X_op == O_absent) as_bad (_("missing operand")); return input_line_pointer;}/* Parse special expressions (needed for LDI command): xx8 (address) xx8 (-address) pm_xx8 (address) pm_xx8 (-address) where xx is: hh, hi, lo. */static bfd_reloc_code_real_typeavr_ldi_expression (exp) expressionS *exp;{ char *str = input_line_pointer; char *tmp; char op[8]; int mod; tmp = str; str = extract_word (str, op, sizeof (op)); if (op[0]) { mod = (int) hash_find (avr_mod_hash, op); if (mod) { int closes = 0; mod -= 10; str = skip_space (str); if (*str == '(') { int neg_p = 0; ++str; if (strncmp ("pm(", str, 3) == 0 || strncmp ("-(pm(", str, 5) == 0) { if (HAVE_PM_P (mod)) { ++mod; ++closes; } else as_bad (_("illegal expression")); if (*str == '-') { neg_p = 1; ++closes; str += 5; } else str += 3; } if (*str == '-' && *(str + 1) == '(') { neg_p ^= 1; ++closes; str += 2; } input_line_pointer = str; expression (exp); do { if (*input_line_pointer != ')') { as_bad (_("`)' required")); break; } input_line_pointer++; } while (closes--); return neg_p ? EXP_MOD_NEG_RELOC (mod) : EXP_MOD_RELOC (mod); } } } input_line_pointer = tmp; expression (exp); /* Warn about expressions that fail to use lo8 (). */ if (exp->X_op == O_constant) { int x = exp->X_add_number; if (x < -255 || x > 255) as_warn (_("constant out of 8-bit range: %d"), x); } else as_warn (_("expression possibly out of 8-bit range")); return BFD_RELOC_AVR_LO8_LDI;}/* Flag to pass `pm' mode between `avr_parse_cons_expression' and `avr_cons_fix_new'. */static int exp_mod_pm = 0;/* Parse special CONS expression: pm (expression) which is used for addressing to a program memory. Relocation: BFD_RELOC_AVR_16_PM. */voidavr_parse_cons_expression (exp, nbytes) expressionS *exp; int nbytes;{ char *tmp; exp_mod_pm = 0; tmp = input_line_pointer = skip_space (input_line_pointer); if (nbytes == 2) { char *pm_name = "pm"; int len = strlen (pm_name); if (strncasecmp (input_line_pointer, pm_name, len) == 0) { input_line_pointer = skip_space (input_line_pointer + len); if (*input_line_pointer == '(') { input_line_pointer = skip_space (input_line_pointer + 1); exp_mod_pm = 1; expression (exp); if (*input_line_pointer == ')') ++input_line_pointer; else { as_bad (_("`)' required")); exp_mod_pm = 0; } return; } input_line_pointer = tmp; } } expression (exp);}voidavr_cons_fix_new (frag, where, nbytes, exp) fragS *frag; int where; int nbytes; expressionS *exp;{ if (exp_mod_pm == 0) { if (nbytes == 2) fix_new_exp (frag, where, nbytes, exp, false, BFD_RELOC_16); else if (nbytes == 4) fix_new_exp (frag, where, nbytes, exp, false, BFD_RELOC_32); else as_bad (_("illegal %srelocation size: %d"), "", nbytes); } else { if (nbytes == 2) fix_new_exp (frag, where, nbytes, exp, false, BFD_RELOC_AVR_16_PM); else as_bad (_("illegal %srelocation size: %d"), "`pm' ", nbytes); exp_mod_pm = 0; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -