mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-26 21:20:37 +00:00
MC/Mach-O: Implement initial support for relaxation.
- The implementation is currently very brain dead and inefficient, but I have a clear plan on how to fix it. - The good news is, it works and correctly assembles 403.gcc (when built with Clang, at '-Os', '-Os -g', and '-O3'). Even better, at '-Os' and '-Os -g', the resulting binary is exactly equivalent to that when built with the system assembler. So it probably works! :) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@98396 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
5027064c69
commit
f08fde41f3
@ -621,11 +621,19 @@ private:
|
||||
unsigned SubsectionsViaSymbols : 1;
|
||||
|
||||
private:
|
||||
/// Check whether a fixup can be satisfied, or whether it needs to be relaxed
|
||||
/// (increased in size, in order to hold its value correctly).
|
||||
bool FixupNeedsRelaxation(MCAsmFixup &Fixup, MCDataFragment *DF);
|
||||
|
||||
/// LayoutSection - Assign offsets and sizes to the fragments in the section
|
||||
/// \arg SD, and update the section size. The section file offset should
|
||||
/// already have been computed.
|
||||
void LayoutSection(MCSectionData &SD);
|
||||
|
||||
/// LayoutOnce - Perform one layout iteration and return true if any offsets
|
||||
/// were adjusted.
|
||||
bool LayoutOnce();
|
||||
|
||||
// FIXME: Make protected once we factor out object writer classes.
|
||||
public:
|
||||
/// Evaluate a fixup to a relocatable expression and the value which should be
|
||||
|
@ -1275,6 +1275,40 @@ void MCAssembler::Finish() {
|
||||
llvm::errs() << "assembler backend - pre-layout\n--\n";
|
||||
dump(); });
|
||||
|
||||
// Layout until everything fits.
|
||||
while (LayoutOnce())
|
||||
continue;
|
||||
|
||||
DEBUG_WITH_TYPE("mc-dump", {
|
||||
llvm::errs() << "assembler backend - post-layout\n--\n";
|
||||
dump(); });
|
||||
|
||||
// Write the object file.
|
||||
MachObjectWriter MOW(OS);
|
||||
MOW.WriteObject(*this);
|
||||
|
||||
OS.flush();
|
||||
}
|
||||
|
||||
bool MCAssembler::FixupNeedsRelaxation(MCAsmFixup &Fixup, MCDataFragment *DF) {
|
||||
// FIXME: Share layout object.
|
||||
MCAsmLayout Layout(*this);
|
||||
|
||||
// Currently we only need to relax X86::reloc_pcrel_1byte.
|
||||
if (unsigned(Fixup.Kind) != X86::reloc_pcrel_1byte)
|
||||
return false;
|
||||
|
||||
// If we cannot resolve the fixup value, it requires relaxation.
|
||||
MCValue Target;
|
||||
uint64_t Value;
|
||||
if (!EvaluateFixup(Layout, Fixup, DF, Target, Value))
|
||||
return true;
|
||||
|
||||
// Otherwise, relax if the value is too big for a (signed) i8.
|
||||
return int64_t(Value) != int64_t(int8_t(Value));
|
||||
}
|
||||
|
||||
bool MCAssembler::LayoutOnce() {
|
||||
// Layout the concrete sections and fragments.
|
||||
uint64_t Address = 0;
|
||||
MCSectionData *Prev = 0;
|
||||
@ -1316,21 +1350,95 @@ void MCAssembler::Finish() {
|
||||
SD.setAddress(Address);
|
||||
LayoutSection(SD);
|
||||
Address += SD.getSize();
|
||||
|
||||
}
|
||||
|
||||
DEBUG_WITH_TYPE("mc-dump", {
|
||||
llvm::errs() << "assembler backend - post-layout\n--\n";
|
||||
dump(); });
|
||||
// Scan the fixups in order and relax any that don't fit.
|
||||
for (iterator it = begin(), ie = end(); it != ie; ++it) {
|
||||
MCSectionData &SD = *it;
|
||||
|
||||
// Write the object file.
|
||||
MachObjectWriter MOW(OS);
|
||||
MOW.WriteObject(*this);
|
||||
for (MCSectionData::iterator it2 = SD.begin(),
|
||||
ie2 = SD.end(); it2 != ie2; ++it2) {
|
||||
MCDataFragment *DF = dyn_cast<MCDataFragment>(it2);
|
||||
if (!DF)
|
||||
continue;
|
||||
|
||||
OS.flush();
|
||||
for (MCDataFragment::fixup_iterator it3 = DF->fixup_begin(),
|
||||
ie3 = DF->fixup_end(); it3 != ie3; ++it3) {
|
||||
MCAsmFixup &Fixup = *it3;
|
||||
|
||||
// Check whether we need to relax this fixup.
|
||||
if (!FixupNeedsRelaxation(Fixup, DF))
|
||||
continue;
|
||||
|
||||
// Relax the instruction.
|
||||
//
|
||||
// FIXME: This is a huge temporary hack which just looks for x86
|
||||
// branches; the only thing we need to relax on x86 is
|
||||
// 'X86::reloc_pcrel_1byte'. Once we have MCInst fragments, this will be
|
||||
// replaced by a TargetAsmBackend hook (most likely tblgen'd) to relax
|
||||
// an individual MCInst.
|
||||
SmallVectorImpl<char> &C = DF->getContents();
|
||||
uint64_t PrevOffset = Fixup.Offset;
|
||||
unsigned Amt = 0;
|
||||
|
||||
// jcc instructions
|
||||
if (unsigned(C[Fixup.Offset-1]) >= 0x70 &&
|
||||
unsigned(C[Fixup.Offset-1]) <= 0x7f) {
|
||||
C[Fixup.Offset] = C[Fixup.Offset-1] + 0x10;
|
||||
C[Fixup.Offset-1] = char(0x0f);
|
||||
++Fixup.Offset;
|
||||
Amt = 4;
|
||||
|
||||
// jmp rel8
|
||||
} else if (C[Fixup.Offset-1] == char(0xeb)) {
|
||||
C[Fixup.Offset-1] = char(0xe9);
|
||||
Amt = 3;
|
||||
|
||||
} else
|
||||
llvm_unreachable("unknown 1 byte pcrel instruction!");
|
||||
|
||||
Fixup.Value = MCBinaryExpr::Create(
|
||||
MCBinaryExpr::Sub, Fixup.Value,
|
||||
MCConstantExpr::Create(3, getContext()),
|
||||
getContext());
|
||||
C.insert(C.begin() + Fixup.Offset, Amt, char(0));
|
||||
Fixup.Kind = MCFixupKind(X86::reloc_pcrel_4byte);
|
||||
|
||||
// Update the remaining fixups, which have slid.
|
||||
//
|
||||
// FIXME: This is bad for performance, but will be eliminated by the
|
||||
// move to MCInst specific fragments.
|
||||
++it3;
|
||||
for (; it3 != ie3; ++it3)
|
||||
it3->Offset += Amt;
|
||||
|
||||
// Update all the symbols for this fragment, which may have slid.
|
||||
//
|
||||
// FIXME: This is really really bad for performance, but will be
|
||||
// eliminated by the move to MCInst specific fragments.
|
||||
for (MCAssembler::symbol_iterator it = symbol_begin(),
|
||||
ie = symbol_end(); it != ie; ++it) {
|
||||
MCSymbolData &SD = *it;
|
||||
|
||||
if (it->getFragment() != DF)
|
||||
continue;
|
||||
|
||||
if (SD.getOffset() > PrevOffset)
|
||||
SD.setOffset(SD.getOffset() + Amt);
|
||||
}
|
||||
|
||||
// Restart layout.
|
||||
//
|
||||
// FIXME: This is O(N^2), but will be eliminated once we have a smart
|
||||
// MCAsmLayout object.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Debugging methods
|
||||
|
||||
namespace llvm {
|
||||
|
31
test/MC/MachO/relax-jumps.s
Normal file
31
test/MC/MachO/relax-jumps.s
Normal file
@ -0,0 +1,31 @@
|
||||
// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump --dump-section-data | FileCheck %s
|
||||
|
||||
// FIXME: This is a horrible way of checking the output, we need an llvm-mc
|
||||
// based 'otool'. Use:
|
||||
// (f=relax-jumps;
|
||||
// llvm-mc -filetype=obj -o $f.mc.o $f.s &&
|
||||
// as -arch i386 -o $f.as.o $f.s &&
|
||||
// otool -tvr $f.mc.o | tail +2 > $f.mc.dump &&
|
||||
// otool -tvr $f.as.o | tail +2 > $f.as.dump &&
|
||||
// diff $f.{as,mc}.dump)
|
||||
// to examine the results in a more sensible fashion.
|
||||
|
||||
// CHECK: ('_section_data', '\x90
|
||||
// CHECK: \x0f\x842\xff\xff\xff\x0f\x82\xe6\x00\x00\x00\x0f\x87&\xff\xff\xff\x0f\x8f\xda\x00\x00\x00\x0f\x88\x1a\xff\xff\xff\x0f\x83\xce\x00\x00\x00\x0f\x89\x0e\xff\xff\xff\x90
|
||||
// CHECK: \x901\xc0')
|
||||
|
||||
L1:
|
||||
.space 200, 0x90
|
||||
|
||||
je L1
|
||||
jb L2
|
||||
ja L1
|
||||
jg L2
|
||||
js L1
|
||||
jae L2
|
||||
jns L1
|
||||
|
||||
.space 200, 0x90
|
||||
L2:
|
||||
|
||||
xorl %eax, %eax
|
37
test/MC/MachO/relax-recompute-align.s
Normal file
37
test/MC/MachO/relax-recompute-align.s
Normal file
@ -0,0 +1,37 @@
|
||||
// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump --dump-section-data | FileCheck %s
|
||||
|
||||
// FIXME: This is a horrible way of checking the output, we need an llvm-mc
|
||||
// based 'otool'.
|
||||
|
||||
// This is a case where llvm-mc computes a better layout than Darwin 'as'. This
|
||||
// issue is that after the first jmp slides, the .align size must be
|
||||
// recomputed -- otherwise the second jump will appear to be out-of-range for a
|
||||
// 1-byte jump.
|
||||
|
||||
// CHECK: # Section 0
|
||||
// CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
|
||||
// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
|
||||
// CHECK: ('address', 0)
|
||||
// CHECK: ('size', 306)
|
||||
// CHECK: ('offset', 324)
|
||||
// CHECK: ('alignment', 4)
|
||||
// CHECK: ('reloc_offset', 0)
|
||||
// CHECK: ('num_reloc', 0)
|
||||
// CHECK: ('flags', 0x80000400)
|
||||
// CHECK: ('reserved1', 0)
|
||||
// CHECK: ('reserved2', 0)
|
||||
// CHECK: ),
|
||||
|
||||
L0:
|
||||
.space 0x8a, 0x90
|
||||
jmp L0
|
||||
.space (0xb3 - 0x8f), 0x90
|
||||
jle L2
|
||||
.space (0xcd - 0xb5), 0x90
|
||||
.align 4, 0x90
|
||||
L1:
|
||||
.space (0x130 - 0xd0),0x90
|
||||
jl L1
|
||||
L2:
|
||||
|
||||
.zerofill __DATA,__bss,_sym,4,2
|
Loading…
Reference in New Issue
Block a user