Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Корпорация Майкрософт имеет определенные методы, используемые для повторного упорядочивания скомпилированного и связанного кода, чтобы он выполнялся с большей эффективностью. Эти методы оптимизируют компонент для иерархий памяти и основаны на сценариях обучения.
Результирующая оптимизация уменьшает разбиение на страницы (и ошибки страниц) и увеличивает пространственное расположение между кодом и данными. Это устраняет ключевое узкое место производительности, которое будет вызвано из-за неудачного расположения исходного кода. Компонент, прошедший эту оптимизацию, может иметь код или блок данных внутри функции, которые могут быть перемещены в разные части двоичного файла.
В модулях, оптимизированных этими методами, расположения блоков кода и данных часто находятся в адресах памяти, отличных от расположений, где они будут находиться после обычной компиляции и связывания. Кроме того, функции, возможно, были разделены на множество несвязанных блоков, чтобы наиболее часто используемые пути кода могли находиться рядом друг с другом на одной странице.
Таким образом, функция (или любой символ) плюс смещение не обязательно будет иметь то же значение, что и в неоптимизованном коде.
Отладка кода Performance-Optimized
При отладке можно увидеть, оптимизирован ли модуль для производительности с помощью команды расширения !lmi в любом модуле, для которого загружены символы:
0:000> !lmi ntdll
Loaded Module Info: [ntdll]
Module: ntdll
Base Address: 77f80000
Image Name: ntdll.dll
Machine Type: 332 (I386)
Time Stamp: 394193d2 Fri Jun 09 18:03:14 2000
CheckSum: 861b1
Characteristics: 230e stripped perf
Debug Data Dirs: Type Size VA Pointer
MISC 110, 0, 76c00 [Data not mapped]
Image Type: DBG - Image read successfully from symbol server.
c:\symbols\dll\ntdll.dbg
Symbol Type: DIA PDB - Symbols loaded successfully from symbol server.
c:\symbols\dll\ntdll.pdb
Обратите внимание на термин perf в строке "Характеристики" в этих выходных данных. Это означает, что эта оптимизация производительности была применена к ntdll.dll.
Отладчик может понять функцию или другой символ без смещения; это позволяет задавать точки останова для функций или других меток без каких-либо проблем. Однако выходные данные операции дизассембли могут быть запутанными, так как этот дизассембли будет отражать изменения, внесенные оптимизатором.
Так как отладчик попытается оставаться близко к исходному коду, вы можете увидеть некоторые забавные результаты. Основное правило при работе с кодом, оптимизированным для производительности, состоит в том, что вы не можете выполнять надежную арифметику адресов в таком коде.
Ниже приведен пример:
kd> bl
0 e f8640ca6 0001 (0001) tcpip!IPTransmit
1 e f8672660 0001 (0001) tcpip!IPFragment
kd> u f864b4cb
tcpip!IPTransmit+e48:
f864b4cb f3a4 rep movsb
f864b4cd 8b75cc mov esi,[ebp-0x34]
f864b4d0 8b4d10 mov ecx,[ebp+0x10]
f864b4d3 8b7da4 mov edi,[ebp-0x5c]
f864b4d6 8bc6 mov eax,esi
f864b4d8 6a10 push 0x10
f864b4da 034114 add eax,[ecx+0x14]
f864b4dd 57 push edi
В списке точек останова видно, что IPTransmit имеет адрес 0xF8640CA6.
При разборке секции кода внутри этой функции по адресу 0xF864B4CB вывод показывает, что это на 0xE48 байт дальше от начала функции. Однако если вычесть основу функции из этого адреса, фактическое смещение будет 0xA825.
Это происходит: отладчик действительно показывает дизассемблию двоичных инструкций, начиная с 0xF864B4CB. Но вместо вычисления смещения путем простого вычитания отладчик отображает, насколько это возможно, смещение до точки входа в функцию, как она существовала в исходном коде перед выполнением оптимизаций. Это значение 0xE48.
С другой стороны, если вы пытаетесь взглянуть на IPTransmit+0xE48, вы увидите следующее:
kd> u tcpip!iptransmit+e48
tcpip!ARPTransmit+d8:
f8641aee 0856ff or [esi-0x1],dl
f8641af1 75fc jnz tcpip!ARPTransmit+0xd9 (f8641aef)
f8641af3 57 push edi
f8641af4 e828eeffff call tcpip!ARPSendData (f8640921)
f8641af9 5f pop edi
f8641afa 5e pop esi
f8641afb 5b pop ebx
f8641afc c9 leave
То, что происходит здесь, отладчик распознает символ IPTransmit как эквивалент адреса 0xF8640CA6, а средство синтаксического анализа команд выполняет простое добавление, чтобы найти, что 0xF8640CA6 + 0xE48 = 0xF8641AEE. Затем этот адрес используется в качестве аргумента для команды u (Unassemble). Но после анализа этого расположения отладчик обнаруживает, что это не IPTransmit плюс смещение 0xE48. Действительно, это не является частью этой функции вообще. Скорее, он соответствует функции ARPTransmit плюс смещение 0xD8.
Причина в том, что оптимизация производительности не является обратимой с помощью арифметики адресов. Хотя отладчик может принимать адрес и выводить исходный символ и смещение, у него недостаточно сведений, чтобы взять символ и смещение и перевести его в правильный адрес. Следовательно, разборка не является полезной в этих случаях.