GnuCOBOL не может найти динамические символы, только в последней версии Ubuntu

Что-то изменилось в последнее время, я думаю.

GnuCOBOL полагается на динамическую компоновку, символы просматриваются с помощью dlsym во время выполнения. Этот код поддержки времени выполнения CALL находится в OpenCOBOL уже около 7 лет. Он больше не работает в Ubuntu 14.04, но работает в Fedora 19/20.

ldd больше не показывает библиотеки, перечисленные с помощью -l

Например, в качестве теста Ubuntu 14.04.1

Следующая программа COBOL

   identification division.
   program-id. simple.

   procedure division.
   call "gtk_init" using
       by value 0
       by reference null
     returning omitted 
   end-call
   goback.
   end program simple.


$ cobc -x -v -lgtk-3 simple.cob
preprocessing simple.cob into /tmp/cob710_0.cob
parsing /tmp/cob710_0.cob (simple.cob)
Return status:  0
translating /tmp/cob710_0.cob into /tmp/cob710_0.c (simple.cob)
gcc -pipe -c -I/usr/local/include   -Wno-unused -fsigned-char -Wno-pointer-sign  -o "/tmp/cob710_0.o" "/tmp/cob710_0.c"
gcc -pipe  -Wl,--export-dynamic -o simple /tmp/cob710_0.o  -L/usr/local/lib -lcob -lm -lgmp -lncurses -ldb -ldl -l"gtk-3"

В бинарном файле НЕТ указаний на то, что libgtk-3.so присутствует.

./simple
libcob: Cannot find module 'gtk_init'

$ ldd simple
    linux-vdso.so.1 =>  (0x00007fff2c9fe000)
    libcob.so.1 => /usr/local/lib/libcob.so.1 (0x00007f2549b06000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2549740000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f2549439000)
    libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f25491c5000)
    libncurses.so.5 => /lib/x86_64-linux-gnu/libncurses.so.5 (0x00007f2548fa2000)
    libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f2548d78000)
    libdb-5.3.so => /usr/lib/x86_64-linux-gnu/libdb-5.3.so (0x00007f25489d6000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f25487d2000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f2549d56000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f25485b3000)

а затем в Fedora 20, та же версия компилятора (построена немного по-другому, находя ncursesw вместо ncurses - если это не является частью рассматриваемой проблемы)

$ cobc -x -v -lgtk-3 simple.cob
Command line:   cobc -x -v -lgtk-3 simple.cob 
Preprocessing:  simple.cob -> /tmp/cob20658_0.cob
Return status:  0
Parsing:        /tmp/cob20658_0.cob (simple.cob)
Return status:  0
Translating:    /tmp/cob20658_0.cob -> /tmp/cob20658_0.c (simple.cob)
Executing:      gcc -std=gnu99 -c -I/usr/local/include -pipe -Wno-unused
                -fsigned-char -Wno-pointer-sign -o "/tmp/cob20658_0.o"
                "/tmp/cob20658_0.c"
Return status:  0
Executing:      gcc -std=gnu99 -Wl,--export-dynamic -o "simple"
                "/tmp/cob20658_0.o" -L/usr/local/lib -lcob -lm -lgmp
                -lncursesw -ldb -ldl -l"gtk-3"
Return status:  0

