Recent

Author Topic: [SOLVED] How to call a FPC compiled shared library under Alpine?  (Read 13026 times)

rarnu

  • New Member
  • *
  • Posts: 14
I'm now using Alpine Linux for some development. I find that the shared library compiled with FPC can't be loaded by other programs.

here's my library's code:

Code: Pascal  [Select][+][-]
  1. library mylib;
  2. {$mode objfpc}{$H+}
  3. uses
  4.   Classes, SysUtils;
  5.  
  6. function add(x: integer; y: integer): integer; cdecl;
  7. begin
  8.   Result := x + y;
  9. end;
  10.  
  11. exports
  12.   add;
  13.  
  14. begin
  15. end.
  16.  

These code compiled by command:
Code: Text  [Select][+][-]
  1. $ fpc mylib.lpr -FL/lib/libc.musl-x86_64.so.1
  2.  

There is no "ld-linux-x86-64.so.2" in Alpine Linux, even glibc is also not included. Only musl-libc can be used.

and here's my app for calling the lib:

Code: Pascal  [Select][+][-]
  1. program host;
  2. {$mode objfpc}{$H+}
  3.  
  4. uses
  5.   Classes, SysUtils, dynlibs;
  6.  
  7. type
  8.   TAdd = function (x: integer; y: integer): integer; cdecl;
  9.  
  10. var
  11.   libPath: string;
  12.   lib: TLibHandle;
  13.   mAdd: TAdd;
  14. begin
  15.   libPath:= ExtractFilePath(ParamStr(0)) + 'libmylib.so';
  16.   lib := loadLibrary(libPath);
  17.   mAdd := TAdd(GetProcAddress(lib, 'add'));
  18.   WriteLn(mAdd(1, 2));
  19. end;
  20.  

These code compiled by command:
Code: Pascal  [Select][+][-]
  1. $ fpc host.lpr -FL/lib/libc.musl-x86_64.so.1
  2.  

now I get "libmylib.so" and "host" files, and I try to run "host", it crashed with the message:

Code: Pascal  [Select][+][-]
  1. An unhandled exception occurred at $00007F4E99259B40:
  2. EAccessViolation:
  3.   $00007F4E99259B40
  4.   $0000000000422D84
  5.   $0000000000422D84
  6.   $0000000000422D84
  7.   $0000000000422D84
  8.   $0000000000422D84
  9.   $0000000000422D84
  10.   $0000000000422D84
  11.   $0000000000422D84
  12.   $0000000000422D84
  13.   $0000000000422D84
  14.   $0000000000422D84
  15.   $0000000000422D84
  16.   $0000000000422D84
  17.   $0000000000422D84
  18.   $0000000000422D84
  19.   $0000000000422D84
  20.  
  21. Segmentation fault
  22.  

I can't solve the problem with the given message, needs help.

And I have also tried, write these code with C and compiled with gcc, it works fine!!

I want to know the reason and how to make it work.

Help me please. thank you.
« Last Edit: June 13, 2021, 04:51:56 am by rarnu »

MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
Re: How to call a FPC compiled shared library under Alpine?
« Reply #1 on: June 11, 2021, 10:00:03 pm »
There is no "ld-linux-x86-64.so.2" in Alpine Linux, even glibc is also not included. Only musl-libc can be used.

That's pretty weird, since generally speaking ld-linux-something.so is a prerequisite for a standard .elf file.

Without volunteering that I have a solution but to keep the ball rolling, what is the output of this command

$ readelf -d `which gcc`

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: How to call a FPC compiled shared library under Alpine?
« Reply #2 on: June 11, 2021, 10:00:43 pm »
Hello Ramu.

Not sure it could help but what about to use for export code in "mylib" ?:

Code: Pascal  [Select][+][-]
  1. ...
  2. exports
  3.   add name 'add';
  4.  

And for fpc command line (added "-fPIC") ?:

Code: Bash  [Select][+][-]
  1. $ fpc mylib.lpr -fPIC -FL/lib/libc.musl-x86_64.so.1

And in "host" program, to localize the error ?:

Code: Pascal  [Select][+][-]
  1. ...
  2.  lib := loadLibrary(libPath);
  3.  if lib = nilhandle then
  4.   WriteLn(libpath + ' not loaded')
  5. else
  6. begin
  7.   mAdd := TAdd(GetProcAddress(lib, 'add'));
  8.   if assigned(mAdd)
  9.   WriteLn(mAdd(1, 2)) else
  10.   WriteLn('mAdd  not assigned')
  11. end;

« Last Edit: June 11, 2021, 10:10:19 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

rarnu

  • New Member
  • *
  • Posts: 14
