From: Michael J. Spencer Date: Tue, 24 Aug 2010 21:04:52 +0000 (+0000) Subject: Fix COFF x86-64 relocations. PR7960. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=82c84fdd23669d23c02a07498c83b83702979829;p=oota-llvm.git Fix COFF x86-64 relocations. PR7960. Multiple symbol reloc handling part of the patch by Cameron Esfahani. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@111963 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/MC/WinCOFFObjectWriter.cpp b/lib/MC/WinCOFFObjectWriter.cpp index eab2ba97ab0..eeb2b9675f4 100644 --- a/lib/MC/WinCOFFObjectWriter.cpp +++ b/lib/MC/WinCOFFObjectWriter.cpp @@ -125,6 +125,7 @@ public: typedef DenseMap section_map; // Root level file contents. + bool Is64Bit; COFF::header Header; sections Sections; symbols Symbols; @@ -274,10 +275,11 @@ size_t StringTable::insert(llvm::StringRef String) { // WinCOFFObjectWriter class implementation WinCOFFObjectWriter::WinCOFFObjectWriter(raw_ostream &OS, bool is64Bit) - : MCObjectWriter(OS, true) { + : MCObjectWriter(OS, true) + , Is64Bit(is64Bit) { memset(&Header, 0, sizeof(Header)); - is64Bit ? Header.Machine = COFF::IMAGE_FILE_MACHINE_AMD64 + Is64Bit ? Header.Machine = COFF::IMAGE_FILE_MACHINE_AMD64 : Header.Machine = COFF::IMAGE_FILE_MACHINE_I386; } @@ -565,22 +567,34 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, MCValue Target, uint64_t &FixedValue) { assert(Target.getSymA() != NULL && "Relocation must reference a symbol!"); - assert(Target.getSymB() == NULL && - "Relocation must reference only one symbol!"); + + const MCSymbol *A = &Target.getSymA()->getSymbol(); + MCSymbolData &A_SD = Asm.getSymbolData(*A); MCSectionData const *SectionData = Fragment->getParent(); - MCSymbolData const *SymbolData = - &Asm.getSymbolData(Target.getSymA()->getSymbol()); + // Mark this symbol as requiring an entry in the symbol table. assert(SectionMap.find(SectionData) != SectionMap.end() && "Section must already have been defined in ExecutePostLayoutBinding!"); - assert(SymbolMap.find(SymbolData) != SymbolMap.end() && + assert(SymbolMap.find(&A_SD) != SymbolMap.end() && "Symbol must already have been defined in ExecutePostLayoutBinding!"); COFFSection *coff_section = SectionMap[SectionData]; - COFFSymbol *coff_symbol = SymbolMap[SymbolData]; + COFFSymbol *coff_symbol = SymbolMap[&A_SD]; + + if (Target.getSymB()) { + const MCSymbol *B = &Target.getSymB()->getSymbol(); + MCSymbolData &B_SD = Asm.getSymbolData(*B); - FixedValue = Target.getConstant(); + FixedValue = Layout.getSymbolAddress(&A_SD) - Layout.getSymbolAddress(&B_SD); + + // In the case where we have SymbA and SymB, we just need to store the delta + // between the two symbols. Update FixedValue to account for the delta, and + // skip recording the relocation. + return; + } else { + FixedValue = Target.getConstant(); + } COFFRelocation Reloc; @@ -590,40 +604,29 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, Reloc.Data.VirtualAddress += Fixup.getOffset(); - COFF::RelocationTypeX86 Type; - - if (Header.Machine == COFF::IMAGE_FILE_MACHINE_I386) { - switch (Fixup.getKind()) { - case X86::reloc_pcrel_4byte: - Type = COFF::IMAGE_REL_I386_REL32; - FixedValue += 4; - break; - case FK_Data_4: - Type = COFF::IMAGE_REL_I386_DIR32; - break; - default: + switch (Fixup.getKind()) { + case X86::reloc_pcrel_4byte: + case X86::reloc_riprel_4byte: + case X86::reloc_riprel_4byte_movq_load: + Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_REL32 + : COFF::IMAGE_REL_I386_REL32; + // FIXME: Can anyone explain what this does other than adjust for the size + // of the offset? + FixedValue += 4; + break; + case FK_Data_4: + Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_ADDR32 + : COFF::IMAGE_REL_I386_DIR32; + break; + case FK_Data_8: + if (Is64Bit) + Reloc.Data.Type = COFF::IMAGE_REL_AMD64_ADDR64; + else llvm_unreachable("unsupported relocation type"); - } - } else if (Header.Machine == COFF::IMAGE_FILE_MACHINE_AMD64) { - switch (Fixup.getKind()) { - case FK_Data_8: - Type = COFF::IMAGE_REL_AMD64_ADDR64; - break; - case X86::reloc_pcrel_4byte: - case X86::reloc_riprel_4byte: - Type = COFF::IMAGE_REL_AMD64_REL32; - FixedValue += 4; - break; - case FK_Data_4: - Type = COFF::IMAGE_REL_AMD64_ADDR32; - break; - default: - llvm_unreachable("unsupported relocation type"); - } - } else - llvm_unreachable("unknown target architecture"); - - Reloc.Data.Type = Type; + break; + default: + llvm_unreachable("unsupported relocation type"); + } coff_section->Relocations.push_back(Reloc); } diff --git a/test/MC/COFF/basic-coff.ll b/test/MC/COFF/basic-coff.ll index 2178bc8a52c..e1bf11ef0b2 100644 --- a/test/MC/COFF/basic-coff.ll +++ b/test/MC/COFF/basic-coff.ll @@ -1,9 +1,9 @@ -; RUN: llc -filetype=obj %s -o %t -; RUN: coff-dump.py %abs_tmp | FileCheck %s +; This test checks that the COFF object emitter works for the most basic +; programs. -; ModuleID = '-' -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32" -target triple = "i686-pc-win32" +; RUN: llc -filetype=obj -mtriple i686-pc-win32 %s -o %t +; RUN: coff-dump.py %abs_tmp | FileCheck %s +; RUN: llc -filetype=obj -mtriple x86_64-pc-win32 %s -o %t @.str = private constant [12 x i8] c"Hello World\00" ; <[12 x i8]*> [#uses=1] diff --git a/test/MC/COFF/switch-relocations.ll b/test/MC/COFF/switch-relocations.ll new file mode 100644 index 00000000000..300c10732ec --- /dev/null +++ b/test/MC/COFF/switch-relocations.ll @@ -0,0 +1,34 @@ +; The purpose of this test is to see if the COFF object writer can properly +; relax the fixups that are created for jump tables on x86-64. See PR7960. + +; This test case was reduced from Lua/lapi.c. + +; RUN: llc -filetype=obj -mtriple i686-pc-win32 %s -o %t +; RUN: llc -filetype=obj -mtriple x86_64-pc-win32 %s -o %t + +define void @lua_gc(i32 %what) nounwind { +entry: + switch i32 %what, label %sw.epilog [ + i32 0, label %sw.bb + i32 1, label %sw.bb + i32 2, label %sw.bb + i32 3, label %sw.bb14 + i32 4, label %sw.bb18 + i32 6, label %sw.bb57 + ] + +sw.bb: ; preds = %entry, %entry, %entry + ret void + +sw.bb14: ; preds = %entry + ret void + +sw.bb18: ; preds = %entry + ret void + +sw.bb57: ; preds = %entry + ret void + +sw.epilog: ; preds = %entry + ret void +} diff --git a/test/MC/COFF/symbol-fragment-offset.ll b/test/MC/COFF/symbol-fragment-offset.ll index bf22c4ecede..25cae5ac1db 100644 --- a/test/MC/COFF/symbol-fragment-offset.ll +++ b/test/MC/COFF/symbol-fragment-offset.ll @@ -1,9 +1,9 @@ -; RUN: llc -filetype=obj %s -o %t -; RUN: coff-dump.py %abs_tmp | FileCheck %s +; The purpose of this test is to see if the COFF object writer is emitting the +; proper relocations for multiple pieces of data in a single data fragment. -; ModuleID = 'coff-fragment-test.c' -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32" -target triple = "i686-pc-win32" +; RUN: llc -filetype=obj -mtriple i686-pc-win32 %s -o %t +; RUN: coff-dump.py %abs_tmp | FileCheck %s +; RUN: llc -filetype=obj -mtriple x86_64-pc-win32 %s -o %t @.str = private constant [7 x i8] c"Hello \00" ; <[7 x i8]*> [#uses=1] @str = internal constant [7 x i8] c"World!\00" ; <[7 x i8]*> [#uses=1]