bug-binutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug ld/27016] New: x86-64: GOTPCREL relaxation with abs symbol and REX


From: matz at suse dot de
Subject: [Bug ld/27016] New: x86-64: GOTPCREL relaxation with abs symbol and REX byte creates incorrect code
Date: Fri, 04 Dec 2020 15:58:02 +0000

https://sourceware.org/bugzilla/show_bug.cgi?id=27016

            Bug ID: 27016
           Summary: x86-64: GOTPCREL relaxation with abs symbol and REX
                    byte creates incorrect code
           Product: binutils
           Version: 2.36 (HEAD)
            Status: NEW
          Severity: normal
          Priority: P2
         Component: ld
          Assignee: unassigned at sourceware dot org
          Reporter: matz at suse dot de
  Target Milestone: ---

Since the fix for PR ld/25749 and PR ld/25754, i.e. commit 382aae0632 ld
generates incorrect code in the following situation:
a) there's a GOTPCREL relocation (not REX_GOTPCRELX!)
b) the REX byte is necessary
c) the instruction is a mov
d) the relocation is against an absolute symbol

Due to the need of an absolute symbol an executable testcase is a bit
difficult, but this happens in the wild with old object files steming from
enterprise software linked during installation.  Can be reproduced with this:

% cat x.s
        .file   "x.c"
        .text
        .comm   global_int,4,4
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movq    thesym@GOTPCREL(%rip), %r11
        movl    (%r11), %eax
        leal    1(%rax), %edx
        movq    thesym@GOTPCREL(%rip), %r11
        movl    %edx, (%r11)
        movl    $0, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (SUSE Linux) 9.2.1 20190903 [gcc-9-branch revision
275330]"
        .section        .note.GNU-stack,"",@progbits

% cat y.s
.globl thesym
thesym = 0x40402c

I've chose the value of this abs symbol to be the address of "global_int" in
the finally linked executable, so that it can be run.  Note how the main
function uses %r11 as destination register, i.e. the REX byte will be required
and must be correct in the rewritten instruction.

% as -mrelax-relocations=no -o x.o x.s
% as -mrelax-relocations=no -o y.o y.s
% ld-new --build-id --eh-frame-hdr -m elf_x86_64 -dynamic-linker
/lib64/ld-linux-x86-64.so.2 /usr/lib64/crt1.o /usr/lib64/crti.o
/usr/lib64/gcc/x86_64-suse-linux/9/crtbegin.o x.o y.o -lc 
/usr/lib64/gcc/x86_64-suse-linux/9/crtend.o /usr/lib64/crtn.o
% ./a.out
Segmentation fault

This is because the input .o file has this:
   4:   4c 8b 1d 00 00 00 00    mov    0x0(%rip),%r11        # b <main+0xb>
                        7: R_X86_64_GOTPCREL    thesym-0x4

(Note: not REX_GOTPCREL).  And the output a.out has this:

00000000004010f2 <main>:
  4010f2:       55                      push   %rbp
  4010f3:       48 89 e5                mov    %rsp,%rbp
  4010f6:       4c c7 c3 2c 40 40 00    rex.WR mov $0x40402c,%rbx
  4010fd:       41 8b 03                mov    (%r11),%eax

Note how the destination of insn main+4 is %rbx and there's an invalid REX
byte.

This is all because of this hunk in elf_x86_64_convert_load_reloc:

      if (r_type == R_X86_64_REX_GOTPCRELX)
        rex = bfd_get_8 (abfd, contents + roff - 3);
      else
        rex = 0;

      if (opcode == 0x8b)
        {
          if (abs_symbol && local_ref)
            to_reloc_pc32 = FALSE;
          if (to_reloc_pc32)
            // just rewrite into lea, don't touch REX byte
          else
            // rewrite into mov, and fiddle with REX byte

So, with an absolute symbol the code expect to be able to change the REX byte,
but with mere GOTPCREL relocs as here, it can't.  Possible patch for this:

--------------------------------------------------------------------
Fix for bsc#1179341

the movload->movconst relaxation can be done only with REX
rewriting, and hence needs a GOTPCRELX relocation.  With old object
files we might still see GOTPCREL relocs, even with REX bytes available.
We still can't do such rewriting and hence need to stay with the old
rewriting into a lea.
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 549a8be6a6..b89b0023db 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -1731,7 +1731,7 @@ elf_x86_64_convert_load_reloc (bfd *abfd,

       if (opcode == 0x8b)
        {
-         if (abs_symbol && local_ref)
+         if (abs_symbol && local_ref && rex)
            to_reloc_pc32 = FALSE;

          if (to_reloc_pc32)

-- 
You are receiving this mail because:
You are on the CC list for the bug.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]