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.

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::EmitIntValue

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());
}
Created Jul 26, 2020 // Last Updated Aug 16, 2020

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

... what would you change?