Bug 23997 - PLT32 relocation is off by 4
Summary: PLT32 relocation is off by 4
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: gas (show other bugs)
Version: 2.30
: P2 normal
Target Milestone: 2.32
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-12-16 23:32 UTC by Ruslan Nikolaev
Modified: 2018-12-19 22:32 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed: 2018-12-18 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ruslan Nikolaev 2018-12-16 23:32:22 UTC
The bug was initially filed at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88524 (see the discussion there) but turns out to be an assembler problem.

Consider the following example for some -fpic -mcmodel=small compiled code.
There is an external function func() for which we store a relative reference
to the corresponding @plt stub in a 32-bit variable.

The following seems to generate correct offsets (@plt is already relative, so
we can probably specify it directly):

void func(void);

asm("a: .long func@plt");

extern int a;

int geta()
{
        return a;
}

gcc -Wall -O2 -c -fpic test.c

yields

RELOCATION RECORDS FOR [.text]:
OFFSET           TYPE              VALUE 
0000000000000000 R_X86_64_PLT32    func
0000000000000013 R_X86_64_REX_GOTPCRELX  a-0x0000000000000004

However, if we change asm("a: .long func@plt") to asm("a: .long func@plt - .")
the generated code is very weird and is off by 4:

RELOCATION RECORDS FOR [.text]:
OFFSET           TYPE              VALUE 
0000000000000000 R_X86_64_PLT32    func-0x0000000000000004
0000000000000013 R_X86_64_REX_GOTPCRELX  a-0x0000000000000004

Specifically, if we generate a shared library, the generated offset to func@plt is off by 4 in the second case.

gcc -Wall -O2 -shared -fpic test.c

the first case is correct:
00000000000004c0 <func@plt>:
...
00000000000005c0 <a>:
 5c0:   00 ff    
 5c2:   ff           
 5c3:   ff

[5c0 + ffffff00] = 4C0


whereas the second case is off by 4:
00000000000004c0 <func@plt>:
...
00000000000005c0 <a>:
 5c0:   fc                    
 5c1:   fe                     
 5c2:   ff                      
 5c3:   ff

[5c0 + fffffefc] = 4BC