$ ldd simple
    linux-vdso.so.1 =>  (0x00007fffae9cf000)
    libcob.so.4 => /usr/local/lib/libcob.so.4 (0x00007f4ff2548000)
    libm.so.6 => /lib64/libm.so.6 (0x0000003e5ae00000)
    libgmp.so.10 => /lib64/libgmp.so.10 (0x0000003e7a200000)
    libncursesw.so.5 => /lib64/libncursesw.so.5 (0x0000003e5d200000)
    libtinfo.so.5 => /lib64/libtinfo.so.5 (0x0000003e69800000)
    libdb-5.3.so => /lib64/libdb-5.3.so (0x0000003e6ac00000)
    libdl.so.2 => /lib64/libdl.so.2 (0x0000003e5b200000)
    libgtk-3.so.0 => /lib64/libgtk-3.so.0 (0x0000003e6ba00000)
    libc.so.6 => /lib64/libc.so.6 (0x0000003e5aa00000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003e5b600000)
    /lib64/ld-linux-x86-64.so.2 (0x0000003e5a600000)
    libgdk-3.so.0 => /lib64/libgdk-3.so.0 (0x0000003e6a800000)
    libgmodule-2.0.so.0 => /lib64/libgmodule-2.0.so.0 (0x0000003e65600000)
    libpangocairo-1.0.so.0 => /lib64/libpangocairo-1.0.so.0 (0x0000003e75200000)
    libX11.so.6 => /lib64/libX11.so.6 (0x00007f4ff2206000)
    libXi.so.6 => /lib64/libXi.so.6 (0x0000003e62600000)
    libXfixes.so.3 => /lib64/libXfixes.so.3 (0x0000003e5fe00000)
    libcairo-gobject.so.2 => /lib64/libcairo-gobject.so.2 (0x0000003e6a400000)
    libcairo.so.2 => /lib64/libcairo.so.2 (0x0000003e71000000)
    libgdk_pixbuf-2.0.so.0 => /lib64/libgdk_pixbuf-2.0.so.0 (0x0000003e6e000000)
    libatk-1.0.so.0 => /lib64/libatk-1.0.so.0 (0x0000003e75600000)
    libatk-bridge-2.0.so.0 => /lib64/libatk-bridge-2.0.so.0 (0x0000003e6c600000)
    libpangoft2-1.0.so.0 => /lib64/libpangoft2-1.0.so.0 (0x0000003e71c00000)
    libpango-1.0.so.0 => /lib64/libpango-1.0.so.0 (0x0000003e73600000)
    libfontconfig.so.1 => /lib64/libfontconfig.so.1 (0x0000003e61600000)
    libgio-2.0.so.0 => /lib64/libgio-2.0.so.0 (0x0000003e66600000)
    libgobject-2.0.so.0 => /lib64/libgobject-2.0.so.0 (0x0000003e5fa00000)
    libglib-2.0.so.0 => /lib64/libglib-2.0.so.0 (0x0000003e5e600000)
    libXinerama.so.1 => /lib64/libXinerama.so.1 (0x0000003e61e00000)
    libXrandr.so.2 => /lib64/libXrandr.so.2 (0x0000003e62200000)
    libXcursor.so.1 => /lib64/libXcursor.so.1 (0x0000003e62e00000)
    libXcomposite.so.1 => /lib64/libXcomposite.so.1 (0x0000003e74e00000)
    libXdamage.so.1 => /lib64/libXdamage.so.1 (0x0000003e67e00000)
    libwayland-client.so.0 => /lib64/libwayland-client.so.0 (0x0000003e6ec00000)
    libxkbcommon.so.0 => /lib64/libxkbcommon.so.0 (0x0000003e6b000000)
    libwayland-cursor.so.0 => /lib64/libwayland-cursor.so.0 (0x0000003e69c00000)
    libXext.so.6 => /lib64/libXext.so.6 (0x0000003e5ea00000)
    librt.so.1 => /lib64/librt.so.1 (0x0000003e5ce00000)
    libgthread-2.0.so.0 => /lib64/libgthread-2.0.so.0 (0x0000003e61a00000)
    libharfbuzz.so.0 => /lib64/libharfbuzz.so.0 (0x0000003e6f000000)
    libfreetype.so.6 => /lib64/libfreetype.so.6 (0x0000003e60e00000)
    libxcb.so.1 => /lib64/libxcb.so.1 (0x0000003e5da00000)
    libpixman-1.so.0 => /lib64/libpixman-1.so.0 (0x0000003e6f800000)
    libEGL.so.1 => /lib64/libEGL.so.1 (0x0000003e73200000)
    libpng16.so.16 => /lib64/libpng16.so.16 (0x0000003e5f600000)
    libxcb-shm.so.0 => /lib64/libxcb-shm.so.0 (0x0000003e6e800000)
    libxcb-render.so.0 => /lib64/libxcb-render.so.0 (0x0000003e70800000)
    libXrender.so.1 => /lib64/libXrender.so.1 (0x0000003e61200000)
    libz.so.1 => /lib64/libz.so.1 (0x0000003e5ba00000)
    libGL.so.1 => /lib64/libGL.so.1 (0x0000003e68200000)
    libatspi.so.0 => /lib64/libatspi.so.0 (0x0000003e6c200000)
    libdbus-1.so.3 => /lib64/libdbus-1.so.3 (0x0000003e62a00000)
    libexpat.so.1 => /lib64/libexpat.so.1 (0x0000003e60a00000)
    libffi.so.6 => /lib64/libffi.so.6 (0x0000003e5ee00000)
    libselinux.so.1 => /lib64/libselinux.so.1 (0x0000003e5ca00000)
    libresolv.so.2 => /lib64/libresolv.so.2 (0x0000003e5e200000)
    libgraphite2.so.3 => /lib64/libgraphite2.so.3 (0x0000003e6fc00000)
    libXau.so.6 => /lib64/libXau.so.6 (0x0000003e5d600000)
    libX11-xcb.so.1 => /lib64/libX11-xcb.so.1 (0x0000003e65e00000)
    libxcb-dri2.so.0 => /lib64/libxcb-dri2.so.0 (0x0000003e67200000)
    libxcb-xfixes.so.0 => /lib64/libxcb-xfixes.so.0 (0x0000003e70400000)
    libxcb-shape.so.0 => /lib64/libxcb-shape.so.0 (0x0000003e72a00000)
    libgbm.so.1 => /lib64/libgbm.so.1 (0x0000003e70c00000)
    libudev.so.1 => /lib64/libudev.so.1 (0x0000003e63200000)
    libwayland-server.so.0 => /lib64/libwayland-server.so.0 (0x0000003e74a00000)
    libglapi.so.0 => /lib64/libglapi.so.0 (0x0000003e67600000)
    libdrm.so.2 => /lib64/libdrm.so.2 (0x0000003e67a00000)
    libxcb-glx.so.0 => /lib64/libxcb-glx.so.0 (0x0000003e66e00000)
    libXxf86vm.so.1 => /lib64/libXxf86vm.so.1 (0x0000003e66200000)
    libpcre.so.1 => /lib64/libpcre.so.1 (0x0000003e5c600000)
    liblzma.so.5 => /lib64/liblzma.so.5 (0x0000003e5c200000)
    libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000003e5be00000)

