OberonCore
https://forum.oberoncore.ru/

ElfLinker
https://forum.oberoncore.ru/viewtopic.php?f=34&t=5459
Страница 7 из 9

Автор:  Димыч [ Понедельник, 07 Ноябрь, 2016 19:23 ]
Заголовок сообщения:  Re: ElfLinker

Я, честно говоря, так и не понял, как переменные отображаются в память из модулей-dll.
Т.е. как заставить загрузчик Linux связать stdin с местом в памяти я понимаю, а вот как привязать Libc.stdin к этому участку - нет.
Похоже, надо читать символьный файл дополнительно.

Автор:  Иван Денисов [ Понедельник, 07 Ноябрь, 2016 19:35 ]
Заголовок сообщения:  Re: ElfLinker

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

Автор:  Valery Solovey [ Понедельник, 07 Ноябрь, 2016 19:55 ]
Заголовок сообщения:  Re: ElfLinker

А наоборот сделать можно? Не переменную привязать к другой, внешней библиотеке, а библиотеку ко внешней переменной. То есть, на этапе компоновки указать библиотеке (или модулю), что вот эта переменная находится вот по такому смещению в стеке или по такому адресу в куче.

Автор:  Trurl [ Понедельник, 07 Ноябрь, 2016 22:35 ]
Заголовок сообщения:  Re: ElfLinker

Можно не импортировать, а экспортировать. :roll: По идее должно работать.

Автор:  Trurl [ Вторник, 08 Ноябрь, 2016 09:43 ]
Заголовок сообщения:  Re: ElfLinker

Действительно, работает.
Добавляем в LnkBase
Код:
PROCEDURE ExportVar*(mod: Module; IN name: STRING; addr: INTEGER);
   VAR sym: Symbol;
BEGIN
   NEW(sym);
   sym.name := name$;
   sym.sect := mod.vars;
   sym.addr := addr;
   sym.next := expList;
   expList := sym;
   INC(expCount);
END ExportVar;

Правим CollectExports
Код:
   
PROCEDURE CollectExports(mod: Module);
VAR p, numobj: INTEGER;
      id, vis, mode, addr: INTEGER;
      name: StrPtr;
