КДЮ>Авторы: КДЮ> Караваев Дмитрий Юрьевич
КДЮ>Аннотация: КДЮ>В статье приведено несколько примеров недостаточно эффективных команд в коде ядра Windows-XP.
Но посмотрите, например, на один из бесчисленных фрагментов ядра:
Здесь, как и в сотнях других подобных мест, выравнивание превратилось в свою противоположность, и подпрограмма начинается из-за команд NOP как раз НЕ с адреса кратного 16 или хотя бы 4, а сами команды NOP стали просто бессмысленным раздуванием кода. Такое впечатление, что где-то в одном месте в ядре выравнивание «съехало» и далее везде дает противоположный эффект. Причем, чтобы увидеть это вовсе не требуется дисассемблировать код, достаточно любой подходящей утилитой посмотреть таблицу экспорта ядра NTOSKRNL.EXE. Там полно, например, нечетных (т.е. явно никак не выровненных) адресов входов.
Это не бессмысленное раздувание кода, а вполне себе осмысленное и имеющее название hot-patch. Mov edi, edi заменяется на short jmp, ведущий на 5 байт вверх, а этих пяти байт в свою очередь хватит, чтобы записать опкод long jmp'a.
Технологии больше десяти лет к слову. Предназначена для уменьшения(или избавления) количества ребутов (что критически важно если ОС стоит на сервере) при апдейтах.
КДЮ>Авторы: КДЮ> Караваев Дмитрий Юрьевич
КДЮ>Аннотация: КДЮ>В статье приведено несколько примеров недостаточно эффективных команд в коде ядра Windows-XP.
Эти фрагменты вызывают в памяти анекдот про двух человек, один из которых выкапывал ямы, а второй шел за ним и закапывал. Согласно анекдоту должен был быть еще и третий, который бы сажал деревья, но он не пришел. Здесь выполняется пролог подпрограммы, а затем сразу эпилог. Возможно, в исходном тексте находится какой-то закомментированный фрагмент и это дает такой эффект. Возможно, это было сделано для каких-то отладочных остановок. Но как бы то не было, каждый раз, когда происходит обращение к подпрограммам IoAllocateIrp и IoFreeIrp, сначала выполняются бессмысленные команды.
Эти две функции объявлены как NTKERNELAPI(DECLSPEC_IMPORT), поэтому генерация пролога для них это необходимость соблюдения стандартов(и да, это идет в ущерб оптимизации). А mov edi, edi — место для hotpatch'a.
Поэтому никаких бессмысленных команд тут нет.
КДЮ>Авторы: КДЮ> Караваев Дмитрий Юрьевич
КДЮ>Аннотация: КДЮ>В статье приведено несколько примеров недостаточно эффективных команд в коде ядра Windows-XP.
Во многих местах ядра происходит обращение к 2-байтовым объектам, например:
Недостаток здесь в том, что у транслятора не хватило «смелости» всегда читать эти объекты в 4-байтовые регистры, т.е. сделать код короче из-за исключения префиксов в командах чтения (даже оставляя префиксы в командах умножения и сравнения)
Это код из KiTrap0D, а он, как и другие обработчики ISR написан на ассемблере, соответственно, никто там сделать короче код не мог, оптимизирующего компилятора у ассемблера нет.
Можно ли было его написать человеку с предложенными вами оптимизациями? Нельзя, в al находится опкод, который вызвал trap.
КДЮ>Авторы: КДЮ> Караваев Дмитрий Юрьевич
КДЮ>Аннотация: КДЮ>В статье приведено несколько примеров недостаточно эффективных команд в коде ядра Windows-XP.
Еще один существенный недостаток кода – большое число пересылок регистров. Например, типичный фрагмент:
Нельзя так написать, ибо приведенная в виде инлайна функция KeGetCurrentPrcb развертывается в разный код на однопроцессорных и многопроцессорных ядрах.
А функции как известно, должны вертать результат в eax.
TSS>Эти две функции объявлены как NTKERNELAPI(DECLSPEC_IMPORT), поэтому генерация пролога для них это необходимость соблюдения стандартов(и да, это идет в ущерб оптимизации).
Про какие стандарты идет речь? Стандарт вызова функций говорит только о передачи параметров, но не заставляет генерировать пролог функции.
Эта же функция, но в Win10 x86 (10.0.10240.16384):
.00454965: CCCCCCCCCCCCCCCCCCCCCC int 3
IoFreeIrp: FF2510106700 jmp d,[pIoFreeIrp]
.00454976: CCCCCCCCCCCCCCCCCCCC int 3
Re[2]: Несколько замечаний по поводу качества кода
TSS>Нельзя так написать, ибо приведенная в виде инлайна функция KeGetCurrentPrcb развертывается в разный код на однопроцессорных и многопроцессорных ядрах. TSS>А функции как известно, должны вертать результат в eax.
А что мешает оптимизатору работать после инлайна? Опять же десятка:
Здравствуйте, EreTIk, Вы писали:
TSS>>Эти две функции объявлены как NTKERNELAPI(DECLSPEC_IMPORT), поэтому генерация пролога для них это необходимость соблюдения стандартов(и да, это идет в ущерб оптимизации). ETI>Про какие стандарты идет речь? Стандарт вызова функций говорит только о передачи параметров, но не заставляет генерировать пролог функции.
ETI>Эта же функция, но в Win10 x86 (10.0.10240.16384): ETI>
ETI>.00454965: CCCCCCCCCCCCCCCCCCCCCC int 3
ETI>IoFreeIrp: FF2510106700 jmp d,[pIoFreeIrp]
ETI>.00454976: CCCCCCCCCCCCCCCCCCCC int 3
ETI>
Да, вероятно я не прав насчет стандарта. Тем не менее, по умолчанию компилятор всегда лепит пролог, если явно не указать ему этого не делать. В сорцах win10 видимо явно указана директива __declspec(naked).
TSS>Да, вероятно я не прав насчет стандарта. Тем не менее, по умолчанию компилятор всегда лепит пролог, если явно не указать ему этого не делать. В сорцах win10 видимо явно указана директива __declspec(naked).
Думаю, что дело в версии и/или настройках компилятора. Пример:
>cl /O2 /Zi /MTd /EHsc test.cpp /link /RELEASE /OPT:REF
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
test.cpp
Microsoft (R) Incremental Linker Version 9.00.30729.4999
Copyright (C) Microsoft Corporation. All rights reserved.
/out:test.exe
/debug
/RELEASE
/OPT:REF
test.obj
Creating library test.lib and object test.exp
f: FF25C03F4200 jmp d,[000423FC0]
.00401006: CCCCCCCCCCCCCCCCCCCC int 3
Re[3]: Несколько замечаний по поводу качества кода
TSS>>Нельзя так написать, ибо приведенная в виде инлайна функция KeGetCurrentPrcb развертывается в разный код на однопроцессорных и многопроцессорных ядрах. TSS>>А функции как известно, должны вертать результат в eax.
ETI>А что мешает оптимизатору работать после инлайна? Опять же десятка: ETI>
Это совершенно другая функция ( 1й пример ) — заинлайненная KeGetCurrentIrql. KeGetCurrentPrcb к слову написана с асм вставкой, это оптимизатору и мешает. А KeGetCurrentIrql написана на С, и у оптимизатора развязаны руки.
По второму примеру лень искать, но видимо там асм вставок тоже не используется, раз код оптимизирован.
Здравствуйте, EreTIk, Вы писали:
TSS>>Да, вероятно я не прав насчет стандарта. Тем не менее, по умолчанию компилятор всегда лепит пролог, если явно не указать ему этого не делать. В сорцах win10 видимо явно указана директива __declspec(naked).
ETI>Думаю, что дело в версии и/или настройках компилятора. Пример: ETI>
>>cl /O2 /Zi /MTd /EHsc test.cpp /link /RELEASE /OPT:REF
ETI>Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
ETI>Copyright (C) Microsoft Corporation. All rights reserved.
ETI>test.cpp
ETI>Microsoft (R) Incremental Linker Version 9.00.30729.4999
ETI>Copyright (C) Microsoft Corporation. All rights reserved.
ETI>/out:test.exe
ETI>/debug
ETI>/RELEASE
ETI>/OPT:REF
ETI>test.obj
ETI> Creating library test.lib and object test.exp
ETI>
ETI>
ETI>f: FF25C03F4200 jmp d,[000423FC0]
ETI>.00401006: CCCCCCCCCCCCCCCCCCCC int 3
ETI>
Это безусловно зависит от компилятора, но все таки мы говорим про windows, а она использует микрософтовский компилятор. Соответственно, с прологом там все более менее понятно. Хотя признаться, я не знаю как с этим дела в последних версиях компиляторов.
TSS>Это совершенно другая функция ( 1й пример ) — заинлайненная KeGetCurrentIrql. KeGetCurrentPrcb к слову написана с асм вставкой, это оптимизатору и мешает. А KeGetCurrentIrql написана на С, и у оптимизатора развязаны руки. TSS>По второму примеру лень искать, но видимо там асм вставок тоже не используется, раз код оптимизирован.
>>>cl /O2 /Zi /MTd /EHsc test.cpp /link /RELEASE /OPT:REF
ETI>>Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
ETI>>Copyright (C) Microsoft Corporation. All rights reserved.
ETI>>test.cpp
ETI>>Microsoft (R) Incremental Linker Version 9.00.30729.4999
ETI>>Copyright (C) Microsoft Corporation. All rights reserved.
ETI>>/out:test.exe
ETI>>/debug
ETI>>/RELEASE
ETI>>/OPT:REF
ETI>>test.obj
ETI>> Creating library test.lib and object test.exp
ETI>>
ETI>>
ETI>>f: FF25C03F4200 jmp d,[000423FC0]
ETI>>.00401006: CCCCCCCCCCCCCCCCCCCC int 3
ETI>>
TSS>Это безусловно зависит от компилятора, но все таки мы говорим про windows, а она использует микрософтовский компилятор. Соответственно, с прологом там все более менее понятно. Хотя признаться, я не знаю как с этим дела в последних версиях компиляторов.
Так мой пример тоже построен на кодо-генерации MS'овских компилятора и линкера (не самых свежих — Microsoft Visual Studio 9.0).
Мой посыл был в том, что старый компилятор, которым собирали XP, мог оставлять пролог из-за недоработки или специфических опций.
Re[7]: Несколько замечаний по поводу качества кода
>>>>cl /O2 /Zi /MTd /EHsc test.cpp /link /RELEASE /OPT:REF
ETI>>>Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
ETI>>>Copyright (C) Microsoft Corporation. All rights reserved.
ETI>>>test.cpp
ETI>>>Microsoft (R) Incremental Linker Version 9.00.30729.4999
ETI>>>Copyright (C) Microsoft Corporation. All rights reserved.
ETI>>>/out:test.exe
ETI>>>/debug
ETI>>>/RELEASE
ETI>>>/OPT:REF
ETI>>>test.obj
ETI>>> Creating library test.lib and object test.exp
ETI>>>
ETI>>>
ETI>>>f: FF25C03F4200 jmp d,[000423FC0]
ETI>>>.00401006: CCCCCCCCCCCCCCCCCCCC int 3
ETI>>>
TSS>>Это безусловно зависит от компилятора, но все таки мы говорим про windows, а она использует микрософтовский компилятор. Соответственно, с прологом там все более менее понятно. Хотя признаться, я не знаю как с этим дела в последних версиях компиляторов.
ETI>Так мой пример тоже построен на кодо-генерации MS'овских компилятора и линкера (не самых свежих — Microsoft Visual Studio 9.0). ETI>Мой посыл был в том, что старый компилятор, которым собирали XP, мог оставлять пролог из-за недоработки или специфических опций.
Упс, совсем я плохой стал, мне почему-то почудился gcc. Тогда да, видимо дело в компиляторе (версии или настройках).