Monday, February 02, 2009

How to run a shared library on Linux

How to run a shared library on Linux

In my prevoius blog I have written how to run the shared libraries on
Open-Solaris.
http://bhushanverma.blogspot.com/2008/06/how-to-run-shared-library-on-open.html

Shared object should have following entries to run:
1. +x permission that is by default is given by the static
linker(program linker) when creating a shared object.
2. Entry point at which the program/shared library is starts to run.
3. Interpreter(Run time linker) that is used to run any shared library
after loaded by kernel part exec().

Entry point at which the program/shared library is starts to run can be
given by passing -Wl,-e entry_point to the linker at command line:

To create .interp section by using GNU gcc, use the follwing line of
code on linux:
const char my_interp[] __attribute__((section(".interp"))) =
"/lib/ld-linux.so.2";

Where /lib/ld-linux.so.2 is the path of interpreter(Run time linker)  in linux.

In open solaris we passed -Wl,-I,/usr/lib/ld.so.1 to the sun linker to
create this section.
I think in gnu linker this option is available but do other things.

Demo on Linux machine:
-------------------------
$ cat func.c
const char my_interp[] __attribute__((section(".interp"))) =
"/lib/ld-linux.so.2";
#include
void bar();

int
func()
{
printf("Hacking\n");
bar();
exit (0);
}

void
bar()
{
printf("Bye...\n");
}

$ gcc -fPIC -o func.so -shared -Wl,-e,func func.c

You can see that foo.so have .interp section and interp program header.
# readelf -l func.so
Elf file type is DYN (Shared object file)
Entry point 0x4dc
There are 7 program headers, starting at offset 52

Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x00000034 0x00000034 0x000e0 0x000e0 R E 0x4
INTERP 0x0005a3 0x000005a3 0x000005a3 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x00000000 0x00000000 0x005bc 0x005bc R E 0x1000
LOAD 0x0005bc 0x000015bc 0x000015bc 0x00104 0x0010c RW 0x1000
DYNAMIC 0x0005d4 0x000015d4 0x000015d4 0x000c0 0x000c0 RW 0x4
NOTE 0x000114 0x00000114 0x00000114 0x00024 0x00024 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4

Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version
.gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata
.interp .eh_frame
03 .ctors .dtors .jcr .data.rel.ro .dynamic .got .got.plt .bss
04 .dynamic
05 .note.gnu.build-id
06

You can cleary see, func.so have .interp section and INTERP program header.
Now try to run func.so:
$ ./func.so
Hacking
Bye...

1 comment:

Bri said...

For C++, declare and invoke _init(); at the start of your "main", and invoke _fini(); at the end of your "main".