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;.
    • MipsTargetELFStreamer class, for ELF object output
      • member: MCStreamer &Streamer;.
  • lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
    • MipsTargetELFStreamer::finish() function. Final step???
  • lib/Target/Mips/MipsTargetObjectFile.h
  • lib/Target/Mips/MipsTargetObjectFile.cpp

MipsTargetStreamer class

Constructor:

MipsTargetStreamer(MCStreamer &S, llvm::Optional<unsigned> CheriCapSize);
  • emitStoreWithImmOffset/SCwithSymOffset()
  • emitLoadWithImmOffset()
  • emitGPRestore()

MipsTargetELFStreamer

Constructor:

MipsTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI);

Global/Section/LD/ST related functions:

  • emitDirectiveCpLoad/CpLocal/CpRestore/Cpsetup/Cpreturn()
  • emitLabel(MCSymbol *Symbol)
  • emitAssignment(MCSymbol *Symbol, const MCExpr *Value)
  • emitFrame(unsigned StackReg, unsigned StackSize, unsigned ReturnReg)

finish():

// lib/Target/MipsMCTargetDesc/MipsTargetStreamer.cpp
finish()
 -> MCObjectFileInfo.get_x_Section() // .text, .data, .bss
 -> MCAssembler.registerSection(_x_) // TextSection, DataSection, BSSSection
 -> MCAssembler.setELFHeaderEFlags(..) // ELF_MIPS_ABI_CHERIABI
 -> MipsELFStreamer.EmitMipsOptionRecords(); // `.Mips.options` section: Streamer->EmitIntValue()....
 -> emitMipsAbiFlags(); //?

finish() is called in MCStreamer::Finish() in lib/MC/MCStreamer.cpp

MCStreamer::Finish()

Finish() -> FinishImpl(), both of them finally call a set of functions as

-> EmitValue() -> EmitZeros() -> finish() -> FinishImpl() is empty.

void MCStreamer::Finish() {
  if ((!DwarfFrameInfos.empty() && !DwarfFrameInfos.back().End) ||
      (!WinFrameInfos.empty() && !WinFrameInfos.back()->End)) {
    getContext().reportError(SMLoc(), "Unfinished frame!");
    return;
  }

  if (!FatRelocs.empty()) {
    MCSection *DefaultRelocSection = Context.getELFSection("__cap_relocs",
        ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
    DefaultRelocSection->setAlignment(llvm::Align(8));
    for (auto &R : FatRelocs) {
      MCSymbol *Sym;
      const MCExpr *Value;
      MCSection *RelocSection;
      StringRef GroupName;

      std::tie(Sym, Value, GroupName) = R;
      if (GroupName != StringRef()) {
        RelocSection =
          Context.getELFSection("__cap_relocs", ELF::SHT_PROGBITS,
                                ELF::SHF_ALLOC | ELF::SHF_GROUP, 0, GroupName);
        RelocSection->setAlignment(llvm::Align(8));
      } else {
        RelocSection = DefaultRelocSection;
      }

      SwitchSection(RelocSection);

      EmitValue(MCSymbolRefExpr::create(Sym, Context), 8);
      if (const MCSymbolRefExpr *Sym = dyn_cast<MCSymbolRefExpr>(Value)) {
        EmitValue(Sym, 8);
        EmitZeros(8);
      } else {
        const MCBinaryExpr *Bin = cast<MCBinaryExpr>(Value);
        EmitValue(cast<MCSymbolRefExpr>(Bin->getLHS()), 8);
        EmitValue(Bin->getRHS(), 8);
      }
      // TODO: Emit size / perms here.
      EmitZeros(16);
    }
  }

  MCTargetStreamer *TS = getTargetStreamer();
  if (TS)
    TS->finish();

  FinishImpl();
}
MipsRegInfoRecord::EmitMipsOptionRecord()
// 
void MipsRegInfoRecord::EmitMipsOptionRecord() {
  MCAssembler &MCA = Streamer->getAssembler();
  MipsTargetStreamer *MTS =
      static_cast<MipsTargetStreamer *>(Streamer->getTargetStreamer());

  Streamer->PushSection();

  // We need to distinguish between N64 and the rest because at the moment
  // we don't emit .Mips.options for other ELFs other than N64.
  // Since .reginfo has the same information as .Mips.options (ODK_REGINFO),
  // we can use the same abstraction (MipsRegInfoRecord class) to handle both.
  if (MTS->getABI().IsN64()) {
    // The EntrySize value of 1 seems strange since the records are neither
    // 1-byte long nor fixed length but it matches the value GAS emits.
    MCSectionELF *Sec =
        Context.getELFSection(".MIPS.options", ELF::SHT_MIPS_OPTIONS,
                              ELF::SHF_ALLOC | ELF::SHF_MIPS_NOSTRIP, 1, "");
    MCA.registerSection(*Sec);
    Sec->setAlignment(llvm::Align(8));
    Streamer->SwitchSection(Sec);

    Streamer->EmitIntValue(ELF::ODK_REGINFO, 1);  // kind
    Streamer->EmitIntValue(40, 1); // size
    Streamer->EmitIntValue(0, 2);  // section
    Streamer->EmitIntValue(0, 4);  // info
    Streamer->EmitIntValue(ri_gprmask, 4);
    Streamer->EmitIntValue(0, 4); // pad
    Streamer->EmitIntValue(ri_cprmask[0], 4);
    Streamer->EmitIntValue(ri_cprmask[1], 4);
    Streamer->EmitIntValue(ri_cprmask[2], 4);
    Streamer->EmitIntValue(ri_cprmask[3], 4);
    Streamer->EmitIntValue(ri_gp_value, 8);
  } else {
    MCSectionELF *Sec = Context.getELFSection(".reginfo", ELF::SHT_MIPS_REGINFO,
                                              ELF::SHF_ALLOC, 24, "");
    MCA.registerSection(*Sec);
    Sec->setAlignment(MTS->getABI().IsN32() ? llvm::Align(8) : llvm::Align(4));
    Streamer->SwitchSection(Sec);

    Streamer->EmitIntValue(ri_gprmask, 4);
    Streamer->EmitIntValue(ri_cprmask[0], 4);
    Streamer->EmitIntValue(ri_cprmask[1], 4);
    Streamer->EmitIntValue(ri_cprmask[2], 4);
    Streamer->EmitIntValue(ri_cprmask[3], 4);
    assert((ri_gp_value & 0xffffffff) == ri_gp_value);
    Streamer->EmitIntValue(ri_gp_value, 4);
  }

  Streamer->PopSection();
}
Steamer->EmitIntValue

MipsELFStreamer Streamer, 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();
}

See more at MCStreamer - MipsELFSteamer::EmitIntValue

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

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

... what would you change?