References:
MCStreamer
class is an abstract API that is implemented in different ways (e.g. to output a .s file, output an ELF .o file, etc).
It is effectively an “assembler API”.
MCStreamer has one method per directive, such as EmitLabel, EmitSymbolAttribute, SwitchSection, etc, which directly correspond to assembly level directives.
Two implementations of MCStreamer
:
MCAsmStreamer
is a straightforward impl that prints out a directive for each method. (e.g EmitValue -> .byte)MCObjectStreamer
implements a full assembler.For Target specific directives, the MCStreamer
has a MCTargetStreamer
instance.
// 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
MCStreamer emit related functions. A series of EmitXXX
functions
Emit()
EmitIntValue()
EmitLabel()
MCStreamer::EmitBytes()
overridden by child class void MCObjectStreamer::EmitBytes(StringRef Data)
:
// llvm/lib/MC/MCStreamer.cpp
void MCStreamer::EmitBytes(StringRef Data) {} // a virtual method
// llvm/lib/MC/MCObjectStreamer.cpp
void MCObjectStreamer::EmitBytes(StringRef Data) { // override the parent method
MCDwarfLineEntry::Make(this, getCurrentSectionOnly());
MCDataFragment *DF = getOrCreateDataFragment();
flushPendingLabels(DF, DF->getContents().size());
DF->getContents().append(Data.begin(), Data.end());
// EmitBytes might not cover all possible ways we emit data (or could be used
// to emit executable code in some cases), but is the best method we have
// right now for checking this.
MCSection *Sec = getCurrentSectionOnly();
Sec->setHasData(true);
}
Steps:
MCDwarfLineEntry::Make()
: if has dwarf, update dwarf section:
MCObjectStreamer.EmitLabel(LineSym)
MCOS->getContext().getMCDwarfLineTable(MCOS->getContext().getDwarfCompileUnitID()).getMCLineSections().addLineEntry(LineEntry, Section);
DF->getContents().append(data.begin, .end)
hasData
: Sec->setHasData(true)
Method to update a line in dwarf section: MCOS->getContext().getMCDwarfLineTable(MCOS->getContext().getDwarfCompileUnitID())....
Method to update a data section: DF->getContents().append(data.begin, .end)
Most of the EmitInstruction()
implementation should be done by derived classes.
As a method in MCStreamer
, the parent class, it only handle one kind of instruction operand: Relocatable immediate operand. Call visitUsedExpr(MCExpr)
. And this is supposed to be called by the same overloaded method in the child class.
MCStreamer::EmitInstruction()
finally calls visitUsedExpr
to recognize different operand expressions, but did not emit the instruction (opcode + operands) into binary stream.
// llvm/lib/MC/MCStreamer.cpp
void MCStreamer::EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &) {
// Scan for values.
for (unsigned i = Inst.getNumOperands(); i--;)
if (Inst.getOperand(i).isExpr())
visitUsedExpr(*Inst.getOperand(i).getExpr());
}
void MCStreamer::visitUsedExpr(const MCExpr &Expr) {
switch (Expr.getKind()) {
case MCExpr::Target:
// here calls `MipsMCExpr::visitUsedExpr(MCStreamer &)`
// but it finally calls back via Streamer.visitUsedExpr(*getSubExpr())
// `*getSubExpr()` --> the MCExpr used to init the MipsMCExpr instance.
cast<MCTargetExpr>(Expr).visitUsedExpr(*this);
break;
case MCExpr::Constant:
break;
case MCExpr::Binary: {
const MCBinaryExpr &BE = cast<MCBinaryExpr>(Expr);
visitUsedExpr(*BE.getLHS());
visitUsedExpr(*BE.getRHS());
break;
}
case MCExpr::SymbolRef:
visitUsedSymbol(cast<MCSymbolRefExpr>(Expr).getSymbol());
break;
case MCExpr::Unary:
visitUsedExpr(*cast<MCUnaryExpr>(Expr).getSubExpr());
break;
}
}
Inheritance:
MCStreamer (contain an instance of `MCTargetStreamer` as member `TargetStreamer`)
-> MCObjectStreamer
-> MCELFStreamer
-> MipsELFStreamer
To iterate through all the sections in a MCAssember &MCA
:
// Make sections sizes a multiple of the alignment. This is useful for
// verifying the output of IAS against the output of other assemblers but
// it's not necessary to produce a correct object and increases section
// size.
MCStreamer &OS = getStreamer();
for (MCSection &S : MCA) {
MCSectionELF &Section = static_cast<MCSectionELF &>(S);
unsigned Alignment = Section.getAlignment();
if (Alignment) {
OS.SwitchSection(&Section);
if (Section.UseCodeAlign())
OS.EmitCodeAlignment(Alignment, Alignment);
else
OS.EmitValueToAlignment(Alignment, 0, 1, Alignment);
}
}
Reference llvm/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h 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() MCELFStreamer::EmitInstToData() handles how an instruction MCInst is emitted to binary file.
Two implementations of MCStreamer: MCAsmStreamer is a straightforward impl that prints out a directive for each method. (e.g EmitValue -> .byte) MCObjectStreamer implements a full assembler. // 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.
For Target specific directives, the MCStreamer has a MCTargetStreamer instance. // Inheritance relations // 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 MipsTargetStreamer Source code list: lib/Target/Mips/MipsTargetStreamer.h MipsTargetStreamer class MipsTargetAsmStreamer class, for ascii asm output member: MCStreamer &Streamer;.
Two implementations of MCStreamer: MCAsmStreamer is a straightforward impl that prints out a directive for each method. (e.g EmitValue -> .byte) MCObjectStreamer implements a full assembler. // 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.
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?