Recent

Author Topic: Call freepascal unit from C  (Read 6565 times)

Olam

  • New Member
  • *
  • Posts: 12
Call freepascal unit from C
« on: June 08, 2022, 07:10:14 pm »
Hi,

I'm trying to call functions from pascal units from C, it works fine as long as the pascal functions doesn't call anything, even like writeln. passing and returning integer works fine.
I can debug into the pascal function and into writeln, it looks like it's doing stuff but at the end it fails in FPC_IOCHECK with "Exception: EXC_BAD_ACCESS (code=1, address=0x8)"

Any hints?

PascalDragon

  • Hero Member
  • *****
  • Posts: 6396
  • Compiler Developer
Re: Call freepascal unit from C
« Reply #1 on: June 09, 2022, 08:55:42 am »
Any hints?

Yes: the RTL is not initialized. You can't just simply use the object files of the units and link them together with some C main function and expect them to work, because the main program or library is responsible for correctly initializing the RTL.
So my suggestion if you want to use functionality like Pascal I/O or even the heap (so basically anything useful if you want to use higher level functionality) would be that you compile your Pascal code as a library, export the functions you require and import those from your C code. For everything else you need to have good knowledge about how the RTL works.

Olam

  • New Member
  • *
  • Posts: 12
Re: Call freepascal unit from C
« Reply #2 on: June 09, 2022, 12:31:47 pm »

I experimented with cdecl with no result. It indeed looks like something is not initialised as needed. I'l have a go at those suggestions.

Thanks!

MarkMLl

  • Hero Member
  • *****
  • Posts: 8572
Re: Call freepascal unit from C
« Reply #3 on: June 09, 2022, 12:58:53 pm »
I experimented with cdecl with no result. It indeed looks like something is not initialised as needed. I'l have a go at those suggestions.

Pretty much everybody defers to PascalDragon as one of the core team for this sort of thing.

Irrespective of consideration of calling convention, I'd suggest that the first stuff to chop out is any calls of WriteLn() etc., followed by Pascal-style strings (plus dynamic arrays etc.) since they are heavy users of the heap.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Roland57

  • Hero Member
  • *****
  • Posts: 609
    • msegui.net
Re: Call freepascal unit from C
« Reply #4 on: June 09, 2022, 01:18:04 pm »
So my suggestion if you want to use functionality like Pascal I/O or even the heap (so basically anything useful if you want to use higher level functionality) would be that you compile your Pascal code as a library, export the functions you require and import those from your C code.

If I may jump into the discussion, I would be interested in seeing a working example of what you say. Has someone already done that?
My projects are on Codeberg.

Olam

  • New Member
  • *
  • Posts: 12
Re: Call freepascal unit from C
« Reply #5 on: June 09, 2022, 01:48:05 pm »
Ha! found the appropriate section in the programmers manual 7.2 Making libraries explains exactly this.
Thanks PascalDragon!

Roland57  this flys, AUnit is a simple unit with a function, Func, that does a writeln where it dumped when called directly.

Code: Pascal  [Select][+][-]
  1. library stuff;
  2. uses AUnit;
  3. function libFunc(percent : integer) : integer; cdecl; public name 'libFunc';
  4. begin
  5.     libFunc := Func(percent);
  6. end;
  7. exports libFunc;
  8. end.
  9.  

and
Code: C  [Select][+][-]
  1. extern "C" int libFunc(int) asm("libFunc");
You need asm("") if you are on macOS, to get around the underscore to c symbols.

Now, I need a strategy to avoid having to rename all uses of Func and thousands more from the C++. Another story, WHY is pascal case insensitive grrrr :P

UPDATE:
Good hints al around, thanks guys!
By removing the "public name 'Func';" from AUnit, You can, in the library, refer to AUnit.Func and export Func so C++ can call Func like it's a unique symbol so the extern "C" int libFunc... can be extern "C" Func... as it was before, plus the asm() statement.
This is good stuff!
« Last Edit: June 09, 2022, 03:29:30 pm by Olam »

Zoran

  • Hero Member
  • *****
  • Posts: 1988
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Call freepascal unit from C
« Reply #6 on: June 09, 2022, 01:56:58 pm »
So my suggestion if you want to use functionality like Pascal I/O or even the heap (so basically anything useful if you want to use higher level functionality) would be that you compile your Pascal code as a library, export the functions you require and import those from your C code.

