What functionality or convenience is gained by having these offsets be negative values from the base address?
It provided easy access to two lists that can be extended independently in future versions with a single pointer.
The Long Read:
A single pointer can only point a single memory location (yes, sound obvious, but stay with me). So at first sight there can be only a single data structure that pointer points to. In case of Amiga libraries that is the Library structure describing the library and its usage.
But to access functions there needs to be a second data structure holding entry points (either directly or as addresses (*1)). The two conventional methods to add something like entry points/jump tables are
- Locate all entry points after that library structure and use offsets from there on.
- Add a pointer for an entry point table to the library structure and make all offsets relative to that address.
Solution 1 would make any extension of the structure rather hard, as it would change offsets of functions each time the OS changes/extends the header. Not a good idea for an upward compatible library system.
Solution 2 is one most OSes (including Windows) use. It avoids the pitfalls about version dependence. On the down side, it comes with an additional instruction (not really a big issue) and the usage of two pointers. one to identify the library and one to handle the entry point table. This might not seem much, and as mentioned, many OSes did go that way.
But not Amiga-OS. They went for a third way: using the one-dimensional nature of address space in both directions. Consider the memory as a (not really) endless sequence of memory cells that can be traversed not only upwards but in both directions, enabling the addressing of two structures with a single pointer - as long as they lie back to back.
To see the effect it's helpful to take a look at a nice picture RichF already presented in an answer to the mentioned question:
Using the one dimensional nature in both directions offers several advantages:
- Both structures can grow with new versions without intruding on either
- New entry points can be added with new library versions
- The library structure can be extended for newer OS versions
- No need to calculate a second pointer for the jump table
- No need to handle two pointers (library and entry table)
- Only one pointer for everything about that library
The last point can't be stressed enough.
- One pointer is all any user for that library needs.
- No programmer has a chance of using the wrong one
- It makes a unique identifier for the loaded library
Of course this only works on an ISA allowing negative offsets - handy that the 68k does exactly that :) Speaking of 68k:
- There is no indirect jump with a target address in memory
- Register indirect plus (negative) offset JSR is with 18 clock as fast as an absolute JSR.
- While the advantages may seem small, they help a lot when it comes to system design in terms of simplicity, usability and upward compatibility.
- And all of that without any disadvantage (on 68k).
*1 - Here it's important to keep in mind that the Amiga was a rather slow machine - incredibly slow by today's standards. Every cycle counts. At the same time Amiga-OS tried to be as clean and well-defined as possible.