Няшная / Говнокод #24383 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
void trampoline(void (*func)(void), bool flag)
{
    if (flag)
        func();
    else
        trampoline(func, true);
}

int 
main(int argc, char *argv[])
{
    /*... */
    trampoline(set_aes_keys, false);
}

Зачем так? ЯННП.

Запостил: codemonkey codemonkey, (Updated )

Комментарии (80) RSS

    • function trampoline($func, $flag)
      {
          if ($flag)
              $func();
          else
              trampoline($func, true);
      }
      
          /*... */
          trampoline("set_aes_keys", false);
      Ответить
      • <?php
        
        function trampoline($func, $flag)
        {
            if ($flag)
                $func();
            else
                trampoline($func, true);
        }
        
        /*... */
        trampoline("set_aes_keys", false);
        trampoline("set_aes_keys", true);
        
        function set_aes_keys()
        {
            var_dump(sizeof(debug_backtrace()));
        }
        Ответить
  • Защита от инлайна какая-нибудь?

    З.Ы. А у этого трамплина только одна реализация? Или есть какая-то другая под #ifdef'ом?
    Ответить
    • Да, очень похоже, что условие вставили, чтобы оптимизатор сразу не сократил вызовы функций. А вызываем с аргументом false, чтобы ещё усложнить работу оптимизатора (в надежде, что так много шагов он не делает, он ведь не будет трассировать всю программу).

      Остаётся открытым вопрос, для чего нам нужен этот трамплин, почему напрямую нельзя. Вызываемая функция использует какие-нибудь "грязные" методы типа вычисления адреса стека?
      Ответить
      • Дождёмся перевода на "PHP", а там глядишь и прояснится
        Ответить
      • >Вызываемая функция использует какие-нибудь "грязные" методы типа вычисления адреса стека?

        Там хуйня типа:
        char buf[SOME_BYTES] = { 0 };
        int fd = open("/dev/urandom", O_RDONLY);
        read(fd, buf, SOME_BYTES);
        close(fd);
        
        for (i = 0; i < SOME_BYTES; i++)
            key[i] ^= buf[i];
        
        fwrite(some_faggot_file, 1, SOME_BYTES, buf);


        Смысл трамплина остаётся неясным.
        Ответить
        • как это может помочь защишщиться от Meltdown?

          Meltdown это когда ты тренишь предиктор чтобы он выполнил левый код, который считает данные в кеш, и потом замеряешь скорость чтения с кеша
          Ответить
    • ХЗ. Кресты-аналог с г++ -О2 выдают:

      func_trampoline(poo_in_loo);
       33b:   be 00 00 00 00          mov    $0x0,%esi
       340:   bf 00 00 00 00          mov    $0x0,%edi
                              341: R_X86_64_32        _Z10poo_in_loo2v
       345:   e8 00 00 00 00          callq  34a <_Z13some_other_crapv+0x123>
                              346: R_X86_64_PC32      _Z15func_trampolinePFvvEb-0x4
      }
       34a:   c9                      leaveq


      Типа кококо-защита от реверсинга, но похоже что хуита.

      >З.Ы. А у этого трамплина только одна реализация? Или есть какая-то другая под #ifdef'ом?
      Только одна.

      Тащемта, похоже что ЭТО надо выжечь калёным железом.
      Ответить
      • Тут коконпелятор убрал ветвление, но сохранил вызов. А если бы ветвления вообще не было, он мог бы заменить вызов инлайном.
        Ответить
          • Так ведь по глубине стека можно вычислить, с каким ключом оптимизации был вызван компилятор.
            Ответить
        • чтобы компилятор не инлайнил функцию есть noinline и аналоги
          Ответить
          • Зачем может понадобиться запрет инлайна функции?
            Ответить
            • Бинарник сильно пухнет в размере.

              ps что с гк творится? почему 500е постоянно?
              неужели задрочили самопальными приблудами и бесконечными стоками?
              Ответить
              • > что с гк творится
                Сам токошто гневный комент пейсал, так ГКшный эксепшен его скушал.
                Ответить
              • Пиздец, это сколько нужно написать вызовов функции, чтобы бинарник заметно распух?
                Ответить
                • Нужно иметь две версии программы: без инлайна (оптимизирована по размеру текста) и с и инлайном (оптимизирована по скорости).

                  Так учил Фредерик Брукс в 1963 г.
                  Ответить
                  • Тем не менее, это не ответ на мой вопрос
                    Ответить
              • Пиздец, это сколько нужно написать вызовов функции, чтобы бинарник заметно распух?
                Ответить
      • Простите мне мою необразованность, но если там есть leave то это не значит-ли что где-то сверху должен быть enter?
        Ответить
        • Вместо enter может лежать пара инструкций:
          push ebp
          mov ebp, esp


          leave в свою очередь является аналогом такого кода:
          mov esp, ebp
          pop ebp


          Есть даже срачи на тему, что работает быстрее. Это примерно как inc eax и add eax, 1 или lea eax, [eax+1].
          Ответить
          • Так enter сохранял frame pointer и всё?

            Вангую что в темные века между 386 (когда стало можно адресоваться по sp) и, примерно, 2006 годом, им никто не пользовался ибо frame pointer omition
            Ответить
            • Порядка не было. В одной и той же библиотеки у половины функций могло быть frame pointer omition, у другой половины всё же копия sp сохранялась в bp (ну чтобы внутри функции можно было невозбранно использовать push/pop, не теряя указатель на локальные переменные и на аргументы функции). Frame pointer omition было популярно у функций без локальных переменных, принимающих аргументы через регистры, а не через стек, и у совсем коротеньких функций (которые свою работу делегировали другим функциям, типа как трамплин из этого ГК).

              Причём компилятор мог генерировать непарные enter/leave. Легко могло быть push bp; mov bp, sp + leave или enter + pop bp (ага, mov sp, bp компилятор мог пропустить, если был "уверен", что никто не портит стек).
              Ответить
              • > не теряя указатель на локальные переменные
                Ой да ладно, конпелятору не так уж и сложно трекать сколько байт он наклал на стек... Единственный случай, где FPO реально не заюзать -- функция с alloca.

                З.Ы. А в 16-битном коде об SP нельзя было адресоваться, так что там BP без вариантов и никакого FPO.
                Ответить
                • Я упустил из виду, что в 16-битном режиме доступна только адресация вида [BX+SI], [BX+DI], [BP+SI], [BP+DI], [SI], [DI], [BP], [ВХ], а в 32-битном и в 64-битном [EAX], [ECX], [EDX], [EBX], [EBP], [ESI], [EDI] плюс s-i-b (в котором можно составлять пары из перечисленных регистров).

                  А где-то можно адресоваться через SP?
                  Ответить
                  • Через esp/rsp -- можно. Через sp -- нет.

                    З.Ы. Разве что въебать 67h, нагло заюзать [esp] прямо из 16-битного кода и молиться, чтобы никто не насрал в старшую половину esp. Всё равно чистых 8086 в природе уже нет.
                    Ответить
                    • Всё, нашёл. В "s-i-b" можно использовать esp/rsp, но только в качестве базы (в качестве индекса с множителем -- нельзя). В "mod R/M" esp/rsp нет.

                      А старшую половину esp можно обнулить. Безо всякой зелени. Видел 16-битные библиотеки, оптимизированные под 386. В них использовались префиксы 66h и 67h, чтобы воспользоваться новыми плюшками, находясь в 16-битном сегменте. И там как раз приходилось инициализировать старшие половинки регистров.
                      Ответить
                      • > Безо всякой зелени.
                        На некоторых прошивках видно, что после вызова "реалмодного" прерывания меняется IDTR. Т.е. CSM иногда зачем-то бегает в защищёнку и есть риск, что он и старшие части регистров хуёво сохранит и помнёт.

                        Нахуй и в пизду, короче. Разве что под CLI и с обнулением прямо перед использованием...
                        Ответить
                • >> конпелятору не так уж
                  именно тем и руководствовались питухи, когда выпиливали frame pointer.
                  А потом без символов стек не прочитать

                  >>А в 16-битном коде об SP нельзя было адресоваться,
                  даже на совр. процах?
                  Ответить
                  • Гугли mod R/M.

                    Косвенная адресация использует либо байт mod R/M, либо s-i-b. В mod R/M нет варианта [SP]. Даже в 32-битном и в 64-битном режиме нет варианта [ESP]/[RSP]. А s-i-b, в котором есть [ESP]/[RSP] в 16-битном варианте недоступен.

                    Отдельной инструкции, использующей [SP], в сетке команд нет.

                    Единственный способ адресоваться в 16-битном коде об SP, это использовать префикс размера адреса. Т. е. писать mov ax, word ptr [esp] вместо mov ax, word ptr [sp], предварительно обнулив старшую половинку регистра esp, чтобы в ней не было мусора. А об этом уже написал bormand: придётся оборачивать код в CLI/STI, чтобы какой-нибудь обработчик прерывания не засрал старшую половину регистра.
                    Ответить
            • Офтопик. Нашёл на просторах интернетов задний конец для "gcc", генерирующий 16-битный код для 8086. А кто-нибудь пытался написать задний конец для 8008 или для 4040, чтобы был полный хардкор?
              Ответить
                • Под однобитный процессор.

                  З.Ы. Лол, оказывается даже суперкомпьютер с 65536 однобитных процессоров был...
                  Ответить
                      • Промышленный контроллер, чтобы всякие моторы и лампочки включать по сигналам от кнопок и датчиков.

                        Там для большинства задач даже переходы нинужны были. Команды тупо исполнялись по кругу. Зато инженерам не надо было учиться программировать, они брали схему на реле и дословно переносили её на асм этого контроллера.
                        Ответить
                        • Для чего-нибудь типа светофора?
                          Ответить
                          • Скорее для какого-нибудь лифта. Светофор то и на обычной логике легко запиливается.
                            Ответить
                  • Следующим шагом предлагаю писать под защелку, а еще лучше под транзистор, а еще лучше сразу под лампу или даже под реле
                    Ответить
                    • Писать под реле не советую, особенно если оно коммутирует цепь высокого напряжения.
                      Ответить
                  • Ну, это уже для пользователя конпеляторва хардкрор, а вот если задний конец под malbolge -- хардкор для разработчика.
                    Ответить
        • ... только правда недоконца выпилил. Кто-нибудь знает что такое этот их
          [clone .constprop.0]

          ?
          Ответить
          • Попытаемся предположить: это версия функции с уже применёнными аргументами. Т. е. компилятор упростил вызов trampoline(set_aes_keys, false), потому что его можно упростить ещё на этапе компиляции, и обозвал это новой функцией.

            Что-то вроде частичного применения.
            Ответить
            • Похожее гуглится по фразе "constprop clones".

              Ну почему нет частичного применения на уровне языка?
              Ответить
            • Обидно, что в режиме оптимизации компилятор это умеет, а на уровне языка средств для этого нет. Хотелось бы явно получать что-то типа такого:
              trampoline_1(func) = trampoline(func, false);
              trampoline_2(flag) = trampoline(set_aes_keys, flag);
              trampoline_3() = trampoline(set_aes_keys, false);
              Чтобы генерацией функцией-клонов можно было управлять и чтобы клоны можно было использовать самостоятельно.
              Ответить
              • Хотя в принципе уже можно: тело функции-клона составить из единственного вызова:
                void trampoline_1(void (*func)(void)) {
                    trampoline(func, false);
                }
                void trampoline_2(bool flag) {
                    trampoline(set_aes_keys, flag);
                }
                void trampoline_3(void) {
                    trampoline(set_aes_keys, false);
                }
                Ответить
    • >>Защита от инлайна какая-нибудь?
      неужто нет ключ слова у копелятора?

      >>З.Ы. А у этого трамплина только одна реализация?
      конечно, есть еще и такая

      void trampoline(void (*func)(void), bool flag)
      {
      if (flag)
      func();
      else
      trampoline(func, false);
      }

      ахахахахах
      Ответить
  • typedef void (*callback_t)(void (*func)(void), void *callback);
    
    void inner_trampoline(void (*func)(void), callback_t callback)
    {
        if (callback == NULL)
            func();
        else
            callback(func, NULL);
    }
    
    void outer_trampoline(void (*func)(void), bool flag)
    {
        if (flag)
            inner_trampoline(func, &inner_trampoline);
        else
            outer_trampoline(func, true);
    }
    
    int 
    main(int argc, char *argv[])
    {
        /*... */
        outer_trampoline(set_aes_keys, false);
    }
    Ответить
  • А неиспользуемые argc, argv никого значит не смутили??!
    Ответить
    • Вспомнился говнокод, где чувак перепутал "argc" и "argv", но чёт не смог найти
      Ответить
          • Страшная сишная арифметика указателей. И ведь работает, хотя мозг отказывается это понимать.
            Ответить
            • Главное - зачем такая питушня понадобилась?
              Идеи кастов в JS ещё можно понять: удобно, когда пишешь "form.y.value = form.x.value * 10" и не отвлекаешься на преобразования.
              Но это перемешивание индексов - какая-то питушня. "Вдруг программист случайно перепутает массив и индекс - с кем не бывает - а наш язык ему поможет".
              Ответить
              • > Но это перемешивание индексов - какая-то питушня.
                Эта питушня наверное походит еще со времен, когда С считался непозволительной роскошью из-за оверхеда над ASM.

                > "Вдруг программист случайно перепутает массив и индекс - с кем не бывает - а наш язык ему поможет".
                Скорее мысль была такая "в случае x[y] заменяем и интерпретируем как *(x + y) ибо надо сэкономить пару байт кода компилятора"
                Ответить

Добавить комментарий

Переведи на "PHP", guest!

    А не использовать ли нам bbcode?


    8