If I may jump into the discussion, I would be interested in seeing a working example of what you say. Has someone already done that?

Ha! found the appropriate section in the programmers manual 7.2 Making libraries explains exactly this.
Thanks PascalDragon!

Apart from Making libraries from chapter 7 (https://www.freepascal.org/docs-html/current/prog/progse29.html), there is a separate chapter in Programming reference, where creating a library is well explained: https://www.freepascal.org/docs-html/current/prog/progch12.html

Also take a look at wiki page: https://wiki.freepascal.org/shared_library

Further, you can search internet for creating libraries in Delphi, and for importing dynamic libraries in C.
Swan, ZX Spectrum emulator https://github.com/zoran-vucenovic/swan

Fred vS

  • Hero Member
  • *****
  • Posts: 3942
    • StrumPract is the musicians best friend
Re: Call freepascal unit from C
« Reply #7 on: June 09, 2022, 04:05:13 pm »
Hello.

Does it exist a demo how to create libraries with fpc+LLVM?

With explanation, step by step, of all the process to install+use fpc+LLVM?
Could the resulting compiled library compete with equivalent C code compiled with clang, mainly in float calculation?

(Or maybe fpc+LLVM is not yet ready so sorry for the noise)

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

BobDog

  • Sr. Member
  • ****
  • Posts: 394
Re: Call freepascal unit from C
« Reply #8 on: June 09, 2022, 10:17:05 pm »
Try this
replace.pas
Code: Pascal  [Select][+][-]
  1. library replace;
  2. uses
  3. sysutils;
  4.  
  5. function SAR(s:pchar;find:pchar;replace:pchar):pchar;
  6. begin
  7. exit(pchar(stringreplace(ansistring(s),ansistring(find),ansistring(replace),[rfReplaceAll])));
  8. end;
  9.  
  10. exports SAR;
  11. end.
  12.  
  13.  
put replace.dll in the same folder as this c code
Code: Pascal  [Select][+][-]
  1.  
  2. #include<stdio.h>
  3. #include<windows.h>
  4.  
  5. int main(){
  6.  
  7.   HANDLE ldll;
  8.  typedef char* ( * thesar)(char*,char*,char*);
  9. thesar sar;
  10.   ldll = LoadLibrary("replace.dll");
  11.   if(ldll>(void*)HINSTANCE_ERROR){
  12.     sar =(thesar) GetProcAddress(ldll, "SAR");
  13.     printf("%p %s\n",sar," Is the address");
  14.    
  15.   } else {
  16.     printf("ERROR.");
  17.   }
  18.  
  19.   char* string="abcdefgh";
  20.   char* find="cde";
  21.   char * replace="X";
  22.   char * result=sar(string,find,replace);
  23.   printf("%s\n",result);
  24.   system("pause");
  25.  
  26. }
Tested 64 bits 3.2.2. pascal and gcc
Works OK here, you are taking the function stringreplace from the unit sysutils and using it in c.
An object file IMO doesn't have the wherewithal to transfer that chunk of the unit, although, I admit, I didn't try it.
sar stands for search and replace, not very original, but it saves typing.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6396
  • Compiler Developer
Re: Call freepascal unit from C
« Reply #9 on: June 10, 2022, 09:16:32 am »
So my suggestion if you want to use functionality like Pascal I/O or even the heap (so basically anything useful if you want to use higher level functionality) would be that you compile your Pascal code as a library, export the functions you require and import those from your C code.

If I may jump into the discussion, I would be interested in seeing a working example of what you say. Has someone already done that?

Don't know if someone did this already, I know that it can be done if one is dedicated enough, but no I won't provide an example for that.

Roland57  this flys, AUnit is a simple unit with a function, Func, that does a writeln where it dumped when called directly.

This isn't what Roland57 is asking for.

Code: Pascal  [Select][+][-]
  1. library stuff;
  2. uses AUnit;
  3. function libFunc(percent : integer) : integer; cdecl; public name 'libFunc';
  4. begin
  5.     libFunc := Func(percent);
  6. end;
  7. exports libFunc;
  8. end.
  9.  

and
Code: C  [Select][+][-]
  1. extern "C" int libFunc(int) asm("libFunc");
You need asm("") if you are on macOS, to get around the underscore to c symbols.

There should be no need for the asm directive as well as the public name ... directive when done correctly. What you might need to do however is to add the export directive to your function; the compiler should then export the function with the correct mangling (I'll have to cross check that on my old Mac OS).

Does it exist a demo how to create libraries with fpc+LLVM?

With explanation, step by step, of all the process to install+use fpc+LLVM?
Could the resulting compiled library compete with equivalent C code compiled with clang, mainly in float calculation?

(Or maybe fpc+LLVM is not yet ready so sorry for the noise)

LLVM is not relevant for this topic. But to build a LLVM based FPC you follow the corresponding tutorial and then use the compile just like normal.

Olam

  • New Member
  • *
  • Posts: 12
Re: Call freepascal unit from C
« Reply #10 on: June 10, 2022, 11:33:56 am »
asm("name") is only needed for macOS to be able to call with "name" instead of "_name". C on mach-o prepends symbols with an underscore. so extern "C" void sym(); refers to a symbol named _sym(). Same for clang and gcc.
« Last Edit: June 10, 2022, 11:44:31 am by Olam »

Roland57

  • Hero Member
  • *****
  • Posts: 609
    • msegui.net
Re: Call freepascal unit from C
« Reply #11 on: June 10, 2022, 12:26:41 pm »
Thank you all for your answers.

Don't know if someone did this already, I know that it can be done if one is dedicated enough, but no I won't provide an example for that.

Some years ago I made a Pascal library with usage examples in Basic, C and Pascal. Maybe it could interest someone, so I post it here. But it's Windows only. In the meantime I switched to Linux. So I would be more interested in a multiplatform example.

(It's a library who searches if a checkmate exists for a given position of chess.)

Apart from Making libraries from chapter 7 (https://www.freepascal.org/docs-html/current/prog/progse29.html), there is a separate chapter in Programming reference, where creating a library is well explained: https://www.freepascal.org/docs-html/current/prog/progch12.html

Also take a look at wiki page: https://wiki.freepascal.org/shared_library

Thank you for the links. I see there is a full example in chapter 12. Good!

P.-S. Attachment deleted. New version of the project here.
« Last Edit: June 13, 2022, 07:20:19 pm by Roland57 »
My projects are on Codeberg.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6396
  • Compiler Developer
Re: Call freepascal unit from C
« Reply #12 on: June 10, 2022, 01:13:25 pm »
asm("name") is only needed for macOS to be able to call with "name" instead of "_name". C on mach-o prepends symbols with an underscore. so extern "C" void sym(); refers to a symbol named _sym(). Same for clang and gcc.

But that's the point: you shouldn't need that, because the compiler knows about the C prefix and should insert it itself. If it doesn't then either there is a bug or you do something wrong.

BobDog

  • Sr. Member
  • ****
  • Posts: 394
Re: Call freepascal unit from C
« Reply #13 on: June 10, 2022, 03:57:29 pm »

I have added a writeln to my dll
procedure PRINT(s:pchar);
begin
writeln(ansistring(s));
end;
But it is so trivial, no need to alter my previous post.
However to create writeln as a variadic procedure, to accept different data types, seperated by commas, is not so trivial, in fact I can see no examples, references, or help about pascal variadic procedures.
Maybe somebody could help?
One of the  "raisons d'être" of dll's is to use them in other windows languages surely, and .so for Linux.
The pascal dll works perfectly in gcc and freebasic.
It is quite large though, 308 kb for the 64 bit.
But using strip can get it to 117 kb.
the .o file associated with the dll is only 8 kb, so, unless it uses no pascal in-builts it will be useless to load in other languages.

Hi roland57, we don't see you much in FB these days.







Olam

  • New Member
  • *
  • Posts: 12
Re: Call freepascal unit from C
« Reply #14 on: June 10, 2022, 04:38:14 pm »
asm("name") is only needed for macOS to be able to call with "name" instead of "_name". C on mach-o prepends symbols with an underscore. so extern "C" void sym(); refers to a symbol named _sym(). Same for clang and gcc.

But that's the point: you shouldn't need that, because the compiler knows about the C prefix and should insert it itself. If it doesn't then either there is a bug or you do something wrong.

Ok, makes sense, that's what I would have expected, but adding "public name 'Func'" to a declaration makes a Symbol with the name "Func", not "_Func". Without public name 'Name' I'm left with the mangled name, not sure how to refer to that cleanly? So, bug? I would ofc prefer not to need the asm("")
« Last Edit: June 10, 2022, 04:40:16 pm by Olam »

 

TinyPortal © 2005-2018