Total Commander Forum Index Total Commander
Форум поддержки пользователей Total Commander
Сайты: Все о Total Commander | Totalcmd.net | Ghisler.com | RU.TCKB
 
 RulesRules   SearchSearch   FAQFAQ   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Указание базового адреса модуля
Goto page 1, 2  Next
 
Post new topic   Reply to topic    Total Commander Forum Index -> Плагины Total Commander printer-friendly view
View previous topic :: View next topic  
Author Message
MVV



Joined: 15 Oct 2009
Posts: 4811
Location: Ростов-Дон

Post (Separately) Posted: Tue Mar 23, 2010 09:48    Post subject: Указание базового адреса модуля Reply with quote

Вот интересно, просмотрел кучу плагинов, которые валяются у меня на рабочем компе, ну и некоторых библиотек, прилагаемых к ним. И могу сказать, что практически никто при компиляции плагина не изменяет базовый адрес модуля.

Каждый модуль (динамическая библиотека) имеет характеристику ImageBase, которая указывает предпочтительный адрес для размещения в памяти процесса при загрузке модуля. Все абсолютные адреса функций и данных модуля в коде указываются с рассчетом на этот адрес. Если при загрузке библиотеки в адресное пространство процесса система замечает, что данный адрес уже занят, она размещает библиотеку по некоторому свободному адресу, при этом корректируя все абсолютные адреса в коде с учетом нового базового адреса. Также, раз код изменяется, он уже не может быть общим с кодом других экземпляров той же библиотеки, и занимает дополнительную память (хотя, для плагинов это, как правило, не критично, так как они редко грузятся по несколько раз, разве что при использовании нескольких инстанций ТК). То есть, чтобы библиотека загружалась быстрее и потребляла меньше памяти, нужно на стадии компоновки выбирать уникальный базовый адрес.

Насколько я понимаю, для модулей ТК нет единой схемы или правила распределения плагинов по адресам (поправьте, пожалуйста, если я ошибаюсь), большинство плагинов (здесь могу быть неточен, т.к. имею лишь около трех десятков модулей в распоряжении на момент анализа - у кого есть интерес, проанализируйте свои, например, с помощью FileInfo, секция OPTIONAL HEADER, поле Image Base) используют стандартный адрес 0x10000000, т.е. системе приходится загружать в дополнительную память и корректировать все плагины, использующие данный базовый адрес, загруженные после первого занявшего его. Далее, некоторые используют адрес 0x400000 - это вообще ужас. Не знаю, какой компоновщик допускает это, но сами приложения (и ТК - не исключение) грузятся по этому адресу, т.е. такие модули всегда будут требовать корректировки при загрузке. Пожалуй, самый образцовый плагин среди анализируемых - Imagine. У него каждая библиотека (Imagine.dll, Imagine.wlx, Imagine.wcx, его плагины) имеет свой базовый адрес. Для своей VirtualPanel я также указал отличный от стандартного базовый адрес.

Думаю, неплохо бы как-то (разумеется, более разумно - и на офсайте) составить таблицу и распределить базовые адреса по модулям, чтобы избежать пересечения адресных пространств плагинов (особенно это будет полезно тем, кто их использует десятками и сотнями).
_________________
TCFS2 + TCFS2Tools: Полноэкранный режим и многое другое (обсуждение)
WINCMD.RU: AskParam, CopyTree, NTLinks, Sudo, VirtualPanel…
Back to top
View user's profile Send private message
prog_san



Joined: 29 Sep 2007
Posts: 282
Location: Пенза

Post (Separately) Posted: Tue Mar 23, 2010 09:59    Post subject: Reply with quote

Набор плагинов у каждого пользователя уникальный => особого смысла в этом распределении не будет. Можно задать базовые адреса для наиболее широко используемых плагинов - это даст небольшой выигрыш. Или, как в случае с Imagine - делать это только для гарантированно совместно используемых модулей.