BEGIN
   IF ~mod.exported THEN
      GetDir(mod, p, numobj);
      WHILE numobj > 0 DO
         id := DWord(mod,  p + 8);   
         mode := id MOD 16;
         vis := id DIV 16 MOD 16;
         IF (vis # mInternal) THEN
            name := GetPName(mod, id DIV 256);
            addr := DWord(mod,  p + 4);
            IF (mode = mProc) THEN   LB.ExportProc(mod, name$, addr)   
            ELSIF (mode = mVar) THEN   LB.ExportVar(mod, name$, addr)   
            END;
         END;
         DEC(numobj); INC(p, 16)
      END;
      mod.exported := TRUE;
   END;
END CollectExports;      

Теперь объявляем в модуле
Код:
VAR  stdin*, stdout*, stderr* : Libc.PtrFILE;
и экспортируем его. Voila.

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

Автор:  Димыч [ Вторник, 08 Ноябрь, 2016 12:12 ]
Заголовок сообщения:  Re: ElfLinker

Это уже сделано.
Я добавил процедуры LB.ExportVar и Load.ExportVariable, которые делают то, что нужно.
Проблема в том, что переменные, экспортируемые таким способом, должны находиться НЕ в модуле-dll.
И тут есть три варианта:
  • экспортируем переменные вручную, как это сделано для переменных __progname и environ во FreeBSD;
  • экспортируем все переменные во всех модулях подряд, но следим, чтобы не было переменных в dll-модулях;
  • собираем все требуемые переменные в один модуль и потом экспортируем только один модуль.

У меня не получилось экспортировать переменные из Libc. Пробежался по подсистеме Win, там вообще нет переменных в dll-модулях.

Так что, полагаю, можно попробовать остановиться на последнем варианте и сделать процедуру ExportModuleVars(mod) для единовременного вызова при любой компоновке.

Автор:  Trurl [ Вторник, 08 Ноябрь, 2016 13:02 ]
Заголовок сообщения:  Re: ElfLinker

Димыч писал(а):
Проблема в том, что переменные, экспортируемые таким способом, должны находиться НЕ в модуле-dll.

Ну конечно. То, что в dll, импортируется, а не экспортируется.

Автор:  Trurl [ Вторник, 08 Ноябрь, 2016 13:08 ]
Заголовок сообщения:  Re: ElfLinker

Димыч писал(а):
Пробежался по подсистеме Win, там вообще нет переменных в dll-модулях.

В Windows нельзя импортировать переменную из dll. Точнее, можно, но не с этим компилятором. Там схема напоминает GOT, нужен дополнительный уровень косвенности.

Автор:  Иван Денисов [ Среда, 09 Ноябрь, 2016 09:51 ]
Заголовок сообщения:  Re: ElfLinker

Trurl писал(а):
Только проблема возникает. Поскольку имена переменных экпортируются без префикса, надо следить, чтобы не смешивались.

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

Автор:  prospero78 [ Среда, 09 Ноябрь, 2016 13:00 ]
Заголовок сообщения:  Re: ElfLinker

Хм... Строго говоря в .Net DLL переменную экспортировать вполне себе можно. Как и объекты.

Автор:  Димыч [ Среда, 09 Ноябрь, 2016 16:14 ]
Заголовок сообщения:  Re: ElfLinker

Димыч писал(а):
Это уже сделано.
...
...
Так что, полагаю, можно попробовать остановиться на последнем варианте и сделать процедуру ExportModuleVars(mod) для единовременного вызова при любой компоновке.

В общем я так и сделал. ConsHello0 собирается хорошо.
Добавлен модуль LinLibcVars, из Libc переменные убраны, добавлен вызов процедуры ExportModuleVars.

Вложения:
LinuxGUI.tar.gz [3.05 МБ]
Скачиваний: 1616

Автор:  Димыч [ Среда, 09 Ноябрь, 2016 16:33 ]
Заголовок сообщения:  Re: ElfLinker

Возможно надо перекомпилировать все модули в цепочке сборки.

Автор:  Alexander Shiryaev [ Среда, 09 Ноябрь, 2016 22:05 ]
Заголовок сообщения:  Re: ElfLinker

Trurl писал(а):
Навскидку 3 варианта:
1. Использовать функции, работающие со стандартными потоками (printf, scanf).
2. Роботать с дескрипторами (read, write).
3. Переоткрыть дескрипторы с помощью fdopen.

Убрал stdin из Libc и реализовал 3-й вариант.

Автор:  Иван Денисов [ Четверг, 10 Ноябрь, 2016 22:08 ]
Заголовок сообщения:  Re: ElfLinker

Alexander Shiryaev писал(а):
Trurl писал(а):
Навскидку 3 варианта:
1. Использовать функции, работающие со стандартными потоками (printf, scanf).
2. Роботать с дескрипторами (read, write).
3. Переоткрыть дескрипторы с помощью fdopen.

Убрал stdin из Libc и реализовал 3-й вариант.

Александр, есть еще h_errno в LinNet.

Автор:  Димыч [ Пятница, 11 Ноябрь, 2016 07:04 ]
Заголовок сообщения:  Re: ElfLinker

Alexander Shiryaev писал(а):
Убрал stdin из Libc и реализовал 3-й вариант.

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

Для этого приложение указывает загрузчику "разъем", куда нужно "воткнуть" значение дескриптора.
Когда мы экспортируем переменные в ELF, мы и помещаем слоты переменных так, чтобы libc могла их использовать.
Поэтому мне подход с экспортом кажется более правильным.

Хотя, еще раз, подход с переоткрытием дескрипторов тоже уместен.

Автор:  Trurl [ Пятница, 11 Ноябрь, 2016 08:50 ]
Заголовок сообщения:  Re: ElfLinker

Ну, строго говоря, дескрипторами занимается ядро. Libc создает обертки-потоки для доступа к файлам. То, что мы не знаем как она это делает, неважно. Мы делаем точно так же, вызывая fdopen. А проблемы могут быть. Если включена буферизация, а мы начнем вызывать попеременно printf/fprintf, то вывод может перемешаться.

А трюк с экпортом работает из-за особенностей динамической линковки. В libc есть свои stdin/stdout/stderr, но по умочанию поиск символов начинается с исполнимого файла. Но если кто-от соберет libc с флагом DT_SYMBOLIC, будет облом.

Автор:  Alexander Shiryaev [ Пятница, 11 Ноябрь, 2016 11:08 ]
Заголовок сообщения:  Re: ElfLinker

Димыч писал(а):
stdin и stdout инициализирует libc и, строго говоря, мы не знаем, как она это делает.
Приложение по факту получает готовый дескриптор. Который затем использует
в своих целях.
...
Для этого приложение указывает загрузчику "разъем", куда нужно "воткнуть" значение дескриптора.

Вот так в OpenBSD, например (а вот fdopen).
B ещё там нет на экспорт переменных stdin, stdout, stderr. Вместо них -- __sF.
Код:
#define stdin   (&__sF[0])
#define stdout  (&__sF[1])
#define stderr  (&__sF[2])

И приходилось к ним получать доступ так:
Код:
MODULE LinLibc;

   ...

   VAR
      (* OpenBSD: stdin, stdout, stderr *)
         __sF*: ARRAY [untagged] 3 OF FILE; (* OpenBSD /usr/include/stdio.h *)
            (*
               stdin = SYSTEM.ADR(__sF[0])
               stdout = SYSTEM.ADR(__sF[1])
               stderr = SYSTEM.ADR(__sF[2])
            *)

   ...

END LinLibc.

В FreeBSD:
Код:
VAR stdin* ["__stdinp"]: PtrFILE;

Автор:  Димыч [ Пятница, 11 Ноябрь, 2016 11:29 ]
Заголовок сообщения:  Re: ElfLinker

Какие же все-таки разные подходы в ОС...
Согласен, тут без fdopen сложно.

Автор:  Alexander Shiryaev [ Пятница, 11 Ноябрь, 2016 12:22 ]
Заголовок сообщения:  Re: ElfLinker

Иван Денисов писал(а):
Alexander Shiryaev писал(а):
Trurl писал(а):
Навскидку 3 варианта:
1. Использовать функции, работающие со стандартными потоками (printf, scanf).
2. Роботать с дескрипторами (read, write).
3. Переоткрыть дескрипторы с помощью fdopen.

Убрал stdin из Libc и реализовал 3-й вариант.

Александр, есть еще h_errno в LinNet.

Исправил.
В Linux h_errno на самом деле нет, есть __h_errno_location()

А вот в OpenBSD переменная h_errno есть, а функции, аналогичной __h_errno_location(), нет ;(

Автор:  Trurl [ Пятница, 11 Ноябрь, 2016 12:50 ]
Заголовок сообщения:  Re: ElfLinker

h_errno deprecated в posix-2001 и совсем удалена в posix-2008, надо от неё избавляться.

Страница 7 из 9 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/