Index: llvm/include/llvm/CodeGen/MachineInstr.h =================================================================== --- llvm/include/llvm/CodeGen/MachineInstr.h +++ llvm/include/llvm/CodeGen/MachineInstr.h @@ -683,6 +683,11 @@ return hasProperty(MCID::Call, Type); } + /// Return true if this is an indirect call + bool isIndirectCall(QueryType Type = AnyInBundle) const { + return hasProperty(MCID::IndirectCall, Type); + } + /// Returns true if the specified instruction stops control flow /// from executing the instruction immediately following it. Examples include /// unconditional branches and return instructions. Index: llvm/include/llvm/MC/MCInstrAnalysis.h =================================================================== --- llvm/include/llvm/MC/MCInstrAnalysis.h +++ llvm/include/llvm/MC/MCInstrAnalysis.h @@ -54,6 +54,10 @@ return Info->get(Inst.getOpcode()).isCall(); } + virtual bool isIndirectCall(const MCInst &Inst) const { + return Info->get(Inst.getOpcode()).isIndirectCall(); + } + virtual bool isReturn(const MCInst &Inst) const { return Info->get(Inst.getOpcode()).isReturn(); } Index: llvm/include/llvm/MC/MCInstrDesc.h =================================================================== --- llvm/include/llvm/MC/MCInstrDesc.h +++ llvm/include/llvm/MC/MCInstrDesc.h @@ -168,6 +168,7 @@ Add, Trap, VariadicOpsAreDefs, + IndirectCall, }; } @@ -276,6 +277,9 @@ /// Return true if the instruction is a call. bool isCall() const { return Flags & (1ULL << MCID::Call); } + /// Return true if this is an indirect call + bool isIndirectCall() const { return Flags & (1ULL << MCID::IndirectCall); } + /// Returns true if the specified instruction stops control flow /// from executing the instruction immediately following it. Examples include /// unconditional branches and return instructions. Index: llvm/include/llvm/Target/Target.td =================================================================== --- llvm/include/llvm/Target/Target.td +++ llvm/include/llvm/Target/Target.td @@ -509,6 +509,7 @@ bit isSelect = 0; // Is this instruction a select instruction? bit isBarrier = 0; // Can control flow fall through this instruction? bit isCall = 0; // Is this instruction a call instruction? + bit isIndirectCall = 0; // Is this instruction an indirect call? bit isAdd = 0; // Is this instruction an add instruction? bit isTrap = 0; // Is this instruction a trap instruction? bit canFoldAsLoad = 0; // Can this be folded as a simple memory operand? Index: llvm/lib/Target/X86/X86InstrControl.td =================================================================== --- llvm/lib/Target/X86/X86InstrControl.td +++ llvm/lib/Target/X86/X86InstrControl.td @@ -228,57 +228,60 @@ (outs), (ins i16imm_pcrel:$dst), "call{w}\t$dst", []>, OpSize16, Sched<[WriteJump]>; - def CALL16r : I<0xFF, MRM2r, (outs), (ins GR16:$dst), - "call{w}\t{*}$dst", [(X86call GR16:$dst)]>, - OpSize16, Requires<[Not64BitMode]>, Sched<[WriteJump]>; - def CALL16m : I<0xFF, MRM2m, (outs), (ins i16mem:$dst), - "call{w}\t{*}$dst", [(X86call (loadi16 addr:$dst))]>, - OpSize16, Requires<[Not64BitMode,FavorMemIndirectCall]>, - Sched<[WriteJumpLd]>; - def CALL32r : I<0xFF, MRM2r, (outs), (ins GR32:$dst), - "call{l}\t{*}$dst", [(X86call GR32:$dst)]>, OpSize32, - Requires<[Not64BitMode,NotUseRetpolineIndirectCalls]>, - Sched<[WriteJump]>; - def CALL32m : I<0xFF, MRM2m, (outs), (ins i32mem:$dst), - "call{l}\t{*}$dst", [(X86call (loadi32 addr:$dst))]>, - OpSize32, - Requires<[Not64BitMode,FavorMemIndirectCall, - NotUseRetpolineIndirectCalls]>, - Sched<[WriteJumpLd]>; - - // Non-tracking calls for IBT, use with caution. - let isCodeGenOnly = 1 in { - def CALL16r_NT : I<0xFF, MRM2r, (outs), (ins GR16 : $dst), - "call{w}\t{*}$dst",[(X86NoTrackCall GR16 : $dst)]>, - OpSize16, Requires<[Not64BitMode]>, Sched<[WriteJump]>, NOTRACK; - def CALL16m_NT : I<0xFF, MRM2m, (outs), (ins i16mem : $dst), - "call{w}\t{*}$dst",[(X86NoTrackCall(loadi16 addr : $dst))]>, - OpSize16, Requires<[Not64BitMode,FavorMemIndirectCall]>, - Sched<[WriteJumpLd]>, NOTRACK; - def CALL32r_NT : I<0xFF, MRM2r, (outs), (ins GR32 : $dst), - "call{l}\t{*}$dst",[(X86NoTrackCall GR32 : $dst)]>, - OpSize32, Requires<[Not64BitMode]>, Sched<[WriteJump]>, NOTRACK; - def CALL32m_NT : I<0xFF, MRM2m, (outs), (ins i32mem : $dst), - "call{l}\t{*}$dst",[(X86NoTrackCall(loadi32 addr : $dst))]>, - OpSize32, Requires<[Not64BitMode,FavorMemIndirectCall]>, - Sched<[WriteJumpLd]>, NOTRACK; - } - let Predicates = [Not64BitMode], AsmVariantName = "att" in { - def FARCALL16i : Iseg16<0x9A, RawFrmImm16, (outs), - (ins i16imm:$off, i16imm:$seg), - "lcall{w}\t$seg, $off", []>, - OpSize16, Sched<[WriteJump]>; - def FARCALL32i : Iseg32<0x9A, RawFrmImm16, (outs), - (ins i32imm:$off, i16imm:$seg), - "lcall{l}\t$seg, $off", []>, - OpSize32, Sched<[WriteJump]>; + let isIndirectCall = 1 in { + def CALL16r : I<0xFF, MRM2r, (outs), (ins GR16:$dst), + "call{w}\t{*}$dst", [(X86call GR16:$dst)]>, + OpSize16, Requires<[Not64BitMode]>, Sched<[WriteJump]>; + def CALL16m : I<0xFF, MRM2m, (outs), (ins i16mem:$dst), + "call{w}\t{*}$dst", [(X86call (loadi16 addr:$dst))]>, + OpSize16, Requires<[Not64BitMode,FavorMemIndirectCall]>, + Sched<[WriteJumpLd]>; + def CALL32r : I<0xFF, MRM2r, (outs), (ins GR32:$dst), + "call{l}\t{*}$dst", [(X86call GR32:$dst)]>, OpSize32, + Requires<[Not64BitMode,NotUseRetpolineIndirectCalls]>, + Sched<[WriteJump]>; + def CALL32m : I<0xFF, MRM2m, (outs), (ins i32mem:$dst), + "call{l}\t{*}$dst", [(X86call (loadi32 addr:$dst))]>, + OpSize32, + Requires<[Not64BitMode,FavorMemIndirectCall, + NotUseRetpolineIndirectCalls]>, + Sched<[WriteJumpLd]>; + + // Non-tracking calls for IBT, use with caution. + let isCodeGenOnly = 1 in { + def CALL16r_NT : I<0xFF, MRM2r, (outs), (ins GR16 : $dst), + "call{w}\t{*}$dst",[(X86NoTrackCall GR16 : $dst)]>, + OpSize16, Requires<[Not64BitMode]>, Sched<[WriteJump]>, NOTRACK; + def CALL16m_NT : I<0xFF, MRM2m, (outs), (ins i16mem : $dst), + "call{w}\t{*}$dst",[(X86NoTrackCall(loadi16 addr : $dst))]>, + OpSize16, Requires<[Not64BitMode,FavorMemIndirectCall]>, + Sched<[WriteJumpLd]>, NOTRACK; + def CALL32r_NT : I<0xFF, MRM2r, (outs), (ins GR32 : $dst), + "call{l}\t{*}$dst",[(X86NoTrackCall GR32 : $dst)]>, + OpSize32, Requires<[Not64BitMode]>, Sched<[WriteJump]>, NOTRACK; + def CALL32m_NT : I<0xFF, MRM2m, (outs), (ins i32mem : $dst), + "call{l}\t{*}$dst",[(X86NoTrackCall(loadi32 addr : $dst))]>, + OpSize32, Requires<[Not64BitMode,FavorMemIndirectCall]>, + Sched<[WriteJumpLd]>, NOTRACK; + } + + let Predicates = [Not64BitMode], AsmVariantName = "att" in { + def FARCALL16i : Iseg16<0x9A, RawFrmImm16, (outs), + (ins i16imm:$off, i16imm:$seg), + "lcall{w}\t$seg, $off", []>, + OpSize16, Sched<[WriteJump]>; + def FARCALL32i : Iseg32<0x9A, RawFrmImm16, (outs), + (ins i32imm:$off, i16imm:$seg), + "lcall{l}\t$seg, $off", []>, + OpSize32, Sched<[WriteJump]>; + } + + def FARCALL16m : I<0xFF, MRM3m, (outs), (ins opaquemem:$dst), + "lcall{w}\t{*}$dst", []>, OpSize16, Sched<[WriteJumpLd]>; + def FARCALL32m : I<0xFF, MRM3m, (outs), (ins opaquemem:$dst), + "{l}call{l}\t{*}$dst", []>, OpSize32, Sched<[WriteJumpLd]>; } - - def FARCALL16m : I<0xFF, MRM3m, (outs), (ins opaquemem:$dst), - "lcall{w}\t{*}$dst", []>, OpSize16, Sched<[WriteJumpLd]>; - def FARCALL32m : I<0xFF, MRM3m, (outs), (ins opaquemem:$dst), - "{l}call{l}\t{*}$dst", []>, OpSize32, Sched<[WriteJumpLd]>; } @@ -331,25 +334,26 @@ (outs), (ins i64i32imm_pcrel:$dst), "call{q}\t$dst", []>, OpSize32, Requires<[In64BitMode]>; - def CALL64r : I<0xFF, MRM2r, (outs), (ins GR64:$dst), - "call{q}\t{*}$dst", [(X86call GR64:$dst)]>, - Requires<[In64BitMode,NotUseRetpolineIndirectCalls]>; - def CALL64m : I<0xFF, MRM2m, (outs), (ins i64mem:$dst), - "call{q}\t{*}$dst", [(X86call (loadi64 addr:$dst))]>, - Requires<[In64BitMode,FavorMemIndirectCall, - NotUseRetpolineIndirectCalls]>; - - // Non-tracking calls for IBT, use with caution. - let isCodeGenOnly = 1 in { - def CALL64r_NT : I<0xFF, MRM2r, (outs), (ins GR64 : $dst), - "call{q}\t{*}$dst",[(X86NoTrackCall GR64 : $dst)]>, - Requires<[In64BitMode]>, NOTRACK; - def CALL64m_NT : I<0xFF, MRM2m, (outs), (ins i64mem : $dst), - "call{q}\t{*}$dst", - [(X86NoTrackCall(loadi64 addr : $dst))]>, - Requires<[In64BitMode,FavorMemIndirectCall]>, NOTRACK; - } + let isIndirectCall = 1 in { + def CALL64r : I<0xFF, MRM2r, (outs), (ins GR64:$dst), + "call{q}\t{*}$dst", [(X86call GR64:$dst)]>, + Requires<[In64BitMode,NotUseRetpolineIndirectCalls]>; + def CALL64m : I<0xFF, MRM2m, (outs), (ins i64mem:$dst), + "call{q}\t{*}$dst", [(X86call (loadi64 addr:$dst))]>, + Requires<[In64BitMode,FavorMemIndirectCall, + NotUseRetpolineIndirectCalls]>; + // Non-tracking calls for IBT, use with caution. + let isCodeGenOnly = 1 in { + def CALL64r_NT : I<0xFF, MRM2r, (outs), (ins GR64 : $dst), + "call{q}\t{*}$dst",[(X86NoTrackCall GR64 : $dst)]>, + Requires<[In64BitMode]>, NOTRACK; + def CALL64m_NT : I<0xFF, MRM2m, (outs), (ins i64mem : $dst), + "call{q}\t{*}$dst", + [(X86NoTrackCall(loadi64 addr : $dst))]>, + Requires<[In64BitMode,FavorMemIndirectCall]>, NOTRACK; + } + } def FARCALL64 : RI<0xFF, MRM3m, (outs), (ins opaquemem:$dst), "lcall{q}\t{*}$dst", []>; } Index: llvm/tools/llvm-objdump/llvm-objdump.cpp =================================================================== --- llvm/tools/llvm-objdump/llvm-objdump.cpp +++ llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -337,6 +337,12 @@ static cl::extrahelp HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); +cl::opt + PrintTargetAddress("print-tgt-addr", + cl::desc("Print target address instead of immediate " + "value in pc-rel branches and calls"), + cl::cat(ObjdumpCat)); + static StringSet<> DisasmFuncsSet; static StringSet<> FoundSectionSet; static StringRef ToolName; @@ -671,14 +677,14 @@ } static void printRelocation(StringRef FileName, const RelocationRef &Rel, - uint64_t Address, bool Is64Bits) { + uint64_t Address, bool Is64Bits, raw_ostream &OS) { StringRef Fmt = Is64Bits ? "\t\t%016" PRIx64 ": " : "\t\t\t%08" PRIx64 ": "; SmallString<16> Name; SmallString<32> Val; Rel.getTypeName(Name); if (Error E = getRelocationValueString(Rel, Val)) reportError(std::move(E), FileName); - outs() << format(Fmt.data(), Address) << Name << "\t" << Val << "\n"; + OS << format(Fmt.data(), Address) << Name << "\t" << Val << "\n"; } class PrettyPrinter { @@ -761,7 +767,7 @@ auto PrintReloc = [&]() -> void { while ((RelCur != RelEnd) && (RelCur->getOffset() <= Address.Address)) { if (RelCur->getOffset() == Address.Address) { - printRelocation(ObjectFilename, *RelCur, Address.Address, false); + printRelocation(ObjectFilename, *RelCur, Address.Address, false, OS); return; } ++RelCur; @@ -1412,24 +1418,27 @@ // Disassemble a real instruction or a data when disassemble all is // provided MCInst Inst; + SmallString<90> InstPrinterBuffer; + raw_svector_ostream InstPrintStream(InstPrinterBuffer); bool Disassembled = DisAsm->getInstruction( Inst, Size, Bytes.slice(Index), SectionAddr + Index, DebugOut, CommentStream); if (Size == 0) Size = 1; - PIP.printInst(*IP, Disassembled ? &Inst : nullptr, - Bytes.slice(Index, Size), - {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, - outs(), "", *STI, &SP, Obj->getFileName(), &Rels); - outs() << CommentStream.str(); - Comments.clear(); + PIP.printInst( + *IP, Disassembled ? &Inst : nullptr, Bytes.slice(Index, Size), + {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, + InstPrintStream, "", *STI, &SP, Obj->getFileName(), &Rels); // Try to resolve the target of a call, tail call, etc. to a specific // symbol. - if (MIA && (MIA->isCall(Inst) || MIA->isUnconditionalBranch(Inst) || + if (MIA && ((MIA->isCall(Inst) && !MIA->isIndirectCall(Inst)) || + MIA->isUnconditionalBranch(Inst) || MIA->isConditionalBranch(Inst))) { uint64_t Target; + SmallString<50> TargetSymbolDetails; + raw_svector_ostream SymbolDetailsStream(TargetSymbolDetails); if (MIA->evaluateBranch(Inst, SectionAddr + Index, Size, Target)) { // In a relocatable object, the target's section must reside in // the same section as the call instruction or it is accessed @@ -1473,14 +1482,28 @@ --TargetSym; uint64_t TargetAddress = std::get<0>(*TargetSym); StringRef TargetName = std::get<1>(*TargetSym); - outs() << " <" << TargetName; + SymbolDetailsStream << " <" << TargetName; uint64_t Disp = Target - TargetAddress; if (Disp) - outs() << "+0x" << Twine::utohexstr(Disp); - outs() << '>'; + SymbolDetailsStream << "+0x" << Twine::utohexstr(Disp); + SymbolDetailsStream << '>'; } } + if (PrintTargetAddress) { + auto splitInstStream = InstPrintStream.str().rsplit('\t'); + outs() << splitInstStream.first << '\t' << Twine::utohexstr(Target) + << CommentStream.str() << SymbolDetailsStream.str(); + } else { + outs() << InstPrintStream.str() << CommentStream.str() + << SymbolDetailsStream.str(); + } + TargetSymbolDetails.clear(); + } else { + outs() << InstPrintStream.str() << CommentStream.str(); } + + Comments.clear(); + InstPrinterBuffer.clear(); outs() << "\n"; // Hexagon does this in pretty printer @@ -1508,7 +1531,7 @@ } printRelocation(Obj->getFileName(), *RelCur, SectionAddr + Offset, - Is64Bits); + Is64Bits, outs()); ++RelCur; } } Index: llvm/utils/TableGen/CodeGenInstruction.h =================================================================== --- llvm/utils/TableGen/CodeGenInstruction.h +++ llvm/utils/TableGen/CodeGenInstruction.h @@ -244,6 +244,7 @@ bool isSelect : 1; bool isBarrier : 1; bool isCall : 1; + bool isIndirectCall : 1; bool isAdd : 1; bool isTrap : 1; bool canFoldAsLoad : 1; Index: llvm/utils/TableGen/CodeGenInstruction.cpp =================================================================== --- llvm/utils/TableGen/CodeGenInstruction.cpp +++ llvm/utils/TableGen/CodeGenInstruction.cpp @@ -375,6 +375,7 @@ isSelect = R->getValueAsBit("isSelect"); isBarrier = R->getValueAsBit("isBarrier"); isCall = R->getValueAsBit("isCall"); + isIndirectCall = R->getValueAsBit("isIndirectCall"); isAdd = R->getValueAsBit("isAdd"); isTrap = R->getValueAsBit("isTrap"); canFoldAsLoad = R->getValueAsBit("canFoldAsLoad"); Index: llvm/utils/TableGen/InstrDocsEmitter.cpp =================================================================== --- llvm/utils/TableGen/InstrDocsEmitter.cpp +++ llvm/utils/TableGen/InstrDocsEmitter.cpp @@ -108,6 +108,7 @@ FLAG(isSelect) FLAG(isBarrier) FLAG(isCall) + FLAG(isIndirectCall) FLAG(isAdd) FLAG(isTrap) FLAG(canFoldAsLoad) Index: llvm/utils/TableGen/InstrInfoEmitter.cpp =================================================================== --- llvm/utils/TableGen/InstrInfoEmitter.cpp +++ llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -678,6 +678,7 @@ if (Inst.isBarrier) OS << "|(1ULL<