diff options
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 14 | ||||
-rw-r--r-- | gas/config/tc-avr.c | 130 |
2 files changed, 109 insertions, 35 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index c9048e3..82ef7b7 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,17 @@ +2012-05-11 Georg-Johann Lay <avr@gjlay.de + + PR target/13503 + * config/tc-avr.c (exp_mod_pm): Remove variable. + (exp_mod_data_t): New typedef. + (pexp_mod_data, exp_mod_data): New variables. + (avr_parse_cons_expression): Scan through exp_mod_data[] to find + data expression modifiers "pm", "gs", "lo8", hi8", "hhi8", "hh8" + and set pexp_mod_data accordingly to be used in avr_cons_fix_new. + (avr_cons_fix_new): Handle new data expression modifiers shipped + in pexp_mod_data. + (md_apply_fix): Handle BFD_RELOC_AVR_8_LO, BFD_RELOC_AVR_8_HI, + BFD_RELOC_AVR_8_HHI. + 2012-05-10 H.J. Lu <hongjiu.lu@intel.com> * config/tc-i386.c (tc_gen_reloc): Use bfd_signed_vma in x32 diff --git a/gas/config/tc-avr.c b/gas/config/tc-avr.c index 42eda2f..b2f2de2 100644 --- a/gas/config/tc-avr.c +++ b/gas/config/tc-avr.c @@ -1,7 +1,7 @@ /* tc-avr.c -- Assembler code for the ATMEL AVR Copyright 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, - 2010 Free Software Foundation, Inc. + 2010, 2012 Free Software Foundation, Inc. Contributed by Denis Chertykov <denisc@overta.ru> This file is part of GAS, the GNU Assembler. @@ -65,19 +65,19 @@ static struct mcu_type_s mcu_types[] = { {"avr1", AVR_ISA_AVR1, bfd_mach_avr1}, /* TODO: insruction 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. */ + 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: insruction set for avr3 architecture should be AVR_ISA_AVR3, - but set to AVR_ISA_AVR3_ALL for some following version +/* TODO: insruction 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: insruction set for avr5 architecture should be AVR_ISA_AVR5, - but set to AVR_ISA_AVR51 for some following version +/* TODO: insruction 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}, @@ -1013,7 +1013,7 @@ avr_operand (struct avr_opcodes_s *opcode, op_mask |= (x << 4); } break; - + case '?': break; @@ -1334,7 +1334,19 @@ 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_HHI: + *where = 0xff & (value >> 16); + break; + + default: as_fatal (_("line %d: unknown relocation type: 0x%x"), fixP->fx_line, fixP->fx_r_type); break; @@ -1465,40 +1477,75 @@ 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; +typedef struct +{ + /* Name of the expression modifier allowed with .byte, .word, etc. */ + const char *name; + + /* Only allowed with n bytes of data. */ + int nbytes; + + /* Associated RELOC. */ + bfd_reloc_code_real_type reloc; + + /* Part of the error message. */ + const char *error; +} exp_mod_data_t; + +static 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, hhi8 will contain the flash segment if the + symbol is located in flash. If the symbol is located in RAM; hhi8 + 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' " }, + { "hhi8", 1, BFD_RELOC_AVR_8_HHI, "`hhi8' " }, + { "hh8", 1, BFD_RELOC_AVR_8_HHI, "`hh8' " }, + /* End of list. */ + { NULL, 0, 0, NULL } +}; + +/* Data to pass between `avr_parse_cons_expression' and `avr_cons_fix_new'. */ +static const exp_mod_data_t *pexp_mod_data = &exp_mod_data[0]; -/* 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 hhi8 (expression). */ void avr_parse_cons_expression (expressionS *exp, int nbytes) { + const exp_mod_data_t *pexp = &exp_mod_data[0]; char *tmp; - exp_mod_pm = 0; + pexp_mod_data = pexp; 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 (pexp++; pexp->name; pexp++) { - char *pm_name1 = "pm"; - char *pm_name2 = "gs"; - int len = strlen (pm_name1); - /* len must be the same for both pm identifiers. */ + 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; + pexp_mod_data = pexp; expression (exp); if (*input_line_pointer == ')') @@ -1506,13 +1553,15 @@ avr_parse_cons_expression (expressionS *exp, int nbytes) else { as_bad (_("`)' required")); - exp_mod_pm = 0; + pexp_mod_data = &exp_mod_data[0]; } return; } input_line_pointer = tmp; + + break; } } @@ -1525,8 +1574,11 @@ avr_cons_fix_new (fragS *frag, int nbytes, expressionS *exp) { - if (exp_mod_pm == 0) + int bad = 0; + + switch (pexp_mod_data->reloc) { + default: if (nbytes == 1) fix_new_exp (frag, where, nbytes, exp, FALSE, BFD_RELOC_8); else if (nbytes == 2) @@ -1534,16 +1586,24 @@ avr_cons_fix_new (fragS *frag, 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); + 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_HHI: + if (nbytes == pexp_mod_data->nbytes) + fix_new_exp (frag, where, nbytes, exp, FALSE, pexp_mod_data->reloc); else - as_bad (_("illegal %srelocation size: %d"), "`pm' ", nbytes); - exp_mod_pm = 0; + bad = 1; + break; } + + if (bad) + as_bad (_("illegal %srelocation size: %d"), pexp_mod_data->error, nbytes); + + pexp_mod_data = &exp_mod_data[0]; } void |