P.S. Желающие могут раскидать плагины по адресному пространству по базовым адресам, а заодно и выполнить предварительное связывание "bound import" для своей системы, с использование утилиты bind.
Если проделать эту операцию - скорость загрузки заметно увеличится.
_________________
Errare humanum est
Back to top
View user's profile Send private message
MVV



Joined: 15 Oct 2009
Posts: 4811
Location: Ростов-Дон

Post (Separately) Posted: Tue Mar 23, 2010 10:24    Post subject: Reply with quote

Для привязки желающим потребуется изменять все модули, причем, это нужно делать под каждую операционнную систему, а я предлагаю лишь распределить адреса между плагинами и придерживаться разбиения. Если подумать, адресное пространство процесса гораздо больше, чем совокупный размер потребляемой плагинами памяти (очевидно, иначе бы они не грузились) - только рекомендуемая область для загрузки библиотек имеет размер 256 МБ (адреса 0x6000000-0x7000000), поэтому идея вполне реальна - выделить каждому модулю определенный адрес с учетом размера его базы с запасом, или же один адрес на группу по возможности непересекающихся модулей, чтобы разработчики новых или обновленных плагинов использовали рекомендуемые значения.
_________________
TCFS2 + TCFS2Tools: Полноэкранный режим и многое другое (обсуждение)
WINCMD.RU: AskParam, CopyTree, NTLinks, Sudo, VirtualPanel…
Back to top
View user's profile Send private message
CaptainFlint



Joined: 14 Dec 2004
Posts: 6151
Location: Москва

Post (Separately) Posted: Tue Mar 23, 2010 12:05    Post subject: Reply with quote

MVV wrote:
Также, раз код изменяется, он уже не может быть общим с кодом других экземпляров той же библиотеки

Не вижу причин, почему код с релоцированными адресами не может быть общим. Это же не самомодификация, а запланированные изменения, внесённые ОСью на стадии загрузки, она знает их, может учитывать и предсказывать результаты (в отличие от случаев, когда плагин сам модифицирует свой код, например, в случае PE-упаковщиков типа UPX).
_________________
Почему же, ё-моё, ты нигде не пишешь "ё"?
Back to top
View user's profile Send private message
VadiMGP



Joined: 21 Mar 2007
Posts: 1625

Post (Separately) Posted: Tue Mar 23, 2010 12:06    Post subject: Reply with quote

MVV wrote:
То есть, чтобы библиотека загружалась быстрее и потребляла меньше памяти, нужно на стадии компоновки выбирать уникальный базовый адрес.
Не буду касаться вопроса об объеме памяти, но насчет времени загрузки имею сильные сомнения, что есть ради чего копья ломать и тыкву чесать. Несколько лет назад я заинтересовался этим вопросом и нашел статью Rebasing Win32 DLLs: The Whole Story. Исследования проведенные на 486 33MHz процессоре под Windows NT 3.51 (!) показали, что перенастройка адресов (независимо от размера DLL) требует время порядка 100 msec.

И, если с тех пор ситуация не изменилась кардинально в худшую сторону (а я думаю, что сегодня это время еще на пару порядков меньше), то я не готов тратить час своего времени на экономию нескольких миллисекунд.
Back to top
View user's profile Send private message
MVV



Joined: 15 Oct 2009
Posts: 4811
Location: Ростов-Дон

Post (Separately) Posted: Tue Mar 23, 2010 18:10    Post subject: Reply with quote

CaptainFlint wrote:
MVV wrote:
Также, раз код изменяется, он уже не может быть общим с кодом других экземпляров той же библиотеки

Не вижу причин, почему код с релоцированными адресами не может быть общим. Это же не самомодификация, а запланированные изменения, внесённые ОСью на стадии загрузки, она знает их, может учитывать и предсказывать результаты (в отличие от случаев, когда плагин сам модифицирует свой код, например, в случае PE-упаковщиков типа UPX).

