Я расследую перемещение общих библиотек и столкнулся с чем-то странным.Рассмотрим этот код:
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, чтобы понять перемещения во время загрузки.