перемещение записей в общей библиотеке - PullRequest
4 голосов
/ 20 августа 2011

Я расследую перемещение общих библиотек и столкнулся с чем-то странным.Рассмотрим этот код:

int myglob;

int ml_util_func(int p)
{
    return p + 2;
}

int ml_func2(int a, int b)
{
    int c = ml_util_func(a);
    return c + b + myglob;
}

Я скомпилирую его в не-PIC разделяемую библиотеку с gcc -shared.Я делаю это на 32-битной Ubuntu, работающей на x86.

Полученный .so имеет запись перемещения для вызова на ml_util_func в ml_func2.Вот вывод objdump -dR -Mintel для ml_func2:

0000050d <ml_func2>:
 50d:   55                      push   ebp
 50e:   89 e5                   mov    ebp,esp
 510:   83 ec 14                sub    esp,0x14
 513:   8b 45 08                mov    eax,DWORD PTR [ebp+0x8]
 516:   89 04 24                mov    DWORD PTR [esp],eax
 519:   e8 fc ff ff ff          call   51a <ml_func2+0xd>
                        51a: R_386_PC32 ml_util_func
 51e:   89 45 fc                mov    DWORD PTR [ebp-0x4],eax
 521:   8b 45 0c                mov    eax,DWORD PTR [ebp+0xc]
 524:   8b 55 fc                mov    edx,DWORD PTR [ebp-0x4]
 527:   01 c2                   add    edx,eax
 529:   a1 00 00 00 00          mov    eax,ds:0x0
                        52a: R_386_32   myglob
 52e:   8d 04 02                lea    eax,[edx+eax*1]
 531:   c9                      leave  
 532:   c3                      ret    
 533:   90                      nop

Обратите внимание на перемещение R_386_PC32 в инструкции call.

Теперь мой вопрос почемуэто перемещение необходимо ?e8 означает "относительный вызов ..." в x86, и поскольку ml_util_func определено в том же объекте, несомненно, компоновщик может вычислить относительное смещение между ним и вызовом, не оставляя его динамическому загрузчику?

Интересно, что если ml_util_func объявлено static, перемещение исчезает, и компоновщик корректно вычисляет и вставляет смещение.Что из-за того, что ml_util_func также экспортируется, что делает компоновщик ленивым об этом?

PS: Я специально играю с кодом, отличным от PIC, чтобы понять перемещения во время загрузки.

Ответы [ 2 ]

4 голосов
/ 20 августа 2011

Не могу найти почему, но это комментарий binutils по этому поводу:

binutils-2.11.90-20010705-src.tar.gz / bfd / elf32-i386.c: 679

      /* If we are creating a shared library, and this is a reloc
         against a global symbol, or a non PC relative reloc
         against a local symbol, then we need to copy the reloc
         into the shared library.  However, if we are linking with
         -Bsymbolic, we do not need to copy a reloc against a
         global symbol which is defined in an object we are

Я думаю, это перемещение создано, чтобы позволить пользователю перегружать любой глобальный символ в библиотеке. И, похоже, -Bsymbolic отключает эту способность и не будет генерировать перемещение символа из самой библиотеки.

http://www.rocketaware.com/man/man1/ld.1.htm

-Bsymbolic Эта опция заставляет все символические ссылки в выводе быть решено в этом сеансе редактирования ссылки. Единственное оставшееся время выполнения требования к перемещению являются базовыми относительно перемещений, т.е. перевод по адресу загрузки. Неспособность решить любая символическая ссылка приводит к сообщению об ошибке.

Более подробное описание различных режимов -B и ограничений (C ++) здесь:

http://developers.sun.com/sunstudio/documentation/ss12/mr/man1/CC.1.html

-B связывание

           Specifies whether a library binding for linking is
           symbolic, dynamic (shared), or static (nonshared).

           -Bdynamic is the default.  You can use the -B
           option several times on a command line.

           For more information on the -Bbinding option, see
           the ld(1) man page and the Solaris documentation.


           -Bdynamic directs the link editor to look for
           liblib.so files. Use this option if you want
           shared library bindings for linking.  If the
           liblib.so files are not found, it looks for
           liblib.a files.

           -Bstatic directs the link editor to look only for
           liblib.a files. The .a suffix indicates that the
           file is static, that is, nonshared.  Use this
           option if you want nonshared library bindings for
           linking.

           -Bsymbolic forces symbols to be resolved within a
           shared library if possible, even when a symbol is
           already defined elsewhere. For an explanation of
           -Bsymbolic, see the ld(1) man page.

           This option and its arguments are passed to the
           linker, ld.  If you compile and link in separate
           steps and are using the -Bbinding option, you must
           include the option in the link step.

           Warning:

           Never use -Bsymbolic with programs containing C++
           code, use linker scoping instead. See the C++
           User's Guide for more information on linker scop-
           ing. See also the -xldscope option.

           With -Bsymbolic, references in different modules
           can bind to different copies of what is supposed
           to be one global object.

           The exception mechanism relies on comparing
           addresses. If you have two copies of something,
           their addresses won't compare equal, and the
           exception mechanism can fail because the exception
           mechanism relies on comparing what are supposed to
           be unique addresses.
0 голосов
/ 01 октября 2011

Обратите внимание, что объект не обязательно является блоком, который связан целиком.Есть способы поместить символы в отдельные разделы, которые могут быть помещены в окончательный .exe-файл в зависимости от того, ссылается ли он на код.(ищите опцию компоновщика -gc-секции и опции gcc генерации связанных секций)

Возможно, это просто не микрооптимизирует, когда секции не используются.

...