Автор Тема: Программа для преобразования исполняемого файла Linux для запуска в OpenSolaris  (Прочитано 19244 раз)

Оффлайн keremet

  • Global Moderator
  • ROOT
  • *****
  • Сообщений: 463
  • Репутация: +237/-0
    • Просмотр профиля
    • OpenSolaris
Существуют такие приложения, как например skype и некоторые фильтры печати, у которых закрыты исходники, но свободно доступны бинарники под Linux. Хотелось бы иметь программу которая преобразовывала бы эти приложения так, чтобы они могли запускаться под OpenSolaris без необходимости использования зоны или lxrun. Узнав, что формат исполняемых файлов под обеими ОС одинаковый, решил попробовать поисследовать возможность создания такой программы.
Взял самый простой пример приложения на С:
#include <stdio.h>
int main(){
   printf("HW!\n");
   return 0;
}

Команда gcc -O3 -S генерирует одинаковый ассемблерный код как в случае Linux (в lx-зоне), так и в случае OpenSolaris.
Сгенерированный в lx-зоне объектный файл, поданный на вход gcc в OpenSolaris, позволил без ошибок слинковать нормально работающее приложение. Таким образом, если приложение использует только libc(не исключаю, что допустимо использование и других библиотек), то если из бинарника удастся сформировать объектный файл, на основе которого он создан, то можно получить такое же приложение под OpenSolaris.
Дизассемблировать линуксовое приложение, а потом снова сассемблировать под OpenSolaris - затруднительно в виду сложности создания адекватного дизассемблера.
Зависимости приложения под Linux:
$ldd a.out
        libc.so.6 => /lib/tls/libc.so.6 (0xfe776000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0xfef61000)

$objdump -R a.out

a.out:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE
08049534 R_386_GLOB_DAT    __gmon_start__
0804952c R_386_JUMP_SLOT   puts
08049530 R_386_JUMP_SLOT   __libc_start_main

Под OpenSolaris зависимости совершенно другие. Для упрощения задачи взял еще более простой пример программы.

// Компиляция: as -o hello.o hello.s && ld -s hello.o -lc && ./a.out
.text
.globl _start
_start:
   pushl $message1
   call puts
   popl %ebx
   call exit
   hlt
.data
message1:
   .string "Hello world\0"

Теперь зависимости от функций совпадают.
$objdump -R a.out

a.out:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE
08049330 R_386_JUMP_SLOT   exit
08049334 R_386_JUMP_SLOT   puts

Открыл файл a.out с lx-зоны в ghex2 и внес изменения:
1. Строку /usr/lib/libc.so.1 заменил на /usr/lib/ld.so.1
2. Строку libc.so.6 заменил на libc.so.1
3. Строку GLIBC_2.0 заменил на SUNW_0.8, находящуюся чуть ниже последовательность байт 10 69 69 0D, тоже задающую версию, заменил на 98 28 3d 0a
Просмотр доступных версий в libc: objdump -p /lib/libc.so.1. objdump -p a.out - просмотр используемой приложением версии.


Файл запускается и работает нормально. Это доказывает возможность с относительно небольшими изменениями модифицировать бинарники из Linux для нативного запуска под OpenSolaris.

Илья

  • Гость
Было ло бы хорошо если в нашей системе такая опция будет :P
Вот этот код что означает?
             
class Foo
{
public:
    Foo(int j) { i=new int[j]; }
    ~Foo() { delete i; }
private:
    int* i;
};

class Bar: Foo
{
public:
    Bar(int j) { i=new char[j]; }
    ~Bar() { delete i; }
private:
    char* i;
};


void main()
{
    Foo* f=new Foo(100);
    Foo* b=new Bar(200);
    *f=*b;
    delete f;
    delete b;
}                     
« Последнее редактирование: Март 05, 2011, 08:59:09 pm от Snow Leopard »

Оффлайн sCode

  • ROOT
  • *****
  • Сообщений: 129
  • Репутация: +10/-0
    • Просмотр профиля
    • E-mail
Существуют такие приложения, как например skype и некоторые фильтры печати, у которых закрыты исходники, но свободно доступны бинарники под Linux. Хотелось бы иметь программу которая преобразовывала бы эти приложения так, чтобы они могли запускаться под OpenSolaris без необходимости использования зоны или lxrun. Узнав, что формат исполняемых файлов под обеими ОС одинаковый, решил попробовать поисследовать возможность создания такой программы.
Взял самый простой пример приложения на С:
#include <stdio.h>
int main(){
   printf("HW!\n");
   return 0;
}

