X86_32: Large Symbol+Offset relocations.

If the offset is more than 24-bits, it won't fit in a scattered
relocation offset field, so we fall back to using a non-scattered
relocation.

rdar://12358909

llvm-svn: 164724
This commit is contained in:
Jim Grosbach 2012-09-26 21:27:45 +00:00
parent 4ca7389925
commit c03a0c241e
2 changed files with 76 additions and 8 deletions

View File

@ -11,11 +11,13 @@
#include "MCTargetDesc/X86MCTargetDesc.h" #include "MCTargetDesc/X86MCTargetDesc.h"
#include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCMachObjectWriter.h" #include "llvm/MC/MCMachObjectWriter.h"
#include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCValue.h" #include "llvm/MC/MCValue.h"
#include "llvm/ADT/Twine.h" #include "llvm/ADT/Twine.h"
#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Object/MachOFormat.h" #include "llvm/Object/MachOFormat.h"
using namespace llvm; using namespace llvm;
@ -23,7 +25,7 @@ using namespace llvm::object;
namespace { namespace {
class X86MachObjectWriter : public MCMachObjectTargetWriter { class X86MachObjectWriter : public MCMachObjectTargetWriter {
void RecordScatteredRelocation(MachObjectWriter *Writer, bool RecordScatteredRelocation(MachObjectWriter *Writer,
const MCAssembler &Asm, const MCAssembler &Asm,
const MCAsmLayout &Layout, const MCAsmLayout &Layout,
const MCFragment *Fragment, const MCFragment *Fragment,
@ -335,7 +337,7 @@ void X86MachObjectWriter::RecordX86_64Relocation(MachObjectWriter *Writer,
Writer->addRelocation(Fragment->getParent(), MRE); Writer->addRelocation(Fragment->getParent(), MRE);
} }
void X86MachObjectWriter::RecordScatteredRelocation(MachObjectWriter *Writer, bool X86MachObjectWriter::RecordScatteredRelocation(MachObjectWriter *Writer,
const MCAssembler &Asm, const MCAssembler &Asm,
const MCAsmLayout &Layout, const MCAsmLayout &Layout,
const MCFragment *Fragment, const MCFragment *Fragment,
@ -381,6 +383,19 @@ void X86MachObjectWriter::RecordScatteredRelocation(MachObjectWriter *Writer,
// Relocations are written out in reverse order, so the PAIR comes first. // Relocations are written out in reverse order, so the PAIR comes first.
if (Type == macho::RIT_Difference || if (Type == macho::RIT_Difference ||
Type == macho::RIT_Generic_LocalDifference) { Type == macho::RIT_Generic_LocalDifference) {
// If the offset is too large to fit in a scattered relocation,
// we're hosed. It's an unfortunate limitation of the MachO format.
if (FixupOffset > 0xffffff) {
char Buffer[32];
format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer));
Asm.getContext().FatalError(Fixup.getLoc(),
Twine("Section too large, can't encode "
"r_address (") + Buffer +
") into 24 bits of scattered "
"relocation entry.");
llvm_unreachable("fatal error returned?!");
}
macho::RelocationEntry MRE; macho::RelocationEntry MRE;
MRE.Word0 = ((0 << 0) | MRE.Word0 = ((0 << 0) |
(macho::RIT_Pair << 24) | (macho::RIT_Pair << 24) |
@ -389,6 +404,16 @@ void X86MachObjectWriter::RecordScatteredRelocation(MachObjectWriter *Writer,
macho::RF_Scattered); macho::RF_Scattered);
MRE.Word1 = Value2; MRE.Word1 = Value2;
Writer->addRelocation(Fragment->getParent(), MRE); Writer->addRelocation(Fragment->getParent(), MRE);
} else {
// If the offset is more than 24-bits, it won't fit in a scattered
// relocation offset field, so we fall back to using a non-scattered
// relocation. This is a bit risky, as if the offset reaches out of
// the block and the linker is doing scattered loading on this
// symbol, things can go badly.
//
// Required for 'as' compatibility.
if (FixupOffset > 0xffffff)
return false;
} }
macho::RelocationEntry MRE; macho::RelocationEntry MRE;
@ -399,6 +424,7 @@ void X86MachObjectWriter::RecordScatteredRelocation(MachObjectWriter *Writer,
macho::RF_Scattered); macho::RF_Scattered);
MRE.Word1 = Value; MRE.Word1 = Value;
Writer->addRelocation(Fragment->getParent(), MRE); Writer->addRelocation(Fragment->getParent(), MRE);
return true;
} }
void X86MachObjectWriter::RecordTLVPRelocation(MachObjectWriter *Writer, void X86MachObjectWriter::RecordTLVPRelocation(MachObjectWriter *Writer,
@ -469,9 +495,11 @@ void X86MachObjectWriter::RecordX86Relocation(MachObjectWriter *Writer,
// If this is a difference or a defined symbol plus an offset, then we need a // If this is a difference or a defined symbol plus an offset, then we need a
// scattered relocation entry. Differences always require scattered // scattered relocation entry. Differences always require scattered
// relocations. // relocations.
if (Target.getSymB()) if (Target.getSymB()) {
return RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
Target, Log2Size, FixedValue); Target, Log2Size, FixedValue);
return;
}
// Get the symbol data, if any. // Get the symbol data, if any.
MCSymbolData *SD = 0; MCSymbolData *SD = 0;
@ -483,9 +511,13 @@ void X86MachObjectWriter::RecordX86Relocation(MachObjectWriter *Writer,
uint32_t Offset = Target.getConstant(); uint32_t Offset = Target.getConstant();
if (IsPCRel) if (IsPCRel)
Offset += 1 << Log2Size; Offset += 1 << Log2Size;
if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD)) // Try to record the scattered relocation if needed. Fall back to non
return RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, // scattered if necessary (see comments in RecordScatteredRelocation()
Target, Log2Size, FixedValue); // for details).
if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD) &&
RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
Target, Log2Size, FixedValue))
return;
// See <reloc.h>. // See <reloc.h>.
uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();

View File

@ -0,0 +1,36 @@
// RUN: llvm-mc -triple i386-apple-darwin10 %s -filetype=obj -o - | macho-dump | FileCheck %s
.space 0x1ed280
.section __DATA,__const
.align 4
.space 0x5181020
_foo:
.long _bar
.long 0
.long _bar+8
.long _bar+24
.long 0
.long _bar+16
.zerofill __DATA,__bss,__dummy,0x5d780
.zerofill __DATA,__bss,_bar,48,4
// Normally scattered relocations are used for sym+offset expressions. When
// the value exceeds 24-bits, however, it's outside what MachO can encode,
// so the assembler falls back to non-scattered relocations.
// rdar://12358909
// CHECK: ('_relocations', [
// CHECK: # Relocation 0
// CHECK: (('word-0', 0x5181034),
// CHECK: ('word-1', 0x4000003)),
// CHECK: # Relocation 1
// CHECK: (('word-0', 0x518102c),
// CHECK: ('word-1', 0x4000003)),
// CHECK: # Relocation 2
// CHECK: (('word-0', 0x5181028),
// CHECK: ('word-1', 0x4000003)),
// CHECK: # Relocation 3
// CHECK: (('word-0', 0x5181020),
// CHECK: ('word-1', 0x4000003)),
// CHECK: ])