From 82759c6cacf861a18b9d362ab6dc766573a1ce2d Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Fri, 20 Mar 2015 19:48:54 +0000 Subject: [PATCH] Reorganize the x86 ELF relocation selection logic. The main differences are: * Split in 32 and 64 bit functions. * First switch on the Modifier so that we have only one non fully covered switch. * Map the fixup kind first to a x86_64 (or i386) specific enum, to make it easy to handle cases like X86::reloc_riprel_4byte_movq_load. * Switch on IsPCRel last, which reduces code duplication. Fixes pr22308. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@232837 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../X86/MCTargetDesc/X86ELFObjectWriter.cpp | 374 +++++++++--------- test/MC/ELF/relocation-386.s | 5 + test/MC/ELF/relocation.s | 4 + 3 files changed, 207 insertions(+), 176 deletions(-) diff --git a/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp b/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp index 3a664b93ef1..65684b7e1cc 100644 --- a/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp +++ b/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp @@ -38,193 +38,215 @@ X86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, X86ELFObjectWriter::~X86ELFObjectWriter() {} -unsigned X86ELFObjectWriter::GetRelocType(const MCValue &Target, - const MCFixup &Fixup, - bool IsPCRel) const { - // determine the type of the relocation +enum X86_64RelType { RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 }; - MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); - if (getEMachine() == ELF::EM_X86_64) { - if (IsPCRel) { - switch ((unsigned)Fixup.getKind()) { - default: - llvm_unreachable("invalid fixup kind!"); +static X86_64RelType getType64(unsigned Kind, + MCSymbolRefExpr::VariantKind &Modifier, + bool &IsPCRel) { + switch (Kind) { + default: + llvm_unreachable("Unimplemented"); + case X86::reloc_global_offset_table8: + Modifier = MCSymbolRefExpr::VK_GOT; + IsPCRel = true; + return RT64_64; + case FK_Data_8: + return RT64_64; + case X86::reloc_signed_4byte: + if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel) + return RT64_32S; + return RT64_32; + case X86::reloc_global_offset_table: + Modifier = MCSymbolRefExpr::VK_GOT; + IsPCRel = true; + return RT64_32; + case FK_Data_4: + case FK_PCRel_4: + case X86::reloc_riprel_4byte: + case X86::reloc_riprel_4byte_movq_load: + return RT64_32; + case FK_Data_2: + return RT64_16; + case FK_PCRel_1: + case FK_Data_1: + return RT64_8; + } +} - case FK_Data_8: - return ELF::R_X86_64_PC64; - case FK_Data_4: - return ELF::R_X86_64_PC32; - case FK_Data_2: - return ELF::R_X86_64_PC16; - case FK_Data_1: - return ELF::R_X86_64_PC8; - case FK_PCRel_8: - assert(Modifier == MCSymbolRefExpr::VK_None); - return ELF::R_X86_64_PC64; - case X86::reloc_signed_4byte: - case X86::reloc_riprel_4byte_movq_load: - case X86::reloc_riprel_4byte: - case FK_PCRel_4: - switch (Modifier) { - default: - llvm_unreachable("Unimplemented"); - case MCSymbolRefExpr::VK_None: - return ELF::R_X86_64_PC32; - case MCSymbolRefExpr::VK_PLT: - return ELF::R_X86_64_PLT32; - case MCSymbolRefExpr::VK_GOTPCREL: - return ELF::R_X86_64_GOTPCREL; - case MCSymbolRefExpr::VK_GOTTPOFF: - return ELF::R_X86_64_GOTTPOFF; - case MCSymbolRefExpr::VK_TLSGD: - return ELF::R_X86_64_TLSGD; - case MCSymbolRefExpr::VK_TLSLD: - return ELF::R_X86_64_TLSLD; - } - case FK_PCRel_2: - assert(Modifier == MCSymbolRefExpr::VK_None); - return ELF::R_X86_64_PC16; - case FK_PCRel_1: - assert(Modifier == MCSymbolRefExpr::VK_None); - return ELF::R_X86_64_PC8; - } +unsigned getRelocType64(MCSymbolRefExpr::VariantKind Modifier, + X86_64RelType Type, bool IsPCRel) { + switch (Modifier) { + default: + llvm_unreachable("Unimplemented"); + case MCSymbolRefExpr::VK_None: + switch (Type) { + case RT64_64: + return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64; + case RT64_32: + return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32; + case RT64_32S: + return ELF::R_X86_64_32S; + case RT64_16: + return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16; + case RT64_8: + return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8; } - switch ((unsigned)Fixup.getKind()) { - default: - llvm_unreachable("invalid fixup kind!"); - case X86::reloc_global_offset_table8: - return ELF::R_X86_64_GOTPC64; - case X86::reloc_global_offset_table: - return ELF::R_X86_64_GOTPC32; - case FK_Data_8: - switch (Modifier) { - default: - llvm_unreachable("Unimplemented"); - case MCSymbolRefExpr::VK_None: - return ELF::R_X86_64_64; - case MCSymbolRefExpr::VK_GOT: - return ELF::R_X86_64_GOT64; - case MCSymbolRefExpr::VK_GOTOFF: - return ELF::R_X86_64_GOTOFF64; - case MCSymbolRefExpr::VK_TPOFF: - return ELF::R_X86_64_TPOFF64; - case MCSymbolRefExpr::VK_DTPOFF: - return ELF::R_X86_64_DTPOFF64; - case MCSymbolRefExpr::VK_SIZE: - return ELF::R_X86_64_SIZE64; - } - case X86::reloc_signed_4byte: - switch (Modifier) { - default: - llvm_unreachable("Unimplemented"); - case MCSymbolRefExpr::VK_None: - return ELF::R_X86_64_32S; - case MCSymbolRefExpr::VK_GOT: - return ELF::R_X86_64_GOT32; - case MCSymbolRefExpr::VK_GOTPCREL: - return ELF::R_X86_64_GOTPCREL; - case MCSymbolRefExpr::VK_TPOFF: - return ELF::R_X86_64_TPOFF32; - case MCSymbolRefExpr::VK_DTPOFF: - return ELF::R_X86_64_DTPOFF32; - case MCSymbolRefExpr::VK_SIZE: - return ELF::R_X86_64_SIZE32; - } - case FK_Data_4: - return ELF::R_X86_64_32; - case FK_Data_2: - return ELF::R_X86_64_16; - case FK_PCRel_1: - case FK_Data_1: - return ELF::R_X86_64_8; + case MCSymbolRefExpr::VK_GOT: + switch (Type) { + case RT64_64: + return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64; + case RT64_32: + return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32; + case RT64_32S: + case RT64_16: + case RT64_8: + llvm_unreachable("Unimplemented"); } + case MCSymbolRefExpr::VK_GOTOFF: + assert(Type == RT64_64); + assert(!IsPCRel); + return ELF::R_X86_64_GOTOFF64; + case MCSymbolRefExpr::VK_TPOFF: + assert(!IsPCRel); + switch (Type) { + case RT64_64: + return ELF::R_X86_64_TPOFF64; + case RT64_32: + return ELF::R_X86_64_TPOFF32; + case RT64_32S: + case RT64_16: + case RT64_8: + llvm_unreachable("Unimplemented"); + } + case MCSymbolRefExpr::VK_DTPOFF: + assert(!IsPCRel); + switch (Type) { + case RT64_64: + return ELF::R_X86_64_DTPOFF64; + case RT64_32: + return ELF::R_X86_64_DTPOFF32; + case RT64_32S: + case RT64_16: + case RT64_8: + llvm_unreachable("Unimplemented"); + } + case MCSymbolRefExpr::VK_SIZE: + assert(!IsPCRel); + switch (Type) { + case RT64_64: + return ELF::R_X86_64_SIZE64; + case RT64_32: + return ELF::R_X86_64_SIZE32; + case RT64_32S: + case RT64_16: + case RT64_8: + llvm_unreachable("Unimplemented"); + } + case MCSymbolRefExpr::VK_TLSGD: + assert(Type == RT64_32); + return ELF::R_X86_64_TLSGD; + case MCSymbolRefExpr::VK_GOTTPOFF: + assert(Type == RT64_32); + return ELF::R_X86_64_GOTTPOFF; + case MCSymbolRefExpr::VK_TLSLD: + assert(Type == RT64_32); + return ELF::R_X86_64_TLSLD; + case MCSymbolRefExpr::VK_PLT: + assert(Type == RT64_32); + return ELF::R_X86_64_PLT32; + case MCSymbolRefExpr::VK_GOTPCREL: + assert(Type == RT64_32); + return ELF::R_X86_64_GOTPCREL; } - assert(getEMachine() == ELF::EM_386 && "Unsupported ELF machine type."); - if (IsPCRel) { - switch ((unsigned)Fixup.getKind()) { - default: - llvm_unreachable("invalid fixup kind!"); +} - case X86::reloc_global_offset_table: - return ELF::R_386_GOTPC; - case FK_PCRel_1: - case FK_Data_1: - switch (Modifier) { - default: - llvm_unreachable("Unimplemented"); - case MCSymbolRefExpr::VK_None: - return ELF::R_386_PC8; - } - case FK_PCRel_2: - case FK_Data_2: - switch (Modifier) { - default: - llvm_unreachable("Unimplemented"); - case MCSymbolRefExpr::VK_None: - return ELF::R_386_PC16; - } - case X86::reloc_riprel_4byte: - case X86::reloc_signed_4byte: - case FK_PCRel_4: - case FK_Data_4: - switch (Modifier) { - default: - llvm_unreachable("Unimplemented"); - case MCSymbolRefExpr::VK_None: - return ELF::R_386_PC32; - case MCSymbolRefExpr::VK_PLT: - return ELF::R_386_PLT32; - } - } - } else { - switch ((unsigned)Fixup.getKind()) { - default: - llvm_unreachable("invalid fixup kind!"); - case X86::reloc_global_offset_table: - return ELF::R_386_GOTPC; +enum X86_32RelType { RT32_32, RT32_16, RT32_8 }; - // FIXME: Should we avoid selecting reloc_signed_4byte in 32 bit mode - // instead? - case X86::reloc_signed_4byte: - case FK_PCRel_4: - case FK_Data_4: - switch (Modifier) { - default: - llvm_unreachable("Unimplemented"); - case MCSymbolRefExpr::VK_None: - return ELF::R_386_32; - case MCSymbolRefExpr::VK_GOT: - return ELF::R_386_GOT32; - case MCSymbolRefExpr::VK_PLT: - return ELF::R_386_PLT32; - case MCSymbolRefExpr::VK_GOTOFF: - return ELF::R_386_GOTOFF; - case MCSymbolRefExpr::VK_TLSGD: - return ELF::R_386_TLS_GD; - case MCSymbolRefExpr::VK_TPOFF: - return ELF::R_386_TLS_LE_32; - case MCSymbolRefExpr::VK_INDNTPOFF: - return ELF::R_386_TLS_IE; - case MCSymbolRefExpr::VK_NTPOFF: - return ELF::R_386_TLS_LE; - case MCSymbolRefExpr::VK_GOTNTPOFF: - return ELF::R_386_TLS_GOTIE; - case MCSymbolRefExpr::VK_TLSLDM: - return ELF::R_386_TLS_LDM; - case MCSymbolRefExpr::VK_DTPOFF: - return ELF::R_386_TLS_LDO_32; - case MCSymbolRefExpr::VK_GOTTPOFF: - return ELF::R_386_TLS_IE_32; - } - case FK_Data_2: - return ELF::R_386_16; - case FK_PCRel_1: - case FK_Data_1: - return ELF::R_386_8; +static X86_32RelType getType32(X86_64RelType T) { + switch (T) { + case RT64_64: + llvm_unreachable("Unimplemented"); + case RT64_32: + case RT64_32S: + return RT32_32; + case RT64_16: + return RT32_16; + case RT64_8: + return RT32_8; + } +} + +unsigned getRelocType32(MCSymbolRefExpr::VariantKind Modifier, + X86_32RelType Type, bool IsPCRel) { + switch (Modifier) { + default: + llvm_unreachable("Unimplemented"); + case MCSymbolRefExpr::VK_None: + switch (Type) { + case RT32_32: + return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32; + case RT32_16: + return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16; + case RT32_8: + return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8; } + case MCSymbolRefExpr::VK_GOT: + assert(Type == RT32_32); + return IsPCRel ? ELF::R_386_GOTPC : ELF::R_386_GOT32; + case MCSymbolRefExpr::VK_GOTOFF: + assert(Type == RT32_32); + assert(!IsPCRel); + return ELF::R_386_GOTOFF; + case MCSymbolRefExpr::VK_TPOFF: + assert(Type == RT32_32); + assert(!IsPCRel); + return ELF::R_386_TLS_LE_32; + case MCSymbolRefExpr::VK_DTPOFF: + assert(Type == RT32_32); + assert(!IsPCRel); + return ELF::R_386_TLS_LDO_32; + case MCSymbolRefExpr::VK_TLSGD: + assert(Type == RT32_32); + assert(!IsPCRel); + return ELF::R_386_TLS_GD; + case MCSymbolRefExpr::VK_GOTTPOFF: + assert(Type == RT32_32); + assert(!IsPCRel); + return ELF::R_386_TLS_IE_32; + case MCSymbolRefExpr::VK_PLT: + assert(Type == RT32_32); + return ELF::R_386_PLT32; + case MCSymbolRefExpr::VK_INDNTPOFF: + assert(Type == RT32_32); + assert(!IsPCRel); + return ELF::R_386_TLS_IE; + case MCSymbolRefExpr::VK_NTPOFF: + assert(Type == RT32_32); + assert(!IsPCRel); + return ELF::R_386_TLS_LE; + case MCSymbolRefExpr::VK_GOTNTPOFF: + assert(Type == RT32_32); + assert(!IsPCRel); + return ELF::R_386_TLS_GOTIE; + case MCSymbolRefExpr::VK_TLSLDM: + assert(Type == RT32_32); + assert(!IsPCRel); + return ELF::R_386_TLS_LDM; } } +unsigned X86ELFObjectWriter::GetRelocType(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); + X86_64RelType Type = getType64(Fixup.getKind(), Modifier, IsPCRel); + if (getEMachine() == ELF::EM_X86_64) + return getRelocType64(Modifier, Type, IsPCRel); + + assert(getEMachine() == ELF::EM_386 && "Unsupported ELF machine type."); + return getRelocType32(Modifier, getType32(Type), IsPCRel); +} + MCObjectWriter *llvm::createX86ELFObjectWriter(raw_ostream &OS, bool IsELF64, uint8_t OSABI, diff --git a/test/MC/ELF/relocation-386.s b/test/MC/ELF/relocation-386.s index 39abcedba5e..b998ea54c89 100644 --- a/test/MC/ELF/relocation-386.s +++ b/test/MC/ELF/relocation-386.s @@ -66,6 +66,8 @@ // Relocation 29 (zed@PLT) is of type R_386_PLT32 and uses the symbol // CHECK-NEXT: 0xA9 R_386_PLT32 zed 0x0 // CHECK-NEXT: 0xAF R_386_PC32 tr_start 0x0 +// CHECK-NEXT: 0xB3 R_386_16 foo 0x0 +// CHECK-NEXT: 0xB5 R_386_8 foo 0x0 // CHECK-NEXT: } // CHECK-NEXT: ] @@ -137,6 +139,9 @@ bar2: .code64 jmpq *tr_start(%rip) + .word foo + .byte foo + .section zedsec,"awT",@progbits zed: .long 0 diff --git a/test/MC/ELF/relocation.s b/test/MC/ELF/relocation.s index 1e0409f3ea7..de2b43454ac 100644 --- a/test/MC/ELF/relocation.s +++ b/test/MC/ELF/relocation.s @@ -41,6 +41,8 @@ bar: movl blah@SIZE + 32, %eax # R_X86_64_SIZE32 movl blah@SIZE - 32, %eax # R_X86_64_SIZE32 + .long foo@gotpcrel + .long foo@plt // CHECK: Section { // CHECK: Name: .rela.text // CHECK: Relocations [ @@ -75,6 +77,8 @@ bar: // CHECK-NEXT: 0xC6 R_X86_64_SIZE32 blah 0x0 // CHECK-NEXT: 0xCD R_X86_64_SIZE32 blah 0x20 // CHECK-NEXT: 0xD4 R_X86_64_SIZE32 blah 0xFFFFFFFFFFFFFFE0 +// CHECK-NEXT: 0xD8 R_X86_64_GOTPCREL foo 0x0 +// CHECK-NEXT: 0xDC R_X86_64_PLT32 foo 0x0 // CHECK-NEXT: ] // CHECK-NEXT: } -- 2.34.1