Re: How to call a FPC compiled shared library under Alpine?
« Reply #3 on: June 12, 2021, 03:02:25 am »
There is no "ld-linux-x86-64.so.2" in Alpine Linux, even glibc is also not included. Only musl-libc can be used.

That's pretty weird, since generally speaking ld-linux-something.so is a prerequisite for a standard .elf file.

Without volunteering that I have a solution but to keep the ball rolling, what is the output of this command

$ readelf -d `which gcc`

MarkMLl

Thank you MarkMLI, here is my command result:

Code: Pascal  [Select][+][-]
  1. Dynamic section at offset 0xf49f8 contains 21 entries:
  2.   Tag        Type                         Name/Value
  3.  0x0000000000000001 (NEEDED)             Shared library: [libc.musl-x86_64.so.1]
  4.  0x000000000000000c (INIT)               0x403000
  5.  0x000000000000000d (FINI)               0x479e6f
  6.  0x0000000000000019 (INIT_ARRAY)         0x4f31d0
  7.  0x000000000000001b (INIT_ARRAYSZ)       112 (bytes)
  8.  0x000000006ffffef5 (GNU_HASH)           0x4002c8
  9.  0x0000000000000005 (STRTAB)             0x401090
  10.  0x0000000000000006 (SYMTAB)             0x400328
  11.  0x000000000000000a (STRSZ)              1097 (bytes)
  12.  0x000000000000000b (SYMENT)             24 (bytes)
  13.  0x0000000000000015 (DEBUG)              0x0
  14.  0x0000000000000003 (PLTGOT)             0x4f5b98
  15.  0x0000000000000002 (PLTRELSZ)           3144 (bytes)
  16.  0x0000000000000014 (PLTREL)             RELA
  17.  0x0000000000000017 (JMPREL)             0x4015b8
  18.  0x0000000000000007 (RELA)               0x4014e0
  19.  0x0000000000000008 (RELASZ)             216 (bytes)
  20.  0x0000000000000009 (RELAENT)            24 (bytes)
  21.  0x0000000000000018 (BIND_NOW)          
  22.  0x000000006ffffffb (FLAGS_1)            Flags: NOW
  23.  0x0000000000000000 (NULL)               0x0
  24.  
  25.  

rarnu

  • New Member
  • *
  • Posts: 14
Re: How to call a FPC compiled shared library under Alpine?
« Reply #4 on: June 12, 2021, 03:08:25 am »
Hello Ramu.

Not sure it could help but what about to use for export code in "mylib" ?:

Code: Pascal  [Select][+][-]
  1. ...
  2. exports
  3.   add name 'add';
  4.  

And for fpc command line (added "-fPIC") ?:

Code: Bash  [Select][+][-]
  1. $ fpc mylib.lpr -fPIC -FL/lib/libc.musl-x86_64.so.1

And in "host" program, to localize the error ?:

Code: Pascal  [Select][+][-]
  1. ...
  2.  lib := loadLibrary(libPath);
  3.  if lib = nilhandle then
  4.   WriteLn(libpath + ' not loaded')
  5. else
  6. begin
  7.   mAdd := TAdd(GetProcAddress(lib, 'add'));
  8.   if assigned(mAdd)
  9.   WriteLn(mAdd(1, 2)) else
  10.   WriteLn('mAdd  not assigned')
  11. end;

Thank you Fred, I have tried your code.

I find the crash happens when calling "loadLibrary", I also tried "SafeLoadLibrary" still not work.

And then I tried the C code like:

Code: C  [Select][+][-]
  1. // add.h
  2. int add(int x, int y);
  3.  

Code: C  [Select][+][-]
  1. // add.c
  2. #include "add.h"
  3.  
  4. int add(int x, int y) {
  5.   return x + y;
  6. }
  7.  

and compiled with command

Code: Text  [Select][+][-]
  1. $ gcc -shared -o libmylib.so add.c
  2.  

Now I get a library named "libmylib.so" and this library can be loaded by FPC's "loadLibrary" and it works fine.

what's the difference between C's library and FPC's library?

PierceNg

  • Sr. Member
  • ****
  • Posts: 369
    • SamadhiWeb
Re: How to call a FPC compiled shared library under Alpine?
« Reply #5 on: June 12, 2021, 04:28:55 am »
There is no "ld-linux-x86-64.so.2" in Alpine Linux, even glibc is also not included. Only musl-libc can be used.

There is a libc-compat package on Alpine. All it does is to create a link to musl-libc. I've used this to run Ubuntu-compiled FPC programs on Alpine.

Try installing libc-compat package and re-run your program. If that fails, try rebuilding your shared library and program on Ubuntu, say, then run on Alpine with libc-compat installed.

If still doesn't work, glibc is also available as an Alpine package.

rarnu

  • New Member
  • *
  • Posts: 14
