Reference
llvm/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp
// Inheritance relations
MCStreamer (contain an instance of `MCTargetStreamer` as member `TargetStreamer`)
-> MCAsmStreamer (final)
-> MCObjectStreamer
-> MCELFStreamer
-> MipsELFStreamer
-> MCWasmStreamer
// MCTargetStreamer for directives.
// llvm/include/llvm/MCStreamer.h
MCTargetStreamer (contain an instance `MCStreamer` as member `Streamer`)
-> ARMTargetStreamer // include/llvm/MCStreamer.h
-> MipsTargetStreamer // lib/Target/Mips/MipsTargetStreamer.h
-> MipsTargetAsmStreamer // lib/Target/Mips/MipsTargetStreamer.h
-> MipsTargetELFStreamer // lib/Target/Mips/MipsTargetStreamer.h
-> RISCVTargetStreamer // lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
MCELFStreamer::EmitInstToData()
handles how an instruction MCInst
is emitted to binary file.
The Call path:
MipsAsmPrinter::EmitInstruction(const MachineInstr *MI)
-> MCInstLowering.Lower(&*I, TmpInst0); // here MachineInstr is lowered to MCInst
-> EmitToStreamer(*OutStreamer, TmpInst0); // here a streamer is called to emit the MCInst
-> MCObjectStreamer::EmitInstruction(MCInst &, MCSubtargetInfo &)
-> MCELFStreamer::EmitInstToData(Inst, STI) // all no-relaxation instructions and some relaxation instructions.
-> MCELFStreamer::EmitInstToFragment(Inst, STI) // for some other relaxiable instructions.
Major steps:
void MCELFStreamer::EmitInstToData(const MCInst &Inst,
const MCSubtargetInfo &STI) {
MCAssembler &Assembler = getAssembler();
SmallVector<MCFixup, 4> Fixups;
SmallString<256> Code;
raw_svector_ostream VecOS(Code);
Assembler.getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI);
// DebugLL("Done encode Instruction by the target: " << VecOS.str() << "\n");
for (unsigned i = 0, e = Fixups.size(); i != e; ++i)
fixSymbolsInTLSFixups(Fixups[i].getValue());
// There are several possibilities here:
//
// If bundling is disabled, append the encoded instruction to the current data
// fragment (or create a new such fragment if the current fragment is not a
// data fragment, or the Subtarget has changed).
//
// If bundling is enabled:
// - If we're not in a bundle-locked group, emit the instruction into a
// fragment of its own. If there are no fixups registered for the
// instruction, emit a MCCompactEncodedInstFragment. Otherwise, emit a
// MCDataFragment.
// - If we're in a bundle-locked group, append the instruction to the current
// data fragment because we want all the instructions in a group to get into
// the same fragment. Be careful not to do that for the first instruction in
// the group, though.
MCDataFragment *DF;
if (Assembler.isBundlingEnabled()) {
DebugLL("Bundling: TODO: check/add support for the ownership emission\n");
MCSection &Sec = *getCurrentSectionOnly();
if (Assembler.getRelaxAll() && isBundleLocked()) {
// If the -mc-relax-all flag is used and we are bundle-locked, we re-use
// the current bundle group.
DF = BundleGroups.back();
CheckBundleSubtargets(DF->getSubtargetInfo(), &STI);
}
else if (Assembler.getRelaxAll() && !isBundleLocked())
// When not in a bundle-locked group and the -mc-relax-all flag is used,
// we create a new temporary fragment which will be later merged into
// the current fragment.
DF = new MCDataFragment();
else if (isBundleLocked() && !Sec.isBundleGroupBeforeFirstInst()) {
// If we are bundle-locked, we re-use the current fragment.
// The bundle-locking directive ensures this is a new data fragment.
DF = cast<MCDataFragment>(getCurrentFragment());
CheckBundleSubtargets(DF->getSubtargetInfo(), &STI);
}
else if (!isBundleLocked() && Fixups.size() == 0) {
// Optimize memory usage by emitting the instruction to a
// MCCompactEncodedInstFragment when not in a bundle-locked group and
// there are no fixups registered.
MCCompactEncodedInstFragment *CEIF = new MCCompactEncodedInstFragment();
insert(CEIF);
CEIF->getContents().append(Code.begin(), Code.end());
CEIF->setHasInstructions(STI);
return;
} else {
DF = new MCDataFragment();
insert(DF);
}
if (Sec.getBundleLockState() == MCSection::BundleLockedAlignToEnd) {
// If this fragment is for a group marked "align_to_end", set a flag
// in the fragment. This can happen after the fragment has already been
// created if there are nested bundle_align groups and an inner one
// is the one marked align_to_end.
DF->setAlignToBundleEnd(true);
}
// We're now emitting an instruction in a bundle group, so this flag has
// to be turned off.
Sec.setBundleGroupBeforeFirstInst(false);
} else {
DF = getOrCreateDataFragment(&STI);
}
// Add the fixups and data.
for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
DF->getFixups().push_back(Fixups[i]);
}
DF->setHasInstructions(STI);
DF->getContents().append(Code.begin(), Code.end());
if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) {
if (!isBundleLocked()) {
mergeFragment(getOrCreateDataFragment(&STI), DF);
delete DF;
}
}
EmitOwnershipToData(Inst, STI);
}
MipsELFStreamer
, defined in lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h
EmitIntValue()
is defined as:
// lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp
void MipsELFStreamer::EmitIntValue(uint64_t Value, unsigned Size) {
MCELFStreamer::EmitIntValue(Value, Size);
Labels.clear();
}
MCELFStreamer::EmitIntValue()
is an inherited methods include/llvm/MC/MCELFStreamer.h
-> include/llvm/MC/MCStreamer.h
, defined in llvm/lib/MC/MCStreamer.cpp
// llvm/lib/MC/MCStreamer.cpp
/// emitIntValue - Special case of EmitValue that avoids the client having to
/// pass in a MCExpr for constant integers.
void MCStreamer::emitIntValue(uint64_t Value, unsigned Size) {
assert(1 <= Size && Size <= 8 && "Invalid size");
assert((isUIntN(8 * Size, Value) || isIntN(8 * Size, Value)) &&
"Invalid size");
char buf[8];
const bool isLittleEndian = Context.getAsmInfo()->isLittleEndian();
for (unsigned i = 0; i != Size; ++i) {
unsigned index = isLittleEndian ? i : (Size - i - 1);
buf[i] = uint8_t(Value >> (index * 8));
}
emitBytes(StringRef(buf, Size));
}
MCStreamer::emitBytes() is implemented in the children classes, such as MCAsmStreamer
, MCObjectStreamer
, ARMELFStreamer
etc.
Here is the MCObjectStreamer impl. (Question: will it update the offset of the current section?)
// llvm/lib/MC/MCObjectStreamer.cpp
void MCObjectStreamer::emitBytes(StringRef Data) {
MCDwarfLineEntry::Make(this, getCurrentSectionOnly());
MCDataFragment *DF = getOrCreateDataFragment();
flushPendingLabels(DF, DF->getContents().size());
DF->getContents().append(Data.begin(), Data.end());
}
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?