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
This commit is contained in:
Michael J. Spencer 2010-08-24 21:04:52 +00:00
parent 3e242f86eb
commit 82c84fdd23
4 changed files with 89 additions and 52 deletions

View 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];
FixedValue = Target.getConstant();
if (Target.getSymB()) {
const MCSymbol *B = &Target.getSymB()->getSymbol();
MCSymbolData &B_SD = Asm.getSymbolData(*B);
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);
}

View 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]

View File

@ -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
}

View File

@ -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]