The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]



Вариант для распечатки  
Пред. тема | След. тема 
Форум Разговоры, обсуждение новостей
Режим отображения отдельной подветви беседы [ Отслеживать ]

Оглавление

Дэниэл Бернштейн выступил с инициативой создания Си-компилят..., opennews (??), 22-Дек-15, (0) [смотреть все] +1

Сообщения [Сортировка по времени | RSS]


59. "Дэниэл Бернштейн выступил с инициативой создания Си-компилят..."  +/
Сообщение от Аноним (-), 22-Дек-15, 16:30 
> Вы сравниваете теплое с фиолетовым – т.е. выкладки и "инновационные" предложения очередного диванного теоретика, с соображениями вполне известного и уже доказавшего, что он "небалабол" DJB?

Это вещи одного порядка. И если уж вы так любите апеллировать к авторитетам, подумайте, почему в стандарте C вообще (и до сих пор) существуют undefined behavior и unspecified behavior.

> Не Мерседес, а Запорожец, не в лотто а в карты ..." oO

Полностью разделяю ваше восхищение (вашим умением передёргивать).
http://blog.cr.yp.to/20140517-insns.html
Фэйла здесь нет, я о нём и не говорил. Просто те, кому *действительно* нужна защита от timing attacks, находят пути её реализовать[1], для остальных это — пустая потеря производительности (и времени автономной работы от батарей).

[1] https://git.kernel.org/cgit/linux/kernel/git/next/linux-next...

Ответить | Правка | Наверх | Cообщить модератору

71. "Дэниэл Бернштейн выступил с инициативой создания Си-компилят..."  +/
Сообщение от Нимано (?), 22-Дек-15, 17:27 
> Это вещи одного порядка.

Угу, угу.

> Полностью разделяю ваше восхищение (вашим умением передёргивать).

Ну, не все умеют в телепатию.

> . Просто те, кому
> *действительно* нужна защита от timing attacks, находят пути её реализовать[1],

GCC-онляи костыль, в виде повторяющегося OPTIMIZER_HIDE_VAR(neq), для – это да, оптимальнейшее решение!

Ответить | Правка | Наверх | Cообщить модератору

73. "Дэниэл Бернштейн выступил с инициативой создания Си-компилят..."  +2 +/
Сообщение от Аноним (-), 22-Дек-15, 17:51 
>> Это вещи одного порядка.
> Угу, угу.

Угу, угу.

>> Полностью разделяю ваше восхищение (вашим умением передёргивать).
> Ну, не все умеют в телепатию.

А и не надо. Непонятно — переспросите. Только, если бы вы действительно иногда читали блог так рьяно защищаемого вами Бернштейна, вам было бы понятно.

>> . Просто те, кому
>> *действительно* нужна защита от timing attacks, находят пути её реализовать[1],
> GCC-онляи костыль, в виде повторяющегося OPTIMIZER_HIDE_VAR(neq), для – это да,
> оптимальнейшее решение!

1. http://lxr.free-electrons.com/ident?i=OPTIMIZER_HIDE_VAR
Это к вопросу у gcc-only.

2. http://lxr.free-electrons.com/source/include/linux/compiler-...
#define OPTIMIZER_HIDE_VAR(var)                                         \
        __asm__ ("" : "=r" (var) : "" (var))

В отличие от вас, я умею в телепатию. Моя телепатия говорит мне, что вы не знаете, что такое суперскалярный процессор с внеочередным исполнением. Ещё моя телепатия говорит мне, что вы гуманитарий: саркастически называя код __asm__ ("" : "=r" (var) : "" (var)) оптимальнейшим решением, вы вступаете в противоречие с самим собой, так как ранее вставали на сторону Бернштейна в его требовании обеспечить постоянное время выполнения команд сравнения (что, как раз-таки, неоптимально). В отличие от этого требования Бернштейна, конструкция __asm__ ("" : "=r" (var) : "" (var)) действительно оптимальна в том смысле, что является лишь указанием компилятору, не внося дополнительных задержек времени исполнения в сгенерированный код, и весь негативный эффект от её применения — запрет компилятору переупорядочивать в сгенерированном коде команды, зависимость по данным между которыми компилятору неочевидна. Фактически, на этапе выборки команд процессор всё равно может переупорядочить их, хотя это переупорядочивание потенциально гораздо менее опасно, чем то, что мог бы выполнить компилятор.

Ответить | Правка | Наверх | Cообщить модератору

74. "Дэниэл Бернштейн выступил с инициативой создания Си-компилят..."  +1 +/
Сообщение от Аноним (-), 22-Дек-15, 17:59 
> 1. http://lxr.free-electrons.com/ident?i=OPTIMIZER_HIDE_VAR
> Это к вопросу у gcc-only.

О, кстати!