Команда gcc -O3 -S генерирует одинаковый ассемблерный код как в случае Linux (в lx-зоне), так и в случае OpenSolaris.
Сгенерированный в lx-зоне объектный файл, поданный на вход gcc в OpenSolaris, позволил без ошибок слинковать нормально работающее приложение. Таким образом, если приложение использует только libc(не исключаю, что допустимо использование и других библиотек), то если из бинарника удастся сформировать объектный файл, на основе которого он создан, то можно получить такое же приложение под OpenSolaris.
Дизассемблировать линуксовое приложение, а потом снова сассемблировать под OpenSolaris - затруднительно в виду сложности создания адекватного дизассемблера.
Зависимости приложения под Linux:
$ldd a.out
        libc.so.6 => /lib/tls/libc.so.6 (0xfe776000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0xfef61000)

$objdump -R a.out

a.out:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE
08049534 R_386_GLOB_DAT    __gmon_start__
0804952c R_386_JUMP_SLOT   puts
08049530 R_386_JUMP_SLOT   __libc_start_main

Под OpenSolaris зависимости совершенно другие. Для упрощения задачи взял еще более простой пример программы.

// Компиляция: as -o hello.o hello.s && ld -s hello.o -lc && ./a.out
.text
.globl _start
_start:
   pushl $message1
   call puts
   popl %ebx
   call exit
   hlt
.data
message1:
   .string "Hello world\0"

Теперь зависимости от функций совпадают.
$objdump -R a.out

a.out:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE
08049330 R_386_JUMP_SLOT   exit
08049334 R_386_JUMP_SLOT   puts

Открыл файл a.out с lx-зоны в ghex2 и внес изменения:
1. Строку /usr/lib/libc.so.1 заменил на /usr/lib/ld.so.1
2. Строку libc.so.6 заменил на libc.so.1
3. Строку GLIBC_2.0 заменил на SUNW_0.8, находящуюся чуть ниже последовательность байт 10 69 69 0D, тоже задающую версию, заменил на 98 28 3d 0a
Просмотр доступных версий в libc: objdump -p /lib/libc.so.1. objdump -p a.out - просмотр используемой приложением версии.


Файл запускается и работает нормально. Это доказывает возможность с относительно небольшими изменениями модифицировать бинарники из Linux для нативного запуска под OpenSolaris.
А чем кросскомпиляторы не устраивают? Типа MinGW? Можно компилировать сразу под три платформы:
  • OpenSolaris
  • GNU/Linux
  • Windows


Оффлайн keremet

  • Global Moderator
  • ROOT
  • *****
  • Сообщений: 463
  • Репутация: +237/-0
    • Просмотр профиля
    • OpenSolaris
Если доступны исходники, тогда, конечно, лучше скомпилировать из них.  Преобразования исполняемого файла актуальны, когда исходников нет, как например в случае со skype.

Оффлайн keremet

  • Global Moderator
  • ROOT
  • *****
  • Сообщений: 463
  • Репутация: +237/-0
    • Просмотр профиля
    • OpenSolaris