Ну подумай сам. Код модуля загружается в память, и все ее копии пользуют его как общий (по логике, второй и далее разы даже читать секцию кода из файла не надо, раз она уже есть в памяти). Но если одна из них загружается по отличному от базового адреса, система ее загрузит и внесет корректировки в ее код, т.е. он уже будет отличаться от кода тех копий, которые загружены по базовому адресу - как минимум, все инструкции call и jmp (кроме вызовов системных функций) будут содержать другие адреса (если быть точным, будет исправлен адрес в каждом месте, указанном в секции релокаций).

VadiMGP wrote:
MVV wrote:
То есть, чтобы библиотека загружалась быстрее и потребляла меньше памяти, нужно на стадии компоновки выбирать уникальный базовый адрес.
И, если с тех пор ситуация не изменилась кардинально в худшую сторону (а я думаю, что сегодня это время еще на пару порядков меньше), то я не готов тратить час своего времени на экономию нескольких миллисекунд.

Давай разбираться. Миллисекунды (про которые ты писал, что их было порядка сотни на старом процессоре, и число которых все-таки зависит от объема кода модуля, т.к. влияет на число адресов, требующих коррекции) тратятся на каждый модуль при каждой его загрузке в каждую запускаемую копию ТК. А от тебя требуется лишь один раз залезть в настройки проекта, или же просто указать в коде прагму с директивой компоновщику, и всё, на выходе будешь получать модуль с уникальным базовым адресом. Где час?
Для C/C++ компиляторов Microsoft достаточно в любом месте файла с исходным кодом указать строчку следующего вида:
Code:
#pragma comment(linker, "/base:0x60000000")


Кстати, более удобный способ просмотра базовых адресов для загруженных плагинов - в нижней панели Process Explorer, переключенной на показ библиотек, посмотреть на столбец Image Base (и на столбец Base, указывающий базовый адрес после перебазирования).
_________________
TCFS2 + TCFS2Tools: Полноэкранный режим и многое другое (обсуждение)
WINCMD.RU: AskParam, CopyTree, NTLinks, Sudo, VirtualPanel…
Back to top
View user's profile Send private message
CaptainFlint



Joined: 14 Dec 2004
Posts: 6151
Location: Москва

Post (Separately) Posted: Tue Mar 23, 2010 19:38    Post subject: Reply with quote

MVV wrote:
Ну подумай сам. Код модуля загружается в память, и все ее копии пользуют его как общий (по логике, второй и далее разы даже читать секцию кода из файла не надо, раз она уже есть в памяти). Но если одна из них загружается по отличному от базового адреса, система ее загрузит и внесет корректировки в ее код, т.е. он уже будет отличаться от кода тех копий, которые загружены по базовому адресу - как минимум, все инструкции call и jmp (кроме вызовов системных функций) будут содержать другие адреса (если быть точным, будет исправлен адрес в каждом месте, указанном в секции релокаций).

Не понял, если библиотека уже загружена в память по некоторому адресу, нафига ж тогда её ещё раз грузить по другому адресу? Что-то у тебя с ног на голову всё повёрнуто. Вот твоя аргументация в сокращённом виде (поправь, если не так понял): система грузит вторую копию DLL по новому адресу, меняет указатели, адреса становятся другими, нельзя переиспользовать код, следовательно, придётся держать несколько копий. Так ведь эта цепочка рассуждений начинается как раз того, что по какой-то причине грузится вторая копия по новому адресу! Какие тут ещё могут быть доводы и обоснования? Мы предположили, что загрузилась новая копия, и на основе этого доказали, что новая копия загрузится.
_________________
Почему же, ё-моё, ты нигде не пишешь "ё"?
Back to top
View user's profile Send private message
MVV



Joined: 15 Oct 2009
Posts: 4811
Location: Ростов-Дон

Post (Separately) Posted: Wed Mar 24, 2010 08:58    Post subject: Reply with quote

