mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-22 19:09:31 +08:00
MSP430: Enable relaxation of relocs in JMP instructions
This patch fixes relocation overflows caused by an inability to relax unconditional JMP instructions to BR instructions. bfd/ChangeLog: 2020-02-10 Jozef Lawrynowicz <jozef.l@mittosystems.com> * elf32-msp430.c (msp430_elf_relax_add_two_words): Rename to msp430_elf_relax_add_words. Support insertion of either one or two words. (msp430_elf_relax_section): Catch opcode of 0x3c00 when relocation needs to be grown. Handle insertion of branch instruction to replace jump.
This commit is contained in:
@ -1,3 +1,12 @@
|
|||||||
|
2020-02-10 Jozef Lawrynowicz <jozef.l@mittosystems.com>
|
||||||
|
|
||||||
|
* elf32-msp430.c (msp430_elf_relax_add_two_words): Rename to
|
||||||
|
msp430_elf_relax_add_words. Support insertion of either one or two
|
||||||
|
words.
|
||||||
|
(msp430_elf_relax_section): Catch opcode of 0x3c00 when relocation
|
||||||
|
needs to be grown. Handle insertion of branch instruction to replace
|
||||||
|
jump.
|
||||||
|
|
||||||
2020-02-10 Jozef Lawrynowicz <jozef.l@mittosystems.com>
|
2020-02-10 Jozef Lawrynowicz <jozef.l@mittosystems.com>
|
||||||
|
|
||||||
* elf32-msp430.c (msp430_final_link_relocate): Add printf statements for
|
* elf32-msp430.c (msp430_final_link_relocate): Add printf statements for
|
||||||
|
@ -1768,11 +1768,11 @@ msp430_elf_relax_delete_bytes (bfd * abfd, asection * sec, bfd_vma addr,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert two words into a section whilst relaxing. */
|
/* Insert one or two words into a section whilst relaxing. */
|
||||||
|
|
||||||
static bfd_byte *
|
static bfd_byte *
|
||||||
msp430_elf_relax_add_two_words (bfd * abfd, asection * sec, bfd_vma addr,
|
msp430_elf_relax_add_words (bfd * abfd, asection * sec, bfd_vma addr,
|
||||||
int word1, int word2)
|
int num_words, int word1, int word2)
|
||||||
{
|
{
|
||||||
Elf_Internal_Shdr *symtab_hdr;
|
Elf_Internal_Shdr *symtab_hdr;
|
||||||
unsigned int sec_shndx;
|
unsigned int sec_shndx;
|
||||||
@ -1787,22 +1787,24 @@ msp430_elf_relax_add_two_words (bfd * abfd, asection * sec, bfd_vma addr,
|
|||||||
bfd_vma sec_end;
|
bfd_vma sec_end;
|
||||||
asection *p;
|
asection *p;
|
||||||
if (debug_relocs)
|
if (debug_relocs)
|
||||||
printf (" adding two words at 0x%lx\n",
|
printf (" adding %d words at 0x%lx\n", num_words,
|
||||||
sec->output_section->vma + sec->output_offset + addr);
|
sec->output_section->vma + sec->output_offset + addr);
|
||||||
|
|
||||||
contents = elf_section_data (sec)->this_hdr.contents;
|
contents = elf_section_data (sec)->this_hdr.contents;
|
||||||
sec_end = sec->size;
|
sec_end = sec->size;
|
||||||
|
int num_bytes = num_words * 2;
|
||||||
|
|
||||||
/* Make space for the new words. */
|
/* Make space for the new words. */
|
||||||
contents = bfd_realloc (contents, sec_end + 4);
|
contents = bfd_realloc (contents, sec_end + num_bytes);
|
||||||
memmove (contents + addr + 4, contents + addr, sec_end - addr);
|
memmove (contents + addr + num_bytes, contents + addr, sec_end - addr);
|
||||||
|
|
||||||
/* Insert the new words. */
|
/* Insert the new words. */
|
||||||
bfd_put_16 (abfd, word1, contents + addr);
|
bfd_put_16 (abfd, word1, contents + addr);
|
||||||
|
if (num_words == 2)
|
||||||
bfd_put_16 (abfd, word2, contents + addr + 2);
|
bfd_put_16 (abfd, word2, contents + addr + 2);
|
||||||
|
|
||||||
/* Update the section information. */
|
/* Update the section information. */
|
||||||
sec->size += 4;
|
sec->size += num_bytes;
|
||||||
elf_section_data (sec)->this_hdr.contents = contents;
|
elf_section_data (sec)->this_hdr.contents = contents;
|
||||||
|
|
||||||
/* Adjust all the relocs. */
|
/* Adjust all the relocs. */
|
||||||
@ -1811,12 +1813,12 @@ msp430_elf_relax_add_two_words (bfd * abfd, asection * sec, bfd_vma addr,
|
|||||||
|
|
||||||
for (; irel < irelend; irel++)
|
for (; irel < irelend; irel++)
|
||||||
if ((irel->r_offset >= addr && irel->r_offset < sec_end))
|
if ((irel->r_offset >= addr && irel->r_offset < sec_end))
|
||||||
irel->r_offset += 4;
|
irel->r_offset += num_bytes;
|
||||||
|
|
||||||
/* Adjust the local symbols defined in this section. */
|
/* Adjust the local symbols defined in this section. */
|
||||||
sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
|
sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
|
||||||
for (p = abfd->sections; p != NULL; p = p->next)
|
for (p = abfd->sections; p != NULL; p = p->next)
|
||||||
msp430_elf_relax_adjust_locals (abfd, p, addr, -4,
|
msp430_elf_relax_adjust_locals (abfd, p, addr, -num_bytes,
|
||||||
sec_shndx, sec_end);
|
sec_shndx, sec_end);
|
||||||
|
|
||||||
/* Adjust the global symbols affected by the move. */
|
/* Adjust the global symbols affected by the move. */
|
||||||
@ -1830,8 +1832,8 @@ msp430_elf_relax_add_two_words (bfd * abfd, asection * sec, bfd_vma addr,
|
|||||||
printf (" adjusting value of local symbol %s from 0x%lx to "
|
printf (" adjusting value of local symbol %s from 0x%lx to "
|
||||||
"0x%lx\n", bfd_elf_string_from_elf_section
|
"0x%lx\n", bfd_elf_string_from_elf_section
|
||||||
(abfd, symtab_hdr->sh_link, isym->st_name),
|
(abfd, symtab_hdr->sh_link, isym->st_name),
|
||||||
isym->st_value, isym->st_value + 4);
|
isym->st_value, isym->st_value + num_bytes);
|
||||||
isym->st_value += 4;
|
isym->st_value += num_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now adjust the global symbols defined in this section. */
|
/* Now adjust the global symbols defined in this section. */
|
||||||
@ -1848,7 +1850,7 @@ msp430_elf_relax_add_two_words (bfd * abfd, asection * sec, bfd_vma addr,
|
|||||||
&& sym_hash->root.u.def.section == sec
|
&& sym_hash->root.u.def.section == sec
|
||||||
&& sym_hash->root.u.def.value >= addr
|
&& sym_hash->root.u.def.value >= addr
|
||||||
&& sym_hash->root.u.def.value < sec_end)
|
&& sym_hash->root.u.def.value < sec_end)
|
||||||
sym_hash->root.u.def.value += 4;
|
sym_hash->root.u.def.value += num_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
return contents;
|
return contents;
|
||||||
@ -2015,6 +2017,10 @@ msp430_elf_relax_section (bfd * abfd, asection * sec,
|
|||||||
opcode = bfd_get_16 (abfd, contents + irel->r_offset);
|
opcode = bfd_get_16 (abfd, contents + irel->r_offset);
|
||||||
|
|
||||||
/* Compute the new opcode. We are going to convert:
|
/* Compute the new opcode. We are going to convert:
|
||||||
|
JMP label
|
||||||
|
into:
|
||||||
|
BR[A] label
|
||||||
|
or
|
||||||
J<cond> label
|
J<cond> label
|
||||||
into:
|
into:
|
||||||
J<inv-cond> 1f
|
J<inv-cond> 1f
|
||||||
@ -2036,8 +2042,14 @@ msp430_elf_relax_section (bfd * abfd, asection * sec,
|
|||||||
1: br label
|
1: br label
|
||||||
2: */
|
2: */
|
||||||
continue;
|
continue;
|
||||||
|
case 0x3c00:
|
||||||
|
if (uses_msp430x_relocs (abfd))
|
||||||
|
opcode = 0x0080; /* JMP -> BRA */
|
||||||
|
else
|
||||||
|
opcode = 0x4030; /* JMP -> BR */
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* Not a conditional branch instruction. */
|
/* Unhandled branch instruction. */
|
||||||
/* fprintf (stderr, "unrecog: %x\n", opcode); */
|
/* fprintf (stderr, "unrecog: %x\n", opcode); */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -2057,16 +2069,29 @@ msp430_elf_relax_section (bfd * abfd, asection * sec,
|
|||||||
printf (" R_MSP430X_10_PCREL -> R_MSP430X_ABS20_ADR_SRC "
|
printf (" R_MSP430X_10_PCREL -> R_MSP430X_ABS20_ADR_SRC "
|
||||||
"(growing with new opcode 0x%x)\n", opcode);
|
"(growing with new opcode 0x%x)\n", opcode);
|
||||||
|
|
||||||
/* Insert an absolute branch (aka MOVA) instruction. */
|
/* Insert an absolute branch (aka MOVA) instruction.
|
||||||
contents = msp430_elf_relax_add_two_words
|
Note that bits 19:16 of the address are stored in the first word
|
||||||
(abfd, sec, irel->r_offset + 2, 0x0080, 0x0000);
|
of the insn, so this is where r_offset will point to. */
|
||||||
|
if (opcode == 0x0080)
|
||||||
|
{
|
||||||
|
/* If we're inserting a BRA because we are converting from a JMP,
|
||||||
|
then only add one word for destination address; the BRA opcode
|
||||||
|
has already been written. */
|
||||||
|
contents = msp430_elf_relax_add_words
|
||||||
|
(abfd, sec, irel->r_offset + 2, 1, 0x0000, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
contents = msp430_elf_relax_add_words
|
||||||
|
(abfd, sec, irel->r_offset + 2, 2, 0x0080, 0x0000);
|
||||||
/* Update the relocation to point to the inserted branch
|
/* Update the relocation to point to the inserted branch
|
||||||
instruction. Note - we are changing a PC-relative reloc
|
instruction. Note - we are changing a PC-relative reloc
|
||||||
into an absolute reloc, but this is OK because we have
|
into an absolute reloc, but this is OK because we have
|
||||||
arranged with the assembler to have the reloc's value be
|
arranged with the assembler to have the reloc's value be
|
||||||
a (local) symbol, not a section+offset value. */
|
a (local) symbol, not a section+offset value. */
|
||||||
irel->r_offset += 2;
|
irel->r_offset += 2;
|
||||||
|
}
|
||||||
|
|
||||||
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
|
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
|
||||||
R_MSP430X_ABS20_ADR_SRC);
|
R_MSP430X_ABS20_ADR_SRC);
|
||||||
}
|
}
|
||||||
@ -2075,12 +2100,23 @@ msp430_elf_relax_section (bfd * abfd, asection * sec,
|
|||||||
if (debug_relocs)
|
if (debug_relocs)
|
||||||
printf (" R_MSP430_10_PCREL -> R_MSP430_16 "
|
printf (" R_MSP430_10_PCREL -> R_MSP430_16 "
|
||||||
"(growing with new opcode 0x%x)\n", opcode);
|
"(growing with new opcode 0x%x)\n", opcode);
|
||||||
contents = msp430_elf_relax_add_two_words
|
if (opcode == 0x4030)
|
||||||
(abfd, sec, irel->r_offset + 2, 0x4030, 0x0000);
|
{
|
||||||
|
/* If we're inserting a BR because we are converting from a JMP,
|
||||||
|
then only add one word for destination address; the BR opcode
|
||||||
|
has already been written. */
|
||||||
|
contents = msp430_elf_relax_add_words
|
||||||
|
(abfd, sec, irel->r_offset + 2, 1, 0x0000, 0);
|
||||||
|
irel->r_offset += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
contents = msp430_elf_relax_add_words
|
||||||
|
(abfd, sec, irel->r_offset + 2, 2, 0x4030, 0x0000);
|
||||||
/* See comment above about converting a 10-bit PC-rel
|
/* See comment above about converting a 10-bit PC-rel
|
||||||
relocation into a 16-bit absolute relocation. */
|
relocation into a 16-bit absolute relocation. */
|
||||||
irel->r_offset += 4;
|
irel->r_offset += 4;
|
||||||
|
}
|
||||||
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
|
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
|
||||||
R_MSP430_16);
|
R_MSP430_16);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user