shared libaries are handled the same way: an application loading a shared libary will be linked by the system by resolving names in a defined order: the order specified in the compiled applications, which lists the shared libraries it needs in a significant order. If two shard libraries export the same symbol, only one will be used: the symbol coming from the first library (the other symbol from a further-listed shared library may still be used indirectly, if the second library has other symbols used by the application, and the application then allows the second distinct implementation of the first symbol used indirectly)
Say that an apps needs symbols ("a","b","c") from "sharedlibary1" and symbols ("d","e","f") from "sharedlibary2". The "sharedlibrary2" may also export the symbol "a" (used indirectly within sharedlibary2 to implement "c"). The app will itself will use directly only "a" from "sharedlibrary1" because the application was compiled to load and use "sharedlibary1,sharedlibary2" in that precise order. But when the application will use "d" from "sharedlibary2", this could cause the implementation "a" from "sharedlibary2" to be used, even if there's also the separate implementation of "a" in sharedlibrary1.
In all cases, the order or resolution is always important and needs to be specified. For this reason, shared libraries are not used in an unordered collection of library names: there must be a specified order (and typically shared libaries are loaded and resolved one at a time, and internal uses by shared libaries themselves are resolved internally by each shared libary itself, specifying its own internal dependencies (already resolved when they were compiled), or external dependencies (these additional dependencies must have NO impact to the application using it, unless the application loading a shared DLL also instructs that DLL to allow resolving its own external dependencies using a path order specified by the application, to override the default path included in the shared library itself; for most cases, such overrides are not possible but many shared library loaders are using an external path, such as in the environment, to indicate where to load the other libraries: a DLL loader may check that the located libaries match a specific digital signature to accept using it, and if not, the lookup will need to search on other entries of the environment path: this can prevent unexpected matches, and it's a solution that allows "signed" libraries to be specified in random order; if libraries are not signed and the application or libraries do not specify a specific digital signature or an absolute path for locating them, then nothing will prevent duplicate symbols to occur, except the specified order).
Symbol dependies form an oriented graph across all modules, with several layers of locality, each module defining its own order of dependencies (the names of shared libaries are themselves also "symbols", like normal symbols attached to individual objects inside each library or module).