Есть такая замечательная OS, называется
HP-UX. Имеет она целых 2 стека TCP: -
POSIX и
BSD. И разработчики этой замечательной системы такие юмористы - сделали одинаковые имена функций, но разные типы аргументов (а еще усугубили тем, что аргументы указатели).
Допустим, я разработал библиотеку с учетом использования BSD реализации, а приложение (не мое), которое данную библиотеку использует, было разработано с учетом использования POSIX реализации сокетов. Это приведет к тому, что при любой сетевой активности моей библиотеки (допустим при вызове из нее функции приложением) - мы получаем
GPF.
Конечно, мы можем договорится с разработчиком приложения использовать одну и ту же реализацию сокетов. Это если приложение одно такое - использует мою библиотеку. А если их несколько? Как быть с уже не поддерживаемыми приложениями?
Выход мне подсказал клиент oracle - libclntsh.so. Ведь правда, линкуй хоть с POSIX хоть с BSD - все работает и не падает. Стал рыть дальше. Посмотрел какие вызовы sockets использует libclntsh.so. Например: setsockopt
elfdump -t libclntsh.so.10.1 | grep setsockopt
3253 FUNC GLOB 0 UNDEF 0x0000000000000000 0 _setsockopt
Ага, использует вызовы из libc (с подчерком перед символом). Как он это делает, интересно?
Ищем дальше. Смотрим в архивах *.o файлы - ничего там не находим. И вот оно - то что надо (для краткости, я опустил часть вывода):
nm xnetstubs.o
[28] | 0| 0|FUNC |GLOB |0| UNDEF|_accept
[29] | 0| 0|FUNC |GLOB |0| UNDEF|_bind
[30] | 0| 0|FUNC |GLOB |0| UNDEF|_connect
[31] | 0| 0|FUNC |GLOB |0| UNDEF|_getpeername
...
[39] | 0| 80|FUNC |GLOB |0| .text|accept
[40] | 0| 80|FUNC |GLOB |0| .text|bind
[41] | 0| 80|FUNC |GLOB |0| .text|connect
[42] | 0| 80|FUNC |GLOB |0| .text|getpeername
...
Смотрим, как он это дело линкует. Находим в clntsh.map на первой же строчке:
-h accept -h bind -h connect -h getpeername -h getsockname -h getsockopt -h setsockopt -h recv -h recvfrom -h send -h sendto -h setsockopt /u01/app/oracle/product/10.2.0/db/lib/xnetstubs.o
В документации по линкеру - -h это значит скрыть символ. Теперь при линковке нашей библиотеки добавляем:
-Wl,-h,accept -Wl,-h,bind -Wl,-h,connect -Wl,-h,getpeername
-Wl,-h,getsockname -Wl,-h,getsockopt
-Wl,-h,setsockopt -Wl,-h,recv -Wl,-h,recvfrom
-Wl,-h,send -Wl,-h,sendto -Wl,-h,setsockopt
${ORACLE_HOME}/lib/xnetstubs.o
Все. Теперь наша библиотека будет использовать BSD сокеты при любых способах линковки основного приложения.
Кстати, таким образом можно и другие вызовы перенаправлять в требуемые библиотеки. (но об этом в другой раз)