2009-09-20 5 views
43

Так что все, вероятно, знают, что glibc's /lib/libc.so.6 может быть запущен в оболочке, как обычный исполняемый файл, в случае которого он печатает информацию о своей версии и выходит. Это делается путем определения точки входа в .so. В некоторых случаях было бы интересно использовать это и для других проектов. К сожалению, низкоуровневая точка входа, которую вы можете установить с помощью параметра ld -e, немного слишком низка: динамический загрузчик недоступен, поэтому вы не можете вызвать какие-либо правильные функции библиотеки. glibc по этой причине реализует системный вызов write() через голый системный вызов в этой точке входа.создание .so также является исполняемым

Вопрос теперь в том, может ли кто-нибудь подумать о том, как можно было бы загружать полный динамический компоновщик из этой точки входа, чтобы можно было получить доступ к функциям из других .so?

+5

'/ lib/ld-linux.so.2' - еще один пример :) –

ответ

43

Создание вашей общей библиотеки с помощью -pie, как представляется, дает вам все, что вы хотите:

/* pie.c */ 
#include <stdio.h> 
int foo() 
{ 
    printf("in %s %s:%d\n", __func__, __FILE__, __LINE__); 
    return 42; 
} 
int main() 
{ 
    printf("in %s %s:%d\n", __func__, __FILE__, __LINE__); 
    return foo(); 
} 


/* main.c */ 
#include <stdio.h> 

extern int foo(void); 
int main() 
{ 
    printf("in %s %s:%d\n", __func__, __FILE__, __LINE__); 
    return foo(); 
} 


$ gcc -fPIC -pie -o pie.so pie.c -Wl,-E 
$ gcc main.c ./pie.so 


$ ./pie.so 
in main pie.c:9 
in foo pie.c:4 
$ ./a.out 
in main main.c:6 
in foo pie.c:4 
$ 

P.S. glibc реализует write(3) через системный вызов, потому что ему больше не нужно звонить (это уже уровень). Это не имеет никакого отношения к возможности выполнить libc.so.6.

+0

Я обнаружил, что опция' -shared' может помешать этому работать, и дать вам ошибку сегментации. Вы должны убедиться, что параметр '-shared' отсутствует или помещен перед' -pie', поэтому он игнорируется. –

1

Не очень хороший способ, но я бы создал крошечную оболочку, исполняемую вокруг .so, которая вызывает функцию точки входа, которую я хочу запустить.

0

Я полагаю, что у вас есть точка ld -e, указывающая на точку входа, которая затем будет использовать семейство функций dlopen() для поиска и загрузки остальной части динамического компоновщика. Конечно, вы должны убедиться, что dlopen() сам был либо статически или вы могли бы реализовать достаточно вашего собственного компоновщика заглушкой, чтобы получить на него (с помощью интерфейсов системных вызовов, таких как mmap() как Libc само по себе делает.

Ничто из этого не кажется мне «приятным». На самом деле просто мысль о чтении источников glibc (и исходный код ld-linux, как один пример) достаточно, чтобы оценить размер задания, который звучит довольно коряво для меня. Это может быть также переносимость кошмара. Могут быть существенные различия между тем, как Linux реализует ld-linux и как эти взаимосвязи выполняются под OpenSolaris, FreeBSD и т. д. (я не знаю).

Смежные вопросы