X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-avr.c;h=7214c070d6a744ec646b6ee7aaaba1ef4bcedc02;hb=33eaf5de31b248f84ae108cf0cf4e1664db9ee51;hp=6b5a7613481d49ba6608f020705852f87a5f537a;hpb=73f4d86e6bf362bd025556c33fecbdc341a88e95;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-avr.c b/gas/config/tc-avr.c index 6b5a761348..7214c070d6 100644 --- a/gas/config/tc-avr.c +++ b/gas/config/tc-avr.c @@ -1,7 +1,6 @@ /* tc-avr.c -- Assembler code for the ATMEL AVR - Copyright 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007 - Free Software Foundation, Inc. + Copyright (C) 1999-2017 Free Software Foundation, Inc. Contributed by Denis Chertykov This file is part of GAS, the GNU Assembler. @@ -24,23 +23,35 @@ #include "as.h" #include "safe-ctype.h" #include "subsegs.h" +#include "dwarf2dbg.h" +#include "dw2gencfi.h" +#include "elf/avr.h" +#include "elf32-avr.h" + +/* For building a linked list of AVR_PROPERTY_RECORD structures. */ +struct avr_property_record_link +{ + struct avr_property_record record; + struct avr_property_record_link *next; +}; struct avr_opcodes_s { - char * name; - char * constraints; + const char * name; + const char * constraints; + const char * opcode; int insn_size; /* In words. */ int isa; unsigned int bin_opcode; }; #define AVR_INSN(NAME, CONSTR, OPCODE, SIZE, ISA, BIN) \ -{#NAME, CONSTR, SIZE, ISA, BIN}, +{#NAME, CONSTR, OPCODE, SIZE, ISA, BIN}, struct avr_opcodes_s avr_opcodes[] = { #include "opcode/avr.h" - {NULL, NULL, 0, 0, 0} + {NULL, NULL, NULL, 0, 0, 0} }; const char comment_chars[] = ";"; @@ -50,120 +61,290 @@ const char line_separator_chars[] = "$"; const char *md_shortopts = "m:"; struct mcu_type_s { - char *name; + const char *name; int isa; int mach; }; /* XXX - devices that don't seem to exist (renamed, replaced with larger - ones, or planned but never produced), left here for compatibility. - TODO: hide them in show_mcu_list output? */ + ones, or planned but never produced), left here for compatibility. */ static struct mcu_type_s mcu_types[] = { - {"avr1", AVR_ISA_TINY1, bfd_mach_avr1}, - {"avr2", AVR_ISA_TINY2, bfd_mach_avr2}, - {"avr3", AVR_ISA_M103, bfd_mach_avr3}, - {"avr4", AVR_ISA_M8, bfd_mach_avr4}, - {"avr5", AVR_ISA_ALL, bfd_mach_avr5}, - {"avr6", AVR_ISA_ALL, bfd_mach_avr6}, + {"avr1", AVR_ISA_AVR1, bfd_mach_avr1}, +/* TODO: instruction set for avr2 architecture should be AVR_ISA_AVR2, + but set to AVR_ISA_AVR25 for some following version + of GCC (from 4.3) for backward compatibility. */ + {"avr2", AVR_ISA_AVR25, bfd_mach_avr2}, + {"avr25", AVR_ISA_AVR25, bfd_mach_avr25}, +/* TODO: instruction set for avr3 architecture should be AVR_ISA_AVR3, + but set to AVR_ISA_AVR3_ALL for some following version + of GCC (from 4.3) for backward compatibility. */ + {"avr3", AVR_ISA_AVR3_ALL, bfd_mach_avr3}, + {"avr31", AVR_ISA_AVR31, bfd_mach_avr31}, + {"avr35", AVR_ISA_AVR35, bfd_mach_avr35}, + {"avr4", AVR_ISA_AVR4, bfd_mach_avr4}, +/* TODO: instruction set for avr5 architecture should be AVR_ISA_AVR5, + but set to AVR_ISA_AVR51 for some following version + of GCC (from 4.3) for backward compatibility. */ + {"avr5", AVR_ISA_AVR51, bfd_mach_avr5}, + {"avr51", AVR_ISA_AVR51, bfd_mach_avr51}, + {"avr6", AVR_ISA_AVR6, bfd_mach_avr6}, + {"avrxmega1", AVR_ISA_XMEGA, bfd_mach_avrxmega1}, + {"avrxmega2", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"avrxmega3", AVR_ISA_XMEGA, bfd_mach_avrxmega3}, + {"avrxmega4", AVR_ISA_XMEGA, bfd_mach_avrxmega4}, + {"avrxmega5", AVR_ISA_XMEGA, bfd_mach_avrxmega5}, + {"avrxmega6", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"avrxmega7", AVR_ISA_XMEGA, bfd_mach_avrxmega7}, + {"avrtiny", AVR_ISA_AVRTINY, bfd_mach_avrtiny}, {"at90s1200", AVR_ISA_1200, bfd_mach_avr1}, - {"attiny10", AVR_ISA_TINY1, bfd_mach_avr1}, /* XXX -> tn11 */ - {"attiny11", AVR_ISA_TINY1, bfd_mach_avr1}, - {"attiny12", AVR_ISA_TINY1, bfd_mach_avr1}, - {"attiny15", AVR_ISA_TINY1, bfd_mach_avr1}, - {"attiny28", AVR_ISA_TINY1, bfd_mach_avr1}, - {"at90s2313", AVR_ISA_2xxx, bfd_mach_avr2}, - {"at90s2323", AVR_ISA_2xxx, bfd_mach_avr2}, - {"at90s2333", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 4433 */ - {"at90s2343", AVR_ISA_2xxx, bfd_mach_avr2}, - {"attiny22", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 2343 */ - {"attiny26", AVR_ISA_2xxx, bfd_mach_avr2}, - {"at90s4433", AVR_ISA_2xxx, bfd_mach_avr2}, - {"at90s4414", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 8515 */ - {"at90s4434", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 8535 */ - {"at90s8515", AVR_ISA_2xxx, bfd_mach_avr2}, - {"at90s8535", AVR_ISA_2xxx, bfd_mach_avr2}, - {"at90c8534", AVR_ISA_2xxx, bfd_mach_avr2}, - {"at86rf401", AVR_ISA_2xxx, bfd_mach_avr2}, - {"attiny13", AVR_ISA_TINY2, bfd_mach_avr2}, - {"attiny2313", AVR_ISA_TINY2, bfd_mach_avr2}, - {"attiny261", AVR_ISA_TINY2, bfd_mach_avr2}, - {"attiny461", AVR_ISA_TINY2, bfd_mach_avr2}, - {"attiny861", AVR_ISA_TINY2, bfd_mach_avr2}, - {"attiny24", AVR_ISA_TINY2, bfd_mach_avr2}, - {"attiny44", AVR_ISA_TINY2, bfd_mach_avr2}, - {"attiny84", AVR_ISA_TINY2, bfd_mach_avr2}, - {"attiny25", AVR_ISA_TINY2, bfd_mach_avr2}, - {"attiny45", AVR_ISA_TINY2, bfd_mach_avr2}, - {"attiny85", AVR_ISA_TINY2, bfd_mach_avr2}, - {"atmega603", AVR_ISA_M603, bfd_mach_avr3}, /* XXX -> m103 */ - {"atmega103", AVR_ISA_M103, bfd_mach_avr3}, - {"at43usb320", AVR_ISA_M103, bfd_mach_avr3}, - {"at43usb355", AVR_ISA_M603, bfd_mach_avr3}, - {"at76c711", AVR_ISA_M603, bfd_mach_avr3}, - {"atmega48", AVR_ISA_PWMx, bfd_mach_avr4}, + {"attiny11", AVR_ISA_AVR1, bfd_mach_avr1}, + {"attiny12", AVR_ISA_AVR1, bfd_mach_avr1}, + {"attiny15", AVR_ISA_AVR1, bfd_mach_avr1}, + {"attiny28", AVR_ISA_AVR1, bfd_mach_avr1}, + {"at90s2313", AVR_ISA_AVR2, bfd_mach_avr2}, + {"at90s2323", AVR_ISA_AVR2, bfd_mach_avr2}, + {"at90s2333", AVR_ISA_AVR2, bfd_mach_avr2}, /* XXX -> 4433 */ + {"at90s2343", AVR_ISA_AVR2, bfd_mach_avr2}, + {"attiny22", AVR_ISA_AVR2, bfd_mach_avr2}, /* XXX -> 2343 */ + {"attiny26", AVR_ISA_2xxe, bfd_mach_avr2}, + {"at90s4414", AVR_ISA_AVR2, bfd_mach_avr2}, /* XXX -> 8515 */ + {"at90s4433", AVR_ISA_AVR2, bfd_mach_avr2}, + {"at90s4434", AVR_ISA_AVR2, bfd_mach_avr2}, /* XXX -> 8535 */ + {"at90s8515", AVR_ISA_AVR2, bfd_mach_avr2}, + {"at90c8534", AVR_ISA_AVR2, bfd_mach_avr2}, + {"at90s8535", AVR_ISA_AVR2, bfd_mach_avr2}, + {"ata5272", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny13", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny13a", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny2313", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny2313a",AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny24", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny24a", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny4313", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny44", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny44a", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny84", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny84a", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny25", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny45", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny85", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny261", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny261a", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny461", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny461a", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny861", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny861a", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny87", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny43u", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny48", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny88", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny828", AVR_ISA_AVR25, bfd_mach_avr25}, + {"at86rf401", AVR_ISA_RF401, bfd_mach_avr25}, + {"at43usb355", AVR_ISA_AVR3, bfd_mach_avr3}, + {"at76c711", AVR_ISA_AVR3, bfd_mach_avr3}, + {"atmega103", AVR_ISA_AVR31, bfd_mach_avr31}, + {"at43usb320", AVR_ISA_AVR31, bfd_mach_avr31}, + {"attiny167", AVR_ISA_AVR35, bfd_mach_avr35}, + {"at90usb82", AVR_ISA_AVR35, bfd_mach_avr35}, + {"at90usb162", AVR_ISA_AVR35, bfd_mach_avr35}, + {"ata5505", AVR_ISA_AVR35, bfd_mach_avr35}, + {"atmega8u2", AVR_ISA_AVR35, bfd_mach_avr35}, + {"atmega16u2", AVR_ISA_AVR35, bfd_mach_avr35}, + {"atmega32u2", AVR_ISA_AVR35, bfd_mach_avr35}, + {"attiny1634", AVR_ISA_AVR35, bfd_mach_avr35}, {"atmega8", AVR_ISA_M8, bfd_mach_avr4}, - {"atmega83", AVR_ISA_M8, bfd_mach_avr4}, /* XXX -> m8535 */ - {"atmega85", AVR_ISA_M8, bfd_mach_avr4}, /* XXX -> m8 */ - {"atmega88", AVR_ISA_PWMx, bfd_mach_avr4}, + {"ata6289", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega8a", AVR_ISA_M8, bfd_mach_avr4}, + {"ata6285", AVR_ISA_AVR4, bfd_mach_avr4}, + {"ata6286", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega48", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega48a", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega48pa", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega48p", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega88", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega88a", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega88p", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega88pa", AVR_ISA_AVR4, bfd_mach_avr4}, {"atmega8515", AVR_ISA_M8, bfd_mach_avr4}, {"atmega8535", AVR_ISA_M8, bfd_mach_avr4}, - {"atmega8hva", AVR_ISA_PWMx, bfd_mach_avr4}, - {"at90pwm1", AVR_ISA_PWMx, bfd_mach_avr4}, - {"at90pwm2", AVR_ISA_PWMx, bfd_mach_avr4}, - {"at90pwm3", AVR_ISA_PWMx, bfd_mach_avr4}, - {"atmega16", AVR_ISA_M323, bfd_mach_avr5}, + {"atmega8hva", AVR_ISA_AVR4, bfd_mach_avr4}, + {"at90pwm1", AVR_ISA_AVR4, bfd_mach_avr4}, + {"at90pwm2", AVR_ISA_AVR4, bfd_mach_avr4}, + {"at90pwm2b", AVR_ISA_AVR4, bfd_mach_avr4}, + {"at90pwm3", AVR_ISA_AVR4, bfd_mach_avr4}, + {"at90pwm3b", AVR_ISA_AVR4, bfd_mach_avr4}, + {"at90pwm81", AVR_ISA_AVR4, bfd_mach_avr4}, + {"at90pwm161", AVR_ISA_AVR5, bfd_mach_avr5}, + {"ata5790", AVR_ISA_AVR5, bfd_mach_avr5}, + {"ata5795", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16a", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega161", AVR_ISA_M161, bfd_mach_avr5}, - {"atmega162", AVR_ISA_M323, bfd_mach_avr5}, + {"atmega162", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega163", AVR_ISA_M161, bfd_mach_avr5}, - {"atmega164p", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega165", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega165p", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega168", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega169", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega169p", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega32", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega323", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega324p", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega325", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega325p", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega329", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega329p", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega3250", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega3250p",AVR_ISA_M323, bfd_mach_avr5}, - {"atmega3290", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega3290p",AVR_ISA_M323, bfd_mach_avr5}, - {"atmega406", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega64", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega640", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega644", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega644p", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega128", AVR_ISA_M128, bfd_mach_avr5}, - {"atmega1280", AVR_ISA_M128, bfd_mach_avr5}, - {"atmega1281", AVR_ISA_M128, bfd_mach_avr5}, - {"atmega645", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega649", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega6450", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega6490", AVR_ISA_M323, bfd_mach_avr5}, - {"atmega16hva",AVR_ISA_M323, bfd_mach_avr5}, - {"at90can32" , AVR_ISA_M323, bfd_mach_avr5}, - {"at90can64" , AVR_ISA_M323, bfd_mach_avr5}, - {"at90can128", AVR_ISA_M128, bfd_mach_avr5}, - {"at90usb82", AVR_ISA_M323, bfd_mach_avr5}, - {"at90usb162", AVR_ISA_M323, bfd_mach_avr5}, - {"at90usb646", AVR_ISA_M323, bfd_mach_avr5}, - {"at90usb647", AVR_ISA_M323, bfd_mach_avr5}, - {"at90usb1286",AVR_ISA_M128, bfd_mach_avr5}, - {"at90usb1287",AVR_ISA_M128, bfd_mach_avr5}, + {"atmega164a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega164p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega164pa",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega165", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega165a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega165p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega165pa",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega168", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega168a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega168p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega168pa",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega169", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega169a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega169p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega169pa",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega32", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega32a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega323", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega324a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega324p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega324pa",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega325", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega325a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega325p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega325pa",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega3250", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega3250a",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega3250p",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega3250pa",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega328", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega328p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega329", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega329a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega329p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega329pa",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega3290", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega3290a",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega3290p",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega3290pa",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega406", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega64rfr2", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega644rfr2",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega64", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega64a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega640", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega644", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega644a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega644p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega644pa",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega645", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega645a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega645p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega649", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega649a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega649p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega6450", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega6450a",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega6450p",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega6490", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega6490a",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega6490p",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega64rfr2",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega644rfr2",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16hva",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16hva2",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16hvb",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16hvbrevb",AVR_ISA_AVR5,bfd_mach_avr5}, + {"atmega32hvb",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega32hvbrevb",AVR_ISA_AVR5,bfd_mach_avr5}, + {"atmega64hve",AVR_ISA_AVR5, bfd_mach_avr5}, + {"at90can32" , AVR_ISA_AVR5, bfd_mach_avr5}, + {"at90can64" , AVR_ISA_AVR5, bfd_mach_avr5}, + {"at90pwm161", AVR_ISA_AVR5, bfd_mach_avr5}, + {"at90pwm216", AVR_ISA_AVR5, bfd_mach_avr5}, + {"at90pwm316", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega32c1", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega64c1", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16m1", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega32m1", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega64m1", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16u4", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega32u4", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega32u6", AVR_ISA_AVR5, bfd_mach_avr5}, + {"at90usb646", AVR_ISA_AVR5, bfd_mach_avr5}, + {"at90usb647", AVR_ISA_AVR5, bfd_mach_avr5}, + {"at90scr100", AVR_ISA_AVR5, bfd_mach_avr5}, {"at94k", AVR_ISA_94K, bfd_mach_avr5}, - {"atmega2560", AVR_ISA_ALL, bfd_mach_avr6}, - {"atmega2561", AVR_ISA_ALL, bfd_mach_avr6}, + {"m3000", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega128", AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega128a", AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega1280", AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega1281", AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega1284", AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega1284p",AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega128rfa1",AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega128rfr2",AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega1284rfr2",AVR_ISA_AVR51, bfd_mach_avr51}, + {"at90can128", AVR_ISA_AVR51, bfd_mach_avr51}, + {"at90usb1286",AVR_ISA_AVR51, bfd_mach_avr51}, + {"at90usb1287",AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega2560", AVR_ISA_AVR6, bfd_mach_avr6}, + {"atmega2561", AVR_ISA_AVR6, bfd_mach_avr6}, + {"atmega256rfr2", AVR_ISA_AVR6, bfd_mach_avr6}, + {"atmega2564rfr2", AVR_ISA_AVR6, bfd_mach_avr6}, + {"atxmega16a4", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega16a4u",AVR_ISA_XMEGAU, bfd_mach_avrxmega2}, + {"atxmega16c4", AVR_ISA_XMEGAU, bfd_mach_avrxmega2}, + {"atxmega16d4", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega32a4", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega32a4u",AVR_ISA_XMEGAU, bfd_mach_avrxmega2}, + {"atxmega32c4", AVR_ISA_XMEGAU, bfd_mach_avrxmega2}, + {"atxmega32d4", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega32e5", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega16e5", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega8e5", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega32x1", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega64a3", AVR_ISA_XMEGA, bfd_mach_avrxmega4}, + {"atxmega64a3u",AVR_ISA_XMEGAU, bfd_mach_avrxmega4}, + {"atxmega64a4u",AVR_ISA_XMEGAU, bfd_mach_avrxmega4}, + {"atxmega64b1", AVR_ISA_XMEGAU, bfd_mach_avrxmega4}, + {"atxmega64b3", AVR_ISA_XMEGAU, bfd_mach_avrxmega4}, + {"atxmega64c3", AVR_ISA_XMEGAU, bfd_mach_avrxmega4}, + {"atxmega64d3", AVR_ISA_XMEGA, bfd_mach_avrxmega4}, + {"atxmega64d4", AVR_ISA_XMEGA, bfd_mach_avrxmega4}, + {"atxmega64a1", AVR_ISA_XMEGA, bfd_mach_avrxmega5}, + {"atxmega64a1u",AVR_ISA_XMEGAU, bfd_mach_avrxmega5}, + {"atxmega128a3", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega128a3u",AVR_ISA_XMEGAU,bfd_mach_avrxmega6}, + {"atxmega128b1", AVR_ISA_XMEGAU, bfd_mach_avrxmega6}, + {"atxmega128b3", AVR_ISA_XMEGAU,bfd_mach_avrxmega6}, + {"atxmega128c3", AVR_ISA_XMEGAU,bfd_mach_avrxmega6}, + {"atxmega128d3", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega128d4", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega192a3", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega192a3u",AVR_ISA_XMEGAU,bfd_mach_avrxmega6}, + {"atxmega192c3", AVR_ISA_XMEGAU, bfd_mach_avrxmega6}, + {"atxmega192d3", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega256a3", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega256a3u",AVR_ISA_XMEGAU,bfd_mach_avrxmega6}, + {"atxmega256a3b",AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega256a3bu",AVR_ISA_XMEGAU, bfd_mach_avrxmega6}, + {"atxmega256c3", AVR_ISA_XMEGAU,bfd_mach_avrxmega6}, + {"atxmega256d3", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega384c3", AVR_ISA_XMEGAU,bfd_mach_avrxmega6}, + {"atxmega384d3", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega128a1", AVR_ISA_XMEGA, bfd_mach_avrxmega7}, + {"atxmega128a1u", AVR_ISA_XMEGAU, bfd_mach_avrxmega7}, + {"atxmega128a4u", AVR_ISA_XMEGAU, bfd_mach_avrxmega7}, + {"attiny4", AVR_ISA_AVRTINY, bfd_mach_avrtiny}, + {"attiny5", AVR_ISA_AVRTINY, bfd_mach_avrtiny}, + {"attiny9", AVR_ISA_AVRTINY, bfd_mach_avrtiny}, + {"attiny10", AVR_ISA_AVRTINY, bfd_mach_avrtiny}, + {"attiny20", AVR_ISA_AVRTINY, bfd_mach_avrtiny}, + {"attiny40", AVR_ISA_AVRTINY, bfd_mach_avrtiny}, {NULL, 0, 0} }; + /* Current MCU type. */ -static struct mcu_type_s default_mcu = {"avr2", AVR_ISA_2xxx,bfd_mach_avr2}; +static struct mcu_type_s default_mcu = {"avr2", AVR_ISA_AVR2, bfd_mach_avr2}; +static struct mcu_type_s specified_mcu; static struct mcu_type_s * avr_mcu = & default_mcu; /* AVR target-specific switches. */ @@ -172,9 +353,11 @@ struct avr_opt_s int all_opcodes; /* -mall-opcodes: accept all known AVR opcodes. */ int no_skip_bug; /* -mno-skip-bug: no warnings for skipping 2-word insns. */ int no_wrap; /* -mno-wrap: reject rjmp/rcall with 8K wrap-around. */ + int no_link_relax; /* -mno-link-relax / -mlink-relax: generate (or not) + relocations for linker relaxation. */ }; -static struct avr_opt_s avr_opt = { 0, 0, 0 }; +static struct avr_opt_s avr_opt = { 0, 0, 0, 0 }; const char EXP_CHARS[] = "eE"; const char FLT_CHARS[] = "dD"; @@ -197,7 +380,7 @@ const pseudo_typeS md_pseudo_table[] = struct exp_mod_s { - char * name; + const char * name; bfd_reloc_code_real_type reloc; bfd_reloc_code_real_type neg_reloc; int have_pm; @@ -215,7 +398,7 @@ static struct exp_mod_s exp_mod[] = {"hhi8", BFD_RELOC_AVR_MS8_LDI, BFD_RELOC_AVR_MS8_LDI_NEG, 0}, }; -/* A union used to store indicies into the exp_mod[] array +/* A union used to store indices into the exp_mod[] array in a hash table which expects void * data types. */ typedef union { @@ -234,7 +417,10 @@ enum options { OPTION_ALL_OPCODES = OPTION_MD_BASE + 1, OPTION_NO_SKIP_BUG, - OPTION_NO_WRAP + OPTION_NO_WRAP, + OPTION_ISA_RMW, + OPTION_LINK_RELAX, + OPTION_NO_LINK_RELAX }; struct option md_longopts[] = @@ -243,6 +429,9 @@ struct option md_longopts[] = { "mall-opcodes", no_argument, NULL, OPTION_ALL_OPCODES }, { "mno-skip-bug", no_argument, NULL, OPTION_NO_SKIP_BUG }, { "mno-wrap", no_argument, NULL, OPTION_NO_WRAP }, + { "mrmw", no_argument, NULL, OPTION_ISA_RMW }, + { "mlink-relax", no_argument, NULL, OPTION_LINK_RELAX }, + { "mno-link-relax", no_argument, NULL, OPTION_NO_LINK_RELAX }, { NULL, no_argument, NULL, 0 } }; @@ -289,7 +478,6 @@ skip_space (char *s) static char * extract_word (char *from, char *to, int limit) { - char *op_start; char *op_end; int size = 0; @@ -298,7 +486,7 @@ extract_word (char *from, char *to, int limit) *to = 0; /* Find the op code end. */ - for (op_start = op_end = from; *op_end != 0 && is_part_of_name (*op_end);) + for (op_end = from; *op_end != 0 && is_part_of_name (*op_end);) { to[size++] = *op_end++; if (size + 1 >= limit) @@ -321,21 +509,38 @@ void md_show_usage (FILE *stream) { fprintf (stream, - _("AVR options:\n" + _("AVR Assembler options:\n" " -mmcu=[avr-name] select microcontroller variant\n" " [avr-name] can be:\n" - " avr1 - AT90S1200, ATtiny1x, ATtiny28\n" - " avr2 - AT90S2xxx, AT90S4xxx, AT90S8xxx, ATtiny22\n" - " avr3 - ATmega103, ATmega603\n" - " avr4 - ATmega83, ATmega85\n" - " avr5 - ATmega161, ATmega163, ATmega32, AT94K\n" - " or immediate microcontroller name.\n")); + " avr1 - classic AVR core without data RAM\n" + " avr2 - classic AVR core with up to 8K program memory\n" + " avr25 - classic AVR core with up to 8K program memory\n" + " plus the MOVW instruction\n" + " avr3 - classic AVR core with up to 64K program memory\n" + " avr31 - classic AVR core with up to 128K program memory\n" + " avr35 - classic AVR core with up to 64K program memory\n" + " plus the MOVW instruction\n" + " avr4 - enhanced AVR core with up to 8K program memory\n" + " avr5 - enhanced AVR core with up to 64K program memory\n" + " avr51 - enhanced AVR core with up to 128K program memory\n" + " avr6 - enhanced AVR core with up to 256K program memory\n" + " avrxmega2 - XMEGA, > 8K, < 64K FLASH, < 64K RAM\n" + " avrxmega3 - XMEGA, > 8K, <= 64K FLASH, > 64K RAM\n" + " avrxmega4 - XMEGA, > 64K, <= 128K FLASH, <= 64K RAM\n" + " avrxmega5 - XMEGA, > 64K, <= 128K FLASH, > 64K RAM\n" + " avrxmega6 - XMEGA, > 128K, <= 256K FLASH, <= 64K RAM\n" + " avrxmega7 - XMEGA, > 128K, <= 256K FLASH, > 64K RAM\n" + " avrtiny - AVR Tiny core with 16 gp registers\n")); fprintf (stream, _(" -mall-opcodes accept all AVR opcodes, even if not supported by MCU\n" " -mno-skip-bug disable warnings for skipping two-word instructions\n" " (default for avr4, avr5)\n" " -mno-wrap reject rjmp/rcall instructions with 8K wrap-around\n" - " (default for avr3, avr5)\n")); + " (default for avr3, avr5)\n" + " -mrmw accept Read-Modify-Write instructions\n" + " -mlink-relax generate relocations for linker relaxation (default)\n" + " -mno-link-relax don't generate relocations for linker relaxation.\n" + )); show_mcu_list (stream); } @@ -350,26 +555,16 @@ avr_set_arch (int dummy ATTRIBUTE_UNUSED) } int -md_parse_option (int c, char *arg) +md_parse_option (int c, const char *arg) { switch (c) { case OPTION_MMCU: { int i; - char *s = alloca (strlen (arg) + 1); - - { - char *t = s; - char *arg1 = arg; - - do - *t = TOLOWER (*arg1++); - while (*t++); - } for (i = 0; mcu_types[i].name; ++i) - if (strcmp (mcu_types[i].name, s) == 0) + if (strcasecmp (mcu_types[i].name, arg) == 0) break; if (!mcu_types[i].name) @@ -382,7 +577,12 @@ md_parse_option (int c, char *arg) type - this for allows passing -mmcu=... via gcc ASM_SPEC as well as .arch ... in the asm output at the same time. */ if (avr_mcu == &default_mcu || avr_mcu->mach == mcu_types[i].mach) - avr_mcu = &mcu_types[i]; + { + specified_mcu.name = mcu_types[i].name; + specified_mcu.isa |= mcu_types[i].isa; + specified_mcu.mach = mcu_types[i].mach; + avr_mcu = &specified_mcu; + } else as_fatal (_("redefinition of mcu type `%s' to `%s'"), avr_mcu->name, mcu_types[i].name); @@ -397,6 +597,15 @@ md_parse_option (int c, char *arg) case OPTION_NO_WRAP: avr_opt.no_wrap = 1; return 1; + case OPTION_ISA_RMW: + specified_mcu.isa |= AVR_ISA_RMW; + return 1; + case OPTION_LINK_RELAX: + avr_opt.no_link_relax = 0; + return 1; + case OPTION_NO_LINK_RELAX: + avr_opt.no_link_relax = 1; + return 1; } return 0; @@ -408,46 +617,10 @@ md_undefined_symbol (char *name ATTRIBUTE_UNUSED) return NULL; } -/* Turn a string in input_line_pointer into a floating point constant - of type TYPE, and store the appropriate bytes in *LITP. The number - of LITTLENUMS emitted is stored in *SIZEP. An error message is - returned, or NULL on OK. */ - -char * +const char * md_atof (int type, char *litP, int *sizeP) { - int prec; - LITTLENUM_TYPE words[4]; - LITTLENUM_TYPE *wordP; - char *t; - - switch (type) - { - case 'f': - prec = 2; - break; - case 'd': - prec = 4; - break; - default: - *sizeP = 0; - return _("bad call to md_atof"); - } - - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - - *sizeP = prec * sizeof (LITTLENUM_TYPE); - - /* This loop outputs the LITTLENUMs in REVERSE order. */ - for (wordP = words + prec - 1; prec--;) - { - md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - - return NULL; + return ieee_md_atof (type, litP, sizeP, FALSE); } void @@ -483,6 +656,7 @@ md_begin (void) } bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach); + linkrelax = !avr_opt.no_link_relax; } /* Resolve STR as a constant expression and return the result. @@ -645,7 +819,9 @@ avr_ldi_expression (expressionS *exp) break; default: - as_warn (_("expression dangerous with linker stubs")); + /* PR 5523: Do not generate a warning here, + legitimate code can trigger this case. */ + break; } } return reloc_to_return; @@ -674,7 +850,7 @@ avr_ldi_expression (expressionS *exp) static unsigned int avr_operand (struct avr_opcodes_s *opcode, int where, - char *op, + const char *op, char **line) { expressionS op_expr; @@ -689,30 +865,55 @@ avr_operand (struct avr_opcodes_s *opcode, case 'r': case 'a': case 'v': - if (*str == 'r' || *str == 'R') - { - char r_name[20]; + { + char * old_str = str; + char *lower; + char r_name[20]; - str = extract_word (str, r_name, sizeof (r_name)); - op_mask = 0xff; - if (ISDIGIT (r_name[1])) - { - if (r_name[2] == '\0') - op_mask = r_name[1] - '0'; - else if (r_name[1] != '0' - && ISDIGIT (r_name[2]) - && r_name[3] == '\0') - op_mask = (r_name[1] - '0') * 10 + r_name[2] - '0'; - } - } - else - { - op_mask = avr_get_constant (str, 31); - str = input_line_pointer; - } + str = extract_word (str, r_name, sizeof (r_name)); + for (lower = r_name; *lower; ++lower) + { + if (*lower >= 'A' && *lower <= 'Z') + *lower += 'a' - 'A'; + } + + if (r_name[0] == 'r' && ISDIGIT (r_name[1]) && r_name[2] == 0) + /* Single-digit register number, ie r0-r9. */ + op_mask = r_name[1] - '0'; + else if (r_name[0] == 'r' && ISDIGIT (r_name[1]) + && ISDIGIT (r_name[2]) && r_name[3] == 0) + /* Double-digit register number, ie r10 - r32. */ + op_mask = (r_name[1] - '0') * 10 + r_name[2] - '0'; + else if (r_name[0] >= 'x' && r_name[0] <= 'z' + && (r_name[1] == 'l' || r_name[1] == 'h') && r_name[2] == 0) + /* Registers r26-r31 referred to by name, ie xl, xh, yl, yh, zl, zh. */ + op_mask = (r_name[0] - 'x') * 2 + (r_name[1] == 'h') + 26; + else if ((*op == 'v' || *op == 'w') + && r_name[0] >= 'x' && r_name[0] <= 'z' && r_name[1] == 0) + /* For the movw and addiw instructions, refer to registers x, y and z by name. */ + op_mask = (r_name[0] - 'x') * 2 + 26; + else + { + /* Numeric or symbolic constant register number. */ + op_mask = avr_get_constant (old_str, 31); + str = input_line_pointer; + } + } + + if (avr_mcu->mach == bfd_mach_avrtiny) + { + if (op_mask < 16 || op_mask > 31) + { + as_bad (_("register name or number from 16 to 31 required")); + break; + } + } + else if (op_mask > 31) + { + as_bad (_("register name or number from 0 to 31 required")); + break; + } - if (op_mask <= 31) - { switch (*op) { case 'a': @@ -740,9 +941,6 @@ avr_operand (struct avr_opcodes_s *opcode, break; } break; - } - as_bad (_("register name or number from 0 to 31 required")); - break; case 'e': { @@ -790,8 +988,19 @@ avr_operand (struct avr_opcodes_s *opcode, if (*str == '+') { ++str; - op_mask |= 1; + const char *s; + for (s = opcode->opcode; *s; ++s) + { + if (*s == '+') + op_mask |= (1 << (15 - (s - opcode->opcode))); + } } + + /* attiny26 can do "lpm" and "lpm r,Z" but not "lpm r,Z+". */ + if (!avr_opt.all_opcodes + && (op_mask & 0x0001) + && !(avr_mcu->isa & AVR_ISA_MOVW)) + as_bad (_("postincrement not supported")); break; case 'b': @@ -838,6 +1047,12 @@ avr_operand (struct avr_opcodes_s *opcode, &op_expr, FALSE, BFD_RELOC_16); break; + case 'j': + str = parse_exp (str, &op_expr); + fix_new_exp (frag_now, where, opcode->insn_size * 2, + &op_expr, FALSE, BFD_RELOC_AVR_LDS_STS_16); + break; + case 'M': { bfd_reloc_code_real_type r_type; @@ -882,22 +1097,24 @@ avr_operand (struct avr_opcodes_s *opcode, break; case 'P': - { - unsigned int x; - - x = avr_get_constant (str, 63); - str = input_line_pointer; - op_mask |= (x & 0xf) | ((x & 0x30) << 5); - } + str = parse_exp (str, &op_expr); + fix_new_exp (frag_now, where, opcode->insn_size * 2, + &op_expr, FALSE, BFD_RELOC_AVR_PORT6); break; case 'p': + str = parse_exp (str, &op_expr); + fix_new_exp (frag_now, where, opcode->insn_size * 2, + &op_expr, FALSE, BFD_RELOC_AVR_PORT5); + break; + + case 'E': { unsigned int x; - x = avr_get_constant (str, 31); + x = avr_get_constant (str, 15); str = input_line_pointer; - op_mask |= x << 3; + op_mask |= (x << 4); } break; @@ -918,7 +1135,7 @@ avr_operand (struct avr_opcodes_s *opcode, static unsigned int avr_operands (struct avr_opcodes_s *opcode, char **line) { - char *op = opcode->constraints; + const char *op = opcode->constraints; unsigned int bin = opcode->bin_opcode; char *frag = frag_more (opcode->insn_size * 2); char *str = *line; @@ -1003,7 +1220,7 @@ valueT md_section_align (asection *seg, valueT addr) { int align = bfd_get_section_alignment (stdoutput, seg); - return ((addr + (1 << align) - 1) & (-1 << align)); + return ((addr + (1 << align) - 1) & (-1UL << align)); } /* If you define this macro, it should return the offset between the @@ -1023,6 +1240,55 @@ md_pcrel_from_section (fixS *fixp, segT sec) return fixp->fx_frag->fr_address + fixp->fx_where; } +static bfd_boolean +relaxable_section (asection *sec) +{ + return ((sec->flags & SEC_DEBUGGING) == 0 + && (sec->flags & SEC_CODE) != 0 + && (sec->flags & SEC_ALLOC) != 0); +} + +/* Does whatever the xtensa port does. */ +int +avr_validate_fix_sub (fixS *fix) +{ + segT add_symbol_segment, sub_symbol_segment; + + /* The difference of two symbols should be resolved by the assembler when + linkrelax is not set. If the linker may relax the section containing + the symbols, then an Xtensa DIFF relocation must be generated so that + the linker knows to adjust the difference value. */ + if (!linkrelax || fix->fx_addsy == NULL) + return 0; + + /* Make sure both symbols are in the same segment, and that segment is + "normal" and relaxable. If the segment is not "normal", then the + fix is not valid. If the segment is not "relaxable", then the fix + should have been handled earlier. */ + add_symbol_segment = S_GET_SEGMENT (fix->fx_addsy); + if (! SEG_NORMAL (add_symbol_segment) || + ! relaxable_section (add_symbol_segment)) + return 0; + + sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy); + return (sub_symbol_segment == add_symbol_segment); +} + +/* TC_FORCE_RELOCATION hook */ + +/* If linkrelax is turned on, and the symbol to relocate + against is in a relaxable segment, don't compute the value - + generate a relocation instead. */ +int +avr_force_relocation (fixS *fix) +{ + if (linkrelax && fix->fx_addsy + && relaxable_section (S_GET_SEGMENT (fix->fx_addsy))) + return 1; + + return generic_force_reloc (fix); +} + /* GAS will call this for each fixup. It should store the correct value in the object file. */ @@ -1046,11 +1312,48 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg) fixP->fx_done = 1; } } - + else if (linkrelax && fixP->fx_subsy) + { + /* For a subtraction relocation expression, generate one + of the DIFF relocs, with the value being the difference. + Note that a sym1 - sym2 expression is adjusted into a + section_start_sym + sym4_offset_from_section_start - sym1 + expression. fixP->fx_addsy holds the section start symbol, + fixP->fx_offset holds sym2's offset, and fixP->fx_subsy + holds sym1. Calculate the current difference and write value, + but leave fx_offset as is - during relaxation, + fx_offset - value gives sym1's value. */ + + switch (fixP->fx_r_type) + { + case BFD_RELOC_8: + fixP->fx_r_type = BFD_RELOC_AVR_DIFF8; + break; + case BFD_RELOC_16: + fixP->fx_r_type = BFD_RELOC_AVR_DIFF16; + break; + case BFD_RELOC_32: + fixP->fx_r_type = BFD_RELOC_AVR_DIFF32; + break; + default: + as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); + break; + } + + value = S_GET_VALUE (fixP->fx_addsy) + + fixP->fx_offset - S_GET_VALUE (fixP->fx_subsy); + *valP = value; + + fixP->fx_subsy = NULL; + } /* We don't actually support subtracting a symbol. */ if (fixP->fx_subsy != (symbolS *) NULL) as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); + /* For the DIFF relocs, write the value into the object file while still + keeping fx_done FALSE, as both the difference (recorded in the object file) + and the sym offset (part of fixP) are needed at link relax time. */ + where = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where; switch (fixP->fx_r_type) { default: @@ -1060,6 +1363,16 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg) case BFD_RELOC_AVR_13_PCREL: case BFD_RELOC_32: case BFD_RELOC_16: + break; + case BFD_RELOC_AVR_DIFF8: + *where = value; + break; + case BFD_RELOC_AVR_DIFF16: + bfd_putl16 ((bfd_vma) value, where); + break; + case BFD_RELOC_AVR_DIFF32: + bfd_putl32 ((bfd_vma) value, where); + break; case BFD_RELOC_AVR_CALL: break; } @@ -1111,13 +1424,20 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg) break; case BFD_RELOC_32: - bfd_putl16 ((bfd_vma) value, where); + bfd_putl32 ((bfd_vma) value, where); break; case BFD_RELOC_16: bfd_putl16 ((bfd_vma) value, where); break; + case BFD_RELOC_8: + if (value > 255 || value < -128) + as_warn_where (fixP->fx_file, fixP->fx_line, + _("operand out of range: %ld"), value); + *where = value; + break; + case BFD_RELOC_AVR_16_PM: bfd_putl16 ((bfd_vma) (value >> 1), where); break; @@ -1129,11 +1449,21 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg) bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value), where); break; + case BFD_RELOC_AVR_LDS_STS_16: + if ((value < 0x40) || (value > 0xBF)) + as_warn_where (fixP->fx_file, fixP->fx_line, + _("operand out of range: 0x%lx"), + (unsigned long)value); + insn |= ((value & 0xF) | ((value & 0x30) << 5) | ((value & 0x40) << 2)); + bfd_putl16 ((bfd_vma) insn, where); + break; + case BFD_RELOC_AVR_6: if ((value > 63) || (value < 0)) as_bad_where (fixP->fx_file, fixP->fx_line, _("operand out of range: %ld"), value); - bfd_putl16 ((bfd_vma) insn | ((value & 7) | ((value & (3 << 3)) << 7) | ((value & (1 << 5)) << 8)), where); + bfd_putl16 ((bfd_vma) insn | ((value & 7) | ((value & (3 << 3)) << 7) + | ((value & (1 << 5)) << 8)), where); break; case BFD_RELOC_AVR_6_ADIW: @@ -1214,15 +1544,41 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg) } break; - default: + case BFD_RELOC_AVR_8_LO: + *where = 0xff & value; + break; + + case BFD_RELOC_AVR_8_HI: + *where = 0xff & (value >> 8); + break; + + case BFD_RELOC_AVR_8_HLO: + *where = 0xff & (value >> 16); + break; + + default: as_fatal (_("line %d: unknown relocation type: 0x%x"), fixP->fx_line, fixP->fx_r_type); break; + + case BFD_RELOC_AVR_PORT6: + if (value > 63) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("operand out of range: %ld"), value); + bfd_putl16 ((bfd_vma) insn | ((value & 0x30) << 5) | (value & 0x0f), where); + break; + + case BFD_RELOC_AVR_PORT5: + if (value > 31) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("operand out of range: %ld"), value); + bfd_putl16 ((bfd_vma) insn | ((value & 0x1f) << 3), where); + break; } } else { - switch (fixP->fx_r_type) + switch ((int) fixP->fx_r_type) { case -BFD_RELOC_AVR_HI8_LDI_NEG: case -BFD_RELOC_AVR_HI8_LDI: @@ -1252,40 +1608,35 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) { arelent *reloc; + bfd_reloc_code_real_type code = fixp->fx_r_type; - if (fixp->fx_addsy && fixp->fx_subsy) + if (fixp->fx_subsy != NULL) { - long value = 0; + as_bad_where (fixp->fx_file, fixp->fx_line, _("expression too complex")); + return NULL; + } - if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy)) - || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - "Difference of symbols in different sections is not supported"); - return NULL; - } + reloc = XNEW (arelent); - /* We are dealing with two symbols defined in the same section. - Let us fix-up them here. */ - value += S_GET_VALUE (fixp->fx_addsy); - value -= S_GET_VALUE (fixp->fx_subsy); + reloc->sym_ptr_ptr = XNEW (asymbol *); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - /* When fx_addsy and fx_subsy both are zero, md_apply_fix - only takes it's second operands for the fixup value. */ - fixp->fx_addsy = NULL; - fixp->fx_subsy = NULL; - md_apply_fix (fixp, (valueT *) &value, NULL); + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - return NULL; + if ((fixp->fx_r_type == BFD_RELOC_32) && (fixp->fx_pcrel)) + { + if (seg->use_rela_p) + fixp->fx_offset -= md_pcrel_from_section (fixp, seg); + else + fixp->fx_offset = reloc->address; + + code = BFD_RELOC_32_PCREL; } - reloc = xmalloc (sizeof (arelent)); + reloc->addend = fixp->fx_offset; - reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); - *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); + reloc->howto = bfd_reloc_type_lookup (stdoutput, code); - 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, @@ -1298,7 +1649,6 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) reloc->address = fixp->fx_offset; - reloc->addend = fixp->fx_offset; return reloc; } @@ -1316,6 +1666,28 @@ md_assemble (char *str) opcode = (struct avr_opcodes_s *) hash_find (avr_hash, op); + if (opcode && !avr_opt.all_opcodes) + { + /* Check if the instruction's ISA bit is ON in the ISA bits of the part + specified by the user. If not look for other instructions + specifications with same mnemonic who's ISA bits matches. + + This requires include/opcode/avr.h to have the instructions with + same mnemonic to be specified in sequence. */ + + while ((opcode->isa & avr_mcu->isa) != opcode->isa) + { + opcode++; + + if (opcode->name && strcmp(op, opcode->name)) + { + as_bad (_("illegal opcode %s for mcu %s"), + opcode->name, avr_mcu->name); + return; + } + } + } + if (opcode == NULL) { as_bad (_("unknown opcode `%s'"), op); @@ -1328,8 +1700,7 @@ md_assemble (char *str) 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); + dwarf2_emit_insn (0); /* 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. */ @@ -1343,81 +1714,496 @@ md_assemble (char *str) } } -/* Flag to pass `pm' mode between `avr_parse_cons_expression' and - `avr_cons_fix_new'. */ -static int exp_mod_pm = 0; +const exp_mod_data_t exp_mod_data[] = +{ + /* Default, must be first. */ + { "", 0, BFD_RELOC_16, "" }, + /* Divides by 2 to get word address. Generate Stub. */ + { "gs", 2, BFD_RELOC_AVR_16_PM, "`gs' " }, + { "pm", 2, BFD_RELOC_AVR_16_PM, "`pm' " }, + /* The following are used together with avr-gcc's __memx address space + in order to initialize a 24-bit pointer variable with a 24-bit address. + For address in flash, hlo8 will contain the flash segment if the + symbol is located in flash. If the symbol is located in RAM; hlo8 + will contain 0x80 which matches avr-gcc's notion of how 24-bit RAM/flash + addresses linearize address space. */ + { "lo8", 1, BFD_RELOC_AVR_8_LO, "`lo8' " }, + { "hi8", 1, BFD_RELOC_AVR_8_HI, "`hi8' " }, + { "hlo8", 1, BFD_RELOC_AVR_8_HLO, "`hlo8' " }, + { "hh8", 1, BFD_RELOC_AVR_8_HLO, "`hh8' " }, +}; -/* Parse special CONS expression: pm (expression) - or alternatively: gs (expression). - These are used for addressing program memory. - Relocation: BFD_RELOC_AVR_16_PM. */ +/* Parse special CONS expression: pm (expression) or alternatively + gs (expression). These are used for addressing program memory. Moreover, + define lo8 (expression), hi8 (expression) and hlo8 (expression). */ -void +const exp_mod_data_t * avr_parse_cons_expression (expressionS *exp, int nbytes) { char *tmp; - - exp_mod_pm = 0; + unsigned int i; tmp = input_line_pointer = skip_space (input_line_pointer); - if (nbytes == 2) + /* The first entry of exp_mod_data[] contains an entry if no + expression modifier is present. Skip it. */ + + for (i = 0; i < ARRAY_SIZE (exp_mod_data); i++) { - char *pm_name1 = "pm"; - char *pm_name2 = "gs"; - int len = strlen (pm_name1); - /* len must be the same for both pm identifiers. */ + const exp_mod_data_t *pexp = &exp_mod_data[i]; + int len = strlen (pexp->name); - if (strncasecmp (input_line_pointer, pm_name1, len) == 0 - || strncasecmp (input_line_pointer, pm_name2, len) == 0) + if (nbytes == pexp->nbytes + && strncasecmp (input_line_pointer, pexp->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; + { + ++input_line_pointer; + return pexp; + } else { as_bad (_("`)' required")); - exp_mod_pm = 0; + return &exp_mod_data[0]; } - - return; } input_line_pointer = tmp; + + break; } } expression (exp); + return &exp_mod_data[0]; } void avr_cons_fix_new (fragS *frag, int where, int nbytes, - expressionS *exp) + expressionS *exp, + const exp_mod_data_t *pexp_mod_data) { - if (exp_mod_pm == 0) + int bad = 0; + + switch (pexp_mod_data->reloc) { - if (nbytes == 2) + default: + if (nbytes == 1) + fix_new_exp (frag, where, nbytes, exp, FALSE, BFD_RELOC_8); + else 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); + 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 = ""; + 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 (stdoutput, 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 { - if (nbytes == 2) - fix_new_exp (frag, where, nbytes, exp, FALSE, BFD_RELOC_AVR_16_PM); + 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 - as_bad (_("illegal %srelocation size: %d"), "`pm' ", nbytes); - exp_mod_pm = 0; + 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 (stdoutput, 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 (); }