+ bad = 1;
+ break;
+
+ case BFD_RELOC_AVR_16_PM:
+ case BFD_RELOC_AVR_8_LO:
+ case BFD_RELOC_AVR_8_HI:
+ case BFD_RELOC_AVR_8_HLO:
+ if (nbytes == pexp_mod_data->nbytes)
+ fix_new_exp (frag, where, nbytes, exp, FALSE, pexp_mod_data->reloc);
+ else
+ bad = 1;
+ break;
+ }
+
+ if (bad)
+ as_bad (_("illegal %s relocation size: %d"), pexp_mod_data->error, nbytes);
+}
+
+static bfd_boolean
+mcu_has_3_byte_pc (void)
+{
+ int mach = avr_mcu->mach;
+
+ return mach == bfd_mach_avr6
+ || mach == bfd_mach_avrxmega6
+ || mach == bfd_mach_avrxmega7;
+}
+
+void
+tc_cfi_frame_initial_instructions (void)
+{
+ /* AVR6 pushes 3 bytes for calls. */
+ int return_size = (mcu_has_3_byte_pc () ? 3 : 2);
+
+ /* The CFA is the caller's stack location before the call insn. */
+ /* Note that the stack pointer is dwarf register number 32. */
+ cfi_add_CFA_def_cfa (32, return_size);
+
+ /* Note that AVR consistently uses post-decrement, which means that things
+ do not line up the same way as for targets that use pre-decrement. */
+ cfi_add_CFA_offset (DWARF2_DEFAULT_RETURN_COLUMN, 1-return_size);
+}
+
+bfd_boolean
+avr_allow_local_subtract (expressionS * left,
+ expressionS * right,
+ segT section)
+{
+ /* If we are not in relaxation mode, subtraction is OK. */
+ if (!linkrelax)
+ return TRUE;
+
+ /* If the symbols are not in a code section then they are OK. */
+ if ((section->flags & SEC_CODE) == 0)
+ return TRUE;
+
+ if (left->X_add_symbol == right->X_add_symbol)
+ return TRUE;
+
+ /* We have to assume that there may be instructions between the
+ two symbols and that relaxation may increase the distance between
+ them. */
+ return FALSE;
+}
+
+void
+avr_elf_final_processing (void)
+{
+ if (linkrelax)
+ elf_elfheader (stdoutput)->e_flags |= EF_AVR_LINKRELAX_PREPARED;
+}
+
+/* Write out the header of a .avr.prop section into the area pointed to by
+ DATA. The RECORD_COUNT will be placed in the header as the number of
+ records that are to follow.
+ The area DATA must be big enough the receive the header, which is
+ AVR_PROPERTY_SECTION_HEADER_SIZE bytes long. */
+
+static char *
+avr_output_property_section_header (char *data,
+ unsigned int record_count)
+{
+ char *orig_data = data;
+
+ md_number_to_chars (data, AVR_PROPERTY_RECORDS_VERSION, 1);
+ data++;
+ /* There's space for a single byte flags field, but right now there's
+ nothing to go in here, so just set the value to zero. */
+ md_number_to_chars (data, 0, 1);
+ data++;
+ md_number_to_chars (data, record_count, 2);
+ data+=2;
+
+ gas_assert (data - orig_data == AVR_PROPERTY_SECTION_HEADER_SIZE);
+
+ return data;
+}
+
+/* Return the number of bytes required to store RECORD into the .avr.prop
+ section. The size returned is the compressed size that corresponds to
+ how the record will be written out in AVR_OUTPUT_PROPERTY_RECORD. */
+
+static int
+avr_record_size (const struct avr_property_record *record)
+{
+ /* The first 5 bytes are a 4-byte address, followed by a 1-byte type
+ identifier. */
+ int size = 5;
+
+ switch (record->type)
+ {
+ case RECORD_ORG:
+ size += 0; /* No extra information. */
+ break;
+
+ case RECORD_ORG_AND_FILL:
+ size += 4; /* A 4-byte fill value. */
+ break;
+
+ case RECORD_ALIGN:
+ size += 4; /* A 4-byte alignment value. */
+ break;
+
+ case RECORD_ALIGN_AND_FILL:
+ size += 8; /* A 4-byte alignment, and 4-byte fill value. */
+ break;
+
+ default:
+ as_fatal (_("unknown record type %d (in %s)"),
+ record->type, __PRETTY_FUNCTION__);
+ }
+
+ return size;
+}
+
+/* Write out RECORD. FRAG_BASE points to the start of the data area setup
+ to hold all of the .avr.prop content, FRAG_PTR points to the next
+ writable location. The data area must be big enough to hold all of the
+ records. The size of the data written out for this RECORD must match
+ the size from AVR_RECORD_SIZE. */
+
+static char *
+avr_output_property_record (char * const frag_base, char *frag_ptr,
+ const struct avr_property_record *record)
+{
+ fixS *fix;
+ int where;
+ char *init_frag_ptr = frag_ptr;
+
+ where = frag_ptr - frag_base;
+ fix = fix_new (frag_now, where, 4,
+ section_symbol (record->section),
+ record->offset, FALSE, BFD_RELOC_32);
+ fix->fx_file = "<internal>";
+ fix->fx_line = 0;
+ frag_ptr += 4;
+
+ md_number_to_chars (frag_ptr, (bfd_byte) record->type, 1);
+ frag_ptr += 1;
+
+ /* Write out the rest of the data. */
+ switch (record->type)
+ {
+ case RECORD_ORG:
+ break;
+
+ case RECORD_ORG_AND_FILL:
+ md_number_to_chars (frag_ptr, record->data.org.fill, 4);
+ frag_ptr += 4;
+ break;
+
+ case RECORD_ALIGN:
+ md_number_to_chars (frag_ptr, record->data.align.bytes, 4);
+ frag_ptr += 4;
+ break;
+
+ case RECORD_ALIGN_AND_FILL:
+ md_number_to_chars (frag_ptr, record->data.align.bytes, 4);
+ md_number_to_chars (frag_ptr + 4, record->data.align.fill, 4);
+ frag_ptr += 8;
+ break;
+
+ default:
+ as_fatal (_("unknown record type %d (in %s)"),
+ record->type, __PRETTY_FUNCTION__);
+ }
+
+ gas_assert (frag_ptr - init_frag_ptr == avr_record_size (record));
+
+ return frag_ptr;
+}
+
+/* Create the section to hold the AVR property information. Return the
+ section. */
+
+static asection *
+avr_create_property_section (void)
+{
+ asection *sec;
+ flagword flags = (SEC_RELOC | SEC_HAS_CONTENTS | SEC_READONLY);
+ const char *section_name = AVR_PROPERTY_RECORD_SECTION_NAME;
+
+ sec = bfd_make_section (stdoutput, section_name);
+ if (sec == NULL)
+ as_fatal (_("Failed to create property section `%s'\n"), section_name);
+ bfd_set_section_flags (sec, flags);
+ sec->output_section = sec;
+ return sec;
+}
+
+/* This hook is called when alignment is performed, and allows us to
+ capture the details of both .org and .align directives. */
+
+void
+avr_handle_align (fragS *fragP)
+{
+ if (linkrelax)
+ {
+ /* Ignore alignment requests at FR_ADDRESS 0, these are at the very
+ start of a section, and will be handled by the standard section
+ alignment mechanism. */
+ if ((fragP->fr_type == rs_align
+ || fragP->fr_type == rs_align_code)
+ && fragP->fr_offset > 0)
+ {
+ char *p = fragP->fr_literal + fragP->fr_fix;
+
+ fragP->tc_frag_data.is_align = TRUE;
+ fragP->tc_frag_data.alignment = fragP->fr_offset;
+ fragP->tc_frag_data.fill = *p;
+ fragP->tc_frag_data.has_fill = (fragP->tc_frag_data.fill != 0);
+ }
+
+ if (fragP->fr_type == rs_org && fragP->fr_offset > 0)
+ {
+ char *p = fragP->fr_literal + fragP->fr_fix;
+
+ fragP->tc_frag_data.is_org = TRUE;
+ fragP->tc_frag_data.fill = *p;
+ fragP->tc_frag_data.has_fill = (fragP->tc_frag_data.fill != 0);
+ }
+ }
+}
+
+/* Return TRUE if this section is not one for which we need to record
+ information in the avr property section. */
+
+static bfd_boolean
+exclude_section_from_property_tables (segT sec)
+{
+ /* Only generate property information for sections on which linker
+ relaxation could be performed. */
+ return !relaxable_section (sec);
+}
+
+/* Create a property record for fragment FRAGP from section SEC and place
+ it into an AVR_PROPERTY_RECORD_LINK structure, which can then formed
+ into a linked list by the caller. */
+
+static struct avr_property_record_link *
+create_record_for_frag (segT sec, fragS *fragP)
+{
+ struct avr_property_record_link *prop_rec_link;
+
+ prop_rec_link = XCNEW (struct avr_property_record_link);
+ gas_assert (fragP->fr_next != NULL);
+
+ if (fragP->tc_frag_data.is_org)
+ {
+ prop_rec_link->record.offset = fragP->fr_next->fr_address;
+ prop_rec_link->record.section = sec;
+
+ if (fragP->tc_frag_data.has_fill)
+ {
+ prop_rec_link->record.data.org.fill = fragP->tc_frag_data.fill;
+ prop_rec_link->record.type = RECORD_ORG_AND_FILL;
+ }
+ else
+ prop_rec_link->record.type = RECORD_ORG;
+ }
+ else
+ {
+ prop_rec_link->record.offset = fragP->fr_next->fr_address;
+ prop_rec_link->record.section = sec;
+
+ gas_assert (fragP->tc_frag_data.is_align);
+ if (fragP->tc_frag_data.has_fill)
+ {
+ prop_rec_link->record.data.align.fill = fragP->tc_frag_data.fill;
+ prop_rec_link->record.type = RECORD_ALIGN_AND_FILL;
+ }
+ else
+ prop_rec_link->record.type = RECORD_ALIGN;
+ prop_rec_link->record.data.align.bytes = fragP->tc_frag_data.alignment;
+ }
+
+ return prop_rec_link;
+}
+
+/* Build a list of AVR_PROPERTY_RECORD_LINK structures for section SEC, and
+ merged them onto the list pointed to by NEXT_PTR. Return a pointer to
+ the last list item created. */
+
+static struct avr_property_record_link **
+append_records_for_section (segT sec,
+ struct avr_property_record_link **next_ptr)
+{
+ segment_info_type *seginfo = seg_info (sec);
+ fragS *fragP;
+
+ if (seginfo && seginfo->frchainP)
+ {
+ for (fragP = seginfo->frchainP->frch_root;
+ fragP;
+ fragP = fragP->fr_next)
+ {
+ if (fragP->tc_frag_data.is_align
+ || fragP->tc_frag_data.is_org)
+ {
+ /* Create a single new entry. */
+ struct avr_property_record_link *new_link
+ = create_record_for_frag (sec, fragP);
+
+ *next_ptr = new_link;
+ next_ptr = &new_link->next;
+ }
+ }
+ }
+
+ return next_ptr;
+}
+
+/* Create the AVR property section and fill it with records of .org and
+ .align directives that were used. The section is only created if it
+ will actually have any content. */
+
+static void
+avr_create_and_fill_property_section (void)
+{
+ segT *seclist;
+ asection *prop_sec;
+ struct avr_property_record_link *r_list, **next_ptr;
+ char *frag_ptr, *frag_base;
+ bfd_size_type sec_size;
+ struct avr_property_record_link *rec;
+ unsigned int record_count;
+
+ /* First walk over all sections. For sections on which linker
+ relaxation could be applied, extend the record list. The record list
+ holds information that the linker will need to know. */
+
+ prop_sec = NULL;
+ r_list = NULL;
+ next_ptr = &r_list;
+ for (seclist = &stdoutput->sections;
+ seclist && *seclist;
+ seclist = &(*seclist)->next)
+ {
+ segT sec = *seclist;
+
+ if (exclude_section_from_property_tables (sec))
+ continue;
+
+ next_ptr = append_records_for_section (sec, next_ptr);
+ }
+
+ /* Create property section and ensure the size is correct. We've already
+ passed the point where gas could size this for us. */
+ sec_size = AVR_PROPERTY_SECTION_HEADER_SIZE;
+ record_count = 0;
+ for (rec = r_list; rec != NULL; rec = rec->next)
+ {
+ record_count++;
+ sec_size += avr_record_size (&rec->record);
+ }
+
+ if (record_count == 0)
+ return;
+
+ prop_sec = avr_create_property_section ();
+ bfd_set_section_size (prop_sec, sec_size);
+
+ subseg_set (prop_sec, 0);
+ frag_base = frag_more (sec_size);
+
+ frag_ptr =
+ avr_output_property_section_header (frag_base, record_count);
+
+ for (rec = r_list; rec != NULL; rec = rec->next)
+ frag_ptr = avr_output_property_record (frag_base, frag_ptr, &rec->record);
+
+ frag_wane (frag_now);
+ frag_new (0);
+ frag_wane (frag_now);
+}
+
+/* We're using this hook to build up the AVR property section. It's called
+ late in the assembly process which suits our needs. */
+void
+avr_post_relax_hook (void)
+{
+ avr_create_and_fill_property_section ();
+}
+
+
+/* Accumulate information about instruction sequence to `avr_isr':
+ wheter TMP_REG, ZERO_REG and SREG might be touched. Used during parse.
+ REG1 is either -1 or a register number used by the instruction as input
+ or output operand. Similar for REG2. */
+
+static void
+avr_update_gccisr (struct avr_opcodes_s *opcode, int reg1, int reg2)
+{
+ const int tiny_p = avr_mcu->mach == bfd_mach_avrtiny;
+ const int reg_tmp = tiny_p ? 16 : 0;
+ const int reg_zero = 1 + reg_tmp;
+
+ if (ISR_CHUNK_Done == avr_isr.prev_chunk
+ || (avr_isr.need_sreg
+ && avr_isr.need_reg_tmp
+ && avr_isr.need_reg_zero))
+ {
+ /* Nothing (more) to do */
+ return;
+ }
+
+ /* SREG: Look up instructions that don't clobber SREG. */
+
+ if (!avr_isr.need_sreg
+ && !hash_find (avr_no_sreg_hash, opcode->name))
+ {
+ avr_isr.need_sreg = 1;
+ }
+
+ /* Handle explicit register operands. Record *any* use as clobber.
+ This is because TMP_REG and ZERO_REG are not global and using
+ them makes no sense without a previous set. */
+
+ avr_isr.need_reg_tmp |= reg1 == reg_tmp || reg2 == reg_tmp;
+ avr_isr.need_reg_zero |= reg1 == reg_zero || reg2 == reg_zero;
+
+ /* Handle implicit register operands and some opaque stuff. */
+
+ if (strstr (opcode->name, "lpm")
+ && '?' == *opcode->constraints)
+ {
+ avr_isr.need_reg_tmp = 1;
+ }
+
+ if (strstr (opcode->name, "call")
+ || strstr (opcode->name, "mul")
+ || 0 == strcmp (opcode->name, "des")
+ || (0 == strcmp (opcode->name, "movw")
+ && (reg1 == reg_tmp || reg2 == reg_tmp)))
+ {
+ avr_isr.need_reg_tmp = 1;
+ avr_isr.need_reg_zero = 1;
+ }
+}
+
+
+/* Emit some 1-word instruction to **PWHERE and advance *PWHERE by the number
+ of octets written. INSN specifies the desired instruction and REG is the
+ register used by it. This function is only used with restricted subset of
+ instructions as might be emit by `__gcc_isr'. IN / OUT will use SREG
+ and LDI loads 0. */
+
+static void
+avr_emit_insn (const char *insn, int reg, char **pwhere)
+{
+ const int sreg = 0x3f;
+ unsigned bin = 0;
+ const struct avr_opcodes_s *op
+ = (struct avr_opcodes_s*) hash_find (avr_hash, insn);
+
+ /* We only have to deal with: IN, OUT, PUSH, POP, CLR, LDI 0. All of
+ these deal with at least one Reg and are 1-word instructions. */
+
+ gas_assert (op && 1 == op->insn_size);
+ gas_assert (reg >= 0 && reg <= 31);
+
+ if (strchr (op->constraints, 'r'))
+ {
+ bin = op->bin_opcode | (reg << 4);
+ }
+ else if (strchr (op->constraints, 'd'))
+ {
+ gas_assert (reg >= 16);
+ bin = op->bin_opcode | ((reg & 0xf) << 4);