Adding fixups and relocations late in code generation

Gang,

I'm tasked with direct object generation for Mips and am trying to not
hack the code.

I how exactly does one set an expression to be PC relative and if the
compiler can resolve it, not produce a relocation?

In our case, the backend produces an expression for the branch which is
the target label. I make a call from the .td for the branch instruction
which calls a routine in MipsMCCodeEmmitter.cpp. That routine

Gang,

I'm tasked with direct object generation for Mips and am trying to not
hack the code.

I how exactly does one set an expression to be PC relative and if the
compiler can resolve it, not produce a relocation?

Fixups are created for all expressions that may need a relocation. The MC layer evaluates them as best it can (MCAssembler::EvaluateFixup()) and calls the target hook RecordRelocation() if it cannot evaluate it directly and needs a relocation in the object file.

In our case, the backend produces an expression for the branch which is
the target label. I make a call from the .td for the branch instruction
which calls a routine in MipsMCCodeEmmitter.cpp. That routine

##############################################################
unsigned MipsMCCodeEmitter::
getBranchTargetOpValue(const MCInst &MI, unsigned OpNo,
       SmallVectorImpl<MCFixup> &Fixups) const {

const MCOperand &MO = MI.getOperand(OpNo);

if (MO.isReg()) {
   unsigned Reg = MO.getReg();

   unsigned RegNo = getMipsRegisterNumbering(Reg);
   return RegNo;

} else if (MO.isImm()) {
   return static_cast<unsigned>(MO.getImm());
} else if (MO.isFPImm()) {
   return static_cast<unsigned>(APFloat(MO.getFPImm())
          .bitcastToAPInt().getHiBits(32).getLimitedValue());
} else if (MO.isExpr()) {
     const MCExpr *p_expr = MO.getExpr();
     Fixups.push_back(MCFixup::Create(0, p_expr,
MCFixupKind(Mips::fixup_Mips_Branch_PCRel)));
}
return 0;
}

############################################

Later in MipsAsmBackend.cpp:ApplyFixup() I find the value is the offset
of the target value from the beginning of the section and not the delta
from the branch address.

I'm not sure I follow. Wouldn't that still require a relocation from the start of the section?

I also get a relocation request even though the label should be
resolved.

The logic for which cases are considered resolved and which require relocations is in MCAssembler::EvaluateFixup(). It's currently not factored all that well, with some target-specific knowledge embedded in the generic code. It's entirely possible we need to create a target hook there to handle any special cases.

Jim,

Both the branch and the branch target are in the same function. This is known delta and should not matter where it is relocated because the delta will remain the same once it is a .o or later.

I just want to know how to tell the compiler that this expression is target offset - branch offset.

More generally, I want to know the rules for setting up expressions in general. I have no idea if one uses post fix, in fix or pre fix. How does one layer different relocations? This will really come in to play for embedded assembler where the gentle user can be as perverse as they want with expressions, resulting with possibly multiple relocations and an immediate for a given instruction operand.

Is expression layering described in the documentation anywhere?

Cheers,

Jack

Jim,

Both the branch and the branch target are in the same function. This is known delta and should not matter where it is relocated because the delta will remain the same once it is a .o or later.

OK. You're likely falling into the case in EvaluateFixup() that contains:
        IsResolved =
          getWriter().IsSymbolRefDifferenceFullyResolvedImpl(*this, DataA,
                                                             *DF, false, true);

Double check that and step through in a debugger and see why it doesn't think the expression is resolved.

I just want to know how to tell the compiler that this expression is target offset - branch offset.

More generally, I want to know the rules for setting up expressions in general. I have no idea if one uses post fix, in fix or pre fix.

What do you mean? An MCExpr is a tree. We generally print the tree using an infix traversal, but that's not related to the representation.

See MCExpr.h and associated files for the details.

How does one layer different relocations? This will really come in to play for embedded assembler where the gentle user can be as perverse as they want with expressions, resulting with possibly multiple relocations and an immediate for a given instruction operand.

This is all going to be very target specific, and is typically handled in the ResolveRelocation() hooks. The x86 backend is probably the best place to look for examples. ARM currently represents fixups in a pretty messed-up way, so I wouldn't look there for this part of things.

Is expression layering described in the documentation anywhere?

Nope. :frowning:

-Jim