Как измерить количество выполненных инструкций ассемблера?
Я хочу как-то получить "количество выполненных инструкций ассемблера" из двоичного файла. Рассмотрим следующий фрагмент кода:
if(password[0] == 'p') {
if(password[1] == 'a') {
......
printf("Correct Password\n");
}
}
Тогда, если бы я запустил программу, например, с "abc", она не заняла бы первую ветвь, таким образом, она бы выполняла меньше инструкций. Если бы я вставил "pbc", это заняло бы первую ветвь, таким образом, это выполнило бы немного больше (приблизительно 4-5) инструкций. (Это некоторые исследования для файлов CTF (Capture The Flag)). Таким образом, моя идея состоит в том, чтобы вместо обращения двоичного файла и попытки понять алгоритм, я использую более быстрый подход в подсчете количества выполненных инструкций ассемблера для различных установок (таких как разные символы или длины пароля и т. Д., Чтобы увидеть, могу ли я взять другую ветку используя другой вход, таким образом создавая больше инструкций ассемблера).
Моя основная идея состоит в том, чтобы написать простой отладчик, просто поместив int3 после текущей инструкции, увеличить счетчик, дизассемблировать следующую инструкцию и поместить int3 сразу после этой инструкции (сильно упрощенная версия моей идеи).
Есть ли какая-нибудь программа / библиотека /... которая уже сделала это? (Потому что я вижу некоторые проблемы, когда программа имеет дело с сигналами,...)
(Я уже пытался использовать таймеры высокой точности для измерения времени, но это было полным провалом, потому что разница составляет всего 4-5 инструкций)
1 ответ
Linux-инструмент "perf" может использовать аппаратные счетчики производительности, чтобы дать вам точные цифры для многих вещей, включая выполненные инструкции.
$ perf stat true
Performance counter stats for 'true':
0.183734 task-clock # 0.314 CPUs utilized
0 context-switches # 0.000 M/sec
0 CPU-migrations # 0.000 M/sec
118 page-faults # 0.642 M/sec
627,313 cycles # 3.414 GHz
396,604 stalled-cycles-frontend # 63.22% frontend cycles idle
268,222 stalled-cycles-backend # 42.76% backend cycles idle
404,935 instructions # 0.65 insns per cycle
# 0.98 stalled cycles per insn
75,949 branches # 413.364 M/sec
3,602 branch-misses # 4.74% of all branches
0.000584503 seconds time elapsed
Чтобы получить только инструкции в пользовательском режиме:
$ perf stat -e instructions:u true
Performance counter stats for 'true':
92,687 instructions:u # 0.00 insns per cycle
0.000520925 seconds time elapsed
Я вижу небольшую разницу в этом, как, например, 5-6 инструкций. Не уверен, что это реально или просто артефакт измерения. Чтобы получить более надежные результаты, я думаю о переходе на симулятор, такой как Valgrind. Мне посчастливилось получить стабильные числа команд, которые меняются только на 1 инструкцию из этих двух команд:
$ valgrind --tool=callgrind true
$ valgrind --tool=exp-bbv true