[llvm-dev] Usage of the jumptable attribute

CompilerCrash via llvm-dev llvm-dev at lists.llvm.org
Wed Sep 4 10:09:27 PDT 2019


Hi Krzysztof,

thank you for your reply. That explains a lot.

I wonder if it is possible to let llvm create plt entries for 
user-written functions as if they were dynamic library functions. Does 
anyone know?

Best

Daniel

Am 04.09.2019 um 15:08 schrieb Krzysztof Parzyszek:
> Hi Daniel,
> This attribute doesn't do anything anymore.  It was added a while back to implement control flow integrity, but that work was eventually removed.  I believe it's still there for backwards compatibility (i.e. to read old bitcode).
>
> --
> Krzysztof Parzyszek  kparzysz at quicinc.com   AI tools development
>
>> -----Original Message-----
>> From: llvm-dev <llvm-dev-bounces at lists.llvm.org> On Behalf Of CompilerCrash
>> via llvm-dev
>> Sent: Saturday, August 31, 2019 2:22 AM
>> To: llvm-dev at lists.llvm.org
>> Subject: [EXT] [llvm-dev] Usage of the jumptable attribute
>>
>> 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
>> _______________________________________________
>> LLVM Developers mailing list
>> llvm-dev at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev


More information about the llvm-dev mailing list