Got stuck with PC-rel branching

Hi all,

I’m trying to make an LLVM backend for the Adapteva’s Epiphany E16 CPU (used in Parallella board), using CPU0 and some other backends as examples, and I’ve got stuck with branching.

When I’m printing out asm, all branch labels are printed as they should be. But when I’m trying to generate obj file, I’m getting zeros instead of PC-related offset in all branch instructions.

In short, what I’m doing:

  • Pattern (br bb:$addr) is selected using as BNONE32(ins jmptarget:$addr), Branch32 class

  • Branch32 class is defined in with bits<24> addr, which should go into bits{31-8} of the MC instruction. Those bits remain zeros after relaxation for some reason.

  • jmptarget operand has type OPERAND_PCREL, and uses EncoderMethod “getJumpTargetOpValue” defined in EpiphanyMCCodeEmitter. If this method gets MCExpr, it creates fixup, and I can see this fixup in debug.

  • Fixup is called fixup_Epiphany_PCREL24, and is defined in EpiphanyFixupKinds and EpiphanyAsmBackend, with FKF_IsPCRel flag.

Can someone please tell me if I am missing something?

The source itself can be found at

Debug output on pastebin:



P.S. sorry for messy code, I knew nothing about LLVM backends when I started, so the code have copy-paste in more than one place.

Are you sure there’s actually a problem? On x86, for example: It looks like the call isn’t calling the right function, but that’s fine: it’ll get fixed by the linker. -Eli


For the function call - yes, probably. But what about branching inside one function (standard if-then for example)?

For example:
echo “int g() { int a = 1; if (a > 3) return 1; return 0; }” | clang -x c - -o /tmp/a.o -c && objdump -d /tmp/a.o



Yes, the assembler tries to avoid emitting relocations for relative offsets within a section. See MCAssembler::layout, particularly the bit at the end where it calls applyFixup().


It is easier to see what happens with objdump -dr :slight_smile:


Big thanks, i’ve managed to find what’s going on. The thing that dumbfolded me a couple of times was that the error was thrown in one of the MCAssembler methods, but never in applyFixup() itself.

Sorry for putting this topic up, but can I ask for your advice once again?
I’m getting some very strange errors and I can’t really understand why. In my applyFixup() I have fixup value adjustment, and for fixup PCREL24 I have the following simple code:

case Epiphany::fixup_Epiphany_PCREL24
Value = Value << 7;


When I’m trying to compile a sample binary (any, even without this fixup type), it “might fail” on MC/ELFObjectWriter.cpp::executePostLayoutBinding():392, which is called from MCAssembler.cpp::layout(). If fails on the following line:

const auto &Alias = cast(A);

“Might fail” - because it doesn’t fail every time. I can change some other completely unrelated piece of code - and suddenly it’ll fail. If I’ll change it to smth else, e.g. Value = Value, it won’t fail, but it still “might fail” after some other change. Sometimes it can fail on different lines, sometimes it can even pass through on the first run and fail on the second.

I’ve checked that it fails because MCSymbol &A has A.Kind different from 2 (SymbolKindELF), usually it’s 1 or 0 (COFF or Unknown).

Why it dumbfolded me heavily is because this code runs before applyFixup(), not after (verified with the debugger), so in general it should not be affected. Changes made can be purely cosmetic, e.g. adding one more debug output.

After running the llc through the debugger, the wrong value is placed while running MCObjectStreamer::flushPendingLabels(), but I failed to find what causes this failure.

Best regards,


This sounds like memory corruption of some sort… have you tried asan and/or valgrind? -Eli

Thanks for telling me to use valgrind, need to be more careful with switches.
It turned out that MCSymbolRefExpr::create() didn’t throw any error regardless of what symbol is actually used for the expression. So, null was able to slip through, causing all kinds of problems, including AsmPrinter writing where it shouldn’t, and MCAssembler going crazy while trying to resolve the symbol.

That’s a bit strange, as there’s an assert that symbol is not null, but for some reason it still let it pass.

Anyway, thanks again, and sorry for asking noobish questions before using all tools available (debugger, memcheck).