Bug 27763 - x86-64 RIP-relative address with labels wraps around signed 32-bit integer
Summary: x86-64 RIP-relative address with labels wraps around signed 32-bit integer
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: gas (show other bugs)
Version: 2.36
: P2 normal
Target Milestone: 2.37
Assignee: H.J. Lu
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-04-21 18:12 UTC by Andrey Vihrov
Modified: 2022-06-22 06:31 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed: 2021-04-22 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andrey Vihrov 2021-04-21 18:12:19 UTC
Consider the following source:

  movq test(%rip), %rax
  .set test, . + 0xF0000000

When assembled and then disassembled with "objdump -d", this gives

  0:	48 8b 05 00 00 00 f0 	mov    -0x10000000(%rip),%rax

The relative address wraps around and results in a negative displacement.

This affects expressions with labels, such as (test + 1) and (test - 0x1E0000000), but not simply 0xF0000000, which is correctly rejected with

  Error: 0xf0000000 out range of signed 32bit displacement

Expressions not smaller than 2^32, such as (test + 0xF0000000), are also correctly rejected:

  Error: value of 8053063680 too large for field of 4 bytes at 3
Comment 1 H.J. Lu 2021-04-22 15:16:23 UTC
A patch has been submitted:

https://sourceware.org/pipermail/binutils/2021-April/116252.html
Comment 2 Sourceware Commits 2021-04-28 08:53:10 UTC
The master branch has been updated by Jan Beulich <jbeulich@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=eb19308f2d09675dd936960c15603ae749e0f837

commit eb19308f2d09675dd936960c15603ae749e0f837
Author: Jan Beulich <jbeulich@suse.com>
Date:   Wed Apr 28 10:53:00 2021 +0200

    x86: honor signedness of PC-relative relocations
    
    PR gas/27763
    
    While the comment in output_jump() was basically correct prior to the
    introduction of 64-bit mode, both that and the not-JMP-like behavior of
    XBEGIN require adjustments: Branches with 32-bit displacement do not
    wrap at 4G in 64-bit mode, and XBEGIN with 16-bit operand size doesn't
    wrap at 64k. Similarly %rip-relative addressing doesn't wrap at 4G.
    
    The new testcase points out that for PE/COFF object_64bit didn't get
    set so far, preventing in particular the check at the end of
    md_convert_frag() to take effect.
    
    For Mach-O the new testcase fails (bogusly), in that only the first two
    of the expected errors get raised. Since for Mach-O many testcases
    already fail, and since an x86_64-darwin target can't even be configured
    for, I didn't think I need to bother.
    
    Note that there are further issues in this area, in particular for
    branches with operand size overrides. Such branches, which truncate
    %rip / %eip, can't be correctly expressed with ordinary PC-relative
    relocations. It's not really clear what to do with them - perhaps the
    best we can do is to carry through all associated relocations, leaving
    it to the linker (or even loader) to decide (once the final address
    layout is known). Same perhaps goes for relocations associated with
    32-bit addressing in 64-bit mode.
Comment 3 H.J. Lu 2021-04-28 12:39:15 UTC
Fixed for 2.37.