Fix COFF x86-64 relocations. PR7960.
authorMichael J. Spencer <bigcheesegs@gmail.com>
Tue, 24 Aug 2010 21:04:52 +0000 (21:04 +0000)
committerMichael J. Spencer <bigcheesegs@gmail.com>
Tue, 24 Aug 2010 21:04:52 +0000 (21:04 +0000)
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

lib/MC/WinCOFFObjectWriter.cpp
test/MC/COFF/basic-coff.ll
test/MC/COFF/switch-relocations.ll [new file with mode: 0644]
test/MC/COFF/symbol-fragment-offset.ll

index eab2ba97ab0f47113b6b59e48dfa65dd98241d9c..eeb2b9675f4b50419b8b1c982b3334dc9086d331 100644 (file)
@@ -125,6 +125,7 @@ public:
   typedef DenseMap<MCSectionData const *, COFFSection *> 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);
 }
index 2178bc8a52c4892a461f795ddb74d7ae3f16ce0e..e1bf11ef0b2809d99eb4e4db1a9a8df7b437407f 100644 (file)
@@ -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 (file)
index 0000000..300c107
--- /dev/null
@@ -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
+}
index bf22c4ecedee6bcde8b15ce70433a9c8dfa3cb09..25cae5ac1dba3a33e89299cdec694a3fb9583af2 100644 (file)
@@ -1,9 +1,9 @@
-; RUN: llc -filetype=obj %s -o %t\r
-; RUN: coff-dump.py %abs_tmp | FileCheck %s\r
+; The purpose of this test is to see if the COFF object writer is emitting the\r
+; proper relocations for multiple pieces of data in a single data fragment.\r
 \r
-; ModuleID = 'coff-fragment-test.c'\r
-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"\r
-target triple = "i686-pc-win32"\r
+; RUN: llc -filetype=obj -mtriple i686-pc-win32 %s -o %t\r
+; RUN: coff-dump.py %abs_tmp | FileCheck %s\r
+; RUN: llc -filetype=obj -mtriple x86_64-pc-win32 %s -o %t\r
 \r
 @.str = private constant [7 x i8] c"Hello \00"    ; <[7 x i8]*> [#uses=1]\r
 @str = internal constant [7 x i8] c"World!\00"    ; <[7 x i8]*> [#uses=1]\r