Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Asm для Windows/Dos > Как работают call и длинные jmp внутри DLL?


Автор: Абабо 5.8.2008, 11:30
Не могли бы вы мне подсказать, как работают инструкции call, длинные jmp и им подобные внутри модуля DLL, спроецированного на адресное пространство процесса? Поскольку в процессе компоновки (создания) DLL известны только относительные адреса (относительно начала DLL-модуля), то при выполнении они должны инкрементироваться некоторым базовым адресом DLL. Мой вопрос в том, где он находится и как, говоря языком ассемблера, происходят подобные вызовы? (т.е. хранится ли базовый адрес постоянно в одном из регистров, либо он перед каждым вызовом считывается  из некоторого адреса). Касательно экспортируемых функций вопросов не возникает, поскольку при загрузке DLL их адреса располагаются в собственном (принадлежащем только данному процессу) блоке IAT (Import Address Table) и инкрементируются базовым адресом сразу после проецирования. Но вот как работают вызова локальных (не экспортируемых) функций и переходов (jmp > 128 байт) внутри DLL? Спасибо.

Автор: W4FhLF 5.8.2008, 14:26
При загрузке PE образа по адресу отличному от ImageBase лоадер использует базовые поправки. В PE предусмотрена таблица под название Relocation Table, в ней эти поправки хранятся. Каждая поправка привязана к определённому RVA в exe. 

http://wasm.ru/article.php?article=green2red02#_Toc100906501

Автор: Абабо 5.8.2008, 14:38
Спасибо... сейчас буду разбираться...

Автор: Абабо 5.8.2008, 15:00
Таким образом, для каждого перехода происходит обращение на соответствующую поправку, которая дает реальный VA... Наверно, при таком подходе имееют место ощутимые потери производительности...

Автор: W4FhLF 5.8.2008, 15:33
Ну эти поправки применяются только при загрузке при проецировании образа в памяти, поэтому они слишком малы даже для больших файлов, чтобы их можно было заметить. 

Автор: Абабо 5.8.2008, 15:38
Места они занимают немного (особенно, если учесть, что в коде большинство переходов условные, т.е. относительные), но любые абсолютные переходы (call, jmp) происходят через поправки, потому при каждом таком переходе происходит дополнительное обращение к соотв. поправке. Или я чего-то не понимаю?

Автор: W4FhLF 5.8.2008, 15:53
Нет, все абсолютные переходы после применения поправок уже верные. Поправки применяются один раз на стадии загрузки PE и всё, дальше уже все переходы выполняются как если бы мы грузили образ по ImageBase. 

Автор: Абабо 5.8.2008, 16:12
Как такое возможно? Ведь DLL разделяется многими процессами, располагаясь в общем случае по разным адресам их вирт. пространств? Проецируются же страницы одной и той же копии... (ведь иначе нивелируется весь смысл DLL). Или, может, при загрузке DLL одним процессом для неё резервируется область виртуальной памяти у всех процессов, вне зависимости от того, проецируется она на пространство того или иного процесса?

Автор: W4FhLF 6.8.2008, 06:03
Основные системные DLL грузятся всегда по одним адресам: kernel32.dll и ntdll.dll. Остальные базовые библиотеки(gdi32, user32, advapi32...) система старается загрузить тоже по одному адресу, но если этот адрес уже занят - будет выделена вирт. память по другому адресу. Для тех страниц, в которых надо применить базовые поправки система выделит отдельную физическую память. 

Автор: Абабо 6.8.2008, 11:07
Т.е., поскольку в общем случае нельзя предугадать, какой интервал адресов будет занят, а какой нет, то много шансов, что собственная DLL в процессах с различным DLL-импортом вероятно будет дублирована в памяти, что не есть хорошо... Ясно, большое спасибо.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)