Сгенерированный код C (GnuCOBOL использует промежуточные продукты C) в Ubuntu

/* Line: 4         : CALL               : simple.cob */
cob_procedure_params[0] = (cob_field *)&c_1;
cob_procedure_params[1] = NULL;
cob_glob_ptr->cob_call_params = 2;
if (unlikely(call_gtk_init.funcvoid == NULL)) {
  call_gtk_init.funcvoid = cob_resolve_cobol ("gtk_init", 0, 1);
}
call_gtk_init.funcnull ((cob_s32_t)0LL, NULL);
b_1 = 0;

И Федора

/* Line: 4         : CALL               : simple.cob */
cob_procedure_params[0] = (cob_field *)&c_1;
cob_procedure_params[1] = NULL;
cob_glob_ptr->cob_call_params = 2;
if (unlikely(call_gtk_init.funcvoid == NULL)) {
  call_gtk_init.funcvoid = cob_resolve_cobol ("gtk_init", 0, 1);
}
call_gtk_init.funcnull ((cob_s32_t)0LL, NULL);
b_1 = 0;

Я получаю хорошие результаты в Ubuntu (полные подсказки по компоновке ELF), когда gtk_init вызывается из C, а не как строка, передаваемая в cob_resolve. Протестировано с помощью gcc -o simple simple-gtk.c -lgtk-3

Так что же изменилось в предположениях, касающихся -llibname? Кажется, он не включен в данные ELF для dlopen, чтобы даже попытаться найти libgtk-3.so.

Дополнительная информация: Ошибочные строки компиляции в Ubuntu действительно выглядят так, как будто это должно работать. (Ошибка ГТК)

$ cobc -x -v -lgkt-3 simple.cob
Command line:   cobc -x -v -lgkt-3 simple.cob 
Preprocessing:  simple.cob -> /tmp/cob13556_0.cob
Return status:  0
Parsing:        /tmp/cob13556_0.cob (simple.cob)  
Return status:  0
Translating:    /tmp/cob13556_0.cob -> /tmp/cob13556_0.c (simple.cob)
Executing:      gcc -std=gnu99 -c -I/usr/local/include -pipe -Wno-unused
                -fsigned-char -Wno-pointer-sign -o "/tmp/cob13556_0.o"
                "/tmp/cob13556_0.c"
Return status:  0
Executing:      gcc -std=gnu99 -Wl,--export-dynamic -o "simple"
                "/tmp/cob13556_0.o" -L/usr/local/lib -lcob -lm -lgmp -lncurses
                -ldb -ldl -l"gkt-3"
/usr/bin/ld: cannot find -lgkt-3
collect2: error: ld returned 1 exit status
Return status:  256

И все же, с правильной строкой компиляции, ELF не показывает никаких намеков на связь с gtk-3.

Я уже некоторое время ломаю голову над этим. Ищу намек на то, какие предположения изменились с Ubuntu и gcc и/или ld и/или dlopen dlsym.

Пакет open-cobol работает в репозиториях Debian и Ubuntu уже несколько лет. Даже более старые версии GnuCOBOL (GNU Cobol и/или OpenCOBOL) в Ubuntu теперь терпят неудачу. Что-то изменилось, и мы не получили записку. Более чем готов изменить исходные коды компилятора, но сначала ищет дружественные идеи StackOverflow.

