На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
Модераторы: Qraizer
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Статическая линковка 2х dll с одинаков названой функцией
    Вопрос не про язык,а про линковку. В частности линковку через link.exe студийный или lld-link из LLVM

    Есть MyDll1.lib в которой объявлена функция MyFunc
    Есть MyDll2.lib в которой объявлена функция с таким же именем MyFunc
    Исходники либ недоступны.
    И есть проект, который хочет статически слинковаться с обоими dll'ками и использовать эти функции. Собственно вопрос, КАК ??

    В дельфе подобное делается пример так:

    ExpandedWrap disabled
      function MyFunc1: Integer; extrenal 'MyDll1.dll' name 'MyFunc';
      function MyFunc2: Integer; extrenal 'MyDll2.dll' name 'MyFunc';


    В C# (но тут не совсем корректное сравнение, .NET AFAIR динамически dll грузит)
    ExpandedWrap disabled
      [DllImport("MyDll1.dll.dll", EntryPoint = "MyFunc")]
      public static extern int MyFunc1();
      [DllImport("MyDll2.dll.dll", EntryPoint = "MyFunc")]
      public static extern int MyFunc2();
      Цитата jack128 @
      И есть проект, который хочет статически слинковаться с обоими dll'ками и использовать эти функции. Собственно вопрос, КАК ??

      В дельфе подобное делается пример так:

      ExpandedWrap disabled
        function MyFunc1: Integer; extrenal 'MyDll1.dll' name 'MyFunc';
        function MyFunc2: Integer; extrenal 'MyDll2.dll' name 'MyFunc';

      jack128, так мы же не знаем, что на самом деле
      делает Дэлфи или C#.
      Возможно, обнаружив соотв. строки они явно грузят dll,
      узнают адреса требуемых функций и присваивают их значения
      указателям с другими именами.
      Само присутствие вышеприведённых строк как бы намекает на это.
        Создаём два DEF-файла. MyDll1.def
        ExpandedWrap disabled
          LIBRARY MyDll1
          EXPORTS
            MyFunc1 = MyFunc
        и MyDll2
        ExpandedWrap disabled
          LIBRARY MyDll2
          EXPORTS
            MyFunc2 = MyFunc
        Создаём наши DLL с указанием этих DEF и получаем библиотеки импорта, в которых MyFunc экспортируется по нужным именам. Используем эти библиотеки для сборки нашего приложения — профит.
        Если DLL уже в наличии и нет возможности их пересобрать, то вместо компиляции в DLL используем lib для получения библиотек импорта прямо из DEF. Но что-то из глубин памяти мне подсказывает, что MSный lib делает это криво и не переименовывает. Возможно, понадобится поискать другие инструменты, безглючные.
        Сообщение отредактировано: Qraizer -
          Так, наверно я неправильный термин использовал. Не статическая линковка, а статическая загрузка. Тут используют термины implicit linking, static load or load-time dynamic linking. В общем когда линкер при генерации exe прописывает в таблицу импорта названия dll'ек/функций в этих dll'ках. Никаких адреса, как и сами dll при сборке приложения при таком подходе не нужны. Нужны только название dll и название функций.

          Добавлено
          Цитата Qraizer @
          Создаём наши DLL с указанием этих DEF

          DLL сторонние, пересобрать я их не могу

          Добавлено
          Цитата Qraizer @
          то MSный lib делает это криво и не переименовывает.

          Ага. Возможно. Я как раз по предложенной тобой схеме пребывал, у меня не получилось. В комплекте llvm наверняка есть аналог lib. Поищем.
            Цитата jack128 @
            В общем когда линкер при генерации exe прописывает в таблицу импорта названия dll'ек/функций в этих dll'ках. Никаких адреса, как и сами dll при сборке приложения при таком подходе не нужны. Нужны только название dll и название функций.
            Та не, это было понятно. Есть такая штука, как библиотека импорта, и вот она, в отличие от просто библиотеки, в которой функции и данные, как раз описывает ссылки на импортируемые из DLL функции и данные. Ну, т.е. библиотека по любому какая-то есть, но для связи с DLL используется некий особый её формат. (На самом деле нет, просто там другие атрибуты у связываемых сущностей, но не суть.) Эту библиотеку как-то надо получить, и проще всего это делается прямо при сборке самой DLL, линкер её автоматом создаёт. Тут даже DEF очень часто необязателен, т.к. линкеру все экспортируемые имена известны, он же как раз эту DLL собирает. И только в особых случаях, типа твоего, DEF-таки нужен. Но в твоём случае это не подходит, так что нужно использовать не "линкер", а "библиотекарь", но скармливать ему нужно всё тот же DEF, где всё описано.

            P.S. В крайнем случае можно написать свою DLL-прокси. В ней сделать функции с разными именами, а каждая из них будет динамически звать нужную из нужно DLL. К ней будет легко присобачить статическую загрузку, а то, что она внутри использует динамическую, будет скрыто и не мешает.
              Цитата Qraizer @
              EXPORTS
                MyFunc1 = MyFunc


              Нет, это не подходит. Эта штука описывает таблицу экспорта и используется при сборке библиотеки.
              Пусть у нас есть есть 1.obj в котором сидит функция MyFunc. тогда подсунув линкеру объектник и def файл (link /dll 1.obj 1.def) теоретически можно получить dll c экспортируемой функций MyFunc1.
              И в lib файле будет сидеть MyFunc1.

              Насколько я понял, в синтаксисе def есть секция IMPORTS (см тут), но применить её у меня пока не получается. lib ничего про неё не знает по крайней мере

              Цитата Qraizer @
              P.S. В крайнем случае можно написать свою DLL-прокси. В ней сделать функции с разными именами, а каждая из них будет динамически звать нужную из нужно DLL. К ней будет легко присобачить статическую загрузку, а то, что она внутри использует динамическую, будет скрыто и не мешает.

              да понятно, что костылей можно нагородить всяких. Но это не наш метод.
              Сообщение отредактировано: jack128 -
                Цитата jack128 @
                Нет, это не подходит. Эта штука описывает таблицу экспорта и используется при сборке библиотеки.
                Подходит. При сборке DLL линкер обычно тут же создаёт библиотеку импорта .LIB к ней, да, но библиотеку импорта можно получить и без построения .DLL, только лишь на основе .DEF, я именно это и предложил. А .DEF в свою очередь можно получить с помощью какого-нибудь dumpbin или любой другой утили, что покажет весь экспорт этой .DLL

                Добавлено
                Цитата jack128 @
                Насколько я понял, в синтаксисе def есть секция IMPORTS (см тут), но применить её у меня пока не получается. lib ничего про неё не знает по крайней мере
                Вот чем-чем, а импортом никогда не пользовался. Если я правильно его понимаю, такой DEF ты должен применить к своему приложению, а не библиотекам, так что lib тут будет ни причём

                Добавлено
                P.S. Проверил MSный lib. Баг в натуре есть. Открыл проблему в саппорте, жду разъяснений. Не исключено, что мне расскажут, какой я дебил, посмотрим.
                Сообщение отредактировано: Qraizer -
                  Цитата Qraizer @
                  Открыл проблему в саппорте, жду разъяснений

                  А ссылочка публичная есть??
                    Цитата jack128 @
                    да понятно, что костылей можно нагородить всяких. Но это не наш метод.

                    Попробовать отредактировать эксторт и .lib - файл
                    одной из dll. Вручную заменить имя проблемной функции.
                      Цитата jack128 @
                      А ссылочка публичная есть??
                      lib.exe does not rename export names from DLL when renaming requested by .DEF or /EXPORT: command line option.
                        Цитата jack128 @
                        Исходники либ недоступны.
                        И есть проект, который хочет статически слинковаться с обоими dll'ками и использовать эти функции. Собственно вопрос, КАК ??

                        jack128, совсем не понятно, в чём проблема.
                        Если ты не из старт-апа собрался вызывать функции dll, тогда:

                        Предположим, статически слинковались с dll.
                        В каждой dll полно своих функций, но есть одна проблемная - с одинаковым именем.
                        При старте приложения обе dll загружены в память.
                        1. Получим на них handle.
                        2. Получим адреса на процедуры с проблемными именами.
                        3. Присвоим адреса указателям (с уникальными именами) на процедуры.
                        Это всё.
                        Не исключено, что Дэлфи делает именно это.
                        Сообщение отредактировано: ЫукпШ -
                          Хм. Баг в lib.exe подтверждён. Уже хорошо. Жаль, что так поздно, если мне не изменяет память, ему около десяти лет как минимум.
                          ЫукпШ, статически слинковать не получится. Хороший линкер даст эррор о множественном определении, но это если хороший. В точки зрения Стандарта языка мы тут имеем нарушение ODR, т.к. одна и та же сущность определена по-разному, а это "всего лишь" неопределённое поведение, не обязательно долженствующее быть обнаруженное средствами разработки.
                            Цитата Qraizer @
                            ЫукпШ, статически слинковать не получится. Хороший линкер даст эррор о множественном определении,

                            Qraizer, я просто проверил это.
                            Простым как табуретка тестом (случайно была заготовка).
                            Всё получится.
                            Что касается определения "хороший линкер".
                            Тут я никак не могу согласиться.
                            Если функции с одним именем имеются в наличии в разных
                            dll, то это разные сущности - однозначно.
                            Доступ к ним должен быть обеспечен, что и происходи в действительности.
                            И то, что возникают потенциальные проблемы в из использовании
                            скорее недостаток компилятора.
                            В Дэлфи решение простое и удобное.
                            Но можно и получше придумать - но не сделали.
                            Для разрешения таких конфликтов предназначен "namespace".
                            Скрытый текст

                            Например, взять и разрешить окружать описанные функции из
                            dll namespace-ом. С тем, чтобы иметь возможность
                            массового переименования всех dll-ных функций для конкретного приложения.
                            Или как то так:
                            ExpandedWrap disabled
                              namespace SomeDll
                              {
                              #pragma comment(lib,"SomeDll.lib")
                              }


                            А для с++ надо знать пару функций WinApi.
                            Сообщение отредактировано: ЫукпШ -
                              ЫукпШ, ты можешь как угодно с любых сторон рассматривать то, что можешь себе представить.
                              Цитата ЫукпШ @
                              Что касается определения "хороший линкер".
                              Тут я никак не могу согласиться.
                              Твоё представление о том, как правильно, никоим образом не меняет положений Стандарта языка. В нём есть правило одного определения. Точка. DLL с разными функциями, имеющие одинаковые имена, это правило нарушают. На этом всё.
                              Если нет, то попробуй слинковать с приложением две функции с одинаковыми именами из разных библиотек. Простых lib, не dll. Хочешь тестов? Я тебе их накидаю три варианта. Один будет звать дважды одну и ту же, другой другую, третий оба раза разные. Обтестироваться можно будет по полной программе: неопределённое поведение по всей красе.
                              Цитата ЫукпШ @
                              Если функции с одним именем имеются в наличии в разных
                              dll, то это разные сущности - однозначно.
                              Чтобы они стали разными, их имена должны различаться. Для этого существует квалификация. Для экспортируемых из DLL функций этого сделано не было их авторами, а сырцов нет.
                              Цитата ЫукпШ @
                              И то, что возникают потенциальные проблемы в из использовании
                              скорее недостаток компилятора.
                              Это недостаток структурного WinAPI. В объектом COM такого нет, там любой метод квалифицирован именем его интерфейса.
                              DLL ничем не отличаются от LIB, они точно также являются частью загруженного приложения. И на них в полной мере распространяется ODR. Не можешь обеспечить разделение сущностей по уникальным именам, получишь UB. А то, что их можно разделить динамической загрузкой, никому не новость, вот только jack128 это не устраивает.

                              Добавлено
                              Цитата ЫукпШ @
                              В Дэлфи решение простое и удобное.
                              Оно делает ровно то же, что и решение с DEF, только средствами языка, а не ОС.
                                Цитата Qraizer @
                                Это недостаток структурного WinAPI. В объектом COM такого нет, там любой метод квалифицирован именем его интерфейса.

                                Это недостаток конкретно линкеров. В секции импорта любая функция квалифицирована именем dll.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0464 ]   [ 17 queries used ]   [ Generated: 25.04.24, 08:21 GMT ]