[llvm-dev] Usage of the jumptable attribute

CompilerCrash via llvm-dev llvm-dev at lists.llvm.org
Sat Aug 31 00:22:06 PDT 2019


Hello everyone,

I'm new to LLVM (which is a really great project by the way) and I hope 
this is the right place for my question.

In the LLVM Language Reference Manual I found the "jumptable" function 
attribute, which seems to be exactly what I need for my project (where I 
want to add one level of indirection to every function call), but I have 
trouble figuring out, how to use it correctly.

I wrote my own transformation pass (using LLVM 8.0.1) to add this 
attribute as well as unnamed_addr (I'm aware that this might break some 
programs, but jumptable requires it) to every function definition:

     // includes ...

     using namespace llvm;

     namespace {
       struct MyPass : public ModulePass {
         static char ID;
         MyPass() : ModulePass(ID) {}

         bool runOnModule(Module &M) override {
           for (Function &F : M.getFunctionList()) {
             if (!F.isDeclaration()) {
F.setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
               F.addFnAttr(Attribute::JumpTable);
             }
           }
           return true;
         }
       };
     }

     char MyPass::ID = 0;
     static RegisterPass<MyPass> X("mypass", "My Pass");

And I wrote a program test.c:

     #include <stdio.h>

     void foo() {
       puts("Hello World");
     }

     int main() {
       foo();
     }

I compiled it to test.ll and ran it through opt:

     clang -O0 -emit-llvm -S -o test.ll test.c
     build/bin/opt -load build/lib/LLVMMyPass.so -mypass -S -o 
test.out.ll test.ll

The output (test.out.ll) was identical to test.ll except for the 3 
occurrences of jumptable and the last 2 occurrences of unnamed_addr:

     ; ModuleID = 'test.ll'
     source_filename = "test.c"
     target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
     target triple = "x86_64-unknown-linux-gnu"

     @.str = private unnamed_addr constant [12 x i8] c"Hello World\00", 
align 1

     ; Function Attrs: jumptable noinline nounwind optnone uwtable
     define dso_local void @foo() unnamed_addr #0 {
       %1 = call i32 @puts(i8* getelementptr inbounds ([12 x i8], [12 x 
i8]* @.str, i32 0, i32 0))
       ret void
     }

     declare dso_local i32 @puts(i8*) #1

     ; Function Attrs: jumptable noinline nounwind optnone uwtable
     define dso_local i32 @main() unnamed_addr #0 {
       call void @foo()
       ret i32 0
     }

     attributes #0 = { jumptable noinline nounwind optnone uwtable 
"no-jump-tables"="false"
     ; ... many more attributes ...
     }
     attributes #1 = {
     ; ... many more attributes ...
     }

     !llvm.module.flags = !{!0}
     !llvm.ident = !{!1}

     !0 = !{i32 1, !"wchar_size", i32 4}
     !1 = !{!"clang version 8.0.0 (tags/RELEASE_800/final)"}

Finally, I executed:

     build/bin/llc -o test.out.s test.out.ll
     clang -o test.out.native test.out.s
     objdump --disassemble-all test.out.native

I hoped to see some kind of jump table being used for the call to foo 
(maybe even the plt mechanism the dynamic library calls use), but it is 
just a "normal" jump to foo's address:

     0000000000400500 <foo>:
       400500:    55                       push   %rbp
       400501:    48 89 e5                 mov    %rsp,%rbp
       400504:    48 bf c0 05 40 00 00     movabs $0x4005c0,%rdi
       40050b:    00 00 00
       40050e:    e8 cd fe ff ff           callq  4003e0 <puts at plt>
       400513:    5d                       pop    %rbp
       400514:    c3                       retq
       400515:    66 2e 0f 1f 84 00 00     nopw %cs:0x0(%rax,%rax,1)
       40051c:    00 00 00
       40051f:    90                       nop

     0000000000400520 <main>:
       400520:    55                       push   %rbp
       400521:    48 89 e5                 mov    %rsp,%rbp
       400524:    e8 d7 ff ff ff           callq  400500 <foo>
       400529:    31 c0                    xor    %eax,%eax
       40052b:    5d                       pop    %rbp
       40052c:    c3                       retq
       40052d:    0f 1f 00                 nopl   (%rax)

So, what am I doing wrong? The documentation indicates that the jump 
table is created at code-generation time. So I guess my pass works fine 
and I just need to get the code generator to process the jumptable 
attribute somehow? I found the createJumpInstrTablesPass in 
include/CodeGen/Passes.h, but it seems like it's never used.

Thanks in advance

Daniel


More information about the llvm-dev mailing list