Похоже, это не проблема локальной среды, поскольку эта проблема Ubuntu проявляется и у других. Это также похоже на один из тех DOH! просто исправить проблемы.

Более чем готов добавить больше журналов компиляции, LD_DEBUG = все дампы или трассировки и т. д.


person Brian Tiffin    schedule 07.10.2014    source источник


Ответы (2)


Похоже, это изменение, внесенное в драйвер компилятора для Ubuntu — оно добавляет параметр --as-needed в строку компиляции при отправке кода collect2, также известному как компоновщик.

Чтобы понять, что происходит, нам нужно разобрать выполнение cobc больше, чем показано:

cobc -x -v simple.cob -lgtk-3
preprocessing simple.cob into /tmp/cob2743_0.cob
translating /tmp/cob2743_0.cob into /tmp/cob2743_0.c
gcc -pipe -c  -Wno-unused -fsigned-char -Wno-pointer-sign  -o /tmp/cob2743_0.o /tmp/cob2743_0.c
gcc -pipe  -Wl,--export-dynamic -o simple /tmp/cob2743_0.o  -L/usr/lib -lcob -lm -lgmp -lncurses -ldb -ldl -lgtk-3

если мы разобьем его на создание кода C, а затем скомпилируем, мы получим:

cobc -C -x -v simple.cob
gcc -pipe -c  -Wno-unused -fsigned-char -Wno-pointer-sign -o simple.o simple.c
gcc -pipe -Wl,--export-dynamic -o simple simple.o  -L/usr/lib -lcob -lm -lgmp -lncurses -ldb -ldl -lgtk-3

Нам нужно далее разобрать последнюю строку gcc на:

gcc -### -pipe -Wl,--export-dynamic -o simple simple.o  -L/usr/lib -lcob -lm -lgmp -lncurses -ldb -ldl -lgtk-3

что дает в качестве вывода:

 /usr/lib/gcc/x86_64-linux-gnu/4.8/collect2 "--sysroot=/" --build-id --eh-frame-hdr -m elf_x86_64 "--hash-style=gnu" --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro -o simple /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.8/crtbegin.o -L/usr/lib -L/usr/lib/gcc/x86_64-linux-gnu/4.8 -L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../.. --export-dynamic simple.o -lcob -lm -lgmp -lncurses -ldb -ldl -lgtk-3 -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.8/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crtn.o

Проблема заключается в наличии первой опции --as-needed - она ​​переворачивает все явные опции -l в командной строке - если в .o, составляющих файл, который зависит от библиотеки, ничего не найдено, она выиграла не подключайте библиотеку - это точный случай динамической загрузки.

Кажется, это имеется в виду со времен Oneiric.

Этот простейший обходной путь добавляет:

COB_LDFLAGS=-Wl,--no-as-needed

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

person Petesh    schedule 12.01.2015
comment
Петеш; Спасибо. Это войдет в исходное дерево компилятора, надеюсь, сегодня. - person Brian Tiffin; 14.01.2015

Из вывода видно, что код C, который динамически ищет gtk_init, не знает о загрузке фактического libgtk-3.so общего объекта во время выполнения.

Вы можете скомпилировать с cobc, используя опцию -fstatic-call. Это вызовет ваши библиотечные функции, такие как gtk_init, напрямую, а не через вызовы dlopen/dlsym . Более подробную информацию об этой опции можно найти на информационных страницах с помощью команды info opencobol:

С параметрами компилятора -fstatic-call более эффективный код будет генерироваться следующим образом:

subr(X);

Обратите внимание, что эта опция эффективна только тогда, когда имя вызываемой программы является буквальным (например, CALL "subr".'). With a data name (likeCALL SUBR.'), программа по-прежнему вызывается динамически.

Если вы хотите пойти по динамическому маршруту, я могу только предложить сообщить вашему приложению Cobol, какие именно динамические объекты вы хотите загружать во время выполнения. Для этого вы можете установить переменную среды COB_PRE_LOAD до запуска вашего приложения. Информацию об этой переменной среды можно найти в этой документации по Open Cobol. В частности, говорится:

COB_PRE_LOAD — это переменная среды, которая определяет, какие модули динамической компоновки включаются в выполнение.

$ cobc occurl.c
$ cobc occgi.c
$ cobc -x myprog.cob
$ export COB_PRE_LOAD=occurl:occgi
$ ./myprog

