Re: PR1ME C compiler sources and pointer formats

Christopher F Clark <christopher.f.clark@compiler-resources.com>
Sun, 29 Sep 2019 07:48:34 -0400

          From comp.compilers

Related articles
PR1ME C compiler sources derek@_NOSPAM_knosof.co.uk (Derek M. Jones) (2019-09-25)
Re: PR1ME C compiler sources arnold@skeeve.com (2019-09-25)
Re: PR1ME C compiler pointer management drb@ihatespam.msu.edu (2019-09-28)
Re: PR1ME C compiler sources and pointer formats christopher.f.clark@compiler-resources.com (Christopher F Clark) (2019-09-29)
Re: PR1ME C compiler sources and pointer formats drb@ihatespam.msu.edu (2019-09-30)
| List of all articles for this month |

From: Christopher F Clark <christopher.f.clark@compiler-resources.com>
Newsgroups: comp.compilers
Date: Sun, 29 Sep 2019 07:48:34 -0400
Organization: Compilers Central
References: 19-09-003 19-09-004 19-09-016
Injection-Info: gal.iecc.com; posting-host="news.iecc.com:2001:470:1f07:1126:0:676f:7373:6970"; logging-data="97940"; mail-complaints-to="abuse@iecc.com"
Keywords: C, history
Posted-Date: 30 Sep 2019 18:11:22 EDT

I don't know where you saw the description of the register set. I
suspect it was only describing the "general purpose registers"
associated with IX-mode (which I knew as I*-mode). The 48 bit pointer
registers are not part of that set. And, what I was describing
previously was the way the C compiler worked in V-mode. Reading the
documentation on the C compiler for IX-mode. It is clear that they
added a whole new way of dealing with 32 bit pointers using the
general purpose registers.


From what I read, my guess is that in IX-mode they tried to create a
linear address space more compatible with C programs than the previous
segmented address space was. Of course, to cooperate with the OS and
it's security model they had to respect and interface with the
segmented address space some.


So, what follows is what I remember of the V-mode segmented address
space (with some guesses as to how they probably tweaked it for
IX-mode to make it appear more linear). There were 4 pointer
registers in V-mode. PB -- a pointer to the instruction space. LB --
a pointer to "static" memory. SB -- a pointer to the "stack frame".
XB -- a pointer for general use. If I recall correctly, only the XB
was actually modifiable by normal code; done with the EAXB
instruction, calculate effective address (including doing
indirections) and store it in the XB register. The PB, LB, and SB
registers were only changed by the PCL (procedure call) instruction
(and it's corresponding return). Each of these registers had the two
bits I mentioned previously (although, I forgot the ring bits which
separated them), a ring number 0, 1, 2, or 3 (the OS ran in ring 0 and
user code ran in ring 3, the DBMS used ring 1 or 2 if I recall
correctly, but the other ring was unused), a segment number, a
half-word (16 bit offset), and a bit offset (that was only used by the
hardware at the character (8 bit) level).


Segments were 64k half-words in length (i.e. the half-word offset was
a 16 bit number that wrapped around inside segments). The segment
number was a 12 bit number, i.e. there were 4k segments. So, at the
byte level, there was approximately 29 bits of byte addressable
storage per user process. The system was a (demand paged) virtual
memory system, so pages from other processes could be distinguished
and would not be accessible.


Calls to the OS or DBMS were done through the standard PCL mechanism
which would change which ring you were running in (increasing your
priority), but every segment also had a ring number (as well as every
pointer) had a ring number associated with it and the values were
ORed, so that you got the lowest priority access. Thus, if you fudged
a pointer and you called into the OS, the OS would see your pointer
was in a lower priority space and use only the access rights that
space had to that address. Code could also lower the priority of a
pointer itself, by setting the ring bits, and I believe if you stored
a pointer, the hardware stored the ring bits in the saved pointer to
be the weak access it was using. So, even if your pointer got copied
into a ring 0 memory location, it would remain a ring 3 pointer if it
originally came from user space.


The hardware supported at least 3 faults related to pointers. Access
violation, the pointer was accessing a segment in a way it didn't have
rights to, with roughly the same 3 mode bits read, write, and execute
for each ring. Pointer fault, the fault bit in the pointer was set.
and page fault, the pointer pointed to a page that wasn't currently
mapped in. I believe there was also a segment fault for segments that
did not exist.


To make this be more like a flat address space, one could treat the
segment number and offset within a segment as a contiguous 28 bit
integer that pointed to a 16 bit half-word. The byte offset within
that half-word was in the wrong spot (essentially the sign bit of a 29
bit number), but a rotate of the 29 bits would fix that. The only
issue was the fault bit and ring bits were kind of in the way from a
pure 32 bit rotate. Thus, it was not pretty code, but it was doable.
I'm sure that is what the comment about V-mode C code being slower
than IX-mode as it probably had that done as part of the generated
code.


The other thing to note is that all instruction addresses (at least in
V-mode) were relative to one of the 4 base registers. Thus, you
needed to put one of the base registers (XB presumably) as the start
of the memory you want to be linearly addressible (and make sure that
none of the segments above that base address are in use by higher
privilege code and inaccessible). Other than that, the paging
mechanism should add pages for you as needed to match your address
space and even gaps in the middle could be accommodated so that you
could have a stack and heap that grew toward each other.


So, my guess is that IX mode did roughly that, putting the XB at the
start of the linear address space for C programs and making the
instructions which used the GPR registers as pointers, do the
appropriate bit twiddling in hardware but basing the resulting address
off the XB. Alternately, the instructions using the GPR registers as
pointers could have used "absolute addressing" with no base register,
letting the pointers deal with the segments (and their ring
restrictions) as required. The rings and segments would have still
been there but the code would have had the 29 bits to play with and
probably treated all accesses as if it were from ring 3.


--
******************************************************************************
Chris Clark email: christopher.f.clark@compiler-resources.com
Compiler Resources, Inc. Web Site: http://world.std.com/~compres
23 Bailey Rd voice: (508) 435-5016
Berlin, MA 01503 USA twitter: @intel_chris
------------------------------------------------------------------------------


Post a followup to this message

Return to the comp.compilers page.
Search the comp.compilers archives again.