aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-avr.c
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2006-03-03 15:25:31 +0000
committerNick Clifton <nickc@redhat.com>2006-03-03 15:25:31 +0000
commitdf406460e9fc46e766dc418f85568062a4912bbe (patch)
tree8e1d5b1142214b245e59c01ed42f4a53510e7b07 /gas/config/tc-avr.c
parentb92a518e7392026b969a7547e5b876ea9413f7ff (diff)
downloadgdb-df406460e9fc46e766dc418f85568062a4912bbe.zip
gdb-df406460e9fc46e766dc418f85568062a4912bbe.tar.gz
gdb-df406460e9fc46e766dc418f85568062a4912bbe.tar.bz2
Add linker relaxation support for the AVR
Diffstat (limited to 'gas/config/tc-avr.c')
-rw-r--r--gas/config/tc-avr.c42
1 files changed, 30 insertions, 12 deletions
diff --git a/gas/config/tc-avr.c b/gas/config/tc-avr.c
index 2ceaa1f..d6294f3 100644
--- a/gas/config/tc-avr.c
+++ b/gas/config/tc-avr.c
@@ -170,8 +170,8 @@ static struct exp_mod_s exp_mod[] =
{"pm_hi8", BFD_RELOC_AVR_HI8_LDI_PM, BFD_RELOC_AVR_HI8_LDI_PM_NEG, 0},
{"lo8", BFD_RELOC_AVR_LO8_LDI, BFD_RELOC_AVR_LO8_LDI_NEG, 1},
{"pm_lo8", BFD_RELOC_AVR_LO8_LDI_PM, BFD_RELOC_AVR_LO8_LDI_PM_NEG, 0},
- {"hlo8", -BFD_RELOC_AVR_LO8_LDI, -BFD_RELOC_AVR_LO8_LDI_NEG, 0},
- {"hhi8", -BFD_RELOC_AVR_HI8_LDI, -BFD_RELOC_AVR_HI8_LDI_NEG, 0},
+ {"hlo8", BFD_RELOC_AVR_HH8_LDI, BFD_RELOC_AVR_HH8_LDI_NEG, 0},
+ {"hhi8", BFD_RELOC_AVR_MS8_LDI, BFD_RELOC_AVR_MS8_LDI_NEG, 0},
};
/* A union used to store indicies into the exp_mod[] array
@@ -1081,15 +1081,11 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
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:
+ case BFD_RELOC_AVR_MS8_LDI:
bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value >> 24), where);
break;
@@ -1101,15 +1097,11 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
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:
+ case BFD_RELOC_AVR_MS8_LDI_NEG:
bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (-value >> 24), where);
break;
@@ -1195,6 +1187,32 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED,
{
arelent *reloc;
+ if (fixp->fx_addsy && fixp->fx_subsy)
+ {
+ long value = 0;
+
+ 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;
+ }
+
+ /* 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);
+
+ /* 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);
+
+ return NULL;
+ }
+
reloc = xmalloc (sizeof (arelent));
reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));