<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Jun 1, 2016 at 9:45 AM, George Rimar via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: grimar<br>
Date: Wed Jun 1 11:45:30 2016<br>
New Revision: 271405<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=271405&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=271405&view=rev</a><br>
Log:<br>
[ELF] - Implemented support for test/binop relaxations from latest ABI.<br>
<br>
Patch implements next relaxation from latest ABI:<br>
<br>
"Convert memory operand of test and binop into immediate operand, where binop is one of adc, add, and, cmp, or,<br>
sbb, sub, xor instructions, when position-independent code is disabled."<br>
<br>
It is described in System V Application Binary Interface AMD64 Architecture Processor<br>
Supplement Draft Version 0.99.8 (<a href="https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-r249.pdf" rel="noreferrer" target="_blank">https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-r249.pdf</a>,<br>
B.2 "B.2 Optimize GOTPCRELX Relocations").<br>
<br>
Differential revision: <a href="http://reviews.llvm.org/D20793" rel="noreferrer" target="_blank">http://reviews.llvm.org/D20793</a><br>
<br>
<br>
Added:<br>
lld/trunk/test/ELF/gotpc-relax-nopic.s<br>
Modified:<br>
lld/trunk/ELF/InputSection.cpp<br>
lld/trunk/ELF/Relocations.cpp<br>
lld/trunk/ELF/Relocations.h<br>
lld/trunk/ELF/Target.cpp<br>
lld/trunk/ELF/Target.h<br>
<br>
Modified: lld/trunk/ELF/InputSection.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=271405&r1=271404&r2=271405&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=271405&r1=271404&r2=271405&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/InputSection.cpp (original)<br>
+++ lld/trunk/ELF/InputSection.cpp Wed Jun 1 11:45:30 2016<br>
@@ -221,6 +221,7 @@ getSymVA(uint32_t Type, typename ELFT::u<br>
case R_NEG_TLS:<br>
return Out<ELF32LE>::TlsPhdr->p_memsz - Body.getVA<ELFT>(A);<br>
case R_ABS:<br>
+ case R_RELAX_GOT_PC_NOPIC:<br>
return Body.getVA<ELFT>(A);<br>
case R_GOT_OFF:<br>
return Body.getGotOffset<ELFT>() + A;<br>
@@ -325,6 +326,7 @@ void InputSectionBase<ELFT>::relocate(ui<br>
<br>
switch (Expr) {<br>
case R_RELAX_GOT_PC:<br>
+ case R_RELAX_GOT_PC_NOPIC:<br>
Target->relaxGot(BufLoc, SymVA);<br>
break;<br>
case R_RELAX_TLS_IE_TO_LE:<br>
<br>
Modified: lld/trunk/ELF/Relocations.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=271405&r1=271404&r2=271405&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=271405&r1=271404&r2=271405&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/Relocations.cpp (original)<br>
+++ lld/trunk/ELF/Relocations.cpp Wed Jun 1 11:45:30 2016<br>
@@ -370,8 +370,8 @@ static RelExpr adjustExpr(const elf::Obj<br>
} else if (!Preemptible) {<br>
if (needsPlt(Expr))<br>
Expr = fromPlt(Expr);<br>
- if (Expr == R_GOT_PC && Target->canRelaxGot(Type, Data + Offset))<br>
- Expr = R_RELAX_GOT_PC;<br>
+ if (Expr == R_GOT_PC)<br>
+ Expr = Target->adjustRelaxGotExpr(Type, Data + Offset, Expr);<br>
}<br>
<br>
if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body))<br>
<br>
Modified: lld/trunk/ELF/Relocations.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.h?rev=271405&r1=271404&r2=271405&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.h?rev=271405&r1=271404&r2=271405&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/Relocations.h (original)<br>
+++ lld/trunk/ELF/Relocations.h Wed Jun 1 11:45:30 2016<br>
@@ -39,6 +39,7 @@ enum RelExpr {<br>
R_PPC_PLT_OPD,<br>
R_PPC_TOC,<br>
R_RELAX_GOT_PC,<br>
+ R_RELAX_GOT_PC_NOPIC,<br>
R_RELAX_TLS_GD_TO_IE,<br>
R_RELAX_TLS_GD_TO_LE,<br>
R_RELAX_TLS_IE_TO_LE,<br>
<br>
Modified: lld/trunk/ELF/Target.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=271405&r1=271404&r2=271405&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=271405&r1=271404&r2=271405&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/Target.cpp (original)<br>
+++ lld/trunk/ELF/Target.cpp Wed Jun 1 11:45:30 2016<br>
@@ -113,7 +113,8 @@ public:<br>
int32_t Index, unsigned RelOff) const override;<br>
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;<br>
<br>
- bool canRelaxGot(uint32_t Type, const uint8_t *Data) const override;<br>
+ RelExpr adjustRelaxGotExpr(uint32_t Type, const uint8_t *Data,<br>
+ RelExpr Expr) const override;<br>
void relaxGot(uint8_t *Loc, uint64_t Val) const override;<br>
void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;<br>
void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;<br>
@@ -234,8 +235,9 @@ bool TargetInfo::isTlsGlobalDynamicRel(u<br>
return false;<br>
}<br>
<br>
-bool TargetInfo::canRelaxGot(uint32_t Type, const uint8_t *Data) const {<br>
- return false;<br>
+RelExpr TargetInfo::adjustRelaxGotExpr(uint32_t Type, const uint8_t *Data,<br>
+ RelExpr Expr) const {<br>
+ return Expr;<br>
}<br>
<br>
void TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const {<br>
@@ -734,16 +736,28 @@ void X86_64TargetInfo::relocateOne(uint8<br>
}<br>
}<br>
<br>
-bool X86_64TargetInfo::canRelaxGot(uint32_t Type, const uint8_t *Data) const {<br>
+RelExpr X86_64TargetInfo::adjustRelaxGotExpr(uint32_t Type, const uint8_t *Data,<br>
+ RelExpr RelExpr) const {<br>
if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX)<br>
- return false;<br>
+ return RelExpr;<br>
const uint8_t Op = Data[-2];<br>
const uint8_t ModRm = Data[-1];<br>
- // Relax mov.<br>
+ // FIXME: When PIC is disabled and foo is defined locally in the<br>
+ // lower 32 bit address space, memory operand in mov can be converted into<br>
+ // immediate operand. Otherwise, mov must be changed to lea. We support only<br>
+ // latter relaxation at this moment.<br>
if (Op == 0x8b)<br>
- return true;<br>
+ return R_RELAX_GOT_PC;<br>
// Relax call and jmp.<br>
- return Op == 0xff && (ModRm == 0x15 || ModRm == 0x25);<br>
+ if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25))<br>
+ return R_RELAX_GOT_PC;<br>
+<br>
+ // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor.<br>
+ // If PIC then no relaxation is available.<br>
+ // We also don't relax test/binop instructions without REX byte,<br>
+ // they are 32bit operations and not common to have.<br>
+ assert(Type == R_X86_64_REX_GOTPCRELX);<br>
+ return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC;<br>
}<br>
<br>
void X86_64TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const {<br>
@@ -757,22 +771,94 @@ void X86_64TargetInfo::relaxGot(uint8_t<br>
return;<br>
}<br>
<br>
- assert(Op == 0xff);<br>
- if (ModRm == 0x15) {<br>
- // ABI says we can convert call *foo@GOTPCREL(%rip) to nop call foo.<br>
- // Instead we convert to addr32 call foo, where addr32 is instruction<br>
- // prefix. That makes result expression to be a single instruction.<br>
- *(Loc - 2) = 0x67; // addr32 prefix<br>
- *(Loc - 1) = 0xe8; // call<br>
- } else {<br>
- assert(ModRm == 0x25);<br>
- // Convert jmp *foo@GOTPCREL(%rip) to jmp foo nop.<br>
- // jmp doesn't return, so it is fine to use nop here, it is just a stub.<br>
- *(Loc - 2) = 0xe9; // jmp<br>
- *(Loc + 3) = 0x90; // nop<br>
- Loc -= 1;<br>
- Val += 1;<br>
+ // Convert call/jmp instructions.<br>
+ if (Op == 0xff) {<br>
+ if (ModRm == 0x15) {<br>
+ // ABI says we can convert call *foo@GOTPCREL(%rip) to nop call foo.<br>
+ // Instead we convert to addr32 call foo, where addr32 is instruction<br>
+ // prefix. That makes result expression to be a single instruction.<br>
+ *(Loc - 2) = 0x67; // addr32 prefix<br>
+ *(Loc - 1) = 0xe8; // call<br>
+ } else {<br>
+ assert(ModRm == 0x25);<br>
+ // Convert jmp *foo@GOTPCREL(%rip) to jmp foo nop.<br>
+ // jmp doesn't return, so it is fine to use nop here, it is just a stub.<br>
+ *(Loc - 2) = 0xe9; // jmp<br>
+ *(Loc + 3) = 0x90; // nop<br>
+ Loc -= 1;<br>
+ Val += 1;<br>
+ }<br>
+ relocateOne(Loc, R_X86_64_PC32, Val);<br>
+ return;<br>
}<br>
+<br>
+ assert(!Config->Pic);<br>
+ // We are relaxing a rip relative to an absolute, so compensate for the old<br>
+ // -4 addend.<br>
+ Val += 4;<br>
+ // "Intel 64 and IA-32 Architectures Software Developer's Manual V2"<br>
+ // (<a href="http://www.intel.com/content/dam/www/public/us/en/documents/manuals/" rel="noreferrer" target="_blank">http://www.intel.com/content/dam/www/public/us/en/documents/manuals/</a><br>
+ // 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf)<br>
+ // can be used as reference.<br>
+<br>
+ const uint8_t Rex = Loc[-3];<br>
+ // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg".<br>
+ if (Op == 0x85) {<br>
+ // See "TEST-Logical Compare" (4-428 Vol. 2B),<br>
+ // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension).<br>
+<br>
+ // ModR/M byte has form XX YYY ZZZ, where<br>
+ // YYY is MODRM.reg(register 2), ZZZ is MODRM.rm(register 1).<br>
+ // XX has different meanings:<br>
+ // 00: The operand's memory address is in reg1.<br>
+ // 01: The operand's memory address is reg1 + a byte-sized displacement.<br>
+ // 10: The operand's memory address is reg1 + a word-sized displacement.<br>
+ // 11: The operand is reg1 itself.<br>
+ // If an instruction requires only one operand, the unused reg2 field<br>
+ // holds extra opcode bits rather than a register code<br>
+ // 0xC0 == 11 000 000 binary.<br>
+ // 0x38 == 00 111 000 binary.<br>
+ // We transfer reg2 to reg1 here as operand.<br>
+ // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3).<br>
+ *(Loc - 1) = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte.<br>
+<br>
+ // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32<br>
+ // See "TEST-Logical Compare" (4-428 Vol. 2B).<br>
+ *(Loc - 2) = 0xf7;<br>
+<br>
+ // Move R bit to the B bit in REX byte.<br>
+ // REX byte is encoded as 0100WRXB, where<br>
+ // 0100 is 4bit fixed pattern.<br>
+ // REX.W When 1, a 64-bit operand size is used. Otherwise, when 0, the<br>
+ // default operand size is used (which is 32-bit for most but not all<br>
+ // instructions).<br>
+ // REX.R This 1-bit value is an extension to the MODRM.reg field.<br>
+ // REX.X This 1-bit value is an extension to the SIB.index field.<br>
+ // REX.B This 1-bit value is an extension to the MODRM.rm field or the<br>
+ // SIB.base field.<br>
+ // See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A).<br>
+ *(Loc - 3) = (Rex & ~0x4) | (Rex & 0x4) >> 2;<br>
+ relocateOne(Loc, R_X86_64_PC32, Val);<br>
+ return;<br>
+ }<br>
+<br>
+ // If we are here then we need to relax the adc, add, and, cmp, or, sbb, sub<br>
+ // or xor operations.<br>
+<br>
+ // Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg".<br>
+ // Logic is close to one for test instruction above, but we also<br>
+ // write opcode extension here, see below for details.<br>
+ *(Loc - 1) = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte.<br>
+<br>
+ // Primary opcode is 0x81, opcode extension is one of:<br>
+ // 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB,<br>
+ // 100b is AND, 101b is SUB, 110b is XOR, 111b is CMP.<br>
+ // This value was wrote to MODRM.reg in a line above.<br>
+ // See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15),<br>
+ // "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for<br>
+ // descriptions about each operation.<br>
+ *(Loc - 2) = 0x81;<br>
+ *(Loc - 3) = (Rex & ~0x4) | (Rex & 0x4) >> 2;<br></blockquote><div><br></div><div>This new piece of code is too long to add to the existing function. Please define (a) new function(s) for it.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
relocateOne(Loc, R_X86_64_PC32, Val);<br>
}<br>
<br>
<br>
Modified: lld/trunk/ELF/Target.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=271405&r1=271404&r2=271405&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=271405&r1=271404&r2=271405&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/Target.h (original)<br>
+++ lld/trunk/ELF/Target.h Wed Jun 1 11:45:30 2016<br>
@@ -88,7 +88,8 @@ public:<br>
<br>
uint32_t ThunkSize = 0;<br>
<br>
- virtual bool canRelaxGot(uint32_t Type, const uint8_t *Data) const;<br>
+ virtual RelExpr adjustRelaxGotExpr(uint32_t Type, const uint8_t *Data,<br>
+ RelExpr Expr) const;<br>
virtual void relaxGot(uint8_t *Loc, uint64_t Val) const;<br>
virtual void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;<br>
virtual void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;<br>
<br>
Added: lld/trunk/test/ELF/gotpc-relax-nopic.s<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/gotpc-relax-nopic.s?rev=271405&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/gotpc-relax-nopic.s?rev=271405&view=auto</a><br>
==============================================================================<br>
--- lld/trunk/test/ELF/gotpc-relax-nopic.s (added)<br>
+++ lld/trunk/test/ELF/gotpc-relax-nopic.s Wed Jun 1 11:45:30 2016<br>
@@ -0,0 +1,81 @@<br>
+# REQUIRES: x86<br>
+# RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-unknown-linux %s -o %t.o<br>
+# RUN: ld.lld %t.o -o %t1<br>
+# RUN: llvm-readobj -symbols -r %t1 | FileCheck --check-prefix=SYMRELOC %s<br>
+# RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s<br>
+<br>
+## There is no relocations.<br>
+# SYMRELOC: Relocations [<br>
+# SYMRELOC-NEXT: ]<br>
+# SYMRELOC: Symbols [<br>
+# SYMRELOC: Symbol {<br>
+# SYMRELOC: Name: bar<br>
+# SYMRELOC-NEXT: Value: 0x12000<br>
+<br>
+## 73728 = 0x12000 (bar)<br>
+# DISASM: Disassembly of section .text:<br>
+# DISASM-NEXT: _start:<br>
+# DISASM-NEXT: 11000: 48 81 d0 00 20 01 00 adcq $73728, %rax<br>
+# DISASM-NEXT: 11007: 48 81 c3 00 20 01 00 addq $73728, %rbx<br>
+# DISASM-NEXT: 1100e: 48 81 e1 00 20 01 00 andq $73728, %rcx<br>
+# DISASM-NEXT: 11015: 48 81 fa 00 20 01 00 cmpq $73728, %rdx<br>
+# DISASM-NEXT: 1101c: 48 81 cf 00 20 01 00 orq $73728, %rdi<br>
+# DISASM-NEXT: 11023: 48 81 de 00 20 01 00 sbbq $73728, %rsi<br>
+# DISASM-NEXT: 1102a: 48 81 ed 00 20 01 00 subq $73728, %rbp<br>
+# DISASM-NEXT: 11031: 49 81 f0 00 20 01 00 xorq $73728, %r8<br>
+# DISASM-NEXT: 11038: 49 f7 c7 00 20 01 00 testq $73728, %r15<br>
+<br>
+# RUN: ld.lld -shared %t.o -o %t2<br>
+# RUN: llvm-readobj -s %t2 | FileCheck --check-prefix=SEC-PIC %s<br>
+# RUN: llvm-objdump -d %t2 | FileCheck --check-prefix=DISASM-PIC %s<br>
+# SEC-PIC: Section {<br>
+# SEC-PIC: Index:<br>
+# SEC-PIC: Name: .got<br>
+# SEC-PIC-NEXT: Type: SHT_PROGBITS<br>
+# SEC-PIC-NEXT: Flags [<br>
+# SEC-PIC-NEXT: SHF_ALLOC<br>
+# SEC-PIC-NEXT: SHF_WRITE<br>
+# SEC-PIC-NEXT: ]<br>
+# SEC-PIC-NEXT: Address: 0x2090<br>
+# SEC-PIC-NEXT: Offset: 0x2090<br>
+# SEC-PIC-NEXT: Size: 8<br>
+# SEC-PIC-NEXT: Link:<br>
+# SEC-PIC-NEXT: Info:<br>
+# SEC-PIC-NEXT: AddressAlignment:<br>
+# SEC-PIC-NEXT: EntrySize:<br>
+# SEC-PIC-NEXT: }<br>
+<br>
+## Check that there was no relaxation performed. All values refer to got entry.<br>
+## Ex: 0x1000 + 4233 + 7 = 0x2090<br>
+## 0x102a + 4191 + 7 = 0x2090<br>
+# DISASM-PIC: Disassembly of section .text:<br>
+# DISASM-PIC-NEXT: _start:<br>
+# DISASM-PIC-NEXT: 1000: 48 13 05 89 10 00 00 adcq 4233(%rip), %rax<br>
+# DISASM-PIC-NEXT: 1007: 48 03 1d 82 10 00 00 addq 4226(%rip), %rbx<br>
+# DISASM-PIC-NEXT: 100e: 48 23 0d 7b 10 00 00 andq 4219(%rip), %rcx<br>
+# DISASM-PIC-NEXT: 1015: 48 3b 15 74 10 00 00 cmpq 4212(%rip), %rdx<br>
+# DISASM-PIC-NEXT: 101c: 48 0b 3d 6d 10 00 00 orq 4205(%rip), %rdi<br>
+# DISASM-PIC-NEXT: 1023: 48 1b 35 66 10 00 00 sbbq 4198(%rip), %rsi<br>
+# DISASM-PIC-NEXT: 102a: 48 2b 2d 5f 10 00 00 subq 4191(%rip), %rbp<br>
+# DISASM-PIC-NEXT: 1031: 4c 33 05 58 10 00 00 xorq 4184(%rip), %r8<br>
+# DISASM-PIC-NEXT: 1038: 4c 85 3d 51 10 00 00 testq 4177(%rip), %r15<br>
+<br>
+.data<br>
+.type bar, @object<br>
+bar:<br>
+ .byte 1<br>
+ .size bar, .-bar<br>
+<br>
+.text<br>
+.globl _start<br>
+.type _start, @function<br>
+_start:<br>
+ adcq bar@GOTPCREL(%rip), %rax<br>
+ addq bar@GOTPCREL(%rip), %rbx<br>
+ andq bar@GOTPCREL(%rip), %rcx<br>
+ cmpq bar@GOTPCREL(%rip), %rdx<br>
+ orq bar@GOTPCREL(%rip), %rdi<br>
+ sbbq bar@GOTPCREL(%rip), %rsi<br>
+ subq bar@GOTPCREL(%rip), %rbp<br>
+ xorq bar@GOTPCREL(%rip), %r8<br>
+ testq %r15, bar@GOTPCREL(%rip)<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>