Война миров - ассемблер против си

         

Эффективность кодогенерации си компиляторов


Желая продемонстрировать превосходство ассемблера над си, обычно берут программы типа "hello, world!" и сравнивают размеры _откомпилированных_ файлов, причем, ассемблер использует прямые вызовы API-функций GetStdHandle()/WriteFile(), а программу на си заставляют обращаться к printf(), которая тащит за собой библиотеку времени исполнения (она же Run Time Library или, сокращенно, RTL). Ну и где же здесь честность?! Как будто на си нельзя программировать без RTL! Можно— для этого достаточно переименовать функцию main() во что-то другое, указав линкеру точку входа в файл вручную. Размер откомпилированного файла сразу же сократится, вплотную приближаясь (или даже совпадая) с ассемблированным файлом, но 99% пространства будет занимать служебная информация PE-формата и место, оставленное линкером для выравнивания секций. На этом фоне различия между компилятором и ассемблером становятся совершенно незаметными!

Мы же поступим иначе — напишем небольшую программку, например, вычисляющую CRC8 (большая — просто бы не уместилась в статью), а затем откомпилируем ее и, прогнав полученный файл через дизассемблер, посмотрим — насколько эффективно компилятор справился со своей задачей и какой простор он оставил нам для ручной оптимизации.

Исходный текст подопытной функции выглядит так:

CRC(unsigned char *p, int n)

{

       int a; unsigned char crc=0;

       for (a=0;a<n;a++) crc += p[a];

       return 0 - crc;

}



Содержание раздела