diff options
author | Zac Walker <zacwalker@microsoft.com> | 2024-01-31 20:15:48 +0100 |
---|---|---|
committer | Christophe Lyon <christophe.lyon@linaro.org> | 2024-02-19 13:02:00 +0000 |
commit | f87eaf8ff3995a5888c6dc4996a20c770e6bcd36 (patch) | |
tree | cdbae78664071dc1196fae6d6c9ed62f0db99619 | |
parent | 046a94c18c543793ab4a8f3f9b2cb0d1280e7b41 (diff) | |
download | binutils-f87eaf8ff3995a5888c6dc4996a20c770e6bcd36.zip binutils-f87eaf8ff3995a5888c6dc4996a20c770e6bcd36.tar.gz binutils-f87eaf8ff3995a5888c6dc4996a20c770e6bcd36.tar.bz2 |
aarch64: Add new relocations and limit COFF AArch64 relocation offsets
The patch adds support for the IMAGE_REL_ARM64_REL32 coff relocation
type. This is needed for 32-bit relative address.
It also adds a check for relocation offsets over 21 bits. Offsets
inside coff files are stored in instruction code. In the case of ADRP
the actual value is stored, not a downshifted page offset. This means
values over 21 bits would otherwise be truncated.
Finally it adds a mapping for BFD_RELOC_AARCH64_ADR_GOT_PAGE and
BFD_RELOC_AARCH64_LD64_GOT_LO12_NC that were previously skipped.
ChangeLog:
* bfd/coff-aarch64.c (coff_aarch64_reloc_type_lookup): Add
BFD_RELOC_AARCH64_ADR_GOT_PAGE,
BFD_RELOC_AARCH64_LD64_GOT_LO12_NC and IMAGE_REL_ARM64_REL32
relocations.
(coff_pe_aarch64_relocate_section): Likewise.
* gas/write.c (adjust_reloc_syms): COFF AArch64 relocation
offsets need to be limited to 21bits
(defined): Likewise.
-rw-r--r-- | bfd/coff-aarch64.c | 31 | ||||
-rw-r--r-- | gas/write.c | 13 |
2 files changed, 43 insertions, 1 deletions
diff --git a/bfd/coff-aarch64.c b/bfd/coff-aarch64.c index 825963c..06c22fc 100644 --- a/bfd/coff-aarch64.c +++ b/bfd/coff-aarch64.c @@ -352,6 +352,7 @@ coff_aarch64_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real return &arm64_reloc_howto_branch26; case BFD_RELOC_AARCH64_ADR_HI21_PCREL: case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL: + case BFD_RELOC_AARCH64_ADR_GOT_PAGE: return &arm64_reloc_howto_page21; case BFD_RELOC_AARCH64_TSTBR14: return &arm64_reloc_howto_branch14; @@ -364,6 +365,7 @@ coff_aarch64_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real case BFD_RELOC_AARCH64_LDST32_LO12: case BFD_RELOC_AARCH64_LDST64_LO12: case BFD_RELOC_AARCH64_LDST128_LO12: + case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC: return &arm64_reloc_howto_pgoff12l; case BFD_RELOC_AARCH64_BRANCH19: return &arm64_reloc_howto_branch19; @@ -761,6 +763,35 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd, break; } + case IMAGE_REL_ARM64_REL32: + { + uint64_t cur_vma; + int64_t addend, val; + + addend = bfd_getl32 (contents + rel->r_vaddr); + + if (addend & 0x80000000) + addend |= 0xffffffff00000000; + + dest_vma += addend; + cur_vma = input_section->output_section->vma + + input_section->output_offset + + rel->r_vaddr; + + val = dest_vma - cur_vma; + + if (val > 0xffffffff || val < -0x100000000) + (*info->callbacks->reloc_overflow) + (info, h ? &h->root : NULL, syms[symndx]._n._n_name, + "IMAGE_REL_ARM64_REL32", addend, input_bfd, + input_section, rel->r_vaddr - input_section->vma); + + bfd_putl32 (val, contents + rel->r_vaddr); + rel->r_type = IMAGE_REL_ARM64_ABSOLUTE; + + break; + } + case IMAGE_REL_ARM64_PAGEOFFSET_12L: { uint32_t opcode, val; diff --git a/gas/write.c b/gas/write.c index 98ead0b..18cf18f 100644 --- a/gas/write.c +++ b/gas/write.c @@ -779,6 +779,7 @@ adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED, { segment_info_type *seginfo = seg_info (sec); fixS *fixp; + valueT val; if (seginfo == NULL) return; @@ -890,10 +891,20 @@ adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED, if ((symsec->flags & SEC_THREAD_LOCAL) != 0) continue; + val = S_GET_VALUE (sym); + +#if defined(TC_AARCH64) && defined(OBJ_COFF) + /* coff aarch64 relocation offsets need to be limited to 21bits. + This is because addend may need to be stored in an ADRP instruction. + In this case the addend cannot be stored down shifted otherwise rounding errors occur. */ + if ((val + 0x100000) > 0x1fffff) + continue; +#endif + /* We refetch the segment when calling section_symbol, rather than using symsec, because S_GET_VALUE may wind up changing the section when it calls resolve_symbol_value. */ - fixp->fx_offset += S_GET_VALUE (sym); + fixp->fx_offset += val; fixp->fx_addsy = section_symbol (S_GET_SEGMENT (sym)); #ifdef DEBUG5 fprintf (stderr, "\nadjusted fixup:\n"); |