- 1
[code]main[]__attribute__((section(".text"))) = {0xC0FFC031,0x7401FF83,0xFFE7F706,0xC3F5EBCF};[/code]
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
+5
[code]main[]__attribute__((section(".text"))) = {0xC0FFC031,0x7401FF83,0xFFE7F706,0xC3F5EBCF};[/code]
Печатает факториал, от числа аргументов.
капча: t4ar
> [code]
действительно
Какой анскилл )))
Кстати компиляторы — говно.
Пишу gcc -Os /clang -Os. Подразумевается компактный код.
Они генерят
Или умножение
Листинг:
Пояснение: в 32-битном режиме Кол Конвеншин «cdecl». Аргументы пушатся справа налево, поэтому argc лежит в [esp+4] (т. к. в [esp+0] лежит адрес разврата). Однако, CRT перед тем, как занести argc в стек, временно вносит его в eax. Этим можно воспользоваться (правда, можно обломаться в некоторых версиях компилятора).
Инструкция loop уменьшает ecx и проверяет ecx на ноль.
А ещё в 32-битном режиме есть однобайтовые инкременты и декременты.
Вот здесь я удивился. Т.к. нет привычных esp.
Сам хотел написать в x32, т.к. верно подмечено что incи на байт короче.
И к тому же баш из кода разврата выводит только младшие 8 бит.
./hex 1 1 1 1 1
➤ 208
720 & 255 = 208
Написав mov ecx, eax, я положился на то, что код инициализации копирует в стек значение argc в последнюю очередь (argv и указатель на окружение копирует раньше), а в качестве промежуточного регистра использует eax (он не пушит, а использует мув, а поскольку мув из памяти в память нельзя, он использует регистр как временное хранилище).
x64, 11 бат, кто меньше?
Пробовал mov al, 1; cbw; cwde — получается длиннее.
stc; setc al; cbw; cwde — будет ещё длиннее.
Ещё вариант div eax — всего два байта для получения единицы в eax. Но если в eax изначально ноль, будет плохо (division by zero). Нужно смотреть код CRT, что там вносится в eax перед call _main.
Чтобы как в прошлом топике N единичек передать и проверить N.
Ну удивление код получился очень «ровный», двухбайтных.
Как в «RISC».
Лишний багор )))
Заодно поменял порядок итерации чтобы начинало проверять с 2, а не N-1.
Тестовый полигон:
А тьфу, для деления же. Понаделают говноинструкций с неявными аргументами.
Проверил эффективность унарного кодирования.
Где-то за секунду оно факторизует числа около миллиона.
Таким образом код вполне даже практичен.
Дальше баш упирается в длину списка: bash: ./prime: Argument list too long
Так оно для 1 и 2 тоже правильно работает!
Заодно считает количество нетривиальных делителей числа. Круто.
0 - простое
1 - квадрат простого
2 - произведение простых
Нечетное - квадрат числа.
Можно использовать трёхбайтовую sete.
А если заменить 5-байтовую загрузку -2 на xor, то код будет считать хорошо известную в теории чисел «функцию делителей».
https://en.wikipedia.org/wiki/Divisor_function
Какой математик )))
«sete» три бата занимает, поэтому баты по сравнению с примитивным «jne» не экономятся. Багор (((
Код будет короче на джва бата. Но тогда потеряется полезность функции делителей.
Впрочем нет. bsf в x64 тоже трёхбатная.
xor ebx, ebx
mov ebx, edi
adc bl,bh
sbb bl,0
И заменив обратно джвухбатный sub eax,ebx на xchg.
Но тогда я не знаю где взять 8-битный регистр с нулём.
bh работает, т.к. число делителей даже на больших числах меньше 255.
И результат всегда влазит в bl.
Что я буду делать? ЫЫЫЫЫ!
Ы, ку, Ы, ку, Ы, ку, Ы!
Спасибо за идею! Только для «div eax» надо ещё edx очищать, иначе бо-бо.
x64, 10 бат!
x64, 11 бат, другой подход.
Какой анскилл )))
На стеке слабо оставить?