Более правильное решение - не вносить изменения в бинарники, а создать динамический линковщик, который позволит запускаться приложениям Linux. За основу хочу взять ld.so.1 из Illumos. Скомпилировал Illumos (https://www.illumos.org/projects/illumos-gate/wiki/How_To_Build_illumos) и столкнулся с проблемой, что при повторном запуске команды компиляции (./nightly illumos.sh ) для компиляции измененного кода ld.so.1 удаляются все результаты предыдущей сборки и сборка начинается сначала (10 часов). Запуск make прямо в каталоге usr/src/cmd/sgs/rtld завершается неудачно из-за невыставленных переменных окружения.
Кривым решением проблемы является составление собственного makefile в usr/src/cmd/sgs/rtld на основе '.make.state.i386', хранящего все команды, выполненные make ранее.
Однако мне кажется, что наверняка есть более корректное решение без написания makefile, тем более эта процедура была достаточно затруднительной.

Оффлайн keremet

  • Global Moderator
  • ROOT
  • *****
  • Сообщений: 463
  • Репутация: +237/-0
    • Просмотр профиля
    • OpenSolaris
Для динамической линковки каждой функции вызывается ulong_t elf_bndr(Rt_map *lmp, ulong_t reloff, caddr_t from):/code/illumos-gate/usr/src/cmd/sgs/rtld/i386/i386_elf.c:192

Результат анализа процесса линковки функции с использованием DTrace

  0  -> elf_rtbndr // /illumos-gate/usr/src/cmd/sgs/rtld/i386/boot_elf.s:306, вызывает elf_bndr и прилинкованную ей функцию
  0    -> elf_bndr                           
  0      -> enter                             //Для синхронизации, захват мьютекса
  0        -> rt_bind_guard                   
  0          -> _ti_bind_guard               
  0            -> mutex_lock                 
  0              -> mutex_lock_impl           
  0              <- mutex_lock_impl           
  0            <- mutex_lock                 
  0            -> set_cancel_pending_flag     
  0            <- set_cancel_pending_flag     
  0          <- _ti_bind_guard               
  0        <- rt_bind_guard                   
  0      <- enter               

             
  0      -> lookup_sym                       
  0        -> elf_hash                       
  0        <- elf_hash                       
  0        -> _lookup_sym                     
  0          -> core_lookup_sym               
  0            -> callable                   
  0            <- callable                   
  0            -> elf_find_sym               
  0              -> strcmp                   
  0              <- strcmp                   
  0            <- elf_find_sym               
  0            -> callable                   
  0            <- callable                   
  0            -> elf_find_sym               
  0              -> strcmp                   
  0              <- strcmp                   
  0            <- elf_find_sym               
  0          <- core_lookup_sym               
  0        <- _lookup_sym                     
  0      <- lookup_sym                       
  0      -> bind_one                         
  0      <- bind_one                         
  0      -> load_completion                   
  0      <- load_completion                   
  0      -> is_dep_init                       
  0      <- is_dep_init                       


  0      -> leave                   //Для синхронизации, освобождение мьютекса           
  0        -> rd_event                       
  0        <- rd_event                       
  0        -> rt_bind_clear                   
  0          -> _ti_bind_clear               
  0          <- _ti_bind_clear               
  0        <- rt_bind_clear                   
  0        -> rt_bind_clear                   
  0          -> _ti_bind_clear               
  0            -> set_cancel_pending_flag     
  0            <- set_cancel_pending_flag     
  0            -> mutex_unlock               
  0            <- mutex_unlock               
  0          <- _ti_bind_clear               
  0        <- rt_bind_clear                   
  0      <- leave                             
  0    <- elf_bndr                           
  0  <- elf_rtbndr


Однако при помощи провайдера pid DTrace не получится посмотреть, что происходит до создания процесса, а приложение Linux валится именно на этом этапе. Для трассировки функций придется внести изменения в код.
")\n{" заменить на ")\n{printf("->%s\\n",__func__);"
"\n}" заменить на "\nprintf("<-%s\\n",__func__);\n}"


Приведенный выше простейший пример приложения для Linux запускается после внесения следующих изменений в analyze.c:

const char *
load_trace(Lm_list *lml, Pdesc *pdp, Rt_map *clmp, Fdesc *fdp)
{
....
        if(strcmp(name,"libc.so.6")==0){
            name="libc.so.1";
        }
   fdp->fd_oname = name;
   return (name);
}

Судя по коду возможно, что желаемая тема уже реализована через аудит, так как он позволяет тоже заменить имя so. Надо изучить аудит.

Для запуска приложений, написанных на C, требуется реализовать функции __gmon_start__ и __libc_start_main в собственном SO. Код этих функций взять из GLIBC.
Стиль кодирования: http://hub.opensolaris.org/bin/download/Community+Group+on/WebHome/cstyle.ms.pdf

Оффлайн keremet

  • Global Moderator
  • ROOT
  • *****
  • Сообщений: 463
  • Репутация: +237/-0
    • Просмотр профиля
    • OpenSolaris
Сегодня был получен первый практически значимый результат. Созданы ld.so.1, reloc.conf и liblinux.so, позволяющие запустить драйвер (линуксовый бинарник с so-шками) моего принтера (Canon IP1500).
Теперь распечатка идет практически моментально и не требуется ждать около 10 секунд, пока зона загрузится.

Оффлайн keremet

  • Global Moderator
  • ROOT
  • *****
  • Сообщений: 463
  • Репутация: +237/-0
    • Просмотр профиля
    • OpenSolaris
В приложении: патч к коду ld.so.1, бинарники, тесты

http://zalil.ru/31493212

Оффлайн keremet

  • Global Moderator
  • ROOT
  • *****
  • Сообщений: 463
  • Репутация: +237/-0
    • Просмотр профиля
    • OpenSolaris
Попытка запуска skype.

ldd skype/skype_static-2.0.0.72-oss/skype
        libasound.so.2 => /usr/lib/libasound.so.2 (0xfec6e000)
        libXv.so.1 => /usr/X11R6/lib/libXv.so.1 (0xfe9e0000)
        libXss.so.1 => /usr/lib/libXss.so.1 (0xfe9d0000)
        libSM.so.6 => /usr/X11R6/lib/libSM.so.6 (0xfe9c0000)
        libICE.so.6 => /usr/X11R6/lib/libICE.so.6 (0xfe978000)
        libXi.so.6 => /usr/X11R6/lib/libXi.so.6 (0xfe8a0000)
        libXrender.so.1 => /usr/X11R6/lib/libXrender.so.1 (0xfe890000)
        libXrandr.so.2 => /usr/X11R6/lib/libXrandr.so.2 (0xfe870000)
        libXfixes.so.3 => /usr/lib/libXfixes.so.3 (0xfe860000)
        libXcursor.so.1 => /usr/X11R6/lib/libXcursor.so.1 (0xfe850000)
        libXinerama.so.1 => /usr/lib/libXinerama.so.1 (0xfe840000)
        libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0xfe7ef000)
        libfontconfig.so.1 => /usr/lib/libfontconfig.so.1 (0xfe7c7000)
        libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0xfe7b0000)
        libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0xfe6d0000)
        librt.so.1 => /lib/tls/librt.so.1 (0xfe6bb000)
        libdl.so.2 => /lib/libdl.so.2 (0xfe6b0000)
        libpthread.so.0 => /lib/tls/libpthread.so.0 (0xfe690000)
        libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xfe5aa000)
        libm.so.6 => /lib/tls/libm.so.6 (0xfe57d000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xfe55f000)
        libc.so.6 => /lib/tls/libc.so.6 (0xfe425000)
        libz.so.1 => /usr/lib/libz.so.1 (0xfe410000)
        libexpat.so.0 => /usr/lib/libexpat.so.0 (0xfe3ef000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0xfef61000)




