flat assembler
Message board for the users of flat assembler.

Index > Linux > creating shared libraries - how to do make PIC with GOT

Goto page 1, 2  Next
Author
Thread Post new topic Reply to topic
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
Tomasz Grysztar 17 Mar 2006, 21:42
The shared libraries in Linux are a bit like a DLL files in Windows, there is one important difference, however. In Windows' DLL there are relocations, so that when Windows loads it somewhere in the address space of given application, it can adjust all the addresses in code, so even though the DLL may get loaded at very different addresses, the ones in its code are always correct.

In case of shared libraries in Linux there are no relocations, and the main point is that the code should be position-independent, that is: unaware of at what address it is placed.

Since all the near jumps on x86 architecture are relative, they are position-independent by themselves - when you move the code to some other place, the jumps still work the same. So the only problem that may occur is with accessing the data.

The most simple method to make position-independent code in general case is to determine at what address the code resides, and calculate the valid address to the data then. Look at this function:
Code:
example_function:

        call    _origin
    _origin:
        pop     ebx

        mov     eax,[ ebx + _const-_origin ]

        ret

_const dd 1234    

It uses the CALL/POP trick to get the address of "_origin" point into EBX register, and then uses the offset of "_const" data relative to the "_origin" to retrieve value of that data.

This works quite well, and such code is truly position-independent. This won't work, however, if we want to access the data defined in some other module for the same library. For this reason the ELF format has support for the so-called GOT (Global Offsets Table), which can act as an universal origin for all the modules withing the given library. So all you need to do in your code is to determine the address of GOT and then use the GOT-relative offsets to access your data. The GOT address is usually kept in EBX, just like the origin in the above sample.

Recently I realized it's actually very simple to adapt fasm to support GOT feature and I added it in 1.65.16. I used the "rva" operator, which was already used PE format - mainly to avoid introducing the new keyword, while its meaning is still quite connected.

Here's the very simple sample of how to use this feature to make PIC module that can be used to compose shared library:
Code:
format ELF

section '.text' executable

public PIC_example

PIC_example:
        push    ebx

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

        mov     eax,[ebx+rva _const]

        pop     ebx
        ret

_const dd 1234    
Post 17 Mar 2006, 21:42
View user's profile Send private message Visit poster's website Reply with quote
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn 18 Mar 2006, 17:50
Maybe it is possible that one can use a symbol so that fasm creates directly a dynamic elf file, so that I don´t need to use a linker for that? Or have I something overseen so that the example from above can be used as dynamic elf file directly, but then you would also need to set the right type in the elf header.
Post 18 Mar 2006, 17:50
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
Tomasz Grysztar 18 Mar 2006, 18:01
That would require much more work from the side the assembler, and since you anyway have a linker available in any ELF-based system, I don't think it really worth it.
Post 18 Mar 2006, 18:01
View user's profile Send private message Visit poster's website Reply with quote
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn 18 Mar 2006, 20:50
Could it be that there is an error in your code for creating elf files? Because if I compile your example code and check the string table there is a string ".rel.text" and this section doesn´t exists in elf also the type is 9 where I get this name. So I assume that there is a "\0" missing between .rel and .text!
Post 18 Mar 2006, 20:50
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
Tomasz Grysztar 18 Mar 2006, 21:49
The ".rel.text" is a name of relocation section for the ".text" section (the ".text" string is re-used twice this way to reduce string table length). The section containing relocations for a given section is always generated automatically and given name created by attaching ".rel" in front of the name of section.
Post 18 Mar 2006, 21:49
View user's profile Send private message Visit poster's website Reply with quote
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn 18 Mar 2006, 22:01
Oh, I see. I think I have to reread the elf specifications. At the moment I´m writing the loader and linker for my os and it´s not easy if you do it for the first time!
Post 18 Mar 2006, 22:01
View user's profile Send private message Reply with quote
james



Joined: 07 Sep 2005
Posts: 45
Location: Australia
james 02 Jun 2006, 02:40
What is the command line for LD to compile and link the example?
Post 02 Jun 2006, 02:40
View user's profile Send private message MSN Messenger Reply with quote
amcl



Joined: 08 May 2006
Posts: 5
amcl 19 Jun 2006, 22:57
Thanks for the explanation Tomasz. I'll take this chance to say thank you for all of your hard work on fasm aswell! Very Happy

This is a nice paper by Ulrich Drepper (glibc developer) on writing shared libs for the curious.

http://people.redhat.com/drepper/dsohowto.pdf
Post 19 Jun 2006, 22:57
View user's profile Send private message Reply with quote
amcl



Joined: 08 May 2006
Posts: 5
amcl 19 Jun 2006, 23:36
@james: to link the example into a shared library you can do:

Code:
ld -m elf_i386 -shared -o libfoo.so.1.0.1 -soname libfoo.so.1 alib.o
    


The -m elf_i386 is only necessary if you are on x86-64 as I am.
Post 19 Jun 2006, 23:36
View user's profile Send private message Reply with quote
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn 11 Aug 2006, 14:37
How to make call to an function where the address is not known?

I tried the following and it didn´t work (ld error):
Code:
format ELF

section '.text' executable

public _start
extrn _kePrint

_start:
        CALL @f
@@:
        pop ebx
        
        sub ebx,rva @b

        lea esi,[ebx + rva msg_test]
        call dword[ebx + rva ptr2_kePrint]
        
        jmp $

section '.data' writeable

