page 120 K&R

K

Keith Thompson

Philip Potter said:
Keith Thompson wrote: [...]
A function pointer needn't even be a machine address. It could, for
example, simply be an index into a table. (I don't know of any
implementations that do this.)

<OT>
What happens if you take the address of a dynamically-linked function
before the first call to it?
</OT>

Um, you get its address.

If the function has already been loaded into memory, or at least into
the program's memory space, at program startup (as is usually the
case), then there's no problem. If not, and if a function pointer is
implemented as a table index, then the implementation could allocate a
table entry, with the information (invisible to the program) to be
filled in at the first call. Or the function could be loaded either
when it's first called or when its address is first taken.

Whatever the method, it's the implementation's responsibility to get
it right.
 
P

Philip Potter

Keith said:
Philip Potter said:
Keith Thompson wrote: [...]
A function pointer needn't even be a machine address. It could, for
example, simply be an index into a table. (I don't know of any
implementations that do this.)
<OT>
What happens if you take the address of a dynamically-linked function
before the first call to it?
</OT>

Um, you get its address.

If the function has already been loaded into memory, or at least into
the program's memory space, at program startup (as is usually the
case), then there's no problem. If not, and if a function pointer is
implemented as a table index, then the implementation could allocate a
table entry, with the information (invisible to the program) to be
filled in at the first call. Or the function could be loaded either
when it's first called or when its address is first taken.

Whatever the method, it's the implementation's responsibility to get
it right.

I agree entirely. I was trying to suggest an implementation which might
use an index into a table for a function pointer instead of a machine
address, without enough knowledge to explicitly state a given case.
 
B

Barry Schwarz

Philip said:
I was thinking of situations where a function is loaded on first call;
I don't know if this is at all common.

For a dynamically loaded function, it should be loaded on first
executed reference. Then, you can take the address before the first
call but that constitutes the first reference and the "dynamic load
manager" will have to load it as part of evaluating that expression.


Remove del for email
 
D

David Thompson

CBFalconer <[email protected]> writes:
Well, in terms of C (this is comp.lang.c, after all), I'm afraid the
above is nonsense. Attempting to increment a function pointer is a
constraint violation, requiring a diagnostic. Attempting to increment
a return address doesn't even make sense, since return addresses
aren't directly accessible in C.

A function pointer needn't even be a machine address. It could, for
example, simply be an index into a table. (I don't know of any
implementations that do this.)

Original Tandem NonStop, still emulated on its Compaq^WHP successor
machines. The ISA was originally defined with call instructions having
a 9-bit index into a table (at the beginning of the code segment) of
almost 512 entries each containing a 16-bit instruction address.

This provided a minor gain in code compactness, and at the same time a
security feature: the OS kernel was simply another code segment, and
kernel calls were a variant call instruction with an index into the
system PEP table instead of the user one, so you couldn't jump into
the middle of a system routine. Moreover, the entries in the table
were grouped into privilege levels (using the first two table slots,
leaving only 510 real entries, hence my 'almost' above) and the CPU
would only raise the privilege level on a system call to those
procedures (= slots = indexes) marked to allow it, like the entry
'gates' in Multics; this meant that the OS segment could also contain
internal routines usable only when already in privileged state
(normally in system code, but see below), and (shared) utility
routines like atoi usable from either user or system code but
privileged only when called from privileged/system code.

Further, the same feature was applied to 'user' (really process) code
segments, so that a process with special privilege (only) could
effectively localize exercise of that privilege to certain procedures,
automatically. This was used with a message-passing OS that today
would be called microkernel -- when a user program does an I/O call,
it directly calls (as above) a small kernel routine that looks up the
fd (or name in some cases) and then sends the request as a message to
the _process_ handling that device -- one* process for each disk
drive, one for magtape, one for each comms line/protocol of which
historically Tandem supported a wide variety although nowadays
TCP/IP/Ethernet is dominant. That driver process code would include
privileged routines (per the PEP table) to do (only) the hardware I/O.
(* Actually driver processes were at least pairs for fault tolerance
and sometimes more for load balancing; but the point here is that they
were always a different process than the user process, with their own
code segment and thus PEP and procedure indexes.)

When this architecture needed to expand code space beyond one (plus)
16-bit segment, they added a second level of indirection. Instead of
call-normal and call-kernel, the two instructions were call-same-seg,
with a 9-bit index into PEP as above; and call-cross-seg, with a 9-bit
index into another (XEP) table with each entry containing a segment id
(including process/kernel) plus a 9-bit PEP index within that segment.

The 'dynamic call' instruction, used for C function-pointer calls,
(now) takes in effect a XEP entry -- 6-bit (or maybe now 7?) to select
process/kernel segment and 9-bit index within that segment.

- formerly david.thompson1 || achar(64) || worldnet.att.net
 
T

Tor Rustad

David said:
Original Tandem NonStop, still emulated on its Compaq^WHP successor
machines. The ISA was originally defined with call instructions having
a 9-bit index into a table (at the beginning of the code segment) of
almost 512 entries each containing a 16-bit instruction address.

<huge snip>

Very interesting read. Nearly 10 years ago, I attended a NonStop Kernel
training course, which I guess was primary intended for Tandem
employees. Nonetheless, it was one of the most interesting CS classes I
have taken.

One of the really nice things on this OS, was the message passing
architecture, combined with a pathway (monitor process), which made
server programming easy. No need for multi-threading.

Did you work on the NSK kernel group?
 
D

David Thompson

David Thompson wrote:

<huge snip>

Very interesting read. Nearly 10 years ago, I attended a NonStop Kernel
training course, which I guess was primary intended for Tandem
employees. Nonetheless, it was one of the most interesting CS classes I
have taken.

One of the really nice things on this OS, was the message passing
architecture, combined with a pathway (monitor process), which made
server programming easy. No need for multi-threading.
I described (in the snip) the message-passing within the O/S (or at
least the most visible part of it, I/O); the use of (almost) the same
capability at user/application level was indeed another valuable and
unusual feature, but one whose description seemed to me to go even
further offtopic so I stopped. You may have noticed that I mentioned
fault-tolerance only briefly, although that was the primary purpose
for most of the architecture, including message-passing.

'Pathway' (or more precisely now TS/MP, if they haven't renamed it
again) + singlethread contextfree servers is convenient for _modest_
levels of concurrency. When you reach many thousands of small/brief
operations per second, or substantial numbers (say hundreds) of
long-running operations, you need to reintroduce some kind of
threading, although it may be via things like 'work queue' files.
Did you work on the NSK kernel group?

I didn't work for Tandeml, but for an outside 'third-party' software
developer; I just RTFMed -- a lot. (Aside: In those days it wasn't
'NSK', just Guardian and Guardian kernel; the distinction into NSK was
created later when they wanted to add POSIX support. Shortly before
the first=Compaq acquisition, IIRC.)

- formerly david.thompson1 || achar(64) || worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
474,262
Messages
2,571,049
Members
48,769
Latest member
Clifft

Latest Threads

Top