LD_LIBRARY_PATH=<путь к libasound.so.2>:/usr/X11/lib/ ../2011_07_31/ld.so.1 ./skype

cat reloc.conf
libXi.so.6=libXi.so.5
libXfixes.so.3=libXfixes.so.1
libXext.so.6=libXext.so.0
libX11.so.6=libX11.so.4
librt.so.1=linux.so.1
libdl.so.2=libdl.so.1
libpthread.so.0=linux.so.1
libm.so.6=libm.so.2
libgcc_s.so.1=libc.so.1
libc.so.6=libc.so.1

Добавил функции
int __cxa_atexit(void (*func) (void *), void * arg, void * dso_handle){
   return 0;
}
int __xstat64(int ver, const char * path, struct stat64 * stat_buf){
   return stat(path, stat_buf);
}
int __lxstat64(int ver, const char * path, struct stat64 * stat_buf){
   return lstat(path, stat_buf);   
}

При запуске возникает segfault. Надо выяснить по какой причине.

LD_DEBUG=all LD_PRELOAD=liblinux/linux.so.1 LD_LIBRARY_PATH=.:/usr/X11/lib/ ./ld.so.1 ./skype

.....
01561: 1: binding file=./skype to file=/lib/libc.so.1: symbol 'getcwd'
01561: 1:
01561: 1: file=/usr/lib/iconv/UTF-8%UTF-16.so;  dlopen() called from file=/lib/libc.so.1  [ RTLD_LAZY ]
01561: 1:
01561: 1: find object=/usr/lib/iconv/UTF-8%UTF-16.so; searching
01561: 1:  trying path=/usr/lib/iconv/UTF-8%UTF-16.so
01561: 1:
01561: 1: symbol=_icv_open;  dlsym() called from file=/lib/libc.so.1; starting at file=/usr/lib/iconv/UTF-8%UTF-16.so 
01561: 1: symbol=_icv_open;  lookup in file=/usr/lib/iconv/UTF-8%UTF-16.so  [ ELF ]
01561: 1: binding file=/lib/libc.so.1 to file=/usr/lib/iconv/UTF-8%UTF-16.so: symbol '_icv_open'
01561: 1:
01561: 1: symbol=_icv_iconv;  dlsym() called from file=/lib/libc.so.1; starting at file=/usr/lib/iconv/UTF-8%UTF-16.so 
01561: 1: symbol=_icv_iconv;  lookup in file=/usr/lib/iconv/UTF-8%UTF-16.so  [ ELF ]
01561: 1: binding file=/lib/libc.so.1 to file=/usr/lib/iconv/UTF-8%UTF-16.so: symbol '_icv_iconv'
01561: 1:
01561: 1: symbol=_icv_close;  dlsym() called from file=/lib/libc.so.1; starting at file=/usr/lib/iconv/UTF-8%UTF-16.so 
01561: 1: symbol=_icv_close;  lookup in file=/usr/lib/iconv/UTF-8%UTF-16.so  [ ELF ]
01561: 1: binding file=/lib/libc.so.1 to file=/usr/lib/iconv/UTF-8%UTF-16.so: symbol '_icv_close'
Segmentation Fault (core dumped)