Re: How to call a FPC compiled shared library under Alpine?
« Reply #6 on: June 12, 2021, 05:49:28 am »
There is no "ld-linux-x86-64.so.2" in Alpine Linux, even glibc is also not included. Only musl-libc can be used.

There is a libc-compat package on Alpine. All it does is to create a link to musl-libc. I've used this to run Ubuntu-compiled FPC programs on Alpine.

Try installing libc-compat package and re-run your program. If that fails, try rebuilding your shared library and program on Ubuntu, say, then run on Alpine with libc-compat installed.

If still doesn't work, glibc is also available as an Alpine package.

Thank you PierceNg, I have tried to install a compat lib of glibc. here's the results:

with official libc6-compat, FPC library can't load, and the app with mysql(needs official libmysqlclient.so) inside works fine.
with 3rd-party glibc 2.33, FPC library works fine, but the libmysqlclient.so can't load.

I want my FPC library and mysql both work, but ...

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: How to call a FPC compiled shared library under Alpine?
« Reply #7 on: June 12, 2021, 06:09:59 am »
Hello Rarnu.

What do you get with this console command to check the methods of the fpc library?

Code: Bash  [Select][+][-]
  1. $ nm -D libmylib.so
« Last Edit: June 12, 2021, 06:13:01 am by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

rarnu

  • New Member
  • *
  • Posts: 14
Re: How to call a FPC compiled shared library under Alpine?
« Reply #8 on: June 12, 2021, 07:09:05 am »
Hello Rarnu.

What do you get with this console command to check the methods of the fpc library?

Code: Bash  [Select][+][-]
  1. $ nm -D libmylib.so

yep, I think this is the key point. FPC's library's exported methods is different with C's

Code: Pascal  [Select][+][-]
  1. 00000000000470a0 T add
  2.  

FPC exports only one method, but C's library exports more:

Code: Pascal  [Select][+][-]
  1.                  w _ITM_deregisterTMCloneTable
  2.                  w _ITM_registerTMCloneTable
  3.                  w __cxa_finalize
  4.                  w __deregister_frame_info
  5.                  w __register_frame_info
  6. 0000000000001175 T _fini
  7. 0000000000001000 T _init
  8. 000000000000113f T add
  9.  

here are "_init" and "_fini", I think my lib must have them exported, but how?

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: How to call a FPC compiled shared library under Alpine?
« Reply #9 on: June 12, 2021, 02:57:11 pm »
Quote
here are "_init" and "_fini", I think my lib must have them exported, but how?

Hum, I think you will need a guru.

Maybe you can try to add those "_init" and "_fini" in your lib and export it.

https://docs.oracle.com/cd/E88353_01/html/E37854/u-fini-9e.html

Sorry, I dont use Alpine so I cannot test.

Fre;D
« Last Edit: June 12, 2021, 02:59:59 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

rarnu

  • New Member
  • *
  • Posts: 14
[Solved] How to call a FPC compiled shared library under Alpine?
« Reply #10 on: June 13, 2021, 04:51:36 am »
Thank you all for the help. I find the final solution.

first of all, official libc6-compat must be installed into Alpine. Do NEVER install the 3rd-party glibc, it will override ld-linux-x86-64.so.2 and break other packages in Alpine because almost all packages in Alpine are built by musl-libc, and the original ld-linux-x86-64.so.2 is a symlink from libc.musl-x86_64.so .

so my solution is to remove the dependency of ld-linux-x86-64.so.2 from my lib.

use the command for make a like.res:

Code: Pascal  [Select][+][-]
  1. $ fpc -Cn mylib.lpr
  2.  

It will generate the link.res and ppas.sh. Open link.res, find "INPUT (ld-linux-x86-64.so.2)" and then remove it. run ppas.sh for build a shared library.

Code: Pascal  [Select][+][-]
  1. $ ./ppas.sh
  2.  

here can get a libmylib.so without ld-linux-x86-64.so.2 required. use "readelf -d libmylib.so" to check it.

And one more step is to remove "dynlibs" from host app. In Alpine can't use that.

I added a compile switch to it:

Code: Pascal  [Select][+][-]
  1. uses Classes, SysUtils {$IFNDEF ALPINE}, dynlibs {$ENDIF};
  2.  

and compile host app with the command:

Code: Pascal  [Select][+][-]
  1. $ fpc -dALPINE host.lpr
  2.  

well, the problem is solved.  :D


MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
Re: [SOLVED] How to call a FPC compiled shared library under Alpine?
« Reply #11 on: June 13, 2021, 09:53:54 am »
Congratulations on fixing it and thanks for keeping us updated.

