Как указывает ответ Триллиана, AMD K8 и K10 имеют проблему с предсказанием ветвления , когда ret
является целью ветвления или следует условной ветви.
Оптимизация AMD Руководство для K10 (Barcelona) рекомендует 3-байтные ret 0
в тех случаях, которые выталкивают нулевые байты из стека, а также возвращаются. Эта версия значительно хуже, чем rep ret
для Intel. По иронии судьбы, это также хуже, чем rep ret
на более поздних процессорах AMD (Bulldozer и далее). Поэтому хорошо, что никто не изменил использование ret 0
на основе обновления руководства по оптимизации AMD Family 10.
Руководства для процессора предупреждают, что будущие процессоры могут по-разному интерпретировать комбинацию префикса и инструкции, которую он не модифицирует. Это верно в теории, но никто не собирается создавать процессор, который не может запускать много существующих двоичных файлов.
gcc по-прежнему использует rep ret
по умолчанию (без -mtune=intel
или -march=haswell
или что-то еще). Таким образом, у большинства Linux-двоичных файлов есть repz ret
.
gcc, вероятно, перестанет использовать rep ret
через несколько лет, как только K10 будет полностью устаревшим. Спустя еще 5 или 10 лет почти все двоичные файлы будут построены с использованием gcc более новой версии. Еще через 15 лет производитель ЦП может подумать о том, чтобы повторить последовательность байтов f3 c3
как (часть) другой команды.
Все еще будут существовать двоичные файлы с закрытым исходным кодом, использующие rep ret
, которые не будут Однако у вас есть более свежие сборки, и кому-то нужно продолжать работать. Поэтому какая бы новая функция f3 c3 != rep ret
не была частью, должна была бы быть отключена (например, с настройкой BIOS), и эта настройка действительно изменит поведение инструкции-декодера, чтобы распознать f3 c3
как rep ret
. Если эта обратная совместимость для устаревших двоичных файлов невозможна (потому что она не может быть эффективно реализована с точки зрения мощности и транзисторов), IDK, на какой временной шкале вы будете смотреть. Гораздо больше, чем 15 лет, если это не было процессором только для части рынка.
Так что безопасно использовать rep ret
, потому что все остальные уже делают это. Использование ret 0
- плохая идея. В новом коде может еще неплохо использовать rep ret
еще пару лет. Вероятно, не так уж много процессоров AMD PhenomII по-прежнему вокруг, но они достаточно медленны без лишних ошибочных ошибок обратного адреса или проблемы с проблемой.
Стоимость довольно мала. В большинстве случаев он не занимает лишнего места, потому что в любом случае обычно его заполняет nop
. Однако в тех случаях, когда это приводит к дополнительному заполнению, это будет наихудший случай, когда требуется 15 бит заполнения для достижения следующей границы 16B. В этом случае gcc может выравниваться только на 8B. (с .p2align 4,,10;
для выравнивания до 16B, если для этого потребуется 10 или меньше nop-байтов, тогда .p2align 3
всегда будет выровняться с 8B. Используйте gcc -S -o-
для вывода asm-выхода в stdout, чтобы увидеть, когда он это делает.)
Итак, если мы предположим, что один из 16 rep ret
в конечном итоге создает дополнительное дополнение, в котором ret
просто ударил бы нужное выравнивание и что дополнительное заполнение переходит на границу 8B, это означает, что каждый rep
имеет среднюю стоимость 8 * 1/16 = половина байта.
rep ret
не используется достаточно часто, чтобы что-то значило. Например, firefox со всеми библиотеками, которые он отобразил, имеет только ~ 9k экземпляров rep ret
. Так что это около 4k байт, во многих файлах. (И меньше оперативной памяти, чем это, так как многие из этих функций в динамических библиотеках никогда не вызывают.)
# disassemble every shared object mapped by a process.
ffproc=/proc/$(pgrep firefox)/
objdump -d "$ffproc/exe" $(sudo ls -l "$ffproc"/map_files/ |
awk '/\.so/ {print $NF}' | sort -u) |
grep 'repz ret' -c
objdump: '(deleted)': No such file # I forgot to restart firefox after the libexpat security update
9649
Что считается rep ret
во всех функциях во всех библиотеках, которые отображал firefox, а не только функции, которые он когда-либо звонил. Это несколько актуально, потому что более низкая плотность кода по функциям означает, что ваши вызовы распределены по большему количеству страниц памяти. ITLB и L2-TLB имеют ограниченное количество записей. Локальная плотность имеет значение для L1I $ (и uop-cache от Intel). Во всяком случае, rep ret
имеет очень незначительное влияние.
Мне потребовалась минута, чтобы подумать о причине, что /proc/
недоступен для владельца процесса, но /proc/
. Если UID = корневой процесс (например, из двоичного файла suid-root) mmap(2)
sa 0666, который находится в каталоге 0700, то делает setuid(nobody)
, любой, кто работает с этим двоичным файлом, может обойти ограничение доступа, наложенное отсутствием x for other
разрешение на каталог.