getcwd реализован в liblinux, однако segfault все равно происходит. Решение - изучить core.

gdb ./ld.so.1 core
Core was generated by `./ld.so.1 ./skype'.
Program terminated with signal 11, Segmentation fault.
[New process 67343    ]
#0  0x08dec187 in _rt_boot ()
(gdb) disas 0x08dec187
Dump of assembler code for function _rt_boot:
0x08dec187 <_rt_boot+0>:   xchg   %edx,(%esi)
0x08dec189 <_rt_boot+2>:   lock decl (%edx)
0x08dec18c <_rt_boot+5>:   setne  %al
0x08dec18f <_rt_boot+8>:   test   %al,%al

(gdb) info registers
edx            0x93f2c28   155135016
esi            0x0   0

segfault происходит при обращении по нулевому адресу.

(22:35:17) keremet: assembler code for function _rt_boot differs from _rt_boot source code
(22:37:03) keremet: How is it possible?
(22:39:12) keremet: May be skype changes _rt_boot in run time
(22:44:02) Triskelios: entirely possible it clobbers where that used to be mapped
(22:55:49) keremet: I think I should study how skype runs on linux zones


Оффлайн keremet

  • Global Moderator
  • ROOT
  • *****
  • Сообщений: 463
  • Репутация: +237/-0
    • Просмотр профиля
    • OpenSolaris
Так как не получилось запустить скайп, надо попробовать запустить более простое исковое приложение Linux. Пусть это будет xterm.

LD_DEBUG=all LD_PRELOAD=/lib/libcrypto.so:libc.so.1:liblinux/linux.so.1 /code/illumos-gate/usr/src/cmd/sgs/rtld/i386/ld.so.1 /home/keremet/linux-gate.so.1/testapp/xterm.linux

01819: 1: binding file=/home/keremet/linux-gate.so.1/testapp/xterm.linux to file=liblinux/linux.so.1: symbol '__ctype_b_loc'
Segmentation Fault (core dumped)

Требуется правильно реализовать в liblinux __ctype_b_loc

Оффлайн keremet

  • Global Moderator
  • ROOT
  • *****
  • Сообщений: 463
  • Репутация: +237/-0
    • Просмотр профиля
    • OpenSolaris
Для получения универсального решения следует рассмотреть вариант трансляции только системных вызовов, так как приложения 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.html
http://articles.manugarg.com/systemcallinlinux2_6.html
http://articles.manugarg.com/aboutelfauxiliaryvectors.html
http://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'

Оффлайн keremet

  • Global Moderator
  • ROOT
  • *****
  • Сообщений: 463
  • Репутация: +237/-0
    • Просмотр профиля
    • OpenSolaris
Сегодня восстановил у себя в OpenIndiana 151a поддержку линуксовых зон (lx brand). Постараюсь подготовить в хорошем виде пачт к коду illumos и бинарники.