It is quite possible that I am missing something here (and the generated code is correct) but just want to check if there is any potential bug in the compiler.
Comment 1 H.J. Lu 2018-12-18 02:17:44 UTC
(In reply to Ruslan Nikolaev from comment #0)
> The bug was initially filed at
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88524 (see the discussion
> there) but turns out to be an assembler problem.
> 
> Consider the following example for some -fpic -mcmodel=small compiled code.
> There is an external function func() for which we store a relative reference
> to the corresponding @plt stub in a 32-bit variable.
> 
> The following seems to generate correct offsets (@plt is already relative, so
> we can probably specify it directly):
> 
> void func(void);
> 
> asm("a: .long func@plt");
> 
> extern int a;
> 
> int geta()
> {
>         return a;
> }
> 
> gcc -Wall -O2 -c -fpic test.c
> 
> yields
> 
> RELOCATION RECORDS FOR [.text]:
> OFFSET           TYPE              VALUE 
> 0000000000000000 R_X86_64_PLT32    func
> 0000000000000013 R_X86_64_REX_GOTPCRELX  a-0x0000000000000004
> 
> However, if we change asm("a: .long func@plt") to asm("a: .long func@plt -
> .")
> the generated code is very weird and is off by 4:

@PLT is PC relative.  Why do you want to use "func@plt - ."?
Comment 2 Ruslan Nikolaev 2018-12-19 00:30:01 UTC
Sometimes when the assembly code is for both PIC and non-PIC code, you may
want to use this construction. I checked LLVM/clang; it compiles correct output in both cases.
Comment 3 H.J. Lu 2018-12-19 03:06:33 UTC
(In reply to Ruslan Nikolaev from comment #2)
> Sometimes when the assembly code is for both PIC and non-PIC code, you may

From x86-64 psAB:

name@PLT: specifies the offset to the PLT entry of symbol name from the current code
location.

"name@PLT - ." has undefined behavior.  Can you just use name@PLT for both
PIC and non-PIC codes?

> want to use this construction. I checked LLVM/clang; it compiles correct
> output in both cases.

This isn't relevant.
Comment 4 Ruslan Nikolaev 2018-12-19 04:08:32 UTC
(In reply to H.J. Lu from comment #3)
> (In reply to Ruslan Nikolaev from comment #2)
> > Sometimes when the assembly code is for both PIC and non-PIC code, you may
> 
> From x86-64 psAB:
> 
> name@PLT: specifies the offset to the PLT entry of symbol name from the
> current code
> location.
> 
> "name@PLT - ." has undefined behavior.  Can you just use name@PLT for both
> PIC and non-PIC codes?
> 

It is possible but see below.

> > want to use this construction. I checked LLVM/clang; it compiles correct
> > output in both cases.
> 
> This isn't relevant.

I guess, I do not have a very strong opinion about that. But my concern is that the generated relocation is off by 4 which is not clear why; I discovered that by a mere chance. The LLVM behavior is probably more intuitive here but at the very least it would be good to error out rather than just silently generate an incorrect relocation.
Comment 5 Ruslan Nikolaev 2018-12-19 04:09:42 UTC
or another possibility -- is to output some warning
Comment 6 Ruslan Nikolaev 2018-12-19 08:44:23 UTC
BTW, I did some further testing with i386. It seems for i386, things are also not consistent but the other way around.
.long func@plt does not seem generate correct offset (even for PIC), but func@plt - . seems to always generate correct offset (even for PIC).

For both i386 and x86-64, clang/LLVM generated correct offset in either case.

So, I think, it may present some problem as i386 and x86_64 assembly code is often (at least partially) shared.
Comment 7 cvs-commit@gcc.gnu.org 2018-12-19 20:23:32 UTC
The master branch has been updated by H.J. Lu <hjl@sourceware.org>:

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

commit b9519cfe9828b9ee5a73e74b4be83d46f33e6886
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Wed Dec 19 12:21:56 2018 -0800

    x86: Properly handle PLT expression in directive
    
    For PLT expressions, we should subtract the PLT relocation size only for
    jump instructions.  Since PLT relocations are PC relative, we only allow
    "symbol@PLT" in PLT expression.
    
    gas/
    
    	PR gas/23997
    	* config/tc-i386.c (x86_cons): Check for invalid PLT expression.
    	(md_apply_fix): Subtract the PLT relocation size only for jump
    	instructions.
    	* testsuite/gas/i386/reloc32.s: Add test for invalid PLT
    	expression.
    	* testsuite/gas/i386/reloc64.s: Likewise.
    	* testsuite/gas/i386/ilp32/reloc64.s: Likewise.
    	* testsuite/gas/i386/reloc32.l: Updated.
    	* testsuite/gas/i386/reloc64.l: Likewise.
    	* testsuite/gas/i386/ilp32/reloc64.l: Likewise.
    
    ld/
    
    	PR gas/23997
    	* testsuite/ld-i386/i386.exp: Run PR gas/23997 test.
    	* testsuite/ld-x86-64/x86-64.exp: Likewise.
    	* testsuite/ld-x86-64/pr23997a.s: New file.
    	* testsuite/ld-x86-64/pr23997b.c: Likewise.
    	* testsuite/ld-x86-64/pr23997c.c: Likewise.
Comment 8 H.J. Lu 2018-12-19 20:23:58 UTC
Fixed for 2.32.
Comment 9 Ruslan Nikolaev 2018-12-19 21:43:41 UTC
(In reply to H.J. Lu from comment #8)
> Fixed for 2.32.

Thanks very much! Does it also fix the problem for i386 where an ordinary func@plt is off by 4?
Comment 10 H.J. Lu 2018-12-19 22:32:35 UTC
(In reply to Ruslan Nikolaev from comment #9)
> (In reply to H.J. Lu from comment #8)
> > Fixed for 2.32.
> 
> Thanks very much! Does it also fix the problem for i386 where an ordinary
> func@plt is off by 4?

Yes.