It's not safe to raise exceptions across the DLL boundary because of the different memory management. To be more precise, it is possible if you use a shared memory manager like: ShareMem, SimpleShareMem, etc...
Or the cmem unit (c memory manager), but I'm not sure delphi and fpc's exception mechanisms are the same (compatible). It would be theoretically better if you had a fpc dll, and and fpc exe, if you were going to try this, not a delphi exe with an fpc dll, or vice versa.
And as for the alternative solution: catch all the exceptions in the DLL itself (not the exe) and make the DLL return error codes, instead of throwing exceptions that the exe will catch. This is obnoxious and tedious, but seems to be the only safe solution for throwing exceptions in a dll. Simply catch them all and return an error code that the exe can deal with. Annoying, I know.
Sorry, standard thread necromancer apology applies.