Tuesday, June 24, 2008

How can I call main() function

This article gives you some basic idea: what happens when user application/program starts.
Why I am saying "some basic idea" since here I am not considering dynamic linking/loading of shared libraries.
If you want to know in depth of what happens when user application/program starts, please
read my Linker and Loader blog:
http://bhushanverma.blogspot.com/search/label/ELF%2FLinker%2FLoader%2Flibc%2FCompiler

Whenever user runs any user application, its get loaded in memory by Operating System/Loader.
Now Operating System/Loader calls user application _start entry point.
User application starts running at _start.
_start calls the user program's main function,then it calls the exit(0)system call, which cleans up the process.

User application starts running at _start as follows:

_start(args) {
ret = main(args);
exit(ret);
}

when main() returns, os calls exit() which destroy the process and returns all its resources.
Most of the above code is written in assembly.

Now lets take an example to undestand this:

$ cat main.c
#include

_start ()
{
int ret;
ret = main ();
exit (ret);
}

int
main (void)
{
printf ("hello world");
return 0;
}

Now build this c program:
$ gcc -c main.c
$ ld -main main.o -lc
$ ./main
hello world

If the above commands not works try as follows:
$ gcc -o main -nostdlib main.c -lc
$ ./main
hello world

Yes, we did it.

Thursday, June 12, 2008

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...


hua.. thats cool.
Happy hacking.

Accessing libc,runtime linker,shared libraries functions using pragma weak

Sometimes you are working on libc, glibc linker ,shared libraries.
You have seen in the code of these libraries as follows:
#pragma weak dlopen = _dlopen
#pragma weak dlcose= _dlclose

What is this? what is the use of these lines of code written in libc,glibc etc.
The above lines code indicates that any user applications can call/use "dlopen" and "dlclose"
functions.

How is this possible?
There is little trick/work done by compiler, which creates the
symbol as a weak.

#pragma weak symbol1 = symbol2
This pragma declares symbol1 to be a weak alias of symbol2. It is an error if symbol2 is not defined in the
current translation unit.
for more information please refers following link.
http://gcc.gnu.org/onlinedocs/gcc/Pragmas.html#Pragmas

Now we have some idea on weak symbol,so move forwards to do some R&D.
I have done this R&D on Open-Soalris. Its also applicable to Linux.

$cat mylibc.c

#pragma weak my_function = _my_function
void _my_function()
{

printf("inside _my_fnction()\n");

}

$ cat main.c

int
main()
{
my_function();
return 0;

}

Now build the shared library:
$ gcc -o mylibc.so -fpic -shared mylibc.c
$ elfdump -s mylibc.so |fgrep my_function
[1] 0x0000049c 0x0000002f FUNC WEAK D 0 .text my_function
[10] 0x0000049c 0x0000002f FUNC GLOB D 0 .text _my_function
[49] 0x0000049c 0x0000002f FUNC WEAK D 0 .text my_function
[58] 0x0000049c 0x0000002f FUNC GLOB D 0 .text _my_function

You can see here my_function as a weak symbol.

Now build the executable using mylibc.so as a dependency:
$ gcc -o main main.c ./mylibc.so
$ elfdump -s main |fgrep my_function
[27] 0x08050680 0x00000000 FUNC GLOB D 0 UNDEF my_function
[81] 0x08050680 0x00000000 FUNC GLOB D 0 UNDEF my_function

Now run the executable:
$ ./main
inside _my_function

Cool! we got the result, Now try yourself.
Happy Hacking.

Wednesday, June 4, 2008

How to run a shared library on Open Solaris

Its is surprising that how is this possible to run a shared library.
Yes, its possible to run any shared library. I have done this R&D on Open Solaris.
It is also possible to run any shared library on Linux by using GNU Toolchain.
Please read my blog: How to run a shared library on Linux:
http://bhushanverma.blogspot.com/2008/06/how-to-run-shared-library-on-linux.html

There are some special shared object examples that can be run as an exectable:
On open solaris you can try to invoke run time linker (ld.so.1) direclty
$ /usr/lib/ld.so.1
usage: ld.so.1 [-e option,...] dynamic-object [object args,...]
Killed

To run any executable/application
$ /usr/lib/ld.so.1 ./appl

On linux you can run libc.so
$ /lib/libc.so.1
This will give you the version of libc library.

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().

By using static linker(program linker) option '-e entry_point', an entry point can be specified.
By using static linker(program linker) option '-I interpreter_path', an .interp section can be created that contains
the absolute path of the interpreter(run time linker).

You can see the interpreter path using following command
$ elfdump -i func.so

Interpreter Section: .interp
/usr/lib/ld.so.1

Demo on Open-Solaris machine
--------------------------------
$ cat func.c
#include
void bar();
int
func()
{
printf("Hacking\n");
bar();
exit (0);
}
void
bar()
{
printf("Bye...\n");
}

$ gcc -o func.so -shared -fPIC func.c
$ ./func.so
func.so: Bad entry point
Killed

$ gcc -o func.so -shared -fPIC func.c -Wl,-e,func
$ ./func.so
Segmentation Fault (core dumped)

$ gcc -o foo.so -shared -fPIC foo.c -Wl,-e,func -Wl,-I,/usr/lib/ld.so.1
$ ./func.so
Hacking
Bye...

Thats cool man, Now try yourself.
Happy hacking.