It seems to me like the discussion in this thread derailed a bit. That said, I want to offer my opinion on the static vs dynamic linking debate before returning to topic.
I did not find much about the benefits of dynamic linking. I did find the GNU people liking the lower amount of redundancy and total binary size of the system, and I did find this article about dynamic linking in Swift:
https://faultlore.com/blah/swift-abi/
The case of dynamic linking in Swift
After reading it, my understanding is that Apple used dynamic linking to keep parts of the standard library in cache in order to improve efficiency. Following the article, they wanted code sharing so much that they even willingly sacrificed cross-module access efficiency to enable it. This mainly works because Apple controls the ecosystem and can enforce almost all running software using the exact same dynamic library, so it seems a bit of a special case.
I would imagine the benefits to primarily touch background tasks, since they should be relatively light on logic and interact with the OS a lot. Else, any active process with a large enough working set would eventually evict the standard library, or at least big parts of it, if it doesn't touch it in the inner loop.
In total, I wouldn't see many opportunities like that in an open, heterogenous system. You would need to link to the exact same version of a library, and that library would have to be small (so it fits in cache next to the working set) and frequently used (so no working set evicts it).
The case of dynamic linking in ForwardCom
From an implementation perspective, ForwardCom doesn't lend itself to dynamic linking all that much. In particular, ForwardCom is much more sensitive to memory fragmentation at a macro level, which does not mean related functions being put next to each other, but putting code in separate memory segments with different address translations and/or permissions.
Compared to the nearly unlimited number of mappings in deeply nested paging, the proposed memory map in ForwardCom has quite a limited capacity. I am currently thinking of three mapping strategies:
- Mapping a combination of libraries into a single segment, efficient mapping, limited code sharing, extremely wasteful for RAM
- Mapping each library into its own segment, medium mapping efficiency, full code sharing, still quite wasteful for RAM
- Mapping each library into multiple segments, terrible mapping efficiency, full code sharing, easy to save on RAM
Each strategy has distinct problems, but dynamic linking in general requires some inefficiencies, limiting optimization potential across libraries and requiring either to patch binary code with long jumps or working with pointers for linking.
On the other hand, one thing that ForwardCom hopes to achieve are a lot more efficient system calls. Putting common functionality in a "software driver" and accessing it via system calls instead of using regular dynamic libraries might be another interesting research opportunity.
Linker symbol lookup
My main question would be how high the payoff is, with the proposal adding considerable complexity to the object file format. What I do like about hashing is not needing to touch a bunch of random memory locations for searching. Do we know of any evidence for a linker (static or dynamic) being severely bottlenecked by this lookup? In the case of static linkers, do modern ones such as mold produce (much) worse code than the big, slow ones? I would accept being half as fast as 'cp' (
https://github.com/rui314/mold) as quite satisfactory.