What the ELF linker does is that it ensures that static and dynamic linker produce the same result. So using shared objects does not create any new problems. You can create some if you use of non-default visibility or version or linker scripts, but you obviously wouldn't do that if it isn't safe in that particular case.
Now if you use incompatible sets of compiler flags for building different objects, whether shared or static, in one application, you will have problems. You can have two kinds of problems:
The flags are so incompatible that calling convention, structure layout or some other such parameter is different between the modules. Obviously the only solution is to know which compiler options always have to remain set to the platform defaults.
The flags modify content of the headers and thus violate one definition rule. Authors of standard libraries, at least the open-source ones, know well how to avoid breaking compatibility between objects. But if you have some special library who's author were not careful, you can get in trouble and will have to make sure the compilation flags are compatible.
In Linux I've not seen these problems happen. Everybody knows not to touch the compiler flags that could break anything and there are no special incompatible versions for debug or such (gcc can emit debug information in optimizing build, so you normally just get unstripped version of the same object or lately even just the debug information for the normal object split out to separate file).
This is different from Windows, where:
- Due to the way shared libraries need explicit export and import there will not merge symbols (like template instances or class impedimenta) generated into different shared libraries.
- Have separate debug and release runtimes that differ in both the shared library used and lot of preprocessor magic. It means that you can't link your debug build to libraries built with the release version, so every library needs to ship debug and release variant. And often variant for static and dynamic linking. And despite all this trouble I don't think the debug support on Windows is better; e.g. Linux libc has hooks for replacing allocator (with debug one) which is always gross hack on Windows and Linux has great tools like Valgrind.
- Have lots of compiler flags that get flipped for various compatibility reasons, causing more complications. It has to be said that Microsoft is in more difficult position here. Since they cater primarily for the closed-source programmers, they have to assume things can't be recompiled and have to provide various compatibility kludges to keep things working. Linux people just assume things can be recompiled and do a breaking change when things get too complicated, like the switch to ELF format was; The ELF format was created between 1997 and 1999, while Windows objects are still backward compatible to the old Windows 3.1 ones. At the cost of all the mess.