«Расширенный» синтаксис ассемблерных вставок gcc, помимо самого gcc, поддерживают, как минимум, clang, Sun Studio и Intel C Compiler[1].

И компилятор из состава Freescale CodeWarrior[2].

Это всё к вопросу о gcc-only.

[1] https://gcc.gnu.org/ml/gcc/2015-12/msg00124.html
[2] https://gcc.gnu.org/ml/gcc/2015-12/msg00123.html

Ответить | Правка | Наверх | Cообщить модератору

79. "Дэниэл Бернштейн выступил с инициативой создания Си-компилят..."  +/
Сообщение от Владимир (??), 22-Дек-15, 18:23 
Повторю слова автора по ссылке:
Ok, I admit it:  I'm surprised.

Не знал, что кроме шланга еще кто-то в это может.

Ответить | Правка | Наверх | Cообщить модератору

90. "Дэниэл Бернштейн выступил с инициативой создания Си-компилят..."  +/
Сообщение от Нимано (?), 22-Дек-15, 19:02 
> 1. http://lxr.free-electrons.com/ident?i=OPTIMIZER_HIDE_VAR
> Это к вопросу у gcc-only.

И что, это уже не костыль?

> В отличие от вас, я умею в телепатию. Моя телепатия говорит мне,
> что вы не знаете, что такое суперскалярный процессор с внеочередным исполнением.

Ну-ну. О великий просветитель, зачем вы вообще приплели сюда суперскалярность?

> Ещё моя телепатия говорит мне, что вы гуманитарий:

Хоспади, д'Артаньян, Вы?

> вступаете в противоречие с самим собой, так как ранее вставали на
> сторону Бернштейна в его требовании обеспечить постоянное время выполнения команд сравнения

Аноним не читатель?
> consider adding AES support to their instruction
> sets. For example, a CPU could support fast constant-time

для анонимов: специальные комманды под это дело.
И ведь таки потом AES-NI запилили, не?

> том смысле, что является лишь указанием компилятору,

Ну, если побочный эффект – указание, то да.

> запрет компилятору переупорядочивать в сгенерированном коде команды,
> зависимость по данным между которыми компилятору неочевидна.

Н-да, а сколько пафоса то было.

В первую очередь, это запрет на оптимизацию.
Т.к. для конечный пользователь  вызывает crypto_memneq

static inline int crypto_memneq(const void *a, const void *b, size_t size)
{
         return __crypto_memneq(a, b, size) != 0UL ? 1 : 0;
}

> return __crypto_memneq(a, b, size) != 0UL ? 1 : 0;

т.е. получает 0 или 1.

Я не знаю, как конкретно называется используемая техника в гцц, но тa же классическая "abstract interpretation" при первом же проходе засветит только на раз, что:
( как только neq != 0 => нефиг далее маятся дурью, можно делать ret, т.к. ответ более  "не меняется").
А так – там эдакая костыльная вставка на асме,  означающая (на сей момент) для компилятора: "неведомая магия с neq в качестве in/out", оптимизировать низзя.

Разъясняю на пальцах:

> __asm__ ("" : "=r" (var) : "" (var))

Темплейт-то пустой. Просто здесь объявляется, что "neq" идет в in/out, а сам темплейт гцц (пока) не парсится.
А теперь, вопрос на засыпку: что будет, когда гцц/шланг научатся парсить темплейт  – и соответсвенно "узнают" о том, что neq там не применяется?
И чем это лучше UD?

Ответить | Правка | К родителю #73 | Наверх | Cообщить модератору

98. "Дэниэл Бернштейн выступил с инициативой создания Си-компилят..."  +/
Сообщение от Аноним (-), 22-Дек-15, 19:37 
>> 1. http://lxr.free-electrons.com/ident?i=OPTIMIZER_HIDE_VAR
>> Это к вопросу у gcc-only.
> И что, это уже не костыль?

Нет.

>> В отличие от вас, я умею в телепатию. Моя телепатия говорит мне,
>> что вы не знаете, что такое суперскалярный процессор с внеочередным исполнением.
> Ну-ну. О великий просветитель, зачем вы вообще приплели сюда суперскалярность?

Суперскалярный процессор с внеочередным исполнением волен исполнять в произвольном порядке команды, если между ними нет барьеров или зависимостей по данным. Компилятор для суперскалярного процессора с внеочередным исполнением использует это его свойство, самостоятельно, *уже на этапе компиляции* переупорядочивая некоторые команды там, где это может быть выгодно, что потенциально может спровоцировать процессор на ещё одно переупорядочивание во время выполнения (например, из-за различного расстояния до данных, адресуемых a или b, в иерархии кэшей).

Если бы тот код писался для тривиального конвеера, в функции __crypto_memneq_16() не было бы ни одной строки OPTIMIZER_HIDE_VAR(neq);. Задача разработчиков функции — постоянное время её исполнения вне зависимости от входных данных, и часть этой задачи они решают строгим упорядочиванием составляющих эту функцию команд.

