Целочисленное переполнение с LLVM? - PullRequest
3 голосов
/ 17 мая 2019

Я создаю статически скомпилированный язык программирования и использую LLVM в качестве бэкэнда.Я хочу, чтобы мой язык прерывался / прерывался всякий раз, когда происходит целочисленное переполнение.

Мне известны такие вещи, как llvm.sadd.with.overflow , но я не думаю, что это оптимально /эффективное решение.Эта функция возвращает структуру из двух значений, а не просто дает мне прямой доступ к флагу регистра OF.В идеале, после каждой арифметической операции у меня должна быть просто инструкция сборки «JO» для перехвата всякий раз, когда происходит целочисленное переполнение.Это именно то, что делает UndefinedBehaviorSanitizer clang .Однако я компилирую в LLVM IR, а не в C или C ++.

Как я могу использовать UndefinedBehaviorSanitizer (или выполнить что-то эквивалентное) для обработки целочисленного переполнения непосредственно в LLVM IR?

1 Ответ

4 голосов
/ 17 мая 2019

Мне известны такие вещи, как llvm.sadd.with.overflow, но я не думаю, что это оптимальное / эффективное решение. [...] В идеале, после каждой арифметической операции у меня должна быть просто инструкция сборки "JO", чтобы перехватывать всякий раз, когда происходит целочисленное переполнение. Это именно то, что делает UndefinedBehaviorSanitizer clang.

Что UndefinedBehaviorSanitizer делает, это генерирует вызовы к llvm.sadd.with.overflow. Вы можете легко это проверить, скомпилировав следующую программу на C с -fsanitize=undefined и просмотрев сгенерированный код 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 закончится как обычная incl инструкция¹, а br i1 %7 как jo в сгенерированной сборке x64, так что это именно то, что вам нужно.


¹ Было бы правильно добавить инструкцию, если бы я добавил что-то, кроме 1, в коде C, конечно.

...