[comp.sys.mac] LSC, function pointers, and segments

gardner@prls.UUCP (Robert Gardner) (01/05/88)

I started working on segmenting a large program that uses function pointers
rather extensively and got worried about assigning a function pointer
in one segment, unloading that segment, and having it accessed later from
another segment. Is the function pointer still valid?

Interestingly, when I step through the code with TMON I noticed that when
the function pointer is used it is called via JSR (A0), as expected,
but the next function called is something like JMP xx(A5), which is usually
the type of call you see in the jump table for a loaded segment, which
is replaced by _LoadSeg if the segment is unloaded. (I haven't yet had time
to see what it says when the segment is unloaded.)

So, it appears that the function pointer should still be valid, even
if the segment containing the function gets unloaded. I would like to know
if this is true, even for static functions, and if so, what kind of magic
makes it possible.

Thank you,
Robert Gardner

oster@dewey.soe.berkeley.edu (David Phillip Oster) (01/11/88)

In article <8217@prls.UUCP> gardner@prls.UUCP (Robert Gardner) writes:
>I started working on segmenting a large program that uses function pointers
>rather extensively and got worried about assigning a function pointer
>in one segment, unloading that segment, and having it accessed later from
>another segment. Is the function pointer still valid?

Yes. What is actually being passed around is the reference to the function
in the jump table, just as you surmised.  The reason this works for static
function is, they go in the jump table too
(Think about it, they have to, see this example:)

static HiddenFunc(){}

ProcPtr PassOut(){
  return (PtocPtr) HiddenFunc;
}

-----------------------------
This is completely legal. The only way this can work is if PassOut() is
really returning the segment table reference.

==============
Caveat: suppose you pass out a reference that uses the segment loader's
jump table, suppose you unload the segment, and pass the address to an
operating system routine that runs at interrupt time (VBL task,
IOCompletion routine,  interrupt handler.) Well, the segment loader will
try to read the segment in, and the memory manager may be in an invalid
state: the bomb!
Moral: if you pass it to the operating system's interrupt system, make
sure it is in memory and stays in memory
=============
There is one case where this will get you into trouble: If you do things
at IAZNotify() time, the heap may be scrambled enough that the segment
table has already been destroyed. If you do this, you must be careful to
use a segment you KNOW is in the heap, and you must dereference it from
the jmp table to the real address (remember to skip the JMP instruction.)
yourself before you pass it.
Moral: You should take Apple's advice and not write IAZNotify routines.

P.S.: You posted to:
Newsgroups: comp.sys.ibm.pc,comp.sys.mac,comp.sys.atari.st

which is not appropriate for this kind of questions. This article is
going only to comp.sys.mac.


--- David Phillip Oster            --A Sun 3/60 makes a poor Macintosh II.
Arpa: oster@dewey.soe.berkeley.edu --A Macintosh II makes a poor Sun 3/60.
Uucp: {uwvax,decvax,ihnp4}!ucbvax!oster%dewey.soe.berkeley.edu

edmoy@violet.berkeley.edu (01/12/88)

In article <8217@prls.UUCP> gardner@prls.UUCP (Robert Gardner) writes:
>I started working on segmenting a large program that uses function pointers
>rather extensively and got worried about assigning a function pointer
>in one segment, unloading that segment, and having it accessed later from
>another segment. Is the function pointer still valid?
>
>Interestingly, when I step through the code with TMON I noticed that when
>the function pointer is used it is called via JSR (A0), as expected,
>but the next function called is something like JMP xx(A5), which is usually
>the type of call you see in the jump table for a loaded segment, which
>is replaced by _LoadSeg if the segment is unloaded. (I haven't yet had time
>to see what it says when the segment is unloaded.)

A compiler can, under normal circumstances always use the jump table address
to reference the function.  A smart compiler/linker could optimize some
of these into direct addresses, if the calling function is in the same segment
as the called function (and thus the segament is guaranteed to be loaded
already).

Edward Moy
Workstation Software Support
University of California
Berkeley, CA  94720

edmoy@violet.Berkeley.EDU
ucbvax!violet!edmoy

gardner@prls.UUCP (Robert Gardner) (01/12/88)

In article <22519@ucbvax.BERKELEY.EDU> oster@dewey.soe.berkeley.edu.UUCP (David Phillip Oster) writes:
>In article <8217@prls.UUCP> gardner@prls.UUCP (Robert Gardner) writes:
>>I started working on segmenting a large program that uses function pointers
>>rather extensively and got worried about assigning a function pointer
>>in one segment, unloading that segment, and having it accessed later from
>>another segment. Is the function pointer still valid?

>Yes. What is actually being passed around is the reference to the function
>in the jump table, just as you surmised.  The reason this works for static
>function is, they go in the jump table too

Thank you. A friend answered this question for me after I posted but
added an interesting observation that perhaps ought to be mentioned. And
if this is wrong, the THINK representative should please clarify!

When referencing the address of static functions, they are added to the 
jump table and the jump table address is used only if they are assigned
to global variables or passed as function parameters to a non-static
function. Otherwise the PC-relative address is used.

This was discovered because the friend was passing a static function
to a function which had access to a previously-stored address of a static
function in a static variable. He would then compare the saved address
with the passed address for equality. Turned out they would never
compare equal because one was a PC-relative address and one was a
jump table entry! Changing the variable that he stored the address in
from static to global solved the problem.

This technique used by LSC (if we understand it correctly) is actually
quite intelligent -- but this experience shows that there are pitfalls
to being intelligent, especially when your intelligence is undocumented!
I like what they've done, but it should be mentioned somewhere...

>P.S.: You posted to:
>Newsgroups: comp.sys.ibm.pc,comp.sys.mac,comp.sys.atari.st
I realized that too late and sent apologies to those newsgroups (thus
wasteing even more net bandwidth :-). I haven't figured out how to post
a message on a new subject without doing a follow-up to an old one,
and I forgot to check the Newsgroups line...

Robert Gardner