>> Ещё моя телепатия говорит мне, что вы гуманитарий:
> Хоспади, д'Артаньян, Вы?

Да.

>> вступаете в противоречие с самим собой, так как ранее вставали на
>> сторону Бернштейна в его требовании обеспечить постоянное время выполнения команд сравнения
> Аноним не читатель?
>> consider adding AES support to their instruction
>> sets. For example, a CPU could support fast constant-time
> для анонимов: специальные комманды под это дело.
> И ведь таки потом AES-NI запилили, не?

Аноним не читатель. Я понятия не имею, зачем вы приплели AES-NI в свой второй пост и повторяете здесь. Речь шла о командах сравнения. AES-NI — не команда сравнения.

>> том смысле, что является лишь указанием компилятору,
> Ну, если побочный эффект – указание, то да.

Указание — единственный эффект этой конструкции.

>> запрет компилятору переупорядочивать в сгенерированном коде команды,
>> зависимость по данным между которыми компилятору неочевидна.
> Н-да, а сколько пафоса то было.
> В первую очередь, это запрет на оптимизацию.

Набор слов.

>[оверквотинг удален]
>> return __crypto_memneq(a, b, size) != 0UL ? 1 : 0;
> т.е. получает 0 или 1.
> Я не знаю, как конкретно называется используемая техника в гцц, но тa
> же классическая "abstract interpretation" при первом же проходе засветит только на
> раз, что:
>  ( как только neq != 0 => нефиг далее маятся дурью,
> можно делать ret, т.к. ответ более  "не меняется").
> А так – там эдакая костыльная вставка на асме,  означающая (на
> сей момент) для компилятора: "неведомая магия с neq в качестве in/out",
> оптимизировать низзя.

Эта вставка вводит фиктивную зависимость по данным между обращениями к neq. Вы правильно поняли часть её назначения: гарантировать, что сгенерированный компилятором код будет в точности, без изъятий соответствовать коду, написанному на C. Это вторая часть решения задачи обеспечения постоянного времени выполнения функции.

Однако ваше опасение справедливо лишь для случаев, когда значения аргументов a и b, а также константные смещения относительно них известны компилятору во время компиляции. На практике, в ядре таких случаев нет. Вы правильно поняли назначение конструкции, но исходите из ошибочной посылки.

> Разъясняю на пальцах:
>> __asm__ ("" : "=r" (var) : "" (var))
> Темплейт-то пустой. Просто здесь объявляется, что "neq" идет в in/out, а сам
> темплейт гцц (пока) не парсится.

Совершенно верно, это фиктивная зависимость по данным. Но предотвращает она не dead code elimination (тогда здесь было бы достаточно спецификатора volatile при объявлении neq), а переупорядочивание выражений друг относительно друга.

> А теперь, вопрос на засыпку: что будет, когда гцц/шланг научатся парсить темплейт
>  – и соответсвенно "узнают" о том, что neq там не
> применяется?
> И чем это лучше UD?

gcc или clang никогда не научатся разбирать содержимое ассемблерных вставок by design. Это контракт. Вопрос не имеет смысла.

Ответить | Правка | Наверх | Cообщить модератору

134. "Дэниэл Бернштейн выступил с инициативой создания Си-компилят..."  +/
Сообщение от Нимано (?), 23-Дек-15, 04:35 
>>  И что, это уже не костыль?
> Нет.

Ну-ну. Особенно приведенный вами вами код.
> __asm__ ("" : "=r" (var) : "" (var))

