Free Pascal dylib exports with name clauses not findable via dlsym on macOS

Free Pascal dylib exports with name clauses not findable via dlsym on macOS
typescript
Ethan Jackson

I'm creating a Free Pascal dynamic library (.dylib) on macOS that works on Windows but fails to load symbols on macOS. The symbols appear in the symbol table when checked with nm, but dlsym cannot find them. Working Windows exports:

pascal exports GetName name 'GetName', GetBid name 'GetBid', GetCard name 'GetCard';

Symbol table shows exports correctly:

bash$ nm -gU libplayer.dylib 0000000000005360 T GetBid 0000000000005370 T GetCard 0000000000005350 T GetName

But dlsym fails to find them:

c void* handle = dlopen("./libplayer.dylib", RTLD_LAZY); // Loads successfully void* symbol = dlsym(handle, "GetName"); // Returns NULL printf("Error: %s\n", dlerror()); // "symbol not found"

The library loads successfully, symbols appear in nm output, but are not accessible via dlsym. This only happens on macOS - the same code works fine on Windows.

Environment:

  • macOS (Apple Silicon)
  • Free Pascal 3.2.2
  • Compiled with: -fPIC -k-no_order_inits -k-dylib

What causes this issue and how can I make the symbols accessible to dlsym?

Answer

The issue is caused by the name clauses in the exports section. On macOS, Free Pascal's name clause creates symbols that appear in the static symbol table (visible to nm) but are not properly added to the dynamic symbol table (required for dlsym).

Solution: Remove the name clauses entirely

Change from:

exports GetName name 'GetName', GetX name 'GetBid', GetY name 'GetCard';

To:

exports GetName, GetBid, GetCard;

Why this works:

  • The function names remain identical

  • Symbols are properly exported to both static and dynamic symbol tables

  • dlsym can now find the symbols successfully

  • Works on both Windows and macOS

Verification:

void* handle = dlopen("./libplayer.dylib", RTLD_LAZY); void* symbol = dlsym(handle, "GetName"); // Now returns valid pointer

Key insight: The name clause is only necessary when you want to change the exported symbol name. When the exported name matches the function name exactly, omitting the name clause avoids this macOS-specific linking issue.

This appears to be a Free Pascal compiler/linker quirk specific to macOS dylib generation.

Related Articles