diff options
author | Daniel Dunbar <daniel@zuster.org> | 2010-03-12 22:07:14 +0000 |
---|---|---|
committer | Daniel Dunbar <daniel@zuster.org> | 2010-03-12 22:07:14 +0000 |
commit | f08fde41f34d739c157b1d75dadbb864e7957cab (patch) | |
tree | c71e2e775d26fa83538ad6c34d1a297234e82e8c /lib/MC/MCAssembler.cpp | |
parent | 5027064c69c89ff605479d9e7eab2395a54b31e9 (diff) |
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
Diffstat (limited to 'lib/MC/MCAssembler.cpp')
-rw-r--r-- | lib/MC/MCAssembler.cpp | 126 |
1 files changed, 117 insertions, 9 deletions
diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index ff930156a0..88be99cffd 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -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,20 +1350,94 @@ 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 |