Это позволит преобразователю ссылок во время выполнения OpenCOBOL найти точку входа для CALL «CBL_OC_CURL_INIT» в модуле instancel.so. Примечание: модули, перечисленные в переменной среды COB_PRE_LOAD, НЕ имеют расширений. OpenCOBOL будет делать правильные вещи на различных платформах.

Вы можете сделать это несколькими способами (используя bash):

COB_PRE_LOAD=libgtk-3 ./simple

Это установит COB_PRE_LOAD для использования libgtk-3.so (вы опускаете .so) запускаете свое приложение, а когда закончите, вернете COB_PRE_LOAD к тому, что было. Вы также можете использовать export для установки переменной среды на время вашего сеанса с помощью:

export COB_PRE_LOAD=libgtk-3 
./simple

Вы можете указать несколько общих объектов, используя COB_PRE_LOAD, разделив их двоеточием. Итак, если вам нужны, например, libgtk-3 и libgmp, вы можете сделать это:

COB_PRE_LOAD=libgtk-3:libgmp ./simple
person Michael Petch    schedule 28.10.2014
comment
Спасибо, Майкл, но на самом деле это не основная проблема. Функция динамической ссылки GnuCOBOL работает уже давно и совсем недавно сломалась в Ubuntu. Приведенные выше командные строки отлично работают в Fedora. Компиляции в Ubuntu не оставляют никаких подсказок в объектах ELF библиотек -l, упомянутых в командной строке. Это новая поломка. (Я хранитель FAQ, на который вы ссылаетесь). У вас хороший ответ, но здесь есть еще кое-что. GnuCOBOL должен работать с динамическими ссылками на библиотеки, он работал и работает везде, кроме недавней Ubuntu. - person Brian Tiffin; 04.11.2014
comment
Спасибо за наводку. Я не знал, что вы (ОП) были хранителем FAQ. Чего мой ответ не говорит, так это того, что я действительно попробовал все это на полностью обновленной версии 14.04, и использование COB_PRE_LOAD действительно работает. Если я его не использую, я получаю вашу ошибку с gtk_init. Мне любопытно, действительно ли COB_PRE_LOAD решает проблему для вас, если вы пытаетесь его использовать? (Если это не так, это может указывать на то, что что-то еще не так только с вашей средой?). - person Michael Petch; 04.11.2014
comment
Мне любопытно, как это когда-либо работало с тех пор, как выглядела поздняя привязка (на мой беглый взгляд) - как Cobol узнает, какие общие объекты загружаются во время выполнения, если вы не сказали что-то вроде COB_PRE_LOAD - если в других средах нет еще какой-то статический компонент в игре, и сгенерированный C делает что-то немного другое, я думаю, один очевидный вопрос заключается в следующем. Вы используете одну и ту же версию Cobol на всех своих платформах? (например, Ubuntu, Fedora и т. д.) - person Michael Petch; 04.11.2014
comment
Ключ компилятора -l (минус ell) обычно оставляет подсказку в ELF, dlopen и dlsym с заданным местом для начала. В настоящее время в Ubuntu -l не оставляет никаких раундов трассировки. ldd обычно показывает библиотеку ссылок -l как зависимость. И делает, например, под Fedora, и раньше под Ubuntu. У нас отсутствуют некоторые изменения в ld.so или другой флаг динамической ссылки. - person Brian Tiffin; 04.11.2014
comment
Возможно, оптимизация компоновщика определила, что, хотя вы добавили эти общие объекты во время компоновки, он обнаружил, что на них никогда не ссылались, и оптимизировал их (включая подсказку, на которую вы полагались). Если бы это было так, компоновщик не знал бы, что вы на самом деле используете dlopen() и т. д. для поздней привязки к ним. Мне пришлось бы провести несколько экспериментов, чтобы увидеть, действительно ли это происходит и есть ли решение. - person Michael Petch; 04.11.2014
comment
Я надеюсь, что это простая вещь, отсутствующая опция или конфигурация. И спасибо, что заглянул, Майкл. Я некоторое время ломал над этим голову. - person Brian Tiffin; 04.11.2014
comment
Мое мнение, что это должна быть какая-то оптимизация. Если я возьму вывод simple.c из вашей примерной программы и после включения добавлю эти 2 строки, это сработает. extern void gtk_init(); void (*gtk_init_ptr)() = gtk_init; . Хотя я нигде в коде не использую указатель, этого достаточно, чтобы убедить компилятор и компоновщик, что я действительно использую библиотеку. Я не нашел способ изменить это поведение. На самом деле это может быть хорошим вопросом для списка рассылки gcc. - person Michael Petch; 04.11.2014