RuntimeDyldChecker/jitlink-check Thumb Support

I’m in the process of adding support for relocations in the AArch32 JITLink backend. While writing test cases making use of jitlink-check I noticed that decode_operand() was not able to disassemble Thumb instructions correctly though there is no problem with ARM instructions. I suspect the halfword layout in memory is the cause of it. I’m curious whether jitlink-check which is RuntimeDyldChecker under the hood, does not support Thumb instructions.

The relevant part in the checker:

  bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size,
                  int64_t Offset) const {
    MCDisassembler *Dis = Checker.Disassembler;
    StringRef SymbolMem = Checker.getSymbolContent(Symbol);
    ArrayRef<uint8_t> SymbolBytes(SymbolMem.bytes_begin() + Offset,
                                  SymbolMem.size() - Offset);

    MCDisassembler::DecodeStatus S =
        Dis->getInstruction(Inst, Size, SymbolBytes, 0, nulls());

    return (S == MCDisassembler::Success);
  }

Hi Eymen, thanks for working on this!

I never checked, so there might totally be an issue. Before we start investigating, can you please check this existing test that uses it for Thumb code? Does it reproduce your observation?

RuntimeDyld/ARM/COFF_Thumb.s works without an issue.
My initial suspicion is that the problem might be about the target triple. Rtdyld has no problem as triple is given as argument however jitlink infers the triple.

For example what the rtdyld sees as triple in the test case above is thumbv7-unknown-windows-msvc on this line in llvm-rtdyld driver.
In jitlink, the triple is armv7-- and Thumb is in the subtarget features +aclass,+thumb2,+vfp3,+neon on this line in llvm-jitlink driver.

Here is the test case I’m trying out Thumb with llvm-jitlink:

// RUN: llvm-mc -triple=thumbv7-none-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t.o %s
// RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb -slab-page-size 4096 \
// RUN:               -abs target=0x76bbe880 -show-entry-es -debug-only=llvm_jitlink -check %s %t.o

# Check R_ARM_CALL and R_ARM_JUMP24 relocation handling
 

        .globl target
        .type target, %function
        .globl  main
        .type main,%function
        .p2align  2

main:
        bx lr
        .size   main, .-main

// R_ARM_THM_CALL
        .global call
# jitlink-check: next_pc(call)+ decode_operand(call, 0) + 4 = target
 call:
        bl target
        .size   call, .-call

# R_ARM_THM_JUMP24
        .global jump24
# jitlink-check: next_pc(jump24)+ decode_operand(jump24, 0) + 4 = target
 jump24:
        b target
        .size   jump24, .-jump24

My initial suspicion is that the problem might be about the target triple. Rtdyld has no problem as triple is given as argument however jitlink infers the triple. […] In jitlink, the triple is armv7-- and Thumb is in the subtarget features +aclass,+thumb2,+vfp3,+neon

Yes, the decoding works if we force the triple to thumb. Inferring the triple from the object file always returns arm though and while we do get the +thumb2 feature, the disassembler only checks for the ARM::ModeThumb and not ARM::FeatureThumb2. That all seems on purpose as is.

What about forcing the triple to thumb if we find the +thumb2 feature here?

This fixes the issue for Thumb however Arm triple also emits Thumb2 feature so the disassembly for Arm crashes this time.

Hm interesting. Could you set up a review and we see what other people say?

Or should we add a triple override option to llvm-jitlink?

Sounds good to me, this could simplify testing. I’ll see what I can do and setup a review for it.

1 Like

The LinkGraph tracks whether each symbol is thumb or not, right? Maybe we could plumb that through to the checker? Then it would work for mixed arm / thumb code too.

Eventually, this was implemented with ⚙ D158280 [jitlink/rtdydl][checker] Add TargetFlag dependent disassembler switching support Thanks @Eymay for working on this!!

1 Like