【问题标题】:Integer overflow trapping with LLVM?使用 LLVM 进行整数溢出捕获?
【发布时间】:2019-05-16 22:24:29
【问题描述】:

我正在创建一种静态编译的编程语言,并使用 LLVM 作为其后端。我希望我的语言在发生整数溢出时陷入陷阱/崩溃。

我知道llvm.sadd.with.overflow 之类的事情,但我认为这不是最佳/有效的解决方案。该函数返回一个包含两个值的结构,而不是让我直接访问 OF 寄存器标志。理想情况下,在每次算术运算之后,只要发生整数溢出,我就会有一个“JO”汇编指令来捕获。这正是 clang 的 UndefinedBehaviorSanitizer 所做的。但是,我正在编译为 LLVM IR,而不是 C 或 C++。

如何直接在 LLVM IR 中使用 UndefinedBehaviorSanitizer(或完成类似的操作)来处理整数溢出?

【问题讨论】:

    标签: llvm undefined-behavior llvm-ir integer-overflow


    【解决方案1】:

    我知道像 llvm.sadd.with.overflow 这样的事情,但我认为这不是最佳/有效的解决方案。 [...] 理想情况下,在每次算术运算之后,只要发生整数溢出,我就会有一个“JO”汇编指令来捕获。这正是 clang 的 UndefinedBehaviorSanitizer 所做的。

    UndefinedBehaviorSanitizer 所做的是生成对llvm.sadd.with.overflow 的调用。您可以通过使用 -fsanitize=undefined 编译以下 C 程序并查看生成的 LLVM 代码来轻松验证这一点:

    bla.c:

    #include <stdio.h>
    
    int main(void){
      int x;
      scanf("%d", &x);
      printf("%d\n", x+1);
      return 0;
    }
    

    命令行:

    clang -fsanitize=undefined -emit-llvm -O2 -S bla.c
    

    bla.ll(摘录):

      %5 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %4, i32 1), !nosanitize !8
      %6 = extractvalue { i32, i1 } %5, 0, !nosanitize !8
      %7 = extractvalue { i32, i1 } %5, 1, !nosanitize !8
      br i1 %7, label %8, label %10, !prof !9, !nosanitize !8
    
    ; <label>:8:                                      ; preds = %0
      %9 = zext i32 %4 to i64, !nosanitize !8
      call void @__ubsan_handle_add_overflow(i8* bitcast ({ { [6 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }* }* @1 to i8*), i64 %9, i64 1) #5, !nosanitize !8
    

    sadd.with.overflow 将在生成的 x64 程序集中作为常规的 incl 指令¹ 和 br i1 %7 作为 jo 结束,所以这正是您想要的。


    ¹当然,如果我在 C 代码中添加了 1 以外的内容,那将是一个正确的添加指令。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-13
      • 2012-03-14
      • 2011-11-19
      • 1970-01-01
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多