bge 0, .LBB0_4
.LBB0_4:
bge 0, .LBB0_5
blr
$ llvm-mc -triple powerpc64le-unknown-unknown --show-encoding ppc-br-test.s
.text
bge 0, .LBB0_4 # encoding: [0bAAAAAA00,A,0x80,0x40]
# fixup A - offset: 0, value: .LBB0_4, kind: fixup_ppc_brcond14
.LBB0_4:
bge 0, .LBB0_5 # encoding: [0bAAAAAA00,A,0x80,0x40]
# fixup A - offset: 0, value: .LBB0_5, kind: fixup_ppc_brcond14
blr # encoding: [0x20,0x00,0x80,0x4e]
Code flow, use PowerPC as our target example:
bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) {
// Create the initial section, if requested.
if (!NoInitialTextSection)
Out.InitSections(false);
...
// While we have input, parse each statement.
while (Lexer.isNot(AsmToken::Eof)) {
ParseStatementInfo Info(&AsmStrRewrites);
if (!parseStatement(Info, nullptr))
continue;
...
// Finalize the output stream if there are no errors and if the client wants
// us to.
if (!HadError && !NoFinalize)
Out.Finish();
return HadError || getContext().hadError();
}
- Out is a MCStreamer
void MCStreamer::Finish() {
..
MCTargetStreamer *TS = getTargetStreamer();
if (TS)
TS->finish();
FinishImpl();
}
bool AsmParser::parseStatement(ParseStatementInfo &Info,
MCAsmParserSemaCallback *SI) {
...
// If parsing succeeded, match the instruction.
if (!ParseHadError) {
uint64_t ErrorInfo;
if (getTargetParser().MatchAndEmitInstruction(
IDLoc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo,
getTargetParser().isParsingInlineAsm()))
bool PPCAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
OperandVector &Operands,
MCStreamer &Out, uint64_t &ErrorInfo,
bool MatchingInlineAsm) {
MCInst Inst;
switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {
case Match_Success:
// Post-process instructions (typically extended mnemonics)
ProcessInstruction(Inst, Operands);
Inst.setLoc(IDLoc);
Out.EmitInstruction(Inst, getSTI());
return false;
- MatchInstructionImpl is automatically generated by llvm TableGen
- If we are Asm-Streamer
void MCAsmStreamer::EmitInstruction(const MCInst &Inst,
const MCSubtargetInfo &STI) {
// Show the encoding in a comment if we have a code emitter.
AddEncodingComment(Inst, STI);
...
if(getTargetStreamer())
getTargetStreamer()->prettyPrintAsm(*InstPrinter, OS, Inst, STI);
else
InstPrinter->printInst(&Inst, OS, "", STI);
void MCAsmStreamer::AddEncodingComment(const MCInst &Inst,
const MCSubtargetInfo &STI) {
...
getAssembler().getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI);
// This show Fixups information
// e.g. # fixup A - offset: 0, value: .LBB0_4, kind: fixup_ppc_brcond14
void PPCMCCodeEmitter::encodeInstruction(
const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
uint64_t Bits = getBinaryCodeForInstr(MI, Fixups, STI);
// Output the constant in big/little endian byte order.
unsigned Size = getInstSizeInBytes(MI);
switch (Size) {
case 0:
break;
case 4:
support::endian::write<uint32_t>(OS, Bits, E);
break;
- getBinaryCodeForInstr: TableGen'erated function
void MCAsmStreamer::FinishImpl() {
... generating dwarf info
}
- If we are ELF-Streamer
void MCObjectStreamer::EmitInstruction(const MCInst &Inst,
const MCSubtargetInfo &STI) {
getAssembler().getBackend().handleCodePaddingInstructionBegin(Inst);
EmitInstructionImpl(Inst, STI);
getAssembler().getBackend().handleCodePaddingInstructionEnd(Inst);
}
void MCObjectStreamer::EmitInstructionImpl(const MCInst &Inst,
const MCSubtargetInfo &STI) {
MCStreamer::EmitInstruction(Inst, STI);
MCSection *Sec = getCurrentSectionOnly();
Sec->setHasInstructions(true);
// Now that a machine instruction has been assembled into this section, make
// a line entry for any .loc directive that has been seen.
MCDwarfLineEntry::Make(this, getCurrentSectionOnly());
// If this instruction doesn't need relaxation, just emit it as data.
MCAssembler &Assembler = getAssembler();
if (!Assembler.getBackend().mayNeedRelaxation(Inst, STI)) {
EmitInstToData(Inst, STI);
return;
}
// Otherwise, relax and emit it as data if either:
// - The RelaxAll flag was passed
// - Bundling is enabled and this instruction is inside a bundle-locked
// group. We want to emit all such instructions into the same data
// fragment.
if (Assembler.getRelaxAll() ||
(Assembler.isBundlingEnabled() && Sec->isBundleLocked())) {
MCInst Relaxed;
getAssembler().getBackend().relaxInstruction(Inst, STI, Relaxed);
while (getAssembler().getBackend().mayNeedRelaxation(Relaxed, STI))
getAssembler().getBackend().relaxInstruction(Relaxed, STI, Relaxed);
EmitInstToData(Relaxed, STI);
return;
}
// Otherwise emit to a separate fragment.
EmitInstToFragment(Inst, STI);
}
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 MCELFStreamer::EmitInstToData(const MCInst &Inst,
const MCSubtargetInfo &STI) {
...
Assembler.getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI);
for (unsigned i = 0, e = Fixups.size(); i != e; ++i)
fixSymbolsInTLSFixups(Fixups[i].getValue());
if (Assembler.isBundlingEnabled()) {
...
}
// Add the fixups and data.
for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
...
}
void MCELFStreamer::FinishImpl() {
// Ensure the last section gets aligned if necessary.
MCSection *CurSection = getCurrentSectionOnly();
setSectionAlignmentForBundling(getAssembler(), CurSection);
finalizeCGProfile();
EmitFrames(nullptr);
this->MCObjectStreamer::FinishImpl();
}
void MCObjectStreamer::FinishImpl() {
...
flushPendingLabels();
resolvePendingFixups();
getAssembler().Finish();
}
class MCObjectStreamer : public MCStreamer {
...
/// If any labels have been emitted but not assigned fragments, ensure that
/// they get assigned, either to F if possible or to a new data fragment.
/// Optionally, it is also possible to provide an offset \p FOffset, which
/// will be used as a symbol offset within the fragment.
void flushPendingLabels(MCFragment *F, uint64_t FOffset = 0);
/// Create a dummy fragment to assign any pending labels.
void flushPendingLabels() { flushPendingLabels(nullptr); }
void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) {
...
for (MCSymbol *Sym : PendingLabels) {
Sym->setFragment(F);
Sym->setOffset(FOffset);
}
PendingLabels.clear();
}
// When fixup's offset is a forward declared label, e.g.:
//
// .reloc 1f, R_MIPS_JALR, foo
// 1: nop
//
// postpone adding it to Fixups vector until the label is defined and its offset
// is known.
void MCObjectStreamer::resolvePendingFixups() {
for (PendingMCFixup &PendingFixup : PendingFixups) {
if (!PendingFixup.Sym || PendingFixup.Sym->isUndefined ()) {
getContext().reportError(PendingFixup.Fixup.getLoc(),
"unresolved relocation offset");
continue;
}
flushPendingLabels(PendingFixup.DF, PendingFixup.DF->getContents().size());
PendingFixup.Fixup.setOffset(PendingFixup.Sym->getOffset());
PendingFixup.DF->getFixups().push_back(PendingFixup.Fixup);
}
PendingFixups.clear();
}
void MCAssembler::Finish() {
// Create the layout object.
MCAsmLayout Layout(*this);
layout(Layout);
// Write the object file.
stats::ObjectBytes += getWriter().writeObject(*this, Layout);
}
void MCAssembler::layout(MCAsmLayout &Layout) {
...
// Finalize the layout, including fragment lowering.
finishLayout(Layout);
...
// Evaluate and apply the fixups, generating relocation entries as necessary.
for (MCSection &Sec : *this) {
for (MCFragment &Frag : Sec) {
...
for (const MCFixup &Fixup : Fixups) {
uint64_t FixedValue;
bool IsResolved;
MCValue Target;
std::tie(Target, FixedValue, IsResolved) =
handleFixup(Layout, Frag, Fixup);
getBackend().applyFixup(*this, Fixup, Target, Contents, FixedValue,
IsResolved, STI);
}
class PPCAsmBackend : public MCAsmBackend {
...
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target, MutableArrayRef<char> Data,
uint64_t Value, bool IsResolved,
const MCSubtargetInfo *STI) const override {
Value = adjustFixupValue(Fixup.getKind(), Value);
if (!Value) return; // Doesn't change encoding.
unsigned Offset = Fixup.getOffset();
unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
// For each byte of the fragment that the fixup touches, mask in the bits
// from the fixup value. The Value has been "split up" into the appropriate
// bitfields above.
for (unsigned i = 0; i != NumBytes; ++i) {
unsigned Idx = Endian == support::little ? i : (NumBytes - 1 - i);
Data[Offset + i] |= uint8_t((Value >> (Idx * 8)) & 0xff);
}
}