msg_test db 'Hello World from a module!\n',0
ptr2_kePrint dd _kePrint
    
Post 11 Aug 2006, 14:37
View user's profile Send private message Reply with quote
scientica
Retired moderator


Joined: 16 Jun 2003
Posts: 689
Location: Linköping, Sweden
scientica 12 Aug 2006, 10:43
uhm... maybe I'm missing something here. but this (sort of) wfm:
Code:
$ cat > test0.asm
format ELF

section '.text' executable

public PIC_example

PIC_example:
        push    ebx

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

        mov     eax,[ebx+rva _const]

        pop     ebx
        ret

_const dd 1234
^D
$ cat > test1.asm

format ELF

section '.text' executable

public _start
extrn _kePrint

_start:
        CALL @f
@@:
        pop ebx

        sub ebx,rva @b

        lea esi,[ebx + rva msg_test]
        call dword[ebx + rva ptr2_kePrint]

        jmp $

section '.data' writeable

msg_test db 'Hello World from a module!\n',0
ptr2_kePrint dd _kePrint
^D
$ fasm test0.asm
flat assembler  version 1.67.7  (16384 kilobytes memory)
3 passes, 380 bytes.
$ fasm test1.asm
flat assembler  version 1.67.7  (16384 kilobytes memory)
3 passes, 556 bytes.
$ ld -m elf_i386 -shared -o libtest.so.1.0.1 -soname libfoo.so.o *.o
ld: warning: creating a DT_TEXTREL in object.
$ file *.o libtest.so.1.0.1
test0.o:          ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
test1.o:          ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
libtest.so.1.0.1: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped
#; this creates an pie (PIC executable)
$ ld --pie -m elf_i386 -shared -o libtest.so.1.0.1 -soname libfoo.so.o *.o
ld: warning: creating a DT_TEXTREL in object.
$ file libtest.so.1.0.1
libtest.so.1.0.1: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped    

(I'm on a amd64 btw, but that sholdn't affect anythings here, my ld is "GNU ld version 2.16.1")
Post 12 Aug 2006, 10:43
View user's profile Send private message Visit poster's website Reply with quote
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn 12 Aug 2006, 13:19
I can compile my code, but ld gives me the following error (ld -shared pci.o -o pci.so)

Code:
pci.o:(.data+0x1d): undefined reference to `kePrint'
    


It should also be a shared object not a relocateable object!

I know that fasm supports the GOT, but does it also support the PLT?

Edit::

Ok, now it works (it seems so). I forgot to use my crosscompiled ld!
Post 12 Aug 2006, 13:19
View user's profile Send private message Reply with quote
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn 29 Aug 2006, 18:05
Are there plans to support PLT in the future?

I know that NASM supports it, but I don´t like to change my assembler, but I also need this feature. Another option would be to change the language, but this is also a step I don´t want to go!
Post 29 Aug 2006, 18:05
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
Tomasz Grysztar 30 Aug 2006, 11:43
How NASM supports it?
Post 30 Aug 2006, 11:43
View user's profile Send private message Visit poster's website Reply with quote
FlashBurn



Joined: 06 Jan 2005
Posts: 87
FlashBurn 30 Aug 2006, 11:54
I think it is better to give you a link to the documentation than explaining it myself!

http://nasm.sourceforge.net/doc/html/nasmdoc6.html#section-6.5.2

I hope it helps!
Post 30 Aug 2006, 11:54
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 12 Sep 2006, 00:08
With the current implementation of this can I call a proc of a shared library? How?

To be clear, how can I port this to Linux:

Code:
format PE GUI 4.0 DLL
entry DllEntryPoint

include 'win32a.inc'

section '.code' code readable executable

proc DllEntryPoint hinstDLL,fdwReason,lpvReserved
        mov     eax,TRUE
        ret
endp

proc MyFunc
    xor  eax, eax
    ret
endp

section '.edata' export data readable

  export 'MyDLL.DLL',\
         MyFunc,'MyFunc'

section '.reloc' fixups data discardable     


Code:
format PE GUI 4.0
entry start

include 'win32a.inc'

section '.code' code readable executable

  start:
        invoke  MyFunc
        ret

section '.idata' import data readable writeable

  library MyDLL,'MyDLL.DLL'

  import MyDLL,\
         MyFunc,'MyFunc'    


(The DLL should still be dynamically loaded)
Post 12 Sep 2006, 00:08
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 25 Sep 2006, 18:29
OK, I'll do a Windows only library then...
Post 25 Sep 2006, 18:29
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
Tomasz Grysztar 25 Sep 2006, 18:34
Try to take the example from the first post here, compile it into shared library, make an ELF object that uses the external function "PIC_example" and link it with "ld" to this shared library. I recall that was about all you'd need to do.
Post 25 Sep 2006, 18:34
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: 4624
Location: Argentina
LocoDelAssembly 25 Sep 2006, 18:40
Oh, sorry I thought that the problem of FlashBurn was that calling a proc of a shared library is not possible. I'll try it now

Thanks!!
Post 25 Sep 2006, 18:40
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
Tomasz Grysztar 25 Sep 2006, 18:44
I assure you that I got this example fully working before I posted here.
It just appears that I forgot to write about a few details that perhaps seemed obvious to me at the time. If you get it working, you may write your method down here, for the record. Wink
Post 25 Sep 2006, 18:44
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:  
Goto page 1, 2  Next

< 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-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.