соберите с ним ядро и наслаждайтесь скоростью (намек: шланг хоть ругается на "invalid constraint", а гцц "кушает" и не обляпывается, генерируя


cmp     rdx, 16
        jne     .L5
        ret

Но ладно, не будем придираться. Просто "некостыльность" обычно несколько иначе выглядит.

>  строгим упорядочиванием составляющих эту функцию команд.

Гм, намекну:
Берем оригинальный код и делаем так:


    unsigned long neq = 0;
    unsigned long tmp1, tmp2;
#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
    if (sizeof(unsigned long) == 8) {
        tmp1 = *(unsigned long *)(a)   ^ *(unsigned long *)(b);
        tmp2 = *(unsigned long *)(a + 8) ^ *(unsigned long *)(b + 8);
        neq |= tmp1;
        OPTIMIZER_HIDE_VAR(neq);        
        neq |= tmp2;
        OPTIMIZER_HIDE_VAR(neq);

Для gcc49 -O2 -DCONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS на выходе у нас будет:

        cmp     rdx, 16
        jne     .L5
        mov     rdx, QWORD PTR [rdi+8]
        xor     rdx, QWORD PTR [rsi+8]
        mov     rax, QWORD PTR [rdi]
        xor     rax, QWORD PTR [rsi]
        or      rax, rdx
        ret

Вот это вам выдаст шланг37 -O2
# BB#1:                                 # %sw.bb
        mov     rax, qword ptr [rsi]
        mov     rcx, qword ptr [rsi + 8]
        xor     rax, qword ptr [rdi]
        xor     rcx, qword ptr [rdi + 8]
        #APP
        #NO_APP
        or      rax, rcx
        #APP
        #NO_APP
        pop     rbp
        ret

ВНЕЗАПНО – и там и там – совершенно неотличимо от оригинала!1
Делаем такой же фокус для ветки else:

        movzx   edx, BYTE PTR [rdi+1]
        movzx   eax, BYTE PTR [rdi]
        xor     dl, BYTE PTR [rsi+1]
        xor     al, BYTE PTR [rsi]
        movzx   edx, dl
        movzx   eax, al
        or      rax, rdx

Опять же, как и ожидалось,  сгенерированный код одинаков в обоих случаях, но и не соответствует порядку "составляющих эту функцию команд".
Да и чего ему соответствовать, когда костыляние OPTIMIZER_HIDE_VAR(var) не дает убрать лишние OR (и заодно "закрепляет" их очередность, да, хотя от этого мало что меняется – вариации в тайминге будут полюбому наамного больше зависить от кэшмисов).


> Указание — единственный эффект этой конструкции.
> Эта вставка вводит фиктивную зависимость по данным между обращениями к neq.

Нет.


neq = neq | expr = (a ^ b);
OPTIMIZER_HIDE_VAR(neq);
neq = neq | expr2 = (a2 ^ b2);

ничто не мешает компилятору вынести expr1,2 и т.д отдельно
Вот это вводит фиктивную зависимость по данным:
 tmp = a ^ b;
OPTIMIZER_HIDE_VAR(neq);
OPTIMIZER_HIDE_VAR(tmp);
neq |= tmp;

Только она там нужна, как рыбе зонтик, ибо еще раз повторюсь – разброс в тайминге из-за кэша будет куда выше, чем из-за очередности выполнения (X)OR r, mem .
А вот преждевременное "or foo,bar; jnz quit" после сравнения первого байта – будет, как бы, очень заметно.

> правильно поняли часть её назначения: гарантировать, что сгенерированный компилятором
> код будет в точности, без изъятий соответствовать коду, написанному на C.

Там, наверху, можно посмотреть на "соответствование".

> Это вторая часть решения задачи обеспечения постоянного времени выполнения функции.

На сферическо-вакуумных суперскалярах – вполне.  А так, см. тайминги для xor/or r/m и "сколько стоит кэшмисс".


> Однако ваше опасение справедливо лишь для случаев, когда значения аргументов a и
> b, а также константные смещения относительно них известны компилятору во время
> компиляции.

Компилятору достаточно того, что любое значение neq !=0 возвращает в итоге единицу.
Это, и зависимость neq от (a xor b) позволяет вообще выкинуть neq и сразу проверять результат XORа.

> Совершенно верно, это фиктивная зависимость по данным. Но предотвращает она не dead
> code elimination (тогда здесь было бы достаточно спецификатора volatile при объявлении
> neq), а переупорядочивание выражений друг относительно друга.

Хоть в ядро бы глянули, что там по этому поводу писали и чего опасались:
https://github.com/torvalds/linux/commit/6bf37e5aa90f18baf5a...
> crypto_memneq is declared noinline, placed in its own source file,
> and compiled with optimizations that might increase code size disabled
> ("Os") because a smart compiler (or LTO) might notice that the return
> value is always compared against zero/nonzero, and might then
> reintroduce the same early-return optimization that we are trying to
> avoid.

https://github.com/torvalds/linux/commit/fe8c8a126806fea4465...

> Instead of disabling compiler optimizations, use a dummy inline assembly
> (based on RELOC_HIDE) to block the problematic kinds of optimization,
> The dummy inline assembly is added after every OR, and has the
> accumulator variable as its input and output. The compiler is forced to
> assume that the dummy inline assembly could both depend on the
> accumulator variable and change the accumulator variable, so it is
> forced to compute the value correctly before the inline assembly, and
> cannot assume anything about its value after the inline assembly.

Хотя, о чем это я – этож опеннет.

> gcc или clang никогда не научатся разбирать содержимое ассемблерных вставок by design.
> Это контракт. Вопрос не имеет смысла.

В вашей вселенной – возможно и контракт. В моей об этом речи нет:
https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Assembl...
Да и ваш "пример" с
>  __asm__ ("" : "=r" (var) : "" (var))

отлично показал "надежность" этого "контракта".


Ответить | Правка | Наверх | Cообщить модератору

Архив | Удалить

Рекомендовать для помещения в FAQ | Индекс форумов | Темы | Пред. тема | След. тема




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру