MCStreamer

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

MCStreamer emit related functions. A series of EmitXXX functions

  • Emit()
  • EmitIntValue()
  • EmitLabel()

MCStreamer::EmitBytes()

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:
    • EmitLabel in MCObjectStreamer.EmitLabel(LineSym)
    • Update the section entries: MCOS->getContext().getMCDwarfLineTable(MCOS->getContext().getDwarfCompileUnitID()).getMCLineSections().addLineEntry(LineEntry, Section);
  • Create a data fragment
  • Append the bytes data to the data fragment DF->getContents().append(data.begin, .end)
  • Update section flagging 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)

MCStreamer::EmitInstruction()

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.

Tracking `MCStreamer::EmitInstruction()`

MipsELFStreamer

Inheritance:

MCStreamer (contain an instance of `MCTargetStreamer` as member `TargetStreamer`)
 -> MCObjectStreamer
    -> MCELFStreamer
       -> MipsELFStreamer

Learnings from source code:

  • 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);
    }
    }
    

  • Mips Elf Streamer
  • 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.

  • MCAsmStreamer
  • 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.

  • Mips Target Streamer
  • 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;.

  • MCObjectStreamer
  • 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.

Created Jul 15, 2020 // Last Updated Aug 16, 2020

If you could revise
the fundmental principles of
computer system design
to improve security...

... what would you change?