[PATCH] D30699: [ELF] - Stop producing broken output for R_386_GOT32X relocation.
George Rimar via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 24 02:26:10 PDT 2017
>> ruiu added a comment.
>> I spent a few hours to understand the situation. Here are my conclusions:
>> 1. The expression to compute R_386_GOT32 value in the i386 psABI draft version 1.1 doesn't indeed make sense. It says that you need to use G+A (as opposed to G+A-GOT) >when the relocation is "[a]pplied on memory operand without base register when position-independent code is disabled". However, it is not doable because you are allowed to >use R_386_GOT32 anywhere and we cannot make an assumption that an R_386_GOT32 follows some certain limited set of instructions. I think this is a bug in the draft spec.
>> 2. That being said, I believe what we are doing now for R_386_GOT32X is correct, and this patch will break it. When you compute G+A instead of G+A-GOT for an >R_386_GOT32X, you always need to rewrite instructions as well. If you don't rewrite instructions, you should always compute G+A-GOT (which is what we are currently doing.)
>"name at GOT" is a memory operand. It is usually computed as "G + A" to
>get the GOT address. If it is computed as G + A - GOT,
>op name at GOT, %reg
>will lead to random result since G + A - GOT is the GOT index, not address.
That is what my patch fixes for LLD.
>LEA is an exception, relocation in
>lea name at GOT, %reg
>should be computed as G + A - GOT for the GOT index. The motivation is
>to allow GOT access without base register when PIC is disabled.
That behavior is equal to what my patch do (because I do not change R_386_GOT32),
but that is not what gold head do currently, please see below. (gold do different because handles R_386_GOT32
in the same way as R_386_GOT32X)
So if we have next code:
movl ifunc at GOT, %eax
movl foo at GOT, %eax
lea ifunc at GOT, %eax
lea foo at GOT, %eax
GAS generates next object with relocations:
2: 8b 05 00 00 00 00 mov 0x0,%eax (R_386_GOT32X)
8: 8b 05 00 00 00 00 mov 0x0,%eax (R_386_GOT32X)
e: 8d 05 00 00 00 00 lea 0x0,%eax (R_386_GOT32)
14: 8d 05 00 00 00 00 lea 0x0,%eax (R_386_GOT32)
GNU gold (GNU Binutils 188.8.131.5270215) 1.14 output is:
[ 5] .got PROGBITS 08049fec 000fec 000008 00 WA 0 0 4
80480c2: 8b 05 ec 9f 04 08 mov 0x8049fec,%eax (0x8049fec is an address in GOT, calculation is G + A)
80480c8: 8d 05 c0 80 04 08 lea 0x80480c0,%eax (mov was optimized to lea, 0x80480c0 is an address of ifunc).
80480ce: 8d 05 ec 9f 04 08 lea 0x8049fec,%eax (lea calculated as G + A, result is an address in GOT)
80480d4: 8d 05 f0 9f 04 08 lea 0x8049ff0,%eax (lea calculated as G + A, result is an address in GOT)
LLD without my patch currently generates:
11002: 8b 05 f8 ff ff ff mov 0xfffffff8,%eax (result value here and below is an offset in GOT, calculation is G + A - GOT).
11008: 8b 05 fc ff ff ff mov 0xfffffffc,%eax (we do not support mov->lea optimization yet, calculation is G + A - GOT)
1100e: 8d 05 f8 ff ff ff lea 0xfffffff8,%eax (G + A - GOT)
11014: 8d 05 fc ff ff ff lea 0xfffffffc,%eax (G + A - GOT)
LLD with my patch:
[ 3] .got PROGBITS 00012000 002000 000008 00 WA 0 0 4
11002: 8b 05 00 20 01 00 mov 0x12000,%eax (0x12000 is an address in GOT, calculation is G + A)
11008: 8b 05 04 20 01 00 mov 0x12004,%eax (0x12004 is an address in GOT, calculation is G + A, we do not support mov->lea optimization yet)
1100e: 8d 05 f8 ff ff ff lea 0xfffffff8,%eax (calculation is G + A - GOT)
11014: 8d 05 fc ff ff ff lea 0xfffffffc,%eax (calculation is G + A - GOT)
So I think behavior with this patch is correct, and current LLD behavior is broken.
More information about the llvm-commits