Для получения универсального решения следует рассмотреть вариант трансляции только системных вызовов, так как приложения linux сильно завязаны на особенности glibc. glibc не компилируется под OpenSolaris, следует взять ее бинарник из linux. Интерфейс системных вызовов есть в linux-gate.so.1, следует его переписать. Динамический линковщик из OpenSolaris по всей видимости должен быть заменен на ld-linux.so.2, исходники которого входят в glibc, или переписан. Дело в том, что он линкует не все подобные зависимости:
//Под Linux
relocation processing: /lib/tls/i686/cmov/libc.so.6 (lazy)
symbol=_res; lookup in file=./hw.bin
symbol=_res; lookup in file=/lib/tls/i686/cmov/libc.so.6
binding file /lib/tls/i686/cmov/libc.so.6 to /lib/tls/i686/cmov/libc.so.6 : normal symbol `_res' [GLIBC_2.0]
//Под OpenSolaris
LD_DEBUG=all LD_LIBRARY_PATH=. LD_PRELOAD=libc-2.10.1.so ./ld.so.1 ./hw.bin.linux
01555: relocation processing: file=./libc-2.10.1.so
01555: symbol=_res; lookup in file=./hw.bin.linux [ ELF ]
01555: symbol=_res; lookup in file=./libc-2.10.1.so [ ELF ]
01555: symbol=_res; hash index=411; version=32770; skipping symbol with GNU version hidden bit set in file=./libc-2.10.1.so
01555: symbol=_res; lookup in file=./ld-linux.so.2 [ ELF ]
ld.so.1: hw.bin.linux: fatal: relocation error: file ./libc-2.10.1.so: symbol _res: referenced symbol not found
Изучение исходников glibc показало, что _res там определен. У ld.so.1 не найден параметр, позволяющий линковать скрытые символы. Следует закомментировать распознавание скрытости символа.
Проблема была решена через комментирование строк в illumos-gate/usr/src/cmd/sgs/rtld/common/elf.c
в функции int elf_find_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl)
/*
* The Solaris ld does not put DT_VERSYM in the dynamic
* section, but the GNU ld does. The GNU runtime linker
* interprets the top bit of the 16-bit Versym value
* (0x8000) as the "hidden" bit. If this bit is set,
* the linker is supposed to act as if that symbol does
* not exist. The hidden bit supports their versioning
* scheme, which allows multiple incompatible functions
* with the same name to exist at different versions
* within an object. The Solaris linker does not support this
* mechanism, or the model of interface evolution that
* it allows, but we honor the hidden bit in GNU ld
* produced objects in order to interoperate with them.
*/
if (VERSYM(ilmp) && (VERSYM(ilmp)[ndx] & 0x8000)) {
DBG_CALL(Dbg_syms_ignore_gnuver(ilmp, name,
ndx, VERSYM(ilmp)[ndx]));
return (0);
}
Новое сообщение об ошибке: TLS requirement failure : TLS support is unavailable
TLS - thread local storage.
Закомментировано
illumos-gate/usr/src/cmd/sgs/rtld/common/external.c
/*
* At this point we know we have a set of objects that have been fully analyzed
* and relocated. Prior to the next major step of running .init sections (ie.
* running user code), retrieve any RTLDINFO interfaces.
*/
int rt_get_extern(Lm_list *lml, Rt_map *lmp)
/*
* Perform some sanity checks. If we have TLS requirements we better
* have the associated external interfaces.
*
if (lml->lm_tls &&
(lml->lm_lcs[CI_TLS_STATMOD].lc_un.lc_func == NULL)) {
eprintf(lml, ERR_FATAL, MSG_INTL(MSG_TLS_NOSUPPORT),
NAME(lmp));
return (0);
}*/
21989: static TLS reservation: in use 0x48: additional backup: 0x200
Segmentation Fault (core dumped)
Анализ дампа показал вызов функции по нулевому адресу (по всей видимости lc_func). Решение - считать, что tls не нужно
/*
* Perform some sanity checks. If we have TLS requirements we better
* have the associated external interfaces.
*/
lml->lm_tls=0; //!!
if (lml->lm_tls &&
(lml->lm_lcs[CI_TLS_STATMOD].lc_un.lc_func == NULL)) {
eprintf(lml, ERR_FATAL, MSG_INTL(MSG_TLS_NOSUPPORT),
NAME(lmp));
return (0);
}
24896: static TLS reservation: in use 0x0: additional backup: 0x200
24896:
24896: calling .init (from sorted order): ./libc.so.6
24896:
24896: calling .init (done): ./libc.so.6
24896:
24896:
24896: transferring control: ./hw.bin
24896:
24896: symbol=__libc_start_main; lookup in file=./hw.bin [ ELF ]
24896: symbol=__libc_start_main; lookup in file=./libc.so.6 [ ELF ]
24896: binding file=./hw.bin to file=./libc.so.6: symbol '__libc_start_main'
24896: symbol=puts; lookup in file=./hw.bin [ ELF ]
24896: symbol=puts; lookup in file=./libc.so.6 [ ELF ]
24896: binding file=./hw.bin to file=./libc.so.6: symbol 'puts'
Segmentation Fault (core dumped)
Предположение - неудачное обращение к ядру. Следует прочитать
http://www.win.tue.nl/~aeb/linux/lk/lk-4.htmlhttp://articles.manugarg.com/systemcallinlinux2_6.htmlhttp://articles.manugarg.com/aboutelfauxiliaryvectors.htmlhttp://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/sgs/rtld/i386/boot.s (состояние памяти после exec)
Тест - приложение под Linux, делающее системный вызов write. Вопрос: в какой момент(где находится код) под Linux читаются Auxiliary entries на определение указателя функции-интефейса к системным вызовам. Под OpenSolaris разбор Auxiliary entries делает ld.so.1.
Выяснено, что в aux всегда естьAT_SUN_PLATFORM и AT_SUN_EXECNAME. После прочтения данных из них, можно записать в них инфу о интефейсе к системным вызовам. В _setup.c в unsigned long _setup(Boot *ebp, Dyn *ld_dyn)
case AT_SUN_PLATFORM: //2008 - 1 in the aux vector
/* platform name */
_platform = auxv->a_un.a_ptr;
break;
case AT_SUN_EXECNAME: //2014 - 2 in the aux vector
/* full pathname of execed object */
_execname = auxv->a_un.a_ptr;
auxv->a_type=32;//AT_SYSINFO 32
auxv->a_un.a_ptr=(void*)getpid;
break;
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct
{
uint32_t a_type; /* Entry type */
union
{
} a_un;
} Elf32_auxv_t;
/* Legal values for a_type (entry type). */
#define AT_NULL 0 /* End of vector */
/* Pointer to the global system page used for system calls and other
nice things. */
#define AT_SYSINFO 32
#define AT_SYSINFO_EHDR 33
static unsigned int getsys(char **envp) {
Elf32_auxv_t *auxv;
/* walk past all env pointers */
while (*envp++ != NULL);
/* and find ELF auxiliary vectors (if this was an ELF binary) */
auxv = (Elf32_auxv_t *) envp;
// printf("2123\n");
for ( ; auxv->a_type != AT_NULL; auxv++){
printf("2123_%i\n", auxv->a_type);
if (auxv->a_type == AT_SYSINFO)
return auxv->a_un.a_val;
}
printf("2123\n");
fprintf(stderr, "no AT_SYSINFO auxv entry found\n");
exit(1);
}
int sce(){
printf("123sce\n");
return 123;
}
unsigned int sys, pid;
char *buf="HW!\n";
int main(int argc, char **argv, char **envp) {
/* char **_envp=envp;
while (*_envp++ != NULL);
Elf32_auxv_t *auxv = (Elf32_auxv_t *) _envp;
auxv->a_un.a_val = sce;
auxv->a_type = AT_SYSINFO;
auxv++;
*/
// auxv->a_type =AT_NULL;
// printf("123\n");
sys = getsys(envp);
printf("123_%i\n", sys);
//return 0;
__asm__(
" movl $4, %eax \n" /* write system call */
" movl $1, %ebx \n" //stdout
" movl buf, %ecx \n"
" movl $4, %edx \n"
" call *sys \n" /* vsyscall */
" movl %eax, pid \n" /* get result */
);
// printf("pid is %d\n", pid);
return 0;
}
Погибает на call *sys. Может быть код ld.so.1 выгружается из памяти?
Найдена возможность скомпилировать glibc 2.7 под OpenSolaris
http://csclub.uwaterloo.ca/~dtbartle/opensolaris/Как выяснилось, восстановить поддержку lx-зон в illumos возможно и не сложно:
http://alexeremin.blogspot.com/2011/06/bring-back-lx-brand.htmlИзменения по удалению lx зон
https://github.com/illumos/illumos-gate/commit/eb5a5c7888f20ad6fa4580e785308db395ef6dfcПоследняя версия их кода:
https://github.com/illumos/illumos-gate/tree/a20ee4162885a4dc8273c6b6903dcb7e0e525704/usr/src/lib/brandВ результате компиляции последней версии illumos, пропатченной вручную откатом изменений по удалению lx-зон не собрался файл usr/lib/lx_brand.so.1
Undefined first referenced
symbol in file
set_l10n_alternate_root pics/lx_brand.o
ld: fatal: symbol referencing errors. No output written to lx_brand.so.1
Функция не найдена нигде, реализована как static и возвращающая 1. Скомпилилось.
Current working directory /code/illumos-gate/usr/src/uts/intel/lx_brand
*** Error code 1
The following command caused the error:
BUILD_TYPE=DBG32 VERSION='testws' dmake install.targ
dmake: Warning: Target `install' not remade because of errors
Current working directory /code/illumos-gate/usr/src/uts/intel/lx_brand
*** Error code 1
The following command caused the error:
cd lx_brand; pwd; dmake install
dmake: Warning: Command failed for target `lx_brand'
Но скомплилось норм. Надо просто скопировать вручную.
После внесения нескольких изменений в код все файлы пакета system-zones-brand-lx скомпилировались успешно.
Создан BE, в него размещены файлы пакета и некоторые дополнительные, код которых был изменен.
Зона сконфигурилась и поставилась нормально.
keremet@openindiana:~$ zoneadm list -vi
ID NAME STATUS PATH BRAND IP
0 global running / ipkg shared
- myzone installed /export/myzone_root lx shared
Запуск зоны не удался
$ sudo zoneadm -z myzone boot
zone 'myzone': could not set zone brand attribute.: Invalid argument
zoneadm: zone 'myzone': call to zoneadmd failed
$ tail /var/adm/messages
Nov 23 11:44:38 openindiana genunix: [ID 819705 kern.notice] /usr/kernel/brand/amd64/lx_brand: undefined symbol
Nov 23 11:44:38 openindiana genunix: [ID 826211 kern.notice] 'pid_find'
Nov 23 11:44:38 openindiana genunix: [ID 472681 kern.notice] WARNING: mod_load: cannot load module 'lx_brand'