flat assembler
Message board for the users of flat assembler.

Index > Linux > INIT and FINI on shared libraries

Author
Thread Post new topic Reply to topic
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
According to http://www.iecc.com/linker/linker10.html shared libraries can have an initializer and a finalizer procedure. http://tldp.org/HOWTO/Program-Library-HOWTO/miscellaneous.html explains how to do it in C and warns that exporting "_init" and "_fini" can lead to unpredicatable results (so doing "public _init" and "public _fini" seems to be not a good idea). I guess that when you use "void __attribute__ ((constructor)) my_init(void);" you are actually setting the INIT pointer to "my_init".

Has FASM a way to set INIT and FINI pointers? If I'm right, INIT and FINI are the DLL_PROCESS_ATTACH and DLL_PROCESS_DETACH equivalents respectivelly, something very useful to have.

Regards

PS: BTW, has the shared libraries a mechanism like DLL_THREAD_ATTACH and DLL_THREAD_DETACH?
Post 29 Sep 2006, 03:38
View user's profile Send private message Reply with quote
arafel



Joined: 29 Aug 2006
Posts: 131
Location: Jerusalem, Israel
arafel
INIT and FINI pointers?
Aren't the initialization/finalization routines just a couple of global _init and _fini functions located in .init and .fini sections respectively
Post 29 Sep 2006, 04:10
View user's profile Send private message Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 7492
Location: Kraków, Poland
Tomasz Grysztar
The INIT and FINI pointers reside in the dynamic table, which is generated by linker. So the only problem might how to tell the linker to make those entries. Perhaps arafel is right, and placing the functions in the .init and .fini sections is enough. The ELF specification say this about .init section:
ELF specification wrote:
This section holds executable instructions that contribute to the process initialization code.
That is, when a program starts to run, the system arranges to execute the code in this section
before calling the main program entry point (called main for C programs).

So definitely you have to put your function into that section (and perhaps this is what the "__attribute__ ((constructor))" in C does). Whether this will be enough for linker to know that it has to make INIT entry in dynamic table for that function, is left to find out.
Post 29 Sep 2006, 07:50
View user's profile Send private message Visit poster's website Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
OK, I'll try and post my results

Thanks to both
Post 29 Sep 2006, 14:02
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Sorry for the late. Now I tried but not complete success Sad

shared-lib.asm:
Code:
format ELF

struc Msg [chars]
{
common
  rb 1
.:
forward
  db chars
common
  store byte $ - . at . - 1
}

section '.init' executable ; separate section but _init works on .text section anyway

public _init
_init:
        push    ebx

        call    @f
    @@: pop     ebx
        sub     ebx,rva @b ; @b-rva @b is the GOT address

        lea     ecx, [ebx+ rva initMessage]
        call    printStr

        pop     ebx
        ret
initMessage Msg "The oracle has come to give you the answer", 10

section '.fini' executable
public _fini
_fini:                     ; never executed Sad
        push    ebx

        call    @f
    @@: pop     ebx
        sub     ebx,rva @b ; @b-rva @b is the GOT address

        lea     ecx, [ebx+ rva finiMessage]
        call    printStr

        pop     ebx
        ret

finiMessage Msg "The oracle has left the building", 10

section '.text' executable

printStr: ; ECX = Pointer to message

  push    ebx

  xor     edx, edx
  mov     eax, 4
  mov     ebx, 1
  mov     dl, [ecx-1]
  int     $80

  pop     ebx
  ret

public getTheMostValuableMessage

getTheMostValuableMessage:
        push    ebx

        call    @f
    @@: pop     ebx
        sub     ebx,rva @b ; @b-rva @b is the GOT address

        lea     eax,[ebx+rva message]
        xor     edx, edx
        mov     dl, [eax-1]

        pop     ebx
        ret

message Msg 'Which is the sense of the life? 42', 10    


shared-lib-test.asm:
Code:
format ELF

section '.text' executable

 public _start
 extrn getTheMostValuableMessage

 _start:
        call    getTheMostValuableMessage

        mov     ecx,eax
        mov     eax,4
        mov     ebx,1
        int     0x80

        mov     eax, 1
        xor     ebx, ebx
        int     $80    

shell stript:
Code:
#!/bin/sh

fasm shared-lib.asm
fasm shared-lib-test.asm

ld -m elf_i386 -shared -o shared-lib.so shared-lib.o
ld -m elf_i386 -rpath . -dynamic-linker /lib/ld-linux.so.2 -o shared-lib-test shared-lib-test.o shared-lib.so    


output:
Code:
oem@athlon64:~/Desktop/test$ ./makeit
flat assembler  version 1.67.10  (16384 kilobytes memory)
4 passes, 885 bytes.
flat assembler  version 1.67.10  (16384 kilobytes memory)
1 passes, 412 bytes.
oem@athlon64:~/Desktop/test$ ./shared-lib-test
The oracle has come to give you the answer
Which is the sense of the life? 42
oem@athlon64:~/Desktop/test$ readelf -d shared-lib.so