Since what you did involved changing FPC-generated files (i.e. wasn't just a fix to your Alpine configuration) I suggest it would be worthwhile posting it on Mantis so that the core developers are aware... not so much because they're expected to do support what can only be described as a minority platform but in case this could usefully be handled in a more general and widely-applicable way.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: [Solved] How to call a FPC compiled shared library under Alpine?
« Reply #12 on: June 13, 2021, 12:57:28 pm »
Code: Pascal  [Select][+][-]
  1. uses Classes, SysUtils {$IFNDEF ALPINE}, dynlibs {$ENDIF};
  2.  

well, the problem is solved.  :D

Wow, congrats!

May I ask you how do you load the library if you dont use dynlibs (LoadLibrary) ?
Do you use instead "external" (and then no dynamic loading)?

Fre;D

I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

rarnu

  • New Member
  • *
  • Posts: 14
Re: [Solved] How to call a FPC compiled shared library under Alpine?
« Reply #13 on: June 13, 2021, 06:09:26 pm »
Wow, congrats!

May I ask you how do you load the library if you dont use dynlibs (LoadLibrary) ?
Do you use instead "external" (and then no dynamic loading)?

Fre;D

I have not found the way to use a library dynamically. Just the simplest code:

Code: Pascal  [Select][+][-]
  1. program host;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses classes, Sysutils{$IFNDEF ALPINE}, dynlibs {$ENDIF};
  6.  
  7. function add(x: integer; y: integer): integer; cdecl; external 'mylib';
  8.  
  9. begin
  10.   writeln(add(1, 2));
  11. end.
  12.  

and execute it by:

Code: Pascal  [Select][+][-]
  1. $ LD_LIBRARY_PATH=. ./host
  2.  

or make libmylib.so a symlink to "/usr/lib" is also worked.

And, I have tried something else to make it dynamic but failed. here is the code:

Code: Pascal  [Select][+][-]
  1. program host;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses Classes, Sysutils, dl;
  6.  
  7. type
  8.   TAdd = function (x: Integer; y: Integer): Integer; cdecl;
  9.  
  10. var
  11.   libPath: string;
  12.   lib: Pointer;
  13.   mAdd: TAdd;
  14. begin
  15.   libPath:= ExtractFilePath(ParamStr(0)) + 'libmylib.so';
  16.   lib := dlopen(PChar(libPath), RTLD_NOW);
  17.   mAdd := TAdd(dlsym(lib, 'add'));
  18.   writeln(mAdd(1, 2));
  19. end.
  20.  

this code works on my ubuntu and manjaro. But on Alpine it crashes when calling "dlopen" and no solution now.

on Alpine, even the C code with "dlopen" is also not work. Strange...
« Last Edit: June 13, 2021, 06:12:40 pm by rarnu »

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: [Solved] How to call a FPC compiled shared library under Alpine?
« Reply #14 on: June 13, 2021, 06:31:55 pm »
Code: Pascal  [Select][+][-]
  1. program host;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses Classes, Sysutils, dl;
  6.  
  7. type
  8.   TAdd = function (x: Integer; y: Integer): Integer; cdecl;
  9.  
  10. var
  11.   libPath: string;
  12.   lib: Pointer;
  13.   mAdd: TAdd;
  14. begin
  15.   libPath:= ExtractFilePath(ParamStr(0)) + 'libmylib.so';
  16.   lib := dlopen(PChar(libPath), RTLD_NOW);
  17.   mAdd := TAdd(dlsym(lib, 'add'));
  18.   writeln(mAdd(1, 2));
  19. end.
  20.  

this code works on my ubuntu and manjaro. But on Alpine it crashes when calling "dlopen" and no solution now.

on Alpine, even the C code with "dlopen" is also not work. Strange...

Hum, strange indeed.

In dl.pas, "dlopen" has this code:

Code: Pascal  [Select][+][-]
  1. function dlopen(Name : PChar; Flags : longint) : Pointer; cdecl; external libdl;  

And libdl is defined as:

Code: Pascal  [Select][+][-]
  1. const
  2. {$ifdef BSD}   // dlopen is in libc on FreeBSD.
  3.   LibDL = 'c';
  4. {$else}
  5.   {$ifdef HAIKU}
  6.     LibDL = 'root';
  7.   {$else}
  8.     LibDL = 'dl';
  9.   {$endif}
  10. {$endif}        

Could you check if there is a /usr/lib/libdl.so in your system?

Maybe you will have to create a symlink that point to the installed libdl.so.x of your system.

[EDIT] Other maybe: It could be that in Alpine dlopen is part of a other library than libdl.so.x .

If it is the case, imho, fpc should add a {$ifdef ALPINE} define (like MarkMLI proposed somebody insinuated).

Fre;D
« Last Edit: June 13, 2021, 08:41:36 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

 

TinyPortal © 2005-2018