CaptainFlint wrote:
MVV wrote:
Ну подумай сам. Код модуля загружается в память, и все ее копии пользуют его как общий (по логике, второй и далее разы даже читать секцию кода из файла не надо, раз она уже есть в памяти). Но если одна из них загружается по отличному от базового адреса, система ее загрузит и внесет корректировки в ее код, т.е. он уже будет отличаться от кода тех копий, которые загружены по базовому адресу - как минимум, все инструкции call и jmp (кроме вызовов системных функций) будут содержать другие адреса (если быть точным, будет исправлен адрес в каждом месте, указанном в секции релокаций).

Не понял, если библиотека уже загружена в память по некоторому адресу, нафига ж тогда её ещё раз грузить по другому адресу? Что-то у тебя с ног на голову всё повёрнуто. Вот твоя аргументация в сокращённом виде (поправь, если не так понял): система грузит вторую копию DLL по новому адресу, меняет указатели, адреса становятся другими, нельзя переиспользовать код, следовательно, придётся держать несколько копий. Так ведь эта цепочка рассуждений начинается как раз того, что по какой-то причине грузится вторая копия по новому адресу! Какие тут ещё могут быть доводы и обоснования? Мы предположили, что загрузилась новая копия, и на основе этого доказали, что новая копия загрузится.

Она еще не загружена, она еще только загружается. Система вынуждена грузить вторую копию модуля по новому адресу, при этом нужно менять указатели - адреса становятся другими, нельзя переиспользовать код, следовательно, придётся держать несколько копий.

Хорошо, постараюсь объяснить подробнее.

У всех копий одной и той же библиотеки, загруженных в разные процессы по одинаковым базовым адресам (например, по рекомендуемому), секции кода ссылаются на общий участок физической памяти (т.к. их код идентичен).

Но если системе нужно подгрузить библиотеку к некоторому процессу, и выясняется, что рекомендуемый базовый адрес уже занят, системе приходится загружать библиотеку по другому адресу в виртуальном адресном пространстве. Тут начинаются проблемы, так как код, прописанный в библиотеке, по другому адресу работать не способен (абсолютные адреса прописаны с учетом рекомендуемого базового адреса - например, базовый адрес 0x400000, и инструкция call 0x400300, но если базовый адрес 0x1000000, эта инструкция должна быть call 0x1000300), поэтому необходимо исправить каждый адрес в коде.

Поэтому система загружает секцию кода в отдельный участок физической памяти, с которым будет связана секция кода новой копии библиотеки, и в этом участке исправляет все адреса, указанные в таблице релокаций библиотеки, с учетом разницы старого и нового базовых адресов.

Т.е., имеем дополнительное потребление физической памяти и необходимость загрузки и коррекции кода с учетом изменившегося базового адреса - если при компоновке библиотеки выбрать адрес, который не используется другими модулями, подгружаемыми к конкретному процессу, такой проблемы просто не возникнет.
_________________
TCFS2 + TCFS2Tools: Полноэкранный режим и многое другое (обсуждение)
WINCMD.RU: AskParam, CopyTree, NTLinks, Sudo, VirtualPanel…
Back to top
View user's profile Send private message
prog_san



Joined: 29 Sep 2007
Posts: 282
Location: Пенза

Post (Separately) Posted: Wed Mar 24, 2010 10:39    Post subject: Reply with quote

Коррекция выполняется не для всего модуля, а только для секций - требующих релокирования - т.е. содержащих код и некоторых других. => секции данных, если они только для чтения, остаются разделяемыми. Часть секций, в которые предусмотрена запись - содержащих глобальные массивы и п.р. - подгружаются каждый раз для каждого процесса. (правда, существует еще и механизм отоженной записи - т.е. пока в эту секцию ничего не записали - она может быть разделяемой для нескольких процессов)
_________________
Errare humanum est
Back to top
View user's profile Send private message
VadiMGP



Joined: 21 Mar 2007
Posts: 1625

Post (Separately) Posted: Wed Mar 24, 2010 12:55    Post subject: Reply with quote