Dynamic section at offset 0x2b8 contains 13 entries:
  Tag        Type                         Name/Value
 0x0000000c (INIT)                       0x1e0
 0x0000000d (FINI)                       0x27c
 0x00000004 (HASH)                       0x94
 0x00000005 (STRTAB)                     0x170
 0x00000006 (SYMTAB)                     0xd0
 0x0000000a (STRSZ)                      63 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000011 (REL)                        0x1b0
 0x00000012 (RELSZ)                      48 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x00000016 (TEXTREL)                    0x0
 0x6ffffffa (RELCOUNT)                   6
 0x00000000 (NULL)                       0x0
oem@athlon64:~/Desktop/test$ readelf -d shared-lib-test

Dynamic section at offset 0x1e8 contains 13 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [shared-lib.so]
 0x0000000f (RPATH)                      Library rpath: [.]
 0x00000004 (HASH)                       0x80480e8
 0x00000005 (STRTAB)                     0x8048160
 0x00000006 (SYMTAB)                     0x8048110
 0x0000000a (STRSZ)                      67 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000003 (PLTGOT)                     0x8049278
 0x00000002 (PLTRELSZ)                   8 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0x80481a4
 0x00000000 (NULL)                       0x0
    


INIT gets executed but FINI no Sad
Post 29 Sep 2006, 20:17
View user's profile Send private message Reply with quote
arafel



Joined: 29 Aug 2006
Posts: 131
Location: Jerusalem, Israel
arafel
Try linking with "-fini _fini" switch. Maybe ld fails to automatically locate the _fini entry point.
Post 29 Sep 2006, 21:59
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Tried "ld -m elf_i386 -fini _fini -shared -o shared-lib.so shared-lib.o" and since it doesn't work I tried "ld -m elf_i386 -rpath . -dynamic-linker /lib/ld-linux.so.2 -o shared-lib-test shared-lib-test.o shared-lib.so -fini _fini" too and then both at the same time but always the same effect, the message "The oracle has left the building" never appears Sad
Post 29 Sep 2006, 23:48
View user's profile Send private message Reply with quote
arafel



Joined: 29 Aug 2006
Posts: 131
Location: Jerusalem, Israel
arafel
hmmm. dunno then.
Post 30 Sep 2006, 01:55
View user's profile Send private message Reply with quote
arafel



Joined: 29 Aug 2006
Posts: 131
Location: Jerusalem, Israel
arafel
Ok, I googled a bit about this issue and here is something interesting:
Quote:

Similarly, shared object files can have termination functions that are executed by the atexit mechanism when the process is terminating. Termination functions are called in dependency order - the exact opposite of the order in which initialization functions are called.
.....
Although atexit termination processing normally is done, it is not guaranteed to have executed when the process terminates. In particular, the process does not execute the termination processing if it calls _exit or if the process terminates because it received a signal that it neither caught nor ignored.

If I not mistaked _exit() is basically a wrapped sys_exit(), so this might be a reason why _finit() is not called.
Post 30 Sep 2006, 02:03
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
UPDATE

Works using GCC (and using main instead of _start). But note that it works when I replace the "ExitProcess" system call with a RET (something that doesn't work without gcc). So the problem here is that I'm leaving the system too fast to give shared-lib.so->fini an oportunity to execute.
Seems that I need to terminate the process in other way, do anyone know how?

[edit] Sorry, apparently I spend too much time writing this and you replied when I was writing Razz
Well, is confirmed then, the question now is how to do this without relying on libc (with gcc you implicity rely on it)[/edit]
Post 30 Sep 2006, 02:20
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Today I tried using "ccall exit, 0" and "ccall _exit, 0" (and linking against libc.so.6), but same problem, seems that using exit which is supposed to terminate normally and calling the exit procedures ( see http://www.borgnet.us/cgi-bin/man2web?program=exit&section=3 ), my _fini functions isn't get excecuted Sad

Seems that I'll always rely on gcc to get it work Sad
Post 08 Oct 2006, 02:27
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 16892
Location: In your JS exploiting you and your system
revolution
For simple programs with one dependency, like the example above, it is sufficient to scan the ELF header and call the FINI function manually. But as the dependencies get more complex the interactions become tricky and the order of FINI calls needs to be done correctly. Looking at the C code that does this, there are a lot of things happening in there. So most likely it would be necessary to reproduce the FINI call order to be sure that everything is closed properly.

But if you know your libraries well and know that the FINI call order isn't important to them, then I'd guess it would be okay to just call each FINI as it is found. Another option is to simply call EXIT_GROUP and forget about all the complexity Razz
Post 20 Feb 2019, 10:02
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2019, Tomasz Grysztar.

Powered by rwasa.