#Generating PURE code?
11 messages in this thread
PURE code is another term for 'reentrant'. The program cannot modify
any portion of itself (code, data, or bss hunks). This is because the
program may be executed by two or more tasks simultaneously, and a program
that has modified itself in one task can really confuse the second task
running the same code.
Pure is reentrant AND reexecutable, the latter meaning you assume nothing
about the initial value of your global variables (i.e. no BSS) and use
executable statements in your initialization code to give them their
original values.
While you are right, it is not necessary to stress both points. A
program that is reentrant IS, by definition, reexecutable. In fact, using
your definition's example of reexecutable, that program WOULD NOT be
reentrant, since it is modifying itself (its global variables) at
initialization, which is a definite NO-NO for rentrant code. The ONLY
things that can be modified by a reentrant program are variables that exist
on the stack, variables that exist solely in registers, or variables that
have been AllocMem()'d.
Actually I'm surprized that any compiler for a multi-tasking system would
generate anything but reentrant code. I haven't bought an Amiga C compiler
yet, I'm just playing with PDC. Do both Lattice and Manx generate PURE
code?
I write OS/2 code for my employer. OS/2 shares the code segment of a program
with all tasks and allocates separate segments for static and global data (the
stack is in the global area too).
(And we all know that the Amiga is better than any old Intel based system
<grin>)
Geo
Actually, up until very recently, the Amiga compilers were incapable of
generating reentrant code. The Amiga BCPL-based CLI environment was not
designed to share code segments of loaded programs between tasks, so
consequently, reentrancy was not a real issue for 'application' programs.
It has always been an issue for things like run-time shared libraries and
device drivers, and there were ways to generate these _MOSTLY_ in C, but a
bit of assembler coding was required.
One "limitation" that the 68000 has over the Intel processors is that
the 68K is not forced to reference memory via a register-displacement type
of addressing. This allows programs to contain direct memory references to
data areas, which must be fixed once the program is loaded. Consequently,
one in-memory copy of a program such as this cannot reference two areas of
memory simultaneously (one for each concurrent task). This makes
re-entrant use of global variables difficult.
Of course, the 68K also allows references to memory via
relative-register addressing, so there are ways around this problem – we
just have to 'pretend' that we're working with a segmented architecture
<grin>. Anyway, this is getting pretty rambling. Think I'll just end it
here before I get totally confused 🙂
Bob, surely you jest. BCPL was _explicitly_ designed to share code and
have separate data segments (called global vectors)
Boy, some folks really get sensitive when a negative remark is made in the
same sentence as BCPL! <grin> I should know better than to argue with you
about the language! <ducking>
Actually, what I was attempting to say (now that I know that I'm being
watched 🙂 is that the manner in which the CLI environment was implented (such
implementation having been written in BCPL but not necessarily because it was
written in BCPL) was not really designed to support shared code segments for
multiple processes. Better?
My biggest complaint about the BCPL layers of the OS environment is that
they are the poorest documented of all components of the Amiga software.
There's a lot of deep, dark hidden voodoo there!
Actually, I think the system was written to handle shared code and separate
data segments for multiple processes. I think the C compiler(s? were there
more than one back then?) couldn't put the right stuff in to the loader text to
support it. Thus, it just may have been that the C people didn't want to look
at the BCPL requirements. That it was documented poorly is true. I believe
one of the reasons was that MetaComCo wished to make some enhancements to
AmigaDOS which would require some changes to the GLOBVEC. In those days
documenting ANYTHING, no matter how severe the warnings were about it not being
stable would just have gotten CBM hollered at if things changed. Do you
remember the abortive attempt to 'fix' the cursor 'hot spot' which is off by
one pixel? EA screamed so loud that CBM (in error, IMHO) backed down, and now
we all live with a one pixel error in pointer hot spot.
I sure do remember the off-by-one problem that CBM wanted to fix but had
to back out. That's a tough one, though, where your d*mned if you do and
d*mned if you don't. I don't think that, at that point in the development
of the CBM software market, it would have been wise to "break" some of the
existing major software packages, so I think that the right decision was
made.
Regarding the splitting of load modules into sharable code segments and
separate (but equal) data segments, I really don't see anything in either
the Process or CLI structures that look like they are there to support it.
There also is no documented dos.library call to spawn off a new Process,
using an existing, loaded, shared SegList. Consequently, I stand by my
original contention that the capability was never designed in. As far as
the existing C compiler(s) (counting the original Lattice compiler, if you
must, and the Greenhills cross-dev system) – there just didn't exist (from
what I can tell) any "standard" for them to aim at, other than the
documented Object/Executable Hunk Format standards. And those definitions
don't really support the shared code segments/separate data segment models.
There was no defined method for anything but 32-bit reloc's, which implies
hard, relocatable addresses.
First, you must realize that reentrant code is not a prerequisite for
multitasking, and secondly, that though reentrancy is desirable for certain
classes of programs, it is by no means cheaply obtained. There is
considerable overhead in making a program reentrant, both from a memory
usage and from a speed point of view, especially in the initialization
portion f a program. What is the minumum memory requirement for OS/2? 2
megs? How much is left for user programs at that size memory? 🙂
Larry, from my experience with OS-9, writing reentrant position
independent code is fairly straight foward. Of course, OS-9 lets you define
the size of your private data area in the module header and then
dynamically allocates the storage for you.
Writing reentrant code on an IBM mainframe is much harder and requires a
lot of extra code due to they way they build parameter lists within the OS
services macros. Writing reentrant code on the IBM Series/1 is real easy
as they designed the OS services macro parameter lists. Writing reentrant
code on OS/2 is easy too, but anything developed on those Intel CPUs are
memory pigs.
Speaking of memory pigs:
OS/2 requires a minimum of 1.5 to 2 megs just to BOOT;
The Presentation Manager requires about a meg;
The Communications Manager requires about a meg;
The Database and Query Managers require about a meg;
The LAN Server requires over TWO megs.
Oh, you want to run applications? IBM actually said to figure about a meg
per application. They sure like round megabytes, don't they?
I was amazed at how much function William Hawes put in Arexx in 32K. I'm
waiting for IBM's OS/2 Rexx to see how many hundreds of K are required to
equal Arexx.