MVV wrote:
Давай разбираться. Миллисекунды (про которые ты писал, что их было порядка сотни на старом процессоре, и число которых все-таки зависит от объема кода модуля,
Я же написал, что время не зависит от размера модуля.

MVV wrote:
А от тебя требуется лишь один раз залезть в настройки проекта, ... Где час?
А ты дай свою оценку времени.
Итак, что надо сделать? Сначала для плагина надо как-то выяснить каков его уникальный базовый адрес. Затем нужно поменять код (или проект), отбилдовать, проверить, что он теперь действительно грузится по новому адресу (как?), и заново выложить новую версию.

И все ради чего? Насколько в точности быстрее будет работать ТС? Ведь даже если у юзера сотня плагинов, ТС не грузит все плагины при старте, а выборочно, только по мере необходимости, значит юзер наверняка не почувствует разницы в скорости.
Back to top
View user's profile Send private message
MVV



Joined: 15 Oct 2009
Posts: 4811
Location: Ростов-Дон

Post (Separately) Posted: Wed Mar 24, 2010 13:41    Post subject: Reply with quote

Да, не для всего модуля, но тем не менее нужно разместить новую копию секции кода в новом участке памяти и внести корректировку. А секции данных, доступные для записи, по умолчанию не разделяемы между копиями.

VadiMGP, можешь не объясняться, я понял, что тебе чисто лень. Абы как изменить адрес можно менее чем за минуту - и уже он будет отличаться от того, который использует большинство плагинов. А по-хорошему - тут да, надо создавать базу плагинов и т.п. Но, опять же, один раз.
А время перебазирования не может не зависеть от размера модуля, т.к. в большом модуле как правило больше адресов, подлежащих корректировке - нужно больше времени на исправление, да и читается большой модуль в память дольше. Контраргументы?
_________________
TCFS2 + TCFS2Tools: Полноэкранный режим и многое другое (обсуждение)
WINCMD.RU: AskParam, CopyTree, NTLinks, Sudo, VirtualPanel…
Back to top
View user's profile Send private message
VadiMGP



Joined: 21 Mar 2007
Posts: 1625

Post (Separately) Posted: Wed Mar 24, 2010 14:55    Post subject: Reply with quote

MVV wrote:
VadiMGP, можешь не объясняться, я понял, что тебе чисто лень.
Делать бессмысленную работу? Конечно лень. Тебе показали цифры, согласно которым работа не имеет смысла. Трудозатраты не оправдывают результат. Если ли у тебя другие оценки? Если есть - не делай из этого секрета и сообщи. Только не абстрактно "будет быстрее" а что-то более ощутимое. Хотя бы порядок. Тогда, возможно, я изменю свои выводы.

MVV wrote:
А время перебазирования не может не зависеть от размера модуля,
И какая конкретно зависимость имеется? Наносекунды? А вот мужик, который писал статью, утверждает, что время перебазирования не зависит от размера модуля. Опровергни его цифрами.
Back to top
View user's profile Send private message
CaptainFlint



Joined: 14 Dec 2004
Posts: 6151
Location: Москва

Post (Separately) Posted: Wed Mar 24, 2010 15:31    Post subject: Reply with quote

MVV wrote:
Но если системе нужно подгрузить библиотеку к некоторому процессу, и выясняется, что рекомендуемый базовый адрес уже занят, системе приходится загружать библиотеку по другому адресу в виртуальном адресном пространстве.

Теперь понял, о чём ты говоришь. Да, в таком случае так просто шарить не получится.
Однако в Википедии говорится, что винда использует некий таинственный memory mapping, который позволяет даже после таких релокаций шарить код DLL-ки, загруженной в несколько процессов, порождённых одним и тем же EXE-файлом. К случаю Тотала это как раз подходит (ситуация с одновременной работой в Тотале и других ФМ, поддерживающих плагины Тотала, думаю, слишком редка, чтобы принимать её во внимание).
_________________
Почему же, ё-моё, ты нигде не пишешь "ё"?
Back to top
View user's profile Send private message
MVV



Joined: 15 Oct 2009
Posts: 4811
Location: Ростов-Дон

Post (Separately) Posted: Wed Mar 24, 2010 16:25    Post subject: Reply with quote

VadiMGP wrote:
Делать бессмысленную работу? Конечно лень. Тебе показали цифры, согласно которым работа не имеет смысла. Трудозатраты не оправдывают результат. Если ли у тебя другие оценки? Если есть - не делай из этого секрета и сообщи. Только не абстрактно "будет быстрее" а что-то более ощутимое. Хотя бы порядок. Тогда, возможно, я изменю свои выводы.

Интересно, куда б мы скатились, если б только и делали, что искали подобные цифры и верили им на слово. На твоем месте я бы не радовался так цифрам пятнадцатилетней давности и не надеялся бы на лучшее. Доверяй, но проверяй ©. Тем более, судя по всему, кроме этих цифр у тебя больше контраргументов нет.

VadiMGP wrote:
И какая конкретно зависимость имеется? Наносекунды? А вот мужик, который писал статью, утверждает, что время перебазирования не зависит от размера модуля. Опровергни его цифрами.

Опять же, какой мужик? Алкаш с перехода? Я тоже много чего могу наговорить. А если посмотреть таблицы в статье по твоей же ссылке, разница по времени между большой и маленькой библиотекой имеется. Так что ты противоречишь сам себе.

Написанная на скорую руку утилита определила время загрузки и выгрузки по предпочтительному и иному адресу (во втором случае я специально выделял блок памяти по предпочтительному адресу функцией VirtualAlloc, заставляя систему перебазировать модуль), совокупное за 1000 итераций:

(виртуальная машина, XP, 1500 МБ ОЗУ, 1 ядро @ 2.66 ГГц)

Quote:
virtualpanel.wfx (119 КБ) - 12368 и 14681 мс
7z.dll (709 КБ) - 13039 и 23924 мс (в 2 раза!)
Imagine.dll (693 КБ) - 56491 и 59365 мс
7zip.wcx (318 КБ) - 16644 и 21110 мс
jdl_avcodec.dll (1164 КБ) - 10506 и 23764 мс
libavcodec.dll (3204 КБ) - 2894 и 53847 мс (тут даже комментировать страшно)
libavcodec.dll (сжатая UPX с --best, 1161 КБ) - 93574 мс и 99894 мс (сжатие почти свело превосходство загрузки по предпочтительному адресу на нет, но тем не менее)


Последний пример показывает отрицательный эффект сжатия.

Цифры разные для разных модулей, сложно определить зависимость падения производительности от размера модуля, но она все равно заметна, как и общая тенденция.

Желающим потестить выложил утилиту тут (требует MSVCR90.dll).

CaptainFlint wrote:
Однако в Википедии говорится, что винда использует некий таинственный memory mapping, который позволяет даже после таких релокаций шарить код DLL-ки, загруженной в несколько процессов, порождённых одним и тем же EXE-файлом.

Статья посвящена специальному коду, работающему по любому адресу - судя по всему, он содержит специальный набор инструкций, не содержащих абсолютных адресов или вычисляющих их на ходу. И, исходя из статьи, в Windows такое не используется.
Back to top
View user's profile Send private message
CaptainFlint



Joined: 14 Dec 2004
Posts: 6151
Location: Москва

Post (Separately) Posted: Wed Mar 24, 2010 19:01    Post subject: Reply with quote

MVV wrote:
Статья посвящена специальному коду, работающему по любому адресу - судя по всему, он содержит специальный набор инструкций, не содержащих абсолютных адресов или вычисляющих их на ходу. И, исходя из статьи, в Windows такое не используется.

Статья — да, посвящена PIC'у, но именно тот подраздел, на который я дал ссылку, говорит прямым текстом, что PIC в виндах не используется, а взамен есть вот такие вот полумеры.
_________________
Почему же, ё-моё, ты нигде не пишешь "ё"?
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Total Commander Forum Index -> Плагины Total Commander All times are GMT + 4 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group