From b01b5d9a0b16fd81cc5535ba70c3ed267d9d7ac0 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 4 Mar 2021 22:58:54 +1030 Subject: Move x86_64 PE changes out of bfd_perform_relocation bfd_perform_relocation should not have special case target code. This patch moves the code that was there for x86_64 PE linking to ELF output into the x86_64 PE howto special function, correcting that function for linking to targets other than ELF too. The fixes in bfd_perform_relocation were over-complicated due to needing to compensate for things that had already gone wrong in coff_amd64_reloc. In particular, an adjustment for pc-relative relocs was done in a way that meant adjustment for things related to symbol offsets was lost. I think those two things are orthogonal, but who knows with COFF where addends and symbol values are found randomly in the section contents. Note that linking natively to an x86_64 PE output relocates by coff_pe_amd64_relocate_section, which does not use arelent relocs or bfd_perform_relocation, but be aware of coff_amd64_rtype_to_howto hacking addends for relocations. The adjustments for a particular relocation type there and in coff_amd64_reloc ought to match after taking into consideration CALC_ADDEND. They don't. For example, the pc-relative adjustment for R_PCRWORD is 2 bytes in coff_amd64_reloc and 4 bytes in coff_amd64_rtype_to_howto. * reloc.c (bfd_perform_relocation): Revert 2021-01-12 and 2020-09-16 changes. * coff-x86_64.c (coff_amd64_reloc): Do more or less the same adjustments here instead. Separate pc-relative adjustments from symbol related adjustments. Tidy comments and formatting. --- bfd/ChangeLog | 8 ++++++++ bfd/coff-x86_64.c | 32 ++++++++++++++++---------------- bfd/reloc.c | 26 +------------------------- 3 files changed, 25 insertions(+), 41 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 7379e7b..bc1a530 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,11 @@ +2021-03-05 Alan Modra + + * reloc.c (bfd_perform_relocation): Revert 2021-01-12 and + 2020-09-16 changes. + * coff-x86_64.c (coff_amd64_reloc): Do more or less the same + adjustments here instead. Separate pc-relative adjustments + from symbol related adjustments. Tidy comments and formatting. + 2021-03-04 Jan Beulich * coffcode.h (sec_to_styp_flags): Don't set IMAGE_SCN_LNK_* in diff --git a/bfd/coff-x86_64.c b/bfd/coff-x86_64.c index adab60c..5b09023 100644 --- a/bfd/coff-x86_64.c +++ b/bfd/coff-x86_64.c @@ -75,14 +75,14 @@ coff_amd64_reloc (bfd *abfd, { symvalue diff; -#if !defined(COFF_WITH_PE) +#if !defined (COFF_WITH_PE) if (output_bfd == NULL) return bfd_reloc_continue; #endif if (bfd_is_com_section (symbol->section)) { -#if !defined(COFF_WITH_PE) +#if !defined (COFF_WITH_PE) /* We are relocating a common symbol. The current value in the object file is ORIG + OFFSET, where ORIG is the value of the common symbol as seen by the object file when it was compiled @@ -106,21 +106,10 @@ coff_amd64_reloc (bfd *abfd, ignores the addend for a COFF target when producing relocatable output. This seems to be always wrong for 386 COFF, so we handle the addend here instead. */ -#if defined(COFF_WITH_PE) +#if defined (COFF_WITH_PE) if (output_bfd == NULL) { - reloc_howto_type *howto = reloc_entry->howto; - - /* Although PC relative relocations are very similar between - PE and non-PE formats, but they are off by 1 << howto->size - bytes. For the external relocation, PE is very different - from others. See md_apply_fix3 () in gas/config/tc-amd64.c. - When we link PE and non-PE object files together to - generate a non-PE executable, we have to compensate it - here. */ - if(howto->pc_relative && howto->pcrel_offset) - diff = -(1 << howto->size); - else if(symbol->flags & BSF_WEAK) + if (symbol->flags & BSF_WEAK) diff = reloc_entry->addend - symbol->value; else diff = -reloc_entry->addend; @@ -130,7 +119,18 @@ coff_amd64_reloc (bfd *abfd, diff = reloc_entry->addend; } -#if defined(COFF_WITH_PE) +#if defined (COFF_WITH_PE) + if (output_bfd == NULL) + { + /* PC relative relocations are off by their size. */ + if (reloc_entry->howto->pc_relative) + diff -= bfd_get_reloc_size (reloc_entry->howto); + + if (reloc_entry->howto->type >= R_AMD64_PCRLONG_1 + && reloc_entry->howto->type <= R_AMD64_PCRLONG_5) + diff -= reloc_entry->howto->type - R_AMD64_PCRLONG; + } + /* FIXME: How should this case be handled? */ if (reloc_entry->howto->type == R_AMD64_IMAGEBASE && output_bfd != NULL diff --git a/bfd/reloc.c b/bfd/reloc.c index a754718..5ed7bb8 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -51,7 +51,7 @@ SECTION #include "bfdlink.h" #include "libbfd.h" #include "bfdver.h" -#include "coff/x86_64.h" + /* DOCDD INODE @@ -905,30 +905,6 @@ space consuming. For each target: } } } - else if (abfd->xvec->flavour == bfd_target_coff_flavour - && (input_section->output_section->owner->xvec->flavour - == bfd_target_elf_flavour) - && strcmp (abfd->xvec->name, "pe-x86-64") == 0 - && strcmp (input_section->output_section->owner->xvec->name, - "elf64-x86-64") == 0) - { - /* NB: bfd_perform_relocation isn't called to generate PE binary. - _bfd_relocate_contents is called instead. When linking PE - object files to generate ELF output, _bfd_relocate_contents - isn't called and bfd_perform_relocation is used. We need to - adjust relocation here. */ - relocation -= reloc_entry->addend; - if (howto->type >= R_AMD64_PCRLONG_1 - && howto->type <= R_AMD64_PCRLONG_5) - relocation -= (bfd_vma)(howto->type - R_AMD64_PCRLONG); - else if (howto->type == R_AMD64_DIR64 - || howto->type == R_AMD64_DIR32) - { - bfd_vma val = read_reloc (abfd, (bfd_byte *) data + octets, - howto); - relocation -= val & howto->src_mask; - } - } /* FIXME: This overflow checking is incomplete, because the value might have overflowed before we get here. For a correct check we -- cgit v1.1