Введение
Тема будет интересна всем, но познать её смогут только "счастливые" обладатели компилятора в популярном пакете dev-cpp для windows. На самом деле среду эту я не люблю и не пользуюсь никогда в силу жуткий глюков и тормозов, но как-то она мне попалась на первых парах изучения C и поэтому до сих пор используется мною как средство установки на комп консольных компилятора g++ и отладчика gdb. Быстро, удобно, бесплатно и всегда под рукой в интернете.
Сабдж
Собственно речь сейчас не идёт о прелестях этого старого приложения. Многие слышали о магии С++, многие её отведали, многие сваливают на неё ошибки в своем коде во время контестов. Ниже, представлен один из примеров подобного заклинания, о возможности компиляции которого даже приходится задуматься, не говоря уже о результате выполнения. Внимание! Уберите от экранов слабонервных, детей и паскальщиков:
char s[56] = "\xB8\1\0\0\0+\xD2\xB9\x1E\0\0\0Q\x8B\xC8\3\xC2\x8B\xD1PRh\x32 @\0\xA1" "\xD0P@\0\x83\xC0 P\xFF\x15\xE8P@\0\x83\xC4\bZXY\xE2\xDB\xC3%\x75\n"; int main(){ (((void(*)())(char*)s)()); return 0; }
Не думаю, что кто-то из ныне живущих людей на планете сможет с уверенностью сходу сказать, что этот код делает. Код без привычных #include. Состоящий буквально из одной строки кода. Он также врядли сделает что-то полезное на других компиляторах, но вот Dev-cpp и его GNU C++ 3.4.2 вполне согласен со всем написанным и готов его корректно исполнить.
Так что же он делает, задаётся вопросом нетерпеливый читатель? Попробуйте сначала предположить что, а потом проверьте у себя на машине. :)
Найдутся люди, которые вникнут в происходящее и даже смогут модифицировать текущий код. В любом случае пост по объяснению происходящего организовать могу. :)
Ссылки
Собственно код http://pastebin.com/w9pyjAtm
Ошибочка вышла, сорри.
За спойлером подозрение на ответ. Мне подсказывают, что он правильный, сделал не запуская.
UDP:
mov eax,0x804a040
call eax
0x804a040 - по этому адресу находится код (в первой правке) который в цикле вызывает какую-то функцию (вроде set_app_type) с параметрами.
В прошлой правке раскомментированый код дизассемблера. Осторожно, спойлер.
получается выводит свой код.
Кстати, забавный можно квайн написать)
Нет, конечно, фактически там делается s + 32
По поводу паскальщиков это Вы напрасно... :)
На паскале асемблерные вставки также можно делать похожим образом. Даже более того - например, можно напрямую делать дамп памяти, изменять её, оперировать с регистрами, видеопамятью и т.д. и т.п.
Другое дело, что школьникам по большому счёту подобные знания не только излишни, но в большинстве случаев бывают вредны.
Почему - объяснять не буду, как и не буду объяснять, почему не буду объяснять... :)
Но какой же честолюбивый школьник согласится оставить хорошую программу без мышки?
Естественно. И правильно делали, что там использовали. :)
Мы, например, когда ещё в школе были "Корветы" писали на паскале асемблерные модули и делали програмы-генераторы для подключения к паскалевским библиотекам спрайтов и музыки - какая же своя игрушка без музыки и анимации?.
Потом научили это чудо говорить - то же самое проделывали и ребята в Каменец-Подольске. И всё это умещали в 48К ...
Эх, интересное было время... :)
Да, программисты были не зажравшиеся... Вот сейчас смотрю на веб-клиент для ICQ - и там снизу требования приписаны... Так меня очень развлекает что для примитивного чата нужно 1 гиг оперативки... ;-)
Если я не ошибаюсь, DEP просто предотвращает исполнение страниц, у которых не выставлен флаг "для исполнения". А у сегмента данных он несомненно не выставлен.
Дык айда к нам на electronix.ru... Обещаю, там намного магичнее... А проблем с отладкой вообще может быть море, т.к. не знаешь, программа ли сбоит, или где-то припаялось плохо, или уже нога процессора отгорела... ;-)
UPD: Да, по поводу "заставить работать строку на java" - этим пользуются даже промышленно обфускаторы - шифруют код а потом его восстанавливают с помощью рефлексии... Ну ведь и в си всё это тоже в первую очередь для защиты программы от копирования использовалось...
- вредоносное ПО;
- защита от копирования.
Когда мне хочется развлечься - у меня под рукой не только ассемблеры для x86, но и для AVR, ARM и прочих чудесных платформ... Операционные системы занимающие по 700 байт в ПЗУ и несколько десятков в оперативке... Ну и т.п.
Но когда мне надо работать - да здравствует java в которой не приходится сутками искать за всякими ________ (нужное вписать) где же это они умудрились нечаянно "запустить" данные вместо кода или натворить ещё стопиццот удивительных в своём идиотизме вещей.
Так что любить надо всё... Я никогда не стану всерьёз задумываться о написании веб-приложения на Си, или о программировании микроконтроллеров на java-подобных извращениях... ;-)
А это разве С++? По-моему, тут чистый Си. А вот ниже С++. Кто сможет понять, что делает этот код?
Отлично, второй эпик слив за этот тред. Пошел читать стандарт по ключевым словам "перегрузка функций", "приоритет выбора между константными и неконстантыми операторами преобразования типа", а также "приоритет выбора при шаблонной подстановке".
Что делает - понятно, что написано - понятно, но почему это ведет себя именно так?!
Upd. Похоже, поведение MS VS 2005 на данном примере не соответствует, по крайней мере, описанию преобразования типов, данному у Страуструпа (R.13.2).
Действительно.
struct super{}; struct sub:super{};
superClass<sub, super>::value
сопоставляются
check(const volatile super&, int);
check(const volatile sub&, T);
Оба требуют пользовательские преобразования и попадают под пункт 4. Оба содержат только пользовательские и тривиальные преобразования. Выбрать вызываемую функцию невозможно, так как наличие лишнего тривиального преобразования Temp -> const Temp само по себе не является основанием для более высокого приоритета (там же в 13.2).