23

As described in these answers, the jump table offsets to functions contained in an AmigaOS library are always negative values. The reason for this is not intuitive to me, but I suspect Carl Sassenrath had some good reason(s) for doing it this way (as opposed to just using positive offsets).

What functionality or convenience is gained by having these offsets be negative values from the base address?

Raffzahn
  • 222,541
  • 22
  • 631
  • 918
Brian H
  • 60,767
  • 20
  • 200
  • 362

1 Answers1

30

TL;DR:

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

  1. Locate all entry points after that library structure and use offsets from there on.
  2. 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:

Figure 1.1: Amiga Library Structure and Jump Table

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.

Bottom line:

  • 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.

Toby Speight
  • 1,611
  • 14
  • 31
Raffzahn
  • 222,541
  • 22
  • 631
  • 918
  • 10
    Someone will say it, though I'm not sure it's completely relevant: most implementations of malloc do the same one-pointer-to-two-things dance. On the positive side of the pointer is the buffer you actually asked for, on the negative is whatever information free will need to do its bookkeeping. Though, again, I guess it's only very broadly related — in the sense of allowing two things of decoupled size to be referenced by a single pointer with no skipping-a-bit burden on either kind of consumer. It's completely irrelevant as concerns the version dependence stuff. – Tommy Feb 23 '21 at 22:17
  • 4
    @Tommy Oh, of course. I would never say this isn't used in other places as well. In fact, classic MS-DOS memory management is kind of similar to your description, just with the little drawback that the 8086 can/does not use negative offset. Something the 68k can do (Added a few lines about that). So only CPUs that allow regular use of a negative offset may really use two structures with a single pointer. It of course opens as well a whole sack of philosophical discussions. – Raffzahn Feb 23 '21 at 22:26
  • You write about the 68k, I'd be curious if the negative offset support is the same on much later Amigas, which were based on PowerPC. The most recent one, Aros, rather moved to ELF format, completely different. – Omar and Lorraine Feb 23 '21 at 22:27
  • @OmarL The support is of course the same across all 68k family members, not just the 68000 - it's deep rooted in their genes. PowerPC does have a basic Register+Index addressing mode, although its not present to me if they can do negative offset - the formats were somewhat confusing. Also, later PowerPC did add a lot of modes over the basic three the original one had. ELF is a complete different format, way more complex than Amiga libraries. I guess they had to add quite some bells and whistles to make it work. Not as simple and elegant as the original format. Also only positive offsets. – Raffzahn Feb 23 '21 at 22:52
  • 1
    They used the same trick again when retrofitting old gadget structures into an object oriented design in Amiga OS 2.0. The old structure started at offset zero, looking like before (except for an additional flag), class information and list node structure were placed at negative offsets. – Holger Feb 24 '21 at 10:38
  • @Tommy - See your point, but in this case I think Amiga libraries would not normally be directly loaded/unloaded by a malloc or equivalent, there would probably be a lower level (library) routine for that also? – nsandersen Feb 24 '21 at 13:15
  • 2
    @nsandersen: True. They'd typically be allocated using the AmigaOS AllocMem routine (called internally by OpenLibrary), which stores no metadata for allocated blocks. (The AmigaOS allocator only keeps track of unallocated memory, and relies on the caller to keep track of the size of the allocated memory chunk and to pass it to FreeMem.) But I think Tommy's comment was meant as an analogy between two different uses of the negative offset trick, not as an implication that both would be used together. – Ilmari Karonen Feb 24 '21 at 16:10
  • 1
    8086 can/does not use negative offset Huh? It's still base-segment relative, but you can certainly add a negative index in any addressing mode that takes index literal operands, unless I'm just grossly misremembering from the last time I wrote x86 by hand... – Kuba hasn't forgotten Monica Feb 24 '21 at 21:31
  • @Kubahasn'tforgottenMonica "in any addressing mode that takes index literal operands" Huh? What mode is that? Keep in mind, the comment is about MS-DOS and 8086, not some Pentium-Ryzen-Core-whatever. 8086 only calculates 16 pit positive offset (to a segment). Ofc, there are many ways to poke around with far addresses and segment calculation and so on, but none as simple as with a 68k (I still prefer the 8086 as being the more intelligent solution ). – Raffzahn Feb 24 '21 at 22:09
  • 1
    @Raffzahn: The 8086 had a few design missteps, but for many purposes having segments with a 64K positive offset range was better than using a 32-bit signed offset range would have been. Though a special addressing mode for applying a negative offsets would have been handy at times. – supercat Feb 26 '21 at 22:40
  • @supercat a positive offset is simply the more common usage (except for branches) so doubling the stretch does pay off. And yes, a few more complex addressing modes would have been nice. A somewhat extended LEA alike instruction might have been a guseful addition. – Raffzahn Feb 26 '21 at 22:46